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
Kirill Smelkov
linux
Commits
444474dd
Commit
444474dd
authored
Oct 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
a72e25f7
246dd992
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
3484 additions
and
1001 deletions
+3484
-1001
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
+14
-0
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-config.h
+1
-0
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-csr.h
+32
-0
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.c
+37
-0
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
+4
-0
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-fw.h
+25
-1
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-prph.h
+2
-0
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
+470
-162
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/constants.h
+3
-1
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/d3.c
+476
-39
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
+154
-52
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
+95
-54
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+67
-2
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
+11
-0
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+28
-1
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
+19
-2
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+30
-4
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+53
-2
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
+10
-6
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/fw.c
+18
-5
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+60
-15
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
+209
-33
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
+82
-6
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/nvm.c
+67
-34
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/ops.c
+44
-16
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/power.c
+57
-13
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/quota.c
+37
-5
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.c
+403
-390
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rs.h
+96
-58
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/rx.c
+21
-0
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/scan.c
+444
-12
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.c
+157
-49
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/sta.h
+0
-4
drivers/net/wireless/iwlwifi/mvm/testmode.h
drivers/net/wireless/iwlwifi/mvm/testmode.h
+95
-0
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
+3
-2
drivers/net/wireless/iwlwifi/mvm/time-event.h
drivers/net/wireless/iwlwifi/mvm/time-event.h
+3
-1
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/tx.c
+26
-23
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/mvm/utils.c
+1
-1
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/drv.c
+4
-4
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/trans.c
+123
-4
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/iwlwifi/pcie/tx.c
+3
-0
No files found.
drivers/net/wireless/iwlwifi/iwl-7000.c
View file @
444474dd
...
...
@@ -83,6 +83,8 @@
#define IWL7260_TX_POWER_VERSION 0xffff
/* meaningless */
#define IWL3160_NVM_VERSION 0x709
#define IWL3160_TX_POWER_VERSION 0xffff
/* meaningless */
#define IWL7265_NVM_VERSION 0x0a1d
#define IWL7265_TX_POWER_VERSION 0xffff
/* meaningless */
#define IWL7260_FW_PRE "iwlwifi-7260-"
#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
...
...
@@ -90,6 +92,9 @@
#define IWL3160_FW_PRE "iwlwifi-3160-"
#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
#define IWL7265_FW_PRE "iwlwifi-7265-"
#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
static
const
struct
iwl_base_params
iwl7000_base_params
=
{
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
,
.
num_of_queues
=
IWLAGN_NUM_QUEUES
,
...
...
@@ -182,5 +187,14 @@ const struct iwl_cfg iwl3160_n_cfg = {
.
nvm_calib_ver
=
IWL3160_TX_POWER_VERSION
,
};
const
struct
iwl_cfg
iwl7265_2ac_cfg
=
{
.
name
=
"Intel(R) Dual Band Wireless AC 7265"
,
.
fw_name_pre
=
IWL7265_FW_PRE
,
IWL_DEVICE_7000
,
.
ht_params
=
&
iwl7000_ht_params
,
.
nvm_ver
=
IWL7265_NVM_VERSION
,
.
nvm_calib_ver
=
IWL7265_TX_POWER_VERSION
,
};
MODULE_FIRMWARE
(
IWL7260_MODULE_FIRMWARE
(
IWL7260_UCODE_API_OK
));
MODULE_FIRMWARE
(
IWL3160_MODULE_FIRMWARE
(
IWL3160_UCODE_API_OK
));
drivers/net/wireless/iwlwifi/iwl-config.h
View file @
444474dd
...
...
@@ -292,6 +292,7 @@ extern const struct iwl_cfg iwl7260_n_cfg;
extern
const
struct
iwl_cfg
iwl3160_2ac_cfg
;
extern
const
struct
iwl_cfg
iwl3160_2n_cfg
;
extern
const
struct
iwl_cfg
iwl3160_n_cfg
;
extern
const
struct
iwl_cfg
iwl7265_2ac_cfg
;
#endif
/* CONFIG_IWLMVM */
#endif
/* __IWL_CONFIG_H__ */
drivers/net/wireless/iwlwifi/iwl-csr.h
View file @
444474dd
...
...
@@ -394,6 +394,38 @@
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
/* SECURE boot registers */
#define CSR_SECURE_BOOT_CONFIG_ADDR (0x100)
enum
secure_boot_config_reg
{
CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP
=
0x00000001
,
CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ
=
0x00000002
,
};
#define CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100)
#define CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100)
enum
secure_boot_status_reg
{
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS
=
0x00000003
,
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED
=
0x00000002
,
CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS
=
0x00000004
,
CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL
=
0x00000008
,
CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL
=
0x00000010
,
};
#define CSR_UCODE_LOAD_STATUS_ADDR (0x100)
enum
secure_load_status_reg
{
CSR_CPU_STATUS_LOADING_STARTED
=
0x00000001
,
CSR_CPU_STATUS_LOADING_COMPLETED
=
0x00000002
,
CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED
=
0x000000F8
,
CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
=
0x0000FF00
,
};
#define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100)
#define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100)
#define CSR_SECURE_TIME_OUT (100)
#define FH_TCSR_0_REG0 (0x1D00)
/*
* HBUS (Host-side Bus)
*
...
...
drivers/net/wireless/iwlwifi/iwl-drv.c
View file @
444474dd
...
...
@@ -483,6 +483,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
const
u8
*
tlv_data
;
char
buildstr
[
25
];
u32
build
;
int
num_of_cpus
;
if
(
len
<
sizeof
(
*
ucode
))
{
IWL_ERR
(
drv
,
"uCode has invalid length: %zd
\n
"
,
len
);
...
...
@@ -692,6 +693,42 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
goto
invalid_tlv_len
;
drv
->
fw
.
phy_config
=
le32_to_cpup
((
__le32
*
)
tlv_data
);
break
;
case
IWL_UCODE_TLV_SECURE_SEC_RT
:
iwl_store_ucode_sec
(
pieces
,
tlv_data
,
IWL_UCODE_REGULAR
,
tlv_len
);
drv
->
fw
.
mvm_fw
=
true
;
drv
->
fw
.
img
[
IWL_UCODE_REGULAR
].
is_secure
=
true
;
break
;
case
IWL_UCODE_TLV_SECURE_SEC_INIT
:
iwl_store_ucode_sec
(
pieces
,
tlv_data
,
IWL_UCODE_INIT
,
tlv_len
);
drv
->
fw
.
mvm_fw
=
true
;
drv
->
fw
.
img
[
IWL_UCODE_INIT
].
is_secure
=
true
;
break
;
case
IWL_UCODE_TLV_SECURE_SEC_WOWLAN
:
iwl_store_ucode_sec
(
pieces
,
tlv_data
,
IWL_UCODE_WOWLAN
,
tlv_len
);
drv
->
fw
.
mvm_fw
=
true
;
drv
->
fw
.
img
[
IWL_UCODE_WOWLAN
].
is_secure
=
true
;
break
;
case
IWL_UCODE_TLV_NUM_OF_CPU
:
if
(
tlv_len
!=
sizeof
(
u32
))
goto
invalid_tlv_len
;
num_of_cpus
=
le32_to_cpup
((
__le32
*
)
tlv_data
);
if
(
num_of_cpus
==
2
)
{
drv
->
fw
.
img
[
IWL_UCODE_REGULAR
].
is_dual_cpus
=
true
;
drv
->
fw
.
img
[
IWL_UCODE_INIT
].
is_dual_cpus
=
true
;
drv
->
fw
.
img
[
IWL_UCODE_WOWLAN
].
is_dual_cpus
=
true
;
}
else
if
((
num_of_cpus
>
2
)
||
(
num_of_cpus
<
1
))
{
IWL_ERR
(
drv
,
"Driver support upto 2 CPUs
\n
"
);
return
-
EINVAL
;
}
break
;
default:
IWL_DEBUG_INFO
(
drv
,
"unknown TLV: %d
\n
"
,
tlv_type
);
break
;
...
...
drivers/net/wireless/iwlwifi/iwl-fw-file.h
View file @
444474dd
...
...
@@ -121,6 +121,10 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_SEC_WOWLAN
=
21
,
IWL_UCODE_TLV_DEF_CALIB
=
22
,
IWL_UCODE_TLV_PHY_SKU
=
23
,
IWL_UCODE_TLV_SECURE_SEC_RT
=
24
,
IWL_UCODE_TLV_SECURE_SEC_INIT
=
25
,
IWL_UCODE_TLV_SECURE_SEC_WOWLAN
=
26
,
IWL_UCODE_TLV_NUM_OF_CPU
=
27
,
};
struct
iwl_ucode_tlv
{
...
...
drivers/net/wireless/iwlwifi/iwl-fw.h
View file @
444474dd
...
...
@@ -75,11 +75,23 @@
* @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
* @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
* @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD
* @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan
* offload profile config command.
* @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api
* @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API.
* @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six
* (rather than two) IPv6 addresses
* @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API
* @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element
* from the probe request template.
* @IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping
* connection when going back to D0
* @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version)
* @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
* @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan.
* @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.
*/
enum
iwl_ucode_tlv_flag
{
IWL_UCODE_TLV_FLAGS_PAN
=
BIT
(
0
),
...
...
@@ -87,11 +99,20 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_MFP
=
BIT
(
2
),
IWL_UCODE_TLV_FLAGS_P2P
=
BIT
(
3
),
IWL_UCODE_TLV_FLAGS_DW_BC_TABLE
=
BIT
(
4
),
IWL_UCODE_TLV_FLAGS_NEWBT_COEX
=
BIT
(
5
),
IWL_UCODE_TLV_FLAGS_UAPSD
=
BIT
(
6
),
IWL_UCODE_TLV_FLAGS_SHORT_BL
=
BIT
(
7
),
IWL_UCODE_TLV_FLAGS_RX_ENERGY_API
=
BIT
(
8
),
IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2
=
BIT
(
9
),
IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS
=
BIT
(
10
),
IWL_UCODE_TLV_FLAGS_BF_UPDATED
=
BIT
(
11
),
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID
=
BIT
(
12
),
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API
=
BIT
(
14
),
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL
=
BIT
(
15
),
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE
=
BIT
(
16
),
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
),
};
/* The default calibrate table size if not specified by firmware file */
...
...
@@ -133,7 +154,8 @@ enum iwl_ucode_sec {
* For 16.0 uCode and above, there is no differentiation between sections,
* just an offset to the HW address.
*/
#define IWL_UCODE_SECTION_MAX 4
#define IWL_UCODE_SECTION_MAX 6
#define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2)
struct
iwl_ucode_capabilities
{
u32
max_probe_length
;
...
...
@@ -150,6 +172,8 @@ struct fw_desc {
struct
fw_img
{
struct
fw_desc
sec
[
IWL_UCODE_SECTION_MAX
];
bool
is_secure
;
bool
is_dual_cpus
;
};
/* uCode version contains 4 values: Major/Minor/API/Serial */
...
...
drivers/net/wireless/iwlwifi/iwl-prph.h
View file @
444474dd
...
...
@@ -97,6 +97,8 @@
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
#define APMG_RTC_INT_STT_RFKILL (0x10000000)
/* Device system time */
#define DEVICE_SYSTEM_TIME_REG 0xA0206C
...
...
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
View file @
444474dd
...
...
@@ -98,126 +98,258 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
#undef EVENT_PRIO_ANT
/* BT Antenna Coupling Threshold (dB) */
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
#define IWL_BT_LOAD_FORCE_SISO_THRESHOLD (3)
#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62)
#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65)
#define BT_REDUCED_TX_POWER_BIT BIT(7)
static
inline
bool
is_loose_coex
(
void
)
{
return
iwlwifi_mod_params
.
ant_coupling
>
IWL_BT_ANTENNA_COUPLING_THRESHOLD
;
}
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
int
iwl_send_bt_prio_tbl
(
struct
iwl_mvm
*
mvm
)
{
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_NEWBT_COEX
))
return
0
;
return
iwl_mvm_send_cmd_pdu
(
mvm
,
BT_COEX_PRIO_TABLE
,
CMD_SYNC
,
sizeof
(
struct
iwl_bt_coex_prio_tbl_cmd
),
&
iwl_bt_prio_tbl
);
}
static
int
iwl_send_bt_env
(
struct
iwl_mvm
*
mvm
,
u8
action
,
u8
type
)
{
struct
iwl_bt_coex_prot_env_cmd
env_cmd
;
int
ret
;
env_cmd
.
action
=
action
;
env_cmd
.
type
=
type
;
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
BT_COEX_PROT_ENV
,
CMD_SYNC
,
sizeof
(
env_cmd
),
&
env_cmd
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to send BT env command
\n
"
);
return
ret
;
}
enum
iwl_bt_kill_msk
{
BT_KILL_MSK_DEFAULT
,
BT_KILL_MSK_SCO_HID_A2DP
,
BT_KILL_MSK_REDUCED_TXPOW
,
BT_KILL_MSK_MAX
,
};
static
const
u32
iwl_bt_ack_kill_msk
[
BT_KILL_MSK_MAX
]
=
{
const
u32
iwl_bt_ack_kill_msk
[
BT_KILL_MSK_MAX
]
=
{
[
BT_KILL_MSK_DEFAULT
]
=
0xffff0000
,
[
BT_KILL_MSK_SCO_HID_A2DP
]
=
0xffffffff
,
[
BT_KILL_MSK_REDUCED_TXPOW
]
=
0
,
};
static
const
u32
iwl_bt_cts_kill_msk
[
BT_KILL_MSK_MAX
]
=
{
const
u32
iwl_bt_cts_kill_msk
[
BT_KILL_MSK_MAX
]
=
{
[
BT_KILL_MSK_DEFAULT
]
=
0xffff0000
,
[
BT_KILL_MSK_SCO_HID_A2DP
]
=
0xffffffff
,
[
BT_KILL_MSK_REDUCED_TXPOW
]
=
0
,
};
#define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0)
/* Tight Coex */
static
const
__le32
iwl_tight_lookup
[
BT_COEX_LUT_SIZE
]
=
{
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaeaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xcc00ff28
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xcc00aaaa
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xf0005000
),
cpu_to_le32
(
0xf0005000
),
static
const
__le32
iwl_bt_prio_boost
[
BT_COEX_BOOST_SIZE
]
=
{
cpu_to_le32
(
0xf0f0f0f0
),
cpu_to_le32
(
0xc0c0c0c0
),
cpu_to_le32
(
0xfcfcfcfc
),
cpu_to_le32
(
0xff00ff00
),
};
/* Loose Coex */
static
const
__le32
iwl_loose_lookup
[
BT_COEX_LUT_SIZE
]
=
{
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xcc00ff28
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xcc00aaaa
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xf0005000
),
cpu_to_le32
(
0xf0005000
),
static
const
__le32
iwl_single_shared_ant
[
BT_COEX_MAX_LUT
][
BT_COEX_LUT_SIZE
]
=
{
{
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0xf0005000
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0xf0005000
),
},
{
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0xf0005000
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0xf0005000
),
},
{
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0xf0005000
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0xf0005000
),
},
};
/* Full concurrency */
static
const
__le32
iwl_concurrent_lookup
[
BT_COEX_LUT_SIZE
]
=
{
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x00000000
),
static
const
__le32
iwl_combined_lookup
[
BT_COEX_MAX_LUT
][
BT_COEX_LUT_SIZE
]
=
{
{
/* Tight */
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaeaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xcc00ff28
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xcc00aaaa
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xc0004000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xf0005000
),
cpu_to_le32
(
0xf0005000
),
},
{
/* Loose */
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xcc00ff28
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xcc00aaaa
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xf0005000
),
cpu_to_le32
(
0xf0005000
),
},
{
/* Tx Tx disabled */
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xaaaaaaaa
),
cpu_to_le32
(
0xcc00ff28
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xcc00aaaa
),
cpu_to_le32
(
0x0000aaaa
),
cpu_to_le32
(
0xC0004000
),
cpu_to_le32
(
0xC0004000
),
cpu_to_le32
(
0xF0005000
),
cpu_to_le32
(
0xF0005000
),
},
};
/* single shared antenna */
static
const
__le32
iwl_single_shared_ant_lookup
[
BT_COEX_LUT_SIZE
]
=
{
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x40000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0x44000000
),
cpu_to_le32
(
0x00000000
),
cpu_to_le32
(
0xC0004000
),
cpu_to_le32
(
0xF0005000
),
cpu_to_le32
(
0xC0004000
),
cpu_to_le32
(
0xF0005000
),
/* 20MHz / 40MHz below / 40Mhz above*/
static
const
__le64
iwl_ci_mask
[][
3
]
=
{
/* dummy entry for channel 0 */
{
cpu_to_le64
(
0
),
cpu_to_le64
(
0
),
cpu_to_le64
(
0
)},
{
cpu_to_le64
(
0x0000001FFFULL
),
cpu_to_le64
(
0x0ULL
),
cpu_to_le64
(
0x00007FFFFFULL
),
},
{
cpu_to_le64
(
0x000000FFFFULL
),
cpu_to_le64
(
0x0ULL
),
cpu_to_le64
(
0x0003FFFFFFULL
),
},
{
cpu_to_le64
(
0x000003FFFCULL
),
cpu_to_le64
(
0x0ULL
),
cpu_to_le64
(
0x000FFFFFFCULL
),
},
{
cpu_to_le64
(
0x00001FFFE0ULL
),
cpu_to_le64
(
0x0ULL
),
cpu_to_le64
(
0x007FFFFFE0ULL
),
},
{
cpu_to_le64
(
0x00007FFF80ULL
),
cpu_to_le64
(
0x00007FFFFFULL
),
cpu_to_le64
(
0x01FFFFFF80ULL
),
},
{
cpu_to_le64
(
0x0003FFFC00ULL
),
cpu_to_le64
(
0x0003FFFFFFULL
),
cpu_to_le64
(
0x0FFFFFFC00ULL
),
},
{
cpu_to_le64
(
0x000FFFF000ULL
),
cpu_to_le64
(
0x000FFFFFFCULL
),
cpu_to_le64
(
0x3FFFFFF000ULL
),
},
{
cpu_to_le64
(
0x007FFF8000ULL
),
cpu_to_le64
(
0x007FFFFFE0ULL
),
cpu_to_le64
(
0xFFFFFF8000ULL
),
},
{
cpu_to_le64
(
0x01FFFE0000ULL
),
cpu_to_le64
(
0x01FFFFFF80ULL
),
cpu_to_le64
(
0xFFFFFE0000ULL
),
},
{
cpu_to_le64
(
0x0FFFF00000ULL
),
cpu_to_le64
(
0x0FFFFFFC00ULL
),
cpu_to_le64
(
0x0ULL
),
},
{
cpu_to_le64
(
0x3FFFC00000ULL
),
cpu_to_le64
(
0x3FFFFFF000ULL
),
cpu_to_le64
(
0x0
)
},
{
cpu_to_le64
(
0xFFFE000000ULL
),
cpu_to_le64
(
0xFFFFFF8000ULL
),
cpu_to_le64
(
0x0
)
},
{
cpu_to_le64
(
0xFFF8000000ULL
),
cpu_to_le64
(
0xFFFFFE0000ULL
),
cpu_to_le64
(
0x0
)
},
{
cpu_to_le64
(
0xFE00000000ULL
),
cpu_to_le64
(
0x0ULL
),
cpu_to_le64
(
0x0
)
},
};
static
const
__le32
iwl_bt_mprio_lut
[
BT_COEX_MULTI_PRIO_LUT_SIZE
]
=
{
cpu_to_le32
(
0x22002200
),
cpu_to_le32
(
0x33113311
),
};
static
enum
iwl_bt_coex_lut_type
iwl_get_coex_type
(
struct
iwl_mvm
*
mvm
,
const
struct
ieee80211_vif
*
vif
)
{
struct
ieee80211_chanctx_conf
*
chanctx_conf
;
enum
iwl_bt_coex_lut_type
ret
;
u16
phy_ctx_id
;
/*
* Checking that we hold mvm->mutex is a good idea, but the rate
* control can't acquire the mutex since it runs in Tx path.
* So this is racy in that case, but in the worst case, the AMPDU
* size limit will be wrong for a short time which is not a big
* issue.
*/
rcu_read_lock
();
chanctx_conf
=
rcu_dereference
(
vif
->
chanctx_conf
);
if
(
!
chanctx_conf
||
chanctx_conf
->
def
.
chan
->
band
!=
IEEE80211_BAND_2GHZ
)
{
rcu_read_unlock
();
return
BT_COEX_LOOSE_LUT
;
}
ret
=
BT_COEX_TX_DIS_LUT
;
if
(
mvm
->
cfg
->
bt_shared_single_ant
)
{
rcu_read_unlock
();
return
ret
;
}
phy_ctx_id
=
*
((
u16
*
)
chanctx_conf
->
drv_priv
);
if
(
mvm
->
last_bt_ci_cmd
.
primary_ch_phy_id
==
phy_ctx_id
)
ret
=
le32_to_cpu
(
mvm
->
last_bt_notif
.
primary_ch_lut
);
else
if
(
mvm
->
last_bt_ci_cmd
.
secondary_ch_phy_id
==
phy_ctx_id
)
ret
=
le32_to_cpu
(
mvm
->
last_bt_notif
.
secondary_ch_lut
);
/* else - default = TX TX disallowed */
rcu_read_unlock
();
return
ret
;
}
int
iwl_send_bt_init_conf
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_bt_coex_cmd
*
bt_cmd
;
...
...
@@ -228,17 +360,10 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
.
flags
=
CMD_SYNC
,
};
int
ret
;
u32
flags
;
/* go to CALIB state in internal BT-Coex state machine */
ret
=
iwl_send_bt_env
(
mvm
,
BT_COEX_ENV_OPEN
,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2
);
if
(
ret
)
return
ret
;
ret
=
iwl_send_bt_env
(
mvm
,
BT_COEX_ENV_CLOSE
,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2
);
if
(
ret
)
return
ret
;
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_NEWBT_COEX
))
return
0
;
bt_cmd
=
kzalloc
(
sizeof
(
*
bt_cmd
),
GFP_KERNEL
);
if
(
!
bt_cmd
)
...
...
@@ -246,40 +371,52 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
cmd
.
data
[
0
]
=
bt_cmd
;
bt_cmd
->
max_kill
=
5
;
bt_cmd
->
bt3_time_t7_value
=
1
;
bt_cmd
->
bt3_prio_sample_time
=
2
;
bt_cmd
->
bt3_timer_t2_value
=
0xc
;
bt_cmd
->
bt4_antenna_isolation_thr
=
BT_ANTENNA_COUPLING_THRESHOLD
,
bt_cmd
->
bt4_antenna_isolation
=
iwlwifi_mod_params
.
ant_coupling
,
bt_cmd
->
bt4_tx_tx_delta_freq_thr
=
15
,
bt_cmd
->
bt4_tx_rx_max_freq0
=
15
,
bt_cmd
->
flags
=
iwlwifi_mod_params
.
bt_coex_active
?
flags
=
iwlwifi_mod_params
.
bt_coex_active
?
BT_COEX_NW
:
BT_COEX_DISABLE
;
bt_cmd
->
flags
|=
BT_CH_PRIMARY_EN
|
BT_SYNC_2_BT_DISABLE
;
flags
|=
BT_CH_PRIMARY_EN
|
BT_CH_SECONDARY_EN
|
BT_SYNC_2_BT_DISABLE
;
bt_cmd
->
flags
=
cpu_to_le32
(
flags
);
bt_cmd
->
valid_bit_msk
=
cpu_to_le
16
(
BT_VALID_ENABLE
|
bt_cmd
->
valid_bit_msk
=
cpu_to_le
32
(
BT_VALID_ENABLE
|
BT_VALID_BT_PRIO_BOOST
|
BT_VALID_MAX_KILL
|
BT_VALID_3W_TMRS
|
BT_VALID_KILL_ACK
|
BT_VALID_KILL_CTS
|
BT_VALID_REDUCED_TX_POWER
|
BT_VALID_LUT
);
BT_VALID_LUT
|
BT_VALID_WIFI_RX_SW_PRIO_BOOST
|
BT_VALID_WIFI_TX_SW_PRIO_BOOST
|
BT_VALID_MULTI_PRIO_LUT
|
BT_VALID_CORUN_LUT_20
|
BT_VALID_CORUN_LUT_40
|
BT_VALID_ANT_ISOLATION
|
BT_VALID_ANT_ISOLATION_THRS
|
BT_VALID_TXTX_DELTA_FREQ_THRS
|
BT_VALID_TXRX_MAX_FREQ_0
);
if
(
mvm
->
cfg
->
bt_shared_single_ant
)
memcpy
(
&
bt_cmd
->
decision_lut
,
iwl_single_shared_ant_lookup
,
sizeof
(
iwl_single_shared_ant_lookup
));
else
if
(
is_loose_coex
())
memcpy
(
&
bt_cmd
->
decision_lut
,
iwl_loose_lookup
,
sizeof
(
iwl_tight_lookup
));
memcpy
(
&
bt_cmd
->
decision_lut
,
iwl_single_shared_ant
,
sizeof
(
iwl_single_shared_ant
));
else
memcpy
(
&
bt_cmd
->
decision_lut
,
iwl_
tight
_lookup
,
sizeof
(
iwl_
tight
_lookup
));
memcpy
(
&
bt_cmd
->
decision_lut
,
iwl_
combined
_lookup
,
sizeof
(
iwl_
combined
_lookup
));
bt_cmd
->
bt_prio_boost
=
cpu_to_le32
(
IWL_BT_DEFAULT_BOOST
);
memcpy
(
&
bt_cmd
->
bt_prio_boost
,
iwl_bt_prio_boost
,
sizeof
(
iwl_bt_prio_boost
));
memcpy
(
&
bt_cmd
->
bt4_multiprio_lut
,
iwl_bt_mprio_lut
,
sizeof
(
iwl_bt_mprio_lut
));
bt_cmd
->
kill_ack_msk
=
cpu_to_le32
(
iwl_bt_ack_kill_msk
[
BT_KILL_MSK_DEFAULT
]);
bt_cmd
->
kill_cts_msk
=
cpu_to_le32
(
iwl_bt_cts_kill_msk
[
BT_KILL_MSK_DEFAULT
]);
memset
(
&
mvm
->
last_bt_notif
,
0
,
sizeof
(
mvm
->
last_bt_notif
));
memset
(
&
mvm
->
last_bt_ci_cmd
,
0
,
sizeof
(
mvm
->
last_bt_ci_cmd
));
ret
=
iwl_mvm_send_cmd
(
mvm
,
&
cmd
);
...
...
@@ -334,13 +471,17 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
if
(
!
bt_cmd
)
return
-
ENOMEM
;
cmd
.
data
[
0
]
=
bt_cmd
;
bt_cmd
->
flags
=
cpu_to_le32
(
BT_COEX_NW
);
bt_cmd
->
kill_ack_msk
=
cpu_to_le32
(
iwl_bt_ack_kill_msk
[
bt_kill_msk
]);
bt_cmd
->
kill_cts_msk
=
cpu_to_le32
(
iwl_bt_cts_kill_msk
[
bt_kill_msk
]);
bt_cmd
->
valid_bit_msk
=
cpu_to_le16
(
BT_VALID_KILL_ACK
|
BT_VALID_KILL_CTS
);
bt_cmd
->
valid_bit_msk
|=
cpu_to_le32
(
BT_VALID_ENABLE
|
BT_VALID_KILL_ACK
|
BT_VALID_KILL_CTS
);
IWL_DEBUG_COEX
(
mvm
,
"bt_kill_msk = %d
\n
"
,
bt_kill_msk
);
IWL_DEBUG_COEX
(
mvm
,
"ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x
\n
"
,
iwl_bt_ack_kill_msk
[
bt_kill_msk
],
iwl_bt_cts_kill_msk
[
bt_kill_msk
]);
ret
=
iwl_mvm_send_cmd
(
mvm
,
&
cmd
);
...
...
@@ -380,8 +521,10 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
if
(
!
bt_cmd
)
return
-
ENOMEM
;
cmd
.
data
[
0
]
=
bt_cmd
;
bt_cmd
->
flags
=
cpu_to_le32
(
BT_COEX_NW
);
bt_cmd
->
valid_bit_msk
=
cpu_to_le16
(
BT_VALID_REDUCED_TX_POWER
),
bt_cmd
->
valid_bit_msk
=
cpu_to_le32
(
BT_VALID_ENABLE
|
BT_VALID_REDUCED_TX_POWER
);
bt_cmd
->
bt_reduced_tx_power
=
sta_id
;
if
(
enable
)
...
...
@@ -403,8 +546,25 @@ struct iwl_bt_iterator_data {
struct
iwl_mvm
*
mvm
;
u32
num_bss_ifaces
;
bool
reduced_tx_power
;
struct
ieee80211_chanctx_conf
*
primary
;
struct
ieee80211_chanctx_conf
*
secondary
;
};
static
inline
void
iwl_mvm_bt_coex_enable_rssi_event
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
enable
,
int
rssi
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
mvmvif
->
bf_data
.
last_bt_coex_event
=
rssi
;
mvmvif
->
bf_data
.
bt_coex_max_thold
=
enable
?
BT_ENABLE_REDUCED_TXPOWER_THRESHOLD
:
0
;
mvmvif
->
bf_data
.
bt_coex_min_thold
=
enable
?
BT_DISABLE_REDUCED_TXPOWER_THRESHOLD
:
0
;
}
/* must be called under rcu_read_lock */
static
void
iwl_mvm_bt_notif_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
...
...
@@ -413,65 +573,94 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct
iwl_mvm
*
mvm
=
data
->
mvm
;
struct
ieee80211_chanctx_conf
*
chanctx_conf
;
enum
ieee80211_smps_mode
smps_mode
;
enum
ieee80211_band
band
;
int
ave_rssi
;
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
)
return
;
rcu_read_lock
();
chanctx_conf
=
rcu_dereference
(
vif
->
chanctx_conf
);
if
(
chanctx_conf
&&
chanctx_conf
->
def
.
chan
)
band
=
chanctx_conf
->
def
.
chan
->
band
;
else
band
=
-
1
;
rcu_read_unlock
();
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
&&
vif
->
type
!=
NL80211_IFTYPE_AP
)
return
;
smps_mode
=
IEEE80211_SMPS_AUTOMATIC
;
/* non associated BSSes aren't to be considered */
if
(
!
vif
->
bss_conf
.
assoc
)
chanctx_conf
=
rcu_dereference
(
vif
->
chanctx_conf
);
/* If channel context is invalid or not on 2.4GHz .. */
if
((
!
chanctx_conf
||
chanctx_conf
->
def
.
chan
->
band
!=
IEEE80211_BAND_2GHZ
))
{
/* ... and it is an associated STATION, relax constraints */
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
vif
->
bss_conf
.
assoc
)
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_BT_COEX
,
smps_mode
);
iwl_mvm_bt_coex_enable_rssi_event
(
mvm
,
vif
,
false
,
0
);
return
;
}
/* SoftAP / GO will always be primary */
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
if
(
!
mvmvif
->
ap_ibss_active
)
return
;
/* the Ack / Cts kill mask must be default if AP / GO */
data
->
reduced_tx_power
=
false
;
if
(
band
!=
IEEE80211_BAND_2GHZ
)
{
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_BT_COEX
,
smps_mode
);
if
(
chanctx_conf
==
data
->
primary
)
return
;
/* downgrade the current primary no matter what its type is */
data
->
secondary
=
data
->
primary
;
data
->
primary
=
chanctx_conf
;
return
;
}
if
(
data
->
notif
->
bt_status
)
smps_mode
=
IEEE80211_SMPS_DYNAMIC
;
data
->
num_bss_ifaces
++
;
/* we are now a STA / P2P Client, and take associated ones only */
if
(
!
vif
->
bss_conf
.
assoc
)
return
;
/* STA / P2P Client, try to be primary if first vif */
if
(
!
data
->
primary
||
data
->
primary
==
chanctx_conf
)
data
->
primary
=
chanctx_conf
;
else
if
(
!
data
->
secondary
)
/* if secondary is not NULL, it might be a GO */
data
->
secondary
=
chanctx_conf
;
if
(
data
->
notif
->
bt_traffic_load
>=
IWL_BT_LOAD_FORCE_SISO_THRESHOLD
)
if
(
le32_to_cpu
(
data
->
notif
->
bt_activity_grading
)
>=
BT_HIGH_TRAFFIC
)
smps_mode
=
IEEE80211_SMPS_STATIC
;
else
if
(
le32_to_cpu
(
data
->
notif
->
bt_activity_grading
)
>=
BT_LOW_TRAFFIC
)
smps_mode
=
IEEE80211_SMPS_DYNAMIC
;
IWL_DEBUG_COEX
(
data
->
mvm
,
"mac %d: bt_status %d
traffic_load
%d smps_req %d
\n
"
,
"mac %d: bt_status %d
bt_activity_grading
%d smps_req %d
\n
"
,
mvmvif
->
id
,
data
->
notif
->
bt_status
,
data
->
notif
->
bt_
traffic_load
,
smps_mode
);
data
->
notif
->
bt_
activity_grading
,
smps_mode
);
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_BT_COEX
,
smps_mode
);
/* don't reduce the Tx power if in loose scheme */
if
(
is_loose_coex
())
if
(
iwl_get_coex_type
(
mvm
,
vif
)
==
BT_COEX_LOOSE_LUT
||
mvm
->
cfg
->
bt_shared_single_ant
)
{
data
->
reduced_tx_power
=
false
;
iwl_mvm_bt_coex_enable_rssi_event
(
mvm
,
vif
,
false
,
0
);
return
;
}
data
->
num_bss_ifaces
++
;
/* reduced Txpower only if there are open BT connections, so ...*/
if
(
!
BT_MBOX_MSG
(
data
->
notif
,
3
,
OPEN_CON_2
))
{
/* reduced Txpower only if BT is on, so ...*/
if
(
!
data
->
notif
->
bt_status
)
{
/* ... cancel reduced Tx power ... */
if
(
iwl_mvm_bt_coex_reduced_txp
(
mvm
,
mvmvif
->
ap_sta_id
,
false
))
IWL_ERR
(
mvm
,
"Couldn't send BT_CONFIG cmd
\n
"
);
data
->
reduced_tx_power
=
false
;
/* ... and there is no need to get reports on RSSI any more. */
i
eee80211_disable_rssi_reports
(
vif
);
i
wl_mvm_bt_coex_enable_rssi_event
(
mvm
,
vif
,
false
,
0
);
return
;
}
ave_rssi
=
ieee80211_ave_rssi
(
vif
);
/* try to get the avg rssi from fw */
ave_rssi
=
mvmvif
->
bf_data
.
ave_beacon_signal
;
/* if the RSSI isn't valid, fake it is very low */
if
(
!
ave_rssi
)
...
...
@@ -499,8 +688,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
}
/* Begin to monitor the RSSI: it may influence the reduced Tx power */
ieee80211_enable_rssi_reports
(
vif
,
BT_DISABLE_REDUCED_TXPOWER_THRESHOLD
,
BT_ENABLE_REDUCED_TXPOWER_THRESHOLD
);
iwl_mvm_bt_coex_enable_rssi_event
(
mvm
,
vif
,
true
,
ave_rssi
);
}
static
void
iwl_mvm_bt_coex_notif_handle
(
struct
iwl_mvm
*
mvm
)
...
...
@@ -510,11 +698,72 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
.
notif
=
&
mvm
->
last_bt_notif
,
.
reduced_tx_power
=
true
,
};
struct
iwl_bt_coex_ci_cmd
cmd
=
{};
u8
ci_bw_idx
;
rcu_read_lock
();
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_bt_notif_iterator
,
&
data
);
if
(
data
.
primary
)
{
struct
ieee80211_chanctx_conf
*
chan
=
data
.
primary
;
if
(
WARN_ON
(
!
chan
->
def
.
chan
))
{
rcu_read_unlock
();
return
;
}
if
(
chan
->
def
.
width
<
NL80211_CHAN_WIDTH_40
)
{
ci_bw_idx
=
0
;
cmd
.
co_run_bw_primary
=
0
;
}
else
{
cmd
.
co_run_bw_primary
=
1
;
if
(
chan
->
def
.
center_freq1
>
chan
->
def
.
chan
->
center_freq
)
ci_bw_idx
=
2
;
else
ci_bw_idx
=
1
;
}
cmd
.
bt_primary_ci
=
iwl_ci_mask
[
chan
->
def
.
chan
->
hw_value
][
ci_bw_idx
];
cmd
.
primary_ch_phy_id
=
*
((
u16
*
)
data
.
primary
->
drv_priv
);
}
if
(
data
.
secondary
)
{
struct
ieee80211_chanctx_conf
*
chan
=
data
.
secondary
;
if
(
WARN_ON
(
!
data
.
secondary
->
def
.
chan
))
{
rcu_read_unlock
();
return
;
}
if
(
chan
->
def
.
width
<
NL80211_CHAN_WIDTH_40
)
{
ci_bw_idx
=
0
;
cmd
.
co_run_bw_secondary
=
0
;
}
else
{
cmd
.
co_run_bw_secondary
=
1
;
if
(
chan
->
def
.
center_freq1
>
chan
->
def
.
chan
->
center_freq
)
ci_bw_idx
=
2
;
else
ci_bw_idx
=
1
;
}
cmd
.
bt_secondary_ci
=
iwl_ci_mask
[
chan
->
def
.
chan
->
hw_value
][
ci_bw_idx
];
cmd
.
secondary_ch_phy_id
=
*
((
u16
*
)
data
.
primary
->
drv_priv
);
}
rcu_read_unlock
();
/* Don't spam the fw with the same command over and over */
if
(
memcmp
(
&
cmd
,
&
mvm
->
last_bt_ci_cmd
,
sizeof
(
cmd
)))
{
if
(
iwl_mvm_send_cmd_pdu
(
mvm
,
BT_COEX_CI
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
))
IWL_ERR
(
mvm
,
"Failed to send BT_CI cmd"
);
memcpy
(
&
mvm
->
last_bt_ci_cmd
,
&
cmd
,
sizeof
(
cmd
));
}
/*
* If there are no BSS / P2P client interfaces, reduced Tx Power is
* irrelevant since it is based on the RSSI coming from the beacon.
...
...
@@ -536,12 +785,18 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
IWL_DEBUG_COEX
(
mvm
,
"BT Coex Notification received
\n
"
);
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT %salive
\n
"
,
notif
->
bt_status
?
""
:
"not "
);
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT status: %s
\n
"
,
notif
->
bt_status
?
"ON"
:
"OFF"
);
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT open conn %d
\n
"
,
notif
->
bt_open_conn
);
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT traffic load %d
\n
"
,
notif
->
bt_traffic_load
);
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT ci compliance %d
\n
"
,
notif
->
bt_ci_compliance
);
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT primary_ch_lut %d
\n
"
,
le32_to_cpu
(
notif
->
primary_ch_lut
));
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT secondary_ch_lut %d
\n
"
,
le32_to_cpu
(
notif
->
secondary_ch_lut
));
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT activity grading %d
\n
"
,
le32_to_cpu
(
notif
->
bt_activity_grading
));
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT agg traffic load %d
\n
"
,
notif
->
bt_agg_traffic_load
);
IWL_DEBUG_COEX
(
mvm
,
"
\t
BT ci compliance %d
\n
"
,
notif
->
bt_ci_compliance
);
/* remember this notification for future use: rssi fluctuations */
memcpy
(
&
mvm
->
last_bt_notif
,
notif
,
sizeof
(
mvm
->
last_bt_notif
));
...
...
@@ -565,6 +820,18 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
struct
ieee80211_sta
*
sta
;
struct
iwl_mvm_sta
*
mvmsta
;
struct
ieee80211_chanctx_conf
*
chanctx_conf
;
rcu_read_lock
();
chanctx_conf
=
rcu_dereference
(
vif
->
chanctx_conf
);
/* If channel context is invalid or not on 2.4GHz - don't count it */
if
(
!
chanctx_conf
||
chanctx_conf
->
def
.
chan
->
band
!=
IEEE80211_BAND_2GHZ
)
{
rcu_read_unlock
();
return
;
}
rcu_read_unlock
();
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
mvmvif
->
ap_sta_id
==
IWL_MVM_STATION_COUNT
)
return
;
...
...
@@ -594,15 +861,15 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
};
int
ret
;
mutex_lock
(
&
mvm
->
mutex
);
lockdep_assert_held
(
&
mvm
->
mutex
);
/* Rssi update while not associated ?! */
if
(
WARN_ON_ONCE
(
mvmvif
->
ap_sta_id
==
IWL_MVM_STATION_COUNT
))
goto
out_unlock
;
return
;
/* No
open connection
- reports should be disabled */
if
(
!
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
OPEN_CON_2
)
)
goto
out_unlock
;
/* No
BT
- reports should be disabled */
if
(
!
mvm
->
last_bt_notif
.
bt_status
)
return
;
IWL_DEBUG_COEX
(
mvm
,
"RSSI for %pM is now %s
\n
"
,
vif
->
bss_conf
.
bssid
,
rssi_event
==
RSSI_EVENT_HIGH
?
"HIGH"
:
"LOW"
);
...
...
@@ -611,7 +878,8 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* Check if rssi is good enough for reduced Tx power, but not in loose
* scheme.
*/
if
(
rssi_event
==
RSSI_EVENT_LOW
||
is_loose_coex
())
if
(
rssi_event
==
RSSI_EVENT_LOW
||
mvm
->
cfg
->
bt_shared_single_ant
||
iwl_get_coex_type
(
mvm
,
vif
)
==
BT_COEX_LOOSE_LUT
)
ret
=
iwl_mvm_bt_coex_reduced_txp
(
mvm
,
mvmvif
->
ap_sta_id
,
false
);
else
...
...
@@ -633,12 +901,52 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if
(
iwl_mvm_bt_udpate_ctrl_kill_msk
(
mvm
,
data
.
reduced_tx_power
))
IWL_ERR
(
mvm
,
"Failed to update the ctrl_kill_msk
\n
"
);
}
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200)
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
u16
iwl_mvm_bt_coex_agg_time_limit
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
enum
iwl_bt_coex_lut_type
lut_type
;
if
(
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
<
BT_LOW_TRAFFIC
)
return
LINK_QUAL_AGG_TIME_LIMIT_DEF
;
lut_type
=
iwl_get_coex_type
(
mvm
,
mvmsta
->
vif
);
if
(
lut_type
==
BT_COEX_LOOSE_LUT
)
return
LINK_QUAL_AGG_TIME_LIMIT_DEF
;
/* tight coex, high bt traffic, reduce AGG time limit */
return
LINK_QUAL_AGG_TIME_LIMIT_BT_ACT
;
}
bool
iwl_mvm_bt_coex_is_mimo_allowed
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
if
(
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
<
BT_HIGH_TRAFFIC
)
return
true
;
/*
* In Tight, BT can't Rx while we Tx, so use both antennas since BT is
* already killed.
* In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we
* Tx.
*/
return
iwl_get_coex_type
(
mvm
,
mvmsta
->
vif
)
==
BT_COEX_TIGHT_LUT
;
}
void
iwl_mvm_bt_coex_vif_
assoc
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
void
iwl_mvm_bt_coex_vif_
change
(
struct
iwl_mvm
*
mvm
)
{
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_NEWBT_COEX
))
return
;
iwl_mvm_bt_coex_notif_handle
(
mvm
);
}
drivers/net/wireless/iwlwifi/mvm/constants.h
View file @
444474dd
...
...
@@ -70,7 +70,9 @@
#define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20
#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 20
#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8
#define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30
#define IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS 20
#define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50
#define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50
#define IWL_MVM_PS_SNOOZE_INTERVAL 25
...
...
drivers/net/wireless/iwlwifi/mvm/d3.c
View file @
444474dd
...
...
@@ -67,6 +67,7 @@
#include <net/cfg80211.h>
#include <net/ipv6.h>
#include <net/tcp.h>
#include <net/addrconf.h>
#include "iwl-modparams.h"
#include "fw-api.h"
#include "mvm.h"
...
...
@@ -381,14 +382,74 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
union
{
struct
iwl_proto_offload_cmd_v1
v1
;
struct
iwl_proto_offload_cmd_v2
v2
;
struct
iwl_proto_offload_cmd_v3_small
v3s
;
struct
iwl_proto_offload_cmd_v3_large
v3l
;
}
cmd
=
{};
struct
iwl_host_cmd
hcmd
=
{
.
id
=
PROT_OFFLOAD_CONFIG_CMD
,
.
flags
=
CMD_SYNC
,
.
data
[
0
]
=
&
cmd
,
.
dataflags
[
0
]
=
IWL_HCMD_DFL_DUP
,
};
struct
iwl_proto_offload_cmd_common
*
common
;
u32
enabled
=
0
,
size
;
u32
capa_flags
=
mvm
->
fw
->
ucode_capa
.
flags
;
#if IS_ENABLED(CONFIG_IPV6)
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
int
i
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS
)
{
if
(
capa_flags
&
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL
||
capa_flags
&
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE
)
{
struct
iwl_ns_config
*
nsc
;
struct
iwl_targ_addr
*
addrs
;
int
n_nsc
,
n_addrs
;
int
c
;
if
(
capa_flags
&
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL
)
{
nsc
=
cmd
.
v3s
.
ns_config
;
n_nsc
=
IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S
;
addrs
=
cmd
.
v3s
.
targ_addrs
;
n_addrs
=
IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S
;
}
else
{
nsc
=
cmd
.
v3l
.
ns_config
;
n_nsc
=
IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L
;
addrs
=
cmd
.
v3l
.
targ_addrs
;
n_addrs
=
IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L
;
}
if
(
mvmvif
->
num_target_ipv6_addrs
)
enabled
|=
IWL_D3_PROTO_OFFLOAD_NS
;
/*
* For each address we have (and that will fit) fill a target
* address struct and combine for NS offload structs with the
* solicited node addresses.
*/
for
(
i
=
0
,
c
=
0
;
i
<
mvmvif
->
num_target_ipv6_addrs
&&
i
<
n_addrs
&&
c
<
n_nsc
;
i
++
)
{
struct
in6_addr
solicited_addr
;
int
j
;
addrconf_addr_solict_mult
(
&
mvmvif
->
target_ipv6_addrs
[
i
],
&
solicited_addr
);
for
(
j
=
0
;
j
<
c
;
j
++
)
if
(
ipv6_addr_cmp
(
&
nsc
[
j
].
dest_ipv6_addr
,
&
solicited_addr
)
==
0
)
break
;
if
(
j
==
c
)
c
++
;
addrs
[
i
].
addr
=
mvmvif
->
target_ipv6_addrs
[
i
];
addrs
[
i
].
config_num
=
cpu_to_le32
(
j
);
nsc
[
j
].
dest_ipv6_addr
=
solicited_addr
;
memcpy
(
nsc
[
j
].
target_mac_addr
,
vif
->
addr
,
ETH_ALEN
);
}
if
(
capa_flags
&
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL
)
cmd
.
v3s
.
num_valid_ipv6_addrs
=
cpu_to_le32
(
i
);
else
cmd
.
v3l
.
num_valid_ipv6_addrs
=
cpu_to_le32
(
i
);
}
else
if
(
capa_flags
&
IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS
)
{
if
(
mvmvif
->
num_target_ipv6_addrs
)
{
enabled
|=
IWL_D3_PROTO_OFFLOAD_NS
;
memcpy
(
cmd
.
v2
.
ndp_mac_addr
,
vif
->
addr
,
ETH_ALEN
);
...
...
@@ -419,7 +480,13 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
}
#endif
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS
)
{
if
(
capa_flags
&
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL
)
{
common
=
&
cmd
.
v3s
.
common
;
size
=
sizeof
(
cmd
.
v3s
);
}
else
if
(
capa_flags
&
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE
)
{
common
=
&
cmd
.
v3l
.
common
;
size
=
sizeof
(
cmd
.
v3l
);
}
else
if
(
capa_flags
&
IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS
)
{
common
=
&
cmd
.
v2
.
common
;
size
=
sizeof
(
cmd
.
v2
);
}
else
{
...
...
@@ -438,8 +505,8 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
common
->
enabled
=
cpu_to_le32
(
enabled
);
return
iwl_mvm_send_cmd_pdu
(
mvm
,
PROT_OFFLOAD_CONFIG_CMD
,
CMD_SYNC
,
size
,
&
cmd
);
hcmd
.
len
[
0
]
=
size
;
return
iwl_mvm_send_cmd
(
mvm
,
&
h
cmd
);
}
enum
iwl_mvm_tcp_packet_type
{
...
...
@@ -793,6 +860,74 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return
0
;
}
static
int
iwl_mvm_get_last_nonqos_seq
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_nonqos_seq_query_cmd
query_cmd
=
{
.
get_set_flag
=
cpu_to_le32
(
IWL_NONQOS_SEQ_GET
),
.
mac_id_n_color
=
cpu_to_le32
(
FW_CMD_ID_AND_COLOR
(
mvmvif
->
id
,
mvmvif
->
color
)),
};
struct
iwl_host_cmd
cmd
=
{
.
id
=
NON_QOS_TX_COUNTER_CMD
,
.
flags
=
CMD_SYNC
|
CMD_WANT_SKB
,
};
int
err
;
u32
size
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API
)
{
cmd
.
data
[
0
]
=
&
query_cmd
;
cmd
.
len
[
0
]
=
sizeof
(
query_cmd
);
}
err
=
iwl_mvm_send_cmd
(
mvm
,
&
cmd
);
if
(
err
)
return
err
;
size
=
le32_to_cpu
(
cmd
.
resp_pkt
->
len_n_flags
)
&
FH_RSCSR_FRAME_SIZE_MSK
;
size
-=
sizeof
(
cmd
.
resp_pkt
->
hdr
);
if
(
size
<
sizeof
(
__le16
))
{
err
=
-
EINVAL
;
}
else
{
err
=
le16_to_cpup
((
__le16
*
)
cmd
.
resp_pkt
->
data
);
/* new API returns next, not last-used seqno */
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API
)
err
-=
0x10
;
}
iwl_free_resp
(
&
cmd
);
return
err
;
}
void
iwl_mvm_set_last_nonqos_seq
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_nonqos_seq_query_cmd
query_cmd
=
{
.
get_set_flag
=
cpu_to_le32
(
IWL_NONQOS_SEQ_SET
),
.
mac_id_n_color
=
cpu_to_le32
(
FW_CMD_ID_AND_COLOR
(
mvmvif
->
id
,
mvmvif
->
color
)),
.
value
=
cpu_to_le16
(
mvmvif
->
seqno
),
};
/* return if called during restart, not resume from D3 */
if
(
!
mvmvif
->
seqno_valid
)
return
;
mvmvif
->
seqno_valid
=
false
;
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API
))
return
;
if
(
iwl_mvm_send_cmd_pdu
(
mvm
,
NON_QOS_TX_COUNTER_CMD
,
CMD_SYNC
,
sizeof
(
query_cmd
),
&
query_cmd
))
IWL_ERR
(
mvm
,
"failed to set non-QoS seqno
\n
"
);
}
static
int
__iwl_mvm_suspend
(
struct
ieee80211_hw
*
hw
,
struct
cfg80211_wowlan
*
wowlan
,
bool
test
)
...
...
@@ -829,7 +964,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
};
int
ret
,
i
;
int
len
__maybe_unused
;
u16
seq
;
u8
old_aux_sta_id
,
old_ap_sta_id
=
IWL_MVM_STATION_COUNT
;
if
(
!
wowlan
)
{
...
...
@@ -872,26 +1006,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvm_ap_sta
=
(
struct
iwl_mvm_sta
*
)
ap_sta
->
drv_priv
;
/*
* The D3 firmware still hardcodes the AP station ID for the
* BSS we're associated with as 0. Store the real STA ID here
* and assign 0. When we leave this function, we'll restore
* the original value for the resume code.
*/
old_ap_sta_id
=
mvm_ap_sta
->
sta_id
;
mvm_ap_sta
->
sta_id
=
0
;
mvmvif
->
ap_sta_id
=
0
;
/* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
wowlan_config_cmd
.
is_11n_connection
=
ap_sta
->
ht_cap
.
ht_supported
;
/*
* We know the last used seqno, and the uCode expects to know that
* one, it will increment before TX.
*/
seq
=
mvm_ap_sta
->
last_seq_ctl
&
IEEE80211_SCTL_SEQ
;
wowlan_config_cmd
.
non_qos_seq
=
cpu_to_le16
(
seq
);
/* Query the last used seqno and set it */
ret
=
iwl_mvm_get_last_nonqos_seq
(
mvm
,
vif
);
if
(
ret
<
0
)
goto
out_noreset
;
wowlan_config_cmd
.
non_qos_seq
=
cpu_to_le16
(
ret
);
/*
* For QoS counters, we store the one to use next, so subtract 0x10
...
...
@@ -899,7 +1022,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
* increment after using the value (i.e. store the next value to use).
*/
for
(
i
=
0
;
i
<
IWL_MAX_TID_COUNT
;
i
++
)
{
seq
=
mvm_ap_sta
->
tid_data
[
i
].
seq_number
;
u16
seq
=
mvm_ap_sta
->
tid_data
[
i
].
seq_number
;
seq
-=
0x10
;
wowlan_config_cmd
.
qos_seq
[
i
]
=
cpu_to_le16
(
seq
);
}
...
...
@@ -944,6 +1067,16 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
iwl_trans_stop_device
(
mvm
->
trans
);
/*
* The D3 firmware still hardcodes the AP station ID for the
* BSS we're associated with as 0. Store the real STA ID here
* and assign 0. When we leave this function, we'll restore
* the original value for the resume code.
*/
old_ap_sta_id
=
mvm_ap_sta
->
sta_id
;
mvm_ap_sta
->
sta_id
=
0
;
mvmvif
->
ap_sta_id
=
0
;
/*
* Set the HW restart bit -- this is mostly true as we're
* going to load new firmware and reprogram that, though
...
...
@@ -1059,6 +1192,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
if
(
ret
)
goto
out
;
ret
=
iwl_mvm_power_update_device_mode
(
mvm
);
if
(
ret
)
goto
out
;
ret
=
iwl_mvm_power_update_mode
(
mvm
,
vif
);
if
(
ret
)
goto
out
;
...
...
@@ -1109,16 +1246,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
return
__iwl_mvm_suspend
(
hw
,
wowlan
,
false
);
}
/* converted data from the different status responses */
struct
iwl_wowlan_status_data
{
u16
pattern_number
;
u16
qos_seq_ctr
[
8
];
u32
wakeup_reasons
;
u32
wake_packet_length
;
u32
wake_packet_bufsize
;
const
u8
*
wake_packet
;
};
static
void
iwl_mvm_report_wakeup_reasons
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_wowlan_status
*
status
)
struct
iwl_wowlan_status
_data
*
status
)
{
struct
sk_buff
*
pkt
=
NULL
;
struct
cfg80211_wowlan_wakeup
wakeup
=
{
.
pattern_idx
=
-
1
,
};
struct
cfg80211_wowlan_wakeup
*
wakeup_report
=
&
wakeup
;
u32
reasons
=
le32_to_cpu
(
status
->
wakeup_reasons
)
;
u32
reasons
=
status
->
wakeup_reasons
;
if
(
reasons
==
IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS
)
{
wakeup_report
=
NULL
;
...
...
@@ -1130,7 +1277,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
if
(
reasons
&
IWL_WOWLAN_WAKEUP_BY_PATTERN
)
wakeup
.
pattern_idx
=
le16_to_cpu
(
status
->
pattern_number
)
;
status
->
pattern_number
;
if
(
reasons
&
(
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON
|
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH
))
...
...
@@ -1158,8 +1305,8 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
wakeup
.
tcp_match
=
true
;
if
(
status
->
wake_packet_bufsize
)
{
int
pktsize
=
le32_to_cpu
(
status
->
wake_packet_bufsize
)
;
int
pktlen
=
le32_to_cpu
(
status
->
wake_packet_length
)
;
int
pktsize
=
status
->
wake_packet_bufsize
;
int
pktlen
=
status
->
wake_packet_length
;
const
u8
*
pktdata
=
status
->
wake_packet
;
struct
ieee80211_hdr
*
hdr
=
(
void
*
)
pktdata
;
int
truncated
=
pktlen
-
pktsize
;
...
...
@@ -1239,8 +1386,229 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
kfree_skb
(
pkt
);
}
static
void
iwl_mvm_aes_sc_to_seq
(
struct
aes_sc
*
sc
,
struct
ieee80211_key_seq
*
seq
)
{
u64
pn
;
pn
=
le64_to_cpu
(
sc
->
pn
);
seq
->
ccmp
.
pn
[
0
]
=
pn
>>
40
;
seq
->
ccmp
.
pn
[
1
]
=
pn
>>
32
;
seq
->
ccmp
.
pn
[
2
]
=
pn
>>
24
;
seq
->
ccmp
.
pn
[
3
]
=
pn
>>
16
;
seq
->
ccmp
.
pn
[
4
]
=
pn
>>
8
;
seq
->
ccmp
.
pn
[
5
]
=
pn
;
}
static
void
iwl_mvm_tkip_sc_to_seq
(
struct
tkip_sc
*
sc
,
struct
ieee80211_key_seq
*
seq
)
{
seq
->
tkip
.
iv32
=
le32_to_cpu
(
sc
->
iv32
);
seq
->
tkip
.
iv16
=
le16_to_cpu
(
sc
->
iv16
);
}
static
void
iwl_mvm_set_aes_rx_seq
(
struct
aes_sc
*
scs
,
struct
ieee80211_key_conf
*
key
)
{
int
tid
;
BUILD_BUG_ON
(
IWL_NUM_RSC
!=
IEEE80211_NUM_TIDS
);
for
(
tid
=
0
;
tid
<
IWL_NUM_RSC
;
tid
++
)
{
struct
ieee80211_key_seq
seq
=
{};
iwl_mvm_aes_sc_to_seq
(
&
scs
[
tid
],
&
seq
);
ieee80211_set_key_rx_seq
(
key
,
tid
,
&
seq
);
}
}
static
void
iwl_mvm_set_tkip_rx_seq
(
struct
tkip_sc
*
scs
,
struct
ieee80211_key_conf
*
key
)
{
int
tid
;
BUILD_BUG_ON
(
IWL_NUM_RSC
!=
IEEE80211_NUM_TIDS
);
for
(
tid
=
0
;
tid
<
IWL_NUM_RSC
;
tid
++
)
{
struct
ieee80211_key_seq
seq
=
{};
iwl_mvm_tkip_sc_to_seq
(
&
scs
[
tid
],
&
seq
);
ieee80211_set_key_rx_seq
(
key
,
tid
,
&
seq
);
}
}
static
void
iwl_mvm_set_key_rx_seq
(
struct
ieee80211_key_conf
*
key
,
struct
iwl_wowlan_status_v6
*
status
)
{
union
iwl_all_tsc_rsc
*
rsc
=
&
status
->
gtk
.
rsc
.
all_tsc_rsc
;
switch
(
key
->
cipher
)
{
case
WLAN_CIPHER_SUITE_CCMP
:
iwl_mvm_set_aes_rx_seq
(
rsc
->
aes
.
multicast_rsc
,
key
);
break
;
case
WLAN_CIPHER_SUITE_TKIP
:
iwl_mvm_set_tkip_rx_seq
(
rsc
->
tkip
.
multicast_rsc
,
key
);
break
;
default:
WARN_ON
(
1
);
}
}
struct
iwl_mvm_d3_gtk_iter_data
{
struct
iwl_wowlan_status_v6
*
status
;
void
*
last_gtk
;
u32
cipher
;
bool
find_phase
,
unhandled_cipher
;
int
num_keys
;
};
static
void
iwl_mvm_d3_update_gtks
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
key
,
void
*
_data
)
{
struct
iwl_mvm_d3_gtk_iter_data
*
data
=
_data
;
if
(
data
->
unhandled_cipher
)
return
;
switch
(
key
->
cipher
)
{
case
WLAN_CIPHER_SUITE_WEP40
:
case
WLAN_CIPHER_SUITE_WEP104
:
/* ignore WEP completely, nothing to do */
return
;
case
WLAN_CIPHER_SUITE_CCMP
:
case
WLAN_CIPHER_SUITE_TKIP
:
/* we support these */
break
;
default:
/* everything else (even CMAC for MFP) - disconnect from AP */
data
->
unhandled_cipher
=
true
;
return
;
}
data
->
num_keys
++
;
/*
* pairwise key - update sequence counters only;
* note that this assumes no TDLS sessions are active
*/
if
(
sta
)
{
struct
ieee80211_key_seq
seq
=
{};
union
iwl_all_tsc_rsc
*
sc
=
&
data
->
status
->
gtk
.
rsc
.
all_tsc_rsc
;
if
(
data
->
find_phase
)
return
;
switch
(
key
->
cipher
)
{
case
WLAN_CIPHER_SUITE_CCMP
:
iwl_mvm_aes_sc_to_seq
(
&
sc
->
aes
.
tsc
,
&
seq
);
iwl_mvm_set_aes_rx_seq
(
sc
->
aes
.
unicast_rsc
,
key
);
break
;
case
WLAN_CIPHER_SUITE_TKIP
:
iwl_mvm_tkip_sc_to_seq
(
&
sc
->
tkip
.
tsc
,
&
seq
);
iwl_mvm_set_tkip_rx_seq
(
sc
->
tkip
.
unicast_rsc
,
key
);
break
;
}
ieee80211_set_key_tx_seq
(
key
,
&
seq
);
/* that's it for this key */
return
;
}
if
(
data
->
find_phase
)
{
data
->
last_gtk
=
key
;
data
->
cipher
=
key
->
cipher
;
return
;
}
if
(
data
->
status
->
num_of_gtk_rekeys
)
ieee80211_remove_key
(
key
);
else
if
(
data
->
last_gtk
==
key
)
iwl_mvm_set_key_rx_seq
(
key
,
data
->
status
);
}
static
bool
iwl_mvm_setup_connection_keep
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_wowlan_status_v6
*
status
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm_d3_gtk_iter_data
gtkdata
=
{
.
status
=
status
,
};
if
(
!
status
||
!
vif
->
bss_conf
.
bssid
)
return
false
;
/* find last GTK that we used initially, if any */
gtkdata
.
find_phase
=
true
;
ieee80211_iter_keys
(
mvm
->
hw
,
vif
,
iwl_mvm_d3_update_gtks
,
&
gtkdata
);
/* not trying to keep connections with MFP/unhandled ciphers */
if
(
gtkdata
.
unhandled_cipher
)
return
false
;
if
(
!
gtkdata
.
num_keys
)
return
true
;
if
(
!
gtkdata
.
last_gtk
)
return
false
;
/*
* invalidate all other GTKs that might still exist and update
* the one that we used
*/
gtkdata
.
find_phase
=
false
;
ieee80211_iter_keys
(
mvm
->
hw
,
vif
,
iwl_mvm_d3_update_gtks
,
&
gtkdata
);
if
(
status
->
num_of_gtk_rekeys
)
{
struct
ieee80211_key_conf
*
key
;
struct
{
struct
ieee80211_key_conf
conf
;
u8
key
[
32
];
}
conf
=
{
.
conf
.
cipher
=
gtkdata
.
cipher
,
.
conf
.
keyidx
=
status
->
gtk
.
key_index
,
};
switch
(
gtkdata
.
cipher
)
{
case
WLAN_CIPHER_SUITE_CCMP
:
conf
.
conf
.
keylen
=
WLAN_KEY_LEN_CCMP
;
memcpy
(
conf
.
conf
.
key
,
status
->
gtk
.
decrypt_key
,
WLAN_KEY_LEN_CCMP
);
break
;
case
WLAN_CIPHER_SUITE_TKIP
:
conf
.
conf
.
keylen
=
WLAN_KEY_LEN_TKIP
;
memcpy
(
conf
.
conf
.
key
,
status
->
gtk
.
decrypt_key
,
16
);
/* leave TX MIC key zeroed, we don't use it anyway */
memcpy
(
conf
.
conf
.
key
+
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY
,
status
->
gtk
.
tkip_mic_key
,
8
);
break
;
}
key
=
ieee80211_gtk_rekey_add
(
vif
,
&
conf
.
conf
);
if
(
IS_ERR
(
key
))
return
false
;
iwl_mvm_set_key_rx_seq
(
key
,
status
);
}
if
(
status
->
num_of_gtk_rekeys
)
{
__be64
replay_ctr
=
cpu_to_be64
(
le64_to_cpu
(
status
->
replay_ctr
));
ieee80211_gtk_rekey_notify
(
vif
,
vif
->
bss_conf
.
bssid
,
(
void
*
)
&
replay_ctr
,
GFP_KERNEL
);
}
mvmvif
->
seqno_valid
=
true
;
/* +0x10 because the set API expects next-to-use, not last-used */
mvmvif
->
seqno
=
le16_to_cpu
(
status
->
non_qos_seq_ctr
)
+
0x10
;
return
true
;
}
/* releases the MVM mutex */
static
void
iwl_mvm_query_wakeup_reasons
(
struct
iwl_mvm
*
mvm
,
static
bool
iwl_mvm_query_wakeup_reasons
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
u32
base
=
mvm
->
error_event_table
;
...
...
@@ -1253,8 +1621,12 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
.
id
=
WOWLAN_GET_STATUSES
,
.
flags
=
CMD_SYNC
|
CMD_WANT_SKB
,
};
struct
iwl_wowlan_status
*
status
;
int
ret
,
len
;
struct
iwl_wowlan_status_data
status
;
struct
iwl_wowlan_status_v6
*
status_v6
;
int
ret
,
len
,
status_size
,
i
;
bool
keep
;
struct
ieee80211_sta
*
ap_sta
;
struct
iwl_mvm_sta
*
mvm_ap_sta
;
iwl_trans_read_mem_bytes
(
mvm
->
trans
,
base
,
&
err_info
,
sizeof
(
err_info
));
...
...
@@ -1287,32 +1659,83 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
if
(
!
cmd
.
resp_pkt
)
goto
out_unlock
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API
)
status_size
=
sizeof
(
struct
iwl_wowlan_status_v6
);
else
status_size
=
sizeof
(
struct
iwl_wowlan_status_v4
);
len
=
le32_to_cpu
(
cmd
.
resp_pkt
->
len_n_flags
)
&
FH_RSCSR_FRAME_SIZE_MSK
;
if
(
len
-
sizeof
(
struct
iwl_cmd_header
)
<
s
izeof
(
*
status
)
)
{
if
(
len
-
sizeof
(
struct
iwl_cmd_header
)
<
s
tatus_size
)
{
IWL_ERR
(
mvm
,
"Invalid WoWLAN status response!
\n
"
);
goto
out_free_resp
;
}
status
=
(
void
*
)
cmd
.
resp_pkt
->
data
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API
)
{
status_v6
=
(
void
*
)
cmd
.
resp_pkt
->
data
;
status
.
pattern_number
=
le16_to_cpu
(
status_v6
->
pattern_number
);
for
(
i
=
0
;
i
<
8
;
i
++
)
status
.
qos_seq_ctr
[
i
]
=
le16_to_cpu
(
status_v6
->
qos_seq_ctr
[
i
]);
status
.
wakeup_reasons
=
le32_to_cpu
(
status_v6
->
wakeup_reasons
);
status
.
wake_packet_length
=
le32_to_cpu
(
status_v6
->
wake_packet_length
);
status
.
wake_packet_bufsize
=
le32_to_cpu
(
status_v6
->
wake_packet_bufsize
);
status
.
wake_packet
=
status_v6
->
wake_packet
;
}
else
{
struct
iwl_wowlan_status_v4
*
status_v4
;
status_v6
=
NULL
;
status_v4
=
(
void
*
)
cmd
.
resp_pkt
->
data
;
status
.
pattern_number
=
le16_to_cpu
(
status_v4
->
pattern_number
);
for
(
i
=
0
;
i
<
8
;
i
++
)
status
.
qos_seq_ctr
[
i
]
=
le16_to_cpu
(
status_v4
->
qos_seq_ctr
[
i
]);
status
.
wakeup_reasons
=
le32_to_cpu
(
status_v4
->
wakeup_reasons
);
status
.
wake_packet_length
=
le32_to_cpu
(
status_v4
->
wake_packet_length
);
status
.
wake_packet_bufsize
=
le32_to_cpu
(
status_v4
->
wake_packet_bufsize
);
status
.
wake_packet
=
status_v4
->
wake_packet
;
}
if
(
len
-
sizeof
(
struct
iwl_cmd_header
)
!=
sizeof
(
*
status
)
+
ALIGN
(
le32_to_cpu
(
status
->
wake_packet_bufsize
),
4
))
{
status_size
+
ALIGN
(
status
.
wake_packet_bufsize
,
4
))
{
IWL_ERR
(
mvm
,
"Invalid WoWLAN status response!
\n
"
);
goto
out_free_resp
;
}
/* still at hard-coded place 0 for D3 image */
ap_sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
0
],
lockdep_is_held
(
&
mvm
->
mutex
));
if
(
IS_ERR_OR_NULL
(
ap_sta
))
goto
out_free_resp
;
mvm_ap_sta
=
(
struct
iwl_mvm_sta
*
)
ap_sta
->
drv_priv
;
for
(
i
=
0
;
i
<
IWL_MAX_TID_COUNT
;
i
++
)
{
u16
seq
=
status
.
qos_seq_ctr
[
i
];
/* firmware stores last-used value, we store next value */
seq
+=
0x10
;
mvm_ap_sta
->
tid_data
[
i
].
seq_number
=
seq
;
}
/* now we have all the data we need, unlock to avoid mac80211 issues */
mutex_unlock
(
&
mvm
->
mutex
);
iwl_mvm_report_wakeup_reasons
(
mvm
,
vif
,
status
);
iwl_mvm_report_wakeup_reasons
(
mvm
,
vif
,
&
status
);
keep
=
iwl_mvm_setup_connection_keep
(
mvm
,
vif
,
status_v6
);
iwl_free_resp
(
&
cmd
);
return
;
return
keep
;
out_free_resp:
iwl_free_resp
(
&
cmd
);
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
return
false
;
}
static
void
iwl_mvm_read_d3_sram
(
struct
iwl_mvm
*
mvm
)
...
...
@@ -1335,6 +1758,17 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
#endif
}
static
void
iwl_mvm_d3_disconnect_iter
(
void
*
data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
/* skip the one we keep connection on */
if
(
data
==
vif
)
return
;
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
)
ieee80211_resume_disconnect
(
vif
);
}
static
int
__iwl_mvm_resume
(
struct
iwl_mvm
*
mvm
,
bool
test
)
{
struct
iwl_d3_iter_data
resume_iter_data
=
{
...
...
@@ -1343,6 +1777,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
struct
ieee80211_vif
*
vif
=
NULL
;
int
ret
;
enum
iwl_d3_status
d3_status
;
bool
keep
=
false
;
mutex_lock
(
&
mvm
->
mutex
);
...
...
@@ -1368,7 +1803,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
/* query SRAM first in case we want event logging */
iwl_mvm_read_d3_sram
(
mvm
);
iwl_mvm_query_wakeup_reasons
(
mvm
,
vif
);
keep
=
iwl_mvm_query_wakeup_reasons
(
mvm
,
vif
);
/* has unlocked the mutex, so skip that */
goto
out
;
...
...
@@ -1376,8 +1811,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
mutex_unlock
(
&
mvm
->
mutex
);
out:
if
(
!
test
&&
vif
)
ieee80211_resume_disconnect
(
vif
);
if
(
!
test
)
ieee80211_iterate_active_interfaces_rtnl
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_d3_disconnect_iter
,
keep
?
vif
:
NULL
);
/* return 1 to reconfigure the device */
set_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
);
...
...
drivers/net/wireless/iwlwifi/mvm/debugfs.c
View file @
444474dd
...
...
@@ -246,58 +246,56 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_
power_down_allow_write
(
struct
file
*
file
,
c
onst
c
har
__user
*
user_buf
,
static
ssize_t
iwl_dbgfs_
disable_power_off_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
8
]
=
{};
int
allow
;
if
(
!
mvm
->
ucode_loaded
)
return
-
EIO
;
if
(
copy_from_user
(
buf
,
user_buf
,
sizeof
(
buf
)))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%d"
,
&
allow
)
!=
1
)
return
-
EINVAL
;
IWL_DEBUG_POWER
(
mvm
,
"%s device power down
\n
"
,
allow
?
"allow"
:
"prevent"
);
char
buf
[
64
];
int
bufsz
=
sizeof
(
buf
);
int
pos
=
0
;
/*
* TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it
*/
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"disable_power_off_d0=%d
\n
"
,
mvm
->
disable_power_off
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"disable_power_off_d3=%d
\n
"
,
mvm
->
disable_power_off_d3
);
return
count
;
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
)
;
}
static
ssize_t
iwl_dbgfs_
power_down_d3_allow
_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
static
ssize_t
iwl_dbgfs_
disable_power_off
_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
8
]
=
{};
int
allow
;
char
buf
[
64
]
=
{};
int
ret
;
int
val
;
if
(
copy_from_user
(
buf
,
user_buf
,
sizeof
(
buf
)))
if
(
!
mvm
->
ucode_loaded
)
return
-
EIO
;
count
=
min_t
(
size_t
,
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
count
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%d"
,
&
allow
)
!=
1
)
if
(
!
strncmp
(
"disable_power_off_d0="
,
buf
,
21
))
{
if
(
sscanf
(
buf
+
21
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
mvm
->
disable_power_off
=
val
;
}
else
if
(
!
strncmp
(
"disable_power_off_d3="
,
buf
,
21
))
{
if
(
sscanf
(
buf
+
21
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
mvm
->
disable_power_off_d3
=
val
;
}
else
{
return
-
EINVAL
;
}
IWL_DEBUG_POWER
(
mvm
,
"%s device power down in d3
\n
"
,
allow
?
"allow"
:
"prevent"
);
/*
* TODO: When WoWLAN FW alive notification happens, driver will send
* REPLY_DEBUG_CMD setting power_down_allow flag according to
* mvm->prevent_power_down_d3
*/
mvm
->
prevent_power_down_d3
=
!
allow
;
mutex_lock
(
&
mvm
->
mutex
);
ret
=
iwl_mvm_power_update_device_mode
(
mvm
);
mutex_unlock
(
&
mvm
->
mutex
);
return
count
;
return
ret
?:
count
;
}
static
void
iwl_dbgfs_update_pm
(
struct
iwl_mvm
*
mvm
,
...
...
@@ -371,7 +369,8 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
int
val
;
int
ret
;
if
(
copy_from_user
(
buf
,
user_buf
,
sizeof
(
buf
)))
count
=
min_t
(
size_t
,
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
count
))
return
-
EFAULT
;
if
(
!
strncmp
(
"keep_alive="
,
buf
,
11
))
{
...
...
@@ -394,7 +393,9 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
if
(
sscanf
(
buf
+
16
,
"%d"
,
&
val
)
!=
1
)
return
-
EINVAL
;
param
=
MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
;
}
else
if
(
!
strncmp
(
"disable_power_off="
,
buf
,
18
))
{
}
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
;
...
...
@@ -581,15 +582,21 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
BT_MBOX_PRINT
(
3
,
UPDATE_REQUEST
,
true
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bt_status = %d
\n
"
,
notif
->
bt_status
);
notif
->
bt_status
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bt_open_conn = %d
\n
"
,
notif
->
bt_open_conn
);
notif
->
bt_open_conn
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bt_traffic_load = %d
\n
"
,
notif
->
bt_traffic_load
);
notif
->
bt_traffic_load
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bt_agg_traffic_load = %d
\n
"
,
notif
->
bt_agg_traffic_load
);
notif
->
bt_agg_traffic_load
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bt_ci_compliance = %d
\n
"
,
notif
->
bt_ci_compliance
);
notif
->
bt_ci_compliance
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"primary_ch_lut = %d
\n
"
,
le32_to_cpu
(
notif
->
primary_ch_lut
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"secondary_ch_lut = %d
\n
"
,
le32_to_cpu
(
notif
->
secondary_ch_lut
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bt_activity_grading = %d
\n
"
,
le32_to_cpu
(
notif
->
bt_activity_grading
));
mutex_unlock
(
&
mvm
->
mutex
);
...
...
@@ -600,6 +607,38 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
}
#undef BT_MBOX_PRINT
static
ssize_t
iwl_dbgfs_bt_cmd_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
struct
iwl_bt_coex_ci_cmd
*
cmd
=
&
mvm
->
last_bt_ci_cmd
;
char
buf
[
256
];
int
bufsz
=
sizeof
(
buf
);
int
pos
=
0
;
mutex_lock
(
&
mvm
->
mutex
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"Channel inhibition CMD
\n
"
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"
\t
Primary Channel Bitmap 0x%016llx Fat: %d
\n
"
,
le64_to_cpu
(
cmd
->
bt_primary_ci
),
!!
cmd
->
co_run_bw_primary
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"
\t
Secondary Channel Bitmap 0x%016llx Fat: %d
\n
"
,
le64_to_cpu
(
cmd
->
bt_secondary_ci
),
!!
cmd
->
co_run_bw_secondary
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"BT Configuration CMD
\n
"
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"
\t
ACK Kill Mask 0x%08x
\n
"
,
iwl_bt_ack_kill_msk
[
mvm
->
bt_kill_msk
]);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"
\t
CTS Kill Mask 0x%08x
\n
"
,
iwl_bt_cts_kill_msk
[
mvm
->
bt_kill_msk
]);
mutex_unlock
(
&
mvm
->
mutex
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
#define PRINT_STATS_LE32(_str, _val) \
pos += scnprintf(buf + pos, bufsz - pos, \
fmt_table, _str, \
...
...
@@ -615,9 +654,11 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
int
pos
=
0
;
char
*
buf
;
int
ret
;
int
bufsz
=
sizeof
(
struct
mvm_statistics_rx_phy
)
*
20
+
sizeof
(
struct
mvm_statistics_rx_non_phy
)
*
10
+
sizeof
(
struct
mvm_statistics_rx_ht_phy
)
*
10
+
200
;
/* 43 is the size of each data line, 33 is the size of each header */
size_t
bufsz
=
((
sizeof
(
struct
mvm_statistics_rx
)
/
sizeof
(
__le32
))
*
43
)
+
(
4
*
33
)
+
1
;
struct
mvm_statistics_rx_phy
*
ofdm
;
struct
mvm_statistics_rx_phy
*
cck
;
struct
mvm_statistics_rx_non_phy
*
general
;
...
...
@@ -712,6 +753,7 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
PRINT_STATS_LE32
(
"beacon_energy_b"
,
general
->
beacon_energy_b
);
PRINT_STATS_LE32
(
"beacon_energy_c"
,
general
->
beacon_energy_c
);
PRINT_STATS_LE32
(
"num_bt_kills"
,
general
->
num_bt_kills
);
PRINT_STATS_LE32
(
"mac_id"
,
general
->
mac_id
);
PRINT_STATS_LE32
(
"directed_data_mpdu"
,
general
->
directed_data_mpdu
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
fmt_header
,
...
...
@@ -757,6 +799,59 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
return
count
;
}
static
ssize_t
iwl_dbgfs_scan_ant_rxchain_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
int
pos
=
0
;
char
buf
[
32
];
const
size_t
bufsz
=
sizeof
(
buf
);
/* print which antennas were set for the scan command by the user */
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"Antennas for scan: "
);
if
(
mvm
->
scan_rx_ant
&
ANT_A
)
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"A"
);
if
(
mvm
->
scan_rx_ant
&
ANT_B
)
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"B"
);
if
(
mvm
->
scan_rx_ant
&
ANT_C
)
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"C"
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
" (%hhx)
\n
"
,
mvm
->
scan_rx_ant
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_scan_ant_rxchain_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
char
buf
[
8
];
int
buf_size
;
u8
scan_rx_ant
;
memset
(
buf
,
0
,
sizeof
(
buf
));
buf_size
=
min
(
count
,
sizeof
(
buf
)
-
1
);
/* get the argument from the user and check if it is valid */
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%hhx"
,
&
scan_rx_ant
)
!=
1
)
return
-
EINVAL
;
if
(
scan_rx_ant
>
ANT_ABC
)
return
-
EINVAL
;
if
(
scan_rx_ant
&
~
iwl_fw_valid_rx_ant
(
mvm
->
fw
))
return
-
EINVAL
;
/* change the rx antennas for scan command */
mvm
->
scan_rx_ant
=
scan_rx_ant
;
return
count
;
}
static
void
iwl_dbgfs_update_bf
(
struct
ieee80211_vif
*
vif
,
enum
iwl_dbgfs_bf_mask
param
,
int
value
)
{
...
...
@@ -968,7 +1063,8 @@ static ssize_t iwl_dbgfs_d3_sram_write(struct file *file,
char
buf
[
8
]
=
{};
int
store
;
if
(
copy_from_user
(
buf
,
user_buf
,
sizeof
(
buf
)))
count
=
min_t
(
size_t
,
count
,
sizeof
(
buf
)
-
1
);
if
(
copy_from_user
(
buf
,
user_buf
,
count
))
return
-
EFAULT
;
if
(
sscanf
(
buf
,
"%d"
,
&
store
)
!=
1
)
...
...
@@ -1063,10 +1159,12 @@ MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
sram
);
MVM_DEBUGFS_READ_FILE_OPS
(
stations
);
MVM_DEBUGFS_READ_FILE_OPS
(
bt_notif
);
MVM_DEBUGFS_
WRITE_FILE_OPS
(
power_down_allow
);
MVM_DEBUGFS_
WRITE_FILE_OPS
(
power_down_d3_allow
);
MVM_DEBUGFS_
READ_FILE_OPS
(
bt_cmd
);
MVM_DEBUGFS_
READ_WRITE_FILE_OPS
(
disable_power_off
);
MVM_DEBUGFS_READ_FILE_OPS
(
fw_rx_stats
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
fw_restart
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
scan_ant_rxchain
);
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
d3_sram
);
#endif
...
...
@@ -1087,10 +1185,14 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE
(
sram
,
mvm
->
debugfs_dir
,
S_IWUSR
|
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE
(
stations
,
dbgfs_dir
,
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE
(
bt_notif
,
dbgfs_dir
,
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE
(
power_down_allow
,
mvm
->
debugfs_dir
,
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
power_down_d3_allow
,
mvm
->
debugfs_dir
,
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
bt_cmd
,
dbgfs_dir
,
S_IRUSR
);
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD
)
MVM_DEBUGFS_ADD_FILE
(
disable_power_off
,
mvm
->
debugfs_dir
,
S_IRUSR
|
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
fw_rx_stats
,
mvm
->
debugfs_dir
,
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE
(
fw_restart
,
mvm
->
debugfs_dir
,
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
scan_ant_rxchain
,
mvm
->
debugfs_dir
,
S_IWUSR
|
S_IRUSR
);
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_ADD_FILE
(
d3_sram
,
mvm
->
debugfs_dir
,
S_IRUSR
|
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
d3_test
,
mvm
->
debugfs_dir
,
S_IRUSR
);
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
View file @
444474dd
...
...
@@ -82,6 +82,8 @@
* @BT_USE_DEFAULTS:
* @BT_SYNC_2_BT_DISABLE:
* @BT_COEX_CORUNNING_TBL_EN:
*
* The COEX_MODE must be set for each command. Even if it is not changed.
*/
enum
iwl_bt_coex_flags
{
BT_CH_PRIMARY_EN
=
BIT
(
0
),
...
...
@@ -95,14 +97,16 @@ enum iwl_bt_coex_flags {
BT_COEX_NW
=
0x3
<<
BT_COEX_MODE_POS
,
BT_USE_DEFAULTS
=
BIT
(
6
),
BT_SYNC_2_BT_DISABLE
=
BIT
(
7
),
/*
* For future use - when the flags will be enlarged
* BT_COEX_CORUNNING_TBL_EN = BIT(8),
*/
BT_COEX_CORUNNING_TBL_EN
=
BIT
(
8
),
BT_COEX_MPLUT_TBL_EN
=
BIT
(
9
),
/* Bit 10 is reserved */
BT_COEX_WF_PRIO_BOOST_CHECK_EN
=
BIT
(
11
),
};
/*
* indicates what has changed in the BT_COEX command.
* BT_VALID_ENABLE must be set for each command. Commands without this bit will
* discarded by the firmware
*/
enum
iwl_bt_coex_valid_bit_msk
{
BT_VALID_ENABLE
=
BIT
(
0
),
...
...
@@ -121,11 +125,8 @@ enum iwl_bt_coex_valid_bit_msk {
BT_VALID_CORUN_LUT_40
=
BIT
(
13
),
BT_VALID_ANT_ISOLATION
=
BIT
(
14
),
BT_VALID_ANT_ISOLATION_THRS
=
BIT
(
15
),
/*
* For future use - when the valid flags will be enlarged
* BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
* BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
*/
BT_VALID_TXTX_DELTA_FREQ_THRS
=
BIT
(
16
),
BT_VALID_TXRX_MAX_FREQ_0
=
BIT
(
17
),
};
/**
...
...
@@ -142,48 +143,88 @@ enum iwl_bt_reduced_tx_power {
BT_REDUCED_TX_POWER_DATA
=
BIT
(
1
),
};
enum
iwl_bt_coex_lut_type
{
BT_COEX_TIGHT_LUT
=
0
,
BT_COEX_LOOSE_LUT
,
BT_COEX_TX_DIS_LUT
,
BT_COEX_MAX_LUT
,
};
#define BT_COEX_LUT_SIZE (12)
#define BT_COEX_CORUN_LUT_SIZE (32)
#define BT_COEX_MULTI_PRIO_LUT_SIZE (2)
#define BT_COEX_BOOST_SIZE (4)
#define BT_REDUCED_TX_POWER_BIT BIT(7)
/**
* struct iwl_bt_coex_cmd - bt coex configuration command
* @flags:&enum iwl_bt_coex_flags
* @lead_time:
* @max_kill:
* @bt3_time_t7_value:
* @kill_ack_msk:
* @kill_cts_msk:
* @bt3_prio_sample_time:
* @bt3_timer_t2_value:
* @bt4_reaction_time:
* @decision_lut[12]:
* @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
* @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
* @bt_prio_boost: values for PTA boost register
* @bt4_antenna_isolation:
* @bt4_antenna_isolation_thr:
* @bt4_tx_tx_delta_freq_thr:
* @bt4_tx_rx_max_freq0:
* @bt_prio_boost:
* @wifi_tx_prio_boost: SW boost of wifi tx priority
* @wifi_rx_prio_boost: SW boost of wifi rx priority
* @kill_ack_msk:
* @kill_cts_msk:
* @decision_lut:
* @bt4_multiprio_lut:
* @bt4_corun_lut20:
* @bt4_corun_lut40:
* @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
*
* The structure is used for the BT_COEX command.
*/
struct
iwl_bt_coex_cmd
{
u8
flags
;
u8
lead_time
;
__le32
flags
;
u8
max_kill
;
u8
bt3_time_t7_value
;
u8
bt_reduced_tx_power
;
u8
reserved
[
2
];
u8
bt4_antenna_isolation
;
u8
bt4_antenna_isolation_thr
;
u8
bt4_tx_tx_delta_freq_thr
;
u8
bt4_tx_rx_max_freq0
;
__le32
bt_prio_boost
[
BT_COEX_BOOST_SIZE
];
__le32
wifi_tx_prio_boost
;
__le32
wifi_rx_prio_boost
;
__le32
kill_ack_msk
;
__le32
kill_cts_msk
;
u8
bt3_prio_sample_time
;
u8
bt3_timer_t2_value
;
__le16
bt4_reaction_time
;
__le32
decision_lut
[
BT_COEX_LUT_SIZE
];
u8
bt_reduced_tx_power
;
u8
reserved
;
__le16
valid_bit_msk
;
__le32
bt_prio_boost
;
u8
reserved2
;
u8
wifi_tx_prio_boost
;
__le16
wifi_rx_prio_boost
;
__le32
decision_lut
[
BT_COEX_MAX_LUT
][
BT_COEX_LUT_SIZE
];
__le32
bt4_multiprio_lut
[
BT_COEX_MULTI_PRIO_LUT_SIZE
];
__le32
bt4_corun_lut20
[
BT_COEX_CORUN_LUT_SIZE
];
__le32
bt4_corun_lut40
[
BT_COEX_CORUN_LUT_SIZE
];
__le32
valid_bit_msk
;
}
__packed
;
/* BT_COEX_CMD_API_S_VER_3 */
/**
* struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command
* @bt_primary_ci:
* @bt_secondary_ci:
* @co_run_bw_primary:
* @co_run_bw_secondary:
* @primary_ch_phy_id:
* @secondary_ch_phy_id:
*
* Used for BT_COEX_CI command
*/
struct
iwl_bt_coex_ci_cmd
{
__le64
bt_primary_ci
;
__le64
bt_secondary_ci
;
u8
co_run_bw_primary
;
u8
co_run_bw_secondary
;
u8
primary_ch_phy_id
;
u8
secondary_ch_phy_id
;
}
__packed
;
/* BT_CI_MSG_API_S_VER_1 */
#define BT_MBOX(n_dw, _msg, _pos, _nbits) \
BT_MBOX##n_dw##_##_msg##_POS = (_pos), \
BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS
...
...
@@ -244,23 +285,39 @@ enum iwl_bt_mxbox_dw3 {
((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
>> BT_MBOX##_num##_##_field##_POS)
enum
iwl_bt_activity_grading
{
BT_OFF
=
0
,
BT_ON_NO_CONNECTION
=
1
,
BT_LOW_TRAFFIC
=
2
,
BT_HIGH_TRAFFIC
=
3
,
};
/**
* struct iwl_bt_coex_profile_notif - notification about BT coex
* @mbox_msg: message from BT to WiFi
* @:bt_status: 0 - off, 1 - on
* @:bt_open_conn: number of BT connections open
* @:bt_traffic_load: load of BT traffic
* @:bt_agg_traffic_load: aggregated load of BT traffic
* @:bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
* @msg_idx: the index of the message
* @bt_status: 0 - off, 1 - on
* @bt_open_conn: number of BT connections open
* @bt_traffic_load: load of BT traffic
* @bt_agg_traffic_load: aggregated load of BT traffic
* @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
* @primary_ch_lut: LUT used for primary channel
* @secondary_ch_lut: LUT used for secondary channel
* @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading
*/
struct
iwl_bt_coex_profile_notif
{
__le32
mbox_msg
[
4
];
__le32
msg_idx
;
u8
bt_status
;
u8
bt_open_conn
;
u8
bt_traffic_load
;
u8
bt_agg_traffic_load
;
u8
bt_ci_compliance
;
u8
reserved
[
3
];
__le32
primary_ch_lut
;
__le32
secondary_ch_lut
;
__le32
bt_activity_grading
;
}
__packed
;
/* BT_COEX_PROFILE_NTFY_API_S_VER_2 */
enum
iwl_bt_coex_prio_table_event
{
...
...
@@ -300,20 +357,4 @@ struct iwl_bt_coex_prio_tbl_cmd {
u8
prio_tbl
[
BT_COEX_PRIO_TBL_EVT_MAX
];
}
__packed
;
enum
iwl_bt_coex_env_action
{
BT_COEX_ENV_CLOSE
=
0
,
BT_COEX_ENV_OPEN
=
1
,
};
/* BT_COEX_PROT_ENV_ACTION_API_E_VER_1 */
/**
* struct iwl_bt_coex_prot_env_cmd - BT Protection Envelope
* @action: enum %iwl_bt_coex_env_action
* @type: enum %iwl_bt_coex_prio_table_event
*/
struct
iwl_bt_coex_prot_env_cmd
{
u8
action
;
/* 0 = closed, 1 = open */
u8
type
;
/* 0 .. 15 */
u8
reserved
[
2
];
}
__packed
;
#endif
/* __fw_api_bt_coex_h__ */
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
View file @
444474dd
...
...
@@ -100,7 +100,12 @@ enum iwl_proto_offloads {
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L 12
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S 4
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 12
#define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L 4
#define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S 2
/**
* struct iwl_proto_offload_cmd_common - ARP/NS offload common part
...
...
@@ -155,6 +160,43 @@ struct iwl_proto_offload_cmd_v2 {
u8
reserved2
[
3
];
}
__packed
;
/* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */
struct
iwl_ns_config
{
struct
in6_addr
source_ipv6_addr
;
struct
in6_addr
dest_ipv6_addr
;
u8
target_mac_addr
[
ETH_ALEN
];
__le16
reserved
;
}
__packed
;
/* NS_OFFLOAD_CONFIG */
struct
iwl_targ_addr
{
struct
in6_addr
addr
;
__le32
config_num
;
}
__packed
;
/* TARGET_IPV6_ADDRESS */
/**
* struct iwl_proto_offload_cmd_v3_small - ARP/NS offload configuration
* @common: common/IPv4 configuration
* @target_ipv6_addr: target IPv6 addresses
* @ns_config: NS offload configurations
*/
struct
iwl_proto_offload_cmd_v3_small
{
struct
iwl_proto_offload_cmd_common
common
;
__le32
num_valid_ipv6_addrs
;
struct
iwl_targ_addr
targ_addrs
[
IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S
];
struct
iwl_ns_config
ns_config
[
IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S
];
}
__packed
;
/* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */
/**
* struct iwl_proto_offload_cmd_v3_large - ARP/NS offload configuration
* @common: common/IPv4 configuration
* @target_ipv6_addr: target IPv6 addresses
* @ns_config: NS offload configurations
*/
struct
iwl_proto_offload_cmd_v3_large
{
struct
iwl_proto_offload_cmd_common
common
;
__le32
num_valid_ipv6_addrs
;
struct
iwl_targ_addr
targ_addrs
[
IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L
];
struct
iwl_ns_config
ns_config
[
IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L
];
}
__packed
;
/* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */
/*
* WOWLAN_PATTERNS
...
...
@@ -293,7 +335,7 @@ enum iwl_wowlan_wakeup_reason {
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET
=
BIT
(
12
),
};
/* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
struct
iwl_wowlan_status
{
struct
iwl_wowlan_status
_v4
{
__le64
replay_ctr
;
__le16
pattern_number
;
__le16
non_qos_seq_ctr
;
...
...
@@ -308,6 +350,29 @@ struct iwl_wowlan_status {
u8
wake_packet
[];
/* can be truncated from _length to _bufsize */
}
__packed
;
/* WOWLAN_STATUSES_API_S_VER_4 */
struct
iwl_wowlan_gtk_status
{
u8
key_index
;
u8
reserved
[
3
];
u8
decrypt_key
[
16
];
u8
tkip_mic_key
[
8
];
struct
iwl_wowlan_rsc_tsc_params_cmd
rsc
;
}
__packed
;
struct
iwl_wowlan_status_v6
{
struct
iwl_wowlan_gtk_status
gtk
;
__le64
replay_ctr
;
__le16
pattern_number
;
__le16
non_qos_seq_ctr
;
__le16
qos_seq_ctr
[
8
];
__le32
wakeup_reasons
;
__le32
num_of_gtk_rekeys
;
__le32
transmitted_ndps
;
__le32
received_beacons
;
__le32
wake_packet_length
;
__le32
wake_packet_bufsize
;
u8
wake_packet
[];
/* can be truncated from _length to _bufsize */
}
__packed
;
/* WOWLAN_STATUSES_API_S_VER_6 */
#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64
#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128
#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
View file @
444474dd
...
...
@@ -170,12 +170,14 @@ struct iwl_mac_data_ap {
* @beacon_tsf: beacon transmit time in TSF
* @bi: beacon interval in TU
* @bi_reciprocal: 2^32 / bi
* @beacon_template: beacon template ID
*/
struct
iwl_mac_data_ibss
{
__le32
beacon_time
;
__le64
beacon_tsf
;
__le32
bi
;
__le32
bi_reciprocal
;
__le32
beacon_template
;
}
__packed
;
/* IBSS_MAC_DATA_API_S_VER_1 */
/**
...
...
@@ -372,4 +374,13 @@ static inline u32 iwl_mvm_reciprocal(u32 v)
return
0xFFFFFFFF
/
v
;
}
#define IWL_NONQOS_SEQ_GET 0x1
#define IWL_NONQOS_SEQ_SET 0x2
struct
iwl_nonqos_seq_query_cmd
{
__le32
get_set_flag
;
__le32
mac_id_n_color
;
__le16
value
;
__le16
reserved
;
}
__packed
;
/* NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */
#endif
/* __fw_api_mac_h__ */
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
View file @
444474dd
...
...
@@ -131,6 +131,33 @@ struct iwl_powertable_cmd {
__le32
lprx_rssi_threshold
;
}
__packed
;
/**
* enum iwl_device_power_flags - masks for device power command flags
* @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
* receiver and transmitter. '0' - does not allow. This flag should be
* always set to '1' unless one need to disable actual power down for debug
* purposes.
* @DEVICE_POWER_FLAGS_CAM_MSK: '1' CAM (Continuous Active Mode) is set, meaning
* that power management is disabled. '0' Power management is enabled, one
* of power schemes is applied.
*/
enum
iwl_device_power_flags
{
DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK
=
BIT
(
0
),
DEVICE_POWER_FLAGS_CAM_MSK
=
BIT
(
13
),
};
/**
* struct iwl_device_power_cmd - device wide power command.
* DEVICE_POWER_CMD = 0x77 (command, has simple generic response)
*
* @flags: Power table command flags from DEVICE_POWER_FLAGS_*
*/
struct
iwl_device_power_cmd
{
/* PM_POWER_TABLE_CMD_API_S_VER_6 */
__le16
flags
;
__le16
reserved
;
}
__packed
;
/**
* struct iwl_mac_power_cmd - New power command containing uAPSD support
* MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response)
...
...
@@ -290,7 +317,7 @@ struct iwl_beacon_filter_cmd {
#define IWL_BF_ESCAPE_TIMER_MIN 0
#define IWL_BA_ESCAPE_TIMER_DEFAULT 6
#define IWL_BA_ESCAPE_TIMER_D3
6
#define IWL_BA_ESCAPE_TIMER_D3
9
#define IWL_BA_ESCAPE_TIMER_MAX 1024
#define IWL_BA_ESCAPE_TIMER_MIN 0
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
View file @
444474dd
...
...
@@ -68,6 +68,7 @@
/*
* These serve as indexes into
* struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT];
* TODO: avoid overlap between legacy and HT rates
*/
enum
{
IWL_RATE_1M_INDEX
=
0
,
...
...
@@ -78,18 +79,31 @@ enum {
IWL_LAST_CCK_RATE
=
IWL_RATE_11M_INDEX
,
IWL_RATE_6M_INDEX
,
IWL_FIRST_OFDM_RATE
=
IWL_RATE_6M_INDEX
,
IWL_RATE_MCS_0_INDEX
=
IWL_RATE_6M_INDEX
,
IWL_FIRST_HT_RATE
=
IWL_RATE_MCS_0_INDEX
,
IWL_FIRST_VHT_RATE
=
IWL_RATE_MCS_0_INDEX
,
IWL_RATE_9M_INDEX
,
IWL_RATE_12M_INDEX
,
IWL_RATE_MCS_1_INDEX
=
IWL_RATE_12M_INDEX
,
IWL_RATE_18M_INDEX
,
IWL_RATE_MCS_2_INDEX
=
IWL_RATE_18M_INDEX
,
IWL_RATE_24M_INDEX
,
IWL_RATE_MCS_3_INDEX
=
IWL_RATE_24M_INDEX
,
IWL_RATE_36M_INDEX
,
IWL_RATE_MCS_4_INDEX
=
IWL_RATE_36M_INDEX
,
IWL_RATE_48M_INDEX
,
IWL_RATE_MCS_5_INDEX
=
IWL_RATE_48M_INDEX
,
IWL_RATE_54M_INDEX
,
IWL_RATE_MCS_6_INDEX
=
IWL_RATE_54M_INDEX
,
IWL_LAST_NON_HT_RATE
=
IWL_RATE_54M_INDEX
,
IWL_RATE_60M_INDEX
,
IWL_LAST_OFDM_RATE
=
IWL_RATE_60M_INDEX
,
IWL_RATE_MCS_7_INDEX
=
IWL_RATE_60M_INDEX
,
IWL_LAST_HT_RATE
=
IWL_RATE_MCS_7_INDEX
,
IWL_RATE_MCS_8_INDEX
,
IWL_RATE_MCS_9_INDEX
,
IWL_LAST_VHT_RATE
=
IWL_RATE_MCS_9_INDEX
,
IWL_RATE_COUNT_LEGACY
=
IWL_LAST_NON_HT_RATE
+
1
,
IWL_RATE_COUNT
,
IWL_RATE_COUNT
=
IWL_LAST_VHT_RATE
+
1
,
};
#define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX)
...
...
@@ -108,6 +122,7 @@ enum {
IWL_RATE_2M_PLCP
=
20
,
IWL_RATE_5M_PLCP
=
55
,
IWL_RATE_11M_PLCP
=
110
,
IWL_RATE_INVM_PLCP
=
-
1
,
};
/*
...
...
@@ -164,6 +179,8 @@ enum {
* which is the duplicate 20 MHz MCS (bit 5 set, all others zero.)
*/
#define RATE_HT_MCS_RATE_CODE_MSK 0x7
#define RATE_HT_MCS_NSS_POS 3
#define RATE_HT_MCS_NSS_MSK (3 << RATE_HT_MCS_NSS_POS)
/* Bit 10: (1) Use Green Field preamble */
#define RATE_HT_MCS_GF_POS 10
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
View file @
444474dd
...
...
@@ -356,6 +356,7 @@ struct iwl_scan_complete_notif {
/* scan offload */
#define IWL_MAX_SCAN_CHANNELS 40
#define IWL_SCAN_MAX_BLACKLIST_LEN 64
#define IWL_SCAN_SHORT_BLACKLIST_LEN 16
#define IWL_SCAN_MAX_PROFILES 11
#define SCAN_OFFLOAD_PROBE_REQ_SIZE 512
...
...
@@ -368,6 +369,12 @@ struct iwl_scan_complete_notif {
#define IWL_FULL_SCAN_MULTIPLIER 5
#define IWL_FAST_SCHED_SCAN_ITERATIONS 3
enum
scan_framework_client
{
SCAN_CLIENT_SCHED_SCAN
=
BIT
(
0
),
SCAN_CLIENT_NETDETECT
=
BIT
(
1
),
SCAN_CLIENT_ASSET_TRACKING
=
BIT
(
2
),
};
/**
* struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6
* @scan_flags: see enum iwl_scan_flags
...
...
@@ -449,11 +456,12 @@ struct iwl_scan_offload_cfg {
* iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S
* @ssid: MAC address to filter out
* @reported_rssi: AP rssi reported to the host
* @client_bitmap: clients ignore this entry - enum scan_framework_client
*/
struct
iwl_scan_offload_blacklist
{
u8
ssid
[
ETH_ALEN
];
u8
reported_rssi
;
u8
reserved
;
u8
client_bitmap
;
}
__packed
;
enum
iwl_scan_offload_network_type
{
...
...
@@ -475,6 +483,7 @@ enum iwl_scan_offload_band_selection {
* @aut_alg: authentication olgorithm to match - bitmap
* @network_type: enum iwl_scan_offload_network_type
* @band_selection: enum iwl_scan_offload_band_selection
* @client_bitmap: clients waiting for match - enum scan_framework_client
*/
struct
iwl_scan_offload_profile
{
u8
ssid_index
;
...
...
@@ -482,7 +491,8 @@ struct iwl_scan_offload_profile {
u8
auth_alg
;
u8
network_type
;
u8
band_selection
;
u8
reserved
[
3
];
u8
client_bitmap
;
u8
reserved
[
2
];
}
__packed
;
/**
...
...
@@ -491,13 +501,18 @@ struct iwl_scan_offload_profile {
* @profiles: profiles to search for match
* @blacklist_len: length of blacklist
* @num_profiles: num of profiles in the list
* @match_notify: clients waiting for match found notification
* @pass_match: clients waiting for the results
* @active_clients: active clients bitmap - enum scan_framework_client
*/
struct
iwl_scan_offload_profile_cfg
{
struct
iwl_scan_offload_blacklist
blacklist
[
IWL_SCAN_MAX_BLACKLIST_LEN
];
struct
iwl_scan_offload_profile
profiles
[
IWL_SCAN_MAX_PROFILES
];
u8
blacklist_len
;
u8
num_profiles
;
u8
reserved
[
2
];
u8
match_notify
;
u8
pass_match
;
u8
active_clients
;
u8
reserved
[
3
];
}
__packed
;
/**
...
...
@@ -560,4 +575,15 @@ struct iwl_scan_offload_complete {
u8
reserved
;
}
__packed
;
/**
* iwl_sched_scan_results - SCAN_OFFLOAD_MATCH_FOUND_NTF_API_S_VER_1
* @ssid_bitmap: SSIDs indexes found in this iteration
* @client_bitmap: clients that are active and wait for this notification
*/
struct
iwl_sched_scan_results
{
__le16
ssid_bitmap
;
u8
client_bitmap
;
u8
reserved
;
};
#endif
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
View file @
444474dd
...
...
@@ -247,7 +247,7 @@ struct iwl_mvm_keyinfo {
}
__packed
;
/**
* struct iwl_mvm_add_sta_cmd
- Add / modify a station in the fw's station table
* struct iwl_mvm_add_sta_cmd
_v5 - Add/modify a station in the fw's sta table.
* ( REPLY_ADD_STA = 0x18 )
* @add_modify: 1: modify existing, 0: add new station
* @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent
...
...
@@ -286,7 +286,7 @@ struct iwl_mvm_keyinfo {
* ADD_STA sets up the table entry for one station, either creating a new
* entry, or modifying a pre-existing one.
*/
struct
iwl_mvm_add_sta_cmd
{
struct
iwl_mvm_add_sta_cmd
_v5
{
u8
add_modify
;
u8
unicast_tx_key_id
;
u8
multicast_tx_key_id
;
...
...
@@ -312,6 +312,57 @@ struct iwl_mvm_add_sta_cmd {
__le32
tfd_queue_msk
;
}
__packed
;
/* ADD_STA_CMD_API_S_VER_5 */
/**
* struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station
* VER_6 of this command is quite similar to VER_5 except
* exclusion of all fields related to the security key installation.
*/
struct
iwl_mvm_add_sta_cmd_v6
{
u8
add_modify
;
u8
reserved1
;
__le16
tid_disable_tx
;
__le32
mac_id_n_color
;
u8
addr
[
ETH_ALEN
];
/* _STA_ID_MODIFY_INFO_API_S_VER_1 */
__le16
reserved2
;
u8
sta_id
;
u8
modify_mask
;
__le16
reserved3
;
__le32
station_flags
;
__le32
station_flags_msk
;
u8
add_immediate_ba_tid
;
u8
remove_immediate_ba_tid
;
__le16
add_immediate_ba_ssn
;
__le16
sleep_tx_count
;
__le16
sleep_state_flags
;
__le16
assoc_id
;
__le16
beamform_flags
;
__le32
tfd_queue_msk
;
}
__packed
;
/* ADD_STA_CMD_API_S_VER_6 */
/**
* struct iwl_mvm_add_sta_key_cmd - add/modify sta key
* ( REPLY_ADD_STA_KEY = 0x17 )
* @sta_id: index of station in uCode's station table
* @key_offset: key offset in key storage
* @key_flags: type %iwl_sta_key_flag
* @key: key material data
* @key2: key material data
* @rx_secur_seq_cnt: RX security sequence counter for the key
* @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
* @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
*/
struct
iwl_mvm_add_sta_key_cmd
{
u8
sta_id
;
u8
key_offset
;
__le16
key_flags
;
u8
key
[
16
];
u8
key2
[
16
];
u8
rx_secur_seq_cnt
[
16
];
u8
tkip_rx_tsc_byte2
;
u8
reserved
;
__le16
tkip_rx_ttak
[
5
];
}
__packed
;
/* ADD_MODIFY_STA_KEY_API_S_VER_1 */
/**
* enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command
* @ADD_STA_SUCCESS: operation was executed successfully
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api.h
View file @
444474dd
...
...
@@ -72,17 +72,17 @@
#include "fw-api-d3.h"
#include "fw-api-bt-coex.h"
/* queue and FIFO numbers by usage */
/* maximal number of Tx queues in any platform */
#define IWL_MVM_MAX_QUEUES 20
/* Tx queue numbers */
enum
{
IWL_MVM_OFFCHANNEL_QUEUE
=
8
,
IWL_MVM_CMD_QUEUE
=
9
,
IWL_MVM_AUX_QUEUE
=
15
,
IWL_MVM_FIRST_AGG_QUEUE
=
16
,
IWL_MVM_NUM_QUEUES
=
20
,
IWL_MVM_LAST_AGG_QUEUE
=
IWL_MVM_NUM_QUEUES
-
1
,
IWL_MVM_CMD_FIFO
=
7
};
#define IWL_MVM_CMD_FIFO 7
#define IWL_MVM_STATION_COUNT 16
/* commands */
...
...
@@ -97,6 +97,7 @@ enum {
DBG_CFG
=
0x9
,
/* station table */
ADD_STA_KEY
=
0x17
,
ADD_STA
=
0x18
,
REMOVE_STA
=
0x19
,
...
...
@@ -114,6 +115,7 @@ enum {
TIME_EVENT_NOTIFICATION
=
0x2a
,
BINDING_CONTEXT_CMD
=
0x2b
,
TIME_QUOTA_CMD
=
0x2c
,
NON_QOS_TX_COUNTER_CMD
=
0x2d
,
LQ_CMD
=
0x4e
,
...
...
@@ -130,6 +132,7 @@ enum {
SCAN_OFFLOAD_COMPLETE
=
0x6D
,
SCAN_OFFLOAD_UPDATE_PROFILES_CMD
=
0x6E
,
SCAN_OFFLOAD_CONFIG_CMD
=
0x6f
,
MATCH_FOUND_NOTIFICATION
=
0xd9
,
/* Phy */
PHY_CONFIGURATION_CMD
=
0x6a
,
...
...
@@ -178,6 +181,7 @@ enum {
BT_COEX_PRIO_TABLE
=
0xcc
,
BT_COEX_PROT_ENV
=
0xcd
,
BT_PROFILE_NOTIFICATION
=
0xce
,
BT_COEX_CI
=
0x5d
,
REPLY_BEACON_FILTERING_CMD
=
0xd2
,
...
...
drivers/net/wireless/iwlwifi/mvm/fw.c
View file @
444474dd
...
...
@@ -199,7 +199,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
*/
for
(
i
=
0
;
i
<
IWL_MAX_HW_QUEUES
;
i
++
)
{
if
(
i
<
IWL_MVM_FIRST_AGG_QUEUE
&&
i
!=
IWL_MVM_CMD_QUEUE
)
if
(
i
<
mvm
->
first_agg_queue
&&
i
!=
IWL_MVM_CMD_QUEUE
)
mvm
->
queue_to_mac80211
[
i
]
=
i
;
else
mvm
->
queue_to_mac80211
[
i
]
=
IWL_INVALID_MAC80211_QUEUE
;
...
...
@@ -243,7 +243,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
mvm
->
init_ucode_
run
)
if
(
mvm
->
init_ucode_
complete
)
return
0
;
iwl_init_notification_wait
(
&
mvm
->
notif_wait
,
...
...
@@ -264,6 +264,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
if
(
ret
)
goto
error
;
/* Read the NVM only at driver load time, no need to do this twice */
if
(
read_nvm
)
{
/* Read nvm */
ret
=
iwl_nvm_init
(
mvm
);
...
...
@@ -273,6 +274,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
}
}
/* In case we read the NVM from external file, load it to the NIC */
if
(
iwlwifi_mod_params
.
nvm_file
)
iwl_mvm_load_nvm_to_nic
(
mvm
);
ret
=
iwl_nvm_check_version
(
mvm
->
nvm_data
,
mvm
->
trans
);
WARN_ON
(
ret
);
...
...
@@ -310,7 +315,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
ret
=
iwl_wait_notification
(
&
mvm
->
notif_wait
,
&
calib_wait
,
MVM_UCODE_CALIB_TIMEOUT
);
if
(
!
ret
)
mvm
->
init_ucode_
run
=
true
;
mvm
->
init_ucode_
complete
=
true
;
goto
out
;
error:
...
...
@@ -353,8 +358,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if
(
ret
)
return
ret
;
/* If we were in RFKILL during module loading, load init ucode now */
if
(
!
mvm
->
init_ucode_run
)
{
/*
* If we haven't completed the run of the init ucode during
* module loading, load init ucode now
* (for example, if we were in RFKILL)
*/
if
(
!
mvm
->
init_ucode_complete
)
{
ret
=
iwl_run_init_mvm_ucode
(
mvm
,
false
);
if
(
ret
&&
!
iwlmvm_mod_params
.
init_dbg
)
{
IWL_ERR
(
mvm
,
"Failed to run INIT ucode: %d
\n
"
,
ret
);
...
...
@@ -424,6 +433,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto
error
;
}
ret
=
iwl_mvm_power_update_device_mode
(
mvm
);
if
(
ret
)
goto
error
;
IWL_DEBUG_INFO
(
mvm
,
"RT uCode started.
\n
"
);
return
0
;
error:
...
...
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
View file @
444474dd
...
...
@@ -80,7 +80,7 @@ struct iwl_mvm_mac_iface_iterator_data {
struct
ieee80211_vif
*
vif
;
unsigned
long
available_mac_ids
[
BITS_TO_LONGS
(
NUM_MAC_INDEX_DRIVER
)];
unsigned
long
available_tsf_ids
[
BITS_TO_LONGS
(
NUM_TSF_IDS
)];
unsigned
long
used_hw_queues
[
BITS_TO_LONGS
(
IWL_MVM_
FIRST_AGG_QUEUE
)];
unsigned
long
used_hw_queues
[
BITS_TO_LONGS
(
IWL_MVM_
MAX_QUEUES
)];
enum
iwl_tsf_id
preferred_tsf
;
bool
found_vif
;
};
...
...
@@ -218,7 +218,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
.
preferred_tsf
=
NUM_TSF_IDS
,
.
used_hw_queues
=
{
BIT
(
IWL_MVM_OFFCHANNEL_QUEUE
)
|
BIT
(
IWL_MVM_AUX_QUEUE
)
|
BIT
(
mvm
->
aux_queue
)
|
BIT
(
IWL_MVM_CMD_QUEUE
)
},
.
found_vif
=
false
,
...
...
@@ -242,9 +242,17 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
* that we should share it with another interface.
*/
/* Currently, MAC ID 0 should be used only for the managed vif */
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
/* Currently, MAC ID 0 should be used only for the managed/IBSS vif */
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_ADHOC
:
break
;
case
NL80211_IFTYPE_STATION
:
if
(
!
vif
->
p2p
)
break
;
/* fall through */
default:
__clear_bit
(
0
,
data
.
available_mac_ids
);
}
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_RESUME_ALL
,
...
...
@@ -302,9 +310,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
/* Find available queues, and allocate them to the ACs */
for
(
ac
=
0
;
ac
<
IEEE80211_NUM_ACS
;
ac
++
)
{
u8
queue
=
find_first_zero_bit
(
data
.
used_hw_queues
,
IWL_MVM_FIRST_AGG_QUEUE
);
mvm
->
first_agg_queue
);
if
(
queue
>=
IWL_MVM_FIRST_AGG_QUEUE
)
{
if
(
queue
>=
mvm
->
first_agg_queue
)
{
IWL_ERR
(
mvm
,
"Failed to allocate queue
\n
"
);
ret
=
-
EIO
;
goto
exit_fail
;
...
...
@@ -317,9 +325,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
/* Allocate the CAB queue for softAP and GO interfaces */
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
u8
queue
=
find_first_zero_bit
(
data
.
used_hw_queues
,
IWL_MVM_FIRST_AGG_QUEUE
);
mvm
->
first_agg_queue
);
if
(
queue
>=
IWL_MVM_FIRST_AGG_QUEUE
)
{
if
(
queue
>=
mvm
->
first_agg_queue
)
{
IWL_ERR
(
mvm
,
"Failed to allocate cab queue
\n
"
);
ret
=
-
EIO
;
goto
exit_fail
;
...
...
@@ -559,8 +567,12 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd
->
qos_flags
|=
cpu_to_le32
(
MAC_QOS_FLG_UPDATE_EDCA
);
/* Don't use cts to self as the fw doesn't support it currently. */
if
(
vif
->
bss_conf
.
use_cts_prot
)
if
(
vif
->
bss_conf
.
use_cts_prot
)
{
cmd
->
protection_flags
|=
cpu_to_le32
(
MAC_PROT_FLG_TGG_PROTECT
);
if
(
IWL_UCODE_API
(
mvm
->
fw
->
ucode_ver
)
>=
8
)
cmd
->
protection_flags
|=
cpu_to_le32
(
MAC_PROT_FLG_SELF_CTS_EN
);
}
/*
* I think that we should enable these 2 flags regardless the HT PROT
...
...
@@ -712,6 +724,31 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
return
iwl_mvm_mac_ctxt_send_cmd
(
mvm
,
&
cmd
);
}
static
int
iwl_mvm_mac_ctxt_cmd_ibss
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
u32
action
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mac_ctx_cmd
cmd
=
{};
WARN_ON
(
vif
->
type
!=
NL80211_IFTYPE_ADHOC
);
iwl_mvm_mac_ctxt_cmd_common
(
mvm
,
vif
,
&
cmd
,
action
);
cmd
.
filter_flags
=
cpu_to_le32
(
MAC_FILTER_IN_BEACON
|
MAC_FILTER_IN_PROBE_REQUEST
);
/* cmd.ibss.beacon_time/cmd.ibss.beacon_tsf are curently ignored */
cmd
.
ibss
.
bi
=
cpu_to_le32
(
vif
->
bss_conf
.
beacon_int
);
cmd
.
ibss
.
bi_reciprocal
=
cpu_to_le32
(
iwl_mvm_reciprocal
(
vif
->
bss_conf
.
beacon_int
));
/* TODO: Assumes that the beacon id == mac context id */
cmd
.
ibss
.
beacon_template
=
cpu_to_le32
(
mvmvif
->
id
);
return
iwl_mvm_mac_ctxt_send_cmd
(
mvm
,
&
cmd
);
}
struct
iwl_mvm_go_iterator_data
{
bool
go_active
;
};
...
...
@@ -721,7 +758,8 @@ static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif)
struct
iwl_mvm_go_iterator_data
*
data
=
_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
if
(
vif
->
type
==
NL80211_IFTYPE_AP
&&
vif
->
p2p
&&
mvmvif
->
ap_active
)
if
(
vif
->
type
==
NL80211_IFTYPE_AP
&&
vif
->
p2p
&&
mvmvif
->
ap_ibss_active
)
data
->
go_active
=
true
;
}
...
...
@@ -833,9 +871,10 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
cpu_to_le32
(
iwl_mvm_mac80211_idx_to_hwrate
(
rate
));
/* Set up TX beacon command fields */
iwl_mvm_mac_ctxt_set_tim
(
mvm
,
&
beacon_cmd
,
beacon
->
data
,
beacon_skb_len
);
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
iwl_mvm_mac_ctxt_set_tim
(
mvm
,
&
beacon_cmd
,
beacon
->
data
,
beacon_skb_len
);
/* Submit command */
cmd
.
len
[
0
]
=
sizeof
(
beacon_cmd
);
...
...
@@ -848,14 +887,15 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
return
iwl_mvm_send_cmd
(
mvm
,
&
cmd
);
}
/* The beacon template for the AP/GO
context
has changed and needs update */
/* The beacon template for the AP/GO
/IBSS
has changed and needs update */
int
iwl_mvm_mac_ctxt_beacon_changed
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
sk_buff
*
beacon
;
int
ret
;
WARN_ON
(
vif
->
type
!=
NL80211_IFTYPE_AP
);
WARN_ON
(
vif
->
type
!=
NL80211_IFTYPE_AP
&&
vif
->
type
!=
NL80211_IFTYPE_ADHOC
);
beacon
=
ieee80211_beacon_get
(
mvm
->
hw
,
vif
);
if
(
!
beacon
)
...
...
@@ -1018,6 +1058,8 @@ static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return
iwl_mvm_mac_ctxt_cmd_listener
(
mvm
,
vif
,
action
);
case
NL80211_IFTYPE_P2P_DEVICE
:
return
iwl_mvm_mac_ctxt_cmd_p2p_device
(
mvm
,
vif
,
action
);
case
NL80211_IFTYPE_ADHOC
:
return
iwl_mvm_mac_ctxt_cmd_ibss
(
mvm
,
vif
,
action
);
default:
break
;
}
...
...
@@ -1038,6 +1080,9 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if
(
ret
)
return
ret
;
/* will only do anything at resume from D3 time */
iwl_mvm_set_last_nonqos_seq
(
mvm
,
vif
);
mvmvif
->
uploaded
=
true
;
return
0
;
}
...
...
drivers/net/wireless/iwlwifi/mvm/mac80211.c
View file @
444474dd
...
...
@@ -77,6 +77,7 @@
#include "iwl-eeprom-parse.h"
#include "fw-api-scan.h"
#include "iwl-phy-db.h"
#include "testmode.h"
static
const
struct
ieee80211_iface_limit
iwl_mvm_limits
[]
=
{
{
...
...
@@ -138,6 +139,14 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
}
}
static
int
iwl_mvm_max_scan_ie_len
(
struct
iwl_mvm
*
mvm
)
{
/* we create the 802.11 header and SSID element */
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID
)
return
mvm
->
fw
->
ucode_capa
.
max_probe_length
-
24
-
2
;
return
mvm
->
fw
->
ucode_capa
.
max_probe_length
-
24
-
34
;
}
int
iwl_mvm_mac_setup_register
(
struct
iwl_mvm
*
mvm
)
{
struct
ieee80211_hw
*
hw
=
mvm
->
hw
;
...
...
@@ -158,7 +167,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IEEE80211_HW_SUPPORTS_STATIC_SMPS
|
IEEE80211_HW_SUPPORTS_UAPSD
;
hw
->
queues
=
IWL_MVM_FIRST_AGG_QUEUE
;
hw
->
queues
=
mvm
->
first_agg_queue
;
hw
->
offchannel_tx_hw_queue
=
IWL_MVM_OFFCHANNEL_QUEUE
;
hw
->
rate_control_algorithm
=
"iwl-mvm-rs"
;
...
...
@@ -181,6 +190,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
BIT
(
NL80211_IFTYPE_P2P_GO
)
|
BIT
(
NL80211_IFTYPE_P2P_DEVICE
);
/* IBSS has bugs in older versions */
if
(
IWL_UCODE_API
(
mvm
->
fw
->
ucode_ver
)
>=
8
)
hw
->
wiphy
->
interface_modes
|=
BIT
(
NL80211_IFTYPE_ADHOC
);
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_CUSTOM_REGULATORY
|
WIPHY_FLAG_DISABLE_BEACON_HINTS
|
WIPHY_FLAG_IBSS_RSN
;
...
...
@@ -212,9 +225,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
iwl_mvm_reset_phy_ctxts
(
mvm
);
/* we create the 802.11 header and a max-length SSID element */
hw
->
wiphy
->
max_scan_ie_len
=
mvm
->
fw
->
ucode_capa
.
max_probe_length
-
24
-
34
;
hw
->
wiphy
->
max_scan_ie_len
=
iwl_mvm_max_scan_ie_len
(
mvm
);
hw
->
wiphy
->
max_scan_ssids
=
PROBE_OPTION_MAX
;
if
(
mvm
->
nvm_data
->
bands
[
IEEE80211_BAND_2GHZ
].
n_channels
)
...
...
@@ -231,6 +243,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
else
hw
->
wiphy
->
flags
&=
~
WIPHY_FLAG_PS_ON_BY_DEFAULT
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_SCHED_SCAN
)
{
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_SUPPORTS_SCHED_SCAN
;
hw
->
wiphy
->
max_sched_scan_ssids
=
PROBE_OPTION_MAX
;
hw
->
wiphy
->
max_match_sets
=
IWL_SCAN_MAX_PROFILES
;
/* we create the 802.11 header and zero length SSID IE. */
hw
->
wiphy
->
max_sched_scan_ie_len
=
SCAN_OFFLOAD_PROBE_REQ_SIZE
-
24
-
2
;
}
hw
->
wiphy
->
features
|=
NL80211_FEATURE_P2P_GO_CTWIN
|
NL80211_FEATURE_P2P_GO_OPPPS
;
...
...
@@ -548,7 +569,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
* In short: there's not much we can do at this point, other than
* allocating resources :)
*/
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
if
(
vif
->
type
==
NL80211_IFTYPE_AP
||
vif
->
type
==
NL80211_IFTYPE_ADHOC
)
{
u32
qmask
=
iwl_mvm_mac_get_queues_mask
(
mvm
,
vif
);
ret
=
iwl_mvm_allocate_int_sta
(
mvm
,
&
mvmvif
->
bcast_sta
,
qmask
);
...
...
@@ -698,7 +720,14 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
* For AP/GO interface, the tear down of the resources allocated to the
* interface is be handled as part of the stop_ap flow.
*/
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
if
(
vif
->
type
==
NL80211_IFTYPE_AP
||
vif
->
type
==
NL80211_IFTYPE_ADHOC
)
{
#ifdef CONFIG_NL80211_TESTMODE
if
(
vif
==
mvm
->
noa_vif
)
{
mvm
->
noa_vif
=
NULL
;
mvm
->
noa_duration
=
0
;
}
#endif
iwl_mvm_dealloc_int_sta
(
mvm
,
&
mvmvif
->
bcast_sta
);
goto
out_release
;
}
...
...
@@ -796,6 +825,27 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
return
;
}
iwl_mvm_configure_mcast_filter
(
mvm
,
vif
);
if
(
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
))
{
/*
* If we're restarting then the firmware will
* obviously have lost synchronisation with
* the AP. It will attempt to synchronise by
* itself, but we can make it more reliable by
* scheduling a session protection time event.
*
* The firmware needs to receive a beacon to
* catch up with synchronisation, use 110% of
* the beacon interval.
*
* Set a large maximum delay to allow for more
* than a single interface.
*/
u32
dur
=
(
11
*
vif
->
bss_conf
.
beacon_int
)
/
10
;
iwl_mvm_protect_session
(
mvm
,
vif
,
dur
,
dur
,
5
*
dur
);
}
}
else
if
(
mvmvif
->
ap_sta_id
!=
IWL_MVM_STATION_COUNT
)
{
/* remove AP station now that the MAC is unassoc */
ret
=
iwl_mvm_rm_sta_id
(
mvm
,
vif
,
mvmvif
->
ap_sta_id
);
...
...
@@ -819,7 +869,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to update power mode
\n
"
);
}
iwl_mvm_bt_coex_vif_
assoc
(
mvm
,
vif
);
iwl_mvm_bt_coex_vif_
change
(
mvm
);
}
else
if
(
changes
&
BSS_CHANGED_BEACON_INFO
)
{
/*
* We received a beacon _after_ association so
...
...
@@ -848,7 +898,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
}
}
static
int
iwl_mvm_start_ap
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
)
static
int
iwl_mvm_start_ap_ibss
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
...
...
@@ -871,7 +922,7 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
if
(
ret
)
goto
out_remove
;
mvmvif
->
ap_active
=
true
;
mvmvif
->
ap_
ibss_
active
=
true
;
/* Send the bcast station. At this stage the TBTT and DTIM time events
* are added and applied to the scheduler */
...
...
@@ -883,10 +934,12 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
if
(
ret
)
goto
out_rm_bcast
;
/* Need to update the P2P Device MAC */
/* Need to update the P2P Device MAC
(only GO, IBSS is single vif)
*/
if
(
vif
->
p2p
&&
mvm
->
p2p_device_vif
)
iwl_mvm_mac_ctxt_changed
(
mvm
,
mvm
->
p2p_device_vif
);
iwl_mvm_bt_coex_vif_change
(
mvm
);
mutex_unlock
(
&
mvm
->
mutex
);
return
0
;
...
...
@@ -901,7 +954,8 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return
ret
;
}
static
void
iwl_mvm_stop_ap
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
)
static
void
iwl_mvm_stop_ap_ibss
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
...
...
@@ -910,9 +964,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mutex_lock
(
&
mvm
->
mutex
);
mvmvif
->
ap_active
=
false
;
mvmvif
->
ap_ibss_active
=
false
;
iwl_mvm_bt_coex_vif_change
(
mvm
);
/* Need to update the P2P Device MAC */
/* Need to update the P2P Device MAC
(only GO, IBSS is single vif)
*/
if
(
vif
->
p2p
&&
mvm
->
p2p_device_vif
)
iwl_mvm_mac_ctxt_changed
(
mvm
,
mvm
->
p2p_device_vif
);
...
...
@@ -924,10 +980,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mutex_unlock
(
&
mvm
->
mutex
);
}
static
void
iwl_mvm_bss_info_changed_ap
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changes
)
static
void
iwl_mvm_bss_info_changed_ap_ibss
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_bss_conf
*
bss_conf
,
u32
changes
)
{
/* Need to send a new beacon template to the FW */
if
(
changes
&
BSS_CHANGED_BEACON
)
{
...
...
@@ -950,7 +1007,8 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
iwl_mvm_bss_info_changed_station
(
mvm
,
vif
,
bss_conf
,
changes
);
break
;
case
NL80211_IFTYPE_AP
:
iwl_mvm_bss_info_changed_ap
(
mvm
,
vif
,
bss_conf
,
changes
);
case
NL80211_IFTYPE_ADHOC
:
iwl_mvm_bss_info_changed_ap_ibss
(
mvm
,
vif
,
bss_conf
,
changes
);
break
;
default:
/* shouldn't happen */
...
...
@@ -1163,7 +1221,54 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
mutex_lock
(
&
mvm
->
mutex
);
/* Try really hard to protect the session and hear a beacon */
iwl_mvm_protect_session
(
mvm
,
vif
,
duration
,
min_duration
);
iwl_mvm_protect_session
(
mvm
,
vif
,
duration
,
min_duration
,
500
);
mutex_unlock
(
&
mvm
->
mutex
);
}
static
int
iwl_mvm_mac_sched_scan_start
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
int
ret
;
mutex_lock
(
&
mvm
->
mutex
);
if
(
mvm
->
scan_status
!=
IWL_MVM_SCAN_NONE
)
{
IWL_DEBUG_SCAN
(
mvm
,
"SCHED SCAN request during internal scan - abort
\n
"
);
ret
=
-
EBUSY
;
goto
out
;
}
mvm
->
scan_status
=
IWL_MVM_SCAN_SCHED
;
ret
=
iwl_mvm_config_sched_scan
(
mvm
,
vif
,
req
,
ies
);
if
(
ret
)
goto
err
;
ret
=
iwl_mvm_config_sched_scan_profiles
(
mvm
,
req
);
if
(
ret
)
goto
err
;
ret
=
iwl_mvm_sched_scan_start
(
mvm
,
req
);
if
(
!
ret
)
goto
out
;
err:
mvm
->
scan_status
=
IWL_MVM_SCAN_NONE
;
out:
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
;
}
static
void
iwl_mvm_mac_sched_scan_stop
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
mutex_lock
(
&
mvm
->
mutex
);
iwl_mvm_sched_scan_stop
(
mvm
);
mutex_unlock
(
&
mvm
->
mutex
);
}
...
...
@@ -1207,8 +1312,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
switch
(
cmd
)
{
case
SET_KEY
:
if
(
vif
->
type
==
NL80211_IFTYPE_AP
&&
!
sta
)
{
/* GTK on AP interface is a TX-only key, return 0 */
if
((
vif
->
type
==
NL80211_IFTYPE_ADHOC
||
vif
->
type
==
NL80211_IFTYPE_AP
)
&&
!
sta
)
{
/*
* GTK on AP interface is a TX-only key, return 0;
* on IBSS they're per-station and because we're lazy
* we don't support them for RX, so do the same.
*/
ret
=
0
;
key
->
hw_key_idx
=
STA_KEY_IDX_INVALID
;
break
;
...
...
@@ -1252,6 +1362,9 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
if
(
keyconf
->
hw_key_idx
==
STA_KEY_IDX_INVALID
)
return
;
iwl_mvm_update_tkip_key
(
mvm
,
vif
,
keyconf
,
sta
,
iv32
,
phase1key
);
}
...
...
@@ -1445,6 +1558,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
iwl_mvm_phy_ctxt_changed
(
mvm
,
phy_ctxt
,
&
ctx
->
def
,
ctx
->
rx_chains_static
,
ctx
->
rx_chains_dynamic
);
iwl_mvm_bt_coex_vif_change
(
mvm
);
mutex_unlock
(
&
mvm
->
mutex
);
}
...
...
@@ -1464,14 +1578,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_AP
:
case
NL80211_IFTYPE_ADHOC
:
/*
* The AP binding flow is handled as part of the start_ap flow
* (in bss_info_changed).
* (in bss_info_changed)
, similarly for IBSS
.
*/
ret
=
0
;
goto
out_unlock
;
case
NL80211_IFTYPE_STATION
:
case
NL80211_IFTYPE_ADHOC
:
case
NL80211_IFTYPE_MONITOR
:
break
;
default:
...
...
@@ -1517,10 +1631,10 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_remove_time_event
(
mvm
,
mvmvif
,
&
mvmvif
->
time_event_data
);
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
goto
out_unlock
;
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_AP
:
case
NL80211_IFTYPE_ADHOC
:
goto
out_unlock
;
case
NL80211_IFTYPE_MONITOR
:
mvmvif
->
monitor_active
=
false
;
iwl_mvm_update_quotas
(
mvm
,
NULL
);
...
...
@@ -1550,14 +1664,72 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
return
iwl_mvm_mac_ctxt_beacon_changed
(
mvm
,
mvm_sta
->
vif
);
}
static
void
iwl_mvm_mac_rssi_callback
(
struct
ieee80211_hw
*
hw
,
#ifdef CONFIG_NL80211_TESTMODE
static
const
struct
nla_policy
iwl_mvm_tm_policy
[
IWL_MVM_TM_ATTR_MAX
+
1
]
=
{
[
IWL_MVM_TM_ATTR_CMD
]
=
{
.
type
=
NLA_U32
},
[
IWL_MVM_TM_ATTR_NOA_DURATION
]
=
{
.
type
=
NLA_U32
},
[
IWL_MVM_TM_ATTR_BEACON_FILTER_STATE
]
=
{
.
type
=
NLA_U32
},
};
static
int
__iwl_mvm_mac_testmode_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
enum
ieee80211_rssi_event
rssi_event
)
void
*
data
,
int
len
)
{
struct
nlattr
*
tb
[
IWL_MVM_TM_ATTR_MAX
+
1
];
int
err
;
u32
noa_duration
;
err
=
nla_parse
(
tb
,
IWL_MVM_TM_ATTR_MAX
,
data
,
len
,
iwl_mvm_tm_policy
);
if
(
err
)
return
err
;
if
(
!
tb
[
IWL_MVM_TM_ATTR_CMD
])
return
-
EINVAL
;
switch
(
nla_get_u32
(
tb
[
IWL_MVM_TM_ATTR_CMD
]))
{
case
IWL_MVM_TM_CMD_SET_NOA
:
if
(
!
vif
||
vif
->
type
!=
NL80211_IFTYPE_AP
||
!
vif
->
p2p
||
!
vif
->
bss_conf
.
enable_beacon
||
!
tb
[
IWL_MVM_TM_ATTR_NOA_DURATION
])
return
-
EINVAL
;
noa_duration
=
nla_get_u32
(
tb
[
IWL_MVM_TM_ATTR_NOA_DURATION
]);
if
(
noa_duration
>=
vif
->
bss_conf
.
beacon_int
)
return
-
EINVAL
;
mvm
->
noa_duration
=
noa_duration
;
mvm
->
noa_vif
=
vif
;
return
iwl_mvm_update_quotas
(
mvm
,
NULL
);
case
IWL_MVM_TM_CMD_SET_BEACON_FILTER
:
/* must be associated client vif - ignore authorized */
if
(
!
vif
||
vif
->
type
!=
NL80211_IFTYPE_STATION
||
!
vif
->
bss_conf
.
assoc
||
!
vif
->
bss_conf
.
dtim_period
||
!
tb
[
IWL_MVM_TM_ATTR_BEACON_FILTER_STATE
])
return
-
EINVAL
;
if
(
nla_get_u32
(
tb
[
IWL_MVM_TM_ATTR_BEACON_FILTER_STATE
]))
return
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
);
return
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
);
}
return
-
EOPNOTSUPP
;
}
static
int
iwl_mvm_mac_testmode_cmd
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
void
*
data
,
int
len
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
int
err
;
iwl_mvm_bt_rssi_event
(
mvm
,
vif
,
rssi_event
);
mutex_lock
(
&
mvm
->
mutex
);
err
=
__iwl_mvm_mac_testmode_cmd
(
mvm
,
vif
,
data
,
len
);
mutex_unlock
(
&
mvm
->
mutex
);
return
err
;
}
#endif
struct
ieee80211_ops
iwl_mvm_hw_ops
=
{
.
tx
=
iwl_mvm_mac_tx
,
...
...
@@ -1578,23 +1750,27 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.
set_rts_threshold
=
iwl_mvm_mac_set_rts_threshold
,
.
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
,
.
sched_scan_stop
=
iwl_mvm_mac_sched_scan_stop
,
.
set_key
=
iwl_mvm_mac_set_key
,
.
update_tkip_key
=
iwl_mvm_mac_update_tkip_key
,
.
remain_on_channel
=
iwl_mvm_roc
,
.
cancel_remain_on_channel
=
iwl_mvm_cancel_roc
,
.
rssi_callback
=
iwl_mvm_mac_rssi_callback
,
.
add_chanctx
=
iwl_mvm_add_chanctx
,
.
remove_chanctx
=
iwl_mvm_remove_chanctx
,
.
change_chanctx
=
iwl_mvm_change_chanctx
,
.
assign_vif_chanctx
=
iwl_mvm_assign_vif_chanctx
,
.
unassign_vif_chanctx
=
iwl_mvm_unassign_vif_chanctx
,
.
start_ap
=
iwl_mvm_start_ap
,
.
stop_ap
=
iwl_mvm_stop_ap
,
.
start_ap
=
iwl_mvm_start_ap_ibss
,
.
stop_ap
=
iwl_mvm_stop_ap_ibss
,
.
join_ibss
=
iwl_mvm_start_ap_ibss
,
.
leave_ibss
=
iwl_mvm_stop_ap_ibss
,
.
set_tim
=
iwl_mvm_set_tim
,
CFG80211_TESTMODE_CMD
(
iwl_mvm_mac_testmode_cmd
)
#ifdef CONFIG_PM_SLEEP
/* look at d3.c */
.
suspend
=
iwl_mvm_suspend
,
...
...
drivers/net/wireless/iwlwifi/mvm/mvm.h
View file @
444474dd
...
...
@@ -162,6 +162,7 @@ enum iwl_power_scheme {
struct
iwl_mvm_power_ops
{
int
(
*
power_update_mode
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
int
(
*
power_update_device_mode
)(
struct
iwl_mvm
*
mvm
);
int
(
*
power_disable
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int
(
*
power_dbgfs_read
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
...
...
@@ -241,12 +242,18 @@ enum iwl_mvm_smps_type_request {
* @last_beacon_signal: last beacon rssi signal in dbm
* @ave_beacon_signal: average beacon signal
* @last_cqm_event: rssi of the last cqm event
* @bt_coex_min_thold: minimum threshold for BT coex
* @bt_coex_max_thold: maximum threshold for BT coex
* @last_bt_coex_event: rssi of the last BT coex event
*/
struct
iwl_mvm_vif_bf_data
{
bool
bf_enabled
;
bool
ba_enabled
;
s8
ave_beacon_signal
;
s8
last_cqm_event
;
s8
bt_coex_min_thold
;
s8
bt_coex_max_thold
;
s8
last_bt_coex_event
;
};
/**
...
...
@@ -255,8 +262,8 @@ struct iwl_mvm_vif_bf_data {
* @color: to solve races upon MAC addition and removal
* @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
* @uploaded: indicates the MAC context has been added to the device
* @ap_
active: indicates that ap context is configured,
and that the interface
*
should get quota etc.
* @ap_
ibss_active: indicates that AP/IBSS is configured
and that the interface
*
should get quota etc.
* @monitor_active: indicates that monitor context is configured, and that the
* interface should get quota etc.
* @queue_params: QoS params for this MAC
...
...
@@ -272,7 +279,7 @@ struct iwl_mvm_vif {
u8
ap_sta_id
;
bool
uploaded
;
bool
ap_active
;
bool
ap_
ibss_
active
;
bool
monitor_active
;
struct
iwl_mvm_vif_bf_data
bf_data
;
...
...
@@ -306,6 +313,9 @@ struct iwl_mvm_vif {
int
tx_key_idx
;
bool
seqno_valid
;
u16
seqno
;
#if IS_ENABLED(CONFIG_IPV6)
/* IPv6 addresses for WoWLAN */
struct
in6_addr
target_ipv6_addrs
[
IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX
];
...
...
@@ -333,6 +343,7 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
enum
iwl_scan_status
{
IWL_MVM_SCAN_NONE
,
IWL_MVM_SCAN_OS
,
IWL_MVM_SCAN_SCHED
,
};
/**
...
...
@@ -434,7 +445,7 @@ struct iwl_mvm {
enum
iwl_ucode_type
cur_ucode
;
bool
ucode_loaded
;
bool
init_ucode_
run
;
bool
init_ucode_
complete
;
u32
error_event_table
;
u32
log_event_table
;
...
...
@@ -470,6 +481,9 @@ struct iwl_mvm {
enum
iwl_scan_status
scan_status
;
struct
iwl_scan_cmd
*
scan_cmd
;
/* rx chain antennas set through debugfs for the scan command */
u8
scan_rx_ant
;
/* Internal station */
struct
iwl_mvm_int_sta
aux_sta
;
...
...
@@ -479,7 +493,8 @@ struct iwl_mvm {
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct
dentry
*
debugfs_dir
;
u32
dbgfs_sram_offset
,
dbgfs_sram_len
;
bool
prevent_power_down_d3
;
bool
disable_power_off
;
bool
disable_power_off_d3
;
#endif
struct
iwl_mvm_phy_ctxt
phy_ctxts
[
NUM_PHY_CTX
];
...
...
@@ -523,12 +538,23 @@ struct iwl_mvm {
/* BT-Coex */
u8
bt_kill_msk
;
struct
iwl_bt_coex_profile_notif
last_bt_notif
;
struct
iwl_bt_coex_ci_cmd
last_bt_ci_cmd
;
/* Thermal Throttling and CTkill */
struct
iwl_mvm_tt_mgmt
thermal_throttle
;
s32
temperature
;
/* Celsius */
const
struct
iwl_mvm_power_ops
*
pm_ops
;
#ifdef CONFIG_NL80211_TESTMODE
u32
noa_duration
;
struct
ieee80211_vif
*
noa_vif
;
#endif
/* Tx queues */
u8
aux_queue
;
u8
first_agg_queue
;
u8
last_agg_queue
;
};
/* Extract MVM priv from op_mode and _hw */
...
...
@@ -570,6 +596,9 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm);
/* Utils */
int
iwl_mvm_legacy_rate_to_mac80211_idx
(
u32
rate_n_flags
,
enum
ieee80211_band
band
);
void
iwl_mvm_hwrate_to_tx_rate
(
u32
rate_n_flags
,
enum
ieee80211_band
band
,
struct
ieee80211_tx_rate
*
r
);
u8
iwl_mvm_mac80211_idx_to_hwrate
(
int
rate_idx
);
void
iwl_mvm_dump_nic_error_log
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_dump_sram
(
struct
iwl_mvm
*
mvm
);
...
...
@@ -608,6 +637,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
/* NVM */
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_load_nvm_to_nic
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_up
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_load_d3_fw
(
struct
iwl_mvm
*
mvm
);
...
...
@@ -682,6 +712,23 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct
iwl_device_cmd
*
cmd
);
void
iwl_mvm_cancel_scan
(
struct
iwl_mvm
*
mvm
);
/* Scheduled scan */
int
iwl_mvm_rx_scan_offload_complete_notif
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
);
int
iwl_mvm_config_sched_scan
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
);
int
iwl_mvm_config_sched_scan_profiles
(
struct
iwl_mvm
*
mvm
,
struct
cfg80211_sched_scan_request
*
req
);
int
iwl_mvm_sched_scan_start
(
struct
iwl_mvm
*
mvm
,
struct
cfg80211_sched_scan_request
*
req
);
void
iwl_mvm_sched_scan_stop
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_rx_sched_scan_results
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
);
/* MVM debugfs */
#ifdef CONFIG_IWLWIFI_DEBUGFS
int
iwl_mvm_dbgfs_register
(
struct
iwl_mvm
*
mvm
,
struct
dentry
*
dbgfs_dir
);
...
...
@@ -720,6 +767,13 @@ static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm,
return
mvm
->
pm_ops
->
power_disable
(
mvm
,
vif
);
}
static
inline
int
iwl_mvm_power_update_device_mode
(
struct
iwl_mvm
*
mvm
)
{
if
(
mvm
->
pm_ops
->
power_update_device_mode
)
return
mvm
->
pm_ops
->
power_update_device_mode
(
mvm
);
return
0
;
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
inline
int
iwl_mvm_power_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
...
...
@@ -745,6 +799,15 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
void
iwl_mvm_set_default_unicast_key
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
int
idx
);
extern
const
struct
file_operations
iwl_dbgfs_d3_test_ops
;
#ifdef CONFIG_PM_SLEEP
void
iwl_mvm_set_last_nonqos_seq
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
#else
static
inline
void
iwl_mvm_set_last_nonqos_seq
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
}
#endif
/* BT Coex */
int
iwl_send_bt_prio_tbl
(
struct
iwl_mvm
*
mvm
);
...
...
@@ -754,7 +817,20 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct
iwl_device_cmd
*
cmd
);
void
iwl_mvm_bt_rssi_event
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
enum
ieee80211_rssi_event
rssi_event
);
void
iwl_mvm_bt_coex_vif_assoc
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
void
iwl_mvm_bt_coex_vif_change
(
struct
iwl_mvm
*
mvm
);
u16
iwl_mvm_bt_coex_agg_time_limit
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
);
bool
iwl_mvm_bt_coex_is_mimo_allowed
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
);
enum
iwl_bt_kill_msk
{
BT_KILL_MSK_DEFAULT
,
BT_KILL_MSK_SCO_HID_A2DP
,
BT_KILL_MSK_REDUCED_TXPOW
,
BT_KILL_MSK_MAX
,
};
extern
const
u32
iwl_bt_ack_kill_msk
[
BT_KILL_MSK_MAX
];
extern
const
u32
iwl_bt_cts_kill_msk
[
BT_KILL_MSK_MAX
];
/* beacon filtering */
#ifdef CONFIG_IWLWIFI_DEBUGFS
...
...
drivers/net/wireless/iwlwifi/mvm/nvm.c
View file @
444474dd
...
...
@@ -77,7 +77,7 @@ static const int nvm_to_read[] = {
/* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
#define IWL_MAX_NVM_SECTION_SIZE
6
000
#define IWL_MAX_NVM_SECTION_SIZE
7
000
#define NVM_WRITE_OPCODE 1
#define NVM_READ_OPCODE 0
...
...
@@ -259,6 +259,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
#define MAX_NVM_FILE_LEN 16384
/*
* Reads external NVM from a file into mvm->nvm_sections
*
* HOW TO CREATE THE NVM FILE FORMAT:
* ------------------------------
* 1. create hex file, format:
...
...
@@ -277,20 +279,23 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
*
* 4. save as "iNVM_xxx.bin" under /lib/firmware
*/
static
int
iwl_mvm_
lo
ad_external_nvm
(
struct
iwl_mvm
*
mvm
)
static
int
iwl_mvm_
re
ad_external_nvm
(
struct
iwl_mvm
*
mvm
)
{
int
ret
,
section_id
,
section_size
;
int
ret
,
section_size
;
u16
section_id
;
const
struct
firmware
*
fw_entry
;
const
struct
{
__le16
word1
;
__le16
word2
;
u8
data
[];
}
*
file_sec
;
const
u8
*
eof
;
const
u8
*
eof
,
*
temp
;
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
#define NVM_WORD2_ID(x) (x >> 12)
IWL_DEBUG_EEPROM
(
mvm
->
trans
->
dev
,
"Read from external NVM
\n
"
);
/*
* Obtain NVM image via request_firmware. Since we already used
* request_firmware_nowait() for the firmware binary load and only
...
...
@@ -362,12 +367,18 @@ static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm)
break
;
}
ret
=
iwl_nvm_write_section
(
mvm
,
section_id
,
file_sec
->
data
,
section_size
);
if
(
ret
<
0
)
{
IWL_ERR
(
mvm
,
"iwl_mvm_send_cmd failed: %d
\n
"
,
ret
);
temp
=
kmemdup
(
file_sec
->
data
,
section_size
,
GFP_KERNEL
);
if
(
!
temp
)
{
ret
=
-
ENOMEM
;
break
;
}
if
(
WARN_ON
(
section_id
>=
NVM_NUM_OF_SECTIONS
))
{
IWL_ERR
(
mvm
,
"Invalid NVM section ID
\n
"
);
ret
=
-
EINVAL
;
break
;
}
mvm
->
nvm_sections
[
section_id
].
data
=
temp
;
mvm
->
nvm_sections
[
section_id
].
length
=
section_size
;
/* advance to the next section */
file_sec
=
(
void
*
)(
file_sec
->
data
+
section_size
);
...
...
@@ -377,6 +388,28 @@ static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm)
return
ret
;
}
/* Loads the NVM data stored in mvm->nvm_sections into the NIC */
int
iwl_mvm_load_nvm_to_nic
(
struct
iwl_mvm
*
mvm
)
{
int
i
,
ret
;
u16
section_id
;
struct
iwl_nvm_section
*
sections
=
mvm
->
nvm_sections
;
IWL_DEBUG_EEPROM
(
mvm
->
trans
->
dev
,
"'Write to NVM
\n
"
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
nvm_to_read
);
i
++
)
{
section_id
=
nvm_to_read
[
i
];
ret
=
iwl_nvm_write_section
(
mvm
,
section_id
,
sections
[
section_id
].
data
,
sections
[
section_id
].
length
);
if
(
ret
<
0
)
{
IWL_ERR
(
mvm
,
"iwl_mvm_send_cmd failed: %d
\n
"
,
ret
);
break
;
}
}
return
ret
;
}
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
)
{
int
ret
,
i
,
section
;
...
...
@@ -385,36 +418,36 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
/* load external NVM if configured */
if
(
iwlwifi_mod_params
.
nvm_file
)
{
/* move to External NVM flow */
ret
=
iwl_mvm_
lo
ad_external_nvm
(
mvm
);
ret
=
iwl_mvm_
re
ad_external_nvm
(
mvm
);
if
(
ret
)
return
ret
;
}
/* Read From FW NVM */
IWL_DEBUG_EEPROM
(
mvm
->
trans
->
dev
,
"Read from NVM
\n
"
);
/* TODO: find correct NVM max size for a section */
nvm_buffer
=
kmalloc
(
mvm
->
cfg
->
base_params
->
eeprom_size
,
GFP_KERNEL
);
if
(
!
nvm_buffer
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
nvm_to_read
);
i
++
)
{
section
=
nvm_to_read
[
i
];
/* we override the constness for initial read */
ret
=
iwl_nvm_read_section
(
mvm
,
section
,
nvm_buffer
);
if
(
ret
<
0
)
break
;
temp
=
kmemdup
(
nvm_buffer
,
ret
,
GFP_KERNEL
);
if
(
!
temp
)
{
ret
=
-
ENOMEM
;
break
;
}
else
{
/* Read From FW NVM */
IWL_DEBUG_EEPROM
(
mvm
->
trans
->
dev
,
"Read from NVM
\n
"
);
/* TODO: find correct NVM max size for a section */
nvm_buffer
=
kmalloc
(
mvm
->
cfg
->
base_params
->
eeprom_size
,
GFP_KERNEL
);
if
(
!
nvm_buffer
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
nvm_to_read
);
i
++
)
{
section
=
nvm_to_read
[
i
];
/* we override the constness for initial read */
ret
=
iwl_nvm_read_section
(
mvm
,
section
,
nvm_buffer
);
if
(
ret
<
0
)
break
;
temp
=
kmemdup
(
nvm_buffer
,
ret
,
GFP_KERNEL
);
if
(
!
temp
)
{
ret
=
-
ENOMEM
;
break
;
}
mvm
->
nvm_sections
[
section
].
data
=
temp
;
mvm
->
nvm_sections
[
section
].
length
=
ret
;
}
mvm
->
nvm_sections
[
section
].
data
=
temp
;
mvm
->
nvm_sections
[
section
].
length
=
ret
;
kfree
(
nvm_buffer
);
if
(
ret
<
0
)
return
ret
;
}
kfree
(
nvm_buffer
);
if
(
ret
<
0
)
return
ret
;
mvm
->
nvm_data
=
iwl_parse_nvm_sections
(
mvm
);
if
(
!
mvm
->
nvm_data
)
...
...
drivers/net/wireless/iwlwifi/mvm/ops.c
View file @
444474dd
...
...
@@ -224,6 +224,10 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER
(
SCAN_REQUEST_CMD
,
iwl_mvm_rx_scan_response
,
false
),
RX_HANDLER
(
SCAN_COMPLETE_NOTIFICATION
,
iwl_mvm_rx_scan_complete
,
false
),
RX_HANDLER
(
SCAN_OFFLOAD_COMPLETE
,
iwl_mvm_rx_scan_offload_complete_notif
,
false
),
RX_HANDLER
(
MATCH_FOUND_NOTIFICATION
,
iwl_mvm_rx_sched_scan_results
,
false
),
RX_HANDLER
(
RADIO_VERSION_NOTIFICATION
,
iwl_mvm_rx_radio_ver
,
false
),
RX_HANDLER
(
CARD_STATE_NOTIFICATION
,
iwl_mvm_rx_card_state_notif
,
false
),
...
...
@@ -249,6 +253,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD
(
TIME_EVENT_NOTIFICATION
),
CMD
(
BINDING_CONTEXT_CMD
),
CMD
(
TIME_QUOTA_CMD
),
CMD
(
NON_QOS_TX_COUNTER_CMD
),
CMD
(
RADIO_VERSION_NOTIFICATION
),
CMD
(
SCAN_REQUEST_CMD
),
CMD
(
SCAN_ABORT_CMD
),
...
...
@@ -260,10 +265,12 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD
(
CALIB_RES_NOTIF_PHY_DB
),
CMD
(
SET_CALIB_DEFAULT_CMD
),
CMD
(
CALIBRATION_COMPLETE_NOTIFICATION
),
CMD
(
ADD_STA_KEY
),
CMD
(
ADD_STA
),
CMD
(
REMOVE_STA
),
CMD
(
LQ_CMD
),
CMD
(
SCAN_OFFLOAD_CONFIG_CMD
),
CMD
(
MATCH_FOUND_NOTIFICATION
),
CMD
(
SCAN_OFFLOAD_REQUEST_CMD
),
CMD
(
SCAN_OFFLOAD_ABORT_CMD
),
CMD
(
SCAN_OFFLOAD_COMPLETE
),
...
...
@@ -303,6 +310,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD
(
REPLY_BEACON_FILTERING_CMD
),
CMD
(
REPLY_THERMAL_MNG_BACKOFF
),
CMD
(
MAC_PM_POWER_TABLE
),
CMD
(
BT_COEX_CI
),
};
#undef CMD
...
...
@@ -344,6 +352,14 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm
->
restart_fw
=
iwlwifi_mod_params
.
restart_fw
?
-
1
:
0
;
mvm
->
aux_queue
=
15
;
mvm
->
first_agg_queue
=
16
;
mvm
->
last_agg_queue
=
mvm
->
cfg
->
base_params
->
num_of_queues
-
1
;
if
(
mvm
->
cfg
->
base_params
->
num_of_queues
==
16
)
{
mvm
->
aux_queue
=
11
;
mvm
->
first_agg_queue
=
12
;
}
mutex_init
(
&
mvm
->
mutex
);
spin_lock_init
(
&
mvm
->
async_handlers_lock
);
INIT_LIST_HEAD
(
&
mvm
->
time_event_list
);
...
...
@@ -401,24 +417,32 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
IWL_INFO
(
mvm
,
"Detected %s, REV=0x%X
\n
"
,
mvm
->
cfg
->
name
,
mvm
->
trans
->
hw_rev
);
err
=
iwl_trans_start_hw
(
mvm
->
trans
);
if
(
err
)
goto
out_free
;
iwl_mvm_tt_initialize
(
mvm
);
mutex_lock
(
&
mvm
->
mutex
);
err
=
iwl_run_init_mvm_ucode
(
mvm
,
true
);
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
;
}
/*
* If the NVM exists in an external file,
* there is no need to unnecessarily power up the NIC at driver load
*/
if
(
iwlwifi_mod_params
.
nvm_file
)
{
iwl_nvm_init
(
mvm
);
}
else
{
err
=
iwl_trans_start_hw
(
mvm
->
trans
);
if
(
err
)
goto
out_free
;
mutex_lock
(
&
mvm
->
mutex
);
err
=
iwl_run_init_mvm_ucode
(
mvm
,
true
);
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
);
/* 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
)
+
mvm
->
fw
->
ucode_capa
.
max_probe_length
+
...
...
@@ -449,7 +473,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
out_free:
iwl_phy_db_free
(
mvm
->
phy_db
);
kfree
(
mvm
->
scan_cmd
);
iwl_trans_stop_hw
(
trans
,
true
);
if
(
!
iwlwifi_mod_params
.
nvm_file
)
iwl_trans_stop_hw
(
trans
,
true
);
ieee80211_free_hw
(
mvm
->
hw
);
return
NULL
;
}
...
...
@@ -715,6 +740,9 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
case
IWL_MVM_SCAN_OS
:
ieee80211_scan_completed
(
mvm
->
hw
,
true
);
break
;
case
IWL_MVM_SCAN_SCHED
:
ieee80211_sched_scan_stopped
(
mvm
->
hw
);
break
;
}
if
(
mvm
->
restart_fw
>
0
)
...
...
drivers/net/wireless/iwlwifi/mvm/power.c
View file @
444474dd
...
...
@@ -297,11 +297,6 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
}
if
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_ADVANCE_PM_ENA_MSK
))
{
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
->
uapsd_ac_flags
==
(
BIT
(
IEEE80211_AC_VO
)
|
BIT
(
IEEE80211_AC_VI
)
|
BIT
(
IEEE80211_AC_BE
)
|
...
...
@@ -316,10 +311,31 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
}
cmd
->
uapsd_max_sp
=
IWL_UAPSD_MAX_SP
;
cmd
->
heavy_tx_thld_packets
=
IWL_MVM_PS_HEAVY_TX_THLD_PACKETS
;
cmd
->
heavy_rx_thld_packets
=
IWL_MVM_PS_HEAVY_RX_THLD_PACKETS
;
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
=
...
...
@@ -427,6 +443,32 @@ 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
)
{
struct
iwl_device_power_cmd
cmd
=
{
.
flags
=
cpu_to_le16
(
DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK
),
};
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
)
cmd
.
flags
|=
cpu_to_le16
(
DEVICE_POWER_FLAGS_CAM_MSK
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if
((
mvm
->
cur_ucode
==
IWL_UCODE_WOWLAN
)
?
mvm
->
disable_power_off_d3
:
mvm
->
disable_power_off
)
cmd
.
flags
&=
cpu_to_le16
(
~
DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK
);
#endif
IWL_DEBUG_POWER
(
mvm
,
"Sending device power command with flags = 0x%X
\n
"
,
cmd
.
flags
);
return
iwl_mvm_send_cmd_pdu
(
mvm
,
POWER_TABLE_CMD
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
int
iwl_mvm_power_mac_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
...
...
@@ -437,10 +479,11 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
iwl_mvm_power_build_cmd
(
mvm
,
vif
,
&
cmd
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"disable_power_off = %d
\n
"
,
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_SAVE_ENA_MSK
))
?
0
:
1
);
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD
))
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"disable_power_off = %d
\n
"
,
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_SAVE_ENA_MSK
))
?
0
:
1
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"power_scheme = %d
\n
"
,
iwlmvm_mod_params
.
power_scheme
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"flags = 0x%x
\n
"
,
...
...
@@ -606,6 +649,7 @@ int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
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
,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.
power_dbgfs_read
=
iwl_mvm_power_mac_dbgfs_read
,
...
...
drivers/net/wireless/iwlwifi/mvm/quota.c
View file @
444474dd
...
...
@@ -110,7 +110,8 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
data
->
n_interfaces
[
id
]
++
;
break
;
case
NL80211_IFTYPE_AP
:
if
(
mvmvif
->
ap_active
)
case
NL80211_IFTYPE_ADHOC
:
if
(
mvmvif
->
ap_ibss_active
)
data
->
n_interfaces
[
id
]
++
;
break
;
case
NL80211_IFTYPE_MONITOR
:
...
...
@@ -119,16 +120,45 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
break
;
case
NL80211_IFTYPE_P2P_DEVICE
:
break
;
case
NL80211_IFTYPE_ADHOC
:
if
(
vif
->
bss_conf
.
ibss_joined
)
data
->
n_interfaces
[
id
]
++
;
break
;
default:
WARN_ON_ONCE
(
1
);
break
;
}
}
static
void
iwl_mvm_adjust_quota_for_noa
(
struct
iwl_mvm
*
mvm
,
struct
iwl_time_quota_cmd
*
cmd
)
{
#ifdef CONFIG_NL80211_TESTMODE
struct
iwl_mvm_vif
*
mvmvif
;
int
i
,
phy_id
=
-
1
,
beacon_int
=
0
;
if
(
!
mvm
->
noa_duration
||
!
mvm
->
noa_vif
)
return
;
mvmvif
=
iwl_mvm_vif_from_mac80211
(
mvm
->
noa_vif
);
if
(
!
mvmvif
->
ap_ibss_active
)
return
;
phy_id
=
mvmvif
->
phy_ctxt
->
id
;
beacon_int
=
mvm
->
noa_vif
->
bss_conf
.
beacon_int
;
for
(
i
=
0
;
i
<
MAX_BINDINGS
;
i
++
)
{
u32
id_n_c
=
le32_to_cpu
(
cmd
->
quotas
[
i
].
id_and_color
);
u32
id
=
(
id_n_c
&
FW_CTXT_ID_MSK
)
>>
FW_CTXT_ID_POS
;
u32
quota
=
le32_to_cpu
(
cmd
->
quotas
[
i
].
quota
);
if
(
id
!=
phy_id
)
continue
;
quota
*=
(
beacon_int
-
mvm
->
noa_duration
);
quota
/=
beacon_int
;
cmd
->
quotas
[
i
].
quota
=
cpu_to_le32
(
quota
);
}
#endif
}
int
iwl_mvm_update_quotas
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
newvif
)
{
struct
iwl_time_quota_cmd
cmd
=
{};
...
...
@@ -196,6 +226,8 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
/* Give the remainder of the session to the first binding */
le32_add_cpu
(
&
cmd
.
quotas
[
0
].
quota
,
quota_rem
);
iwl_mvm_adjust_quota_for_noa
(
mvm
,
&
cmd
);
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
TIME_QUOTA_CMD
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
if
(
ret
)
...
...
drivers/net/wireless/iwlwifi/mvm/rs.c
View file @
444474dd
...
...
@@ -82,13 +82,24 @@ static const u8 ant_toggle_lookup[] = {
[
ANT_ABC
]
=
ANT_ABC
,
};
#define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
IWL_RATE_SISO_##s##M_PLCP, \
IWL_RATE_MIMO2_##s##M_PLCP,\
IWL_RATE_##rp##M_INDEX, \
#define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
IWL_RATE_HT_SISO_MCS_##s##_PLCP, \
IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \
IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \
IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP,\
IWL_RATE_##rp##M_INDEX, \
IWL_RATE_##rn##M_INDEX }
#define IWL_DECLARE_MCS_RATE(s) \
[IWL_RATE_MCS_##s##_INDEX] = { IWL_RATE_INVM_PLCP, \
IWL_RATE_HT_SISO_MCS_##s##_PLCP, \
IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \
IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \
IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP, \
IWL_RATE_INVM_INDEX, \
IWL_RATE_INVM_INDEX }
/*
* Parameter order:
* rate, ht rate, prev rate, next rate
...
...
@@ -102,16 +113,17 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
IWL_DECLARE_RATE_INFO
(
2
,
INV
,
1
,
5
),
/* 2mbps */
IWL_DECLARE_RATE_INFO
(
5
,
INV
,
2
,
11
),
/*5.5mbps */
IWL_DECLARE_RATE_INFO
(
11
,
INV
,
9
,
12
),
/* 11mbps */
IWL_DECLARE_RATE_INFO
(
6
,
6
,
5
,
11
),
/* 6mbps */
IWL_DECLARE_RATE_INFO
(
9
,
6
,
6
,
11
),
/* 9mbps */
IWL_DECLARE_RATE_INFO
(
12
,
12
,
11
,
18
),
/* 12mbps */
IWL_DECLARE_RATE_INFO
(
18
,
18
,
12
,
24
),
/* 18mbps */
IWL_DECLARE_RATE_INFO
(
24
,
24
,
18
,
36
),
/* 24mbps */
IWL_DECLARE_RATE_INFO
(
36
,
36
,
24
,
48
),
/* 36mbps */
IWL_DECLARE_RATE_INFO
(
48
,
48
,
36
,
54
),
/* 48mbps */
IWL_DECLARE_RATE_INFO
(
54
,
54
,
48
,
INV
),
/* 54mbps */
IWL_DECLARE_RATE_INFO
(
60
,
60
,
48
,
INV
),
/* 60mbps */
/* FIXME:RS: ^^ should be INV (legacy) */
IWL_DECLARE_RATE_INFO
(
6
,
0
,
5
,
11
),
/* 6mbps ; MCS 0 */
IWL_DECLARE_RATE_INFO
(
9
,
INV
,
6
,
11
),
/* 9mbps */
IWL_DECLARE_RATE_INFO
(
12
,
1
,
11
,
18
),
/* 12mbps ; MCS 1 */
IWL_DECLARE_RATE_INFO
(
18
,
2
,
12
,
24
),
/* 18mbps ; MCS 2 */
IWL_DECLARE_RATE_INFO
(
24
,
3
,
18
,
36
),
/* 24mbps ; MCS 3 */
IWL_DECLARE_RATE_INFO
(
36
,
4
,
24
,
48
),
/* 36mbps ; MCS 4 */
IWL_DECLARE_RATE_INFO
(
48
,
5
,
36
,
54
),
/* 48mbps ; MCS 5 */
IWL_DECLARE_RATE_INFO
(
54
,
6
,
48
,
INV
),
/* 54mbps ; MCS 6 */
IWL_DECLARE_MCS_RATE
(
7
),
/* MCS 7 */
IWL_DECLARE_MCS_RATE
(
8
),
/* MCS 8 */
IWL_DECLARE_MCS_RATE
(
9
),
/* MCS 9 */
};
static
inline
u8
rs_extract_rate
(
u32
rate_n_flags
)
...
...
@@ -124,26 +136,30 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
{
int
idx
=
0
;
/* HT rate format */
if
(
rate_n_flags
&
RATE_MCS_HT_MSK
)
{
idx
=
rs_extract_rate
(
rate_n_flags
);
WARN_ON_ONCE
(
idx
>=
IWL_RATE_MIMO3_6M_PLCP
);
if
(
idx
>=
IWL_RATE_MIMO2_6M_PLCP
)
idx
=
idx
-
IWL_RATE_MIMO2_6M_PLCP
;
idx
=
rate_n_flags
&
RATE_HT_MCS_RATE_CODE_MSK
;
idx
+=
IWL_RATE_MCS_0_INDEX
;
idx
+=
IWL_FIRST_OFDM_RATE
;
/* skip 9M not supported in ht*/
/* skip 9M not supported in HT*/
if
(
idx
>=
IWL_RATE_9M_INDEX
)
idx
+=
1
;
if
((
idx
>=
IWL_FIRST_
OFDM_RATE
)
&&
(
idx
<=
IWL_LAST_OFDM
_RATE
))
if
((
idx
>=
IWL_FIRST_
HT_RATE
)
&&
(
idx
<=
IWL_LAST_HT
_RATE
))
return
idx
;
}
else
if
(
rate_n_flags
&
RATE_MCS_VHT_MSK
)
{
idx
=
rate_n_flags
&
RATE_VHT_MCS_RATE_CODE_MSK
;
idx
+=
IWL_RATE_MCS_0_INDEX
;
/* legacy rate format, search for match in table */
/* skip 9M not supported in VHT*/
if
(
idx
>=
IWL_RATE_9M_INDEX
)
idx
++
;
if
((
idx
>=
IWL_FIRST_VHT_RATE
)
&&
(
idx
<=
IWL_LAST_VHT_RATE
))
return
idx
;
}
else
{
/* legacy rate format, search for match in table */
u8
legacy_rate
=
rs_extract_rate
(
rate_n_flags
);
for
(
idx
=
0
;
idx
<
ARRAY_SIZE
(
iwl_rates
);
idx
++
)
if
(
iwl_rates
[
idx
].
plcp
==
rs_extract_rate
(
rate_n_flags
))
if
(
iwl_rates
[
idx
].
plcp
==
legacy_rate
)
return
idx
;
}
...
...
@@ -155,6 +171,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
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_stay_in_table
(
struct
iwl_lq_sta
*
lq_sta
,
bool
force_search
);
...
...
@@ -180,35 +197,52 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
*/
static
s32
expected_tpt_legacy
[
IWL_RATE_COUNT
]
=
{
7
,
13
,
35
,
58
,
40
,
57
,
72
,
98
,
121
,
154
,
177
,
186
,
0
7
,
13
,
35
,
58
,
40
,
57
,
72
,
98
,
121
,
154
,
177
,
186
,
0
,
0
,
0
};
static
s32
expected_tpt_siso20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
42
,
0
,
76
,
102
,
124
,
159
,
183
,
193
,
202
},
/* Norm */
{
0
,
0
,
0
,
0
,
46
,
0
,
82
,
110
,
132
,
168
,
192
,
202
,
210
},
/* SGI */
{
0
,
0
,
0
,
0
,
47
,
0
,
91
,
133
,
171
,
242
,
305
,
334
,
362
},
/* AGG */
{
0
,
0
,
0
,
0
,
52
,
0
,
101
,
145
,
187
,
264
,
330
,
361
,
390
},
/* AGG+SGI */
/* Expected TpT tables. 4 indexes:
* 0 - NGI, 1 - SGI, 2 - AGG+NGI, 3 - AGG+SGI
*/
static
s32
expected_tpt_siso_20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
42
,
0
,
76
,
102
,
124
,
159
,
183
,
193
,
202
,
216
,
0
},
{
0
,
0
,
0
,
0
,
46
,
0
,
82
,
110
,
132
,
168
,
192
,
202
,
210
,
225
,
0
},
{
0
,
0
,
0
,
0
,
49
,
0
,
97
,
145
,
192
,
285
,
375
,
420
,
464
,
551
,
0
},
{
0
,
0
,
0
,
0
,
54
,
0
,
108
,
160
,
213
,
315
,
415
,
465
,
513
,
608
,
0
},
};
static
s32
expected_tpt_siso40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
77
,
0
,
127
,
160
,
184
,
220
,
242
,
250
,
257
},
/* Norm */
{
0
,
0
,
0
,
0
,
83
,
0
,
135
,
169
,
193
,
229
,
250
,
257
,
264
},
/* SGI */
{
0
,
0
,
0
,
0
,
94
,
0
,
177
,
249
,
313
,
423
,
512
,
550
,
586
},
/* AGG */
{
0
,
0
,
0
,
0
,
104
,
0
,
193
,
270
,
338
,
454
,
545
,
584
,
620
},
/* AGG+SGI */
static
s32
expected_tpt_siso_40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
77
,
0
,
127
,
160
,
184
,
220
,
242
,
250
,
257
,
269
,
275
},
{
0
,
0
,
0
,
0
,
83
,
0
,
135
,
169
,
193
,
229
,
250
,
257
,
264
,
275
,
280
},
{
0
,
0
,
0
,
0
,
101
,
0
,
199
,
295
,
389
,
570
,
744
,
828
,
911
,
1070
,
1173
},
{
0
,
0
,
0
,
0
,
112
,
0
,
220
,
326
,
429
,
629
,
819
,
912
,
1000
,
1173
,
1284
},
};
static
s32
expected_tpt_siso_80MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
130
,
0
,
191
,
223
,
244
,
273
,
288
,
294
,
298
,
305
,
308
},
{
0
,
0
,
0
,
0
,
138
,
0
,
200
,
231
,
251
,
279
,
293
,
298
,
302
,
308
,
312
},
{
0
,
0
,
0
,
0
,
217
,
0
,
429
,
634
,
834
,
1220
,
1585
,
1760
,
1931
,
2258
,
2466
},
{
0
,
0
,
0
,
0
,
241
,
0
,
475
,
701
,
921
,
1343
,
1741
,
1931
,
2117
,
2468
,
2691
},
};
static
s32
expected_tpt_mimo2_20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
74
,
0
,
123
,
155
,
179
,
21
4
,
236
,
244
,
251
},
/* Norm */
{
0
,
0
,
0
,
0
,
81
,
0
,
131
,
164
,
18
8
,
223
,
243
,
251
,
257
},
/* SGI */
{
0
,
0
,
0
,
0
,
89
,
0
,
167
,
235
,
296
,
402
,
488
,
526
,
560
},
/* AGG */
{
0
,
0
,
0
,
0
,
97
,
0
,
182
,
255
,
320
,
431
,
520
,
558
,
593
},
/* AGG+SGI*/
{
0
,
0
,
0
,
0
,
74
,
0
,
123
,
155
,
179
,
21
3
,
235
,
243
,
250
,
261
,
0
},
{
0
,
0
,
0
,
0
,
81
,
0
,
131
,
164
,
18
7
,
221
,
242
,
250
,
256
,
267
,
0
},
{
0
,
0
,
0
,
0
,
98
,
0
,
193
,
286
,
375
,
550
,
718
,
799
,
878
,
1032
,
0
},
{
0
,
0
,
0
,
0
,
109
,
0
,
214
,
316
,
414
,
607
,
790
,
879
,
965
,
1132
,
0
},
};
static
s32
expected_tpt_mimo2_40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
123
,
0
,
182
,
214
,
235
,
264
,
279
,
285
,
289
},
/* Norm */
{
0
,
0
,
0
,
0
,
131
,
0
,
191
,
222
,
242
,
270
,
284
,
289
,
293
},
/* SGI */
{
0
,
0
,
0
,
0
,
171
,
0
,
305
,
410
,
496
,
634
,
731
,
771
,
805
},
/* AGG */
{
0
,
0
,
0
,
0
,
186
,
0
,
329
,
439
,
527
,
667
,
764
,
803
,
838
},
/* AGG+SGI */
{
0
,
0
,
0
,
0
,
123
,
0
,
182
,
214
,
235
,
264
,
279
,
285
,
289
,
296
,
300
},
{
0
,
0
,
0
,
0
,
131
,
0
,
191
,
222
,
242
,
270
,
284
,
289
,
293
,
300
,
303
},
{
0
,
0
,
0
,
0
,
200
,
0
,
390
,
571
,
741
,
1067
,
1365
,
1505
,
1640
,
1894
,
2053
},
{
0
,
0
,
0
,
0
,
221
,
0
,
430
,
630
,
816
,
1169
,
1490
,
1641
,
1784
,
2053
,
2221
},
};
static
s32
expected_tpt_mimo2_80MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
182
,
0
,
240
,
264
,
278
,
299
,
308
,
311
,
313
,
317
,
319
},
{
0
,
0
,
0
,
0
,
190
,
0
,
247
,
269
,
282
,
302
,
310
,
313
,
315
,
319
,
320
},
{
0
,
0
,
0
,
0
,
428
,
0
,
833
,
1215
,
1577
,
2254
,
2863
,
3147
,
3418
,
3913
,
4219
},
{
0
,
0
,
0
,
0
,
474
,
0
,
920
,
1338
,
1732
,
2464
,
3116
,
3418
,
3705
,
4225
,
4545
},
};
/* mbps, mcs */
...
...
@@ -263,7 +297,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
lq_sta
->
lq
.
sta_id
,
lq_sta
->
dbg_fixed_rate
);
if
(
lq_sta
->
dbg_fixed_rate
)
{
rs_fill_link_cmd
(
NULL
,
lq_sta
,
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
,
CMD_ASYNC
,
false
);
}
}
...
...
@@ -275,17 +309,6 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
{
int
ret
=
-
EAGAIN
;
/*
* Don't create TX aggregation sessions when in high
* BT traffic, as they would just be disrupted by BT.
*/
if
(
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
)
>=
2
)
{
IWL_DEBUG_COEX
(
mvm
,
"BT traffic (%d), no aggregation allowed
\n
"
,
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
));
return
ret
;
}
IWL_DEBUG_HT
(
mvm
,
"Starting Tx agg: STA: %pM tid: %d
\n
"
,
sta
->
addr
,
tid
);
ret
=
ieee80211_start_tx_ba_session
(
sta
,
tid
,
5000
);
...
...
@@ -416,49 +439,54 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
*/
/* FIXME:RS:remove this function and put the flags statically in the table */
static
u32
rate_n_flags_from_tbl
(
struct
iwl_mvm
*
mvm
,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
,
u8
use_green
)
struct
iwl_scale_tbl_info
*
tbl
,
int
index
)
{
u32
rate_n_flags
=
0
;
rate_n_flags
|=
((
tbl
->
ant_type
<<
RATE_MCS_ANT_POS
)
&
RATE_MCS_ANT_ABC_MSK
);
if
(
is_legacy
(
tbl
->
lq_type
))
{
rate_n_flags
=
iwl_rates
[
index
].
plcp
;
rate_n_flags
|
=
iwl_rates
[
index
].
plcp
;
if
(
index
>=
IWL_FIRST_CCK_RATE
&&
index
<=
IWL_LAST_CCK_RATE
)
rate_n_flags
|=
RATE_MCS_CCK_MSK
;
}
else
if
(
is_Ht
(
tbl
->
lq_type
))
{
if
(
index
>
IWL_LAST_OFDM_RATE
)
{
return
rate_n_flags
;
}
if
(
is_ht
(
tbl
->
lq_type
))
{
if
(
index
<
IWL_FIRST_HT_RATE
||
index
>
IWL_LAST_HT_RATE
)
{
IWL_ERR
(
mvm
,
"Invalid HT rate index %d
\n
"
,
index
);
index
=
IWL_LAST_
OFDM
_RATE
;
index
=
IWL_LAST_
HT
_RATE
;
}
rate_n_flags
=
RATE_MCS_HT_MSK
;
rate_n_flags
|
=
RATE_MCS_HT_MSK
;
if
(
is_siso
(
tbl
->
lq_type
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_siso
;
else
if
(
is_mimo2
(
tbl
->
lq_type
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_mimo2
;
if
(
is_
ht_
siso
(
tbl
->
lq_type
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_
ht_
siso
;
else
if
(
is_
ht_
mimo2
(
tbl
->
lq_type
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_
ht_
mimo2
;
else
WARN_ON_ONCE
(
1
);
}
else
if
(
is_vht
(
tbl
->
lq_type
))
{
if
(
index
<
IWL_FIRST_VHT_RATE
||
index
>
IWL_LAST_VHT_RATE
)
{
IWL_ERR
(
mvm
,
"Invalid VHT rate index %d
\n
"
,
index
);
index
=
IWL_LAST_VHT_RATE
;
}
rate_n_flags
|=
RATE_MCS_VHT_MSK
;
if
(
is_vht_siso
(
tbl
->
lq_type
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_vht_siso
;
else
if
(
is_vht_mimo2
(
tbl
->
lq_type
))
rate_n_flags
|=
iwl_rates
[
index
].
plcp_vht_mimo2
;
else
WARN_ON_ONCE
(
1
);
}
else
{
IWL_ERR
(
mvm
,
"Invalid tbl->lq_type %d
\n
"
,
tbl
->
lq_type
);
}
rate_n_flags
|=
((
tbl
->
ant_type
<<
RATE_MCS_ANT_POS
)
&
RATE_MCS_ANT_ABC_MSK
);
if
(
is_Ht
(
tbl
->
lq_type
))
{
if
(
tbl
->
is_ht40
)
rate_n_flags
|=
RATE_MCS_CHAN_WIDTH_40
;
if
(
tbl
->
is_SGI
)
rate_n_flags
|=
RATE_MCS_SGI_MSK
;
if
(
use_green
)
{
rate_n_flags
|=
RATE_HT_MCS_GF_MSK
;
if
(
is_siso
(
tbl
->
lq_type
)
&&
tbl
->
is_SGI
)
{
rate_n_flags
&=
~
RATE_MCS_SGI_MSK
;
IWL_ERR
(
mvm
,
"GF was set with SGI:SISO
\n
"
);
}
}
}
rate_n_flags
|=
tbl
->
bw
;
if
(
tbl
->
is_SGI
)
rate_n_flags
|=
RATE_MCS_SGI_MSK
;
return
rate_n_flags
;
}
...
...
@@ -473,7 +501,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
{
u32
ant_msk
=
(
rate_n_flags
&
RATE_MCS_ANT_ABC_MSK
);
u8
num_of_ant
=
get_num_of_ant_from_rate
(
rate_n_flags
);
u8
mc
s
;
u8
ns
s
;
memset
(
tbl
,
0
,
offsetof
(
struct
iwl_scale_tbl_info
,
win
));
*
rate_idx
=
iwl_hwrate_to_plcp_idx
(
rate_n_flags
);
...
...
@@ -483,41 +511,62 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
return
-
EINVAL
;
}
tbl
->
is_SGI
=
0
;
/* default legacy setup */
tbl
->
is_ht40
=
0
;
tbl
->
bw
=
0
;
tbl
->
ant_type
=
(
ant_msk
>>
RATE_MCS_ANT_POS
);
tbl
->
lq_type
=
LQ_NONE
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
/* legacy rate format */
if
(
!
(
rate_n_flags
&
RATE_MCS_HT_MSK
))
{
/* Legacy */
if
(
!
(
rate_n_flags
&
RATE_MCS_HT_MSK
)
&&
!
(
rate_n_flags
&
RATE_MCS_VHT_MSK
))
{
if
(
num_of_ant
==
1
)
{
if
(
band
==
IEEE80211_BAND_5GHZ
)
tbl
->
lq_type
=
LQ_A
;
tbl
->
lq_type
=
LQ_
LEGACY_
A
;
else
tbl
->
lq_type
=
LQ_G
;
tbl
->
lq_type
=
LQ_
LEGACY_
G
;
}
/* HT rate format */
}
else
{
if
(
rate_n_flags
&
RATE_MCS_SGI_MSK
)
tbl
->
is_SGI
=
1
;
if
(
rate_n_flags
&
RATE_MCS_CHAN_WIDTH_40
)
/* TODO */
tbl
->
is_ht40
=
1
;
mcs
=
rs_extract_rate
(
rate_n_flags
);
/* SISO */
if
(
mcs
<=
IWL_RATE_SISO_60M_PLCP
)
{
if
(
num_of_ant
==
1
)
tbl
->
lq_type
=
LQ_SISO
;
/*else NONE*/
/* MIMO2 */
}
else
if
(
mcs
<=
IWL_RATE_MIMO2_60M_PLCP
)
{
if
(
num_of_ant
==
2
)
tbl
->
lq_type
=
LQ_MIMO2
;
return
0
;
}
/* HT or VHT */
if
(
rate_n_flags
&
RATE_MCS_SGI_MSK
)
tbl
->
is_SGI
=
1
;
tbl
->
bw
=
rate_n_flags
&
RATE_MCS_CHAN_WIDTH_MSK
;
if
(
rate_n_flags
&
RATE_MCS_HT_MSK
)
{
nss
=
((
rate_n_flags
&
RATE_HT_MCS_NSS_MSK
)
>>
RATE_HT_MCS_NSS_POS
)
+
1
;
if
(
nss
==
1
)
{
tbl
->
lq_type
=
LQ_HT_SISO
;
WARN_ON_ONCE
(
num_of_ant
!=
1
);
}
else
if
(
nss
==
2
)
{
tbl
->
lq_type
=
LQ_HT_MIMO2
;
WARN_ON_ONCE
(
num_of_ant
!=
2
);
}
else
{
WARN_ON_ONCE
(
1
);
}
}
else
if
(
rate_n_flags
&
RATE_MCS_VHT_MSK
)
{
nss
=
((
rate_n_flags
&
RATE_VHT_MCS_NSS_MSK
)
>>
RATE_VHT_MCS_NSS_POS
)
+
1
;
if
(
nss
==
1
)
{
tbl
->
lq_type
=
LQ_VHT_SISO
;
WARN_ON_ONCE
(
num_of_ant
!=
1
);
}
else
if
(
nss
==
2
)
{
tbl
->
lq_type
=
LQ_VHT_MIMO2
;
WARN_ON_ONCE
(
num_of_ant
!=
2
);
}
else
{
WARN_ON_ONCE
(
num_of_ant
==
3
);
WARN_ON_ONCE
(
1
);
}
}
WARN_ON_ONCE
(
tbl
->
bw
==
RATE_MCS_CHAN_WIDTH_160
);
WARN_ON_ONCE
(
tbl
->
bw
==
RATE_MCS_CHAN_WIDTH_80
&&
!
is_vht
(
tbl
->
lq_type
));
return
0
;
}
...
...
@@ -549,22 +598,6 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
return
1
;
}
/**
* Green-field mode is valid if the station supports it and
* there are no non-GF stations present in the BSS.
*/
static
bool
rs_use_green
(
struct
ieee80211_sta
*
sta
)
{
/*
* There's a bug somewhere in this code that causes the
* scaling to get stuck because GF+SGI can't be combined
* in SISO rates. Until we find that bug, disable GF, it
* has only limited benefit and we still interoperate with
* GF APs since we can always receive GF transmissions.
*/
return
false
;
}
/**
* rs_get_supported_rates - get the available rates
*
...
...
@@ -576,16 +609,15 @@ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
struct
ieee80211_hdr
*
hdr
,
enum
iwl_table_type
rate_type
)
{
if
(
is_legacy
(
rate_type
))
{
if
(
is_legacy
(
rate_type
))
return
lq_sta
->
active_legacy_rate
;
}
else
{
if
(
is_siso
(
rate_type
))
return
lq_sta
->
active_siso_rate
;
else
{
WARN_ON_ONCE
(
!
is_mimo2
(
rate_type
));
return
lq_sta
->
active_mimo2_rate
;
}
}
else
if
(
is_siso
(
rate_type
))
return
lq_sta
->
active_siso_rate
;
else
if
(
is_mimo2
(
rate_type
))
return
lq_sta
->
active_mimo2_rate
;
WARN_ON_ONCE
(
1
);
return
0
;
}
static
u16
rs_get_adjacent_rate
(
struct
iwl_mvm
*
mvm
,
u8
index
,
u16
rate_mask
,
...
...
@@ -652,7 +684,6 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
u16
rate_mask
;
u16
high_low
;
u8
switch_to_legacy
=
0
;
u8
is_green
=
lq_sta
->
is_green
;
struct
iwl_mvm
*
mvm
=
lq_sta
->
drv
;
/* check if we need to switch from HT to legacy rates.
...
...
@@ -662,15 +693,15 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
switch_to_legacy
=
1
;
scale_index
=
rs_ht_to_legacy
[
scale_index
];
if
(
lq_sta
->
band
==
IEEE80211_BAND_5GHZ
)
tbl
->
lq_type
=
LQ_A
;
tbl
->
lq_type
=
LQ_
LEGACY_
A
;
else
tbl
->
lq_type
=
LQ_G
;
tbl
->
lq_type
=
LQ_
LEGACY_
G
;
if
(
num_of_ant
(
tbl
->
ant_type
)
>
1
)
tbl
->
ant_type
=
first_antenna
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
tbl
->
is_ht40
=
0
;
tbl
->
bw
=
0
;
tbl
->
is_SGI
=
0
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
}
...
...
@@ -701,7 +732,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
low
=
scale_index
;
out:
return
rate_n_flags_from_tbl
(
lq_sta
->
drv
,
tbl
,
low
,
is_green
);
return
rate_n_flags_from_tbl
(
lq_sta
->
drv
,
tbl
,
low
);
}
/*
...
...
@@ -714,6 +745,18 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,
(
a
->
is_SGI
==
b
->
is_SGI
);
}
static
u32
rs_ch_width_from_mac_flags
(
enum
mac80211_rate_control_flags
flags
)
{
if
(
flags
&
IEEE80211_TX_RC_40_MHZ_WIDTH
)
return
RATE_MCS_CHAN_WIDTH_40
;
else
if
(
flags
&
IEEE80211_TX_RC_80_MHZ_WIDTH
)
return
RATE_MCS_CHAN_WIDTH_80
;
else
if
(
flags
&
IEEE80211_TX_RC_160_MHZ_WIDTH
)
return
RATE_MCS_CHAN_WIDTH_160
;
return
RATE_MCS_CHAN_WIDTH_20
;
}
/*
* mac80211 sends us Tx status
*/
...
...
@@ -783,16 +826,23 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
*/
if
(
info
->
band
==
IEEE80211_BAND_2GHZ
)
mac_index
+=
IWL_FIRST_OFDM_RATE
;
}
else
if
(
mac_flags
&
IEEE80211_TX_RC_VHT_MCS
)
{
mac_index
&=
RATE_VHT_MCS_RATE_CODE_MSK
;
if
(
mac_index
>=
(
IWL_RATE_9M_INDEX
-
IWL_FIRST_OFDM_RATE
))
mac_index
++
;
}
/* Here we actually compare this rate to the latest LQ command */
if
((
mac_index
<
0
)
||
(
tbl_type
.
is_SGI
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_SHORT_GI
))
||
(
tbl_type
.
is_ht40
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_40_MHZ_WIDTH
))
||
(
tbl_type
.
bw
!=
rs_ch_width_from_mac_flags
(
mac_flags
))
||
(
tbl_type
.
ant_type
!=
info
->
status
.
antenna
)
||
(
!!
(
tx_rate
&
RATE_MCS_HT_MSK
)
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_MCS
))
||
!!
(
mac_flags
&
IEEE80211_TX_RC_MCS
))
||
(
!!
(
tx_rate
&
RATE_MCS_VHT_MSK
)
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_VHT_MCS
))
||
(
!!
(
tx_rate
&
RATE_HT_MCS_GF_MSK
)
!=
!!
(
mac_flags
&
IEEE80211_TX_RC_GREEN_FIELD
))
||
!!
(
mac_flags
&
IEEE80211_TX_RC_GREEN_FIELD
))
||
(
rs_index
!=
mac_index
))
{
IWL_DEBUG_RATE
(
mvm
,
"initial rate %d does not match %d (0x%x)
\n
"
,
...
...
@@ -947,7 +997,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
s32
(
*
ht_tbl_pointer
)[
IWL_RATE_COUNT
];
/* Check for invalid LQ type */
if
(
WARN_ON_ONCE
(
!
is_legacy
(
tbl
->
lq_type
)
&&
!
is_Ht
(
tbl
->
lq_type
)))
{
if
(
WARN_ON_ONCE
(
!
is_legacy
(
tbl
->
lq_type
)
&&
!
is_ht
(
tbl
->
lq_type
)
&&
!
(
is_vht
(
tbl
->
lq_type
))))
{
tbl
->
expected_tpt
=
expected_tpt_legacy
;
return
;
}
...
...
@@ -958,18 +1009,40 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
return
;
}
ht_tbl_pointer
=
expected_tpt_mimo2_20MHz
;
/* Choose among many HT tables depending on number of streams
* (SISO/MIMO2), channel width (20/40), SGI, and aggregation
* (SISO/MIMO2), channel width (20/40
/80
), SGI, and aggregation
* status */
if
(
is_siso
(
tbl
->
lq_type
)
&&
!
tbl
->
is_ht40
)
ht_tbl_pointer
=
expected_tpt_siso20MHz
;
else
if
(
is_siso
(
tbl
->
lq_type
))
ht_tbl_pointer
=
expected_tpt_siso40MHz
;
else
if
(
is_mimo2
(
tbl
->
lq_type
)
&&
!
tbl
->
is_ht40
)
ht_tbl_pointer
=
expected_tpt_mimo2_20MHz
;
else
{
WARN_ON_ONCE
(
!
is_mimo2
(
tbl
->
lq_type
));
ht_tbl_pointer
=
expected_tpt_mimo2_40MHz
;
if
(
is_siso
(
tbl
->
lq_type
))
{
switch
(
tbl
->
bw
)
{
case
RATE_MCS_CHAN_WIDTH_20
:
ht_tbl_pointer
=
expected_tpt_siso_20MHz
;
break
;
case
RATE_MCS_CHAN_WIDTH_40
:
ht_tbl_pointer
=
expected_tpt_siso_40MHz
;
break
;
case
RATE_MCS_CHAN_WIDTH_80
:
ht_tbl_pointer
=
expected_tpt_siso_80MHz
;
break
;
default:
WARN_ON_ONCE
(
1
);
}
}
else
if
(
is_mimo2
(
tbl
->
lq_type
))
{
switch
(
tbl
->
bw
)
{
case
RATE_MCS_CHAN_WIDTH_20
:
ht_tbl_pointer
=
expected_tpt_mimo2_20MHz
;
break
;
case
RATE_MCS_CHAN_WIDTH_40
:
ht_tbl_pointer
=
expected_tpt_mimo2_40MHz
;
break
;
case
RATE_MCS_CHAN_WIDTH_80
:
ht_tbl_pointer
=
expected_tpt_mimo2_80MHz
;
break
;
default:
WARN_ON_ONCE
(
1
);
}
}
else
{
WARN_ON_ONCE
(
1
);
}
if
(
!
tbl
->
is_SGI
&&
!
lq_sta
->
is_agg
)
/* Normal */
...
...
@@ -1084,9 +1157,47 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
return
new_rate
;
}
static
bool
iwl_is_ht40_tx_allowed
(
struct
ieee80211_sta
*
sta
)
/* Move to the next action and wrap around to the first action in case
* we're at the last action. Assumes actions start at 0.
*/
static
inline
void
rs_move_next_action
(
struct
iwl_scale_tbl_info
*
tbl
,
u8
last_action
)
{
BUILD_BUG_ON
(
IWL_LEGACY_FIRST_ACTION
!=
0
);
BUILD_BUG_ON
(
IWL_SISO_FIRST_ACTION
!=
0
);
BUILD_BUG_ON
(
IWL_MIMO2_FIRST_ACTION
!=
0
);
tbl
->
action
=
(
tbl
->
action
+
1
)
%
(
last_action
+
1
);
}
static
void
rs_set_bw_from_sta
(
struct
iwl_scale_tbl_info
*
tbl
,
struct
ieee80211_sta
*
sta
)
{
if
(
sta
->
bandwidth
>=
IEEE80211_STA_RX_BW_80
)
tbl
->
bw
=
RATE_MCS_CHAN_WIDTH_80
;
else
if
(
sta
->
bandwidth
>=
IEEE80211_STA_RX_BW_40
)
tbl
->
bw
=
RATE_MCS_CHAN_WIDTH_40
;
else
tbl
->
bw
=
RATE_MCS_CHAN_WIDTH_20
;
}
static
bool
rs_sgi_allowed
(
struct
iwl_scale_tbl_info
*
tbl
,
struct
ieee80211_sta
*
sta
)
{
return
sta
->
bandwidth
>=
IEEE80211_STA_RX_BW_40
;
struct
ieee80211_sta_ht_cap
*
ht_cap
=
&
sta
->
ht_cap
;
struct
ieee80211_sta_vht_cap
*
vht_cap
=
&
sta
->
vht_cap
;
if
(
is_ht20
(
tbl
)
&&
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_20
))
return
true
;
if
(
is_ht40
(
tbl
)
&&
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_40
))
return
true
;
if
(
is_ht80
(
tbl
)
&&
(
vht_cap
->
cap
&
IEEE80211_VHT_CAP_SHORT_GI_80
))
return
true
;
return
false
;
}
/*
...
...
@@ -1099,7 +1210,6 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
{
u16
rate_mask
;
s32
rate
;
s8
is_green
=
lq_sta
->
is_green
;
if
(
!
sta
->
ht_cap
.
ht_supported
)
return
-
1
;
...
...
@@ -1113,16 +1223,12 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
IWL_DEBUG_RATE
(
mvm
,
"LQ: try to switch to MIMO2
\n
"
);
tbl
->
lq_type
=
LQ
_MIMO2
;
tbl
->
lq_type
=
lq_sta
->
is_vht
?
LQ_VHT_MIMO2
:
LQ_HT
_MIMO2
;
tbl
->
action
=
0
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
rate_mask
=
lq_sta
->
active_mimo2_rate
;
if
(
iwl_is_ht40_tx_allowed
(
sta
))
tbl
->
is_ht40
=
1
;
else
tbl
->
is_ht40
=
0
;
rs_set_bw_from_sta
(
tbl
,
sta
);
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
rate
=
rs_get_best_rate
(
mvm
,
lq_sta
,
tbl
,
rate_mask
,
index
);
...
...
@@ -1134,10 +1240,10 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
rate
,
rate_mask
);
return
-
1
;
}
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate
,
is_green
);
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate
);
IWL_DEBUG_RATE
(
mvm
,
"LQ: Switch to new mcs %X index
is green %X
\n
"
,
tbl
->
current_rate
,
is_green
);
IWL_DEBUG_RATE
(
mvm
,
"LQ: Switch to new mcs %X index
\n
"
,
tbl
->
current_rate
);
return
0
;
}
...
...
@@ -1150,7 +1256,6 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
)
{
u16
rate_mask
;
u8
is_green
=
lq_sta
->
is_green
;
s32
rate
;
if
(
!
sta
->
ht_cap
.
ht_supported
)
...
...
@@ -1158,19 +1263,12 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm,
IWL_DEBUG_RATE
(
mvm
,
"LQ: try to switch to SISO
\n
"
);
tbl
->
lq_type
=
LQ
_SISO
;
tbl
->
lq_type
=
lq_sta
->
is_vht
?
LQ_VHT_SISO
:
LQ_HT
_SISO
;
tbl
->
action
=
0
;
tbl
->
max_search
=
IWL_MAX_SEARCH
;
rate_mask
=
lq_sta
->
active_siso_rate
;
if
(
iwl_is_ht40_tx_allowed
(
sta
))
tbl
->
is_ht40
=
1
;
else
tbl
->
is_ht40
=
0
;
if
(
is_green
)
tbl
->
is_SGI
=
0
;
/*11n spec: no SGI in SISO+Greenfield*/
rs_set_bw_from_sta
(
tbl
,
sta
);
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
rate
=
rs_get_best_rate
(
mvm
,
lq_sta
,
tbl
,
rate_mask
,
index
);
...
...
@@ -1181,9 +1279,9 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm,
rate
,
rate_mask
);
return
-
1
;
}
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate
,
is_green
);
IWL_DEBUG_RATE
(
mvm
,
"LQ: Switch to new mcs %X index
is green %X
\n
"
,
tbl
->
current_rate
,
is_green
);
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate
);
IWL_DEBUG_RATE
(
mvm
,
"LQ: Switch to new mcs %X index
\n
"
,
tbl
->
current_rate
);
return
0
;
}
...
...
@@ -1211,14 +1309,10 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,
while
(
1
)
{
lq_sta
->
action_counter
++
;
switch
(
tbl
->
action
)
{
case
IWL_LEGACY_SWITCH_ANTENNA1
:
case
IWL_LEGACY_SWITCH_ANTENNA2
:
case
IWL_LEGACY_SWITCH_ANTENNA
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: Legacy toggle Antenna
\n
"
);
if
((
tbl
->
action
==
IWL_LEGACY_SWITCH_ANTENNA1
&&
tx_chains_num
<=
1
)
||
(
tbl
->
action
==
IWL_LEGACY_SWITCH_ANTENNA2
&&
tx_chains_num
<=
2
))
if
(
tx_chains_num
<=
1
)
break
;
/* Don't change antenna if success has been great */
...
...
@@ -1273,9 +1367,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,
default:
WARN_ON_ONCE
(
1
);
}
tbl
->
action
++
;
if
(
tbl
->
action
>
IWL_LEGACY_SWITCH_MIMO2
)
tbl
->
action
=
IWL_LEGACY_SWITCH_ANTENNA1
;
rs_move_next_action
(
tbl
,
IWL_LEGACY_LAST_ACTION
);
if
(
tbl
->
action
==
start_action
)
break
;
...
...
@@ -1285,9 +1377,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,
out:
lq_sta
->
search_better_tbl
=
1
;
tbl
->
action
++
;
if
(
tbl
->
action
>
IWL_LEGACY_SWITCH_MIMO2
)
tbl
->
action
=
IWL_LEGACY_SWITCH_ANTENNA1
;
rs_move_next_action
(
tbl
,
IWL_LEGACY_LAST_ACTION
);
if
(
update_search_tbl_counter
)
search_tbl
->
action
=
tbl
->
action
;
return
0
;
...
...
@@ -1300,12 +1390,10 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
int
index
)
{
u8
is_green
=
lq_sta
->
is_green
;
struct
iwl_scale_tbl_info
*
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
struct
iwl_scale_tbl_info
*
search_tbl
=
&
(
lq_sta
->
lq_info
[(
1
-
lq_sta
->
active_tbl
)]);
struct
iwl_rate_scale_data
*
window
=
&
(
tbl
->
win
[
index
]);
struct
ieee80211_sta_ht_cap
*
ht_cap
=
&
sta
->
ht_cap
;
u32
sz
=
(
sizeof
(
struct
iwl_scale_tbl_info
)
-
(
sizeof
(
struct
iwl_rate_scale_data
)
*
IWL_RATE_COUNT
));
u8
start_action
;
...
...
@@ -1314,40 +1402,17 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
u8
update_search_tbl_counter
=
0
;
int
ret
;
switch
(
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
))
{
case
IWL_BT_COEX_TRAFFIC_LOAD_NONE
:
/* nothing */
break
;
case
IWL_BT_COEX_TRAFFIC_LOAD_LOW
:
/* avoid antenna B unless MIMO */
if
(
tbl
->
action
==
IWL_SISO_SWITCH_ANTENNA2
)
tbl
->
action
=
IWL_SISO_SWITCH_MIMO2
;
break
;
case
IWL_BT_COEX_TRAFFIC_LOAD_HIGH
:
case
IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS
:
/* avoid antenna B and MIMO */
valid_tx_ant
=
first_antenna
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
));
if
(
tbl
->
action
!=
IWL_SISO_SWITCH_ANTENNA1
)
tbl
->
action
=
IWL_SISO_SWITCH_ANTENNA1
;
break
;
default:
IWL_ERR
(
mvm
,
"Invalid BT load %d"
,
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
));
break
;
}
if
(
tbl
->
action
==
IWL_SISO_SWITCH_MIMO2
&&
!
iwl_mvm_bt_coex_is_mimo_allowed
(
mvm
,
sta
))
tbl
->
action
=
IWL_SISO_SWITCH_ANTENNA
;
start_action
=
tbl
->
action
;
while
(
1
)
{
lq_sta
->
action_counter
++
;
switch
(
tbl
->
action
)
{
case
IWL_SISO_SWITCH_ANTENNA1
:
case
IWL_SISO_SWITCH_ANTENNA2
:
case
IWL_SISO_SWITCH_ANTENNA
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: SISO toggle Antenna
\n
"
);
if
((
tbl
->
action
==
IWL_SISO_SWITCH_ANTENNA1
&&
tx_chains_num
<=
1
)
||
(
tbl
->
action
==
IWL_SISO_SWITCH_ANTENNA2
&&
tx_chains_num
<=
2
))
if
(
tx_chains_num
<=
1
)
break
;
if
(
window
->
success_ratio
>=
IWL_RS_GOOD_RATIO
&&
...
...
@@ -1380,23 +1445,12 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
goto
out
;
break
;
case
IWL_SISO_SWITCH_GI
:
if
(
!
tbl
->
is_ht40
&&
!
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_20
))
break
;
if
(
tbl
->
is_ht40
&&
!
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_40
))
if
(
!
rs_sgi_allowed
(
tbl
,
sta
))
break
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: SISO toggle SGI/NGI
\n
"
);
memcpy
(
search_tbl
,
tbl
,
sz
);
if
(
is_green
)
{
if
(
!
tbl
->
is_SGI
)
break
;
else
IWL_ERR
(
mvm
,
"SGI was set in GF+SISO
\n
"
);
}
search_tbl
->
is_SGI
=
!
tbl
->
is_SGI
;
rs_set_expected_tpt_table
(
lq_sta
,
search_tbl
);
if
(
tbl
->
is_SGI
)
{
...
...
@@ -1405,16 +1459,13 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
break
;
}
search_tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
search_tbl
,
index
,
is_green
);
rate_n_flags_from_tbl
(
mvm
,
search_tbl
,
index
);
update_search_tbl_counter
=
1
;
goto
out
;
default:
WARN_ON_ONCE
(
1
);
}
tbl
->
action
++
;
if
(
tbl
->
action
>
IWL_SISO_SWITCH_GI
)
tbl
->
action
=
IWL_SISO_SWITCH_ANTENNA1
;
rs_move_next_action
(
tbl
,
IWL_SISO_LAST_ACTION
);
if
(
tbl
->
action
==
start_action
)
break
;
...
...
@@ -1424,9 +1475,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
out:
lq_sta
->
search_better_tbl
=
1
;
tbl
->
action
++
;
if
(
tbl
->
action
>
IWL_SISO_SWITCH_GI
)
tbl
->
action
=
IWL_SISO_SWITCH_ANTENNA1
;
rs_move_next_action
(
tbl
,
IWL_SISO_LAST_ACTION
);
if
(
update_search_tbl_counter
)
search_tbl
->
action
=
tbl
->
action
;
...
...
@@ -1440,63 +1489,20 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
struct
iwl_lq_sta
*
lq_sta
,
struct
ieee80211_sta
*
sta
,
int
index
)
{
s8
is_green
=
lq_sta
->
is_green
;
struct
iwl_scale_tbl_info
*
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
struct
iwl_scale_tbl_info
*
search_tbl
=
&
(
lq_sta
->
lq_info
[(
1
-
lq_sta
->
active_tbl
)]);
struct
iwl_rate_scale_data
*
window
=
&
(
tbl
->
win
[
index
]);
struct
ieee80211_sta_ht_cap
*
ht_cap
=
&
sta
->
ht_cap
;
u32
sz
=
(
sizeof
(
struct
iwl_scale_tbl_info
)
-
(
sizeof
(
struct
iwl_rate_scale_data
)
*
IWL_RATE_COUNT
));
u8
start_action
;
u8
valid_tx_ant
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
u8
tx_chains_num
=
num_of_ant
(
valid_tx_ant
);
u8
update_search_tbl_counter
=
0
;
int
ret
;
switch
(
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
))
{
case
IWL_BT_COEX_TRAFFIC_LOAD_NONE
:
/* nothing */
break
;
case
IWL_BT_COEX_TRAFFIC_LOAD_HIGH
:
case
IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS
:
/* avoid antenna B and MIMO */
if
(
tbl
->
action
!=
IWL_MIMO2_SWITCH_SISO_A
)
tbl
->
action
=
IWL_MIMO2_SWITCH_SISO_A
;
break
;
case
IWL_BT_COEX_TRAFFIC_LOAD_LOW
:
/* avoid antenna B unless MIMO */
if
(
tbl
->
action
==
IWL_MIMO2_SWITCH_SISO_B
)
tbl
->
action
=
IWL_MIMO2_SWITCH_SISO_A
;
break
;
default:
IWL_ERR
(
mvm
,
"Invalid BT load %d"
,
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
));
break
;
}
start_action
=
tbl
->
action
;
while
(
1
)
{
lq_sta
->
action_counter
++
;
switch
(
tbl
->
action
)
{
case
IWL_MIMO2_SWITCH_ANTENNA1
:
case
IWL_MIMO2_SWITCH_ANTENNA2
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: MIMO2 toggle Antennas
\n
"
);
if
(
tx_chains_num
<=
2
)
break
;
if
(
window
->
success_ratio
>=
IWL_RS_GOOD_RATIO
)
break
;
memcpy
(
search_tbl
,
tbl
,
sz
);
if
(
rs_toggle_antenna
(
valid_tx_ant
,
&
search_tbl
->
current_rate
,
search_tbl
))
{
update_search_tbl_counter
=
1
;
goto
out
;
}
break
;
case
IWL_MIMO2_SWITCH_SISO_A
:
case
IWL_MIMO2_SWITCH_SISO_B
:
IWL_DEBUG_RATE
(
mvm
,
"LQ: MIMO2 switch to SISO
\n
"
);
...
...
@@ -1521,11 +1527,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
break
;
case
IWL_MIMO2_SWITCH_GI
:
if
(
!
tbl
->
is_ht40
&&
!
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_20
))
break
;
if
(
tbl
->
is_ht40
&&
!
(
ht_cap
->
cap
&
IEEE80211_HT_CAP_SGI_40
))
if
(
!
rs_sgi_allowed
(
tbl
,
sta
))
break
;
IWL_DEBUG_RATE
(
mvm
,
"LQ: MIMO2 toggle SGI/NGI
\n
"
);
...
...
@@ -1546,16 +1548,13 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
break
;
}
search_tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
search_tbl
,
index
,
is_green
);
rate_n_flags_from_tbl
(
mvm
,
search_tbl
,
index
);
update_search_tbl_counter
=
1
;
goto
out
;
default:
WARN_ON_ONCE
(
1
);
}
tbl
->
action
++
;
if
(
tbl
->
action
>
IWL_MIMO2_SWITCH_GI
)
tbl
->
action
=
IWL_MIMO2_SWITCH_ANTENNA1
;
rs_move_next_action
(
tbl
,
IWL_MIMO2_LAST_ACTION
);
if
(
tbl
->
action
==
start_action
)
break
;
...
...
@@ -1564,9 +1563,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
return
0
;
out:
lq_sta
->
search_better_tbl
=
1
;
tbl
->
action
++
;
if
(
tbl
->
action
>
IWL_MIMO2_SWITCH_GI
)
tbl
->
action
=
IWL_MIMO2_SWITCH_ANTENNA1
;
rs_move_next_action
(
tbl
,
IWL_MIMO2_LAST_ACTION
);
if
(
update_search_tbl_counter
)
search_tbl
->
action
=
tbl
->
action
;
...
...
@@ -1660,15 +1657,16 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
* setup rate table in uCode
*/
static
void
rs_update_rate_tbl
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
struct
iwl_scale_tbl_info
*
tbl
,
int
index
,
u8
is_green
)
int
index
)
{
u32
rate
;
/* Update uCode's rate table. */
rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
index
,
is_green
);
rs_fill_link_cmd
(
mvm
,
lq_sta
,
rate
);
rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
index
);
rs_fill_link_cmd
(
mvm
,
sta
,
lq_sta
,
rate
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
CMD_ASYNC
,
false
);
}
...
...
@@ -1712,7 +1710,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
u8
update_lq
=
0
;
struct
iwl_scale_tbl_info
*
tbl
,
*
tbl1
;
u16
rate_scale_index_msk
=
0
;
u8
is_green
=
0
;
u8
active_tbl
=
0
;
u8
done_search
=
0
;
u16
high_low
;
...
...
@@ -1754,11 +1751,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
active_tbl
=
1
-
lq_sta
->
active_tbl
;
tbl
=
&
(
lq_sta
->
lq_info
[
active_tbl
]);
if
(
is_legacy
(
tbl
->
lq_type
))
lq_sta
->
is_green
=
0
;
else
lq_sta
->
is_green
=
rs_use_green
(
sta
);
is_green
=
lq_sta
->
is_green
;
/* current tx rate */
index
=
lq_sta
->
last_txrate_idx
;
...
...
@@ -1797,7 +1789,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
/* get "active" rate info */
index
=
iwl_hwrate_to_plcp_idx
(
tbl
->
current_rate
);
rs_update_rate_tbl
(
mvm
,
lq_sta
,
tbl
,
index
,
is_green
);
rs_update_rate_tbl
(
mvm
,
sta
,
lq_sta
,
tbl
,
index
);
}
return
;
}
...
...
@@ -1978,24 +1970,24 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
(
current_tpt
>
(
100
*
tbl
->
expected_tpt
[
low
]))))
scale_action
=
0
;
if
((
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
)
>=
if
((
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
>=
IWL_BT_COEX_TRAFFIC_LOAD_HIGH
)
&&
(
is_mimo
(
tbl
->
lq_type
)))
{
if
(
lq_sta
->
last_bt_traffic
>
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
))
{
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
))
{
/*
* don't set scale_action, don't want to scale up if
* the rate scale doesn't otherwise think that is a
* good idea.
*/
}
else
if
(
lq_sta
->
last_bt_traffic
<=
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
))
{
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
))
{
scale_action
=
-
1
;
}
}
lq_sta
->
last_bt_traffic
=
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
);
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
);
if
((
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
)
>=
if
((
le32_to_cpu
(
mvm
->
last_bt_notif
.
bt_activity_grading
)
>=
IWL_BT_COEX_TRAFFIC_LOAD_HIGH
)
&&
is_mimo
(
tbl
->
lq_type
))
{
/* search for a new modulation */
rs_stay_in_table
(
lq_sta
,
true
);
...
...
@@ -2032,7 +2024,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
lq_update:
/* Replace uCode's rate table for the destination station. */
if
(
update_lq
)
rs_update_rate_tbl
(
mvm
,
lq_sta
,
tbl
,
index
,
is_green
);
rs_update_rate_tbl
(
mvm
,
sta
,
lq_sta
,
tbl
,
index
);
rs_stay_in_table
(
lq_sta
,
false
);
...
...
@@ -2071,7 +2063,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
IWL_DEBUG_RATE
(
mvm
,
"Switch current mcs: %X index: %d
\n
"
,
tbl
->
current_rate
,
index
);
rs_fill_link_cmd
(
mvm
,
lq_sta
,
tbl
->
current_rate
);
rs_fill_link_cmd
(
mvm
,
sta
,
lq_sta
,
tbl
->
current_rate
);
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
CMD_ASYNC
,
false
);
}
else
{
done_search
=
1
;
...
...
@@ -2113,7 +2105,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
out:
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
index
,
is_green
);
tbl
->
current_rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
index
);
lq_sta
->
last_txrate_idx
=
index
;
}
...
...
@@ -2140,7 +2132,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
int
rate_idx
;
int
i
;
u32
rate
;
u8
use_green
=
rs_use_green
(
sta
);
u8
active_tbl
=
0
;
u8
valid_tx_ant
;
...
...
@@ -2172,10 +2163,10 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
if
(
!
rs_is_valid_ant
(
valid_tx_ant
,
tbl
->
ant_type
))
rs_toggle_antenna
(
valid_tx_ant
,
&
rate
,
tbl
);
rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate_idx
,
use_green
);
rate
=
rate_n_flags_from_tbl
(
mvm
,
tbl
,
rate_idx
);
tbl
->
current_rate
=
rate
;
rs_set_expected_tpt_table
(
lq_sta
,
tbl
);
rs_fill_link_cmd
(
NULL
,
lq_sta
,
rate
);
rs_fill_link_cmd
(
NULL
,
NULL
,
lq_sta
,
rate
);
/* TODO restore station should remember the lq cmd */
iwl_mvm_send_lq_cmd
(
mvm
,
&
lq_sta
->
lq
,
CMD_SYNC
,
true
);
}
...
...
@@ -2190,7 +2181,6 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
struct
iwl_mvm
*
mvm
__maybe_unused
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
struct
ieee80211_tx_info
*
info
=
IEEE80211_SKB_CB
(
skb
);
struct
iwl_lq_sta
*
lq_sta
=
mvm_sta
;
int
rate_idx
;
IWL_DEBUG_RATE_LIMIT
(
mvm
,
"rate scale calculate new rate for skb
\n
"
);
...
...
@@ -2215,36 +2205,9 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
if
(
rate_control_send_low
(
sta
,
mvm_sta
,
txrc
))
return
;
rate_idx
=
lq_sta
->
last_txrate_idx
;
if
(
lq_sta
->
last_rate_n_flags
&
RATE_MCS_HT_MSK
)
{
rate_idx
-=
IWL_FIRST_OFDM_RATE
;
/* 6M and 9M shared same MCS index */
rate_idx
=
(
rate_idx
>
0
)
?
(
rate_idx
-
1
)
:
0
;
WARN_ON_ONCE
(
rs_extract_rate
(
lq_sta
->
last_rate_n_flags
)
>=
IWL_RATE_MIMO3_6M_PLCP
);
if
(
rs_extract_rate
(
lq_sta
->
last_rate_n_flags
)
>=
IWL_RATE_MIMO2_6M_PLCP
)
rate_idx
=
rate_idx
+
MCS_INDEX_PER_STREAM
;
info
->
control
.
rates
[
0
].
flags
=
IEEE80211_TX_RC_MCS
;
if
(
lq_sta
->
last_rate_n_flags
&
RATE_MCS_SGI_MSK
)
info
->
control
.
rates
[
0
].
flags
|=
IEEE80211_TX_RC_SHORT_GI
;
if
(
lq_sta
->
last_rate_n_flags
&
RATE_MCS_CHAN_WIDTH_40
)
/* TODO */
info
->
control
.
rates
[
0
].
flags
|=
IEEE80211_TX_RC_40_MHZ_WIDTH
;
if
(
lq_sta
->
last_rate_n_flags
&
RATE_HT_MCS_GF_MSK
)
info
->
control
.
rates
[
0
].
flags
|=
IEEE80211_TX_RC_GREEN_FIELD
;
}
else
{
/* Check for invalid rates */
if
((
rate_idx
<
0
)
||
(
rate_idx
>=
IWL_RATE_COUNT_LEGACY
)
||
((
sband
->
band
==
IEEE80211_BAND_5GHZ
)
&&
(
rate_idx
<
IWL_FIRST_OFDM_RATE
)))
rate_idx
=
rate_lowest_index
(
sband
,
sta
);
/* On valid 5 GHz rate, adjust index */
else
if
(
sband
->
band
==
IEEE80211_BAND_5GHZ
)
rate_idx
-=
IWL_FIRST_OFDM_RATE
;
info
->
control
.
rates
[
0
].
flags
=
0
;
}
info
->
control
.
rates
[
0
].
idx
=
rate_idx
;
iwl_mvm_hwrate_to_tx_rate
(
lq_sta
->
last_rate_n_flags
,
info
->
band
,
&
info
->
control
.
rates
[
0
]);
info
->
control
.
rates
[
0
].
count
=
1
;
}
...
...
@@ -2261,6 +2224,24 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
return
&
sta_priv
->
lq_sta
;
}
static
int
rs_vht_highest_rx_mcs_index
(
struct
ieee80211_sta_vht_cap
*
vht_cap
,
int
nss
)
{
u16
rx_mcs
=
le16_to_cpu
(
vht_cap
->
vht_mcs
.
rx_mcs_map
)
&
(
0x3
<<
(
2
*
(
nss
-
1
)));
rx_mcs
>>=
(
2
*
(
nss
-
1
));
if
(
rx_mcs
==
IEEE80211_VHT_MCS_SUPPORT_0_7
)
return
IWL_RATE_MCS_7_INDEX
;
else
if
(
rx_mcs
==
IEEE80211_VHT_MCS_SUPPORT_0_8
)
return
IWL_RATE_MCS_8_INDEX
;
else
if
(
rx_mcs
==
IEEE80211_VHT_MCS_SUPPORT_0_9
)
return
IWL_RATE_MCS_9_INDEX
;
WARN_ON_ONCE
(
rx_mcs
!=
IEEE80211_VHT_MCS_NOT_SUPPORTED
);
return
-
1
;
}
/*
* Called after adding a new station to initialize rate scaling
*/
...
...
@@ -2270,6 +2251,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int
i
,
j
;
struct
ieee80211_hw
*
hw
=
mvm
->
hw
;
struct
ieee80211_sta_ht_cap
*
ht_cap
=
&
sta
->
ht_cap
;
struct
ieee80211_sta_vht_cap
*
vht_cap
=
&
sta
->
vht_cap
;
struct
iwl_mvm_sta
*
sta_priv
;
struct
iwl_lq_sta
*
lq_sta
;
struct
ieee80211_supported_band
*
sband
;
...
...
@@ -2298,7 +2280,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta
->
max_rate_idx
=
-
1
;
lq_sta
->
missed_rate_counter
=
IWL_MISSED_RATE_MAX
;
lq_sta
->
is_green
=
rs_use_green
(
sta
);
lq_sta
->
band
=
sband
->
band
;
/*
* active legacy rates as per supported rates bitmap
...
...
@@ -2308,25 +2289,54 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
for_each_set_bit
(
i
,
&
supp
,
BITS_PER_LONG
)
lq_sta
->
active_legacy_rate
|=
BIT
(
sband
->
bitrates
[
i
].
hw_value
);
/*
* active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
* supp_rates[] does not; shift to convert format, force 9 MBits off.
*/
lq_sta
->
active_siso_rate
=
ht_cap
->
mcs
.
rx_mask
[
0
]
<<
1
;
lq_sta
->
active_siso_rate
|=
ht_cap
->
mcs
.
rx_mask
[
0
]
&
0x1
;
lq_sta
->
active_siso_rate
&=
~
((
u16
)
0x2
);
lq_sta
->
active_siso_rate
<<=
IWL_FIRST_OFDM_RATE
;
/* TODO: should probably account for rx_highest for both HT/VHT */
if
(
!
vht_cap
||
!
vht_cap
->
vht_supported
)
{
/* active_siso_rate mask includes 9 MBits (bit 5),
* and CCK (bits 0-3), supp_rates[] does not;
* shift to convert format, force 9 MBits off.
*/
lq_sta
->
active_siso_rate
=
ht_cap
->
mcs
.
rx_mask
[
0
]
<<
1
;
lq_sta
->
active_siso_rate
|=
ht_cap
->
mcs
.
rx_mask
[
0
]
&
0x1
;
lq_sta
->
active_siso_rate
&=
~
((
u16
)
0x2
);
lq_sta
->
active_siso_rate
<<=
IWL_FIRST_OFDM_RATE
;
/* Same here */
lq_sta
->
active_mimo2_rate
=
ht_cap
->
mcs
.
rx_mask
[
1
]
<<
1
;
lq_sta
->
active_mimo2_rate
|=
ht_cap
->
mcs
.
rx_mask
[
1
]
&
0x1
;
lq_sta
->
active_mimo2_rate
&=
~
((
u16
)
0x2
);
lq_sta
->
active_mimo2_rate
<<=
IWL_FIRST_OFDM_RATE
;
lq_sta
->
is_vht
=
false
;
}
else
{
int
highest_mcs
=
rs_vht_highest_rx_mcs_index
(
vht_cap
,
1
);
if
(
highest_mcs
>=
IWL_RATE_MCS_0_INDEX
)
{
for
(
i
=
IWL_RATE_MCS_0_INDEX
;
i
<=
highest_mcs
;
i
++
)
{
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
lq_sta
->
active_siso_rate
|=
BIT
(
i
);
}
}
highest_mcs
=
rs_vht_highest_rx_mcs_index
(
vht_cap
,
2
);
if
(
highest_mcs
>=
IWL_RATE_MCS_0_INDEX
)
{
for
(
i
=
IWL_RATE_MCS_0_INDEX
;
i
<=
highest_mcs
;
i
++
)
{
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* Same here */
lq_sta
->
active_mimo2_rate
=
ht_cap
->
mcs
.
rx_mask
[
1
]
<<
1
;
lq_sta
->
active_mimo2_rate
|=
ht_cap
->
mcs
.
rx_mask
[
1
]
&
0x1
;
lq_sta
->
active_mimo2_rate
&=
~
((
u16
)
0x2
);
lq_sta
->
active_mimo2_rate
<<=
IWL_FIRST_OFDM_RATE
;
lq_sta
->
active_mimo2_rate
|=
BIT
(
i
);
}
}
/* TODO: avoid MCS9 in 20Mhz which isn't valid for 11ac */
lq_sta
->
is_vht
=
true
;
}
IWL_DEBUG_RATE
(
mvm
,
"SISO-RATE=%X MIMO2-RATE=%X
\n
"
,
"SISO-RATE=%X MIMO2-RATE=%X
VHT=%d
\n
"
,
lq_sta
->
active_siso_rate
,
lq_sta
->
active_mimo2_rate
);
lq_sta
->
active_mimo2_rate
,
lq_sta
->
is_vht
);
/* These values will be overridden later */
lq_sta
->
lq
.
single_stream_ant_msk
=
...
...
@@ -2358,6 +2368,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
static
void
rs_fill_link_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
struct
iwl_lq_sta
*
lq_sta
,
u32
new_rate
)
{
struct
iwl_scale_tbl_info
tbl_type
;
...
...
@@ -2429,7 +2440,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
rs_get_tbl_info_from_mcs
(
new_rate
,
lq_sta
->
band
,
&
tbl_type
,
&
rate_idx
);
/* 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. */
...
...
@@ -2455,7 +2465,9 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
}
/* Don't allow HT rates after next pass.
* rs_get_lower_rate() will change type to LQ_A or LQ_G. */
* rs_get_lower_rate() will change type to LQ_LEGACY_A
* or LQ_LEGACY_G.
*/
use_ht_possible
=
0
;
/* Override next rate if needed for debug purposes */
...
...
@@ -2474,12 +2486,9 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
lq_cmd
->
agg_time_limit
=
cpu_to_le16
(
LINK_QUAL_AGG_TIME_LIMIT_DEF
);
/*
* overwrite if needed, pass aggregation time limit
* to uCode in uSec - This is racy - but heh, at least it helps...
*/
if
(
mvm
&&
BT_MBOX_MSG
(
&
mvm
->
last_bt_notif
,
3
,
TRAFFIC_LOAD
)
>=
2
)
lq_cmd
->
agg_time_limit
=
cpu_to_le16
(
1200
);
if
(
sta
)
lq_cmd
->
agg_time_limit
=
cpu_to_le16
(
iwl_mvm_bt_coex_agg_time_limit
(
mvm
,
sta
));
}
static
void
*
rs_alloc
(
struct
ieee80211_hw
*
hw
,
struct
dentry
*
debugfsdir
)
...
...
@@ -2586,16 +2595,18 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
)
&
ANT_B
)
?
"ANT_B,"
:
""
,
(
iwl_fw_valid_tx_ant
(
mvm
->
fw
)
&
ANT_C
)
?
"ANT_C"
:
""
);
desc
+=
sprintf
(
buff
+
desc
,
"lq type %s
\n
"
,
(
is_legacy
(
tbl
->
lq_type
))
?
"legacy"
:
"HT"
);
if
(
is_Ht
(
tbl
->
lq_type
))
{
(
is_legacy
(
tbl
->
lq_type
))
?
"legacy"
:
is_vht
(
tbl
->
lq_type
)
?
"VHT"
:
"HT"
);
if
(
is_ht
(
tbl
->
lq_type
))
{
desc
+=
sprintf
(
buff
+
desc
,
" %s"
,
(
is_siso
(
tbl
->
lq_type
))
?
"SISO"
:
"MIMO2"
);
desc
+=
sprintf
(
buff
+
desc
,
" %s"
,
(
tbl
->
is_ht40
)
?
"40MHz"
:
"20MHz"
);
desc
+=
sprintf
(
buff
+
desc
,
" %s %s %s
\n
"
,
(
is_ht20
(
tbl
))
?
"20MHz"
:
(
is_ht40
(
tbl
))
?
"40MHz"
:
(
is_ht80
(
tbl
))
?
"80Mhz"
:
"BAD BW"
);
desc
+=
sprintf
(
buff
+
desc
,
" %s %s
\n
"
,
(
tbl
->
is_SGI
)
?
"SGI"
:
""
,
(
lq_sta
->
is_green
)
?
"GF enabled"
:
""
,
(
lq_sta
->
is_agg
)
?
"AGG on"
:
""
);
(
lq_sta
->
is_agg
)
?
"AGG on"
:
""
);
}
desc
+=
sprintf
(
buff
+
desc
,
"last tx rate=0x%X
\n
"
,
lq_sta
->
last_rate_n_flags
);
...
...
@@ -2653,7 +2664,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
int
desc
=
0
;
int
i
,
j
;
ssize_t
ret
;
struct
iwl_scale_tbl_info
*
tbl
;
struct
iwl_lq_sta
*
lq_sta
=
file
->
private_data
;
buff
=
kmalloc
(
1024
,
GFP_KERNEL
);
...
...
@@ -2661,21 +2672,23 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
LQ_SIZE
;
i
++
)
{
tbl
=
&
(
lq_sta
->
lq_info
[
i
]);
desc
+=
sprintf
(
buff
+
desc
,
"%s type=%d SGI=%d
HT40=%d DUP=0 GF=%d
\n
"
"%s type=%d SGI=%d
BW=%s DUP=0
\n
"
"rate=0x%X
\n
"
,
lq_sta
->
active_tbl
==
i
?
"*"
:
"x"
,
lq_sta
->
lq_info
[
i
].
lq_type
,
lq_sta
->
lq_info
[
i
].
is_SGI
,
lq_sta
->
lq_info
[
i
].
is_ht40
,
lq_sta
->
is_green
,
lq_sta
->
lq_info
[
i
].
current_rate
);
tbl
->
lq_type
,
tbl
->
is_SGI
,
is_ht20
(
tbl
)
?
"20Mhz"
:
is_ht40
(
tbl
)
?
"40Mhz"
:
is_ht80
(
tbl
)
?
"80Mhz"
:
"ERR"
,
tbl
->
current_rate
);
for
(
j
=
0
;
j
<
IWL_RATE_COUNT
;
j
++
)
{
desc
+=
sprintf
(
buff
+
desc
,
"counter=%d success=%d %%=%d
\n
"
,
lq_sta
->
lq_info
[
i
].
win
[
j
].
counter
,
lq_sta
->
lq_info
[
i
].
win
[
j
].
success_counter
,
lq_sta
->
lq_info
[
i
].
win
[
j
].
success_ratio
);
tbl
->
win
[
j
].
counter
,
tbl
->
win
[
j
].
success_counter
,
tbl
->
win
[
j
].
success_ratio
);
}
}
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buff
,
desc
);
...
...
drivers/net/wireless/iwlwifi/mvm/rs.h
View file @
444474dd
...
...
@@ -35,9 +35,11 @@
#include "iwl-trans.h"
struct
iwl_rs_rate_info
{
u8
plcp
;
/* uCode API: IWL_RATE_6M_PLCP, etc. */
u8
plcp_siso
;
/* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
u8
plcp_mimo2
;
/* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
u8
plcp
;
/* uCode API: IWL_RATE_6M_PLCP, etc. */
u8
plcp_ht_siso
;
/* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
u8
plcp_ht_mimo2
;
/* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
u8
plcp_vht_siso
;
u8
plcp_vht_mimo2
;
u8
prev_rs
;
/* previous rate used in rs algo */
u8
next_rs
;
/* next rate used in rs algo */
};
...
...
@@ -83,35 +85,52 @@ enum {
#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX)
/* uCode API values for
OFDM high-throughput (HT)
bit rates */
/* uCode API values for
HT/VHT
bit rates */
enum
{
IWL_RATE_SISO_6M_PLCP
=
0
,
IWL_RATE_SISO_12M_PLCP
=
1
,
IWL_RATE_SISO_18M_PLCP
=
2
,
IWL_RATE_SISO_24M_PLCP
=
3
,
IWL_RATE_SISO_36M_PLCP
=
4
,
IWL_RATE_SISO_48M_PLCP
=
5
,
IWL_RATE_SISO_54M_PLCP
=
6
,
IWL_RATE_SISO_60M_PLCP
=
7
,
IWL_RATE_MIMO2_6M_PLCP
=
0x8
,
IWL_RATE_MIMO2_12M_PLCP
=
0x9
,
IWL_RATE_MIMO2_18M_PLCP
=
0xa
,
IWL_RATE_MIMO2_24M_PLCP
=
0xb
,
IWL_RATE_MIMO2_36M_PLCP
=
0xc
,
IWL_RATE_MIMO2_48M_PLCP
=
0xd
,
IWL_RATE_MIMO2_54M_PLCP
=
0xe
,
IWL_RATE_MIMO2_60M_PLCP
=
0xf
,
IWL_RATE_MIMO3_6M_PLCP
=
0x10
,
IWL_RATE_MIMO3_12M_PLCP
=
0x11
,
IWL_RATE_MIMO3_18M_PLCP
=
0x12
,
IWL_RATE_MIMO3_24M_PLCP
=
0x13
,
IWL_RATE_MIMO3_36M_PLCP
=
0x14
,
IWL_RATE_MIMO3_48M_PLCP
=
0x15
,
IWL_RATE_MIMO3_54M_PLCP
=
0x16
,
IWL_RATE_MIMO3_60M_PLCP
=
0x17
,
IWL_RATE_SISO_INVM_PLCP
,
IWL_RATE_MIMO2_INVM_PLCP
=
IWL_RATE_SISO_INVM_PLCP
,
IWL_RATE_MIMO3_INVM_PLCP
=
IWL_RATE_SISO_INVM_PLCP
,
IWL_RATE_HT_SISO_MCS_0_PLCP
=
0
,
IWL_RATE_HT_SISO_MCS_1_PLCP
=
1
,
IWL_RATE_HT_SISO_MCS_2_PLCP
=
2
,
IWL_RATE_HT_SISO_MCS_3_PLCP
=
3
,
IWL_RATE_HT_SISO_MCS_4_PLCP
=
4
,
IWL_RATE_HT_SISO_MCS_5_PLCP
=
5
,
IWL_RATE_HT_SISO_MCS_6_PLCP
=
6
,
IWL_RATE_HT_SISO_MCS_7_PLCP
=
7
,
IWL_RATE_HT_MIMO2_MCS_0_PLCP
=
0x8
,
IWL_RATE_HT_MIMO2_MCS_1_PLCP
=
0x9
,
IWL_RATE_HT_MIMO2_MCS_2_PLCP
=
0xA
,
IWL_RATE_HT_MIMO2_MCS_3_PLCP
=
0xB
,
IWL_RATE_HT_MIMO2_MCS_4_PLCP
=
0xC
,
IWL_RATE_HT_MIMO2_MCS_5_PLCP
=
0xD
,
IWL_RATE_HT_MIMO2_MCS_6_PLCP
=
0xE
,
IWL_RATE_HT_MIMO2_MCS_7_PLCP
=
0xF
,
IWL_RATE_VHT_SISO_MCS_0_PLCP
=
0
,
IWL_RATE_VHT_SISO_MCS_1_PLCP
=
1
,
IWL_RATE_VHT_SISO_MCS_2_PLCP
=
2
,
IWL_RATE_VHT_SISO_MCS_3_PLCP
=
3
,
IWL_RATE_VHT_SISO_MCS_4_PLCP
=
4
,
IWL_RATE_VHT_SISO_MCS_5_PLCP
=
5
,
IWL_RATE_VHT_SISO_MCS_6_PLCP
=
6
,
IWL_RATE_VHT_SISO_MCS_7_PLCP
=
7
,
IWL_RATE_VHT_SISO_MCS_8_PLCP
=
8
,
IWL_RATE_VHT_SISO_MCS_9_PLCP
=
9
,
IWL_RATE_VHT_MIMO2_MCS_0_PLCP
=
0x10
,
IWL_RATE_VHT_MIMO2_MCS_1_PLCP
=
0x11
,
IWL_RATE_VHT_MIMO2_MCS_2_PLCP
=
0x12
,
IWL_RATE_VHT_MIMO2_MCS_3_PLCP
=
0x13
,
IWL_RATE_VHT_MIMO2_MCS_4_PLCP
=
0x14
,
IWL_RATE_VHT_MIMO2_MCS_5_PLCP
=
0x15
,
IWL_RATE_VHT_MIMO2_MCS_6_PLCP
=
0x16
,
IWL_RATE_VHT_MIMO2_MCS_7_PLCP
=
0x17
,
IWL_RATE_VHT_MIMO2_MCS_8_PLCP
=
0x18
,
IWL_RATE_VHT_MIMO2_MCS_9_PLCP
=
0x19
,
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
IWL_RATE_HT_MIMO2_MCS_INV_PLCP
=
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
IWL_RATE_VHT_SISO_MCS_INV_PLCP
=
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
IWL_RATE_VHT_MIMO2_MCS_INV_PLCP
=
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
IWL_RATE_HT_SISO_MCS_8_PLCP
=
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
IWL_RATE_HT_SISO_MCS_9_PLCP
=
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
IWL_RATE_HT_MIMO2_MCS_8_PLCP
=
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
IWL_RATE_HT_MIMO2_MCS_9_PLCP
=
IWL_RATE_HT_SISO_MCS_INV_PLCP
,
};
#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
...
...
@@ -139,25 +158,33 @@ enum {
#define IWL_RATE_DECREASE_TH 1920
/* 15% */
/* possible actions when in legacy mode */
#define IWL_LEGACY_SWITCH_ANTENNA1 0
#define IWL_LEGACY_SWITCH_ANTENNA2 1
#define IWL_LEGACY_SWITCH_SISO 2
#define IWL_LEGACY_SWITCH_MIMO2 3
enum
{
IWL_LEGACY_SWITCH_ANTENNA
,
IWL_LEGACY_SWITCH_SISO
,
IWL_LEGACY_SWITCH_MIMO2
,
IWL_LEGACY_FIRST_ACTION
=
IWL_LEGACY_SWITCH_ANTENNA
,
IWL_LEGACY_LAST_ACTION
=
IWL_LEGACY_SWITCH_MIMO2
,
};
/* possible actions when in siso mode */
#define IWL_SISO_SWITCH_ANTENNA1 0
#define IWL_SISO_SWITCH_ANTENNA2 1
#define IWL_SISO_SWITCH_MIMO2 2
#define IWL_SISO_SWITCH_GI 3
enum
{
IWL_SISO_SWITCH_ANTENNA
,
IWL_SISO_SWITCH_MIMO2
,
IWL_SISO_SWITCH_GI
,
IWL_SISO_FIRST_ACTION
=
IWL_SISO_SWITCH_ANTENNA
,
IWL_SISO_LAST_ACTION
=
IWL_SISO_SWITCH_GI
,
};
/* possible actions when in mimo mode */
#define IWL_MIMO2_SWITCH_ANTENNA1 0
#define IWL_MIMO2_SWITCH_ANTENNA2 1
#define IWL_MIMO2_SWITCH_SISO_A 2
#define IWL_MIMO2_SWITCH_SISO_B 3
#define IWL_MIMO2_SWITCH_GI 4
enum
{
IWL_MIMO2_SWITCH_SISO_A
,
IWL_MIMO2_SWITCH_SISO_B
,
IWL_MIMO2_SWITCH_GI
,
IWL_MIMO2_FIRST_ACTION
=
IWL_MIMO2_SWITCH_SISO_A
,
IWL_MIMO2_LAST_ACTION
=
IWL_MIMO2_SWITCH_GI
,
};
#define IWL_MAX_SEARCH IWL_MIMO2_
SWITCH_GI
#define IWL_MAX_SEARCH IWL_MIMO2_
LAST_ACTION
#define IWL_ACTION_LIMIT 3
/* # possible actions */
...
...
@@ -188,20 +215,31 @@ enum {
enum
iwl_table_type
{
LQ_NONE
,
LQ_G
,
/* legacy types */
LQ_A
,
LQ_SISO
,
/* high-throughput types */
LQ_MIMO2
,
LQ_LEGACY_G
,
/* legacy types */
LQ_LEGACY_A
,
LQ_HT_SISO
,
/* HT types */
LQ_HT_MIMO2
,
LQ_VHT_SISO
,
/* VHT types */
LQ_VHT_MIMO2
,
LQ_MAX
,
};
#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
#define is_siso(tbl) ((tbl) == LQ_SISO)
#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
#define is_mimo(tbl) is_mimo2(tbl)
#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
#define is_a_band(tbl) ((tbl) == LQ_A)
#define is_g_and(tbl) ((tbl) == LQ_G)
#define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A))
#define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO)
#define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2)
#define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO)
#define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2)
#define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl))
#define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl))
#define is_mimo(tbl) (is_mimo2(tbl))
#define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl))
#define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl))
#define is_a_band(tbl) ((tbl) == LQ_LEGACY_A)
#define is_g_band(tbl) ((tbl) == LQ_LEGACY_G)
#define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20)
#define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40)
#define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80)
#define IWL_MAX_MCS_DISPLAY_SIZE 12
...
...
@@ -232,7 +270,7 @@ struct iwl_scale_tbl_info {
enum
iwl_table_type
lq_type
;
u8
ant_type
;
u8
is_SGI
;
/* 1 = short guard interval */
u
8
is_ht40
;
/* 1 = 40 MHz channel width
*/
u
32
bw
;
/* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX
*/
u8
action
;
/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
u8
max_search
;
/* maximun number of tables we can search */
s32
*
expected_tpt
;
/* throughput metrics; expected_tpt_G, etc. */
...
...
@@ -262,7 +300,7 @@ struct iwl_lq_sta {
u64
flush_timer
;
/* time staying in mode before new search */
u8
action_counter
;
/* # mode-switch actions tried */
u8
is_green
;
bool
is_vht
;
enum
ieee80211_band
band
;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
...
...
drivers/net/wireless/iwlwifi/mvm/rx.c
View file @
444474dd
...
...
@@ -422,6 +422,27 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
mvmvif
->
bf_data
.
ave_beacon_signal
=
sig
;
/* BT Coex */
if
(
mvmvif
->
bf_data
.
bt_coex_min_thold
!=
mvmvif
->
bf_data
.
bt_coex_max_thold
)
{
last_event
=
mvmvif
->
bf_data
.
last_bt_coex_event
;
if
(
sig
>
mvmvif
->
bf_data
.
bt_coex_max_thold
&&
(
last_event
<=
mvmvif
->
bf_data
.
bt_coex_min_thold
||
last_event
==
0
))
{
mvmvif
->
bf_data
.
last_bt_coex_event
=
sig
;
IWL_DEBUG_RX
(
mvm
,
"cqm_iterator bt coex high %d
\n
"
,
sig
);
iwl_mvm_bt_rssi_event
(
mvm
,
vif
,
RSSI_EVENT_HIGH
);
}
else
if
(
sig
<
mvmvif
->
bf_data
.
bt_coex_min_thold
&&
(
last_event
>=
mvmvif
->
bf_data
.
bt_coex_max_thold
||
last_event
==
0
))
{
mvmvif
->
bf_data
.
last_bt_coex_event
=
sig
;
IWL_DEBUG_RX
(
mvm
,
"cqm_iterator bt coex low %d
\n
"
,
sig
);
iwl_mvm_bt_rssi_event
(
mvm
,
vif
,
RSSI_EVENT_LOW
);
}
}
if
(
!
(
vif
->
driver_flags
&
IEEE80211_VIF_SUPPORTS_CQM_RSSI
))
return
;
...
...
drivers/net/wireless/iwlwifi/mvm/scan.c
View file @
444474dd
...
...
@@ -74,8 +74,12 @@
static
inline
__le16
iwl_mvm_scan_rx_chain
(
struct
iwl_mvm
*
mvm
)
{
u16
rx_chain
;
u8
rx_ant
=
iwl_fw_valid_rx_ant
(
mvm
->
fw
)
;
u8
rx_ant
;
if
(
mvm
->
scan_rx_ant
!=
ANT_NONE
)
rx_ant
=
mvm
->
scan_rx_ant
;
else
rx_ant
=
iwl_fw_valid_rx_ant
(
mvm
->
fw
);
rx_chain
=
rx_ant
<<
PHY_RX_CHAIN_VALID_POS
;
rx_chain
|=
rx_ant
<<
PHY_RX_CHAIN_FORCE_MIMO_SEL_POS
;
rx_chain
|=
rx_ant
<<
PHY_RX_CHAIN_FORCE_SEL_POS
;
...
...
@@ -133,11 +137,12 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
* request.
*/
static
void
iwl_mvm_scan_fill_ssids
(
struct
iwl_scan_cmd
*
cmd
,
struct
cfg80211_scan_request
*
req
)
struct
cfg80211_scan_request
*
req
,
int
first
)
{
int
fw_idx
,
req_idx
;
for
(
req_idx
=
req
->
n_ssids
-
1
,
fw_idx
=
0
;
req_idx
>
0
;
for
(
req_idx
=
req
->
n_ssids
-
1
,
fw_idx
=
0
;
req_idx
>
=
first
;
req_idx
--
,
fw_idx
++
)
{
cmd
->
direct_scan
[
fw_idx
].
id
=
WLAN_EID_SSID
;
cmd
->
direct_scan
[
fw_idx
].
len
=
req
->
ssids
[
req_idx
].
ssid_len
;
...
...
@@ -153,9 +158,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
* just to notify that this scan is active and not passive.
* In order to notify the FW of the number of SSIDs we wish to scan (including
* the zero-length one), we need to set the corresponding bits in chan->type,
* one for each SSID, and set the active bit (first).
The first SSID is already
*
included in the probe template, so we need to set only req->n_ssids - 1 bits
* in addition to the first bit.
* one for each SSID, and set the active bit (first).
If the first SSID is
*
already included in the probe template, so we need to set only
*
req->n_ssids - 1 bits
in addition to the first bit.
*/
static
u16
iwl_mvm_get_active_dwell
(
enum
ieee80211_band
band
,
int
n_ssids
)
{
...
...
@@ -170,7 +175,8 @@ static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
}
static
void
iwl_mvm_scan_fill_channels
(
struct
iwl_scan_cmd
*
cmd
,
struct
cfg80211_scan_request
*
req
)
struct
cfg80211_scan_request
*
req
,
bool
basic_ssid
)
{
u16
passive_dwell
=
iwl_mvm_get_passive_dwell
(
req
->
channels
[
0
]
->
band
);
u16
active_dwell
=
iwl_mvm_get_active_dwell
(
req
->
channels
[
0
]
->
band
,
...
...
@@ -178,10 +184,14 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
struct
iwl_scan_channel
*
chan
=
(
struct
iwl_scan_channel
*
)
(
cmd
->
data
+
le16_to_cpu
(
cmd
->
tx_cmd
.
len
));
int
i
;
int
type
=
BIT
(
req
->
n_ssids
)
-
1
;
if
(
!
basic_ssid
)
type
|=
BIT
(
req
->
n_ssids
);
for
(
i
=
0
;
i
<
cmd
->
channel_count
;
i
++
)
{
chan
->
channel
=
cpu_to_le16
(
req
->
channels
[
i
]
->
hw_value
);
chan
->
type
=
cpu_to_le32
(
BIT
(
req
->
n_ssids
)
-
1
);
chan
->
type
=
cpu_to_le32
(
type
);
if
(
req
->
channels
[
i
]
->
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
)
chan
->
type
&=
cpu_to_le32
(
~
SCAN_CHANNEL_TYPE_ACTIVE
);
chan
->
active_dwell
=
cpu_to_le16
(
active_dwell
);
...
...
@@ -268,6 +278,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
u32
status
;
int
ssid_len
=
0
;
u8
*
ssid
=
NULL
;
bool
basic_ssid
=
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID
);
lockdep_assert_held
(
&
mvm
->
mutex
);
BUG_ON
(
mvm
->
scan_cmd
==
NULL
);
...
...
@@ -302,14 +314,16 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
if
(
req
->
n_ssids
>
0
)
{
cmd
->
passive2active
=
cpu_to_le16
(
1
);
cmd
->
scan_flags
|=
SCAN_FLAGS_PASSIVE2ACTIVE
;
ssid
=
req
->
ssids
[
0
].
ssid
;
ssid_len
=
req
->
ssids
[
0
].
ssid_len
;
if
(
basic_ssid
)
{
ssid
=
req
->
ssids
[
0
].
ssid
;
ssid_len
=
req
->
ssids
[
0
].
ssid_len
;
}
}
else
{
cmd
->
passive2active
=
0
;
cmd
->
scan_flags
&=
~
SCAN_FLAGS_PASSIVE2ACTIVE
;
}
iwl_mvm_scan_fill_ssids
(
cmd
,
req
);
iwl_mvm_scan_fill_ssids
(
cmd
,
req
,
basic_ssid
?
1
:
0
);
cmd
->
tx_cmd
.
tx_flags
=
cpu_to_le32
(
TX_CMD_FLG_SEQ_CTL
);
cmd
->
tx_cmd
.
sta_id
=
mvm
->
aux_sta
.
sta_id
;
...
...
@@ -326,7 +340,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
req
->
ie
,
req
->
ie_len
,
mvm
->
fw
->
ucode_capa
.
max_probe_length
));
iwl_mvm_scan_fill_channels
(
cmd
,
req
);
iwl_mvm_scan_fill_channels
(
cmd
,
req
,
basic_ssid
);
cmd
->
len
=
cpu_to_le16
(
sizeof
(
struct
iwl_scan_cmd
)
+
le16_to_cpu
(
cmd
->
tx_cmd
.
len
)
+
...
...
@@ -377,6 +391,21 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
return
0
;
}
int
iwl_mvm_rx_sched_scan_results
(
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_sched_scan_results
*
notif
=
(
void
*
)
pkt
->
data
;
if
(
notif
->
client_bitmap
&
SCAN_CLIENT_SCHED_SCAN
)
{
IWL_DEBUG_SCAN
(
mvm
,
"Scheduled scan results
\n
"
);
ieee80211_sched_scan_results
(
mvm
->
hw
);
}
return
0
;
}
static
bool
iwl_mvm_scan_abort_notif
(
struct
iwl_notif_wait_data
*
notif_wait
,
struct
iwl_rx_packet
*
pkt
,
void
*
data
)
{
...
...
@@ -437,3 +466,406 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
out_remove_notif:
iwl_remove_notification
(
&
mvm
->
notif_wait
,
&
wait_scan_abort
);
}
int
iwl_mvm_rx_scan_offload_complete_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_scan_offload_complete
*
scan_notif
=
(
void
*
)
pkt
->
data
;
IWL_DEBUG_SCAN
(
mvm
,
"Scheduled scan completed, status %s
\n
"
,
scan_notif
->
status
==
IWL_SCAN_OFFLOAD_COMPLETED
?
"completed"
:
"aborted"
);
mvm
->
scan_status
=
IWL_MVM_SCAN_NONE
;
ieee80211_sched_scan_stopped
(
mvm
->
hw
);
return
0
;
}
static
void
iwl_scan_offload_build_tx_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sched_scan_ies
*
ies
,
enum
ieee80211_band
band
,
struct
iwl_tx_cmd
*
cmd
,
u8
*
data
)
{
u16
cmd_len
;
cmd
->
tx_flags
=
cpu_to_le32
(
TX_CMD_FLG_SEQ_CTL
);
cmd
->
life_time
=
cpu_to_le32
(
TX_CMD_LIFE_TIME_INFINITE
);
cmd
->
sta_id
=
mvm
->
aux_sta
.
sta_id
;
cmd
->
rate_n_flags
=
iwl_mvm_scan_rate_n_flags
(
mvm
,
band
,
false
);
cmd_len
=
iwl_mvm_fill_probe_req
((
struct
ieee80211_mgmt
*
)
data
,
vif
->
addr
,
1
,
NULL
,
0
,
ies
->
ie
[
band
],
ies
->
len
[
band
],
SCAN_OFFLOAD_PROBE_REQ_SIZE
);
cmd
->
len
=
cpu_to_le16
(
cmd_len
);
}
static
void
iwl_build_scan_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
iwl_scan_offload_cmd
*
scan
)
{
scan
->
channel_count
=
mvm
->
nvm_data
->
bands
[
IEEE80211_BAND_2GHZ
].
n_channels
+
mvm
->
nvm_data
->
bands
[
IEEE80211_BAND_5GHZ
].
n_channels
;
scan
->
quiet_time
=
cpu_to_le16
(
IWL_ACTIVE_QUIET_TIME
);
scan
->
quiet_plcp_th
=
cpu_to_le16
(
IWL_PLCP_QUIET_THRESH
);
scan
->
good_CRC_th
=
IWL_GOOD_CRC_TH_DEFAULT
;
scan
->
rx_chain
=
iwl_mvm_scan_rx_chain
(
mvm
);
scan
->
max_out_time
=
cpu_to_le32
(
200
*
1024
);
scan
->
suspend_time
=
iwl_mvm_scan_suspend_time
(
vif
);
scan
->
filter_flags
|=
cpu_to_le32
(
MAC_FILTER_ACCEPT_GRP
|
MAC_FILTER_IN_BEACON
);
scan
->
scan_type
=
cpu_to_le32
(
SCAN_TYPE_BACKGROUND
);
scan
->
rep_count
=
cpu_to_le32
(
1
);
}
static
int
iwl_ssid_exist
(
u8
*
ssid
,
u8
ssid_len
,
struct
iwl_ssid_ie
*
ssid_list
)
{
int
i
;
for
(
i
=
0
;
i
<
PROBE_OPTION_MAX
;
i
++
)
{
if
(
!
ssid_list
[
i
].
len
)
break
;
if
(
ssid_list
[
i
].
len
==
ssid_len
&&
!
memcmp
(
ssid_list
->
ssid
,
ssid
,
ssid_len
))
return
i
;
}
return
-
1
;
}
static
void
iwl_scan_offload_build_ssid
(
struct
cfg80211_sched_scan_request
*
req
,
struct
iwl_scan_offload_cmd
*
scan
,
u32
*
ssid_bitmap
)
{
int
i
,
j
;
int
index
;
/*
* copy SSIDs from match list.
* iwl_config_sched_scan_profiles() uses the order of these ssids to
* config match list.
*/
for
(
i
=
0
;
i
<
req
->
n_match_sets
&&
i
<
PROBE_OPTION_MAX
;
i
++
)
{
scan
->
direct_scan
[
i
].
id
=
WLAN_EID_SSID
;
scan
->
direct_scan
[
i
].
len
=
req
->
match_sets
[
i
].
ssid
.
ssid_len
;
memcpy
(
scan
->
direct_scan
[
i
].
ssid
,
req
->
match_sets
[
i
].
ssid
.
ssid
,
scan
->
direct_scan
[
i
].
len
);
}
/* add SSIDs from scan SSID list */
*
ssid_bitmap
=
0
;
for
(
j
=
0
;
j
<
req
->
n_ssids
&&
i
<
PROBE_OPTION_MAX
;
j
++
)
{
index
=
iwl_ssid_exist
(
req
->
ssids
[
j
].
ssid
,
req
->
ssids
[
j
].
ssid_len
,
scan
->
direct_scan
);
if
(
index
<
0
)
{
if
(
!
req
->
ssids
[
j
].
ssid_len
)
continue
;
scan
->
direct_scan
[
i
].
id
=
WLAN_EID_SSID
;
scan
->
direct_scan
[
i
].
len
=
req
->
ssids
[
j
].
ssid_len
;
memcpy
(
scan
->
direct_scan
[
i
].
ssid
,
req
->
ssids
[
j
].
ssid
,
scan
->
direct_scan
[
i
].
len
);
*
ssid_bitmap
|=
BIT
(
i
+
1
);
i
++
;
}
else
{
*
ssid_bitmap
|=
BIT
(
index
+
1
);
}
}
}
static
void
iwl_build_channel_cfg
(
struct
iwl_mvm
*
mvm
,
struct
cfg80211_sched_scan_request
*
req
,
struct
iwl_scan_channel_cfg
*
channels
,
enum
ieee80211_band
band
,
int
*
head
,
int
*
tail
,
u32
ssid_bitmap
)
{
struct
ieee80211_supported_band
*
s_band
;
int
n_probes
=
req
->
n_ssids
;
int
n_channels
=
req
->
n_channels
;
u8
active_dwell
,
passive_dwell
;
int
i
,
j
,
index
=
0
;
bool
partial
;
/*
* We have to configure all supported channels, even if we don't want to
* scan on them, but we have to send channels in the order that we want
* to scan. So add requested channels to head of the list and others to
* the end.
*/
active_dwell
=
iwl_mvm_get_active_dwell
(
band
,
n_probes
);
passive_dwell
=
iwl_mvm_get_passive_dwell
(
band
);
s_band
=
&
mvm
->
nvm_data
->
bands
[
band
];
for
(
i
=
0
;
i
<
s_band
->
n_channels
&&
*
head
<=
*
tail
;
i
++
)
{
partial
=
false
;
for
(
j
=
0
;
j
<
n_channels
;
j
++
)
if
(
s_band
->
channels
[
i
].
center_freq
==
req
->
channels
[
j
]
->
center_freq
)
{
index
=
*
head
;
(
*
head
)
++
;
/*
* Channels that came with the request will be
* in partial scan .
*/
partial
=
true
;
break
;
}
if
(
!
partial
)
{
index
=
*
tail
;
(
*
tail
)
--
;
}
channels
->
channel_number
[
index
]
=
cpu_to_le16
(
ieee80211_frequency_to_channel
(
s_band
->
channels
[
i
].
center_freq
));
channels
->
dwell_time
[
index
][
0
]
=
active_dwell
;
channels
->
dwell_time
[
index
][
1
]
=
passive_dwell
;
channels
->
iter_count
[
index
]
=
cpu_to_le16
(
1
);
channels
->
iter_interval
[
index
]
=
0
;
if
(
!
(
s_band
->
channels
[
i
].
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
))
channels
->
type
[
index
]
|=
cpu_to_le32
(
IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE
);
channels
->
type
[
index
]
|=
cpu_to_le32
(
IWL_SCAN_OFFLOAD_CHANNEL_FULL
);
if
(
partial
)
channels
->
type
[
index
]
|=
cpu_to_le32
(
IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL
);
if
(
s_band
->
channels
[
i
].
flags
&
IEEE80211_CHAN_NO_HT40
)
channels
->
type
[
index
]
|=
cpu_to_le32
(
IWL_SCAN_OFFLOAD_CHANNEL_NARROW
);
/* scan for all SSIDs from req->ssids */
channels
->
type
[
index
]
|=
cpu_to_le32
(
ssid_bitmap
);
}
}
int
iwl_mvm_config_sched_scan
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
int
supported_bands
=
0
;
int
band_2ghz
=
mvm
->
nvm_data
->
bands
[
IEEE80211_BAND_2GHZ
].
n_channels
;
int
band_5ghz
=
mvm
->
nvm_data
->
bands
[
IEEE80211_BAND_5GHZ
].
n_channels
;
int
head
=
0
;
int
tail
=
band_2ghz
+
band_5ghz
;
u32
ssid_bitmap
;
int
cmd_len
;
int
ret
;
struct
iwl_scan_offload_cfg
*
scan_cfg
;
struct
iwl_host_cmd
cmd
=
{
.
id
=
SCAN_OFFLOAD_CONFIG_CMD
,
.
flags
=
CMD_SYNC
,
};
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
band_2ghz
)
supported_bands
++
;
if
(
band_5ghz
)
supported_bands
++
;
cmd_len
=
sizeof
(
struct
iwl_scan_offload_cfg
)
+
supported_bands
*
SCAN_OFFLOAD_PROBE_REQ_SIZE
;
scan_cfg
=
kzalloc
(
cmd_len
,
GFP_KERNEL
);
if
(
!
scan_cfg
)
return
-
ENOMEM
;
iwl_build_scan_cmd
(
mvm
,
vif
,
req
,
&
scan_cfg
->
scan_cmd
);
scan_cfg
->
scan_cmd
.
len
=
cpu_to_le16
(
cmd_len
);
iwl_scan_offload_build_ssid
(
req
,
&
scan_cfg
->
scan_cmd
,
&
ssid_bitmap
);
/* build tx frames for supported bands */
if
(
band_2ghz
)
{
iwl_scan_offload_build_tx_cmd
(
mvm
,
vif
,
ies
,
IEEE80211_BAND_2GHZ
,
&
scan_cfg
->
scan_cmd
.
tx_cmd
[
0
],
scan_cfg
->
data
);
iwl_build_channel_cfg
(
mvm
,
req
,
&
scan_cfg
->
channel_cfg
,
IEEE80211_BAND_2GHZ
,
&
head
,
&
tail
,
ssid_bitmap
);
}
if
(
band_5ghz
)
{
iwl_scan_offload_build_tx_cmd
(
mvm
,
vif
,
ies
,
IEEE80211_BAND_5GHZ
,
&
scan_cfg
->
scan_cmd
.
tx_cmd
[
1
],
scan_cfg
->
data
+
SCAN_OFFLOAD_PROBE_REQ_SIZE
);
iwl_build_channel_cfg
(
mvm
,
req
,
&
scan_cfg
->
channel_cfg
,
IEEE80211_BAND_5GHZ
,
&
head
,
&
tail
,
ssid_bitmap
);
}
cmd
.
data
[
0
]
=
scan_cfg
;
cmd
.
len
[
0
]
=
cmd_len
;
cmd
.
dataflags
[
0
]
=
IWL_HCMD_DFL_NOCOPY
;
IWL_DEBUG_SCAN
(
mvm
,
"Sending scheduled scan config
\n
"
);
ret
=
iwl_mvm_send_cmd
(
mvm
,
&
cmd
);
kfree
(
scan_cfg
);
return
ret
;
}
int
iwl_mvm_config_sched_scan_profiles
(
struct
iwl_mvm
*
mvm
,
struct
cfg80211_sched_scan_request
*
req
)
{
struct
iwl_scan_offload_profile
*
profile
;
struct
iwl_scan_offload_profile_cfg
*
profile_cfg
;
struct
iwl_scan_offload_blacklist
*
blacklist
;
struct
iwl_host_cmd
cmd
=
{
.
id
=
SCAN_OFFLOAD_UPDATE_PROFILES_CMD
,
.
flags
=
CMD_SYNC
,
.
len
[
1
]
=
sizeof
(
*
profile_cfg
),
.
dataflags
[
0
]
=
IWL_HCMD_DFL_NOCOPY
,
.
dataflags
[
1
]
=
IWL_HCMD_DFL_NOCOPY
,
};
int
blacklist_len
;
int
i
;
int
ret
;
if
(
WARN_ON
(
req
->
n_match_sets
>
IWL_SCAN_MAX_PROFILES
))
return
-
EIO
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_SHORT_BL
)
blacklist_len
=
IWL_SCAN_SHORT_BLACKLIST_LEN
;
else
blacklist_len
=
IWL_SCAN_MAX_BLACKLIST_LEN
;
blacklist
=
kzalloc
(
sizeof
(
*
blacklist
)
*
blacklist_len
,
GFP_KERNEL
);
if
(
!
blacklist
)
return
-
ENOMEM
;
profile_cfg
=
kzalloc
(
sizeof
(
*
profile_cfg
),
GFP_KERNEL
);
if
(
!
profile_cfg
)
{
ret
=
-
ENOMEM
;
goto
free_blacklist
;
}
cmd
.
data
[
0
]
=
blacklist
;
cmd
.
len
[
0
]
=
sizeof
(
*
blacklist
)
*
blacklist_len
;
cmd
.
data
[
1
]
=
profile_cfg
;
/* No blacklist configuration */
profile_cfg
->
num_profiles
=
req
->
n_match_sets
;
profile_cfg
->
active_clients
=
SCAN_CLIENT_SCHED_SCAN
;
profile_cfg
->
pass_match
=
SCAN_CLIENT_SCHED_SCAN
;
profile_cfg
->
match_notify
=
SCAN_CLIENT_SCHED_SCAN
;
for
(
i
=
0
;
i
<
req
->
n_match_sets
;
i
++
)
{
profile
=
&
profile_cfg
->
profiles
[
i
];
profile
->
ssid_index
=
i
;
/* Support any cipher and auth algorithm */
profile
->
unicast_cipher
=
0xff
;
profile
->
auth_alg
=
0xff
;
profile
->
network_type
=
IWL_NETWORK_TYPE_ANY
;
profile
->
band_selection
=
IWL_SCAN_OFFLOAD_SELECT_ANY
;
profile
->
client_bitmap
=
SCAN_CLIENT_SCHED_SCAN
;
}
IWL_DEBUG_SCAN
(
mvm
,
"Sending scheduled scan profile config
\n
"
);
ret
=
iwl_mvm_send_cmd
(
mvm
,
&
cmd
);
kfree
(
profile_cfg
);
free_blacklist:
kfree
(
blacklist
);
return
ret
;
}
int
iwl_mvm_sched_scan_start
(
struct
iwl_mvm
*
mvm
,
struct
cfg80211_sched_scan_request
*
req
)
{
struct
iwl_scan_offload_req
scan_req
=
{
.
watchdog
=
IWL_SCHED_SCAN_WATCHDOG
,
.
schedule_line
[
0
].
iterations
=
IWL_FAST_SCHED_SCAN_ITERATIONS
,
.
schedule_line
[
0
].
delay
=
req
->
interval
/
1000
,
.
schedule_line
[
0
].
full_scan_mul
=
1
,
.
schedule_line
[
1
].
iterations
=
0xff
,
.
schedule_line
[
1
].
delay
=
req
->
interval
/
1000
,
.
schedule_line
[
1
].
full_scan_mul
=
IWL_FULL_SCAN_MULTIPLIER
,
};
if
(
req
->
n_match_sets
&&
req
->
match_sets
[
0
].
ssid
.
ssid_len
)
{
IWL_DEBUG_SCAN
(
mvm
,
"Sending scheduled scan with filtering, filter len %d
\n
"
,
req
->
n_match_sets
);
scan_req
.
flags
|=
cpu_to_le16
(
IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID
);
}
else
{
IWL_DEBUG_SCAN
(
mvm
,
"Sending Scheduled scan without filtering
\n
"
);
}
return
iwl_mvm_send_cmd_pdu
(
mvm
,
SCAN_OFFLOAD_REQUEST_CMD
,
CMD_SYNC
,
sizeof
(
scan_req
),
&
scan_req
);
}
static
int
iwl_mvm_send_sched_scan_abort
(
struct
iwl_mvm
*
mvm
)
{
int
ret
;
struct
iwl_host_cmd
cmd
=
{
.
id
=
SCAN_OFFLOAD_ABORT_CMD
,
.
flags
=
CMD_SYNC
,
};
u32
status
;
/* Exit instantly with error when device is not ready
* to receive scan abort command or it does not perform
* scheduled scan currently */
if
(
mvm
->
scan_status
!=
IWL_MVM_SCAN_SCHED
)
return
-
EIO
;
ret
=
iwl_mvm_send_cmd_status
(
mvm
,
&
cmd
,
&
status
);
if
(
ret
)
return
ret
;
if
(
status
!=
CAN_ABORT_STATUS
)
{
/*
* The scan abort will return 1 for success or
* 2 for "failure". A failure condition can be
* due to simply not being in an active scan which
* can occur if we send the scan abort before the
* microcode has notified us that a scan is completed.
*/
IWL_DEBUG_SCAN
(
mvm
,
"SCAN OFFLOAD ABORT ret %d.
\n
"
,
status
);
ret
=
-
EIO
;
}
return
ret
;
}
void
iwl_mvm_sched_scan_stop
(
struct
iwl_mvm
*
mvm
)
{
int
ret
;
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
mvm
->
scan_status
!=
IWL_MVM_SCAN_SCHED
)
{
IWL_DEBUG_SCAN
(
mvm
,
"No offloaded scan to stop
\n
"
);
return
;
}
ret
=
iwl_mvm_send_sched_scan_abort
(
mvm
);
if
(
ret
)
IWL_DEBUG_SCAN
(
mvm
,
"Send stop offload scan failed %d
\n
"
,
ret
);
else
IWL_DEBUG_SCAN
(
mvm
,
"Successfully sent stop offload scan
\n
"
);
}
drivers/net/wireless/iwlwifi/mvm/sta.c
View file @
444474dd
...
...
@@ -66,6 +66,115 @@
#include "sta.h"
#include "rs.h"
static
void
iwl_mvm_add_sta_cmd_v6_to_v5
(
struct
iwl_mvm_add_sta_cmd_v6
*
cmd_v6
,
struct
iwl_mvm_add_sta_cmd_v5
*
cmd_v5
)
{
memset
(
cmd_v5
,
0
,
sizeof
(
*
cmd_v5
));
cmd_v5
->
add_modify
=
cmd_v6
->
add_modify
;
cmd_v5
->
tid_disable_tx
=
cmd_v6
->
tid_disable_tx
;
cmd_v5
->
mac_id_n_color
=
cmd_v6
->
mac_id_n_color
;
memcpy
(
cmd_v5
->
addr
,
cmd_v6
->
addr
,
ETH_ALEN
);
cmd_v5
->
sta_id
=
cmd_v6
->
sta_id
;
cmd_v5
->
modify_mask
=
cmd_v6
->
modify_mask
;
cmd_v5
->
station_flags
=
cmd_v6
->
station_flags
;
cmd_v5
->
station_flags_msk
=
cmd_v6
->
station_flags_msk
;
cmd_v5
->
add_immediate_ba_tid
=
cmd_v6
->
add_immediate_ba_tid
;
cmd_v5
->
remove_immediate_ba_tid
=
cmd_v6
->
remove_immediate_ba_tid
;
cmd_v5
->
add_immediate_ba_ssn
=
cmd_v6
->
add_immediate_ba_ssn
;
cmd_v5
->
sleep_tx_count
=
cmd_v6
->
sleep_tx_count
;
cmd_v5
->
sleep_state_flags
=
cmd_v6
->
sleep_state_flags
;
cmd_v5
->
assoc_id
=
cmd_v6
->
assoc_id
;
cmd_v5
->
beamform_flags
=
cmd_v6
->
beamform_flags
;
cmd_v5
->
tfd_queue_msk
=
cmd_v6
->
tfd_queue_msk
;
}
static
void
iwl_mvm_add_sta_key_to_add_sta_cmd_v5
(
struct
iwl_mvm_add_sta_key_cmd
*
key_cmd
,
struct
iwl_mvm_add_sta_cmd_v5
*
sta_cmd
,
u32
mac_id_n_color
)
{
memset
(
sta_cmd
,
0
,
sizeof
(
*
sta_cmd
));
sta_cmd
->
sta_id
=
key_cmd
->
sta_id
;
sta_cmd
->
add_modify
=
STA_MODE_MODIFY
;
sta_cmd
->
modify_mask
=
STA_MODIFY_KEY
;
sta_cmd
->
mac_id_n_color
=
cpu_to_le32
(
mac_id_n_color
);
sta_cmd
->
key
.
key_offset
=
key_cmd
->
key_offset
;
sta_cmd
->
key
.
key_flags
=
key_cmd
->
key_flags
;
memcpy
(
sta_cmd
->
key
.
key
,
key_cmd
->
key
,
sizeof
(
sta_cmd
->
key
.
key
));
sta_cmd
->
key
.
tkip_rx_tsc_byte2
=
key_cmd
->
tkip_rx_tsc_byte2
;
memcpy
(
sta_cmd
->
key
.
tkip_rx_ttak
,
key_cmd
->
tkip_rx_ttak
,
sizeof
(
sta_cmd
->
key
.
tkip_rx_ttak
));
}
static
int
iwl_mvm_send_add_sta_cmd_status
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_add_sta_cmd_v6
*
cmd
,
int
*
status
)
{
struct
iwl_mvm_add_sta_cmd_v5
cmd_v5
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD
)
return
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
*
cmd
),
cmd
,
status
);
iwl_mvm_add_sta_cmd_v6_to_v5
(
cmd
,
&
cmd_v5
);
return
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
cmd_v5
),
&
cmd_v5
,
status
);
}
static
int
iwl_mvm_send_add_sta_cmd
(
struct
iwl_mvm
*
mvm
,
u32
flags
,
struct
iwl_mvm_add_sta_cmd_v6
*
cmd
)
{
struct
iwl_mvm_add_sta_cmd_v5
cmd_v5
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD
)
return
iwl_mvm_send_cmd_pdu
(
mvm
,
ADD_STA
,
flags
,
sizeof
(
*
cmd
),
cmd
);
iwl_mvm_add_sta_cmd_v6_to_v5
(
cmd
,
&
cmd_v5
);
return
iwl_mvm_send_cmd_pdu
(
mvm
,
ADD_STA
,
flags
,
sizeof
(
cmd_v5
),
&
cmd_v5
);
}
static
int
iwl_mvm_send_add_sta_key_cmd_status
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_add_sta_key_cmd
*
cmd
,
u32
mac_id_n_color
,
int
*
status
)
{
struct
iwl_mvm_add_sta_cmd_v5
sta_cmd
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD
)
return
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA_KEY
,
sizeof
(
*
cmd
),
cmd
,
status
);
iwl_mvm_add_sta_key_to_add_sta_cmd_v5
(
cmd
,
&
sta_cmd
,
mac_id_n_color
);
return
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
sta_cmd
),
&
sta_cmd
,
status
);
}
static
int
iwl_mvm_send_add_sta_key_cmd
(
struct
iwl_mvm
*
mvm
,
u32
flags
,
struct
iwl_mvm_add_sta_key_cmd
*
cmd
,
u32
mac_id_n_color
)
{
struct
iwl_mvm_add_sta_cmd_v5
sta_cmd
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD
)
return
iwl_mvm_send_cmd_pdu
(
mvm
,
ADD_STA_KEY
,
flags
,
sizeof
(
*
cmd
),
cmd
);
iwl_mvm_add_sta_key_to_add_sta_cmd_v5
(
cmd
,
&
sta_cmd
,
mac_id_n_color
);
return
iwl_mvm_send_cmd_pdu
(
mvm
,
ADD_STA
,
flags
,
sizeof
(
sta_cmd
),
&
sta_cmd
);
}
static
int
iwl_mvm_find_free_sta_id
(
struct
iwl_mvm
*
mvm
)
{
int
sta_id
;
...
...
@@ -87,7 +196,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
bool
update
)
{
struct
iwl_mvm_sta
*
mvm_sta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_add_sta_cmd
add_sta_cmd
;
struct
iwl_mvm_add_sta_cmd
_v6
add_sta_cmd
;
int
ret
;
u32
status
;
u32
agg_size
=
0
,
mpdu_dens
=
0
;
...
...
@@ -175,8 +284,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
cpu_to_le32
(
mpdu_dens
<<
STA_FLG_AGG_MPDU_DENS_SHIFT
);
status
=
ADD_STA_SUCCESS
;
ret
=
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
add_sta_cmd
),
&
add_sta_cmd
,
&
status
);
ret
=
iwl_mvm_send_add_sta_cmd_status
(
mvm
,
&
add_sta_cmd
,
&
status
);
if
(
ret
)
return
ret
;
...
...
@@ -229,8 +337,12 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
if
(
vif
->
hw_queue
[
i
]
!=
IEEE80211_INVAL_HW_QUEUE
)
mvm_sta
->
tfd_queue_msk
|=
BIT
(
vif
->
hw_queue
[
i
]);
/* for HW restart - need to reset the seq_number etc... */
memset
(
mvm_sta
->
tid_data
,
0
,
sizeof
(
mvm_sta
->
tid_data
));
/* for HW restart - reset everything but the sequence number */
for
(
i
=
0
;
i
<
IWL_MAX_TID_COUNT
;
i
++
)
{
u16
seq
=
mvm_sta
->
tid_data
[
i
].
seq_number
;
memset
(
&
mvm_sta
->
tid_data
[
i
],
0
,
sizeof
(
mvm_sta
->
tid_data
[
i
]));
mvm_sta
->
tid_data
[
i
].
seq_number
=
seq
;
}
ret
=
iwl_mvm_sta_send_to_fw
(
mvm
,
sta
,
false
);
if
(
ret
)
...
...
@@ -256,7 +368,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm,
int
iwl_mvm_drain_sta
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_sta
*
mvmsta
,
bool
drain
)
{
struct
iwl_mvm_add_sta_cmd
cmd
=
{};
struct
iwl_mvm_add_sta_cmd
_v6
cmd
=
{};
int
ret
;
u32
status
;
...
...
@@ -269,8 +381,7 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
cmd
.
station_flags_msk
=
cpu_to_le32
(
STA_FLG_DRAIN_FLOW
);
status
=
ADD_STA_SUCCESS
;
ret
=
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
cmd
),
&
cmd
,
&
status
);
ret
=
iwl_mvm_send_add_sta_cmd_status
(
mvm
,
&
cmd
,
&
status
);
if
(
ret
)
return
ret
;
...
...
@@ -469,13 +580,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
const
u8
*
addr
,
u16
mac_id
,
u16
color
)
{
struct
iwl_mvm_add_sta_cmd
cmd
;
struct
iwl_mvm_add_sta_cmd
_v6
cmd
;
int
ret
;
u32
status
;
lockdep_assert_held
(
&
mvm
->
mutex
);
memset
(
&
cmd
,
0
,
sizeof
(
struct
iwl_mvm_add_sta_cmd
));
memset
(
&
cmd
,
0
,
sizeof
(
struct
iwl_mvm_add_sta_cmd
_v6
));
cmd
.
sta_id
=
sta
->
sta_id
;
cmd
.
mac_id_n_color
=
cpu_to_le32
(
FW_CMD_ID_AND_COLOR
(
mac_id
,
color
));
...
...
@@ -485,8 +596,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
if
(
addr
)
memcpy
(
cmd
.
addr
,
addr
,
ETH_ALEN
);
ret
=
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
cmd
),
&
cmd
,
&
status
);
ret
=
iwl_mvm_send_add_sta_cmd_status
(
mvm
,
&
cmd
,
&
status
);
if
(
ret
)
return
ret
;
...
...
@@ -534,10 +644,14 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct
iwl_mvm_int_sta
*
bsta
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
static
const
u8
baddr
[]
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
};
static
const
u8
_baddr
[]
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
};
static
const
u8
*
baddr
=
_baddr
;
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
vif
->
type
==
NL80211_IFTYPE_ADHOC
)
baddr
=
vif
->
bss_conf
.
bssid
;
if
(
WARN_ON_ONCE
(
bsta
->
sta_id
==
IWL_MVM_STATION_COUNT
))
return
-
ENOSPC
;
...
...
@@ -614,7 +728,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int
tid
,
u16
ssn
,
bool
start
)
{
struct
iwl_mvm_sta
*
mvm_sta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_add_sta_cmd
cmd
=
{};
struct
iwl_mvm_add_sta_cmd
_v6
cmd
=
{};
int
ret
;
u32
status
;
...
...
@@ -638,8 +752,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
STA_MODIFY_REMOVE_BA_TID
;
status
=
ADD_STA_SUCCESS
;
ret
=
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
cmd
),
&
cmd
,
&
status
);
ret
=
iwl_mvm_send_add_sta_cmd_status
(
mvm
,
&
cmd
,
&
status
);
if
(
ret
)
return
ret
;
...
...
@@ -674,7 +787,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int
tid
,
u8
queue
,
bool
start
)
{
struct
iwl_mvm_sta
*
mvm_sta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_add_sta_cmd
cmd
=
{};
struct
iwl_mvm_add_sta_cmd
_v6
cmd
=
{};
int
ret
;
u32
status
;
...
...
@@ -696,8 +809,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
cmd
.
tid_disable_tx
=
cpu_to_le16
(
mvm_sta
->
tid_disable_agg
);
status
=
ADD_STA_SUCCESS
;
ret
=
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
cmd
),
&
cmd
,
&
status
);
ret
=
iwl_mvm_send_add_sta_cmd_status
(
mvm
,
&
cmd
,
&
status
);
if
(
ret
)
return
ret
;
...
...
@@ -743,13 +855,13 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held
(
&
mvm
->
mutex
);
for
(
txq_id
=
IWL_MVM_FIRST_AGG_QUEUE
;
txq_id
<=
IWL_MVM_LAST_AGG_QUEUE
;
txq_id
++
)
for
(
txq_id
=
mvm
->
first_agg_queue
;
txq_id
<=
mvm
->
last_agg_queue
;
txq_id
++
)
if
(
mvm
->
queue_to_mac80211
[
txq_id
]
==
IWL_INVALID_MAC80211_QUEUE
)
break
;
if
(
txq_id
>
IWL_MVM_LAST_AGG_QUEUE
)
{
if
(
txq_id
>
mvm
->
last_agg_queue
)
{
IWL_ERR
(
mvm
,
"Failed to allocate agg queue
\n
"
);
return
-
EIO
;
}
...
...
@@ -987,10 +1099,11 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
u32
cmd_flags
)
{
__le16
key_flags
;
struct
iwl_mvm_add_sta_cmd
cmd
=
{};
struct
iwl_mvm_add_sta_
key_
cmd
cmd
=
{};
int
ret
,
status
;
u16
keyidx
;
int
i
;
u32
mac_id_n_color
=
mvm_sta
->
mac_id_n_color
;
keyidx
=
(
keyconf
->
keyidx
<<
STA_KEY_FLG_KEYID_POS
)
&
STA_KEY_FLG_KEYID_MSK
;
...
...
@@ -1000,14 +1113,14 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
switch
(
keyconf
->
cipher
)
{
case
WLAN_CIPHER_SUITE_TKIP
:
key_flags
|=
cpu_to_le16
(
STA_KEY_FLG_TKIP
);
cmd
.
key
.
tkip_rx_tsc_byte2
=
tkip_iv32
;
cmd
.
tkip_rx_tsc_byte2
=
tkip_iv32
;
for
(
i
=
0
;
i
<
5
;
i
++
)
cmd
.
key
.
tkip_rx_ttak
[
i
]
=
cpu_to_le16
(
tkip_p1k
[
i
]);
memcpy
(
cmd
.
key
.
key
,
keyconf
->
key
,
keyconf
->
keylen
);
cmd
.
tkip_rx_ttak
[
i
]
=
cpu_to_le16
(
tkip_p1k
[
i
]);
memcpy
(
cmd
.
key
,
keyconf
->
key
,
keyconf
->
keylen
);
break
;
case
WLAN_CIPHER_SUITE_CCMP
:
key_flags
|=
cpu_to_le16
(
STA_KEY_FLG_CCM
);
memcpy
(
cmd
.
key
.
key
,
keyconf
->
key
,
keyconf
->
keylen
);
memcpy
(
cmd
.
key
,
keyconf
->
key
,
keyconf
->
keylen
);
break
;
default:
WARN_ON
(
1
);
...
...
@@ -1017,20 +1130,18 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
if
(
!
(
keyconf
->
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
))
key_flags
|=
cpu_to_le16
(
STA_KEY_MULTICAST
);
cmd
.
mac_id_n_color
=
cpu_to_le32
(
mvm_sta
->
mac_id_n_color
);
cmd
.
key
.
key_offset
=
keyconf
->
hw_key_idx
;
cmd
.
key
.
key_flags
=
key_flags
;
cmd
.
add_modify
=
STA_MODE_MODIFY
;
cmd
.
modify_mask
=
STA_MODIFY_KEY
;
cmd
.
key_offset
=
keyconf
->
hw_key_idx
;
cmd
.
key_flags
=
key_flags
;
cmd
.
sta_id
=
sta_id
;
status
=
ADD_STA_SUCCESS
;
if
(
cmd_flags
==
CMD_SYNC
)
ret
=
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
cmd
),
&
cmd
,
&
status
);
ret
=
iwl_mvm_send_add_sta_key_cmd_status
(
mvm
,
&
cmd
,
mac_id_n_color
,
&
status
);
else
ret
=
iwl_mvm_send_
cmd_pdu
(
mvm
,
ADD_STA
,
CMD_ASYNC
,
sizeof
(
cmd
),
&
cmd
);
ret
=
iwl_mvm_send_
add_sta_key_cmd
(
mvm
,
CMD_ASYNC
,
&
cmd
,
mac_id_n_color
);
switch
(
status
)
{
case
ADD_STA_SUCCESS
:
...
...
@@ -1197,7 +1308,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
struct
ieee80211_key_conf
*
keyconf
)
{
struct
iwl_mvm_sta
*
mvm_sta
;
struct
iwl_mvm_add_sta_cmd
cmd
=
{};
struct
iwl_mvm_add_sta_
key_
cmd
cmd
=
{};
__le16
key_flags
;
int
ret
,
status
;
u8
sta_id
;
...
...
@@ -1252,17 +1363,14 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
if
(
!
(
keyconf
->
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
))
key_flags
|=
cpu_to_le16
(
STA_KEY_MULTICAST
);
cmd
.
mac_id_n_color
=
cpu_to_le32
(
mvm_sta
->
mac_id_n_color
);
cmd
.
key
.
key_flags
=
key_flags
;
cmd
.
key
.
key_offset
=
keyconf
->
hw_key_idx
;
cmd
.
key_flags
=
key_flags
;
cmd
.
key_offset
=
keyconf
->
hw_key_idx
;
cmd
.
sta_id
=
sta_id
;
cmd
.
modify_mask
=
STA_MODIFY_KEY
;
cmd
.
add_modify
=
STA_MODE_MODIFY
;
status
=
ADD_STA_SUCCESS
;
ret
=
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
cmd
),
&
cmd
,
&
status
);
ret
=
iwl_mvm_send_add_sta_key_cmd_status
(
mvm
,
&
cmd
,
mvm_sta
->
mac_id_n_color
,
&
status
);
switch
(
status
)
{
case
ADD_STA_SUCCESS
:
...
...
@@ -1309,7 +1417,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_add_sta_cmd
cmd
=
{
struct
iwl_mvm_add_sta_cmd
_v6
cmd
=
{
.
add_modify
=
STA_MODE_MODIFY
,
.
sta_id
=
mvmsta
->
sta_id
,
.
station_flags_msk
=
cpu_to_le32
(
STA_FLG_PS
),
...
...
@@ -1317,7 +1425,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
};
int
ret
;
ret
=
iwl_mvm_send_
cmd_pdu
(
mvm
,
ADD_STA
,
CMD_ASYNC
,
sizeof
(
cmd
)
,
&
cmd
);
ret
=
iwl_mvm_send_
add_sta_cmd
(
mvm
,
CMD_ASYNC
,
&
cmd
);
if
(
ret
)
IWL_ERR
(
mvm
,
"Failed to send ADD_STA command (%d)
\n
"
,
ret
);
}
...
...
@@ -1331,7 +1439,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
(
reason
==
IEEE80211_FRAME_RELEASE_UAPSD
)
?
STA_SLEEP_STATE_UAPSD
:
STA_SLEEP_STATE_PS_POLL
;
struct
iwl_mvm_sta
*
mvmsta
=
(
void
*
)
sta
->
drv_priv
;
struct
iwl_mvm_add_sta_cmd
cmd
=
{
struct
iwl_mvm_add_sta_cmd
_v6
cmd
=
{
.
add_modify
=
STA_MODE_MODIFY
,
.
sta_id
=
mvmsta
->
sta_id
,
.
modify_mask
=
STA_MODIFY_SLEEPING_STA_TX_COUNT
,
...
...
@@ -1346,7 +1454,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
int
ret
;
/* TODO: somehow the fw doesn't seem to take PS_POLL into account */
ret
=
iwl_mvm_send_
cmd_pdu
(
mvm
,
ADD_STA
,
CMD_ASYNC
,
sizeof
(
cmd
)
,
&
cmd
);
ret
=
iwl_mvm_send_
add_sta_cmd
(
mvm
,
CMD_ASYNC
,
&
cmd
);
if
(
ret
)
IWL_ERR
(
mvm
,
"Failed to send ADD_STA command (%d)
\n
"
,
ret
);
}
drivers/net/wireless/iwlwifi/mvm/sta.h
View file @
444474dd
...
...
@@ -293,10 +293,6 @@ struct iwl_mvm_sta {
struct
iwl_lq_sta
lq_sta
;
struct
ieee80211_vif
*
vif
;
#ifdef CONFIG_PM_SLEEP
u16
last_seq_ctl
;
#endif
/* Temporary, until the new TLC will control the Tx protection */
s8
tx_protection
;
bool
tt_tx_protection
;
...
...
drivers/net/wireless/iwlwifi/mvm/testmode.h
0 → 100644
View file @
444474dd
/******************************************************************************
*
* 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.
*
*****************************************************************************/
#ifndef __IWL_MVM_TESTMODE_H__
#define __IWL_MVM_TESTMODE_H__
/**
* enum iwl_mvm_testmode_attrs - testmode attributes inside NL80211_ATTR_TESTDATA
* @IWL_MVM_TM_ATTR_UNSPEC: (invalid attribute)
* @IWL_MVM_TM_ATTR_CMD: sub command, see &enum iwl_mvm_testmode_commands (u32)
* @IWL_MVM_TM_ATTR_NOA_DURATION: requested NoA duration (u32)
* @IWL_MVM_TM_ATTR_BEACON_FILTER_STATE: beacon filter state (0 or 1, u32)
*/
enum
iwl_mvm_testmode_attrs
{
IWL_MVM_TM_ATTR_UNSPEC
,
IWL_MVM_TM_ATTR_CMD
,
IWL_MVM_TM_ATTR_NOA_DURATION
,
IWL_MVM_TM_ATTR_BEACON_FILTER_STATE
,
/* keep last */
NUM_IWL_MVM_TM_ATTRS
,
IWL_MVM_TM_ATTR_MAX
=
NUM_IWL_MVM_TM_ATTRS
-
1
,
};
/**
* enum iwl_mvm_testmode_commands - MVM testmode commands
* @IWL_MVM_TM_CMD_SET_NOA: set NoA on GO vif for testing
* @IWL_MVM_TM_CMD_SET_BEACON_FILTER: turn beacon filtering off/on
*/
enum
iwl_mvm_testmode_commands
{
IWL_MVM_TM_CMD_SET_NOA
,
IWL_MVM_TM_CMD_SET_BEACON_FILTER
,
};
#endif
/* __IWL_MVM_TESTMODE_H__ */
drivers/net/wireless/iwlwifi/mvm/time-event.c
View file @
444474dd
...
...
@@ -387,7 +387,8 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
void
iwl_mvm_protect_session
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
u32
duration
,
u32
min_duration
)
u32
duration
,
u32
min_duration
,
u32
max_delay
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm_time_event_data
*
te_data
=
&
mvmvif
->
time_event_data
;
...
...
@@ -426,7 +427,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
cpu_to_le32
(
iwl_read_prph
(
mvm
->
trans
,
DEVICE_SYSTEM_TIME_REG
));
time_cmd
.
max_frags
=
TE_V2_FRAG_NONE
;
time_cmd
.
max_delay
=
cpu_to_le32
(
500
);
time_cmd
.
max_delay
=
cpu_to_le32
(
max_delay
);
/* TODO: why do we need to interval = bi if it is not periodic? */
time_cmd
.
interval
=
cpu_to_le32
(
1
);
time_cmd
.
duration
=
cpu_to_le32
(
duration
);
...
...
drivers/net/wireless/iwlwifi/mvm/time-event.h
View file @
444474dd
...
...
@@ -123,6 +123,7 @@
* @duration: the duration of the session in TU.
* @min_duration: will start a new session if the current session will end
* in less than min_duration.
* @max_delay: maximum delay before starting the time event (in TU)
*
* This function can be used to start a session protection which means that the
* fw will stay on the channel for %duration_ms milliseconds. This function
...
...
@@ -133,7 +134,8 @@
*/
void
iwl_mvm_protect_session
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
u32
duration
,
u32
min_duration
);
u32
duration
,
u32
min_duration
,
u32
max_delay
);
/**
* iwl_mvm_stop_session_protection - cancel the session protection.
...
...
drivers/net/wireless/iwlwifi/mvm/tx.c
View file @
444474dd
...
...
@@ -417,7 +417,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
spin_unlock
(
&
mvmsta
->
lock
);
if
(
txq_id
<
IWL_MVM_FIRST_AGG_QUEUE
)
if
(
txq_id
<
mvm
->
first_agg_queue
)
atomic_inc
(
&
mvm
->
pending_frames
[
mvmsta
->
sta_id
]);
return
0
;
...
...
@@ -511,16 +511,10 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status)
}
#endif
/* CONFIG_IWLWIFI_DEBUG */
/**
* translate ucode response to mac80211 tx status control values
*/
static
void
iwl_mvm_hwrate_to_tx_control
(
u32
rate_n_flags
,
struct
ieee80211_tx_info
*
info
)
void
iwl_mvm_hwrate_to_tx_rate
(
u32
rate_n_flags
,
enum
ieee80211_band
band
,
struct
ieee80211_tx_rate
*
r
)
{
struct
ieee80211_tx_rate
*
r
=
&
info
->
status
.
rates
[
0
];
info
->
status
.
antenna
=
((
rate_n_flags
&
RATE_MCS_ANT_ABC_MSK
)
>>
RATE_MCS_ANT_POS
);
if
(
rate_n_flags
&
RATE_HT_MCS_GF_MSK
)
r
->
flags
|=
IEEE80211_TX_RC_GREEN_FIELD
;
switch
(
rate_n_flags
&
RATE_MCS_CHAN_WIDTH_MSK
)
{
...
...
@@ -549,10 +543,23 @@ static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags,
r
->
flags
|=
IEEE80211_TX_RC_VHT_MCS
;
}
else
{
r
->
idx
=
iwl_mvm_legacy_rate_to_mac80211_idx
(
rate_n_flags
,
info
->
band
);
band
);
}
}
/**
* translate ucode response to mac80211 tx status control values
*/
static
void
iwl_mvm_hwrate_to_tx_status
(
u32
rate_n_flags
,
struct
ieee80211_tx_info
*
info
)
{
struct
ieee80211_tx_rate
*
r
=
&
info
->
status
.
rates
[
0
];
info
->
status
.
antenna
=
((
rate_n_flags
&
RATE_MCS_ANT_ABC_MSK
)
>>
RATE_MCS_ANT_POS
);
iwl_mvm_hwrate_to_tx_rate
(
rate_n_flags
,
info
->
band
,
r
);
}
static
void
iwl_mvm_rx_tx_cmd_single
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_packet
*
pkt
)
{
...
...
@@ -602,11 +609,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
}
info
->
status
.
rates
[
0
].
count
=
tx_resp
->
failure_frame
+
1
;
iwl_mvm_hwrate_to_tx_
control
(
le32_to_cpu
(
tx_resp
->
initial_rate
),
info
);
iwl_mvm_hwrate_to_tx_
status
(
le32_to_cpu
(
tx_resp
->
initial_rate
),
info
);
/* Single frame failure in an AMPDU queue => send BAR */
if
(
txq_id
>=
IWL_MVM_FIRST_AGG_QUEUE
&&
if
(
txq_id
>=
mvm
->
first_agg_queue
&&
!
(
info
->
flags
&
IEEE80211_TX_STAT_ACK
))
info
->
flags
|=
IEEE80211_TX_STAT_AMPDU_NO_BACK
;
...
...
@@ -619,7 +626,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
ieee80211_tx_status_ni
(
mvm
->
hw
,
skb
);
}
if
(
txq_id
>=
IWL_MVM_FIRST_AGG_QUEUE
)
{
if
(
txq_id
>=
mvm
->
first_agg_queue
)
{
/* If this is an aggregation queue, we use the ssn since:
* ssn = wifi seq_num % 256.
* The seq_ctl is the sequence control of the packet to which
...
...
@@ -668,10 +675,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
iwl_mvm_check_ratid_empty
(
mvm
,
sta
,
tid
);
spin_unlock_bh
(
&
mvmsta
->
lock
);
}
#ifdef CONFIG_PM_SLEEP
mvmsta
->
last_seq_ctl
=
seq_ctl
;
#endif
}
else
{
sta
=
NULL
;
mvmsta
=
NULL
;
...
...
@@ -681,7 +684,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
* If the txq is not an AMPDU queue, there is no chance we freed
* several skbs. Check that out...
*/
if
(
txq_id
<
IWL_MVM_FIRST_AGG_QUEUE
&&
!
WARN_ON
(
skb_freed
>
1
)
&&
if
(
txq_id
<
mvm
->
first_agg_queue
&&
!
WARN_ON
(
skb_freed
>
1
)
&&
atomic_sub_and_test
(
skb_freed
,
&
mvm
->
pending_frames
[
sta_id
]))
{
if
(
mvmsta
)
{
/*
...
...
@@ -777,7 +780,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
u16
sequence
=
le16_to_cpu
(
pkt
->
hdr
.
sequence
);
struct
ieee80211_sta
*
sta
;
if
(
WARN_ON_ONCE
(
SEQ_TO_QUEUE
(
sequence
)
<
IWL_MVM_FIRST_AGG_QUEUE
))
if
(
WARN_ON_ONCE
(
SEQ_TO_QUEUE
(
sequence
)
<
mvm
->
first_agg_queue
))
return
;
if
(
WARN_ON_ONCE
(
tid
==
IWL_TID_NON_QOS
))
...
...
@@ -904,8 +907,8 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
info
->
flags
|=
IEEE80211_TX_STAT_AMPDU
;
info
->
status
.
ampdu_ack_len
=
ba_notif
->
txed_2_done
;
info
->
status
.
ampdu_len
=
ba_notif
->
txed
;
iwl_mvm_hwrate_to_tx_
control
(
tid_data
->
rate_n_flags
,
info
);
iwl_mvm_hwrate_to_tx_
status
(
tid_data
->
rate_n_flags
,
info
);
}
}
...
...
drivers/net/wireless/iwlwifi/mvm/utils.c
View file @
444474dd
...
...
@@ -466,7 +466,7 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm)
ofs
=
img
->
sec
[
IWL_UCODE_SECTION_DATA
].
offset
;
len
=
img
->
sec
[
IWL_UCODE_SECTION_DATA
].
len
;
buf
=
kzalloc
(
len
,
GFP_
KERNEL
);
buf
=
kzalloc
(
len
,
GFP_
ATOMIC
);
if
(
!
buf
)
return
;
...
...
drivers/net/wireless/iwlwifi/pcie/drv.c
View file @
444474dd
...
...
@@ -258,7 +258,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
#endif
/* CONFIG_IWLDVM */
#if IS_ENABLED(CONFIG_IWLMVM)
/* 7
00
0 Series */
/* 7
26
0 Series */
{
IWL_PCI_DEVICE
(
0x08B1
,
0x4070
,
iwl7260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x4170
,
iwl7260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B1
,
0x4060
,
iwl7260_2n_cfg
)},
...
...
@@ -308,6 +308,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{
IWL_PCI_DEVICE
(
0x08B3
,
0x8062
,
iwl3160_n_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B4
,
0x8270
,
iwl3160_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x08B3
,
0x8470
,
iwl3160_2ac_cfg
)},
/* 7265 Series */
{
IWL_PCI_DEVICE
(
0x095A
,
0x5010
,
iwl7265_2ac_cfg
)},
#endif
/* CONFIG_IWLMVM */
{
0
}
...
...
@@ -349,7 +352,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_drv_stop
(
trans_pcie
->
drv
);
out_free_trans:
iwl_trans_pcie_free
(
iwl_trans
);
pci_set_drvdata
(
pdev
,
NULL
);
return
ret
;
}
...
...
@@ -360,8 +362,6 @@ static void iwl_pci_remove(struct pci_dev *pdev)
iwl_drv_stop
(
trans_pcie
->
drv
);
iwl_trans_pcie_free
(
trans
);
pci_set_drvdata
(
pdev
,
NULL
);
}
#ifdef CONFIG_PM_SLEEP
...
...
drivers/net/wireless/iwlwifi/pcie/trans.c
View file @
444474dd
...
...
@@ -220,6 +220,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
iwl_set_bits_prph
(
trans
,
APMG_PCIDEV_STT_REG
,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS
);
/* 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
);
out:
...
...
@@ -443,22 +446,138 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
return
ret
;
}
static
int
iwl_pcie_secure_set
(
struct
iwl_trans
*
trans
,
int
cpu
)
{
int
shift_param
;
u32
address
;
int
ret
=
0
;
if
(
cpu
==
1
)
{
shift_param
=
0
;
address
=
CSR_SECURE_BOOT_CPU1_STATUS_ADDR
;
}
else
{
shift_param
=
16
;
address
=
CSR_SECURE_BOOT_CPU2_STATUS_ADDR
;
}
/* set CPU to started */
iwl_trans_set_bits_mask
(
trans
,
CSR_UCODE_LOAD_STATUS_ADDR
,
CSR_CPU_STATUS_LOADING_STARTED
<<
shift_param
,
1
);
/* set last complete descriptor number */
iwl_trans_set_bits_mask
(
trans
,
CSR_UCODE_LOAD_STATUS_ADDR
,
CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED
<<
shift_param
,
1
);
/* set last loaded block */
iwl_trans_set_bits_mask
(
trans
,
CSR_UCODE_LOAD_STATUS_ADDR
,
CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
<<
shift_param
,
1
);
/* image loading complete */
iwl_trans_set_bits_mask
(
trans
,
CSR_UCODE_LOAD_STATUS_ADDR
,
CSR_CPU_STATUS_LOADING_COMPLETED
<<
shift_param
,
1
);
/* set FH_TCSR_0_REG */
iwl_trans_set_bits_mask
(
trans
,
FH_TCSR_0_REG0
,
0x00400000
,
1
);
/* verify image verification started */
ret
=
iwl_poll_bit
(
trans
,
address
,
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS
,
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS
,
CSR_SECURE_TIME_OUT
);
if
(
ret
<
0
)
{
IWL_ERR
(
trans
,
"secure boot process didn't start
\n
"
);
return
ret
;
}
/* wait for image verification to complete */
ret
=
iwl_poll_bit
(
trans
,
address
,
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED
,
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED
,
CSR_SECURE_TIME_OUT
);
if
(
ret
<
0
)
{
IWL_ERR
(
trans
,
"Time out on secure boot process
\n
"
);
return
ret
;
}
return
0
;
}
static
int
iwl_pcie_load_given_ucode
(
struct
iwl_trans
*
trans
,
const
struct
fw_img
*
image
)
{
int
i
,
ret
=
0
;
for
(
i
=
0
;
i
<
IWL_UCODE_SECTION_MAX
;
i
++
)
{
IWL_DEBUG_FW
(
trans
,
"working with %s image
\n
"
,
image
->
is_secure
?
"Secured"
:
"Non Secured"
);
IWL_DEBUG_FW
(
trans
,
"working with %s CPU
\n
"
,
image
->
is_dual_cpus
?
"Dual"
:
"Single"
);
/* configure the ucode to be ready to get the secured image */
if
(
image
->
is_secure
)
{
/* set secure boot inspector addresses */
iwl_write32
(
trans
,
CSR_SECURE_INSPECTOR_CODE_ADDR
,
0
);
iwl_write32
(
trans
,
CSR_SECURE_INSPECTOR_DATA_ADDR
,
0
);
/* release CPU1 reset if secure inspector image burned in OTP */
iwl_write32
(
trans
,
CSR_RESET
,
0
);
}
/* load to FW the binary sections of CPU1 */
IWL_DEBUG_INFO
(
trans
,
"Loading CPU1
\n
"
);
for
(
i
=
0
;
i
<
IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU
;
i
++
)
{
if
(
!
image
->
sec
[
i
].
data
)
break
;
ret
=
iwl_pcie_load_section
(
trans
,
i
,
&
image
->
sec
[
i
]);
if
(
ret
)
return
ret
;
}
/* Remove all resets to allow NIC to operate */
iwl_write32
(
trans
,
CSR_RESET
,
0
);
/* configure the ucode to start secure process on CPU1 */
if
(
image
->
is_secure
)
{
/* config CPU1 to start secure protocol */
ret
=
iwl_pcie_secure_set
(
trans
,
1
);
if
(
ret
)
return
ret
;
}
else
{
/* Remove all resets to allow NIC to operate */
iwl_write32
(
trans
,
CSR_RESET
,
0
);
}
if
(
image
->
is_dual_cpus
)
{
/* load to FW the binary sections of CPU2 */
IWL_DEBUG_INFO
(
trans
,
"working w/ DUAL CPUs - Loading CPU2
\n
"
);
for
(
i
=
IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU
;
i
<
IWL_UCODE_SECTION_MAX
;
i
++
)
{
if
(
!
image
->
sec
[
i
].
data
)
break
;
ret
=
iwl_pcie_load_section
(
trans
,
i
,
&
image
->
sec
[
i
]);
if
(
ret
)
return
ret
;
}
if
(
image
->
is_secure
)
{
/* set CPU2 for secure protocol */
ret
=
iwl_pcie_secure_set
(
trans
,
2
);
if
(
ret
)
return
ret
;
}
}
return
0
;
}
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
View file @
444474dd
...
...
@@ -1539,6 +1539,9 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
"Clearing HCMD_ACTIVE for command %s
\n
"
,
get_cmd_string
(
trans_pcie
,
cmd
->
id
));
ret
=
-
ETIMEDOUT
;
iwl_op_mode_nic_error
(
trans
->
op_mode
);
goto
cancel
;
}
}
...
...
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