Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
623c4387
Commit
623c4387
authored
Dec 18, 2013
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
parents
204e35a9
cf4ef654
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
1837 additions
and
766 deletions
+1837
-766
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
+0
-6
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/main.c
+2
-2
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
+1
-1
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-config.h
+2
-0
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.c
+39
-0
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+7
-0
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
+1
-0
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-fw.h
+46
-0
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+14
-1
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-op-mode.h
+1
-3
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-trans.h
+52
-14
drivers/net/wireless/iwlwifi/mvm/Makefile
drivers/net/wireless/iwlwifi/mvm/Makefile
+1
-2
drivers/net/wireless/iwlwifi/mvm/binding.c
drivers/net/wireless/iwlwifi/mvm/binding.c
+15
-1
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+353
-0
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+16
-0
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+9
-1
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+1
-0
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
+65
-0
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/fw.c
+18
-10
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
+174
-78
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
+37
-8
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/ops.c
+12
-8
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/power.c
+243
-152
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.c
+350
-336
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rs.h
+0
-2
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/rx.c
+6
-0
drivers/net/wireless/iwlwifi/mvm/sf.c
drivers/net/wireless/iwlwifi/mvm/sf.c
+291
-0
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.c
+4
-17
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tt.c
+1
-1
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/tx.c
+1
-2
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/mvm/utils.c
+5
-0
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/internal.h
+2
-31
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
+16
-19
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/trans.c
+37
-49
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/iwlwifi/pcie/tx.c
+15
-22
No files found.
drivers/net/wireless/iwlwifi/dvm/mac80211.c
View file @
623c4387
...
...
@@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
flush_workqueue
(
priv
->
workqueue
);
/* User space software may expect getting rfkill changes
* even if interface is down, trans->down will leave the RF
* kill interrupt enabled
*/
iwl_trans_stop_hw
(
priv
->
trans
,
false
);
IWL_DEBUG_MAC80211
(
priv
,
"leave
\n
"
);
}
...
...
drivers/net/wireless/iwlwifi/dvm/main.c
View file @
623c4387
...
...
@@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
}
/* Reset chip to save power until we load uCode during "up". */
iwl_trans_stop_
hw
(
priv
->
trans
,
false
);
iwl_trans_stop_
device
(
priv
->
trans
);
priv
->
nvm_data
=
iwl_parse_eeprom_data
(
priv
->
trans
->
dev
,
priv
->
cfg
,
priv
->
eeprom_blob
,
...
...
@@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
dev_kfree_skb
(
priv
->
beacon_skb
);
iwl_trans_
stop_hw
(
priv
->
trans
,
true
);
iwl_trans_
op_mode_leave
(
priv
->
trans
);
ieee80211_free_hw
(
priv
->
hw
);
}
...
...
drivers/net/wireless/iwlwifi/iwl-7000.c
View file @
623c4387
...
...
@@ -108,7 +108,7 @@ static const struct iwl_base_params iwl7000_base_params = {
};
static
const
struct
iwl_ht_params
iwl7000_ht_params
=
{
.
use_rts_for_aggregation
=
true
,
/* use rts/cts protection */
.
stbc
=
true
,
.
ht40_bands
=
BIT
(
IEEE80211_BAND_2GHZ
)
|
BIT
(
IEEE80211_BAND_5GHZ
),
};
...
...
drivers/net/wireless/iwlwifi/iwl-config.h
View file @
623c4387
...
...
@@ -162,12 +162,14 @@ struct iwl_base_params {
};
/*
* @stbc: support Tx STBC and 1*SS Rx STBC
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
*/
struct
iwl_ht_params
{
enum
ieee80211_smps_mode
smps_mode
;
const
bool
ht_greenfield_support
;
/* if used set to true */
const
bool
stbc
;
bool
use_rts_for_aggregation
;
u8
ht40_bands
;
};
...
...
drivers/net/wireless/iwlwifi/iwl-drv.c
View file @
623c4387
...
...
@@ -322,6 +322,41 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
pieces
->
img
[
type
].
sec
[
sec
].
offset
=
offset
;
}
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
]))
return
-
EINVAL
;
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
)
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
;
}
return
0
;
}
/*
* Gets uCode section from tlv.
*/
...
...
@@ -729,6 +764,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
return
-
EINVAL
;
}
break
;
case
IWL_UCODE_TLV_CSCHEME
:
if
(
iwl_store_cscheme
(
&
drv
->
fw
,
tlv_data
,
tlv_len
))
goto
invalid_tlv_len
;
break
;
default:
IWL_DEBUG_INFO
(
drv
,
"unknown TLV: %d
\n
"
,
tlv_type
);
break
;
...
...
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
View file @
623c4387
...
...
@@ -751,6 +751,13 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
ht_info
->
ht_supported
=
true
;
ht_info
->
cap
=
IEEE80211_HT_CAP_DSSSCCK40
;
if
(
cfg
->
ht_params
->
stbc
)
{
ht_info
->
cap
|=
(
1
<<
IEEE80211_HT_CAP_RX_STBC_SHIFT
);
if
(
tx_chains
>
1
)
ht_info
->
cap
|=
IEEE80211_HT_CAP_TX_STBC
;
}
if
(
iwlwifi_mod_params
.
amsdu_size_8K
)
ht_info
->
cap
|=
IEEE80211_HT_CAP_MAX_AMSDU
;
...
...
drivers/net/wireless/iwlwifi/iwl-fw-file.h
View file @
623c4387
...
...
@@ -125,6 +125,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_SECURE_SEC_INIT
=
25
,
IWL_UCODE_TLV_SECURE_SEC_WOWLAN
=
26
,
IWL_UCODE_TLV_NUM_OF_CPU
=
27
,
IWL_UCODE_TLV_CSCHEME
=
28
,
};
struct
iwl_ucode_tlv
{
...
...
drivers/net/wireless/iwlwifi/iwl-fw.h
View file @
623c4387
...
...
@@ -92,6 +92,9 @@
* @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
* @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
* containing CAM (Continuous Active Mode) indication.
* @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
* single bound interface).
* @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
*/
enum
iwl_ucode_tlv_flag
{
IWL_UCODE_TLV_FLAGS_PAN
=
BIT
(
0
),
...
...
@@ -113,7 +116,9 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_SCHED_SCAN
=
BIT
(
17
),
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD
=
BIT
(
19
),
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD
=
BIT
(
20
),
IWL_UCODE_TLV_FLAGS_P2P_PS
=
BIT
(
21
),
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT
=
BIT
(
24
),
IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD
=
BIT
(
26
),
};
/* The default calibrate table size if not specified by firmware file */
...
...
@@ -209,6 +214,44 @@ enum iwl_fw_phy_cfg {
FW_PHY_CFG_RX_CHAIN
=
0xf
<<
FW_PHY_CFG_RX_CHAIN_POS
,
};
#define IWL_UCODE_MAX_CS 1
/**
* struct iwl_fw_cipher_scheme - a cipher scheme supported by FW.
* @cipher: a cipher suite selector
* @flags: cipher scheme flags (currently reserved for a future use)
* @hdr_len: a size of MPDU security header
* @pn_len: a size of PN
* @pn_off: an offset of pn from the beginning of the security header
* @key_idx_off: an offset of key index byte in the security header
* @key_idx_mask: a bit mask of key_idx bits
* @key_idx_shift: bit shift needed to get key_idx
* @mic_len: mic length in bytes
* @hw_cipher: a HW cipher index used in host commands
*/
struct
iwl_fw_cipher_scheme
{
__le32
cipher
;
u8
flags
;
u8
hdr_len
;
u8
pn_len
;
u8
pn_off
;
u8
key_idx_off
;
u8
key_idx_mask
;
u8
key_idx_shift
;
u8
mic_len
;
u8
hw_cipher
;
}
__packed
;
/**
* struct iwl_fw_cscheme_list - a cipher scheme list
* @size: a number of entries
* @cs: cipher scheme entries
*/
struct
iwl_fw_cscheme_list
{
u8
size
;
struct
iwl_fw_cipher_scheme
cs
[];
}
__packed
;
/**
* struct iwl_fw - variables associated with the firmware
*
...
...
@@ -224,6 +267,7 @@ enum iwl_fw_phy_cfg {
* @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
* @cipher_scheme: optional external cipher scheme.
*/
struct
iwl_fw
{
u32
ucode_ver
;
...
...
@@ -243,6 +287,8 @@ struct iwl_fw {
u32
phy_config
;
bool
mvm_fw
;
struct
ieee80211_cipher_scheme
cs
[
IWL_UCODE_MAX_CS
];
};
static
inline
u8
iwl_fw_valid_tx_ant
(
const
struct
iwl_fw
*
fw
)
...
...
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
View file @
623c4387
...
...
@@ -263,13 +263,20 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct
iwl_nvm_data
*
data
,
struct
ieee80211_sta_vht_cap
*
vht_cap
)
{
int
num_ants
=
num_of_ant
(
data
->
valid_rx_ant
);
int
bf_sts_cap
=
num_ants
-
1
;
vht_cap
->
vht_supported
=
true
;
vht_cap
->
cap
=
IEEE80211_VHT_CAP_SHORT_GI_80
|
IEEE80211_VHT_CAP_RXSTBC_1
|
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
|
bf_sts_cap
<<
IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT
|
7
<<
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT
;
if
(
num_ants
>
1
)
vht_cap
->
cap
|=
IEEE80211_VHT_CAP_TXSTBC
;
if
(
iwlwifi_mod_params
.
amsdu_size_8K
)
vht_cap
->
cap
|=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991
;
...
...
@@ -283,16 +290,22 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_MCS_NOT_SUPPORTED
<<
12
|
IEEE80211_VHT_MCS_NOT_SUPPORTED
<<
14
);
if
(
num_of_ant
(
data
->
valid_rx_ant
)
==
1
||
/* Max rate for Long GI NSS=2 80Mhz is 780Mbps */
vht_cap
->
vht_mcs
.
rx_highest
=
cpu_to_le16
(
780
);
if
(
num_ants
==
1
||
cfg
->
rx_with_siso_diversity
)
{
vht_cap
->
cap
|=
IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN
|
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN
;
/* this works because NOT_SUPPORTED == 3 */
vht_cap
->
vht_mcs
.
rx_mcs_map
|=
cpu_to_le16
(
IEEE80211_VHT_MCS_NOT_SUPPORTED
<<
2
);
/* Max rate for Long GI NSS=1 80Mhz is 390Mbps */
vht_cap
->
vht_mcs
.
rx_highest
=
cpu_to_le16
(
390
);
}
vht_cap
->
vht_mcs
.
tx_mcs_map
=
vht_cap
->
vht_mcs
.
rx_mcs_map
;
vht_cap
->
vht_mcs
.
tx_highest
=
vht_cap
->
vht_mcs
.
rx_highest
;
}
static
void
iwl_init_sbands
(
struct
device
*
dev
,
const
struct
iwl_cfg
*
cfg
,
...
...
drivers/net/wireless/iwlwifi/iwl-op-mode.h
View file @
623c4387
...
...
@@ -155,14 +155,12 @@ void iwl_opmode_deregister(const char *name);
/**
* struct iwl_op_mode - operational mode
* @ops - pointer to its own ops
*
* This holds an implementation of the mac80211 / fw API.
*
* @ops - pointer to its own ops
*/
struct
iwl_op_mode
{
const
struct
iwl_op_mode_ops
*
ops
;
const
struct
iwl_trans
*
trans
;
char
op_mode_specific
[
0
]
__aligned
(
sizeof
(
void
*
));
};
...
...
drivers/net/wireless/iwlwifi/iwl-trans.h
View file @
623c4387
...
...
@@ -70,6 +70,7 @@
#include "iwl-debug.h"
#include "iwl-config.h"
#include "iwl-fw.h"
#include "iwl-op-mode.h"
/**
* DOC: Transport layer - what is it ?
...
...
@@ -100,8 +101,7 @@
* start_fw
*
* 5) Then when finished (or reset):
* stop_fw (a.k.a. stop device for the moment)
* stop_hw
* stop_device
*
* 6) Eventually, the free function will be called.
*/
...
...
@@ -317,6 +317,24 @@ enum iwl_d3_status {
IWL_D3_STATUS_RESET
,
};
/**
* enum iwl_trans_status: transport status flags
* @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed
* @STATUS_DEVICE_ENABLED: APM is enabled
* @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_FW_ERROR: the fw is in error state
*/
enum
iwl_trans_status
{
STATUS_SYNC_HCMD_ACTIVE
,
STATUS_DEVICE_ENABLED
,
STATUS_TPOWER_PMI
,
STATUS_INT_ENABLED
,
STATUS_RFKILL
,
STATUS_FW_ERROR
,
};
/**
* struct iwl_trans_config - transport configuration
*
...
...
@@ -361,9 +379,7 @@ struct iwl_trans;
*
* @start_hw: starts the HW- from that point on, the HW can send interrupts
* May sleep
* @stop_hw: stops the HW- from that point on, the HW will be in low power but
* will still issue interrupt if the HW RF kill is triggered unless
* op_mode_leaving is true.
* @op_mode_leave: Turn off the HW RF kill indication if on
* May sleep
* @start_fw: allocates and inits all the resources for the transport
* layer. Also kick a fw image.
...
...
@@ -371,8 +387,11 @@ struct iwl_trans;
* @fw_alive: called when the fw sends alive notification. If the fw provides
* the SCD base address in SRAM, then provide it here, or 0 otherwise.
* May sleep
* @stop_device:stops the whole device (embedded CPU put to reset)
* May sleep
* @stop_device: stops the whole device (embedded CPU put to reset) and stops
* the HW. From that point on, the HW will be in low power but will still
* issue interrupt if the HW RF kill is triggered. This callback must do
* the right thing and not crash even if start_hw() was called but not
* start_fw(). May sleep
* @d3_suspend: put the device into the correct mode for WoWLAN during
* suspend. This is optional, if not implemented WoWLAN will not be
* supported. This callback may sleep.
...
...
@@ -418,7 +437,7 @@ struct iwl_trans;
struct
iwl_trans_ops
{
int
(
*
start_hw
)(
struct
iwl_trans
*
iwl_trans
);
void
(
*
stop_hw
)(
struct
iwl_trans
*
iwl_trans
,
bool
op_mode_leaving
);
void
(
*
op_mode_leave
)(
struct
iwl_trans
*
iwl_trans
);
int
(
*
start_fw
)(
struct
iwl_trans
*
trans
,
const
struct
fw_img
*
fw
,
bool
run_in_rfkill
);
void
(
*
fw_alive
)(
struct
iwl_trans
*
trans
,
u32
scd_addr
);
...
...
@@ -479,6 +498,7 @@ enum iwl_trans_state {
* @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @cfg - pointer to the configuration
* @status: a bit-mask of transport status flags
* @dev - pointer to struct device * that represents the device
* @hw_id: a u32 with the ID of the device / subdevice.
* Set during transport allocation.
...
...
@@ -499,6 +519,7 @@ struct iwl_trans {
struct
iwl_op_mode
*
op_mode
;
const
struct
iwl_cfg
*
cfg
;
enum
iwl_trans_state
state
;
unsigned
long
status
;
struct
device
*
dev
;
u32
hw_rev
;
...
...
@@ -540,15 +561,14 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
return
trans
->
ops
->
start_hw
(
trans
);
}
static
inline
void
iwl_trans_stop_hw
(
struct
iwl_trans
*
trans
,
bool
op_mode_leaving
)
static
inline
void
iwl_trans_op_mode_leave
(
struct
iwl_trans
*
trans
)
{
might_sleep
();
trans
->
ops
->
stop_hw
(
trans
,
op_mode_leaving
);
if
(
trans
->
ops
->
op_mode_leave
)
trans
->
ops
->
op_mode_leave
(
trans
);
if
(
op_mode_leaving
)
trans
->
op_mode
=
NULL
;
trans
->
op_mode
=
NULL
;
trans
->
state
=
IWL_TRANS_NO_FW
;
}
...
...
@@ -570,6 +590,7 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans,
WARN_ON_ONCE
(
!
trans
->
rx_mpdu_cmd
);
clear_bit
(
STATUS_FW_ERROR
,
&
trans
->
status
);
return
trans
->
ops
->
start_fw
(
trans
,
fw
,
run_in_rfkill
);
}
...
...
@@ -601,6 +622,9 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
{
int
ret
;
if
(
unlikely
(
test_bit
(
STATUS_FW_ERROR
,
&
trans
->
status
)))
return
-
EIO
;
if
(
unlikely
(
trans
->
state
!=
IWL_TRANS_FW_ALIVE
))
{
IWL_ERR
(
trans
,
"%s bad state = %d"
,
__func__
,
trans
->
state
);
return
-
EIO
;
...
...
@@ -640,6 +664,9 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
static
inline
int
iwl_trans_tx
(
struct
iwl_trans
*
trans
,
struct
sk_buff
*
skb
,
struct
iwl_device_cmd
*
dev_cmd
,
int
queue
)
{
if
(
unlikely
(
test_bit
(
STATUS_FW_ERROR
,
&
trans
->
status
)))
return
-
EIO
;
if
(
unlikely
(
trans
->
state
!=
IWL_TRANS_FW_ALIVE
))
IWL_ERR
(
trans
,
"%s bad state = %d"
,
__func__
,
trans
->
state
);
...
...
@@ -760,7 +787,8 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
static
inline
void
iwl_trans_set_pmi
(
struct
iwl_trans
*
trans
,
bool
state
)
{
trans
->
ops
->
set_pmi
(
trans
,
state
);
if
(
trans
->
ops
->
set_pmi
)
trans
->
ops
->
set_pmi
(
trans
,
state
);
}
static
inline
void
...
...
@@ -780,6 +808,16 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
__release
(
nic_access
);
}
static
inline
void
iwl_trans_fw_error
(
struct
iwl_trans
*
trans
)
{
if
(
WARN_ON_ONCE
(
!
trans
->
op_mode
))
return
;
/* prevent double restarts due to the same erroneous FW */
if
(
!
test_and_set_bit
(
STATUS_FW_ERROR
,
&
trans
->
status
))
iwl_op_mode_nic_error
(
trans
->
op_mode
);
}
/*****************************************************
* driver (transport) register/unregister functions
******************************************************/
...
...
drivers/net/wireless/iwlwifi/mvm/Makefile
View file @
623c4387
obj-$(CONFIG_IWLMVM)
+=
iwlmvm.o
iwlmvm-y
+=
fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y
+=
utils.o rx.o tx.o binding.o quota.o sta.o
iwlmvm-y
+=
utils.o rx.o tx.o binding.o quota.o sta.o
sf.o
iwlmvm-y
+=
scan.o time-event.o rs.o
iwlmvm-y
+=
power.o power_legacy.o bt-coex.o
iwlmvm-y
+=
led.o tt.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_PM_SLEEP)
+=
d3.o
...
...
drivers/net/wireless/iwlwifi/mvm/binding.c
View file @
623c4387
...
...
@@ -183,15 +183,29 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if
(
WARN_ON_ONCE
(
!
mvmvif
->
phy_ctxt
))
return
-
EINVAL
;
/*
* Update SF - Disable if needed. if this fails, SF might still be on
* while many macs are bound, which is forbidden - so fail the binding.
*/
if
(
iwl_mvm_sf_update
(
mvm
,
vif
,
false
))
return
-
EINVAL
;
return
iwl_mvm_binding_update
(
mvm
,
vif
,
mvmvif
->
phy_ctxt
,
true
);
}
int
iwl_mvm_binding_remove_vif
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
int
ret
;
if
(
WARN_ON_ONCE
(
!
mvmvif
->
phy_ctxt
))
return
-
EINVAL
;
return
iwl_mvm_binding_update
(
mvm
,
vif
,
mvmvif
->
phy_ctxt
,
false
);
ret
=
iwl_mvm_binding_update
(
mvm
,
vif
,
mvmvif
->
phy_ctxt
,
false
);
if
(
!
ret
)
if
(
iwl_mvm_sf_update
(
mvm
,
vif
,
true
))
IWL_ERR
(
mvm
,
"Failed to update SF state
\n
"
);
return
ret
;
}
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
View file @
623c4387
...
...
@@ -63,6 +63,150 @@
#include "mvm.h"
#include "debugfs.h"
static
void
iwl_dbgfs_update_pm
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
enum
iwl_dbgfs_pm_mask
param
,
int
val
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_dbgfs_pm
*
dbgfs_pm
=
&
mvmvif
->
dbgfs_pm
;
dbgfs_pm
->
mask
|=
param
;
switch
(
param
)
{
case
MVM_DEBUGFS_PM_KEEP_ALIVE
:
{
struct
ieee80211_hw
*
hw
=
mvm
->
hw
;
int
dtimper
=
hw
->
conf
.
ps_dtim_period
?:
1
;
int
dtimper_msec
=
dtimper
*
vif
->
bss_conf
.
beacon_int
;
IWL_DEBUG_POWER
(
mvm
,
"debugfs: set keep_alive= %d sec
\n
"
,
val
);
if
(
val
*
MSEC_PER_SEC
<
3
*
dtimper_msec
)
IWL_WARN
(
mvm
,
"debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)
\n
"
,
val
*
MSEC_PER_SEC
,
3
*
dtimper_msec
);
dbgfs_pm
->
keep_alive_seconds
=
val
;
break
;
}
case
MVM_DEBUGFS_PM_SKIP_OVER_DTIM
:
IWL_DEBUG_POWER
(
mvm
,
"skip_over_dtim %s
\n
"
,
val
?
"enabled"
:
"disabled"
);
dbgfs_pm
->
skip_over_dtim
=
val
;
break
;
case
MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS
:
IWL_DEBUG_POWER
(
mvm
,
"skip_dtim_periods=%d
\n
"
,
val
);
dbgfs_pm
->
skip_dtim_periods
=
val
;
break
;
case
MVM_DEBUGFS_PM_RX_DATA_TIMEOUT
:
IWL_DEBUG_POWER
(
mvm
,
"rx_data_timeout=%d
\n
"
,
val
);
dbgfs_pm
->
rx_data_timeout
=
val
;
break
;
case
MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
:
IWL_DEBUG_POWER
(
mvm
,
"tx_data_timeout=%d
\n
"
,
val
);
dbgfs_pm
->
tx_data_timeout
=
val
;
break
;
case
MVM_DEBUGFS_PM_DISABLE_POWER_OFF
:
IWL_DEBUG_POWER
(
mvm
,
"disable_power_off=%d
\n
"
,
val
);
dbgfs_pm
->
disable_power_off
=
val
;
break
;
case
MVM_DEBUGFS_PM_LPRX_ENA
:
IWL_DEBUG_POWER
(
mvm
,
"lprx %s
\n
"
,
val
?
"enabled"
:
"disabled"
);
dbgfs_pm
->
lprx_ena
=
val
;
break
;
case
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
:
IWL_DEBUG_POWER
(
mvm
,
"lprx_rssi_threshold=%d
\n
"
,
val
);
dbgfs_pm
->
lprx_rssi_threshold
=
val
;
break
;
case
MVM_DEBUGFS_PM_SNOOZE_ENABLE
:
IWL_DEBUG_POWER
(
mvm
,
"snooze_enable=%d
\n
"
,
val
);
dbgfs_pm
->
snooze_ena
=
val
;
break
;
case
MVM_DEBUGFS_PM_UAPSD_MISBEHAVING
:
IWL_DEBUG_POWER
(
mvm
,
"uapsd_misbehaving_enable=%d
\n
"
,
val
);
dbgfs_pm
->
uapsd_misbehaving
=
val
;
break
;
}
}
static
ssize_t
iwl_dbgfs_pm_params_write
(
struct
ieee80211_vif
*
vif
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
mvm
;
enum
iwl_dbgfs_pm_mask
param
;
int
val
,
ret
;
if
(
!
strncmp
(
"keep_alive="
,
buf
,
11
))
{
if
(
sscanf
(
buf
+
11
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_KEEP_ALIVE
;
}
else
if
(
!
strncmp
(
"skip_over_dtim="
,
buf
,
15
))
{
if
(
sscanf
(
buf
+
15
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_SKIP_OVER_DTIM
;
}
else
if
(
!
strncmp
(
"skip_dtim_periods="
,
buf
,
18
))
{
if
(
sscanf
(
buf
+
18
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS
;
}
else
if
(
!
strncmp
(
"rx_data_timeout="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_RX_DATA_TIMEOUT
;
}
else
if
(
!
strncmp
(
"tx_data_timeout="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
;
}
else
if
(
!
strncmp
(
"disable_power_off="
,
buf
,
18
)
&&
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD
))
{
if
(
sscanf
(
buf
+
18
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_DISABLE_POWER_OFF
;
}
else
if
(
!
strncmp
(
"lprx="
,
buf
,
5
))
{
if
(
sscanf
(
buf
+
5
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_LPRX_ENA
;
}
else
if
(
!
strncmp
(
"lprx_rssi_threshold="
,
buf
,
20
))
{
if
(
sscanf
(
buf
+
20
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
if
(
val
>
POWER_LPRX_RSSI_THRESHOLD_MAX
||
val
<
POWER_LPRX_RSSI_THRESHOLD_MIN
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
;
}
else
if
(
!
strncmp
(
"snooze_enable="
,
buf
,
14
))
{
if
(
sscanf
(
buf
+
14
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_SNOOZE_ENABLE
;
}
else
if
(
!
strncmp
(
"uapsd_misbehaving="
,
buf
,
18
))
{
if
(
sscanf
(
buf
+
18
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_UAPSD_MISBEHAVING
;
}
else
{
return
-
EINVAL
;
}
mutex_lock
(
&
mvm
->
mutex
);
iwl_dbgfs_update_pm
(
mvm
,
vif
,
param
,
val
);
ret
=
iwl_mvm_power_update_mode
(
mvm
,
vif
);
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?:
count
;
}
static
ssize_t
iwl_dbgfs_pm_params_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
mvm
;
char
buf
[
512
];
int
bufsz
=
sizeof
(
buf
);
int
pos
;
pos
=
iwl_mvm_power_dbgfs_read
(
mvm
,
vif
,
buf
,
bufsz
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_mac_params_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
...
...
@@ -125,6 +269,201 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
void
iwl_dbgfs_update_bf
(
struct
ieee80211_vif
*
vif
,
enum
iwl_dbgfs_bf_mask
param
,
int
value
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_dbgfs_bf
*
dbgfs_bf
=
&
mvmvif
->
dbgfs_bf
;
dbgfs_bf
->
mask
|=
param
;
switch
(
param
)
{
case
MVM_DEBUGFS_BF_ENERGY_DELTA
:
dbgfs_bf
->
bf_energy_delta
=
value
;
break
;
case
MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA
:
dbgfs_bf
->
bf_roaming_energy_delta
=
value
;
break
;
case
MVM_DEBUGFS_BF_ROAMING_STATE
:
dbgfs_bf
->
bf_roaming_state
=
value
;
break
;
case
MVM_DEBUGFS_BF_TEMP_THRESHOLD
:
dbgfs_bf
->
bf_temp_threshold
=
value
;
break
;
case
MVM_DEBUGFS_BF_TEMP_FAST_FILTER
:
dbgfs_bf
->
bf_temp_fast_filter
=
value
;
break
;
case
MVM_DEBUGFS_BF_TEMP_SLOW_FILTER
:
dbgfs_bf
->
bf_temp_slow_filter
=
value
;
break
;
case
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
:
dbgfs_bf
->
bf_enable_beacon_filter
=
value
;
break
;
case
MVM_DEBUGFS_BF_DEBUG_FLAG
:
dbgfs_bf
->
bf_debug_flag
=
value
;
break
;
case
MVM_DEBUGFS_BF_ESCAPE_TIMER
:
dbgfs_bf
->
bf_escape_timer
=
value
;
break
;
case
MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT
:
dbgfs_bf
->
ba_enable_beacon_abort
=
value
;
break
;
case
MVM_DEBUGFS_BA_ESCAPE_TIMER
:
dbgfs_bf
->
ba_escape_timer
=
value
;
break
;
}
}
static
ssize_t
iwl_dbgfs_bf_params_write
(
struct
ieee80211_vif
*
vif
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
mvm
;
enum
iwl_dbgfs_bf_mask
param
;
int
value
,
ret
=
0
;
if
(
!
strncmp
(
"bf_energy_delta="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ENERGY_DELTA_MIN
||
value
>
IWL_BF_ENERGY_DELTA_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ENERGY_DELTA
;
}
else
if
(
!
strncmp
(
"bf_roaming_energy_delta="
,
buf
,
24
))
{
if
(
sscanf
(
buf
+
24
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ROAMING_ENERGY_DELTA_MIN
||
value
>
IWL_BF_ROAMING_ENERGY_DELTA_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA
;
}
else
if
(
!
strncmp
(
"bf_roaming_state="
,
buf
,
17
))
{
if
(
sscanf
(
buf
+
17
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ROAMING_STATE_MIN
||
value
>
IWL_BF_ROAMING_STATE_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ROAMING_STATE
;
}
else
if
(
!
strncmp
(
"bf_temp_threshold="
,
buf
,
18
))
{
if
(
sscanf
(
buf
+
18
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_TEMP_THRESHOLD_MIN
||
value
>
IWL_BF_TEMP_THRESHOLD_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_TEMP_THRESHOLD
;
}
else
if
(
!
strncmp
(
"bf_temp_fast_filter="
,
buf
,
20
))
{
if
(
sscanf
(
buf
+
20
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_TEMP_FAST_FILTER_MIN
||
value
>
IWL_BF_TEMP_FAST_FILTER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_TEMP_FAST_FILTER
;
}
else
if
(
!
strncmp
(
"bf_temp_slow_filter="
,
buf
,
20
))
{
if
(
sscanf
(
buf
+
20
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_TEMP_SLOW_FILTER_MIN
||
value
>
IWL_BF_TEMP_SLOW_FILTER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_TEMP_SLOW_FILTER
;
}
else
if
(
!
strncmp
(
"bf_enable_beacon_filter="
,
buf
,
24
))
{
if
(
sscanf
(
buf
+
24
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
0
||
value
>
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
;
}
else
if
(
!
strncmp
(
"bf_debug_flag="
,
buf
,
14
))
{
if
(
sscanf
(
buf
+
14
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
0
||
value
>
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_DEBUG_FLAG
;
}
else
if
(
!
strncmp
(
"bf_escape_timer="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BF_ESCAPE_TIMER_MIN
||
value
>
IWL_BF_ESCAPE_TIMER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BF_ESCAPE_TIMER
;
}
else
if
(
!
strncmp
(
"ba_escape_timer="
,
buf
,
16
))
{
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
IWL_BA_ESCAPE_TIMER_MIN
||
value
>
IWL_BA_ESCAPE_TIMER_MAX
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BA_ESCAPE_TIMER
;
}
else
if
(
!
strncmp
(
"ba_enable_beacon_abort="
,
buf
,
23
))
{
if
(
sscanf
(
buf
+
23
,
"%d"
,
&
value
)
!=
1
)
return
-
EINVAL
;
if
(
value
<
0
||
value
>
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT
;
}
else
{
return
-
EINVAL
;
}
mutex_lock
(
&
mvm
->
mutex
);
iwl_dbgfs_update_bf
(
vif
,
param
,
value
);
if
(
param
==
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
&&
!
value
)
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
);
else
ret
=
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
);
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?:
count
;
}
static
ssize_t
iwl_dbgfs_bf_params_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
char
buf
[
256
];
int
pos
=
0
;
const
size_t
bufsz
=
sizeof
(
buf
);
struct
iwl_beacon_filter_cmd
cmd
=
{
IWL_BF_CMD_CONFIG_DEFAULTS
,
.
bf_enable_beacon_filter
=
cpu_to_le32
(
IWL_BF_ENABLE_BEACON_FILTER_DEFAULT
),
.
ba_enable_beacon_abort
=
cpu_to_le32
(
IWL_BA_ENABLE_BEACON_ABORT_DEFAULT
),
};
iwl_mvm_beacon_filter_debugfs_parameters
(
vif
,
&
cmd
);
if
(
mvmvif
->
bf_data
.
bf_enabled
)
cmd
.
bf_enable_beacon_filter
=
cpu_to_le32
(
1
);
else
cmd
.
bf_enable_beacon_filter
=
0
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_energy_delta = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_energy_delta
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_roaming_energy_delta = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_roaming_energy_delta
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_roaming_state = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_roaming_state
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_temp_threshold = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_temp_threshold
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_temp_fast_filter = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_temp_fast_filter
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_temp_slow_filter = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_temp_slow_filter
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_enable_beacon_filter = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_enable_beacon_filter
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_debug_flag = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_debug_flag
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bf_escape_timer = %d
\n
"
,
le32_to_cpu
(
cmd
.
bf_escape_timer
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"ba_escape_timer = %d
\n
"
,
le32_to_cpu
(
cmd
.
ba_escape_timer
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"ba_enable_beacon_abort = %d
\n
"
,
le32_to_cpu
(
cmd
.
ba_enable_beacon_abort
));
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, vif, \
&iwl_dbgfs_##name##_ops)) \
...
...
@@ -132,6 +471,8 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
} while (0)
MVM_DEBUGFS_READ_FILE_OPS
(
mac_params
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
pm_params
,
32
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
bf_params
,
256
);
void
iwl_mvm_vif_dbgfs_register
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
...
...
@@ -155,9 +496,21 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return
;
}
if
(
iwlmvm_mod_params
.
power_scheme
!=
IWL_POWER_SCHEME_CAM
&&
((
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
)
||
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
vif
->
p2p
&&
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_P2P_PS
)))
MVM_DEBUGFS_ADD_FILE_VIF
(
pm_params
,
mvmvif
->
dbgfs_dir
,
S_IWUSR
|
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE_VIF
(
mac_params
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
);
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
&&
mvmvif
==
mvm
->
bf_allowed_vif
)
MVM_DEBUGFS_ADD_FILE_VIF
(
bf_params
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
|
S_IWUSR
);
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
View file @
623c4387
...
...
@@ -85,6 +85,8 @@
* PBW Snoozing enabled
* @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
* @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
* @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving
* detection enablement
*/
enum
iwl_power_flags
{
POWER_FLAGS_POWER_SAVE_ENA_MSK
=
BIT
(
0
),
...
...
@@ -94,6 +96,7 @@ enum iwl_power_flags {
POWER_FLAGS_BT_SCO_ENA
=
BIT
(
8
),
POWER_FLAGS_ADVANCE_PM_ENA_MSK
=
BIT
(
9
),
POWER_FLAGS_LPRX_ENA_MSK
=
BIT
(
11
),
POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK
=
BIT
(
12
),
};
#define IWL_POWER_VEC_SIZE 5
...
...
@@ -228,6 +231,19 @@ struct iwl_mac_power_cmd {
u8
reserved
;
}
__packed
;
/*
* struct iwl_uapsd_misbehaving_ap_notif - FW sends this notification when
* associated AP is identified as improperly implementing uAPSD protocol.
* PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78
* @sta_id: index of station in uCode's station table - associated AP ID in
* this context.
*/
struct
iwl_uapsd_misbehaving_ap_notif
{
__le32
sta_id
;
u8
mac_id
;
u8
reserved
[
3
];
}
__packed
;
/**
* struct iwl_beacon_filter_cmd
* REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
View file @
623c4387
...
...
@@ -138,7 +138,14 @@ enum iwl_sta_flags {
/**
* enum iwl_sta_key_flag - key flags for the ADD_STA host command
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithm
* @STA_KEY_FLG_NO_ENC: no encryption
* @STA_KEY_FLG_WEP: WEP encryption algorithm
* @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_CMAC: CMAC encryption algorithm
* @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
* @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
* station info array (1 - n 1X mode)
* @STA_KEY_FLG_KEYID_MSK: the index of the key
...
...
@@ -152,6 +159,7 @@ enum iwl_sta_key_flag {
STA_KEY_FLG_WEP
=
(
1
<<
0
),
STA_KEY_FLG_CCM
=
(
2
<<
0
),
STA_KEY_FLG_TKIP
=
(
3
<<
0
),
STA_KEY_FLG_EXT
=
(
4
<<
0
),
STA_KEY_FLG_CMAC
=
(
6
<<
0
),
STA_KEY_FLG_ENC_UNKNOWN
=
(
7
<<
0
),
STA_KEY_FLG_EN_MSK
=
(
7
<<
0
),
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
View file @
623c4387
...
...
@@ -132,6 +132,7 @@ enum iwl_tx_flags {
#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
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api.h
View file @
623c4387
...
...
@@ -141,6 +141,7 @@ enum {
/* Power - legacy power table command */
POWER_TABLE_CMD
=
0x77
,
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION
=
0x78
,
/* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF
=
0x7e
,
...
...
@@ -183,6 +184,7 @@ enum {
BT_PROFILE_NOTIFICATION
=
0xce
,
BT_COEX_CI
=
0x5d
,
REPLY_SF_CFG_CMD
=
0xd1
,
REPLY_BEACON_FILTERING_CMD
=
0xd2
,
REPLY_DEBUG_CMD
=
0xf0
,
...
...
@@ -1052,6 +1054,7 @@ enum iwl_mvm_rx_status {
RX_MPDU_RES_STATUS_SEC_WEP_ENC
=
(
1
<<
8
),
RX_MPDU_RES_STATUS_SEC_CCM_ENC
=
(
2
<<
8
),
RX_MPDU_RES_STATUS_SEC_TKIP_ENC
=
(
3
<<
8
),
RX_MPDU_RES_STATUS_SEC_EXT_ENC
=
(
4
<<
8
),
RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC
=
(
6
<<
8
),
RX_MPDU_RES_STATUS_SEC_ENC_ERR
=
(
7
<<
8
),
RX_MPDU_RES_STATUS_SEC_ENC_MSK
=
(
7
<<
8
),
...
...
@@ -1131,6 +1134,7 @@ struct iwl_set_calib_default_cmd {
}
__packed
;
/* PHY_CALIB_OVERRIDE_VALUES_S */
#define MAX_PORT_ID_NUM 2
#define MAX_MCAST_FILTERING_ADDRESSES 256
/**
* struct iwl_mcast_filter_cmd - configure multicast filter.
...
...
@@ -1363,4 +1367,65 @@ struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
struct
mvm_statistics_general
general
;
}
__packed
;
/***********************************
* Smart Fifo API
***********************************/
/* Smart Fifo state */
enum
iwl_sf_state
{
SF_LONG_DELAY_ON
=
0
,
/* should never be called by driver */
SF_FULL_ON
,
SF_UNINIT
,
SF_INIT_OFF
,
SF_HW_NUM_STATES
};
/* Smart Fifo possible scenario */
enum
iwl_sf_scenario
{
SF_SCENARIO_SINGLE_UNICAST
,
SF_SCENARIO_AGG_UNICAST
,
SF_SCENARIO_MULTICAST
,
SF_SCENARIO_BA_RESP
,
SF_SCENARIO_TX_RESP
,
SF_NUM_SCENARIO
};
#define SF_TRANSIENT_STATES_NUMBER 2
/* SF_LONG_DELAY_ON and SF_FULL_ON */
#define SF_NUM_TIMEOUT_TYPES 2
/* Aging timer and Idle timer */
/* smart FIFO default values */
#define SF_W_MARK_SISO 4096
#define SF_W_MARK_MIMO2 8192
#define SF_W_MARK_MIMO3 6144
#define SF_W_MARK_LEGACY 4096
#define SF_W_MARK_SCAN 4096
/* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */
#define SF_SINGLE_UNICAST_IDLE_TIMER 320
/* 300 uSec */
#define SF_SINGLE_UNICAST_AGING_TIMER 2016
/* 2 mSec */
#define SF_AGG_UNICAST_IDLE_TIMER 320
/* 300 uSec */
#define SF_AGG_UNICAST_AGING_TIMER 2016
/* 2 mSec */
#define SF_MCAST_IDLE_TIMER 2016
/* 2 mSec */
#define SF_MCAST_AGING_TIMER 10016
/* 10 mSec */
#define SF_BA_IDLE_TIMER 320
/* 300 uSec */
#define SF_BA_AGING_TIMER 2016
/* 2 mSec */
#define SF_TX_RE_IDLE_TIMER 320
/* 300 uSec */
#define SF_TX_RE_AGING_TIMER 2016
/* 2 mSec */
#define SF_LONG_DELAY_AGING_TIMER 1000000
/* 1 Sec */
/**
* Smart Fifo configuration command.
* @state: smart fifo state, types listed in iwl_sf_sate.
* @watermark: Minimum allowed availabe free space in RXF for transient state.
* @long_delay_timeouts: aging and idle timer values for each scenario
* in long delay state.
* @full_on_timeouts: timer values for each scenario in full on state.
*/
struct
iwl_sf_cfg_cmd
{
enum
iwl_sf_state
state
;
__le32
watermark
[
SF_TRANSIENT_STATES_NUMBER
];
__le32
long_delay_timeouts
[
SF_NUM_SCENARIO
][
SF_NUM_TIMEOUT_TYPES
];
__le32
full_on_timeouts
[
SF_NUM_SCENARIO
][
SF_NUM_TIMEOUT_TYPES
];
}
__packed
;
/* SF_CFG_API_S_VER_2 */
#endif
/* __fw_api_h__ */
drivers/net/wireless/iwlwifi/mvm/fw.c
View file @
623c4387
...
...
@@ -241,7 +241,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
mvm
->
init_ucode_complete
)
if
(
WARN_ON_ONCE
(
mvm
->
init_ucode_complete
)
)
return
0
;
iwl_init_notification_wait
(
&
mvm
->
notif_wait
,
...
...
@@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
IWL_DEBUG_RF_KILL
(
mvm
,
"jump over all phy activities due to RF kill
\n
"
);
iwl_remove_notification
(
&
mvm
->
notif_wait
,
&
calib_wait
);
return
1
;
ret
=
1
;
goto
out
;
}
/* Send TX valid antennas before triggering calibrations */
...
...
@@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
error:
iwl_remove_notification
(
&
mvm
->
notif_wait
,
&
calib_wait
);
out:
if
(
!
iwlmvm_mod_params
.
init_dbg
)
{
iwl_trans_stop_device
(
mvm
->
trans
);
}
else
if
(
!
mvm
->
nvm_data
)
{
if
(
iwlmvm_mod_params
.
init_dbg
&&
!
mvm
->
nvm_data
)
{
/* we want to debug INIT and we have no NVM - fake */
mvm
->
nvm_data
=
kzalloc
(
sizeof
(
struct
iwl_nvm_data
)
+
sizeof
(
struct
ieee80211_channel
)
+
...
...
@@ -370,11 +369,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
ret
=
-
ERFKILL
;
goto
error
;
}
/* should stop & start HW since that INIT image just loaded */
iwl_trans_stop_hw
(
mvm
->
trans
,
false
);
ret
=
iwl_trans_start_hw
(
mvm
->
trans
);
if
(
ret
)
return
ret
;
if
(
!
iwlmvm_mod_params
.
init_dbg
)
{
/*
* should stop and start HW since that INIT
* image just loaded
*/
iwl_trans_stop_device
(
mvm
->
trans
);
ret
=
iwl_trans_start_hw
(
mvm
->
trans
);
if
(
ret
)
return
ret
;
}
}
if
(
iwlmvm_mod_params
.
init_dbg
)
...
...
@@ -386,6 +390,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto
error
;
}
ret
=
iwl_mvm_sf_update
(
mvm
,
NULL
,
false
);
if
(
ret
)
IWL_ERR
(
mvm
,
"Failed to initialize Smart Fifo
\n
"
);
ret
=
iwl_send_tx_ant_cfg
(
mvm
,
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
if
(
ret
)
goto
error
;
...
...
drivers/net/wireless/iwlwifi/mvm/mac80211.c
View file @
623c4387
...
...
@@ -261,6 +261,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
mvm
->
rts_threshold
=
IEEE80211_MAX_RTS_THRESHOLD
;
/* currently FW API supports only one optional cipher scheme */
if
(
mvm
->
fw
->
cs
&&
mvm
->
fw
->
cs
->
cipher
)
{
mvm
->
hw
->
n_cipher_schemes
=
1
;
mvm
->
hw
->
cipher_schemes
=
mvm
->
fw
->
cs
;
}
#ifdef CONFIG_PM_SLEEP
if
(
mvm
->
fw
->
img
[
IWL_UCODE_WOWLAN
].
sec
[
0
].
len
&&
mvm
->
trans
->
ops
->
d3_suspend
&&
...
...
@@ -399,7 +405,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
static
void
iwl_mvm_restart_cleanup
(
struct
iwl_mvm
*
mvm
)
{
iwl_trans_stop_device
(
mvm
->
trans
);
iwl_trans_stop_hw
(
mvm
->
trans
,
false
);
mvm
->
scan_status
=
IWL_MVM_SCAN_NONE
;
...
...
@@ -471,7 +476,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync
(
&
mvm
->
roc_done_wk
);
iwl_trans_stop_device
(
mvm
->
trans
);
iwl_trans_stop_hw
(
mvm
->
trans
,
false
);
iwl_mvm_async_handlers_purge
(
mvm
);
/* async_handlers_list is empty and will stay empty: HW is stopped */
...
...
@@ -488,17 +492,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync
(
&
mvm
->
async_handlers_wk
);
}
static
void
iwl_mvm_pm_disable_iterator
(
void
*
data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm
*
mvm
=
data
;
int
ret
;
ret
=
iwl_mvm_power_disable
(
mvm
,
vif
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to disable power management
\n
"
);
}
static
void
iwl_mvm_power_update_iterator
(
void
*
data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
...
...
@@ -521,6 +514,20 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
return
NULL
;
}
static
int
iwl_mvm_set_tx_power
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
s8
tx_power
)
{
/* FW is in charge of regulatory enforcement */
struct
iwl_reduce_tx_power_cmd
reduce_txpwr_cmd
=
{
.
mac_context_id
=
iwl_mvm_vif_from_mac80211
(
vif
)
->
id
,
.
pwr_restriction
=
cpu_to_le16
(
tx_power
),
};
return
iwl_mvm_send_cmd_pdu
(
mvm
,
REDUCE_TX_POWER_CMD
,
CMD_SYNC
,
sizeof
(
reduce_txpwr_cmd
),
&
reduce_txpwr_cmd
);
}
static
int
iwl_mvm_mac_add_interface
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
)
{
...
...
@@ -541,26 +548,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if
(
ret
)
goto
out_unlock
;
/*
* TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC.
* If new interface added, disable PM on existing interface.
* P2P device is a special case, since it is handled by FW similary to
* scan. If P2P deviced is added, PM remains enabled on existing
* interface.
* Note: the method below does not count the new interface being added
* at this moment.
*/
/* Counting number of interfaces is needed for legacy PM */
if
(
vif
->
type
!=
NL80211_IFTYPE_P2P_DEVICE
)
mvm
->
vif_count
++
;
if
(
mvm
->
vif_count
>
1
)
{
IWL_DEBUG_MAC80211
(
mvm
,
"Disable power on existing interfaces
\n
"
);
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_pm_disable_iterator
,
mvm
);
}
/*
* The AP binding flow can be done only after the beacon
...
...
@@ -591,11 +581,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if
(
ret
)
goto
out_release
;
/*
* Update power state on the new interface. Admittedly, based on
* mac80211 logics this power update will disable power management
*/
iwl_mvm_power_update_mode
(
mvm
,
vif
);
iwl_mvm_power_disable
(
mvm
,
vif
);
/* beacon filtering */
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
);
...
...
@@ -656,9 +642,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
out_release:
if
(
vif
->
type
!=
NL80211_IFTYPE_P2P_DEVICE
)
mvm
->
vif_count
--
;
/* TODO: remove this when legacy PM will be discarded */
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_update_iterator
,
mvm
);
iwl_mvm_mac_ctxt_release
(
mvm
,
vif
);
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
...
...
@@ -744,21 +733,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvmvif
->
phy_ctxt
=
NULL
;
}
/*
* TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC.
* Check if only one additional interface remains after removing
* current one. Update power mode on the remaining interface.
*/
if
(
mvm
->
vif_count
&&
vif
->
type
!=
NL80211_IFTYPE_P2P_DEVICE
)
mvm
->
vif_count
--
;
IWL_DEBUG_MAC80211
(
mvm
,
"Currently %d interfaces active
\n
"
,
mvm
->
vif_count
);
if
(
mvm
->
vif_count
==
1
)
{
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_update_iterator
,
mvm
);
}
/* TODO: remove this when legacy PM will be discarded */
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_update_iterator
,
mvm
);
iwl_mvm_mac_ctxt_remove
(
mvm
,
vif
);
...
...
@@ -767,23 +748,91 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mutex_unlock
(
&
mvm
->
mutex
);
}
static
int
iwl_mvm_set_tx_power
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
s8
tx_power
)
static
int
iwl_mvm_mac_config
(
struct
ieee80211_hw
*
hw
,
u32
changed
)
{
/* FW is in charge of regulatory enforcement */
struct
iwl_reduce_tx_power_cmd
reduce_txpwr_cmd
=
{
.
mac_context_id
=
iwl_mvm_vif_from_mac80211
(
vif
)
->
id
,
.
pwr_restriction
=
cpu_to_le16
(
tx_power
),
return
0
;
}
struct
iwl_mvm_mc_iter_data
{
struct
iwl_mvm
*
mvm
;
int
port_id
;
};
static
void
iwl_mvm_mc_iface_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_mc_iter_data
*
data
=
_data
;
struct
iwl_mvm
*
mvm
=
data
->
mvm
;
struct
iwl_mcast_filter_cmd
*
cmd
=
mvm
->
mcast_filter_cmd
;
int
ret
,
len
;
/* if we don't have free ports, mcast frames will be dropped */
if
(
WARN_ON_ONCE
(
data
->
port_id
>=
MAX_PORT_ID_NUM
))
return
;
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
!
vif
->
bss_conf
.
assoc
)
return
;
cmd
->
port_id
=
data
->
port_id
++
;
memcpy
(
cmd
->
bssid
,
vif
->
bss_conf
.
bssid
,
ETH_ALEN
);
len
=
roundup
(
sizeof
(
*
cmd
)
+
cmd
->
count
*
ETH_ALEN
,
4
);
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
MCAST_FILTER_CMD
,
CMD_SYNC
,
len
,
cmd
);
if
(
ret
)
IWL_ERR
(
mvm
,
"mcast filter cmd error. ret=%d
\n
"
,
ret
);
}
static
void
iwl_mvm_recalc_multicast
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_mvm_mc_iter_data
iter_data
=
{
.
mvm
=
mvm
,
};
return
iwl_mvm_send_cmd_pdu
(
mvm
,
REDUCE_TX_POWER_CMD
,
CMD_SYNC
,
sizeof
(
reduce_txpwr_cmd
),
&
reduce_txpwr_cmd
);
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
WARN_ON_ONCE
(
!
mvm
->
mcast_filter_cmd
))
return
;
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_mc_iface_iterator
,
&
iter_data
);
}
static
int
iwl_mvm_mac_config
(
struct
ieee80211_hw
*
hw
,
u32
changed
)
static
u64
iwl_mvm_prepare_multicast
(
struct
ieee80211_hw
*
hw
,
struct
netdev_hw_addr_list
*
mc_list
)
{
return
0
;
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_mcast_filter_cmd
*
cmd
;
struct
netdev_hw_addr
*
addr
;
int
addr_count
=
netdev_hw_addr_list_count
(
mc_list
);
bool
pass_all
=
false
;
int
len
;
if
(
addr_count
>
MAX_MCAST_FILTERING_ADDRESSES
)
{
pass_all
=
true
;
addr_count
=
0
;
}
len
=
roundup
(
sizeof
(
*
cmd
)
+
addr_count
*
ETH_ALEN
,
4
);
cmd
=
kzalloc
(
len
,
GFP_ATOMIC
);
if
(
!
cmd
)
return
0
;
if
(
pass_all
)
{
cmd
->
pass_all
=
1
;
return
(
u64
)(
unsigned
long
)
cmd
;
}
netdev_hw_addr_list_for_each
(
addr
,
mc_list
)
{
IWL_DEBUG_MAC80211
(
mvm
,
"mcast addr (%d): %pM
\n
"
,
cmd
->
count
,
addr
->
addr
);
memcpy
(
&
cmd
->
addr_list
[
cmd
->
count
*
ETH_ALEN
],
addr
->
addr
,
ETH_ALEN
);
cmd
->
count
++
;
}
return
(
u64
)(
unsigned
long
)
cmd
;
}
static
void
iwl_mvm_configure_filter
(
struct
ieee80211_hw
*
hw
,
...
...
@@ -791,21 +840,22 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
unsigned
int
*
total_flags
,
u64
multicast
)
{
*
total_flags
=
0
;
}
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
)
;
struct
iwl_mcast_filter_cmd
*
cmd
=
(
void
*
)(
unsigned
long
)
multicast
;
static
int
iwl_mvm_configure_mcast_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mcast_filter_cmd
mcast_filter_cmd
=
{
.
pass_all
=
1
,
};
mutex_lock
(
&
mvm
->
mutex
);
/* replace previous configuration */
kfree
(
mvm
->
mcast_filter_cmd
);
mvm
->
mcast_filter_cmd
=
cmd
;
memcpy
(
mcast_filter_cmd
.
bssid
,
vif
->
bss_conf
.
bssid
,
ETH_ALEN
);
if
(
!
cmd
)
goto
out
;
return
iwl_mvm_send_cmd_pdu
(
mvm
,
MCAST_FILTER_CMD
,
CMD_SYNC
,
sizeof
(
mcast_filter_cmd
),
&
mcast_filter_cmd
);
iwl_mvm_recalc_multicast
(
mvm
);
out:
mutex_unlock
(
&
mvm
->
mutex
);
*
total_flags
=
0
;
}
static
void
iwl_mvm_bss_info_changed_station
(
struct
iwl_mvm
*
mvm
,
...
...
@@ -828,7 +878,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR
(
mvm
,
"failed to update quotas
\n
"
);
return
;
}
iwl_mvm_configure_mcast_filter
(
mvm
,
vif
);
if
(
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
))
{
...
...
@@ -850,7 +899,17 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
iwl_mvm_protect_session
(
mvm
,
vif
,
dur
,
dur
,
5
*
dur
);
}
iwl_mvm_sf_update
(
mvm
,
vif
,
false
);
iwl_mvm_power_vif_assoc
(
mvm
,
vif
);
}
else
if
(
mvmvif
->
ap_sta_id
!=
IWL_MVM_STATION_COUNT
)
{
/*
* If update fails - SF might be running in associated
* mode while disassociated - which is forbidden.
*/
WARN_ONCE
(
iwl_mvm_sf_update
(
mvm
,
vif
,
false
),
"Failed to update SF upon disassociation
\n
"
);
/* remove AP station now that the MAC is unassoc */
ret
=
iwl_mvm_rm_sta_id
(
mvm
,
vif
,
mvmvif
->
ap_sta_id
);
if
(
ret
)
...
...
@@ -862,6 +921,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR
(
mvm
,
"failed to update quotas
\n
"
);
}
iwl_mvm_recalc_multicast
(
mvm
);
/* reset rssi values */
mvmvif
->
bf_data
.
ave_beacon_signal
=
0
;
...
...
@@ -882,7 +943,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
iwl_mvm_remove_time_event
(
mvm
,
mvmvif
,
&
mvmvif
->
time_event_data
);
}
else
if
(
changes
&
(
BSS_CHANGED_PS
|
BSS_CHANGED_QOS
))
{
}
else
if
(
changes
&
(
BSS_CHANGED_PS
|
BSS_CHANGED_P2P_PS
|
BSS_CHANGED_QOS
))
{
ret
=
iwl_mvm_power_update_mode
(
mvm
,
vif
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to update power mode
\n
"
);
...
...
@@ -991,11 +1053,16 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changes
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
enum
ieee80211_bss_change
ht_change
=
BSS_CHANGED_ERP_CTS_PROT
|
BSS_CHANGED_HT
|
BSS_CHANGED_BANDWIDTH
;
int
ret
;
/* Changes will be applied when the AP/IBSS is started */
if
(
!
mvmvif
->
ap_ibss_active
)
return
;
if
(
changes
&
ht_change
)
{
ret
=
iwl_mvm_mac_ctxt_changed
(
mvm
,
vif
);
if
(
ret
)
...
...
@@ -1222,6 +1289,17 @@ static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return
0
;
}
static
void
iwl_mvm_sta_rc_update
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
u32
changed
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
changed
&
IEEE80211_RC_NSS_CHANGED
)
iwl_mvm_sf_update
(
mvm
,
vif
,
false
);
}
static
int
iwl_mvm_mac_conf_tx
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
u16
ac
,
const
struct
ieee80211_tx_queue_params
*
params
)
...
...
@@ -1344,7 +1422,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
*/
return
0
;
default:
return
-
EOPNOTSUPP
;
/* currently FW supports only one optional cipher scheme */
if
(
hw
->
n_cipher_schemes
&&
hw
->
cipher_schemes
->
cipher
==
key
->
cipher
)
key
->
flags
|=
IEEE80211_KEY_FLAG_PUT_IV_SPACE
;
else
return
-
EOPNOTSUPP
;
}
mutex_lock
(
&
mvm
->
mutex
);
...
...
@@ -1550,7 +1633,7 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
goto
out
;
}
ret
=
iwl_mvm_phy_ctxt_changed
(
mvm
,
phy_ctxt
,
&
ctx
->
def
,
ret
=
iwl_mvm_phy_ctxt_changed
(
mvm
,
phy_ctxt
,
&
ctx
->
min_
def
,
ctx
->
rx_chains_static
,
ctx
->
rx_chains_dynamic
);
if
(
ret
)
{
...
...
@@ -1594,7 +1677,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
return
;
mutex_lock
(
&
mvm
->
mutex
);
iwl_mvm_phy_ctxt_changed
(
mvm
,
phy_ctxt
,
&
ctx
->
def
,
iwl_mvm_phy_ctxt_changed
(
mvm
,
phy_ctxt
,
&
ctx
->
min_
def
,
ctx
->
rx_chains_static
,
ctx
->
rx_chains_dynamic
);
iwl_mvm_bt_coex_vif_change
(
mvm
);
...
...
@@ -1637,7 +1720,13 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
goto
out_unlock
;
/*
* Setting the quota at this stage is only required for monitor
* Power state must be updated before quotas,
* otherwise fw will complain.
*/
mvm
->
bound_vif_cnt
++
;
iwl_mvm_power_update_binding
(
mvm
,
vif
,
true
);
/* Setting the quota at this stage is only required for monitor
* interfaces. For the other types, the bss_info changed flow
* will handle quota settings.
*/
...
...
@@ -1652,6 +1741,8 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
out_remove_binding:
iwl_mvm_binding_remove_vif
(
mvm
,
vif
);
mvm
->
bound_vif_cnt
--
;
iwl_mvm_power_update_binding
(
mvm
,
vif
,
false
);
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
if
(
ret
)
...
...
@@ -1685,6 +1776,9 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_binding_remove_vif
(
mvm
,
vif
);
out_unlock:
mvmvif
->
phy_ctxt
=
NULL
;
mvm
->
bound_vif_cnt
--
;
iwl_mvm_power_update_binding
(
mvm
,
vif
,
false
);
mutex_unlock
(
&
mvm
->
mutex
);
}
...
...
@@ -1779,6 +1873,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.
add_interface
=
iwl_mvm_mac_add_interface
,
.
remove_interface
=
iwl_mvm_mac_remove_interface
,
.
config
=
iwl_mvm_mac_config
,
.
prepare_multicast
=
iwl_mvm_prepare_multicast
,
.
configure_filter
=
iwl_mvm_configure_filter
,
.
bss_info_changed
=
iwl_mvm_bss_info_changed
,
.
hw_scan
=
iwl_mvm_mac_hw_scan
,
...
...
@@ -1788,6 +1883,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.
sta_notify
=
iwl_mvm_mac_sta_notify
,
.
allow_buffered_frames
=
iwl_mvm_mac_allow_buffered_frames
,
.
set_rts_threshold
=
iwl_mvm_mac_set_rts_threshold
,
.
sta_rc_update
=
iwl_mvm_sta_rc_update
,
.
conf_tx
=
iwl_mvm_mac_conf_tx
,
.
mgd_prepare_tx
=
iwl_mvm_mac_mgd_prepare_tx
,
.
sched_scan_start
=
iwl_mvm_mac_sched_scan_start
,
...
...
drivers/net/wireless/iwlwifi/mvm/mvm.h
View file @
623c4387
...
...
@@ -163,6 +163,8 @@ struct iwl_mvm_power_ops {
struct
ieee80211_vif
*
vif
);
int
(
*
power_update_device_mode
)(
struct
iwl_mvm
*
mvm
);
int
(
*
power_disable
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
void
(
*
power_update_binding
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
assign
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int
(
*
power_dbgfs_read
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
int
bufsz
);
...
...
@@ -181,6 +183,7 @@ enum iwl_dbgfs_pm_mask {
MVM_DEBUGFS_PM_LPRX_ENA
=
BIT
(
6
),
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
=
BIT
(
7
),
MVM_DEBUGFS_PM_SNOOZE_ENABLE
=
BIT
(
8
),
MVM_DEBUGFS_PM_UAPSD_MISBEHAVING
=
BIT
(
9
),
};
struct
iwl_dbgfs_pm
{
...
...
@@ -193,6 +196,7 @@ struct iwl_dbgfs_pm {
bool
lprx_ena
;
u32
lprx_rssi_threshold
;
bool
snooze_ena
;
bool
uapsd_misbehaving
;
int
mask
;
};
...
...
@@ -269,8 +273,8 @@ struct iwl_mvm_vif_bf_data {
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
* @beacon_skb: the skb used to hold the AP/GO beacon template
* @smps_requests: the
requests of of differents parts of the driver, regard
the desired smps mode
.
* @smps_requests: the
SMPS requests of differents parts of the driver,
* combined on update to yield the overall request to mac80211
.
*/
struct
iwl_mvm_vif
{
u16
id
;
...
...
@@ -331,6 +335,11 @@ struct iwl_mvm_vif {
#endif
enum
ieee80211_smps_mode
smps_requests
[
NUM_IWL_MVM_SMPS_REQ
];
/* FW identified misbehaving AP */
u8
uapsd_misbehaving_bssid
[
ETH_ALEN
];
bool
pm_prevented
;
};
static
inline
struct
iwl_mvm_vif
*
...
...
@@ -479,6 +488,7 @@ struct iwl_mvm {
/* Scan status, cmd (pre-allocated) and auxiliary station */
enum
iwl_scan_status
scan_status
;
struct
iwl_scan_cmd
*
scan_cmd
;
struct
iwl_mcast_filter_cmd
*
mcast_filter_cmd
;
/* rx chain antennas set through debugfs for the scan command */
u8
scan_rx_ant
;
...
...
@@ -489,6 +499,9 @@ struct iwl_mvm {
u8
scan_last_antenna_idx
;
/* to toggle TX between antennas */
u8
mgmt_last_antenna_idx
;
/* last smart fifo state that was successfully sent to firmware */
enum
iwl_sf_state
sf_state
;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct
dentry
*
debugfs_dir
;
u32
dbgfs_sram_offset
,
dbgfs_sram_len
;
...
...
@@ -512,12 +525,6 @@ struct iwl_mvm {
*/
unsigned
long
fw_key_table
[
BITS_TO_LONGS
(
STA_KEY_MAX_NUM
)];
/*
* This counter of created interfaces is referenced only in conjunction
* with FW limitation related to power management. Currently PM is
* supported only on a single interface.
* IMPORTANT: this variable counts all interfaces except P2P device.
*/
u8
vif_count
;
/* -1 for always, 0 for never, >0 for that many times */
...
...
@@ -560,6 +567,11 @@ struct iwl_mvm {
u8
aux_queue
;
u8
first_agg_queue
;
u8
last_agg_queue
;
u8
bound_vif_cnt
;
/* Indicate if device power save is allowed */
bool
ps_prevented
;
};
/* Extract MVM priv from op_mode and _hw */
...
...
@@ -778,6 +790,19 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
return
0
;
}
static
inline
void
iwl_mvm_power_update_binding
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
assign
)
{
if
(
mvm
->
pm_ops
->
power_update_binding
)
mvm
->
pm_ops
->
power_update_binding
(
mvm
,
vif
,
assign
);
}
void
iwl_mvm_power_vif_assoc
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
int
iwl_mvm_power_uapsd_misbehaving_ap_notif
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
inline
int
iwl_mvm_power_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
...
...
@@ -869,4 +894,8 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
void
iwl_mvm_tt_exit
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_set_hw_ctkill_state
(
struct
iwl_mvm
*
mvm
,
bool
state
);
/* smart fifo */
int
iwl_mvm_sf_update
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
added_vif
);
#endif
/* __IWL_MVM_H__ */
drivers/net/wireless/iwlwifi/mvm/ops.c
View file @
623c4387
...
...
@@ -236,6 +236,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
false
),
RX_HANDLER
(
REPLY_ERROR
,
iwl_mvm_rx_fw_error
,
false
),
RX_HANDLER
(
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION
,
iwl_mvm_power_uapsd_misbehaving_ap_notif
,
false
),
};
#undef RX_HANDLER
#define CMD(x) [x] = #x
...
...
@@ -311,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD
(
REPLY_THERMAL_MNG_BACKOFF
),
CMD
(
MAC_PM_POWER_TABLE
),
CMD
(
BT_COEX_CI
),
CMD
(
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION
),
};
#undef CMD
...
...
@@ -341,7 +344,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
op_mode
=
hw
->
priv
;
op_mode
->
ops
=
&
iwl_mvm_ops
;
op_mode
->
trans
=
trans
;
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
mvm
->
dev
=
trans
->
dev
;
...
...
@@ -359,6 +361,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm
->
aux_queue
=
11
;
mvm
->
first_agg_queue
=
12
;
}
mvm
->
sf_state
=
SF_UNINIT
;
mutex_init
(
&
mvm
->
mutex
);
spin_lock_init
(
&
mvm
->
async_handlers_lock
);
...
...
@@ -424,7 +427,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
* there is no need to unnecessarily power up the NIC at driver load
*/
if
(
iwlwifi_mod_params
.
nvm_file
)
{
iwl_nvm_init
(
mvm
);
err
=
iwl_nvm_init
(
mvm
);
if
(
err
)
goto
out_free
;
}
else
{
err
=
iwl_trans_start_hw
(
mvm
->
trans
);
if
(
err
)
...
...
@@ -432,16 +437,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock
(
&
mvm
->
mutex
);
err
=
iwl_run_init_mvm_ucode
(
mvm
,
true
);
iwl_trans_stop_device
(
trans
);
mutex_unlock
(
&
mvm
->
mutex
);
/* returns 0 if successful, 1 if success but in rfkill */
if
(
err
<
0
&&
!
iwlmvm_mod_params
.
init_dbg
)
{
IWL_ERR
(
mvm
,
"Failed to run INIT ucode: %d
\n
"
,
err
);
goto
out_free
;
}
/* Stop the hw after the ALIVE and NVM has been read */
if
(
!
iwlmvm_mod_params
.
init_dbg
)
iwl_trans_stop_hw
(
mvm
->
trans
,
false
);
}
scan_size
=
sizeof
(
struct
iwl_scan_cmd
)
+
...
...
@@ -474,7 +476,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_phy_db_free
(
mvm
->
phy_db
);
kfree
(
mvm
->
scan_cmd
);
if
(
!
iwlwifi_mod_params
.
nvm_file
)
iwl_trans_
stop_hw
(
trans
,
true
);
iwl_trans_
op_mode_leave
(
trans
);
ieee80211_free_hw
(
mvm
->
hw
);
return
NULL
;
}
...
...
@@ -491,12 +493,14 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw
(
mvm
->
hw
);
kfree
(
mvm
->
scan_cmd
);
kfree
(
mvm
->
mcast_filter_cmd
);
mvm
->
mcast_filter_cmd
=
NULL
;
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree
(
mvm
->
d3_resume_sram
);
#endif
iwl_trans_
stop_hw
(
mvm
->
trans
,
true
);
iwl_trans_
op_mode_leave
(
mvm
->
trans
);
iwl_phy_db_free
(
mvm
->
phy_db
);
mvm
->
phy_db
=
NULL
;
...
...
drivers/net/wireless/iwlwifi/mvm/power.c
View file @
623c4387
...
...
@@ -186,6 +186,92 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm,
}
}
static
void
iwl_mvm_power_configure_uapsd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_mac_power_cmd
*
cmd
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
enum
ieee80211_ac_numbers
ac
;
bool
tid_found
=
false
;
for
(
ac
=
IEEE80211_AC_VO
;
ac
<=
IEEE80211_AC_BK
;
ac
++
)
{
if
(
!
mvmvif
->
queue_params
[
ac
].
uapsd
)
continue
;
if
(
mvm
->
cur_ucode
!=
IWL_UCODE_WOWLAN
)
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
);
cmd
->
uapsd_ac_flags
|=
BIT
(
ac
);
/* QNDP TID - the highest TID with no admission control */
if
(
!
tid_found
&&
!
mvmvif
->
queue_params
[
ac
].
acm
)
{
tid_found
=
true
;
switch
(
ac
)
{
case
IEEE80211_AC_VO
:
cmd
->
qndp_tid
=
6
;
break
;
case
IEEE80211_AC_VI
:
cmd
->
qndp_tid
=
5
;
break
;
case
IEEE80211_AC_BE
:
cmd
->
qndp_tid
=
0
;
break
;
case
IEEE80211_AC_BK
:
cmd
->
qndp_tid
=
1
;
break
;
}
}
}
if
(
!
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
)))
return
;
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK
);
if
(
cmd
->
uapsd_ac_flags
==
(
BIT
(
IEEE80211_AC_VO
)
|
BIT
(
IEEE80211_AC_VI
)
|
BIT
(
IEEE80211_AC_BE
)
|
BIT
(
IEEE80211_AC_BK
)))
{
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
);
cmd
->
snooze_interval
=
cpu_to_le16
(
IWL_MVM_PS_SNOOZE_INTERVAL
);
cmd
->
snooze_window
=
(
mvm
->
cur_ucode
==
IWL_UCODE_WOWLAN
)
?
cpu_to_le16
(
IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW
)
:
cpu_to_le16
(
IWL_MVM_PS_SNOOZE_WINDOW
);
}
cmd
->
uapsd_max_sp
=
IWL_UAPSD_MAX_SP
;
if
(
mvm
->
cur_ucode
==
IWL_UCODE_WOWLAN
||
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
))
{
cmd
->
rx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT
);
cmd
->
tx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT
);
}
else
{
cmd
->
rx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_UAPSD_RX_DATA_TIMEOUT
);
cmd
->
tx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_UAPSD_TX_DATA_TIMEOUT
);
}
if
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
))
{
cmd
->
heavy_tx_thld_packets
=
IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS
;
cmd
->
heavy_rx_thld_packets
=
IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS
;
}
else
{
cmd
->
heavy_tx_thld_packets
=
IWL_MVM_PS_HEAVY_TX_THLD_PACKETS
;
cmd
->
heavy_rx_thld_packets
=
IWL_MVM_PS_HEAVY_RX_THLD_PACKETS
;
}
cmd
->
heavy_tx_thld_percentage
=
IWL_MVM_PS_HEAVY_TX_THLD_PERCENT
;
cmd
->
heavy_rx_thld_percentage
=
IWL_MVM_PS_HEAVY_RX_THLD_PERCENT
;
}
static
void
iwl_mvm_power_build_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_mac_power_cmd
*
cmd
)
...
...
@@ -198,8 +284,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
bool
radar_detect
=
false
;
struct
iwl_mvm_vif
*
mvmvif
__maybe_unused
=
iwl_mvm_vif_from_mac80211
(
vif
);
enum
ieee80211_ac_numbers
ac
;
bool
tid_found
=
false
;
bool
allow_uapsd
=
true
;
cmd
->
id_and_color
=
cpu_to_le32
(
FW_CMD_ID_AND_COLOR
(
mvmvif
->
id
,
mvmvif
->
color
));
...
...
@@ -217,7 +302,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
keep_alive
=
DIV_ROUND_UP
(
keep_alive
,
MSEC_PER_SEC
);
cmd
->
keep_alive_seconds
=
cpu_to_le16
(
keep_alive
);
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
)
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
||
mvm
->
ps_prevented
)
return
;
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
...
...
@@ -227,7 +313,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
mvmvif
->
dbgfs_pm
.
disable_power_off
)
cmd
->
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
#endif
if
(
!
vif
->
bss_conf
.
ps
)
if
(
!
vif
->
bss_conf
.
ps
||
mvmvif
->
pm_prevented
)
return
;
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
);
...
...
@@ -269,81 +355,24 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cpu_to_le32
(
IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT
);
}
for
(
ac
=
IEEE80211_AC_VO
;
ac
<=
IEEE80211_AC_BK
;
ac
++
)
{
if
(
!
mvmvif
->
queue_params
[
ac
].
uapsd
)
continue
;
if
(
mvm
->
cur_ucode
!=
IWL_UCODE_WOWLAN
)
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
);
cmd
->
uapsd_ac_flags
|=
BIT
(
ac
);
if
(
!
memcmp
(
mvmvif
->
uapsd_misbehaving_bssid
,
vif
->
bss_conf
.
bssid
,
ETH_ALEN
))
allow_uapsd
=
false
;
/* QNDP TID - the highest TID with no admission control */
if
(
!
tid_found
&&
!
mvmvif
->
queue_params
[
ac
].
acm
)
{
tid_found
=
true
;
switch
(
ac
)
{
case
IEEE80211_AC_VO
:
cmd
->
qndp_tid
=
6
;
break
;
case
IEEE80211_AC_VI
:
cmd
->
qndp_tid
=
5
;
break
;
case
IEEE80211_AC_BE
:
cmd
->
qndp_tid
=
0
;
break
;
case
IEEE80211_AC_BK
:
cmd
->
qndp_tid
=
1
;
break
;
}
}
}
if
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
))
{
if
(
cmd
->
uapsd_ac_flags
==
(
BIT
(
IEEE80211_AC_VO
)
|
BIT
(
IEEE80211_AC_VI
)
|
BIT
(
IEEE80211_AC_BE
)
|
BIT
(
IEEE80211_AC_BK
)))
{
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
);
cmd
->
snooze_interval
=
cpu_to_le16
(
IWL_MVM_PS_SNOOZE_INTERVAL
);
cmd
->
snooze_window
=
(
mvm
->
cur_ucode
==
IWL_UCODE_WOWLAN
)
?
cpu_to_le16
(
IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW
)
:
cpu_to_le16
(
IWL_MVM_PS_SNOOZE_WINDOW
);
}
cmd
->
uapsd_max_sp
=
IWL_UAPSD_MAX_SP
;
if
(
mvm
->
cur_ucode
==
IWL_UCODE_WOWLAN
||
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
))
{
cmd
->
rx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT
);
cmd
->
tx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT
);
}
else
{
cmd
->
rx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_UAPSD_RX_DATA_TIMEOUT
);
cmd
->
tx_data_timeout_uapsd
=
cpu_to_le32
(
IWL_MVM_UAPSD_TX_DATA_TIMEOUT
);
}
if
(
vif
->
p2p
&&
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD
))
allow_uapsd
=
false
;
/*
* Avoid using uAPSD if P2P client is associated to GO that uses
* opportunistic power save. This is due to current FW limitation.
*/
if
(
vif
->
p2p
&&
vif
->
bss_conf
.
p2p_noa_attr
.
oppps_ctwindow
&
IEEE80211_P2P_OPPPS_ENABLE_BIT
)
allow_uapsd
=
false
;
if
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
))
{
cmd
->
heavy_tx_thld_packets
=
IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS
;
cmd
->
heavy_rx_thld_packets
=
IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS
;
}
else
{
cmd
->
heavy_tx_thld_packets
=
IWL_MVM_PS_HEAVY_TX_THLD_PACKETS
;
cmd
->
heavy_rx_thld_packets
=
IWL_MVM_PS_HEAVY_RX_THLD_PACKETS
;
}
cmd
->
heavy_tx_thld_percentage
=
IWL_MVM_PS_HEAVY_TX_THLD_PERCENT
;
cmd
->
heavy_rx_thld_percentage
=
IWL_MVM_PS_HEAVY_RX_THLD_PERCENT
;
}
if
(
allow_uapsd
)
iwl_mvm_power_configure_uapsd
(
mvm
,
vif
,
cmd
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_KEEP_ALIVE
)
...
...
@@ -381,6 +410,13 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd
->
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_SNOOZE_ENA_MSK
);
}
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_UAPSD_MISBEHAVING
)
{
u16
flag
=
POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK
;
if
(
mvmvif
->
dbgfs_pm
.
uapsd_misbehaving
)
cmd
->
flags
|=
cpu_to_le16
(
flag
);
else
cmd
->
flags
&=
cpu_to_le16
(
flag
);
}
#endif
/* CONFIG_IWLWIFI_DEBUGFS */
}
...
...
@@ -391,18 +427,11 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
bool
ba_enable
;
struct
iwl_mac_power_cmd
cmd
=
{};
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
)
return
0
;
/*
* TODO: The following vif_count verification is temporary condition.
* Avoid power mode update if more than one interface is currently
* active. Remove this condition when FW will support power management
* on multiple MACs.
*/
IWL_DEBUG_POWER
(
mvm
,
"Currently %d interfaces active
\n
"
,
mvm
->
vif_count
);
if
(
mvm
->
vif_count
>
1
)
if
(
vif
->
p2p
&&
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_P2P_PS
))
return
0
;
iwl_mvm_power_build_cmd
(
mvm
,
vif
,
&
cmd
);
...
...
@@ -446,7 +475,7 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
sizeof
(
cmd
),
&
cmd
);
}
static
int
iwl_mvm_power_update_device
(
struct
iwl_mvm
*
mvm
)
static
int
_iwl_mvm_power_update_device
(
struct
iwl_mvm
*
mvm
,
bool
force_disable
)
{
struct
iwl_device_power_cmd
cmd
=
{
.
flags
=
cpu_to_le16
(
DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK
),
...
...
@@ -455,7 +484,8 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD
))
return
0
;
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
)
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
||
force_disable
)
cmd
.
flags
|=
cpu_to_le16
(
DEVICE_POWER_FLAGS_CAM_MSK
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
...
...
@@ -472,6 +502,78 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
&
cmd
);
}
static
int
iwl_mvm_power_update_device
(
struct
iwl_mvm
*
mvm
)
{
return
_iwl_mvm_power_update_device
(
mvm
,
false
);
}
void
iwl_mvm_power_vif_assoc
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
if
(
memcmp
(
vif
->
bss_conf
.
bssid
,
mvmvif
->
uapsd_misbehaving_bssid
,
ETH_ALEN
))
memset
(
mvmvif
->
uapsd_misbehaving_bssid
,
0
,
ETH_ALEN
);
}
static
void
iwl_mvm_power_uapsd_misbehav_ap_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
u8
*
ap_sta_id
=
_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
/* The ap_sta_id is not expected to change during current association
* so no explicit protection is needed
*/
if
(
mvmvif
->
ap_sta_id
==
*
ap_sta_id
)
memcpy
(
mvmvif
->
uapsd_misbehaving_bssid
,
vif
->
bss_conf
.
bssid
,
ETH_ALEN
);
}
int
iwl_mvm_power_uapsd_misbehaving_ap_notif
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
)
{
struct
iwl_rx_packet
*
pkt
=
rxb_addr
(
rxb
);
struct
iwl_uapsd_misbehaving_ap_notif
*
notif
=
(
void
*
)
pkt
->
data
;
u8
ap_sta_id
=
le32_to_cpu
(
notif
->
sta_id
);
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_uapsd_misbehav_ap_iterator
,
&
ap_sta_id
);
return
0
;
}
static
void
iwl_mvm_power_binding_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
_data
;
int
ret
;
mvmvif
->
pm_prevented
=
(
mvm
->
bound_vif_cnt
<=
1
)
?
false
:
true
;
ret
=
iwl_mvm_power_mac_update_mode
(
mvm
,
vif
);
WARN_ONCE
(
ret
,
"Failed to update power parameters on a specific vif
\n
"
);
}
static
void
_iwl_mvm_power_update_binding
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
assign
)
{
if
(
vif
->
type
==
NL80211_IFTYPE_MONITOR
)
{
int
ret
=
_iwl_mvm_power_update_device
(
mvm
,
assign
);
mvm
->
ps_prevented
=
assign
;
WARN_ONCE
(
ret
,
"Failed to update power device state
\n
"
);
}
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_binding_iterator
,
mvm
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
int
iwl_mvm_power_mac_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
...
...
@@ -494,70 +596,58 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"keep_alive = %d
\n
"
,
le16_to_cpu
(
cmd
.
keep_alive_seconds
));
if
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
))
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"skip_over_dtim = %d
\n
"
,
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_SKIP_OVER_DTIM_MSK
))
?
1
:
0
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"skip_dtim_periods = %d
\n
"
,
cmd
.
skip_dtim_periods
);
if
(
!
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
)))
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"rx_data_timeout = %d
\n
"
,
le32_to_cpu
(
cmd
.
rx_data_timeout
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"tx_data_timeout = %d
\n
"
,
le32_to_cpu
(
cmd
.
tx_data_timeout
));
}
if
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_LPRX_ENA_MSK
))
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"lprx_rssi_threshold = %d
\n
"
,
cmd
.
lprx_rssi_threshold
);
if
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
))
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"rx_data_timeout_uapsd = %d
\n
"
,
le32_to_cpu
(
cmd
.
rx_data_timeout_uapsd
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"tx_data_timeout_uapsd = %d
\n
"
,
le32_to_cpu
(
cmd
.
tx_data_timeout_uapsd
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"qndp_tid = %d
\n
"
,
cmd
.
qndp_tid
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"uapsd_ac_flags = 0x%x
\n
"
,
cmd
.
uapsd_ac_flags
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"uapsd_max_sp = %d
\n
"
,
cmd
.
uapsd_max_sp
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_tx_thld_packets = %d
\n
"
,
cmd
.
heavy_tx_thld_packets
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_rx_thld_packets = %d
\n
"
,
cmd
.
heavy_rx_thld_packets
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_tx_thld_percentage = %d
\n
"
,
cmd
.
heavy_tx_thld_percentage
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_rx_thld_percentage = %d
\n
"
,
cmd
.
heavy_rx_thld_percentage
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"snooze_enable = %d
\n
"
,
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
))
?
1
:
0
);
}
if
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
))
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"snooze_interval = %d
\n
"
,
cmd
.
snooze_interval
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"snooze_window = %d
\n
"
,
cmd
.
snooze_window
);
}
if
(
!
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
)))
return
pos
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"skip_over_dtim = %d
\n
"
,
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_SKIP_OVER_DTIM_MSK
))
?
1
:
0
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"skip_dtim_periods = %d
\n
"
,
cmd
.
skip_dtim_periods
);
if
(
!
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
)))
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"rx_data_timeout = %d
\n
"
,
le32_to_cpu
(
cmd
.
rx_data_timeout
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"tx_data_timeout = %d
\n
"
,
le32_to_cpu
(
cmd
.
tx_data_timeout
));
}
if
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_LPRX_ENA_MSK
))
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"lprx_rssi_threshold = %d
\n
"
,
cmd
.
lprx_rssi_threshold
);
if
(
!
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
)))
return
pos
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"rx_data_timeout_uapsd = %d
\n
"
,
le32_to_cpu
(
cmd
.
rx_data_timeout_uapsd
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"tx_data_timeout_uapsd = %d
\n
"
,
le32_to_cpu
(
cmd
.
tx_data_timeout_uapsd
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"qndp_tid = %d
\n
"
,
cmd
.
qndp_tid
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"uapsd_ac_flags = 0x%x
\n
"
,
cmd
.
uapsd_ac_flags
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"uapsd_max_sp = %d
\n
"
,
cmd
.
uapsd_max_sp
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_tx_thld_packets = %d
\n
"
,
cmd
.
heavy_tx_thld_packets
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_rx_thld_packets = %d
\n
"
,
cmd
.
heavy_rx_thld_packets
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_tx_thld_percentage = %d
\n
"
,
cmd
.
heavy_tx_thld_percentage
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"heavy_rx_thld_percentage = %d
\n
"
,
cmd
.
heavy_rx_thld_percentage
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"uapsd_misbehaving_enable = %d
\n
"
,
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK
))
?
1
:
0
);
if
(
!
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_SNOOZE_ENA_MSK
)))
return
pos
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"snooze_interval = %d
\n
"
,
cmd
.
snooze_interval
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"snooze_window = %d
\n
"
,
cmd
.
snooze_window
);
return
pos
;
}
...
...
@@ -654,6 +744,7 @@ const struct iwl_mvm_power_ops pm_mac_ops = {
.
power_update_mode
=
iwl_mvm_power_mac_update_mode
,
.
power_update_device_mode
=
iwl_mvm_power_update_device
,
.
power_disable
=
iwl_mvm_power_mac_disable
,
.
power_update_binding
=
_iwl_mvm_power_update_binding
,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.
power_dbgfs_read
=
iwl_mvm_power_mac_dbgfs_read
,
#endif
...
...
drivers/net/wireless/iwlwifi/mvm/rs.c
View file @
623c4387
...
...
@@ -42,9 +42,16 @@
#define RS_NAME "iwl-mvm-rs"
#define NUM_TRY_BEFORE_ANT_TOGGLE 1
#define IWL_NUMBER_TRY 1
#define IWL_HT_NUMBER_TRY 3
#define NUM_TRY_BEFORE_ANT_TOGGLE 1
#define RS_LEGACY_RETRIES_PER_RATE 1
#define RS_HT_VHT_RETRIES_PER_RATE 2
#define RS_HT_VHT_RETRIES_PER_RATE_TW 1
#define RS_INITIAL_MIMO_NUM_RATES 3
#define RS_INITIAL_SISO_NUM_RATES 3
#define RS_INITIAL_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM
#define RS_SECONDARY_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM
#define RS_SECONDARY_SISO_NUM_RATES 3
#define RS_SECONDARY_SISO_RETRIES 1
#define IWL_RATE_MAX_WINDOW 62
/* # tx in history window */
#define IWL_RATE_MIN_FAILURE_TH 3
/* min failures to calc tpt */
...
...
@@ -123,6 +130,12 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
IWL_DECLARE_MCS_RATE
(
9
),
/* MCS 9 */
};
enum
rs_action
{
RS_ACTION_STAY
=
0
,
RS_ACTION_DOWNSCALE
=
-
1
,
RS_ACTION_UPSCALE
=
1
,
};
enum
rs_column_mode
{
RS_INVALID
=
0
,
RS_LEGACY
,
...
...
@@ -351,20 +364,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
struct
sk_buff
*
skb
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
);
static
void
rs_fill_link_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
u32
rate_n_flags
);
static
void
rs_fill_lq_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
const
struct
rs_rate
*
initial_rate
);
static
void
rs_stay_in_table
(
struct
iwl_lq_sta
*
lq_sta
,
bool
force_search
);
#ifdef CONFIG_MAC80211_DEBUGFS
static
void
rs_dbgfs_set_mcs
(
struct
iwl_lq_sta
*
lq_sta
,
u32
*
rate_n_flags
);
#else
static
void
rs_dbgfs_set_mcs
(
struct
iwl_lq_sta
*
lq_sta
,
u32
*
rate_n_flags
)
{}
#endif
/**
* The following tables contain the expected throughput metrics for all rates
*
...
...
@@ -504,30 +509,6 @@ static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
return
(
ant_type
&
valid_antenna
)
==
ant_type
;
}
#ifdef CONFIG_MAC80211_DEBUGFS
/**
* Program the device to use fixed rate for frame transmit
* This is for debugging/testing only
* once the device start use fixed rate, we need to reload the module
* to being back the normal operation.
*/
static
void
rs_program_fix_rate
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
)
{
lq_sta
->
active_legacy_rate
=
0x0FFF
;
/* 1 - 54 MBits, includes CCK */
lq_sta
->
active_siso_rate
=
0x1FD0
;
/* 6 - 60 MBits, no 9, no CCK */
lq_sta
->
active_mimo2_rate
=
0x1FD0
;
/* 6 - 60 MBits, no 9, no CCK */
IWL_DEBUG_RATE
(
mvm
,
"sta_id %d rate 0x%X
\n
"
,
lq_sta
->
lq
.
sta_id
,
lq_sta
->
dbg_fixed_rate
);
if
(
lq_sta
->
dbg_fixed_rate
)
{
rs_fill_link_cmd
(
NULL
,
NULL
,
lq_sta
,
lq_sta
->
dbg_fixed_rate
);
iwl_mvm_send_lq_cmd
(
lq_sta
->
drv
,
&
lq_sta
->
lq
,
false
);
}
}
#endif
static
int
rs_tl_turn_on_agg_for_tid
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_data
,
u8
tid
,
struct
ieee80211_sta
*
sta
)
...
...
@@ -658,7 +639,7 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
/* Convert rs_rate object into ucode rate bitmask */
static
u32
ucode_rate_from_rs_rate
(
struct
iwl_mvm
*
mvm
,
struct
rs_rate
*
rate
)
struct
rs_rate
*
rate
)
{
u32
ucode_rate
=
0
;
int
index
=
rate
->
index
;
...
...
@@ -785,8 +766,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
/* switch to another antenna/antennas and return 1 */
/* if no other valid antenna found, return 0 */
static
int
rs_toggle_antenna
(
u32
valid_ant
,
u32
*
ucode_rate
,
struct
rs_rate
*
rate
)
static
int
rs_toggle_antenna
(
u32
valid_ant
,
struct
rs_rate
*
rate
)
{
u8
new_ant_type
;
...
...
@@ -807,9 +787,6 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate,
rate
->
ant
=
new_ant_type
;
/* TODO: get rid of ucode_rate here. This should handle only rs_rate */
*
ucode_rate
&=
~
RATE_MCS_ANT_ABC_MSK
;
*
ucode_rate
|=
new_ant_type
<<
RATE_MCS_ANT_POS
;
return
1
;
}
...
...
@@ -883,65 +860,73 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
return
(
high
<<
8
)
|
low
;
}
static
u32
rs_get_lower_rate
(
struct
iwl_lq_sta
*
lq_sta
,
struct
rs_rate
*
rate
,
u8
scale_index
,
u8
ht_possible
)
static
inline
bool
rs_rate_supported
(
struct
iwl_lq_sta
*
lq_sta
,
struct
rs_rate
*
rate
)
{
s32
low
;
u16
rate_mask
;
return
BIT
(
rate
->
index
)
&
rs_get_supported_rates
(
lq_sta
,
rate
);
}
/* Get the next supported lower rate in the current column.
* Return true if bottom rate in the current column was reached
*/
static
bool
rs_get_lower_rate_in_column
(
struct
iwl_lq_sta
*
lq_sta
,
struct
rs_rate
*
rate
)
{
u8
low
;
u16
high_low
;
u
8
switch_to_legacy
=
0
;
u
16
rate_mask
;
struct
iwl_mvm
*
mvm
=
lq_sta
->
drv
;
/* check if we need to switch from HT to legacy rates.
* assumption is that mandatory rates (1Mbps or 6Mbps)
* are always supported (spec demand) */
if
(
!
is_legacy
(
rate
)
&&
(
!
ht_possible
||
!
scale_index
))
{
switch_to_legacy
=
1
;
WARN_ON_ONCE
(
scale_index
<
IWL_RATE_MCS_0_INDEX
&&
scale_index
>
IWL_RATE_MCS_9_INDEX
);
scale_index
=
rs_ht_to_legacy
[
scale_index
];
rate_mask
=
rs_get_supported_rates
(
lq_sta
,
rate
);
high_low
=
rs_get_adjacent_rate
(
mvm
,
rate
->
index
,
rate_mask
,
rate
->
type
);
low
=
high_low
&
0xff
;
/* Bottom rate of column reached */
if
(
low
==
IWL_RATE_INVALID
)
return
true
;
rate
->
index
=
low
;
return
false
;
}
/* Get the next rate to use following a column downgrade */
static
void
rs_get_lower_rate_down_column
(
struct
iwl_lq_sta
*
lq_sta
,
struct
rs_rate
*
rate
)
{
struct
iwl_mvm
*
mvm
=
lq_sta
->
drv
;
if
(
is_legacy
(
rate
))
{
/* No column to downgrade from Legacy */
return
;
}
else
if
(
is_siso
(
rate
))
{
/* Downgrade to Legacy if we were in SISO */
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
rate
->
type
=
LQ_LEGACY_A
;
else
rate
->
type
=
LQ_LEGACY_G
;
if
(
num_of_ant
(
rate
->
ant
)
>
1
)
rate
->
ant
=
first_antenna
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
rate
->
bw
=
RATE_MCS_CHAN_WIDTH_20
;
rate
->
sgi
=
false
;
}
rate_mask
=
rs_get_supported_rates
(
lq_sta
,
rate
);
WARN_ON_ONCE
(
rate
->
index
<
IWL_RATE_MCS_0_INDEX
&&
rate
->
index
>
IWL_RATE_MCS_9_INDEX
);
/* Mask with station rate restriction */
if
(
is_legacy
(
rate
))
{
/* supp_rates has no CCK bits in A mode */
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
rate_mask
=
(
u16
)(
rate_mask
&
(
lq_sta
->
supp_rates
<<
IWL_FIRST_OFDM_RATE
));
else
rate_mask
=
(
u16
)(
rate_mask
&
lq_sta
->
supp_rates
);
rate
->
index
=
rs_ht_to_legacy
[
rate
->
index
];
}
else
{
/* Downgrade to SISO with same MCS if in MIMO */
rate
->
type
=
is_vht_mimo2
(
rate
)
?
LQ_VHT_SISO
:
LQ_HT_SISO
;
}
/* If we switched from HT to legacy, check current rate */
if
(
switch_to_legacy
&&
(
rate_mask
&
(
1
<<
scale_index
)))
{
low
=
scale_index
;
goto
out
;
}
high_low
=
rs_get_adjacent_rate
(
lq_sta
->
drv
,
scale_index
,
rate_mask
,
rate
->
type
);
low
=
high_low
&
0xff
;
if
(
num_of_ant
(
rate
->
ant
)
>
1
)
rate
->
ant
=
first_antenna
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
if
(
low
==
IWL_RATE_INVALID
)
low
=
scale_index
;
/* Relevant in both switching to SISO or Legacy */
rate
->
sgi
=
false
;
out:
rate
->
index
=
low
;
return
ucode_rate_from_rs_rate
(
lq_sta
->
drv
,
rate
);
if
(
!
rs_rate_supported
(
lq_sta
,
rate
))
rs_get_lower_rate_in_column
(
lq_sta
,
rate
);
}
/* Simple function to compare two rate scale table types */
...
...
@@ -1137,14 +1122,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
tmp_tbl
=
curr_tbl
;
else
if
(
rs_rate_match
(
&
rate
,
&
other_tbl
->
rate
))
tmp_tbl
=
other_tbl
;
else
{
IWL_DEBUG_RATE
(
mvm
,
"Tx packet rate doesn't match ACTIVE or SEARCH tables
\n
"
);
rs_dump_rate
(
mvm
,
&
rate
,
"Tx PACKET:"
);
rs_dump_rate
(
mvm
,
&
curr_tbl
->
rate
,
"CURRENT:"
);
rs_dump_rate
(
mvm
,
&
other_tbl
->
rate
,
"OTHER:"
);
else
continue
;
}
rs_collect_tx_data
(
tmp_tbl
,
rate
.
index
,
1
,
i
<
retries
?
0
:
legacy_success
);
}
...
...
@@ -1471,10 +1451,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm,
struct
iwl_lq_sta
*
lq_sta
,
struct
rs_rate
*
rate
)
{
u32
ucode_rate
;
ucode_rate
=
ucode_rate_from_rs_rate
(
mvm
,
rate
);
rs_fill_link_cmd
(
mvm
,
sta
,
lq_sta
,
ucode_rate
);
rs_fill_lq_cmd
(
mvm
,
sta
,
lq_sta
,
rate
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
false
);
}
...
...
@@ -1634,10 +1611,6 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
rate
->
index
=
rate_idx
;
}
/* TODO: remove current_rate and keep using rs_rate all the way until
* we need to fill in the rs_table in the LQ command
*/
search_tbl
->
current_rate
=
ucode_rate_from_rs_rate
(
mvm
,
rate
);
IWL_DEBUG_RATE
(
mvm
,
"Switched to column %d: Index %d
\n
"
,
col_id
,
rate
->
index
);
...
...
@@ -1649,6 +1622,97 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
return
-
1
;
}
static
enum
rs_action
rs_get_rate_action
(
struct
iwl_mvm
*
mvm
,
struct
iwl_scale_tbl_info
*
tbl
,
s32
sr
,
int
low
,
int
high
,
int
current_tpt
,
int
low_tpt
,
int
high_tpt
)
{
enum
rs_action
action
=
RS_ACTION_STAY
;
/* Too many failures, decrease rate */
if
((
sr
<=
RS_SR_FORCE_DECREASE
)
||
(
current_tpt
==
0
))
{
IWL_DEBUG_RATE
(
mvm
,
"decrease rate because of low SR
\n
"
);
action
=
RS_ACTION_DOWNSCALE
;
/* No throughput measured yet for adjacent rates; try increase. */
}
else
if
((
low_tpt
==
IWL_INVALID_VALUE
)
&&
(
high_tpt
==
IWL_INVALID_VALUE
))
{
if
(
high
!=
IWL_RATE_INVALID
&&
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Good SR and no high rate measurement. "
"Increase rate
\n
"
);
action
=
RS_ACTION_UPSCALE
;
}
else
if
(
low
!=
IWL_RATE_INVALID
)
{
IWL_DEBUG_RATE
(
mvm
,
"Remain in current rate
\n
"
);
action
=
RS_ACTION_STAY
;
}
}
/* Both adjacent throughputs are measured, but neither one has better
* throughput; we're using the best rate, don't change it!
*/
else
if
((
low_tpt
!=
IWL_INVALID_VALUE
)
&&
(
high_tpt
!=
IWL_INVALID_VALUE
)
&&
(
low_tpt
<
current_tpt
)
&&
(
high_tpt
<
current_tpt
))
{
IWL_DEBUG_RATE
(
mvm
,
"Both high and low are worse. "
"Maintain rate
\n
"
);
action
=
RS_ACTION_STAY
;
}
/* At least one adjacent rate's throughput is measured,
* and may have better performance.
*/
else
{
/* Higher adjacent rate's throughput is measured */
if
(
high_tpt
!=
IWL_INVALID_VALUE
)
{
/* Higher rate has better throughput */
if
(
high_tpt
>
current_tpt
&&
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Higher rate is better and good "
"SR. Increate rate
\n
"
);
action
=
RS_ACTION_UPSCALE
;
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"Higher rate isn't better OR "
"no good SR. Maintain rate
\n
"
);
action
=
RS_ACTION_STAY
;
}
/* Lower adjacent rate's throughput is measured */
}
else
if
(
low_tpt
!=
IWL_INVALID_VALUE
)
{
/* Lower rate has better throughput */
if
(
low_tpt
>
current_tpt
)
{
IWL_DEBUG_RATE
(
mvm
,
"Lower rate is better. "
"Decrease rate
\n
"
);
action
=
RS_ACTION_DOWNSCALE
;
}
else
if
(
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Lower rate isn't better and "
"good SR. Increase rate
\n
"
);
action
=
RS_ACTION_UPSCALE
;
}
}
}
/* Sanity check; asked for decrease, but success rate or throughput
* has been good at old rate. Don't change it.
*/
if
((
action
==
RS_ACTION_DOWNSCALE
)
&&
(
low
!=
IWL_RATE_INVALID
)
&&
((
sr
>
IWL_RATE_HIGH_TH
)
||
(
current_tpt
>
(
100
*
tbl
->
expected_tpt
[
low
]))))
{
IWL_DEBUG_RATE
(
mvm
,
"Sanity check failed. Maintain rate
\n
"
);
action
=
RS_ACTION_STAY
;
}
return
action
;
}
/*
* Do rate scaling and search for new modulation mode.
...
...
@@ -1669,11 +1733,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
int
low_tpt
=
IWL_INVALID_VALUE
;
int
high_tpt
=
IWL_INVALID_VALUE
;
u32
fail_count
;
s8
scale_action
=
0
;
enum
rs_action
scale_action
=
RS_ACTION_STAY
;
u16
rate_mask
;
u8
update_lq
=
0
;
struct
iwl_scale_tbl_info
*
tbl
,
*
tbl1
;
u16
rate_scale_index_msk
=
0
;
u8
active_tbl
=
0
;
u8
done_search
=
0
;
u16
high_low
;
...
...
@@ -1690,8 +1753,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
info
->
flags
&
IEEE80211_TX_CTL_NO_ACK
)
return
;
lq_sta
->
supp_rates
=
sta
->
supp_rates
[
lq_sta
->
band
];
tid
=
rs_get_tid
(
lq_sta
,
hdr
);
if
((
tid
!=
IWL_MAX_TID_COUNT
)
&&
(
lq_sta
->
tx_agg_tid_en
&
(
1
<<
tid
)))
{
...
...
@@ -1730,33 +1791,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* rates available for this association, and for modulation mode */
rate_mask
=
rs_get_supported_rates
(
lq_sta
,
rate
);
/* mask with station rate restriction */
if
(
is_legacy
(
rate
))
{
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
/* supp_rates has no CCK bits in A mode */
rate_scale_index_msk
=
(
u16
)
(
rate_mask
&
(
lq_sta
->
supp_rates
<<
IWL_FIRST_OFDM_RATE
));
else
rate_scale_index_msk
=
(
u16
)
(
rate_mask
&
lq_sta
->
supp_rates
);
}
else
{
rate_scale_index_msk
=
rate_mask
;
}
if
(
!
rate_scale_index_msk
)
rate_scale_index_msk
=
rate_mask
;
if
(
!
((
BIT
(
index
)
&
rate_scale_index_msk
)))
{
if
(
!
(
BIT
(
index
)
&
rate_mask
))
{
IWL_ERR
(
mvm
,
"Current Rate is not valid
\n
"
);
if
(
lq_sta
->
search_better_tbl
)
{
/* revert to active table if search table is not valid*/
rate
->
type
=
LQ_NONE
;
lq_sta
->
search_better_tbl
=
0
;
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
/* get "active" rate info */
index
=
iwl_hwrate_to_plcp_idx
(
tbl
->
current_rate
);
tbl
->
rate
.
index
=
index
;
rs_update_rate_tbl
(
mvm
,
sta
,
lq_sta
,
&
tbl
->
rate
);
}
return
;
...
...
@@ -1847,7 +1888,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
tbl
=
&
(
lq_sta
->
lq_info
[
active_tbl
]);
/* Revert to "active" rate and throughput info */
index
=
iwl_hwrate_to_plcp_idx
(
tbl
->
current_rate
)
;
index
=
tbl
->
rate
.
index
;
current_tpt
=
lq_sta
->
last_tpt
;
/* Need to set up a new rate table in uCode */
...
...
@@ -1863,8 +1904,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* (Else) not in search of better modulation mode, try for better
* starting rate, while staying in this mode. */
high_low
=
rs_get_adjacent_rate
(
mvm
,
index
,
rate_scale_index_msk
,
rate
->
type
);
high_low
=
rs_get_adjacent_rate
(
mvm
,
index
,
rate_mask
,
rate
->
type
);
low
=
high_low
&
0xff
;
high
=
(
high_low
>>
8
)
&
0xff
;
...
...
@@ -1887,85 +1927,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
rs_pretty_lq_type
(
rate
->
type
),
index
,
current_tpt
,
sr
,
low
,
high
,
low_tpt
,
high_tpt
);
scale_action
=
0
;
/* Too many failures, decrease rate */
if
((
sr
<=
RS_SR_FORCE_DECREASE
)
||
(
current_tpt
==
0
))
{
IWL_DEBUG_RATE
(
mvm
,
"decrease rate because of low SR
\n
"
);
scale_action
=
-
1
;
/* No throughput measured yet for adjacent rates; try increase. */
}
else
if
((
low_tpt
==
IWL_INVALID_VALUE
)
&&
(
high_tpt
==
IWL_INVALID_VALUE
))
{
if
(
high
!=
IWL_RATE_INVALID
&&
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Good SR and no high rate measurement. "
"Increase rate
\n
"
);
scale_action
=
1
;
}
else
if
(
low
!=
IWL_RATE_INVALID
)
{
IWL_DEBUG_RATE
(
mvm
,
"Remain in current rate
\n
"
);
scale_action
=
0
;
}
}
/* Both adjacent throughputs are measured, but neither one has better
* throughput; we're using the best rate, don't change it! */
else
if
((
low_tpt
!=
IWL_INVALID_VALUE
)
&&
(
high_tpt
!=
IWL_INVALID_VALUE
)
&&
(
low_tpt
<
current_tpt
)
&&
(
high_tpt
<
current_tpt
))
{
IWL_DEBUG_RATE
(
mvm
,
"Both high and low are worse. "
"Maintain rate
\n
"
);
scale_action
=
0
;
}
/* At least one adjacent rate's throughput is measured,
* and may have better performance. */
else
{
/* Higher adjacent rate's throughput is measured */
if
(
high_tpt
!=
IWL_INVALID_VALUE
)
{
/* Higher rate has better throughput */
if
(
high_tpt
>
current_tpt
&&
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Higher rate is better and good "
"SR. Increate rate
\n
"
);
scale_action
=
1
;
}
else
{
IWL_DEBUG_RATE
(
mvm
,
"Higher rate isn't better OR "
"no good SR. Maintain rate
\n
"
);
scale_action
=
0
;
}
/* Lower adjacent rate's throughput is measured */
}
else
if
(
low_tpt
!=
IWL_INVALID_VALUE
)
{
/* Lower rate has better throughput */
if
(
low_tpt
>
current_tpt
)
{
IWL_DEBUG_RATE
(
mvm
,
"Lower rate is better. "
"Decrease rate
\n
"
);
scale_action
=
-
1
;
}
else
if
(
sr
>=
IWL_RATE_INCREASE_TH
)
{
IWL_DEBUG_RATE
(
mvm
,
"Lower rate isn't better and "
"good SR. Increase rate
\n
"
);
scale_action
=
1
;
}
}
}
/* Sanity check; asked for decrease, but success rate or throughput
* has been good at old rate. Don't change it. */
if
((
scale_action
==
-
1
)
&&
(
low
!=
IWL_RATE_INVALID
)
&&
((
sr
>
IWL_RATE_HIGH_TH
)
||
(
current_tpt
>
(
100
*
tbl
->
expected_tpt
[
low
]))))
{
IWL_DEBUG_RATE
(
mvm
,
"Sanity check failed. Maintain rate
\n
"
);
scale_action
=
0
;
}
scale_action
=
rs_get_rate_action
(
mvm
,
tbl
,
sr
,
low
,
high
,
current_tpt
,
low_tpt
,
high_tpt
);
/* Force a search in case BT doesn't like us being in MIMO */
if
(
is_mimo
(
rate
)
&&
...
...
@@ -1977,7 +1940,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
switch
(
scale_action
)
{
case
-
1
:
case
RS_ACTION_DOWNSCALE
:
/* Decrease starting rate, update uCode's rate table */
if
(
low
!=
IWL_RATE_INVALID
)
{
update_lq
=
1
;
...
...
@@ -1988,7 +1951,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
break
;
case
1
:
case
RS_ACTION_UPSCALE
:
/* Increase starting rate, update uCode's rate table */
if
(
high
!=
IWL_RATE_INVALID
)
{
update_lq
=
1
;
...
...
@@ -1999,7 +1962,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
break
;
case
0
:
case
RS_ACTION_STAY
:
/* No change */
default:
break
;
...
...
@@ -2053,11 +2016,11 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
rs_rate_scale_clear_window
(
&
(
tbl
->
win
[
i
]));
/* Use new "search" start rate */
index
=
iwl_hwrate_to_plcp_idx
(
tbl
->
current_rate
)
;
index
=
tbl
->
rate
.
index
;
rs_dump_rate
(
mvm
,
&
tbl
->
rate
,
"Switch to SEARCH TABLE:"
);
rs_fill_l
ink_cmd
(
mvm
,
sta
,
lq_sta
,
tbl
->
current_
rate
);
rs_fill_l
q_cmd
(
mvm
,
sta
,
lq_sta
,
&
tbl
->
rate
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
false
);
}
else
{
done_search
=
1
;
...
...
@@ -2095,8 +2058,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
out:
tbl
->
rate
.
index
=
index
;
tbl
->
current_rate
=
ucode_rate_from_rs_rate
(
mvm
,
&
tbl
->
rate
);
lq_sta
->
last_txrate_idx
=
index
;
}
...
...
@@ -2123,7 +2084,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
struct
iwl_scale_tbl_info
*
tbl
;
struct
rs_rate
*
rate
;
int
i
;
u32
ucode_rate
;
u8
active_tbl
=
0
;
u8
valid_tx_ant
;
...
...
@@ -2154,9 +2114,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
else
rate
->
type
=
LQ_LEGACY_G
;
ucode_rate
=
ucode_rate_from_rs_rate
(
mvm
,
rate
);
tbl
->
current_rate
=
ucode_rate
;
WARN_ON_ONCE
(
rate
->
ant
!=
ANT_A
&&
rate
->
ant
!=
ANT_B
);
if
(
rate
->
ant
==
ANT_A
)
tbl
->
column
=
RS_COLUMN_LEGACY_ANT_A
;
...
...
@@ -2164,7 +2121,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
tbl
->
column
=
RS_COLUMN_LEGACY_ANT_B
;
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
rs_fill_l
ink_cmd
(
NULL
,
NULL
,
lq_sta
,
ucode_
rate
);
rs_fill_l
q_cmd
(
NULL
,
NULL
,
lq_sta
,
rate
);
/* TODO restore station should remember the lq cmd */
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
init
);
}
...
...
@@ -2250,6 +2207,10 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* Disable MCS9 as a workaround */
if
(
i
==
IWL_RATE_MCS_9_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
...
...
@@ -2268,6 +2229,10 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* Disable MCS9 as a workaround */
if
(
i
==
IWL_RATE_MCS_9_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
...
...
@@ -2306,7 +2271,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
rs_rate_scale_clear_window
(
&
lq_sta
->
lq_info
[
j
].
win
[
i
]);
lq_sta
->
flush_timer
=
0
;
lq_sta
->
supp_rates
=
sta
->
supp_rates
[
sband
->
band
];
IWL_DEBUG_RATE
(
mvm
,
"LQ: *** rate scale station global init for station %d ***
\n
"
,
...
...
@@ -2395,112 +2359,164 @@ static void rs_rate_update(void *mvm_r,
iwl_mvm_rs_rate_init
(
mvm
,
sta
,
sband
->
band
,
false
);
}
static
void
rs_fill_link_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
u32
new_rate
)
#ifdef CONFIG_MAC80211_DEBUGFS
static
void
rs_build_rates_table_from_fixed
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_cmd
*
lq_cmd
,
enum
ieee80211_band
band
,
u32
ucode_rate
)
{
struct
rs_rate
rate
;
int
index
=
0
;
int
repeat_rate
=
0
;
u8
ant_toggle_cnt
=
0
;
u8
use_ht_possible
=
1
;
u8
valid_tx_ant
=
0
;
struct
iwl_lq_cmd
*
lq_cmd
=
&
lq_sta
->
lq
;
int
i
;
int
num_rates
=
ARRAY_SIZE
(
lq_cmd
->
rs_table
);
__le32
ucode_rate_le32
=
cpu_to_le32
(
ucode_rate
);
/* Override starting rate (index 0) if needed for debug purposes */
rs_dbgfs_set_mcs
(
lq_sta
,
&
new_rate
)
;
for
(
i
=
0
;
i
<
num_rates
;
i
++
)
lq_cmd
->
rs_table
[
i
]
=
ucode_rate_le32
;
rs_rate_from_ucode_rate
(
new_rate
,
lq_sta
->
band
,
&
rate
);
rs_rate_from_ucode_rate
(
ucode_rate
,
band
,
&
rate
);
/* How many times should we repeat the initial rate? */
if
(
is_legacy
(
&
rate
))
{
ant_toggle_cnt
=
1
;
repeat_rate
=
IWL_NUMBER_TRY
;
}
else
{
repeat_rate
=
min
(
IWL_HT_NUMBER_TRY
,
LINK_QUAL_AGG_DISABLE_START_DEF
-
1
);
if
(
is_mimo
(
&
rate
))
lq_cmd
->
mimo_delim
=
num_rates
-
1
;
else
lq_cmd
->
mimo_delim
=
0
;
}
#endif
/* CONFIG_MAC80211_DEBUGFS */
static
void
rs_fill_rates_for_column
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
rs_rate
*
rate
,
__le32
*
rs_table
,
int
*
rs_table_index
,
int
num_rates
,
int
num_retries
,
u8
valid_tx_ant
,
bool
toggle_ant
)
{
int
i
,
j
;
__le32
ucode_rate
;
bool
bottom_reached
=
false
;
int
prev_rate_idx
=
rate
->
index
;
int
end
=
LINK_QUAL_MAX_RETRY_NUM
;
int
index
=
*
rs_table_index
;
for
(
i
=
0
;
i
<
num_rates
&&
index
<
end
;
i
++
)
{
ucode_rate
=
cpu_to_le32
(
ucode_rate_from_rs_rate
(
mvm
,
rate
));
for
(
j
=
0
;
j
<
num_retries
&&
index
<
end
;
j
++
,
index
++
)
rs_table
[
index
]
=
ucode_rate
;
if
(
toggle_ant
)
rs_toggle_antenna
(
valid_tx_ant
,
rate
);
prev_rate_idx
=
rate
->
index
;
bottom_reached
=
rs_get_lower_rate_in_column
(
lq_sta
,
rate
);
if
(
bottom_reached
&&
!
is_legacy
(
rate
))
break
;
}
lq_cmd
->
mimo_delim
=
is_mimo
(
&
rate
)
?
1
:
0
;
if
(
!
bottom_reached
)
rate
->
index
=
prev_rate_idx
;
/* Fill 1st table entry (index 0) */
lq_cmd
->
rs_table
[
index
]
=
cpu_to_le32
(
new_rate
);
*
rs_table_index
=
index
;
}
if
(
num_of_ant
(
rate
.
ant
)
==
1
)
lq_cmd
->
single_stream_ant_msk
=
rate
.
ant
;
/* otherwise we don't modify the existing value */
/* Building the rate table is non trivial. When we're in MIMO2/VHT/80Mhz/SGI
* column the rate table should look like this:
*
* rate[0] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
* rate[1] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
* rate[2] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
* rate[3] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
* rate[4] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
* rate[5] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
* rate[6] 0x4005007 VHT | ANT: A BW: 80Mhz MCS: 7 NSS: 1 NGI
* rate[7] 0x4009006 VHT | ANT: B BW: 80Mhz MCS: 6 NSS: 1 NGI
* rate[8] 0x4005005 VHT | ANT: A BW: 80Mhz MCS: 5 NSS: 1 NGI
* rate[9] 0x800B Legacy | ANT: B Rate: 36 Mbps
* rate[10] 0x4009 Legacy | ANT: A Rate: 24 Mbps
* rate[11] 0x8007 Legacy | ANT: B Rate: 18 Mbps
* rate[12] 0x4005 Legacy | ANT: A Rate: 12 Mbps
* rate[13] 0x800F Legacy | ANT: B Rate: 9 Mbps
* rate[14] 0x400D Legacy | ANT: A Rate: 6 Mbps
* rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
*/
static
void
rs_build_rates_table
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
const
struct
rs_rate
*
initial_rate
)
{
struct
rs_rate
rate
;
int
num_rates
,
num_retries
,
index
=
0
;
u8
valid_tx_ant
=
0
;
struct
iwl_lq_cmd
*
lq_cmd
=
&
lq_sta
->
lq
;
bool
toggle_ant
=
false
;
memcpy
(
&
rate
,
initial_rate
,
sizeof
(
struct
rs_rate
));
index
++
;
repeat_rate
--
;
if
(
mvm
)
valid_tx_ant
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
/* Fill rest of rate table */
while
(
index
<
LINK_QUAL_MAX_RETRY_NUM
)
{
/* Repeat initial/next rate.
* For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
* For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
while
(
repeat_rate
>
0
&&
(
index
<
LINK_QUAL_MAX_RETRY_NUM
))
{
if
(
is_legacy
(
&
rate
))
{
if
(
ant_toggle_cnt
<
NUM_TRY_BEFORE_ANT_TOGGLE
)
ant_toggle_cnt
++
;
else
if
(
mvm
&&
rs_toggle_antenna
(
valid_tx_ant
,
&
new_rate
,
&
rate
))
ant_toggle_cnt
=
1
;
}
if
(
is_siso
(
&
rate
))
{
num_rates
=
RS_INITIAL_SISO_NUM_RATES
;
num_retries
=
RS_HT_VHT_RETRIES_PER_RATE
;
}
else
if
(
is_mimo
(
&
rate
))
{
num_rates
=
RS_INITIAL_MIMO_NUM_RATES
;
num_retries
=
RS_HT_VHT_RETRIES_PER_RATE
;
}
else
{
num_rates
=
RS_INITIAL_LEGACY_NUM_RATES
;
num_retries
=
RS_LEGACY_RETRIES_PER_RATE
;
toggle_ant
=
true
;
}
/* Override next rate if needed for debug purposes */
rs_dbgfs_set_mcs
(
lq_sta
,
&
new_rate
);
rs_fill_rates_for_column
(
mvm
,
lq_sta
,
&
rate
,
lq_cmd
->
rs_table
,
&
index
,
num_rates
,
num_retries
,
valid_tx_ant
,
toggle_ant
);
/* Fill next table entry */
lq_cmd
->
rs_table
[
index
]
=
cpu_to_le32
(
new_rate
);
repeat_rate
--
;
index
++
;
}
rs_get_lower_rate_down_column
(
lq_sta
,
&
rate
);
rs_rate_from_ucode_rate
(
new_rate
,
lq_sta
->
band
,
&
rate
);
if
(
is_siso
(
&
rate
))
{
num_rates
=
RS_SECONDARY_SISO_NUM_RATES
;
num_retries
=
RS_SECONDARY_SISO_RETRIES
;
}
else
if
(
is_legacy
(
&
rate
))
{
num_rates
=
RS_SECONDARY_LEGACY_NUM_RATES
;
num_retries
=
RS_LEGACY_RETRIES_PER_RATE
;
}
else
{
WARN_ON_ONCE
(
1
);
}
/* Indicate to uCode which entries might be MIMO.
* If initial rate was MIMO, this will finally end up
* as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
if
(
is_mimo
(
&
rate
))
lq_cmd
->
mimo_delim
=
index
;
toggle_ant
=
true
;
/* Get next rate */
new_rate
=
rs_get_lower_rate
(
lq_sta
,
&
rate
,
rate
.
index
,
use_ht_possible
);
rs_fill_rates_for_column
(
mvm
,
lq_sta
,
&
rate
,
lq_cmd
->
rs_table
,
&
index
,
num_rates
,
num_retries
,
valid_tx_ant
,
toggle_ant
);
/* How many times should we repeat the next rate? */
if
(
is_legacy
(
&
rate
))
{
if
(
ant_toggle_cnt
<
NUM_TRY_BEFORE_ANT_TOGGLE
)
ant_toggle_cnt
++
;
else
if
(
mvm
&&
rs_toggle_antenna
(
valid_tx_ant
,
&
new_rate
,
&
rate
))
ant_toggle_cnt
=
1
;
rs_get_lower_rate_down_column
(
lq_sta
,
&
rate
);
repeat_rate
=
IWL_NUMBER_TRY
;
}
else
{
repeat_rate
=
IWL_HT_NUMBER_TRY
;
}
num_rates
=
RS_SECONDARY_LEGACY_NUM_RATES
;
num_retries
=
RS_LEGACY_RETRIES_PER_RATE
;
/* Don't allow HT rates after next pass.
* rs_get_lower_rate() will change type to LQ_LEGACY_A
* or LQ_LEGACY_G.
*/
use_ht_possible
=
0
;
rs_fill_rates_for_column
(
mvm
,
lq_sta
,
&
rate
,
lq_cmd
->
rs_table
,
&
index
,
num_rates
,
num_retries
,
valid_tx_ant
,
toggle_ant
);
/* Override next rate if needed for debug purposes */
rs_dbgfs_set_mcs
(
lq_sta
,
&
new_rate
);
}
/* Fill next table entry */
lq_cmd
->
rs_table
[
index
]
=
cpu_to_le32
(
new_rate
);
static
void
rs_fill_lq_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
const
struct
rs_rate
*
initial_rate
)
{
struct
iwl_lq_cmd
*
lq_cmd
=
&
lq_sta
->
lq
;
u8
ant
=
initial_rate
->
ant
;
index
++
;
repeat_rate
--
;
}
#ifdef CONFIG_MAC80211_DEBUGFS
if
(
lq_sta
->
dbg_fixed_rate
)
{
rs_build_rates_table_from_fixed
(
mvm
,
lq_cmd
,
lq_sta
->
band
,
lq_sta
->
dbg_fixed_rate
);
ant
=
(
lq_sta
->
dbg_fixed_rate
&
RATE_MCS_ANT_ABC_MSK
)
>>
RATE_MCS_ANT_POS
;
}
else
#endif
rs_build_rates_table
(
mvm
,
lq_sta
,
initial_rate
);
if
(
num_of_ant
(
ant
)
==
1
)
lq_cmd
->
single_stream_ant_msk
=
ant
;
lq_cmd
->
agg_frame_cnt_limit
=
LINK_QUAL_AGG_FRAME_LIMIT_DEF
;
lq_cmd
->
agg_disable_start_th
=
LINK_QUAL_AGG_DISABLE_START_DEF
;
...
...
@@ -2534,31 +2550,6 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta,
}
#ifdef CONFIG_MAC80211_DEBUGFS
static
void
rs_dbgfs_set_mcs
(
struct
iwl_lq_sta
*
lq_sta
,
u32
*
rate_n_flags
)
{
struct
iwl_mvm
*
mvm
;
u8
valid_tx_ant
;
u8
ant_sel_tx
;
mvm
=
lq_sta
->
drv
;
valid_tx_ant
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
if
(
lq_sta
->
dbg_fixed_rate
)
{
ant_sel_tx
=
((
lq_sta
->
dbg_fixed_rate
&
RATE_MCS_ANT_ABC_MSK
)
>>
RATE_MCS_ANT_POS
);
if
((
valid_tx_ant
&
ant_sel_tx
)
==
ant_sel_tx
)
{
*
rate_n_flags
=
lq_sta
->
dbg_fixed_rate
;
}
else
{
lq_sta
->
dbg_fixed_rate
=
0
;
IWL_ERR
(
mvm
,
"Invalid antenna selection 0x%X, Valid is 0x%X
\n
"
,
ant_sel_tx
,
valid_tx_ant
);
IWL_DEBUG_RATE
(
mvm
,
"Fixed rate OFF
\n
"
);
}
}
}
static
int
rs_pretty_print_rate
(
char
*
buf
,
const
u32
rate
)
{
...
...
@@ -2612,6 +2603,31 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
(
rate
&
RATE_MCS_ZLF_MSK
)
?
"ZLF "
:
""
);
}
/**
* Program the device to use fixed rate for frame transmit
* This is for debugging/testing only
* once the device start use fixed rate, we need to reload the module
* to being back the normal operation.
*/
static
void
rs_program_fix_rate
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
)
{
lq_sta
->
active_legacy_rate
=
0x0FFF
;
/* 1 - 54 MBits, includes CCK */
lq_sta
->
active_siso_rate
=
0x1FD0
;
/* 6 - 60 MBits, no 9, no CCK */
lq_sta
->
active_mimo2_rate
=
0x1FD0
;
/* 6 - 60 MBits, no 9, no CCK */
IWL_DEBUG_RATE
(
mvm
,
"sta_id %d rate 0x%X
\n
"
,
lq_sta
->
lq
.
sta_id
,
lq_sta
->
dbg_fixed_rate
);
if
(
lq_sta
->
dbg_fixed_rate
)
{
struct
rs_rate
rate
;
rs_rate_from_ucode_rate
(
lq_sta
->
dbg_fixed_rate
,
lq_sta
->
band
,
&
rate
);
rs_fill_lq_cmd
(
NULL
,
NULL
,
lq_sta
,
&
rate
);
iwl_mvm_send_lq_cmd
(
lq_sta
->
drv
,
&
lq_sta
->
lq
,
false
);
}
}
static
ssize_t
rs_sta_dbgfs_scale_table_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
...
...
@@ -2702,12 +2718,10 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta
->
lq
.
initial_rate_index
[
3
]);
for
(
i
=
0
;
i
<
LINK_QUAL_MAX_RETRY_NUM
;
i
++
)
{
u32
rate
=
le32_to_cpu
(
lq_sta
->
lq
.
rs_table
[
i
]);
desc
+=
sprintf
(
buff
+
desc
,
" rate[%d] 0x%X "
,
i
,
rate
);
u32
r
=
le32_to_cpu
(
lq_sta
->
lq
.
rs_table
[
i
]);
desc
+=
rs_pretty_print_rate
(
buff
+
desc
,
rate
);
desc
+=
sprintf
(
buff
+
desc
,
" rate[%d] 0x%X "
,
i
,
r
);
desc
+=
rs_pretty_print_rate
(
buff
+
desc
,
r
);
}
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buff
,
desc
);
...
...
@@ -2741,14 +2755,14 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
rate
=
&
tbl
->
rate
;
desc
+=
sprintf
(
buff
+
desc
,
"%s type=%d SGI=%d BW=%s DUP=0
\n
"
"
rate=0x%X
\n
"
,
"
index=%d
\n
"
,
lq_sta
->
active_tbl
==
i
?
"*"
:
"x"
,
rate
->
type
,
rate
->
sgi
,
is_ht20
(
rate
)
?
"20Mhz"
:
is_ht40
(
rate
)
?
"40Mhz"
:
is_ht80
(
rate
)
?
"80Mhz"
:
"ERR"
,
tbl
->
current_rate
);
rate
->
index
);
for
(
j
=
0
;
j
<
IWL_RATE_COUNT
;
j
++
)
{
desc
+=
sprintf
(
buff
+
desc
,
"counter=%d success=%d %%=%d
\n
"
,
...
...
drivers/net/wireless/iwlwifi/mvm/rs.h
View file @
623c4387
...
...
@@ -278,7 +278,6 @@ struct iwl_scale_tbl_info {
struct
rs_rate
rate
;
enum
rs_column
column
;
s32
*
expected_tpt
;
/* throughput metrics; expected_tpt_G, etc. */
u32
current_rate
;
/* rate_n_flags, uCode API format */
struct
iwl_rate_scale_data
win
[
IWL_RATE_COUNT
];
/* rate histories */
};
...
...
@@ -315,7 +314,6 @@ struct iwl_lq_sta {
enum
ieee80211_band
band
;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
u32
supp_rates
;
u16
active_legacy_rate
;
u16
active_siso_rate
;
u16
active_mimo2_rate
;
...
...
drivers/net/wireless/iwlwifi/mvm/rx.c
View file @
623c4387
...
...
@@ -251,6 +251,12 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
stats
->
flag
|=
RX_FLAG_DECRYPTED
;
return
0
;
case
RX_MPDU_RES_STATUS_SEC_EXT_ENC
:
if
(
!
(
rx_pkt_status
&
RX_MPDU_RES_STATUS_MIC_OK
))
return
-
1
;
stats
->
flag
|=
RX_FLAG_DECRYPTED
;
return
0
;
default:
IWL_ERR
(
mvm
,
"Unhandled alg: 0x%x
\n
"
,
rx_pkt_status
);
}
...
...
drivers/net/wireless/iwlwifi/mvm/sf.c
0 → 100644
View file @
623c4387
/******************************************************************************
*
* 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) 2013 Intel Corporation. All rights reserved.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2013 Intel Corporation. All rights reserved.
* 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 "mvm.h"
/* For counting bound interfaces */
struct
iwl_mvm_active_iface_iterator_data
{
struct
ieee80211_vif
*
ignore_vif
;
u8
sta_vif_ap_sta_id
;
enum
iwl_sf_state
sta_vif_state
;
int
num_active_macs
;
};
/*
* Count bound interfaces which are not p2p, besides data->ignore_vif.
* data->station_vif will point to one bound vif of type station, if exists.
*/
static
void
iwl_mvm_bound_iface_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_active_iface_iterator_data
*
data
=
_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
if
(
vif
==
data
->
ignore_vif
||
!
mvmvif
->
phy_ctxt
||
vif
->
type
==
NL80211_IFTYPE_P2P_DEVICE
)
return
;
data
->
num_active_macs
++
;
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
)
{
data
->
sta_vif_ap_sta_id
=
mvmvif
->
ap_sta_id
;
if
(
vif
->
bss_conf
.
assoc
)
data
->
sta_vif_state
=
SF_FULL_ON
;
else
data
->
sta_vif_state
=
SF_INIT_OFF
;
}
}
/*
* Aging and idle timeouts for the different possible scenarios
* in SF_FULL_ON state.
*/
static
const
__le32
sf_full_timeout
[
SF_NUM_SCENARIO
][
SF_NUM_TIMEOUT_TYPES
]
=
{
{
cpu_to_le32
(
SF_SINGLE_UNICAST_AGING_TIMER
),
cpu_to_le32
(
SF_SINGLE_UNICAST_IDLE_TIMER
)
},
{
cpu_to_le32
(
SF_AGG_UNICAST_AGING_TIMER
),
cpu_to_le32
(
SF_AGG_UNICAST_IDLE_TIMER
)
},
{
cpu_to_le32
(
SF_MCAST_AGING_TIMER
),
cpu_to_le32
(
SF_MCAST_IDLE_TIMER
)
},
{
cpu_to_le32
(
SF_BA_AGING_TIMER
),
cpu_to_le32
(
SF_BA_IDLE_TIMER
)
},
{
cpu_to_le32
(
SF_TX_RE_AGING_TIMER
),
cpu_to_le32
(
SF_TX_RE_IDLE_TIMER
)
},
};
static
void
iwl_mvm_fill_sf_command
(
struct
iwl_sf_cfg_cmd
*
sf_cmd
,
struct
ieee80211_sta
*
sta
)
{
int
i
,
j
,
watermark
;
sf_cmd
->
watermark
[
SF_LONG_DELAY_ON
]
=
cpu_to_le32
(
SF_W_MARK_SCAN
);
/*
* If we are in association flow - check antenna configuration
* capabilities of the AP station, and choose the watermark accordingly.
*/
if
(
sta
)
{
if
(
sta
->
ht_cap
.
ht_supported
||
sta
->
vht_cap
.
vht_supported
)
{
switch
(
sta
->
rx_nss
)
{
case
1
:
watermark
=
SF_W_MARK_SISO
;
break
;
case
2
:
watermark
=
SF_W_MARK_MIMO2
;
break
;
default:
watermark
=
SF_W_MARK_MIMO3
;
break
;
}
}
else
{
watermark
=
SF_W_MARK_LEGACY
;
}
/* default watermark value for unassociated mode. */
}
else
{
watermark
=
SF_W_MARK_MIMO2
;
}
sf_cmd
->
watermark
[
SF_FULL_ON
]
=
cpu_to_le32
(
watermark
);
for
(
i
=
0
;
i
<
SF_NUM_SCENARIO
;
i
++
)
{
for
(
j
=
0
;
j
<
SF_NUM_TIMEOUT_TYPES
;
j
++
)
{
sf_cmd
->
long_delay_timeouts
[
i
][
j
]
=
cpu_to_le32
(
SF_LONG_DELAY_AGING_TIMER
);
}
}
BUILD_BUG_ON
(
sizeof
(
sf_full_timeout
)
!=
sizeof
(
__le32
)
*
SF_NUM_SCENARIO
*
SF_NUM_TIMEOUT_TYPES
);
memcpy
(
sf_cmd
->
full_on_timeouts
,
sf_full_timeout
,
sizeof
(
sf_full_timeout
));
}
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
=
new_state
,
};
struct
ieee80211_sta
*
sta
;
int
ret
=
0
;
/*
* If an associated AP sta changed its antenna configuration, the state
* will remain FULL_ON but SF parameters need to be reconsidered.
*/
if
(
new_state
!=
SF_FULL_ON
&&
mvm
->
sf_state
==
new_state
)
return
0
;
switch
(
new_state
)
{
case
SF_UNINIT
:
break
;
case
SF_FULL_ON
:
if
(
sta_id
==
IWL_MVM_STATION_COUNT
)
{
IWL_ERR
(
mvm
,
"No station: Cannot switch SF to FULL_ON
\n
"
);
return
-
EINVAL
;
}
rcu_read_lock
();
sta
=
rcu_dereference
(
mvm
->
fw_id_to_mac_id
[
sta_id
]);
if
(
IS_ERR_OR_NULL
(
sta
))
{
IWL_ERR
(
mvm
,
"Invalid station id
\n
"
);
rcu_read_unlock
();
return
-
EINVAL
;
}
iwl_mvm_fill_sf_command
(
&
sf_cmd
,
sta
);
rcu_read_unlock
();
break
;
case
SF_INIT_OFF
:
iwl_mvm_fill_sf_command
(
&
sf_cmd
,
NULL
);
break
;
default:
WARN_ONCE
(
1
,
"Invalid state: %d. not sending Smart Fifo cmd
\n
"
,
new_state
);
return
-
EINVAL
;
}
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
REPLY_SF_CFG_CMD
,
CMD_ASYNC
,
sizeof
(
sf_cmd
),
&
sf_cmd
);
if
(
!
ret
)
mvm
->
sf_state
=
new_state
;
return
ret
;
}
/*
* Update Smart fifo:
* Count bound interfaces that are not to be removed, ignoring p2p devices,
* and set new state accordingly.
*/
int
iwl_mvm_sf_update
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
changed_vif
,
bool
remove_vif
)
{
enum
iwl_sf_state
new_state
;
u8
sta_id
=
IWL_MVM_STATION_COUNT
;
struct
iwl_mvm_vif
*
mvmvif
=
NULL
;
struct
iwl_mvm_active_iface_iterator_data
data
=
{
.
ignore_vif
=
changed_vif
,
.
sta_vif_state
=
SF_UNINIT
,
.
sta_vif_ap_sta_id
=
IWL_MVM_STATION_COUNT
,
};
if
(
IWL_UCODE_API
(
mvm
->
fw
->
ucode_ver
)
<
8
)
return
0
;
/*
* Ignore the call if we are in HW Restart flow, or if the handled
* vif is a p2p device.
*/
if
(
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
)
||
(
changed_vif
&&
changed_vif
->
type
==
NL80211_IFTYPE_P2P_DEVICE
))
return
0
;
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_bound_iface_iterator
,
&
data
);
/* If changed_vif exists and is not to be removed, add to the count */
if
(
changed_vif
&&
!
remove_vif
)
data
.
num_active_macs
++
;
switch
(
data
.
num_active_macs
)
{
case
0
:
/* If there are no active macs - change state to SF_INIT_OFF */
new_state
=
SF_INIT_OFF
;
break
;
case
1
:
if
(
remove_vif
)
{
/* The one active mac left is of type station
* and we filled the relevant data during iteration
*/
new_state
=
data
.
sta_vif_state
;
sta_id
=
data
.
sta_vif_ap_sta_id
;
}
else
{
if
(
WARN_ON
(
!
changed_vif
))
return
-
EINVAL
;
if
(
changed_vif
->
type
!=
NL80211_IFTYPE_STATION
)
{
new_state
=
SF_UNINIT
;
}
else
if
(
changed_vif
->
bss_conf
.
assoc
)
{
mvmvif
=
iwl_mvm_vif_from_mac80211
(
changed_vif
);
sta_id
=
mvmvif
->
ap_sta_id
;
new_state
=
SF_FULL_ON
;
}
else
{
new_state
=
SF_INIT_OFF
;
}
}
break
;
default:
/* If there are multiple active macs - change to SF_UNINIT */
new_state
=
SF_UNINIT
;
}
return
iwl_mvm_sf_config
(
mvm
,
sta_id
,
new_state
);
}
drivers/net/wireless/iwlwifi/mvm/sta.c
View file @
623c4387
...
...
@@ -939,19 +939,6 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_DEBUG_HT
(
mvm
,
"Tx aggregation enabled on ra = %pM tid = %d
\n
"
,
sta
->
addr
,
tid
);
if
(
mvm
->
cfg
->
ht_params
->
use_rts_for_aggregation
)
{
/*
* switch to RTS/CTS if it is the prefer protection
* method for HT traffic
* this function also sends the LQ command
*/
return
iwl_mvm_tx_protection
(
mvm
,
mvmsta
,
true
);
/*
* TODO: remove the TLC_RTS flag when we tear down the last
* AGG session (agg_tids_count in DVM)
*/
}
return
iwl_mvm_send_lq_cmd
(
mvm
,
&
mvmsta
->
lq_sta
.
lq
,
false
);
}
...
...
@@ -1130,8 +1117,8 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
memcpy
(
cmd
.
key
,
keyconf
->
key
,
keyconf
->
keylen
);
break
;
default:
WARN_ON
(
1
);
return
-
EINVAL
;
key_flags
|=
cpu_to_le16
(
STA_KEY_FLG_EXT
);
memcpy
(
cmd
.
key
,
keyconf
->
key
,
keyconf
->
keylen
)
;
}
if
(
!
(
keyconf
->
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
))
...
...
@@ -1295,8 +1282,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
0
,
NULL
,
CMD_SYNC
);
break
;
default:
IWL_ERR
(
mvm
,
"Unknown cipher %x
\n
"
,
keyconf
->
cipher
);
ret
=
-
EINVAL
;
ret
=
iwl_mvm_send_sta_key
(
mvm
,
mvm_sta
,
keyconf
,
sta_id
,
0
,
NULL
,
CMD_SYNC
)
;
}
if
(
ret
)
...
...
drivers/net/wireless/iwlwifi/mvm/tt.c
View file @
623c4387
...
...
@@ -340,7 +340,7 @@ static void check_exit_ctkill(struct work_struct *work)
iwl_trans_start_hw
(
mvm
->
trans
);
temp
=
check_nic_temperature
(
mvm
);
iwl_trans_stop_
hw
(
mvm
->
trans
,
false
);
iwl_trans_stop_
device
(
mvm
->
trans
);
if
(
temp
<
MIN_TEMPERATURE
||
temp
>
MAX_TEMPERATURE
)
{
IWL_DEBUG_TEMP
(
mvm
,
"Failed to measure NIC temperature
\n
"
);
...
...
drivers/net/wireless/iwlwifi/mvm/tx.c
View file @
623c4387
...
...
@@ -253,8 +253,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
memcpy
(
&
tx_cmd
->
key
[
3
],
keyconf
->
key
,
keyconf
->
keylen
);
break
;
default:
IWL_ERR
(
mvm
,
"Unknown encode cipher %x
\n
"
,
keyconf
->
cipher
);
break
;
tx_cmd
->
sec_ctl
|=
TX_CMD_SEC_EXT
;
}
}
...
...
drivers/net/wireless/iwlwifi/mvm/utils.c
View file @
623c4387
...
...
@@ -518,6 +518,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int
i
;
lockdep_assert_held
(
&
mvm
->
mutex
);
/* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
if
(
num_of_ant
(
iwl_fw_valid_rx_ant
(
mvm
->
fw
))
==
1
)
return
;
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
mvmvif
->
smps_requests
[
req_type
]
=
smps_request
;
for
(
i
=
0
;
i
<
NUM_IWL_MVM_SMPS_REQ
;
i
++
)
{
...
...
drivers/net/wireless/iwlwifi/pcie/internal.h
View file @
623c4387
...
...
@@ -256,7 +256,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @hw_base: pci hardware address support
* @ucode_write_complete: indicates that the ucode has been copied.
* @ucode_write_waitq: wait queue for uCode load
* @status - transport specific status flags
* @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
...
...
@@ -296,7 +295,6 @@ struct iwl_trans_pcie {
wait_queue_head_t
ucode_write_waitq
;
wait_queue_head_t
wait_command_queue
;
unsigned
long
status
;
u8
cmd_queue
;
u8
cmd_fifo
;
u8
n_no_reclaim_cmds
;
...
...
@@ -315,24 +313,6 @@ struct iwl_trans_pcie {
spinlock_t
reg_lock
;
};
/**
* enum iwl_pcie_status: status of the PCIe transport
* @STATUS_HCMD_ACTIVE: a SYNC command is being processed
* @STATUS_DEVICE_ENABLED: APM is enabled
* @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_FW_ERROR: the fw is in error state
*/
enum
iwl_pcie_status
{
STATUS_HCMD_ACTIVE
,
STATUS_DEVICE_ENABLED
,
STATUS_TPOWER_PMI
,
STATUS_INT_ENABLED
,
STATUS_RFKILL
,
STATUS_FW_ERROR
,
};
#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
...
...
@@ -399,8 +379,7 @@ void iwl_pcie_dump_csr(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
);
clear_bit
(
STATUS_INT_ENABLED
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_INT_ENABLED
,
&
trans
->
status
);
/* disable interrupts from uCode/NIC to host */
iwl_write32
(
trans
,
CSR_INT_MASK
,
0x00000000
);
...
...
@@ -417,7 +396,7 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
IWL_DEBUG_ISR
(
trans
,
"Enabling interrupts
\n
"
);
set_bit
(
STATUS_INT_ENABLED
,
&
trans
_pcie
->
status
);
set_bit
(
STATUS_INT_ENABLED
,
&
trans
->
status
);
iwl_write32
(
trans
,
CSR_INT_MASK
,
trans_pcie
->
inta_mask
);
}
...
...
@@ -477,12 +456,4 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW
);
}
static
inline
void
iwl_nic_error
(
struct
iwl_trans
*
trans
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
set_bit
(
STATUS_FW_ERROR
,
&
trans_pcie
->
status
);
iwl_op_mode_nic_error
(
trans
->
op_mode
);
}
#endif
/* __iwl_trans_int_pcie_h__ */
drivers/net/wireless/iwlwifi/pcie/rx.c
View file @
623c4387
...
...
@@ -162,11 +162,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
rxq
->
write_actual
=
(
rxq
->
write
&
~
0x7
);
iwl_write32
(
trans
,
FH_RSCSR_CHNL0_WPTR
,
rxq
->
write_actual
);
}
else
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
/* If power-saving is in use, make sure device is awake */
if
(
test_bit
(
STATUS_TPOWER_PMI
,
&
trans
_pcie
->
status
))
{
if
(
test_bit
(
STATUS_TPOWER_PMI
,
&
trans
->
status
))
{
reg
=
iwl_read32
(
trans
,
CSR_UCODE_DRV_GP1
);
if
(
reg
&
CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP
)
{
...
...
@@ -222,7 +219,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
* stopped, we cannot access the HW (in particular not prph).
* So don't try to restock if the APM has been already stopped.
*/
if
(
!
test_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
_pcie
->
status
))
if
(
!
test_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
->
status
))
return
;
spin_lock_irqsave
(
&
rxq
->
lock
,
flags
);
...
...
@@ -791,7 +788,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
APMS_CLK_VAL_MRB_FUNC_MODE
)
||
(
iwl_read_prph
(
trans
,
APMG_PS_CTRL_REG
)
&
APMG_PS_CTRL_VAL_RESET_REQ
)))
{
clear_bit
(
STATUS_
HCMD_ACTIVE
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_
SYNC_HCMD_ACTIVE
,
&
trans
->
status
);
iwl_op_mode_wimax_active
(
trans
->
op_mode
);
wake_up
(
&
trans_pcie
->
wait_command_queue
);
return
;
...
...
@@ -800,14 +797,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
iwl_pcie_dump_csr
(
trans
);
iwl_dump_fh
(
trans
,
NULL
);
/* set the ERROR bit before we wake up the caller */
set_bit
(
STATUS_FW_ERROR
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_HCMD_ACTIVE
,
&
trans_pcie
->
status
);
wake_up
(
&
trans_pcie
->
wait_command_queue
);
local_bh_disable
();
iwl_nic_error
(
trans
);
/* The STATUS_FW_ERROR bit is set in this function. This must happen
* before we wake up the command caller, to ensure a proper cleanup. */
iwl_trans_fw_error
(
trans
);
local_bh_enable
();
clear_bit
(
STATUS_SYNC_HCMD_ACTIVE
,
&
trans
->
status
);
wake_up
(
&
trans_pcie
->
wait_command_queue
);
}
irqreturn_t
iwl_pcie_irq_handler
(
int
irq
,
void
*
dev_id
)
...
...
@@ -894,14 +891,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
iwl_op_mode_hw_rf_kill
(
trans
->
op_mode
,
hw_rfkill
);
if
(
hw_rfkill
)
{
set_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
);
if
(
test_and_clear_bit
(
STATUS_HCMD_ACTIVE
,
&
trans
_pcie
->
status
))
set_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
if
(
test_and_clear_bit
(
STATUS_
SYNC_
HCMD_ACTIVE
,
&
trans
->
status
))
IWL_DEBUG_RF_KILL
(
trans
,
"Rfkill while SYNC HCMD in flight
\n
"
);
wake_up
(
&
trans_pcie
->
wait_command_queue
);
}
else
{
clear_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
);
clear_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
}
handled
|=
CSR_INT_BIT_RF_KILL
;
...
...
@@ -1005,7 +1002,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
/* Re-enable all interrupts */
/* only Re-enable if disabled by irq */
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans
_pcie
->
status
))
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans
->
status
))
iwl_enable_interrupts
(
trans
);
/* Re-enable RF_KILL if it occurred */
else
if
(
handled
&
CSR_INT_BIT_RF_KILL
)
...
...
@@ -1160,7 +1157,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
* the handler can be scheduled because of a previous
* interrupt.
*/
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans
_pcie
->
status
)
&&
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans
->
status
)
&&
!
trans_pcie
->
inta
)
iwl_enable_interrupts
(
trans
);
return
IRQ_NONE
;
...
...
@@ -1290,7 +1287,7 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
/* re-enable interrupts here since we don't have anything to service.
* only Re-enable if disabled by irq.
*/
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans
_pcie
->
status
)
&&
if
(
test_bit
(
STATUS_INT_ENABLED
,
&
trans
->
status
)
&&
!
trans_pcie
->
inta
)
iwl_enable_interrupts
(
trans
);
...
...
drivers/net/wireless/iwlwifi/pcie/trans.c
View file @
623c4387
...
...
@@ -150,7 +150,6 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
*/
static
int
iwl_pcie_apm_init
(
struct
iwl_trans
*
trans
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
int
ret
=
0
;
IWL_DEBUG_INFO
(
trans
,
"Init card's basic functions
\n
"
);
...
...
@@ -223,7 +222,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
/* Clear the interrupt in APMG if the NIC is in RFKILL */
iwl_write_prph
(
trans
,
APMG_RTC_INT_STT_REG
,
APMG_RTC_INT_STT_RFKILL
);
set_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
_pcie
->
status
);
set_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
->
status
);
out:
return
ret
;
...
...
@@ -249,10 +248,9 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
static
void
iwl_pcie_apm_stop
(
struct
iwl_trans
*
trans
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
IWL_DEBUG_INFO
(
trans
,
"Stop card, put in low power state
\n
"
);
clear_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
_pcie
->
status
);
clear_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
->
status
);
/* Stop device's DMA activity */
iwl_pcie_apm_stop_master
(
trans
);
...
...
@@ -582,7 +580,6 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
static
int
iwl_trans_pcie_start_fw
(
struct
iwl_trans
*
trans
,
const
struct
fw_img
*
fw
,
bool
run_in_rfkill
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
int
ret
;
bool
hw_rfkill
;
...
...
@@ -592,16 +589,14 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
return
-
EIO
;
}
clear_bit
(
STATUS_FW_ERROR
,
&
trans_pcie
->
status
);
iwl_enable_rfkill_int
(
trans
);
/* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill
=
iwl_is_rfkill_set
(
trans
);
if
(
hw_rfkill
)
set_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
);
set_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
else
clear_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
);
clear_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
iwl_op_mode_hw_rf_kill
(
trans
->
op_mode
,
hw_rfkill
);
if
(
hw_rfkill
&&
!
run_in_rfkill
)
return
-
ERFKILL
;
...
...
@@ -641,6 +636,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
unsigned
long
flags
;
bool
hw_rfkill
;
/* tell the device to stop sending interrupts */
spin_lock_irqsave
(
&
trans_pcie
->
irq_lock
,
flags
);
...
...
@@ -657,7 +653,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
* restart. So don't process again if the device is
* already dead.
*/
if
(
test_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
_pcie
->
status
))
{
if
(
test_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
->
status
))
{
iwl_pcie_tx_stop
(
trans
);
iwl_pcie_rx_stop
(
trans
);
...
...
@@ -681,17 +677,34 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_disable_interrupts
(
trans
);
spin_unlock_irqrestore
(
&
trans_pcie
->
irq_lock
,
flags
);
iwl_enable_rfkill_int
(
trans
);
/* stop and reset the on-board processor */
iwl_write32
(
trans
,
CSR_RESET
,
CSR_RESET_REG_FLAG_NEVO_RESET
);
/* clear all status bits */
clear_bit
(
STATUS_HCMD_ACTIVE
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_INT_ENABLED
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_DEVICE_ENABLED
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_TPOWER_PMI
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_RFKILL
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_SYNC_HCMD_ACTIVE
,
&
trans
->
status
);
clear_bit
(
STATUS_INT_ENABLED
,
&
trans
->
status
);
clear_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
->
status
);
clear_bit
(
STATUS_TPOWER_PMI
,
&
trans
->
status
);
clear_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
/*
* Even if we stop the HW, we still want the RF kill
* interrupt
*/
iwl_enable_rfkill_int
(
trans
);
/*
* Check again since the RF kill state may have changed while
* all the interrupts were disabled, in this case we couldn't
* receive the RF kill interrupt and update the state in the
* op_mode.
*/
hw_rfkill
=
iwl_is_rfkill_set
(
trans
);
if
(
hw_rfkill
)
set_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
else
clear_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
iwl_op_mode_hw_rf_kill
(
trans
->
op_mode
,
hw_rfkill
);
}
static
void
iwl_trans_pcie_d3_suspend
(
struct
iwl_trans
*
trans
,
bool
test
)
...
...
@@ -776,7 +789,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
static
int
iwl_trans_pcie_start_hw
(
struct
iwl_trans
*
trans
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
bool
hw_rfkill
;
int
err
;
...
...
@@ -798,21 +810,20 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
hw_rfkill
=
iwl_is_rfkill_set
(
trans
);
if
(
hw_rfkill
)
set_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
);
set_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
else
clear_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
);
clear_bit
(
STATUS_RFKILL
,
&
trans
->
status
);
iwl_op_mode_hw_rf_kill
(
trans
->
op_mode
,
hw_rfkill
);
return
0
;
}
static
void
iwl_trans_pcie_stop_hw
(
struct
iwl_trans
*
trans
,
bool
op_mode_leaving
)
static
void
iwl_trans_pcie_op_mode_leave
(
struct
iwl_trans
*
trans
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
bool
hw_rfkill
;
unsigned
long
flags
;
/* disable interrupts - don't enable HW RF kill interrupt */
spin_lock_irqsave
(
&
trans_pcie
->
irq_lock
,
flags
);
iwl_disable_interrupts
(
trans
);
spin_unlock_irqrestore
(
&
trans_pcie
->
irq_lock
,
flags
);
...
...
@@ -824,27 +835,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
spin_unlock_irqrestore
(
&
trans_pcie
->
irq_lock
,
flags
);
iwl_pcie_disable_ict
(
trans
);
if
(
!
op_mode_leaving
)
{
/*
* Even if we stop the HW, we still want the RF kill
* interrupt
*/
iwl_enable_rfkill_int
(
trans
);
/*
* Check again since the RF kill state may have changed while
* all the interrupts were disabled, in this case we couldn't
* receive the RF kill interrupt and update the state in the
* op_mode.
*/
hw_rfkill
=
iwl_is_rfkill_set
(
trans
);
if
(
hw_rfkill
)
set_bit
(
STATUS_RFKILL
,
&
trans_pcie
->
status
);
else
clear_bit
(
STATUS_RFKILL
,
&
trans_pcie
->
status
);
iwl_op_mode_hw_rf_kill
(
trans
->
op_mode
,
hw_rfkill
);
}
}
static
void
iwl_trans_pcie_write8
(
struct
iwl_trans
*
trans
,
u32
ofs
,
u8
val
)
...
...
@@ -928,12 +918,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
static
void
iwl_trans_pcie_set_pmi
(
struct
iwl_trans
*
trans
,
bool
state
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
if
(
state
)
set_bit
(
STATUS_TPOWER_PMI
,
&
trans
_pcie
->
status
);
set_bit
(
STATUS_TPOWER_PMI
,
&
trans
->
status
);
else
clear_bit
(
STATUS_TPOWER_PMI
,
&
trans
_pcie
->
status
);
clear_bit
(
STATUS_TPOWER_PMI
,
&
trans
->
status
);
}
static
bool
iwl_trans_pcie_grab_nic_access
(
struct
iwl_trans
*
trans
,
bool
silent
,
...
...
@@ -1457,7 +1445,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
static
const
struct
iwl_trans_ops
trans_ops_pcie
=
{
.
start_hw
=
iwl_trans_pcie_start_hw
,
.
stop_hw
=
iwl_trans_pcie_stop_hw
,
.
op_mode_leave
=
iwl_trans_pcie_op_mode_leave
,
.
fw_alive
=
iwl_trans_pcie_fw_alive
,
.
start_fw
=
iwl_trans_pcie_start_fw
,
.
stop_device
=
iwl_trans_pcie_stop_device
,
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
View file @
623c4387
...
...
@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR
(
trans
,
"scratch %d = 0x%08x
\n
"
,
i
,
le32_to_cpu
(
txq
->
scratchbufs
[
i
].
scratch
));
iwl_
nic
_error
(
trans
);
iwl_
trans_fw
_error
(
trans
);
}
/*
...
...
@@ -300,10 +300,8 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
iwl_write32
(
trans
,
HBUS_TARG_WRPTR
,
txq
->
q
.
write_ptr
|
(
txq_id
<<
8
));
}
else
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
/* if we're trying to save power */
if
(
test_bit
(
STATUS_TPOWER_PMI
,
&
trans
_pcie
->
status
))
{
if
(
test_bit
(
STATUS_TPOWER_PMI
,
&
trans
->
status
))
{
/* wake up nic if it's powered down ...
* uCode will wake up, and interrupt us again, so next
* time we'll skip this part. */
...
...
@@ -1023,7 +1021,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
if
(
nfreed
++
>
0
)
{
IWL_ERR
(
trans
,
"HCMD skipped: index (%d) %d %d
\n
"
,
idx
,
q
->
write_ptr
,
q
->
read_ptr
);
iwl_
nic
_error
(
trans
);
iwl_
trans_fw
_error
(
trans
);
}
}
...
...
@@ -1449,12 +1447,12 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
iwl_pcie_cmdq_reclaim
(
trans
,
txq_id
,
index
);
if
(
!
(
meta
->
flags
&
CMD_ASYNC
))
{
if
(
!
test_bit
(
STATUS_
HCMD_ACTIVE
,
&
trans_pcie
->
status
))
{
if
(
!
test_bit
(
STATUS_
SYNC_HCMD_ACTIVE
,
&
trans
->
status
))
{
IWL_WARN
(
trans
,
"HCMD_ACTIVE already clear for command %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
hdr
.
cmd
));
}
clear_bit
(
STATUS_
HCMD_ACTIVE
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_
SYNC_HCMD_ACTIVE
,
&
trans
->
status
);
IWL_DEBUG_INFO
(
trans
,
"Clearing HCMD_ACTIVE for command %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
hdr
.
cmd
));
wake_up
(
&
trans_pcie
->
wait_command_queue
);
...
...
@@ -1499,8 +1497,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
IWL_DEBUG_INFO
(
trans
,
"Attempting to send sync command %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
));
if
(
WARN
(
test_and_set_bit
(
STATUS_HCMD_ACTIVE
,
&
trans
_pcie
->
status
),
if
(
WARN
(
test_and_set_bit
(
STATUS_
SYNC_
HCMD_ACTIVE
,
&
trans
->
status
),
"Command %s: a command is already active!
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
)))
return
-
EIO
;
...
...
@@ -1511,7 +1509,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
cmd_idx
=
iwl_pcie_enqueue_hcmd
(
trans
,
cmd
);
if
(
cmd_idx
<
0
)
{
ret
=
cmd_idx
;
clear_bit
(
STATUS_
HCMD_ACTIVE
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_
SYNC_HCMD_ACTIVE
,
&
trans
->
status
);
IWL_ERR
(
trans
,
"Error sending %s: enqueue_hcmd failed: %d
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
),
ret
);
...
...
@@ -1523,8 +1521,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
timeout
-=
COMMAND_POKE_TIMEOUT
;
ret
=
wait_event_timeout
(
trans_pcie
->
wait_command_queue
,
!
test_bit
(
STATUS_HCMD_ACTIVE
,
&
trans
_pcie
->
status
),
!
test_bit
(
STATUS_
SYNC_
HCMD_ACTIVE
,
&
trans
->
status
),
COMMAND_POKE_TIMEOUT
);
if
(
ret
)
break
;
...
...
@@ -1552,17 +1550,17 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
IWL_ERR
(
trans
,
"Current CMD queue read_ptr %d write_ptr %d
\n
"
,
q
->
read_ptr
,
q
->
write_ptr
);
clear_bit
(
STATUS_
HCMD_ACTIVE
,
&
trans_pcie
->
status
);
clear_bit
(
STATUS_
SYNC_HCMD_ACTIVE
,
&
trans
->
status
);
IWL_DEBUG_INFO
(
trans
,
"Clearing HCMD_ACTIVE for command %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
));
ret
=
-
ETIMEDOUT
;
iwl_
nic
_error
(
trans
);
iwl_
trans_fw
_error
(
trans
);
goto
cancel
;
}
if
(
test_bit
(
STATUS_FW_ERROR
,
&
trans
_pcie
->
status
))
{
if
(
test_bit
(
STATUS_FW_ERROR
,
&
trans
->
status
))
{
IWL_ERR
(
trans
,
"FW error in SYNC CMD %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
));
dump_stack
();
...
...
@@ -1571,7 +1569,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
}
if
(
!
(
cmd
->
flags
&
CMD_SEND_IN_RFKILL
)
&&
test_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
))
{
test_bit
(
STATUS_RFKILL
,
&
trans
->
status
))
{
IWL_DEBUG_RF_KILL
(
trans
,
"RFKILL in SYNC CMD... no rsp
\n
"
);
ret
=
-
ERFKILL
;
goto
cancel
;
...
...
@@ -1608,13 +1606,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
int
iwl_trans_pcie_send_hcmd
(
struct
iwl_trans
*
trans
,
struct
iwl_host_cmd
*
cmd
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
if
(
test_bit
(
STATUS_FW_ERROR
,
&
trans_pcie
->
status
))
return
-
EIO
;
if
(
!
(
cmd
->
flags
&
CMD_SEND_IN_RFKILL
)
&&
test_bit
(
STATUS_RFKILL
,
&
trans
_pcie
->
status
))
{
test_bit
(
STATUS_RFKILL
,
&
trans
->
status
))
{
IWL_DEBUG_RF_KILL
(
trans
,
"Dropping CMD 0x%x: RF KILL
\n
"
,
cmd
->
id
);
return
-
ERFKILL
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment