Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
e9c65316
Commit
e9c65316
authored
Feb 12, 2014
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
parents
b28a960c
3281bd4c
Changes
52
Show whitespace changes
Inline
Side-by-side
Showing
52 changed files
with
2784 additions
and
1095 deletions
+2784
-1095
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Kconfig
+14
-0
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/Makefile
+1
-1
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/iwlwifi/dvm/rs.c
+9
-10
drivers/net/wireless/iwlwifi/dvm/rs.h
drivers/net/wireless/iwlwifi/dvm/rs.h
+1
-1
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
+20
-3
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-8000.c
+132
-0
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-config.h
+18
-0
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-csr.h
+0
-32
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debug.h
+2
-0
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.c
+3
-2
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-fw.h
+5
-2
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.c
+15
-0
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-io.h
+2
-0
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+1
-5
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-op-mode.h
+23
-1
drivers/net/wireless/iwlwifi/iwl-phy-db.c
drivers/net/wireless/iwlwifi/iwl-phy-db.c
+2
-2
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-prph.h
+46
-0
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-trans.h
+38
-0
drivers/net/wireless/iwlwifi/mvm/Makefile
drivers/net/wireless/iwlwifi/mvm/Makefile
+1
-1
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
+86
-52
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/constants.h
+4
-0
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/d3.c
+2
-29
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+103
-9
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
+276
-9
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
+2
-15
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+5
-1
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+22
-11
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+23
-8
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
+120
-8
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/fw.c
+54
-13
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+46
-30
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
+407
-69
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
+105
-63
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/nvm.c
+19
-15
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/ops.c
+227
-30
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/power.c
+261
-124
drivers/net/wireless/iwlwifi/mvm/power_legacy.c
drivers/net/wireless/iwlwifi/mvm/power_legacy.c
+0
-319
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/quota.c
+99
-20
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.c
+12
-13
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rs.h
+1
-1
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/rx.c
+1
-7
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/scan.c
+10
-2
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.c
+153
-50
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/sta.h
+44
-18
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
+2
-0
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tt.c
+5
-2
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/tx.c
+23
-0
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/mvm/utils.c
+95
-4
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/drv.c
+82
-0
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
+1
-2
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/trans.c
+158
-109
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/iwlwifi/pcie/tx.c
+3
-2
No files found.
drivers/net/wireless/iwlwifi/Kconfig
View file @
e9c65316
...
...
@@ -68,6 +68,19 @@ config IWLWIFI_OPMODE_MODULAR
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
depends on IWLWIFI && IWLDVM=n && IWLMVM=n
config IWLWIFI_BCAST_FILTERING
bool "Enable broadcast filtering"
depends on IWLMVM
help
Say Y here to enable default bcast filtering configuration.
Enabling broadcast filtering will drop any incoming wireless
broadcast frames, except some very specific predefined
patterns (e.g. incoming arp requests).
If unsure, don't enable this option, as some programs might
expect incoming broadcasts for their normal operations.
menu "Debugging Options"
depends on IWLWIFI
...
...
@@ -111,6 +124,7 @@ config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
Enable use of experimental ucode for testing and debugging.
config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing"
depends on IWLWIFI
depends on EVENT_TRACING
...
...
drivers/net/wireless/iwlwifi/Makefile
View file @
e9c65316
...
...
@@ -8,7 +8,7 @@ iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o
iwlwifi-objs
+=
iwl-phy-db.o iwl-nvm-parse.o
iwlwifi-objs
+=
pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
iwlwifi-$(CONFIG_IWLDVM)
+=
iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o
iwlwifi-$(CONFIG_IWLMVM)
+=
iwl-7000.o
iwlwifi-$(CONFIG_IWLMVM)
+=
iwl-7000.o
iwl-8000.o
iwlwifi-objs
+=
$
(
iwlwifi-m
)
...
...
drivers/net/wireless/iwlwifi/dvm/rs.c
View file @
e9c65316
...
...
@@ -176,46 +176,46 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
* (2.4 GHz) band.
*/
static
s32
expected_tpt_legacy
[
IWL_RATE_COUNT
]
=
{
static
const
u16
expected_tpt_legacy
[
IWL_RATE_COUNT
]
=
{
7
,
13
,
35
,
58
,
40
,
57
,
72
,
98
,
121
,
154
,
177
,
186
,
0
};
static
s32
expected_tpt_siso20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
static
const
u16
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 */
};
static
s32
expected_tpt_siso40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
static
const
u16
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_mimo2_20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
static
const
u16
expected_tpt_mimo2_20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
74
,
0
,
123
,
155
,
179
,
214
,
236
,
244
,
251
},
/* Norm */
{
0
,
0
,
0
,
0
,
81
,
0
,
131
,
164
,
188
,
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*/
};
static
s32
expected_tpt_mimo2_40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
static
const
u16
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 */
};
static
s32
expected_tpt_mimo3_20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
static
const
u16
expected_tpt_mimo3_20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
99
,
0
,
153
,
186
,
208
,
239
,
256
,
263
,
268
},
/* Norm */
{
0
,
0
,
0
,
0
,
106
,
0
,
162
,
194
,
215
,
246
,
262
,
268
,
273
},
/* SGI */
{
0
,
0
,
0
,
0
,
134
,
0
,
249
,
346
,
431
,
574
,
685
,
732
,
775
},
/* AGG */
{
0
,
0
,
0
,
0
,
148
,
0
,
272
,
376
,
465
,
614
,
727
,
775
,
818
},
/* AGG+SGI */
};
static
s32
expected_tpt_mimo3_40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
static
const
u16
expected_tpt_mimo3_40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
152
,
0
,
211
,
239
,
255
,
279
,
290
,
294
,
297
},
/* Norm */
{
0
,
0
,
0
,
0
,
160
,
0
,
219
,
245
,
261
,
284
,
294
,
297
,
300
},
/* SGI */
{
0
,
0
,
0
,
0
,
254
,
0
,
443
,
584
,
695
,
868
,
984
,
1030
,
1070
},
/* AGG */
...
...
@@ -1111,7 +1111,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
struct
iwl_scale_tbl_info
*
tbl
)
{
/* Used to choose among HT tables */
s32
(
*
ht_tbl_pointer
)[
IWL_RATE_COUNT
];
const
u16
(
*
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
)))
{
...
...
@@ -1173,9 +1173,8 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
s32
active_sr
=
active_tbl
->
win
[
index
].
success_ratio
;
s32
active_tpt
=
active_tbl
->
expected_tpt
[
index
];
/* expected "search" throughput */
s32
*
tpt_tbl
=
tbl
->
expected_tpt
;
const
u16
*
tpt_tbl
=
tbl
->
expected_tpt
;
s32
new_rate
,
high
,
low
,
start_hi
;
u16
high_low
;
...
...
drivers/net/wireless/iwlwifi/dvm/rs.h
View file @
e9c65316
...
...
@@ -315,7 +315,7 @@ struct iwl_scale_tbl_info {
u8
is_dup
;
/* 1 = duplicated data streams */
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. */
const
u16
*
expected_tpt
;
/* throughput metrics; expected_tpt_G, etc. */
u32
current_rate
;
/* rate_n_flags, uCode API format */
struct
iwl_rate_scale_data
win
[
IWL_RATE_COUNT
];
/* rate histories */
};
...
...
drivers/net/wireless/iwlwifi/iwl-7000.c
View file @
e9c65316
...
...
@@ -71,8 +71,8 @@
#define IWL3160_UCODE_API_MAX 8
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK
7
#define IWL3160_UCODE_API_OK
7
#define IWL7260_UCODE_API_OK
8
#define IWL3160_UCODE_API_OK
8
/* Lowest firmware API version supported */
#define IWL7260_UCODE_API_MIN 7
...
...
@@ -95,6 +95,8 @@
#define IWL7265_FW_PRE "iwlwifi-7265-"
#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_7000 0
static
const
struct
iwl_base_params
iwl7000_base_params
=
{
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
,
.
num_of_queues
=
IWLAGN_NUM_QUEUES
,
...
...
@@ -120,7 +122,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl7000_base_params, \
.led_mode = IWL_LED_RF_STATE
.led_mode = IWL_LED_RF_STATE, \
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000
const
struct
iwl_cfg
iwl7260_2ac_cfg
=
{
...
...
@@ -194,6 +197,17 @@ const struct iwl_cfg iwl3160_n_cfg = {
.
host_interrupt_operation_mode
=
true
,
};
static
const
struct
iwl_pwr_tx_backoff
iwl7265_pwr_tx_backoffs
[]
=
{
{.
pwr
=
1600
,
.
backoff
=
0
},
{.
pwr
=
1300
,
.
backoff
=
467
},
{.
pwr
=
900
,
.
backoff
=
1900
},
{.
pwr
=
800
,
.
backoff
=
2630
},
{.
pwr
=
700
,
.
backoff
=
3720
},
{.
pwr
=
600
,
.
backoff
=
5550
},
{.
pwr
=
500
,
.
backoff
=
9350
},
{
0
},
};
const
struct
iwl_cfg
iwl7265_2ac_cfg
=
{
.
name
=
"Intel(R) Dual Band Wireless AC 7265"
,
.
fw_name_pre
=
IWL7265_FW_PRE
,
...
...
@@ -201,6 +215,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
.
ht_params
=
&
iwl7000_ht_params
,
.
nvm_ver
=
IWL7265_NVM_VERSION
,
.
nvm_calib_ver
=
IWL7265_TX_POWER_VERSION
,
.
pwr_tx_backoffs
=
iwl7265_pwr_tx_backoffs
,
};
const
struct
iwl_cfg
iwl7265_2n_cfg
=
{
...
...
@@ -210,6 +225,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
.
ht_params
=
&
iwl7000_ht_params
,
.
nvm_ver
=
IWL7265_NVM_VERSION
,
.
nvm_calib_ver
=
IWL7265_TX_POWER_VERSION
,
.
pwr_tx_backoffs
=
iwl7265_pwr_tx_backoffs
,
};
const
struct
iwl_cfg
iwl7265_n_cfg
=
{
...
...
@@ -219,6 +235,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
.
ht_params
=
&
iwl7000_ht_params
,
.
nvm_ver
=
IWL7265_NVM_VERSION
,
.
nvm_calib_ver
=
IWL7265_TX_POWER_VERSION
,
.
pwr_tx_backoffs
=
iwl7265_pwr_tx_backoffs
,
};
MODULE_FIRMWARE
(
IWL7260_MODULE_FIRMWARE
(
IWL7260_UCODE_API_OK
));
...
...
drivers/net/wireless/iwlwifi/iwl-8000.c
0 → 100644
View file @
e9c65316
/******************************************************************************
*
* 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) 2014 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) 2014 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include <linux/module.h>
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 8
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 8
/* Lowest firmware API version supported */
#define IWL8000_UCODE_API_MIN 8
/* NVM versions */
#define IWL8000_NVM_VERSION 0x0a1d
#define IWL8000_TX_POWER_VERSION 0xffff
/* meaningless */
#define IWL8000_FW_PRE "iwlwifi-8000-"
#define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
static
const
struct
iwl_base_params
iwl8000_base_params
=
{
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
,
.
num_of_queues
=
IWLAGN_NUM_QUEUES
,
.
pll_cfg_val
=
0
,
.
shadow_ram_support
=
true
,
.
led_compensation
=
57
,
.
wd_timeout
=
IWL_LONG_WD_TIMEOUT
,
.
max_event_log_size
=
512
,
.
shadow_reg_enable
=
true
,
.
pcie_l1_allowed
=
true
,
};
static
const
struct
iwl_ht_params
iwl8000_ht_params
=
{
.
ht40_bands
=
BIT
(
IEEE80211_BAND_2GHZ
)
|
BIT
(
IEEE80211_BAND_5GHZ
),
};
#define IWL_DEVICE_8000 \
.ucode_api_max = IWL8000_UCODE_API_MAX, \
.ucode_api_ok = IWL8000_UCODE_API_OK, \
.ucode_api_min = IWL8000_UCODE_API_MIN, \
.device_family = IWL_DEVICE_FAMILY_8000, \
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl8000_base_params, \
.led_mode = IWL_LED_RF_STATE, \
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000
const
struct
iwl_cfg
iwl8260_2ac_cfg
=
{
.
name
=
"Intel(R) Dual Band Wireless AC 8260"
,
.
fw_name_pre
=
IWL8000_FW_PRE
,
IWL_DEVICE_8000
,
.
ht_params
=
&
iwl8000_ht_params
,
.
nvm_ver
=
IWL8000_NVM_VERSION
,
.
nvm_calib_ver
=
IWL8000_TX_POWER_VERSION
,
};
const
struct
iwl_cfg
iwl8260_n_cfg
=
{
.
name
=
"Intel(R) Dual Band Wireless-AC 8260"
,
.
fw_name_pre
=
IWL8000_FW_PRE
,
IWL_DEVICE_8000
,
.
ht_params
=
&
iwl8000_ht_params
,
.
nvm_ver
=
IWL8000_NVM_VERSION
,
.
nvm_calib_ver
=
IWL8000_TX_POWER_VERSION
,
};
MODULE_FIRMWARE
(
IWL8000_MODULE_FIRMWARE
(
IWL8000_UCODE_API_OK
));
drivers/net/wireless/iwlwifi/iwl-config.h
View file @
e9c65316
...
...
@@ -84,6 +84,7 @@ enum iwl_device_family {
IWL_DEVICE_FAMILY_6050
,
IWL_DEVICE_FAMILY_6150
,
IWL_DEVICE_FAMILY_7000
,
IWL_DEVICE_FAMILY_8000
,
};
/*
...
...
@@ -192,6 +193,15 @@ struct iwl_eeprom_params {
bool
enhanced_txpower
;
};
/* Tx-backoff power threshold
* @pwr: The power limit in mw
* @backoff: The tx-backoff in uSec
*/
struct
iwl_pwr_tx_backoff
{
u32
pwr
;
u32
backoff
;
};
/**
* struct iwl_cfg
* @name: Offical name of the device
...
...
@@ -217,6 +227,9 @@ struct iwl_eeprom_params {
* @high_temp: Is this NIC is designated to be in high temperature.
* @host_interrupt_operation_mode: device needs host interrupt operation
* mode set
* @d0i3: device uses d0i3 instead of d3
* @nvm_hw_section_num: the ID of the HW NVM section
* @pwr_tx_backoffs: translation table between power limits and backoffs
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
...
...
@@ -247,6 +260,9 @@ struct iwl_cfg {
const
bool
internal_wimax_coex
;
const
bool
host_interrupt_operation_mode
;
bool
high_temp
;
bool
d0i3
;
u8
nvm_hw_section_num
;
const
struct
iwl_pwr_tx_backoff
*
pwr_tx_backoffs
;
};
/*
...
...
@@ -307,6 +323,8 @@ extern const struct iwl_cfg iwl3160_n_cfg;
extern
const
struct
iwl_cfg
iwl7265_2ac_cfg
;
extern
const
struct
iwl_cfg
iwl7265_2n_cfg
;
extern
const
struct
iwl_cfg
iwl7265_n_cfg
;
extern
const
struct
iwl_cfg
iwl8260_2ac_cfg
;
extern
const
struct
iwl_cfg
iwl8260_n_cfg
;
#endif
/* CONFIG_IWLMVM */
#endif
/* __IWL_CONFIG_H__ */
drivers/net/wireless/iwlwifi/iwl-csr.h
View file @
e9c65316
...
...
@@ -395,38 +395,6 @@
#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-debug.h
View file @
e9c65316
...
...
@@ -126,6 +126,7 @@ do { \
/* 0x00000F00 - 0x00000100 */
#define IWL_DL_POWER 0x00000100
#define IWL_DL_TEMP 0x00000200
#define IWL_DL_RPM 0x00000400
#define IWL_DL_SCAN 0x00000800
/* 0x0000F000 - 0x00001000 */
#define IWL_DL_ASSOC 0x00001000
...
...
@@ -189,5 +190,6 @@ do { \
#define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
#define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
#define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a)
#define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a)
#endif
drivers/net/wireless/iwlwifi/iwl-drv.c
View file @
e9c65316
...
...
@@ -128,7 +128,7 @@ struct iwl_drv {
const
struct
iwl_cfg
*
cfg
;
int
fw_index
;
/* firmware we're trying to load */
char
firmware_name
[
25
];
/* name of firmware file to load */
char
firmware_name
[
32
];
/* name of firmware file to load */
struct
completion
request_firmware_complete
;
...
...
@@ -237,7 +237,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
return
-
ENOENT
;
}
sprintf
(
drv
->
firmware_name
,
"%s%s%s"
,
name_pre
,
tag
,
".ucode"
);
snprintf
(
drv
->
firmware_name
,
sizeof
(
drv
->
firmware_name
),
"%s%s.ucode"
,
name_pre
,
tag
);
IWL_DEBUG_INFO
(
drv
,
"attempting to load firmware %s'%s'
\n
"
,
(
drv
->
fw_index
==
UCODE_EXPERIMENTAL_INDEX
)
...
...
drivers/net/wireless/iwlwifi/iwl-fw.h
View file @
e9c65316
...
...
@@ -95,6 +95,8 @@
* @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
* single bound interface).
* @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
* @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
* @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
*/
enum
iwl_ucode_tlv_flag
{
IWL_UCODE_TLV_FLAGS_PAN
=
BIT
(
0
),
...
...
@@ -119,6 +121,8 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_P2P_PS
=
BIT
(
21
),
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT
=
BIT
(
24
),
IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD
=
BIT
(
26
),
IWL_UCODE_TLV_FLAGS_BCAST_FILTERING
=
BIT
(
29
),
IWL_UCODE_TLV_FLAGS_GO_UAPSD
=
BIT
(
30
),
};
/* The default calibrate table size if not specified by firmware file */
...
...
@@ -160,8 +164,7 @@ 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 6
#define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2)
#define IWL_UCODE_SECTION_MAX 12
struct
iwl_ucode_capabilities
{
u32
max_probe_length
;
...
...
drivers/net/wireless/iwlwifi/iwl-io.c
View file @
e9c65316
...
...
@@ -130,6 +130,21 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
}
IWL_EXPORT_SYMBOL
(
iwl_write_prph
);
int
iwl_poll_prph_bit
(
struct
iwl_trans
*
trans
,
u32
addr
,
u32
bits
,
u32
mask
,
int
timeout
)
{
int
t
=
0
;
do
{
if
((
iwl_read_prph
(
trans
,
addr
)
&
mask
)
==
(
bits
&
mask
))
return
t
;
udelay
(
IWL_POLL_INTERVAL
);
t
+=
IWL_POLL_INTERVAL
;
}
while
(
t
<
timeout
);
return
-
ETIMEDOUT
;
}
void
iwl_set_bits_prph
(
struct
iwl_trans
*
trans
,
u32
ofs
,
u32
mask
)
{
unsigned
long
flags
;
...
...
drivers/net/wireless/iwlwifi/iwl-io.h
View file @
e9c65316
...
...
@@ -72,6 +72,8 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
u32
iwl_read_prph
(
struct
iwl_trans
*
trans
,
u32
ofs
);
void
iwl_write_prph
(
struct
iwl_trans
*
trans
,
u32
ofs
,
u32
val
);
int
iwl_poll_prph_bit
(
struct
iwl_trans
*
trans
,
u32
addr
,
u32
bits
,
u32
mask
,
int
timeout
);
void
iwl_set_bits_prph
(
struct
iwl_trans
*
trans
,
u32
ofs
,
u32
mask
);
void
iwl_set_bits_mask_prph
(
struct
iwl_trans
*
trans
,
u32
ofs
,
u32
bits
,
u32
mask
);
...
...
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
View file @
e9c65316
...
...
@@ -397,11 +397,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
iwl_init_sbands
(
dev
,
cfg
,
data
,
nvm_sw
,
sku
&
NVM_SKU_CAP_11AC_ENABLE
,
tx_chains
,
rx_chains
);
data
->
calib_version
=
255
;
/* TODO:
this value will prevent some checks from
failing, we need to check if this
field is still needed, and if it does,
where is it in the NVM*/
data
->
calib_version
=
255
;
return
data
;
}
...
...
drivers/net/wireless/iwlwifi/iwl-op-mode.h
View file @
e9c65316
...
...
@@ -131,6 +131,8 @@ struct iwl_cfg;
* @nic_config: configure NIC, called before firmware is started.
* May sleep
* @wimax_active: invoked when WiMax becomes active. May sleep
* @enter_d0i3: configure the fw to enter d0i3. May sleep.
* @exit_d0i3: configure the fw to exit d0i3. May sleep.
*/
struct
iwl_op_mode_ops
{
struct
iwl_op_mode
*
(
*
start
)(
struct
iwl_trans
*
trans
,
...
...
@@ -148,6 +150,8 @@ struct iwl_op_mode_ops {
void
(
*
cmd_queue_full
)(
struct
iwl_op_mode
*
op_mode
);
void
(
*
nic_config
)(
struct
iwl_op_mode
*
op_mode
);
void
(
*
wimax_active
)(
struct
iwl_op_mode
*
op_mode
);
int
(
*
enter_d0i3
)(
struct
iwl_op_mode
*
op_mode
);
int
(
*
exit_d0i3
)(
struct
iwl_op_mode
*
op_mode
);
};
int
iwl_opmode_register
(
const
char
*
name
,
const
struct
iwl_op_mode_ops
*
ops
);
...
...
@@ -155,7 +159,7 @@ void iwl_opmode_deregister(const char *name);
/**
* struct iwl_op_mode - operational mode
* @ops
-
pointer to its own ops
* @ops
:
pointer to its own ops
*
* This holds an implementation of the mac80211 / fw API.
*/
...
...
@@ -226,4 +230,22 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
op_mode
->
ops
->
wimax_active
(
op_mode
);
}
static
inline
int
iwl_op_mode_enter_d0i3
(
struct
iwl_op_mode
*
op_mode
)
{
might_sleep
();
if
(
!
op_mode
->
ops
->
enter_d0i3
)
return
0
;
return
op_mode
->
ops
->
enter_d0i3
(
op_mode
);
}
static
inline
int
iwl_op_mode_exit_d0i3
(
struct
iwl_op_mode
*
op_mode
)
{
might_sleep
();
if
(
!
op_mode
->
ops
->
exit_d0i3
)
return
0
;
return
op_mode
->
ops
->
exit_d0i3
(
op_mode
);
}
#endif
/* __iwl_op_mode_h__ */
drivers/net/wireless/iwlwifi/iwl-phy-db.c
View file @
e9c65316
...
...
@@ -72,7 +72,7 @@
#include "iwl-trans.h"
#define CHANNEL_NUM_SIZE 4
/* num of channels in calib_ch size */
#define IWL_NUM_PAPD_CH_GROUPS
4
#define IWL_NUM_PAPD_CH_GROUPS
7
#define IWL_NUM_TXP_CH_GROUPS 9
struct
iwl_phy_db_entry
{
...
...
@@ -383,7 +383,7 @@ static int iwl_phy_db_send_all_channel_groups(
if
(
!
entry
)
return
-
EINVAL
;
if
(
WARN_ON_ONCE
(
!
entry
->
size
)
)
if
(
!
entry
->
size
)
continue
;
/* Send the requested PHY DB section */
...
...
drivers/net/wireless/iwlwifi/iwl-prph.h
View file @
e9c65316
...
...
@@ -105,6 +105,13 @@
/* Device NMI register */
#define DEVICE_SET_NMI_REG 0x00a01c30
/*
* Device reset for family 8000
* write to bit 24 in order to reset the CPU
*/
#define RELEASE_CPU_RESET (0x300C)
#define RELEASE_CPU_RESET_BIT BIT(24)
/*****************************************************************************
* 7000/3000 series SHR DTS addresses *
*****************************************************************************/
...
...
@@ -281,4 +288,43 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
#define OSC_CLK (0xa04068)
#define OSC_CLK_FORCE_CONTROL (0x8)
/* SECURE boot registers */
#define LMPM_SECURE_BOOT_CONFIG_ADDR (0x100)
enum
secure_boot_config_reg
{
LMPM_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP
=
0x00000001
,
LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ
=
0x00000002
,
};
#define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30)
#define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34)
enum
secure_boot_status_reg
{
LMPM_SECURE_BOOT_CPU_STATUS_VERF_STATUS
=
0x00000001
,
LMPM_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED
=
0x00000002
,
LMPM_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS
=
0x00000004
,
LMPM_SECURE_BOOT_CPU_STATUS_VERF_FAIL
=
0x00000008
,
LMPM_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL
=
0x00000010
,
LMPM_SECURE_BOOT_STATUS_SUCCESS
=
0x00000003
,
};
#define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70)
enum
secure_load_status_reg
{
LMPM_CPU_UCODE_LOADING_STARTED
=
0x00000001
,
LMPM_CPU_HDRS_LOADING_COMPLETED
=
0x00000003
,
LMPM_CPU_UCODE_LOADING_COMPLETED
=
0x00000007
,
LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED
=
0x000000F8
,
LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
=
0x0000FF00
,
};
#define LMPM_SECURE_INSPECTOR_CODE_ADDR (0x1E38)
#define LMPM_SECURE_INSPECTOR_DATA_ADDR (0x1E3C)
#define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR (0x1E78)
#define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR (0x1E7C)
#define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000)
#define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000)
#define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000)
#define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400)
#define LMPM_SECURE_TIME_OUT (100)
#endif
/* __iwl_prph_h__ */
drivers/net/wireless/iwlwifi/iwl-trans.h
View file @
e9c65316
...
...
@@ -193,12 +193,23 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)
* @CMD_ASYNC: Return right away and don't wait for the response
* @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
* response. The caller needs to call iwl_free_resp when done.
* @CMD_HIGH_PRIO: The command is high priority - it goes to the front of the
* command queue, but after other high priority commands. valid only
* with CMD_ASYNC.
* @CMD_SEND_IN_IDLE: The command should be sent even when the trans is idle.
* @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle.
* @CMD_WAKE_UP_TRANS: The command response should wake up the trans
* (i.e. mark it as non-idle).
*/
enum
CMD_MODE
{
CMD_SYNC
=
0
,
CMD_ASYNC
=
BIT
(
0
),
CMD_WANT_SKB
=
BIT
(
1
),
CMD_SEND_IN_RFKILL
=
BIT
(
2
),
CMD_HIGH_PRIO
=
BIT
(
3
),
CMD_SEND_IN_IDLE
=
BIT
(
4
),
CMD_MAKE_TRANS_IDLE
=
BIT
(
5
),
CMD_WAKE_UP_TRANS
=
BIT
(
6
),
};
#define DEF_CMD_PAYLOAD_SIZE 320
...
...
@@ -335,6 +346,9 @@ enum iwl_d3_status {
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_FW_ERROR: the fw is in error state
* @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands
* are sent
* @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent
*/
enum
iwl_trans_status
{
STATUS_SYNC_HCMD_ACTIVE
,
...
...
@@ -343,6 +357,8 @@ enum iwl_trans_status {
STATUS_INT_ENABLED
,
STATUS_RFKILL
,
STATUS_FW_ERROR
,
STATUS_TRANS_GOING_IDLE
,
STATUS_TRANS_IDLE
,
};
/**
...
...
@@ -443,6 +459,11 @@ struct iwl_trans;
* @release_nic_access: let the NIC go to sleep. The "flags" parameter
* must be the same one that was sent before to the grab_nic_access.
* @set_bits_mask - set SRAM register according to value and mask.
* @ref: grab a reference to the transport/FW layers, disallowing
* certain low power states
* @unref: release a reference previously taken with @ref. Note that
* initially the reference count is 1, making an initial @unref
* necessary to allow low power states.
*/
struct
iwl_trans_ops
{
...
...
@@ -489,6 +510,8 @@ struct iwl_trans_ops {
unsigned
long
*
flags
);
void
(
*
set_bits_mask
)(
struct
iwl_trans
*
trans
,
u32
reg
,
u32
mask
,
u32
value
);
void
(
*
ref
)(
struct
iwl_trans
*
trans
);
void
(
*
unref
)(
struct
iwl_trans
*
trans
);
};
/**
...
...
@@ -523,6 +546,7 @@ enum iwl_trans_state {
* starting the firmware, used for tracing
* @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
* start of the 802.11 header in the @rx_mpdu_cmd
* @dflt_pwr_limit: default power limit fetched from the platform (ACPI)
*/
struct
iwl_trans
{
const
struct
iwl_trans_ops
*
ops
;
...
...
@@ -551,6 +575,8 @@ struct iwl_trans {
struct
lockdep_map
sync_cmd_lockdep_map
;
#endif
u64
dflt_pwr_limit
;
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char
trans_specific
[
0
]
__aligned
(
sizeof
(
void
*
));
...
...
@@ -627,6 +653,18 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
return
trans
->
ops
->
d3_resume
(
trans
,
status
,
test
);
}
static
inline
void
iwl_trans_ref
(
struct
iwl_trans
*
trans
)
{
if
(
trans
->
ops
->
ref
)
trans
->
ops
->
ref
(
trans
);
}
static
inline
void
iwl_trans_unref
(
struct
iwl_trans
*
trans
)
{
if
(
trans
->
ops
->
unref
)
trans
->
ops
->
unref
(
trans
);
}
static
inline
int
iwl_trans_send_cmd
(
struct
iwl_trans
*
trans
,
struct
iwl_host_cmd
*
cmd
)
{
...
...
drivers/net/wireless/iwlwifi/mvm/Makefile
View file @
e9c65316
...
...
@@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o
iwlmvm-y
+=
fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y
+=
utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y
+=
scan.o time-event.o rs.o
iwlmvm-y
+=
power.o
power_legacy.o
bt-coex.o
iwlmvm-y
+=
power.o bt-coex.o
iwlmvm-y
+=
led.o tt.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_PM_SLEEP)
+=
d3.o
...
...
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
View file @
e9c65316
...
...
@@ -378,7 +378,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
flags
=
iwlwifi_mod_params
.
bt_coex_active
?
BT_COEX_NW
:
BT_COEX_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_le32
(
BT_VALID_ENABLE
|
...
...
@@ -399,6 +398,9 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
BT_VALID_TXRX_MAX_FREQ_0
|
BT_VALID_SYNC_TO_SCO
);
if
(
IWL_MVM_BT_COEX_SYNC2SCO
)
bt_cmd
->
flags
|=
cpu_to_le32
(
BT_COEX_SYNC2SCO
);
if
(
mvm
->
cfg
->
bt_shared_single_ant
)
memcpy
(
&
bt_cmd
->
decision_lut
,
iwl_single_shared_ant
,
sizeof
(
iwl_single_shared_ant
));
...
...
@@ -489,8 +491,7 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
return
ret
;
}
static
int
iwl_mvm_bt_coex_reduced_txp
(
struct
iwl_mvm
*
mvm
,
u8
sta_id
,
bool
enable
)
int
iwl_mvm_bt_coex_reduced_txp
(
struct
iwl_mvm
*
mvm
,
u8
sta_id
,
bool
enable
)
{
struct
iwl_bt_coex_cmd
*
bt_cmd
;
/* Send ASYNC since this can be sent from an atomic context */
...
...
@@ -500,25 +501,16 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
.
dataflags
=
{
IWL_HCMD_DFL_DUP
,
},
.
flags
=
CMD_ASYNC
,
};
struct
ieee80211_sta
*
sta
;
struct
iwl_mvm_sta
*
mvmsta
;
int
ret
;
if
(
sta_id
==
IWL_MVM_STATION_COUNT
)
return
0
;
sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
));
/* This can happen if the station has been removed right now */
if
(
IS_ERR_OR_NULL
(
sta
))
mvmsta
=
iwl_mvm_sta_from_staid_protected
(
mvm
,
sta_id
);
if
(
!
mvmsta
)
return
0
;
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
);
/* nothing to do */
if
(
mvmsta
->
bt_reduced_txpower
==
enable
)
if
(
mvmsta
->
bt_reduced_txpower_dbg
||
mvmsta
->
bt_reduced_txpower
==
enable
)
return
0
;
bt_cmd
=
kzalloc
(
sizeof
(
*
bt_cmd
),
GFP_ATOMIC
);
...
...
@@ -552,6 +544,7 @@ struct iwl_bt_iterator_data {
bool
reduced_tx_power
;
struct
ieee80211_chanctx_conf
*
primary
;
struct
ieee80211_chanctx_conf
*
secondary
;
bool
primary_ll
;
};
static
inline
...
...
@@ -577,72 +570,113 @@ 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
;
u32
bt_activity_grading
;
int
ave_rssi
;
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
&&
vif
->
type
!=
NL80211_IFTYPE_AP
)
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_STATION
:
/* default smps_mode for BSS / P2P client is AUTOMATIC */
smps_mode
=
IEEE80211_SMPS_AUTOMATIC
;
data
->
num_bss_ifaces
++
;
/*
* Count unassoc BSSes, relax SMSP constraints
* and disable reduced Tx Power
*/
if
(
!
vif
->
bss_conf
.
assoc
)
{
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_BT_COEX
,
smps_mode
);
if
(
iwl_mvm_bt_coex_reduced_txp
(
mvm
,
mvmvif
->
ap_sta_id
,
false
))
IWL_ERR
(
mvm
,
"Couldn't send BT_CONFIG cmd
\n
"
);
return
;
}
break
;
case
NL80211_IFTYPE_AP
:
/* default smps_mode for AP / GO is OFF */
smps_mode
=
IEEE80211_SMPS_OFF
;
if
(
!
mvmvif
->
ap_ibss_active
)
{
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_BT_COEX
,
smps_mode
);
return
;
}
smps_mode
=
IEEE80211_SMPS_AUTOMATIC
;
/* the Ack / Cts kill mask must be default if AP / GO */
data
->
reduced_tx_power
=
false
;
break
;
default:
return
;
}
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
)
/* ... relax constraints and disable rssi events */
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_BT_COEX
,
smps_mode
);
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
)
iwl_mvm_bt_coex_enable_rssi_event
(
mvm
,
vif
,
false
,
0
);
return
;
}
/* SoftAP / GO will always be primary */
bt_activity_grading
=
le32_to_cpu
(
data
->
notif
->
bt_activity_grading
);
if
(
bt_activity_grading
>=
BT_HIGH_TRAFFIC
)
smps_mode
=
IEEE80211_SMPS_STATIC
;
else
if
(
bt_activity_grading
>=
BT_LOW_TRAFFIC
)
smps_mode
=
vif
->
type
==
NL80211_IFTYPE_AP
?
IEEE80211_SMPS_OFF
:
IEEE80211_SMPS_DYNAMIC
;
IWL_DEBUG_COEX
(
data
->
mvm
,
"mac %d: bt_status %d bt_activity_grading %d smps_req %d
\n
"
,
mvmvif
->
id
,
data
->
notif
->
bt_status
,
bt_activity_grading
,
smps_mode
);
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_BT_COEX
,
smps_mode
);
/* low latency is always primary */
if
(
iwl_mvm_vif_low_latency
(
mvmvif
))
{
data
->
primary_ll
=
true
;
data
->
secondary
=
data
->
primary
;
data
->
primary
=
chanctx_conf
;
}
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
(
chanctx_conf
==
data
->
primary
)
return
;
/* downgrade the current primary no matter what its type is */
if
(
!
data
->
primary_ll
)
{
/*
* downgrade the current primary no matter what its
* type is.
*/
data
->
secondary
=
data
->
primary
;
data
->
primary
=
chanctx_conf
;
return
;
}
else
{
/* there is low latency vif - we will be secondary */
data
->
secondary
=
chanctx_conf
;
}
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 */
/*
* STA / P2P Client, try to be primary if first vif. If we are in low
* latency mode, we are already in primary and just don't do much
*/
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
(
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 bt_activity_grading %d smps_req %d
\n
"
,
mvmvif
->
id
,
data
->
notif
->
bt_status
,
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
(
iwl_get_coex_type
(
mvm
,
vif
)
==
BT_COEX_LOOSE_LUT
||
mvm
->
cfg
->
bt_shared_single_ant
)
{
...
...
drivers/net/wireless/iwlwifi/mvm/constants.h
View file @
e9c65316
...
...
@@ -78,5 +78,9 @@
#define IWL_MVM_PS_SNOOZE_INTERVAL 25
#define IWL_MVM_PS_SNOOZE_WINDOW 50
#define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25
#define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64
#define IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR 24
/* TU */
#define IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR 24
/* TU */
#define IWL_MVM_BT_COEX_SYNC2SCO 1
#endif
/* __MVM_CONSTANTS_H */
drivers/net/wireless/iwlwifi/mvm/d3.c
View file @
e9c65316
...
...
@@ -963,7 +963,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
};
int
ret
,
i
;
int
len
__maybe_unused
;
u8
old_aux_sta_id
,
old_ap_sta_id
=
IWL_MVM_STATION_COUNT
;
if
(
!
wowlan
)
{
/*
...
...
@@ -980,8 +979,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mutex_lock
(
&
mvm
->
mutex
);
old_aux_sta_id
=
mvm
->
aux_sta
.
sta_id
;
/* see if there's only a single BSS vif and it's associated */
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
...
...
@@ -1066,16 +1063,6 @@ 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
...
...
@@ -1096,16 +1083,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvm
->
ptk_ivlen
=
0
;
mvm
->
ptk_icvlen
=
0
;
/*
* The D3 firmware still hardcodes the AP station ID for the
* BSS we're associated with as 0. As a result, we have to move
* the auxiliary station to ID 1 so the ID 0 remains free for
* the AP station for later.
* We set the sta_id to 1 here, and reset it to its previous
* value (that we stored above) later.
*/
mvm
->
aux_sta
.
sta_id
=
1
;
ret
=
iwl_mvm_load_d3_fw
(
mvm
);
if
(
ret
)
goto
out
;
...
...
@@ -1191,11 +1168,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
if
(
ret
)
goto
out
;
ret
=
iwl_mvm_power_update_device
_mode
(
mvm
);
ret
=
iwl_mvm_power_update_device
(
mvm
);
if
(
ret
)
goto
out
;
ret
=
iwl_mvm_power_update_m
ode
(
mvm
,
vif
);
ret
=
iwl_mvm_power_update_m
ac
(
mvm
,
vif
);
if
(
ret
)
goto
out
;
...
...
@@ -1222,10 +1199,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
iwl_trans_d3_suspend
(
mvm
->
trans
,
test
);
out:
mvm
->
aux_sta
.
sta_id
=
old_aux_sta_id
;
mvm_ap_sta
->
sta_id
=
old_ap_sta_id
;
mvmvif
->
ap_sta_id
=
old_ap_sta_id
;
if
(
ret
<
0
)
ieee80211_restart_hw
(
mvm
->
hw
);
out_noreset:
...
...
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
View file @
e9c65316
...
...
@@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
mutex_lock
(
&
mvm
->
mutex
);
iwl_dbgfs_update_pm
(
mvm
,
vif
,
param
,
val
);
ret
=
iwl_mvm_power_update_m
ode
(
mvm
,
vif
);
ret
=
iwl_mvm_power_update_m
ac
(
mvm
,
vif
);
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?:
count
;
...
...
@@ -202,7 +202,7 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
int
bufsz
=
sizeof
(
buf
);
int
pos
;
pos
=
iwl_mvm_power_dbgfs_read
(
mvm
,
vif
,
buf
,
bufsz
);
pos
=
iwl_mvm_power_
mac_
dbgfs_read
(
mvm
,
vif
,
buf
,
bufsz
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
...
...
@@ -225,6 +225,29 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
ap_sta_id
=
mvmvif
->
ap_sta_id
;
switch
(
ieee80211_vif_type_p2p
(
vif
))
{
case
NL80211_IFTYPE_ADHOC
:
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"type: ibss
\n
"
);
break
;
case
NL80211_IFTYPE_STATION
:
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"type: bss
\n
"
);
break
;
case
NL80211_IFTYPE_AP
:
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"type: ap
\n
"
);
break
;
case
NL80211_IFTYPE_P2P_CLIENT
:
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"type: p2p client
\n
"
);
break
;
case
NL80211_IFTYPE_P2P_GO
:
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"type: p2p go
\n
"
);
break
;
case
NL80211_IFTYPE_P2P_DEVICE
:
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"type: p2p dev
\n
"
);
break
;
default:
break
;
}
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"mac id/color: %d / %d
\n
"
,
mvmvif
->
id
,
mvmvif
->
color
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"bssid: %pM
\n
"
,
...
...
@@ -249,9 +272,10 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
struct
iwl_mvm_sta
*
mvm_sta
=
(
void
*
)
sta
->
drv_priv
;
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"ap_sta_id %d - reduced Tx power %d
\n
"
,
"ap_sta_id %d - reduced Tx power %d
force %d
\n
"
,
ap_sta_id
,
mvm_sta
->
bt_reduced_txpower
);
mvm_sta
->
bt_reduced_txpower
,
mvm_sta
->
bt_reduced_txpower_dbg
);
}
}
...
...
@@ -269,6 +293,36 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_reduced_txp_write
(
struct
ieee80211_vif
*
vif
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
mvm
;
struct
iwl_mvm_sta
*
mvmsta
;
bool
reduced_tx_power
;
int
ret
;
if
(
mvmvif
->
ap_sta_id
>=
ARRAY_SIZE
(
mvm
->
fw_id_to_mac_id
))
return
-
ENOTCONN
;
if
(
strtobool
(
buf
,
&
reduced_tx_power
)
!=
0
)
return
-
EINVAL
;
mutex_lock
(
&
mvm
->
mutex
);
mvmsta
=
iwl_mvm_sta_from_staid_protected
(
mvm
,
mvmvif
->
ap_sta_id
);
mvmsta
->
bt_reduced_txpower_dbg
=
false
;
ret
=
iwl_mvm_bt_coex_reduced_txp
(
mvm
,
mvmvif
->
ap_sta_id
,
reduced_tx_power
);
if
(
!
ret
)
mvmsta
->
bt_reduced_txpower_dbg
=
true
;
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?
:
count
;
}
static
void
iwl_dbgfs_update_bf
(
struct
ieee80211_vif
*
vif
,
enum
iwl_dbgfs_bf_mask
param
,
int
value
)
{
...
...
@@ -403,9 +457,9 @@ static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
mutex_lock
(
&
mvm
->
mutex
);
iwl_dbgfs_update_bf
(
vif
,
param
,
value
);
if
(
param
==
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
&&
!
value
)
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
);
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
,
CMD_SYNC
);
else
ret
=
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
);
ret
=
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
,
CMD_SYNC
);
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?:
count
;
...
...
@@ -460,6 +514,41 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_low_latency_write
(
struct
ieee80211_vif
*
vif
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
mvmvif
->
mvm
;
u8
value
;
int
ret
;
ret
=
kstrtou8
(
buf
,
0
,
&
value
);
if
(
ret
)
return
ret
;
if
(
value
>
1
)
return
-
EINVAL
;
mutex_lock
(
&
mvm
->
mutex
);
iwl_mvm_update_low_latency
(
mvm
,
vif
,
value
);
mutex_unlock
(
&
mvm
->
mutex
);
return
count
;
}
static
ssize_t
iwl_dbgfs_low_latency_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ieee80211_vif
*
vif
=
file
->
private_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
char
buf
[
3
];
buf
[
0
]
=
mvmvif
->
low_latency
?
'1'
:
'0'
;
buf
[
1
]
=
'\n'
;
buf
[
2
]
=
'\0'
;
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
sizeof
(
buf
));
}
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
...
...
@@ -473,6 +562,8 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
MVM_DEBUGFS_READ_FILE_OPS
(
mac_params
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
pm_params
,
32
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
bf_params
,
256
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
low_latency
,
10
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
reduced_txp
,
10
);
void
iwl_mvm_vif_dbgfs_register
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
...
...
@@ -496,15 +587,18 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return
;
}
if
(
iwlmvm_mod_params
.
power_scheme
!=
IWL_POWER_SCHEME_CAM
&&
if
((
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT
)
&&
iwlmvm_mod_params
.
power_scheme
!=
IWL_POWER_SCHEME_CAM
&&
((
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
)
||
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
vif
->
p2p
&&
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_P2P_PS
)))
MVM_DEBUGFS_ADD_FILE_VIF
(
pm_params
,
mvmvif
->
dbgfs_dir
,
S_IWUSR
|
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE_VIF
(
mac_params
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE_VIF
(
mac_params
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE_VIF
(
reduced_txp
,
mvmvif
->
dbgfs_dir
,
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE_VIF
(
low_latency
,
mvmvif
->
dbgfs_dir
,
S_IRUSR
|
S_IWUSR
);
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
&&
mvmvif
==
mvm
->
bf_allowed_vif
)
...
...
drivers/net/wireless/iwlwifi/mvm/debugfs.c
View file @
e9c65316
...
...
@@ -90,7 +90,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
static
ssize_t
iwl_dbgfs_sta_drain_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
i
eee80211_sta
*
sta
;
struct
i
wl_mvm_sta
*
mvm
sta
;
int
sta_id
,
drain
,
ret
;
if
(
!
mvm
->
ucode_loaded
||
mvm
->
cur_ucode
!=
IWL_UCODE_REGULAR
)
...
...
@@ -105,13 +105,12 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
mutex_lock
(
&
mvm
->
mutex
);
sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
));
if
(
IS_ERR_OR_NULL
(
sta
)
)
mvmsta
=
iwl_mvm_sta_from_staid_protected
(
mvm
,
sta_id
);
if
(
!
mvmsta
)
ret
=
-
ENOENT
;
else
ret
=
iwl_mvm_drain_sta
(
mvm
,
(
void
*
)
sta
->
drv_priv
,
drain
)
?
:
count
;
ret
=
iwl_mvm_drain_sta
(
mvm
,
mvmsta
,
drain
)
?
:
count
;
mutex_unlock
(
&
mvm
->
mutex
);
...
...
@@ -251,7 +250,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
}
mutex_lock
(
&
mvm
->
mutex
);
ret
=
iwl_mvm_power_update_device
_mode
(
mvm
);
ret
=
iwl_mvm_power_update_device
(
mvm
);
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
?:
count
;
...
...
@@ -600,6 +599,187 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
return
count
;
}
#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
static
ssize_t
iwl_dbgfs_bcast_filters_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
struct
iwl_bcast_filter_cmd
cmd
;
const
struct
iwl_fw_bcast_filter
*
filter
;
char
*
buf
;
int
bufsz
=
1024
;
int
i
,
j
,
pos
=
0
;
ssize_t
ret
;
buf
=
kzalloc
(
bufsz
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
mutex_lock
(
&
mvm
->
mutex
);
if
(
!
iwl_mvm_bcast_filter_build_cmd
(
mvm
,
&
cmd
))
{
ADD_TEXT
(
"None
\n
"
);
mutex_unlock
(
&
mvm
->
mutex
);
goto
out
;
}
mutex_unlock
(
&
mvm
->
mutex
);
for
(
i
=
0
;
cmd
.
filters
[
i
].
attrs
[
0
].
mask
;
i
++
)
{
filter
=
&
cmd
.
filters
[
i
];
ADD_TEXT
(
"Filter [%d]:
\n
"
,
i
);
ADD_TEXT
(
"
\t
Discard=%d
\n
"
,
filter
->
discard
);
ADD_TEXT
(
"
\t
Frame Type: %s
\n
"
,
filter
->
frame_type
?
"IPv4"
:
"Generic"
);
for
(
j
=
0
;
j
<
ARRAY_SIZE
(
filter
->
attrs
);
j
++
)
{
const
struct
iwl_fw_bcast_filter_attr
*
attr
;
attr
=
&
filter
->
attrs
[
j
];
if
(
!
attr
->
mask
)
break
;
ADD_TEXT
(
"
\t
Attr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x
\n
"
,
j
,
attr
->
offset
,
attr
->
offset_type
?
"IP End"
:
"Payload Start"
,
be32_to_cpu
(
attr
->
mask
),
be32_to_cpu
(
attr
->
val
),
le16_to_cpu
(
attr
->
reserved1
));
}
}
out:
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
kfree
(
buf
);
return
ret
;
}
static
ssize_t
iwl_dbgfs_bcast_filters_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
int
pos
,
next_pos
;
struct
iwl_fw_bcast_filter
filter
=
{};
struct
iwl_bcast_filter_cmd
cmd
;
u32
filter_id
,
attr_id
,
mask
,
value
;
int
err
=
0
;
if
(
sscanf
(
buf
,
"%d %hhi %hhi %n"
,
&
filter_id
,
&
filter
.
discard
,
&
filter
.
frame_type
,
&
pos
)
!=
3
)
return
-
EINVAL
;
if
(
filter_id
>=
ARRAY_SIZE
(
mvm
->
dbgfs_bcast_filtering
.
cmd
.
filters
)
||
filter
.
frame_type
>
BCAST_FILTER_FRAME_TYPE_IPV4
)
return
-
EINVAL
;
for
(
attr_id
=
0
;
attr_id
<
ARRAY_SIZE
(
filter
.
attrs
);
attr_id
++
)
{
struct
iwl_fw_bcast_filter_attr
*
attr
=
&
filter
.
attrs
[
attr_id
];
if
(
pos
>=
count
)
break
;
if
(
sscanf
(
&
buf
[
pos
],
"%hhi %hhi %i %i %n"
,
&
attr
->
offset
,
&
attr
->
offset_type
,
&
mask
,
&
value
,
&
next_pos
)
!=
4
)
return
-
EINVAL
;
attr
->
mask
=
cpu_to_be32
(
mask
);
attr
->
val
=
cpu_to_be32
(
value
);
if
(
mask
)
filter
.
num_attrs
++
;
pos
+=
next_pos
;
}
mutex_lock
(
&
mvm
->
mutex
);
memcpy
(
&
mvm
->
dbgfs_bcast_filtering
.
cmd
.
filters
[
filter_id
],
&
filter
,
sizeof
(
filter
));
/* send updated bcast filtering configuration */
if
(
mvm
->
dbgfs_bcast_filtering
.
override
&&
iwl_mvm_bcast_filter_build_cmd
(
mvm
,
&
cmd
))
err
=
iwl_mvm_send_cmd_pdu
(
mvm
,
BCAST_FILTER_CMD
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
mutex_unlock
(
&
mvm
->
mutex
);
return
err
?:
count
;
}
static
ssize_t
iwl_dbgfs_bcast_filters_macs_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_mvm
*
mvm
=
file
->
private_data
;
struct
iwl_bcast_filter_cmd
cmd
;
char
*
buf
;
int
bufsz
=
1024
;
int
i
,
pos
=
0
;
ssize_t
ret
;
buf
=
kzalloc
(
bufsz
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
mutex_lock
(
&
mvm
->
mutex
);
if
(
!
iwl_mvm_bcast_filter_build_cmd
(
mvm
,
&
cmd
))
{
ADD_TEXT
(
"None
\n
"
);
mutex_unlock
(
&
mvm
->
mutex
);
goto
out
;
}
mutex_unlock
(
&
mvm
->
mutex
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cmd
.
macs
);
i
++
)
{
const
struct
iwl_fw_bcast_mac
*
mac
=
&
cmd
.
macs
[
i
];
ADD_TEXT
(
"Mac [%d]: discard=%d attached_filters=0x%x
\n
"
,
i
,
mac
->
default_discard
,
mac
->
attached_filters
);
}
out:
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
kfree
(
buf
);
return
ret
;
}
static
ssize_t
iwl_dbgfs_bcast_filters_macs_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
iwl_bcast_filter_cmd
cmd
;
struct
iwl_fw_bcast_mac
mac
=
{};
u32
mac_id
,
attached_filters
;
int
err
=
0
;
if
(
!
mvm
->
bcast_filters
)
return
-
ENOENT
;
if
(
sscanf
(
buf
,
"%d %hhi %i"
,
&
mac_id
,
&
mac
.
default_discard
,
&
attached_filters
)
!=
3
)
return
-
EINVAL
;
if
(
mac_id
>=
ARRAY_SIZE
(
cmd
.
macs
)
||
mac
.
default_discard
>
1
||
attached_filters
>=
BIT
(
ARRAY_SIZE
(
cmd
.
filters
)))
return
-
EINVAL
;
mac
.
attached_filters
=
cpu_to_le16
(
attached_filters
);
mutex_lock
(
&
mvm
->
mutex
);
memcpy
(
&
mvm
->
dbgfs_bcast_filtering
.
cmd
.
macs
[
mac_id
],
&
mac
,
sizeof
(
mac
));
/* send updated bcast filtering configuration */
if
(
mvm
->
dbgfs_bcast_filtering
.
override
&&
iwl_mvm_bcast_filter_build_cmd
(
mvm
,
&
cmd
))
err
=
iwl_mvm_send_cmd_pdu
(
mvm
,
BCAST_FILTER_CMD
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
mutex_unlock
(
&
mvm
->
mutex
);
return
err
?:
count
;
}
#endif
#ifdef CONFIG_PM_SLEEP
static
ssize_t
iwl_dbgfs_d3_sram_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
...
...
@@ -658,15 +838,74 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
}
#endif
#define PRINT_MVM_REF(ref) do { \
if (test_bit(ref, mvm->ref_bitmap)) \
pos += scnprintf(buf + pos, bufsz - pos, \
"\t(0x%lx) %s\n", \
BIT(ref), #ref); \
} while (0)
static
ssize_t
iwl_dbgfs_d0i3_refs_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
[
256
];
const
size_t
bufsz
=
sizeof
(
buf
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"taken mvm refs: 0x%lx
\n
"
,
mvm
->
ref_bitmap
[
0
]);
PRINT_MVM_REF
(
IWL_MVM_REF_UCODE_DOWN
);
PRINT_MVM_REF
(
IWL_MVM_REF_SCAN
);
PRINT_MVM_REF
(
IWL_MVM_REF_ROC
);
PRINT_MVM_REF
(
IWL_MVM_REF_P2P_CLIENT
);
PRINT_MVM_REF
(
IWL_MVM_REF_AP_IBSS
);
PRINT_MVM_REF
(
IWL_MVM_REF_USER
);
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
}
static
ssize_t
iwl_dbgfs_d0i3_refs_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
unsigned
long
value
;
int
ret
;
bool
taken
;
ret
=
kstrtoul
(
buf
,
10
,
&
value
);
if
(
ret
<
0
)
return
ret
;
mutex_lock
(
&
mvm
->
mutex
);
taken
=
test_bit
(
IWL_MVM_REF_USER
,
mvm
->
ref_bitmap
);
if
(
value
==
1
&&
!
taken
)
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_USER
);
else
if
(
value
==
0
&&
taken
)
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_USER
);
else
ret
=
-
EINVAL
;
mutex_unlock
(
&
mvm
->
mutex
);
if
(
ret
<
0
)
return
ret
;
return
count
;
}
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
#define MVM_DEBUGFS_ADD_FILE
(name, parent, mode) do {
\
if (!debugfs_create_file(
#name
, mode, parent, mvm, \
#define MVM_DEBUGFS_ADD_FILE
_ALIAS(alias, name, parent, mode) do {
\
if (!debugfs_create_file(
alias
, mode, parent, mvm, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
/* Device wide debugfs entries */
MVM_DEBUGFS_WRITE_FILE_OPS
(
tx_flush
,
16
);
...
...
@@ -680,6 +919,12 @@ MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
MVM_DEBUGFS_WRITE_FILE_OPS
(
fw_restart
,
10
);
MVM_DEBUGFS_WRITE_FILE_OPS
(
fw_nmi
,
10
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
scan_ant_rxchain
,
8
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
d0i3_refs
,
8
);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
bcast_filters
,
256
);
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
bcast_filters_macs
,
256
);
#endif
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_READ_WRITE_FILE_OPS
(
d3_sram
,
8
);
...
...
@@ -687,6 +932,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
int
iwl_mvm_dbgfs_register
(
struct
iwl_mvm
*
mvm
,
struct
dentry
*
dbgfs_dir
)
{
struct
dentry
*
bcast_dir
__maybe_unused
;
char
buf
[
100
];
mvm
->
debugfs_dir
=
dbgfs_dir
;
...
...
@@ -705,6 +951,27 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE
(
fw_nmi
,
mvm
->
debugfs_dir
,
S_IWUSR
);
MVM_DEBUGFS_ADD_FILE
(
scan_ant_rxchain
,
mvm
->
debugfs_dir
,
S_IWUSR
|
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE
(
d0i3_refs
,
mvm
->
debugfs_dir
,
S_IRUSR
|
S_IWUSR
);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_BCAST_FILTERING
)
{
bcast_dir
=
debugfs_create_dir
(
"bcast_filtering"
,
mvm
->
debugfs_dir
);
if
(
!
bcast_dir
)
goto
err
;
if
(
!
debugfs_create_bool
(
"override"
,
S_IRUSR
|
S_IWUSR
,
bcast_dir
,
&
mvm
->
dbgfs_bcast_filtering
.
override
))
goto
err
;
MVM_DEBUGFS_ADD_FILE_ALIAS
(
"filters"
,
bcast_filters
,
bcast_dir
,
S_IWUSR
|
S_IRUSR
);
MVM_DEBUGFS_ADD_FILE_ALIAS
(
"macs"
,
bcast_filters_macs
,
bcast_dir
,
S_IWUSR
|
S_IRUSR
);
}
#endif
#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 @
e9c65316
...
...
@@ -70,37 +70,24 @@
/**
* enum iwl_bt_coex_flags - flags for BT_COEX command
* @BT_CH_PRIMARY_EN:
* @BT_CH_SECONDARY_EN:
* @BT_NOTIF_COEX_OFF:
* @BT_COEX_MODE_POS:
* @BT_COEX_MODE_MSK:
* @BT_COEX_DISABLE:
* @BT_COEX_2W:
* @BT_COEX_3W:
* @BT_COEX_NW:
* @BT_USE_DEFAULTS:
* @BT_SYNC_2_BT_DISABLE:
* @BT_COEX_CORUNNING_TBL_EN:
* @BT_COEX_SYNC2SCO:
*
* 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
),
BT_CH_SECONDARY_EN
=
BIT
(
1
),
BT_NOTIF_COEX_OFF
=
BIT
(
2
),
BT_COEX_MODE_POS
=
3
,
BT_COEX_MODE_MSK
=
BITS
(
3
)
<<
BT_COEX_MODE_POS
,
BT_COEX_DISABLE
=
0x0
<<
BT_COEX_MODE_POS
,
BT_COEX_2W
=
0x1
<<
BT_COEX_MODE_POS
,
BT_COEX_3W
=
0x2
<<
BT_COEX_MODE_POS
,
BT_COEX_NW
=
0x3
<<
BT_COEX_MODE_POS
,
BT_USE_DEFAULTS
=
BIT
(
6
),
BT_SYNC_2_BT_DISABLE
=
BIT
(
7
),
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
),
BT_COEX_SYNC2SCO
=
BIT
(
7
),
};
/*
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
View file @
e9c65316
...
...
@@ -231,8 +231,12 @@ enum iwl_wowlan_wakeup_filters {
IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT
=
BIT
(
8
),
IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS
=
BIT
(
9
),
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE
=
BIT
(
10
),
/* BIT(11) reserved */
IWL_WOWLAN_WAKEUP_REMOTE_TCP_EXTERNAL
=
BIT
(
11
),
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET
=
BIT
(
12
),
IWL_WOWLAN_WAKEUP_IOAC_MAGIC_PACKET
=
BIT
(
13
),
IWL_WOWLAN_WAKEUP_HOST_TIMER
=
BIT
(
14
),
IWL_WOWLAN_WAKEUP_RX_FRAME
=
BIT
(
15
),
IWL_WOWLAN_WAKEUP_BCN_FILTERING
=
BIT
(
16
),
};
/* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */
struct
iwl_wowlan_config_cmd
{
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
View file @
e9c65316
...
...
@@ -301,54 +301,65 @@ struct iwl_beacon_filter_cmd {
/* Beacon filtering and beacon abort */
#define IWL_BF_ENERGY_DELTA_DEFAULT 5
#define IWL_BF_ENERGY_DELTA_D0I3 20
#define IWL_BF_ENERGY_DELTA_MAX 255
#define IWL_BF_ENERGY_DELTA_MIN 0
#define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1
#define IWL_BF_ROAMING_ENERGY_DELTA_D0I3 20
#define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255
#define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0
#define IWL_BF_ROAMING_STATE_DEFAULT 72
#define IWL_BF_ROAMING_STATE_D0I3 72
#define IWL_BF_ROAMING_STATE_MAX 255
#define IWL_BF_ROAMING_STATE_MIN 0
#define IWL_BF_TEMP_THRESHOLD_DEFAULT 112
#define IWL_BF_TEMP_THRESHOLD_D0I3 112
#define IWL_BF_TEMP_THRESHOLD_MAX 255
#define IWL_BF_TEMP_THRESHOLD_MIN 0
#define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1
#define IWL_BF_TEMP_FAST_FILTER_D0I3 1
#define IWL_BF_TEMP_FAST_FILTER_MAX 255
#define IWL_BF_TEMP_FAST_FILTER_MIN 0
#define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5
#define IWL_BF_TEMP_SLOW_FILTER_D0I3 5
#define IWL_BF_TEMP_SLOW_FILTER_MAX 255
#define IWL_BF_TEMP_SLOW_FILTER_MIN 0
#define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1
#define IWL_BF_DEBUG_FLAG_DEFAULT 0
#define IWL_BF_DEBUG_FLAG_D0I3 0
#define IWL_BF_ESCAPE_TIMER_DEFAULT 50
#define IWL_BF_ESCAPE_TIMER_D0I3 1024
#define IWL_BF_ESCAPE_TIMER_MAX 1024
#define IWL_BF_ESCAPE_TIMER_MIN 0
#define IWL_BA_ESCAPE_TIMER_DEFAULT 6
#define IWL_BA_ESCAPE_TIMER_D0I3 6
#define IWL_BA_ESCAPE_TIMER_D3 9
#define IWL_BA_ESCAPE_TIMER_MAX 1024
#define IWL_BA_ESCAPE_TIMER_MIN 0
#define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1
#define IWL_BF_CMD_CONFIG
_DEFAULTS
\
.bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA
_DEFAULT),
\
#define IWL_BF_CMD_CONFIG
(mode)
\
.bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA
## mode),
\
.bf_roaming_energy_delta = \
cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA
_DEFAULT),
\
.bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE
_DEFAULT),
\
.bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD
_DEFAULT),
\
.bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER
_DEFAULT),
\
.bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER
_DEFAULT),
\
.bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG
_DEFAULT),
\
.bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER
_DEFAULT),
\
.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER
_DEFAULT
)
cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA
## mode),
\
.bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE
## mode),
\
.bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD
## mode),
\
.bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER
## mode),
\
.bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER
## mode),
\
.bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG
## mode),
\
.bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER
## mode),
\
.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER
## mode
)
#define IWL_BF_CMD_CONFIG_DEFAULTS IWL_BF_CMD_CONFIG(_DEFAULT)
#define IWL_BF_CMD_CONFIG_D0I3 IWL_BF_CMD_CONFIG(_D0I3)
#endif
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
View file @
e9c65316
...
...
@@ -199,11 +199,14 @@ enum iwl_sta_modify_flag {
* @STA_SLEEP_STATE_AWAKE:
* @STA_SLEEP_STATE_PS_POLL:
* @STA_SLEEP_STATE_UAPSD:
* @STA_SLEEP_STATE_MOREDATA: set more-data bit on
* (last) released frame
*/
enum
iwl_sta_sleep_flag
{
STA_SLEEP_STATE_AWAKE
=
0
,
STA_SLEEP_STATE_PS_POLL
=
BIT
(
0
),
STA_SLEEP_STATE_UAPSD
=
BIT
(
1
),
STA_SLEEP_STATE_MOREDATA
=
BIT
(
2
),
};
/* STA ID and color bits definitions */
...
...
@@ -318,13 +321,15 @@ struct iwl_mvm_add_sta_cmd_v5 {
}
__packed
;
/* ADD_STA_CMD_API_S_VER_5 */
/**
* struct iwl_mvm_add_sta_cmd_v
6
- Add / modify a station
* VER_
6
of this command is quite similar to VER_5 except
* struct iwl_mvm_add_sta_cmd_v
7
- Add / modify a station
* VER_
7
of this command is quite similar to VER_5 except
* exclusion of all fields related to the security key installation.
* It only differs from VER_6 by the "awake_acs" field that is
* reserved and ignored in VER_6.
*/
struct
iwl_mvm_add_sta_cmd_v
6
{
struct
iwl_mvm_add_sta_cmd_v
7
{
u8
add_modify
;
u8
reserved1
;
u8
awake_acs
;
__le16
tid_disable_tx
;
__le32
mac_id_n_color
;
u8
addr
[
ETH_ALEN
];
/* _STA_ID_MODIFY_INFO_API_S_VER_1 */
...
...
@@ -342,7 +347,7 @@ struct iwl_mvm_add_sta_cmd_v6 {
__le16
assoc_id
;
__le16
beamform_flags
;
__le32
tfd_queue_msk
;
}
__packed
;
/* ADD_STA_CMD_API_S_VER_
6
*/
}
__packed
;
/* ADD_STA_CMD_API_S_VER_
7
*/
/**
* struct iwl_mvm_add_sta_key_cmd - add/modify sta key
...
...
@@ -432,5 +437,15 @@ struct iwl_mvm_wep_key_cmd {
struct
iwl_mvm_wep_key
wep_key
[
0
];
}
__packed
;
/* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */
/**
* struct iwl_mvm_eosp_notification - EOSP notification from firmware
* @remain_frame_count: # of frames remaining, non-zero if SP was cut
* short by GO absence
* @sta_id: station ID
*/
struct
iwl_mvm_eosp_notification
{
__le32
remain_frame_count
;
__le32
sta_id
;
}
__packed
;
/* UAPSD_EOSP_NTFY_API_S_VER_1 */
#endif
/* __fw_api_sta_h__ */
drivers/net/wireless/iwlwifi/mvm/fw-api.h
View file @
e9c65316
...
...
@@ -163,6 +163,7 @@ enum {
TX_ANT_CONFIGURATION_CMD
=
0x98
,
BT_CONFIG
=
0x9b
,
STATISTICS_NOTIFICATION
=
0x9d
,
EOSP_NOTIFICATION
=
0x9e
,
REDUCE_TX_POWER_CMD
=
0x9f
,
/* RF-KILL commands and notifications */
...
...
@@ -190,6 +191,7 @@ enum {
REPLY_DEBUG_CMD
=
0xf0
,
DEBUG_LOG_MSG
=
0xf7
,
BCAST_FILTER_CMD
=
0xcf
,
MCAST_FILTER_CMD
=
0xd0
,
/* D3 commands/notifications */
...
...
@@ -197,6 +199,7 @@ enum {
PROT_OFFLOAD_CONFIG_CMD
=
0xd4
,
OFFLOADS_QUERY_CMD
=
0xd5
,
REMOTE_WAKE_CONFIG_CMD
=
0xd6
,
D0I3_END_CMD
=
0xed
,
/* for WoWLAN in particular */
WOWLAN_PATTERNS
=
0xe0
,
...
...
@@ -303,6 +306,7 @@ struct iwl_phy_cfg_cmd {
#define PHY_CFG_RX_CHAIN_B BIT(13)
#define PHY_CFG_RX_CHAIN_C BIT(14)
#define NVM_MAX_NUM_SECTIONS 11
/* Target of the NVM_ACCESS_CMD */
enum
{
...
...
@@ -313,14 +317,9 @@ enum {
/* Section types for NVM_ACCESS_CMD */
enum
{
NVM_SECTION_TYPE_HW
=
0
,
NVM_SECTION_TYPE_SW
,
NVM_SECTION_TYPE_PAPD
,
NVM_SECTION_TYPE_BT
,
NVM_SECTION_TYPE_CALIBRATION
,
NVM_SECTION_TYPE_PRODUCTION
,
NVM_SECTION_TYPE_POST_FCS_CALIB
,
NVM_NUM_OF_SECTIONS
,
NVM_SECTION_TYPE_SW
=
1
,
NVM_SECTION_TYPE_CALIBRATION
=
4
,
NVM_SECTION_TYPE_PRODUCTION
=
5
,
};
/**
...
...
@@ -412,6 +411,35 @@ struct mvm_alive_resp {
__le32
scd_base_ptr
;
/* SRAM address for SCD */
}
__packed
;
/* ALIVE_RES_API_S_VER_1 */
struct
mvm_alive_resp_ver2
{
__le16
status
;
__le16
flags
;
u8
ucode_minor
;
u8
ucode_major
;
__le16
id
;
u8
api_minor
;
u8
api_major
;
u8
ver_subtype
;
u8
ver_type
;
u8
mac
;
u8
opt
;
__le16
reserved2
;
__le32
timestamp
;
__le32
error_event_table_ptr
;
/* SRAM address for error log */
__le32
log_event_table_ptr
;
/* SRAM address for LMAC event log */
__le32
cpu_register_ptr
;
__le32
dbgm_config_ptr
;
__le32
alive_counter_ptr
;
__le32
scd_base_ptr
;
/* SRAM address for SCD */
__le32
st_fwrd_addr
;
/* pointer to Store and forward */
__le32
st_fwrd_size
;
u8
umac_minor
;
/* UMAC version: minor */
u8
umac_major
;
/* UMAC version: major */
__le16
umac_id
;
/* UMAC version: id */
__le32
error_info_addr
;
/* SRAM address for UMAC error log */
__le32
dbg_print_buff_addr
;
}
__packed
;
/* ALIVE_RES_API_S_VER_2 */
/* Error response/notification */
enum
{
FW_ERR_UNKNOWN_CMD
=
0x0
,
...
...
@@ -1159,6 +1187,90 @@ struct iwl_mcast_filter_cmd {
u8
addr_list
[
0
];
}
__packed
;
/* MCAST_FILTERING_CMD_API_S_VER_1 */
#define MAX_BCAST_FILTERS 8
#define MAX_BCAST_FILTER_ATTRS 2
/**
* enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet
* @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start.
* @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e.
* start of ip payload).
*/
enum
iwl_mvm_bcast_filter_attr_offset
{
BCAST_FILTER_OFFSET_PAYLOAD_START
=
0
,
BCAST_FILTER_OFFSET_IP_END
=
1
,
};
/**
* struct iwl_fw_bcast_filter_attr - broadcast filter attribute
* @offset_type: &enum iwl_mvm_bcast_filter_attr_offset.
* @offset: starting offset of this pattern.
* @val: value to match - big endian (MSB is the first
* byte to match from offset pos).
* @mask: mask to match (big endian).
*/
struct
iwl_fw_bcast_filter_attr
{
u8
offset_type
;
u8
offset
;
__le16
reserved1
;
__be32
val
;
__be32
mask
;
}
__packed
;
/* BCAST_FILTER_ATT_S_VER_1 */
/**
* enum iwl_mvm_bcast_filter_frame_type - filter frame type
* @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames.
* @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames
*/
enum
iwl_mvm_bcast_filter_frame_type
{
BCAST_FILTER_FRAME_TYPE_ALL
=
0
,
BCAST_FILTER_FRAME_TYPE_IPV4
=
1
,
};
/**
* struct iwl_fw_bcast_filter - broadcast filter
* @discard: discard frame (1) or let it pass (0).
* @frame_type: &enum iwl_mvm_bcast_filter_frame_type.
* @num_attrs: number of valid attributes in this filter.
* @attrs: attributes of this filter. a filter is considered matched
* only when all its attributes are matched (i.e. AND relationship)
*/
struct
iwl_fw_bcast_filter
{
u8
discard
;
u8
frame_type
;
u8
num_attrs
;
u8
reserved1
;
struct
iwl_fw_bcast_filter_attr
attrs
[
MAX_BCAST_FILTER_ATTRS
];
}
__packed
;
/* BCAST_FILTER_S_VER_1 */
/**
* struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration.
* @default_discard: default action for this mac (discard (1) / pass (0)).
* @attached_filters: bitmap of relevant filters for this mac.
*/
struct
iwl_fw_bcast_mac
{
u8
default_discard
;
u8
reserved1
;
__le16
attached_filters
;
}
__packed
;
/* BCAST_MAC_CONTEXT_S_VER_1 */
/**
* struct iwl_bcast_filter_cmd - broadcast filtering configuration
* @disable: enable (0) / disable (1)
* @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS)
* @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER)
* @filters: broadcast filters
* @macs: broadcast filtering configuration per-mac
*/
struct
iwl_bcast_filter_cmd
{
u8
disable
;
u8
max_bcast_filters
;
u8
max_macs
;
u8
reserved1
;
struct
iwl_fw_bcast_filter
filters
[
MAX_BCAST_FILTERS
];
struct
iwl_fw_bcast_mac
macs
[
NUM_MAC_INDEX_DRIVER
];
}
__packed
;
/* BCAST_FILTERING_HCMD_API_S_VER_1 */
struct
mvm_statistics_dbg
{
__le32
burst_check
;
__le32
burst_count
;
...
...
drivers/net/wireless/iwlwifi/mvm/fw.c
View file @
e9c65316
...
...
@@ -110,18 +110,46 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
container_of
(
notif_wait
,
struct
iwl_mvm
,
notif_wait
);
struct
iwl_mvm_alive_data
*
alive_data
=
data
;
struct
mvm_alive_resp
*
palive
;
struct
mvm_alive_resp_ver2
*
palive2
;
if
(
iwl_rx_packet_payload_len
(
pkt
)
==
sizeof
(
*
palive
))
{
palive
=
(
void
*
)
pkt
->
data
;
mvm
->
error_event_table
=
le32_to_cpu
(
palive
->
error_event_table_ptr
);
mvm
->
support_umac_log
=
false
;
mvm
->
error_event_table
=
le32_to_cpu
(
palive
->
error_event_table_ptr
);
mvm
->
log_event_table
=
le32_to_cpu
(
palive
->
log_event_table_ptr
);
alive_data
->
scd_base_addr
=
le32_to_cpu
(
palive
->
scd_base_ptr
);
alive_data
->
valid
=
le16_to_cpu
(
palive
->
status
)
==
IWL_ALIVE_STATUS_OK
;
alive_data
->
valid
=
le16_to_cpu
(
palive
->
status
)
==
IWL_ALIVE_STATUS_OK
;
IWL_DEBUG_FW
(
mvm
,
"Alive
ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X
\n
"
,
"Alive VER1
ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X
\n
"
,
le16_to_cpu
(
palive
->
status
),
palive
->
ver_type
,
palive
->
ver_subtype
,
palive
->
flags
);
}
else
{
palive2
=
(
void
*
)
pkt
->
data
;
mvm
->
support_umac_log
=
true
;
mvm
->
error_event_table
=
le32_to_cpu
(
palive2
->
error_event_table_ptr
);
mvm
->
log_event_table
=
le32_to_cpu
(
palive2
->
log_event_table_ptr
);
alive_data
->
scd_base_addr
=
le32_to_cpu
(
palive2
->
scd_base_ptr
);
mvm
->
umac_error_event_table
=
le32_to_cpu
(
palive2
->
error_info_addr
);
alive_data
->
valid
=
le16_to_cpu
(
palive2
->
status
)
==
IWL_ALIVE_STATUS_OK
;
IWL_DEBUG_FW
(
mvm
,
"Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X
\n
"
,
le16_to_cpu
(
palive2
->
status
),
palive2
->
ver_type
,
palive2
->
ver_subtype
,
palive2
->
flags
);
IWL_DEBUG_FW
(
mvm
,
"UMAC version: Major - 0x%x, Minor - 0x%x
\n
"
,
palive2
->
umac_major
,
palive2
->
umac_minor
);
}
return
true
;
}
...
...
@@ -439,10 +467,23 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto
error
;
}
ret
=
iwl_mvm_power_update_device_mode
(
mvm
);
/* Initialize tx backoffs to the minimal possible */
iwl_mvm_tt_tx_backoff
(
mvm
,
0
);
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT
))
{
ret
=
iwl_power_legacy_set_cam_mode
(
mvm
);
if
(
ret
)
goto
error
;
}
ret
=
iwl_mvm_power_update_device
(
mvm
);
if
(
ret
)
goto
error
;
/* allow FW/transport low power modes if not during restart */
if
(
!
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
))
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_UCODE_DOWN
);
IWL_DEBUG_INFO
(
mvm
,
"RT uCode started.
\n
"
);
return
0
;
error:
...
...
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
View file @
e9c65316
...
...
@@ -90,6 +90,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
{
struct
iwl_mvm_mac_iface_iterator_data
*
data
=
_data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
u16
min_bi
;
/* Skip the interface for which we are trying to assign a tsf_id */
if
(
vif
==
data
->
vif
)
...
...
@@ -114,43 +115,58 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
switch
(
data
->
vif
->
type
)
{
case
NL80211_IFTYPE_STATION
:
/*
* The new interface is
client, so if the existing one
*
we're iterating is an AP, and both interfaces have the
*
same beacon interval, the same TSF should be used to
*
avoid drift between the new client and existing AP,
*
the existing AP will get drift updates from the new
*
client context in this case
* The new interface is
a client, so if the one we're iterating
*
is an AP, and the beacon interval of the AP is a multiple or
*
divisor of the beacon interval of the client, the same TSF
*
should be used to avoid drift between the new client and
*
existing AP. The existing AP will get drift updates from the
*
new client context in this case.
*/
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
if
(
data
->
preferred_tsf
==
NUM_TSF_IDS
&&
test_bit
(
mvmvif
->
tsf_id
,
data
->
available_tsf_ids
)
&&
(
vif
->
bss_conf
.
beacon_int
==
data
->
vif
->
bss_conf
.
beacon_int
))
{
if
(
vif
->
type
!=
NL80211_IFTYPE_AP
||
data
->
preferred_tsf
!=
NUM_TSF_IDS
||
!
test_bit
(
mvmvif
->
tsf_id
,
data
->
available_tsf_ids
))
break
;
min_bi
=
min
(
data
->
vif
->
bss_conf
.
beacon_int
,
vif
->
bss_conf
.
beacon_int
);
if
(
!
min_bi
)
break
;
if
((
data
->
vif
->
bss_conf
.
beacon_int
-
vif
->
bss_conf
.
beacon_int
)
%
min_bi
==
0
)
{
data
->
preferred_tsf
=
mvmvif
->
tsf_id
;
return
;
}
}
break
;
case
NL80211_IFTYPE_AP
:
/*
* The new interface is AP/GO, so i
n case both interfaces
*
have the same beacon interval, it should get drift
*
updates from an existing client or use the same
*
TSF as an existing GO. There's no drift between
*
TSFs internally but if they used different TSFs
*
then a new client MAC could update one of them
*
and
cause drift that way.
* The new interface is AP/GO, so i
f its beacon interval is a
*
multiple or a divisor of the beacon interval of an existing
*
interface, it should get drift updates from an existing
*
client or use the same TSF as an existing GO. There's no
*
drift between TSFs internally but if they used different
*
TSFs then a new client MAC could update one of them and
* cause drift that way.
*/
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
||
vif
->
type
==
NL80211_IFTYPE_AP
)
{
if
(
data
->
preferred_tsf
==
NUM_TSF_IDS
&&
test_bit
(
mvmvif
->
tsf_id
,
data
->
available_tsf_ids
)
&&
(
vif
->
bss_conf
.
beacon_int
==
data
->
vif
->
bss_conf
.
beacon_int
))
{
if
((
vif
->
type
!=
NL80211_IFTYPE_AP
&&
vif
->
type
!=
NL80211_IFTYPE_STATION
)
||
data
->
preferred_tsf
!=
NUM_TSF_IDS
||
!
test_bit
(
mvmvif
->
tsf_id
,
data
->
available_tsf_ids
))
break
;
min_bi
=
min
(
data
->
vif
->
bss_conf
.
beacon_int
,
vif
->
bss_conf
.
beacon_int
);
if
(
!
min_bi
)
break
;
if
((
data
->
vif
->
bss_conf
.
beacon_int
-
vif
->
bss_conf
.
beacon_int
)
%
min_bi
==
0
)
{
data
->
preferred_tsf
=
mvmvif
->
tsf_id
;
return
;
}
}
break
;
default:
/*
...
...
drivers/net/wireless/iwlwifi/mvm/mac80211.c
View file @
e9c65316
...
...
@@ -66,6 +66,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/if_arp.h>
#include <net/mac80211.h>
#include <net/tcp.h>
...
...
@@ -128,6 +129,117 @@ static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = {
};
#endif
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
/*
* Use the reserved field to indicate magic values.
* these values will only be used internally by the driver,
* and won't make it to the fw (reserved will be 0).
* BC_FILTER_MAGIC_IP - configure the val of this attribute to
* be the vif's ip address. in case there is not a single
* ip address (0, or more than 1), this attribute will
* be skipped.
* BC_FILTER_MAGIC_MAC - set the val of this attribute to
* the LSB bytes of the vif's mac address
*/
enum
{
BC_FILTER_MAGIC_NONE
=
0
,
BC_FILTER_MAGIC_IP
,
BC_FILTER_MAGIC_MAC
,
};
static
const
struct
iwl_fw_bcast_filter
iwl_mvm_default_bcast_filters
[]
=
{
{
/* arp */
.
discard
=
0
,
.
frame_type
=
BCAST_FILTER_FRAME_TYPE_ALL
,
.
attrs
=
{
{
/* frame type - arp, hw type - ethernet */
.
offset_type
=
BCAST_FILTER_OFFSET_PAYLOAD_START
,
.
offset
=
sizeof
(
rfc1042_header
),
.
val
=
cpu_to_be32
(
0x08060001
),
.
mask
=
cpu_to_be32
(
0xffffffff
),
},
{
/* arp dest ip */
.
offset_type
=
BCAST_FILTER_OFFSET_PAYLOAD_START
,
.
offset
=
sizeof
(
rfc1042_header
)
+
2
+
sizeof
(
struct
arphdr
)
+
ETH_ALEN
+
sizeof
(
__be32
)
+
ETH_ALEN
,
.
mask
=
cpu_to_be32
(
0xffffffff
),
/* mark it as special field */
.
reserved1
=
cpu_to_le16
(
BC_FILTER_MAGIC_IP
),
},
},
},
{
/* dhcp offer bcast */
.
discard
=
0
,
.
frame_type
=
BCAST_FILTER_FRAME_TYPE_IPV4
,
.
attrs
=
{
{
/* udp dest port - 68 (bootp client)*/
.
offset_type
=
BCAST_FILTER_OFFSET_IP_END
,
.
offset
=
offsetof
(
struct
udphdr
,
dest
),
.
val
=
cpu_to_be32
(
0x00440000
),
.
mask
=
cpu_to_be32
(
0xffff0000
),
},
{
/* dhcp - lsb bytes of client hw address */
.
offset_type
=
BCAST_FILTER_OFFSET_IP_END
,
.
offset
=
38
,
.
mask
=
cpu_to_be32
(
0xffffffff
),
/* mark it as special field */
.
reserved1
=
cpu_to_le16
(
BC_FILTER_MAGIC_MAC
),
},
},
},
/* last filter must be empty */
{},
};
#endif
void
iwl_mvm_ref
(
struct
iwl_mvm
*
mvm
,
enum
iwl_mvm_ref_type
ref_type
)
{
if
(
!
mvm
->
trans
->
cfg
->
d0i3
)
return
;
IWL_DEBUG_RPM
(
mvm
,
"Take mvm reference - type %d
\n
"
,
ref_type
);
WARN_ON
(
test_and_set_bit
(
ref_type
,
mvm
->
ref_bitmap
));
iwl_trans_ref
(
mvm
->
trans
);
}
void
iwl_mvm_unref
(
struct
iwl_mvm
*
mvm
,
enum
iwl_mvm_ref_type
ref_type
)
{
if
(
!
mvm
->
trans
->
cfg
->
d0i3
)
return
;
IWL_DEBUG_RPM
(
mvm
,
"Leave mvm reference - type %d
\n
"
,
ref_type
);
WARN_ON
(
!
test_and_clear_bit
(
ref_type
,
mvm
->
ref_bitmap
));
iwl_trans_unref
(
mvm
->
trans
);
}
static
void
iwl_mvm_unref_all_except
(
struct
iwl_mvm
*
mvm
,
enum
iwl_mvm_ref_type
ref
)
{
int
i
;
if
(
!
mvm
->
trans
->
cfg
->
d0i3
)
return
;
for_each_set_bit
(
i
,
mvm
->
ref_bitmap
,
IWL_MVM_REF_COUNT
)
{
if
(
ref
==
i
)
continue
;
IWL_DEBUG_RPM
(
mvm
,
"Cleanup: remove mvm ref type %d
\n
"
,
i
);
clear_bit
(
i
,
mvm
->
ref_bitmap
);
iwl_trans_unref
(
mvm
->
trans
);
}
}
static
void
iwl_mvm_reset_phy_ctxts
(
struct
iwl_mvm
*
mvm
)
{
int
i
;
...
...
@@ -203,6 +315,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw
->
wiphy
->
regulatory_flags
|=
REGULATORY_CUSTOM_REG
|
REGULATORY_DISABLE_BEACON_HINTS
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_GO_UAPSD
)
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_AP_UAPSD
;
hw
->
wiphy
->
iface_combinations
=
iwl_mvm_iface_combinations
;
hw
->
wiphy
->
n_iface_combinations
=
ARRAY_SIZE
(
iwl_mvm_iface_combinations
);
...
...
@@ -289,6 +404,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
}
#endif
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
/* assign default bcast filtering configuration */
mvm
->
bcast_filters
=
iwl_mvm_default_bcast_filters
;
#endif
ret
=
iwl_mvm_leds_init
(
mvm
);
if
(
ret
)
return
ret
;
...
...
@@ -305,6 +425,9 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
struct
sk_buff
*
skb
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
ieee80211_sta
*
sta
=
control
->
sta
;
struct
ieee80211_tx_info
*
info
=
IEEE80211_SKB_CB
(
skb
);
struct
ieee80211_hdr
*
hdr
=
(
void
*
)
skb
->
data
;
if
(
iwl_mvm_is_radio_killed
(
mvm
))
{
IWL_DEBUG_DROP
(
mvm
,
"Dropping - RF/CT KILL
\n
"
);
...
...
@@ -315,8 +438,16 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
!
test_bit
(
IWL_MVM_STATUS_ROC_RUNNING
,
&
mvm
->
status
))
goto
drop
;
if
(
control
->
sta
)
{
if
(
iwl_mvm_tx_skb
(
mvm
,
skb
,
control
->
sta
))
/* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
if
(
unlikely
(
info
->
flags
&
IEEE80211_TX_CTL_NO_PS_BUFFER
&&
ieee80211_is_mgmt
(
hdr
->
frame_control
)
&&
!
ieee80211_is_deauth
(
hdr
->
frame_control
)
&&
!
ieee80211_is_disassoc
(
hdr
->
frame_control
)
&&
!
ieee80211_is_action
(
hdr
->
frame_control
)))
sta
=
NULL
;
if
(
sta
)
{
if
(
iwl_mvm_tx_skb
(
mvm
,
skb
,
sta
))
goto
drop
;
return
;
}
...
...
@@ -416,6 +547,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_mvm_cleanup_iterator
,
mvm
);
mvm
->
p2p_device_vif
=
NULL
;
mvm
->
d0i3_ap_sta_id
=
IWL_MVM_STATION_COUNT
;
iwl_mvm_reset_phy_ctxts
(
mvm
);
memset
(
mvm
->
fw_key_table
,
0
,
sizeof
(
mvm
->
fw_key_table
));
...
...
@@ -423,6 +555,10 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
ieee80211_wake_queues
(
mvm
->
hw
);
/* cleanup all stale references (scan, roc), but keep the
* ucode_down ref until reconfig is complete */
iwl_mvm_unref_all_except
(
mvm
,
IWL_MVM_REF_UCODE_DOWN
);
mvm
->
vif_count
=
0
;
mvm
->
rx_ba_sessions
=
0
;
}
...
...
@@ -457,6 +593,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
IWL_ERR
(
mvm
,
"Failed to update quotas after restart (%d)
\n
"
,
ret
);
/* allow transport/FW low power modes */
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_UCODE_DOWN
);
mutex_unlock
(
&
mvm
->
mutex
);
}
...
...
@@ -464,9 +603,14 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
flush_work
(
&
mvm
->
d0i3_exit_work
);
flush_work
(
&
mvm
->
async_handlers_wk
);
mutex_lock
(
&
mvm
->
mutex
);
/* disallow low power states when the FW is down */
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_UCODE_DOWN
);
/* async_handlers_wk is now blocked */
/*
...
...
@@ -492,14 +636,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync
(
&
mvm
->
async_handlers_wk
);
}
static
void
iwl_mvm_power_update_iterator
(
void
*
data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm
*
mvm
=
data
;
iwl_mvm_power_update_mode
(
mvm
,
vif
);
}
static
struct
iwl_mvm_phy_ctxt
*
iwl_mvm_get_free_phy_ctxt
(
struct
iwl_mvm
*
mvm
)
{
u16
i
;
...
...
@@ -567,7 +703,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
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
);
qmask
,
ieee80211_vif_type_p2p
(
vif
));
if
(
ret
)
{
IWL_ERR
(
mvm
,
"Failed to allocate bcast sta
\n
"
);
goto
out_release
;
...
...
@@ -581,10 +718,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if
(
ret
)
goto
out_release
;
iwl_mvm_power_disable
(
mvm
,
vif
);
ret
=
iwl_mvm_power_update_mac
(
mvm
,
vif
);
if
(
ret
)
goto
out_release
;
/* beacon filtering */
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
);
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
,
CMD_SYNC
);
if
(
ret
)
goto
out_remove_mac
;
...
...
@@ -643,11 +782,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if
(
vif
->
type
!=
NL80211_IFTYPE_P2P_DEVICE
)
mvm
->
vif_count
--
;
/* TODO: remove this when legacy PM will be discarded */
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_update_iterator
,
mvm
);
iwl_mvm_mac_ctxt_release
(
mvm
,
vif
);
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
...
...
@@ -736,11 +870,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
if
(
mvm
->
vif_count
&&
vif
->
type
!=
NL80211_IFTYPE_P2P_DEVICE
)
mvm
->
vif_count
--
;
/* TODO: remove this when legacy PM will be discarded */
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_update_iterator
,
mvm
);
iwl_mvm_power_update_mac
(
mvm
,
vif
);
iwl_mvm_mac_ctxt_remove
(
mvm
,
vif
);
out_release:
...
...
@@ -858,6 +988,156 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
*
total_flags
=
0
;
}
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
struct
iwl_bcast_iter_data
{
struct
iwl_mvm
*
mvm
;
struct
iwl_bcast_filter_cmd
*
cmd
;
u8
current_filter
;
};
static
void
iwl_mvm_set_bcast_filter
(
struct
ieee80211_vif
*
vif
,
const
struct
iwl_fw_bcast_filter
*
in_filter
,
struct
iwl_fw_bcast_filter
*
out_filter
)
{
struct
iwl_fw_bcast_filter_attr
*
attr
;
int
i
;
memcpy
(
out_filter
,
in_filter
,
sizeof
(
*
out_filter
));
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
out_filter
->
attrs
);
i
++
)
{
attr
=
&
out_filter
->
attrs
[
i
];
if
(
!
attr
->
mask
)
break
;
switch
(
attr
->
reserved1
)
{
case
cpu_to_le16
(
BC_FILTER_MAGIC_IP
):
if
(
vif
->
bss_conf
.
arp_addr_cnt
!=
1
)
{
attr
->
mask
=
0
;
continue
;
}
attr
->
val
=
vif
->
bss_conf
.
arp_addr_list
[
0
];
break
;
case
cpu_to_le16
(
BC_FILTER_MAGIC_MAC
):
attr
->
val
=
*
(
__be32
*
)
&
vif
->
addr
[
2
];
break
;
default:
break
;
}
attr
->
reserved1
=
0
;
out_filter
->
num_attrs
++
;
}
}
static
void
iwl_mvm_bcast_filter_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_bcast_iter_data
*
data
=
_data
;
struct
iwl_mvm
*
mvm
=
data
->
mvm
;
struct
iwl_bcast_filter_cmd
*
cmd
=
data
->
cmd
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_fw_bcast_mac
*
bcast_mac
;
int
i
;
if
(
WARN_ON
(
mvmvif
->
id
>=
ARRAY_SIZE
(
cmd
->
macs
)))
return
;
bcast_mac
=
&
cmd
->
macs
[
mvmvif
->
id
];
/* enable filtering only for associated stations */
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
!
vif
->
bss_conf
.
assoc
)
return
;
bcast_mac
->
default_discard
=
1
;
/* copy all configured filters */
for
(
i
=
0
;
mvm
->
bcast_filters
[
i
].
attrs
[
0
].
mask
;
i
++
)
{
/*
* Make sure we don't exceed our filters limit.
* if there is still a valid filter to be configured,
* be on the safe side and just allow bcast for this mac.
*/
if
(
WARN_ON_ONCE
(
data
->
current_filter
>=
ARRAY_SIZE
(
cmd
->
filters
)))
{
bcast_mac
->
default_discard
=
0
;
bcast_mac
->
attached_filters
=
0
;
break
;
}
iwl_mvm_set_bcast_filter
(
vif
,
&
mvm
->
bcast_filters
[
i
],
&
cmd
->
filters
[
data
->
current_filter
]);
/* skip current filter if it contains no attributes */
if
(
!
cmd
->
filters
[
data
->
current_filter
].
num_attrs
)
continue
;
/* attach the filter to current mac */
bcast_mac
->
attached_filters
|=
cpu_to_le16
(
BIT
(
data
->
current_filter
));
data
->
current_filter
++
;
}
}
bool
iwl_mvm_bcast_filter_build_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_bcast_filter_cmd
*
cmd
)
{
struct
iwl_bcast_iter_data
iter_data
=
{
.
mvm
=
mvm
,
.
cmd
=
cmd
,
};
memset
(
cmd
,
0
,
sizeof
(
*
cmd
));
cmd
->
max_bcast_filters
=
ARRAY_SIZE
(
cmd
->
filters
);
cmd
->
max_macs
=
ARRAY_SIZE
(
cmd
->
macs
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* use debugfs filters/macs if override is configured */
if
(
mvm
->
dbgfs_bcast_filtering
.
override
)
{
memcpy
(
cmd
->
filters
,
&
mvm
->
dbgfs_bcast_filtering
.
cmd
.
filters
,
sizeof
(
cmd
->
filters
));
memcpy
(
cmd
->
macs
,
&
mvm
->
dbgfs_bcast_filtering
.
cmd
.
macs
,
sizeof
(
cmd
->
macs
));
return
true
;
}
#endif
/* if no filters are configured, do nothing */
if
(
!
mvm
->
bcast_filters
)
return
false
;
/* configure and attach these filters for each associated sta vif */
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_bcast_filter_iterator
,
&
iter_data
);
return
true
;
}
static
int
iwl_mvm_configure_bcast_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_bcast_filter_cmd
cmd
;
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_BCAST_FILTERING
))
return
0
;
if
(
!
iwl_mvm_bcast_filter_build_cmd
(
mvm
,
&
cmd
))
return
0
;
return
iwl_mvm_send_cmd_pdu
(
mvm
,
BCAST_FILTER_CMD
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
}
#else
static
inline
int
iwl_mvm_configure_bcast_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
return
0
;
}
#endif
static
void
iwl_mvm_bss_info_changed_station
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_bss_conf
*
bss_conf
,
...
...
@@ -910,6 +1190,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
iwl_mvm_sf_update
(
mvm
,
vif
,
false
);
iwl_mvm_power_vif_assoc
(
mvm
,
vif
);
if
(
vif
->
p2p
)
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_P2P_CLIENT
);
}
else
if
(
mvmvif
->
ap_sta_id
!=
IWL_MVM_STATION_COUNT
)
{
/*
* If update fails - SF might be running in associated
...
...
@@ -922,27 +1204,25 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
ret
=
iwl_mvm_rm_sta_id
(
mvm
,
vif
,
mvmvif
->
ap_sta_id
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to remove AP station
\n
"
);
if
(
mvm
->
d0i3_ap_sta_id
==
mvmvif
->
ap_sta_id
)
mvm
->
d0i3_ap_sta_id
=
IWL_MVM_STATION_COUNT
;
mvmvif
->
ap_sta_id
=
IWL_MVM_STATION_COUNT
;
/* remove quota for this interface */
ret
=
iwl_mvm_update_quotas
(
mvm
,
NULL
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to update quotas
\n
"
);
if
(
vif
->
p2p
)
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_P2P_CLIENT
);
}
iwl_mvm_recalc_multicast
(
mvm
);
iwl_mvm_configure_bcast_filter
(
mvm
,
vif
);
/* reset rssi values */
mvmvif
->
bf_data
.
ave_beacon_signal
=
0
;
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT
))
{
/* Workaround for FW bug, otherwise FW disables device
* power save upon disassociation
*/
ret
=
iwl_mvm_power_update_mode
(
mvm
,
vif
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to update power mode
\n
"
);
}
iwl_mvm_bt_coex_vif_change
(
mvm
);
iwl_mvm_update_smps
(
mvm
,
vif
,
IWL_MVM_SMPS_REQ_TT
,
IEEE80211_SMPS_AUTOMATIC
);
...
...
@@ -955,7 +1235,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
&
mvmvif
->
time_event_data
);
}
else
if
(
changes
&
(
BSS_CHANGED_PS
|
BSS_CHANGED_P2P_PS
|
BSS_CHANGED_QOS
))
{
ret
=
iwl_mvm_power_update_m
ode
(
mvm
,
vif
);
ret
=
iwl_mvm_power_update_m
ac
(
mvm
,
vif
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to update power mode
\n
"
);
}
...
...
@@ -969,10 +1249,15 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_DEBUG_MAC80211
(
mvm
,
"cqm info_changed"
);
/* reset cqm events tracking */
mvmvif
->
bf_data
.
last_cqm_event
=
0
;
ret
=
iwl_mvm_update_beacon_filter
(
mvm
,
vif
);
ret
=
iwl_mvm_update_beacon_filter
(
mvm
,
vif
,
false
,
CMD_SYNC
);
if
(
ret
)
IWL_ERR
(
mvm
,
"failed to update CQM thresholds
\n
"
);
}
if
(
changes
&
BSS_CHANGED_ARP_FILTER
)
{
IWL_DEBUG_MAC80211
(
mvm
,
"arp filter changed"
);
iwl_mvm_configure_bcast_filter
(
mvm
,
vif
);
}
}
static
int
iwl_mvm_start_ap_ibss
(
struct
ieee80211_hw
*
hw
,
...
...
@@ -1006,8 +1291,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
if
(
ret
)
goto
out_remove
;
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 */
ret
=
iwl_mvm_send_bcast_sta
(
mvm
,
vif
,
&
mvmvif
->
bcast_sta
);
...
...
@@ -1019,7 +1302,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
/* power updated needs to be done before quotas */
mvm
->
bound_vif_cnt
++
;
iwl_mvm_power_update_
binding
(
mvm
,
vif
,
true
);
iwl_mvm_power_update_
mac
(
mvm
,
vif
);
ret
=
iwl_mvm_update_quotas
(
mvm
,
vif
);
if
(
ret
)
...
...
@@ -1029,6 +1312,8 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
if
(
vif
->
p2p
&&
mvm
->
p2p_device_vif
)
iwl_mvm_mac_ctxt_changed
(
mvm
,
mvm
->
p2p_device_vif
);
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_AP_IBSS
);
iwl_mvm_bt_coex_vif_change
(
mvm
);
mutex_unlock
(
&
mvm
->
mutex
);
...
...
@@ -1036,7 +1321,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
out_quota_failed:
mvm
->
bound_vif_cnt
--
;
iwl_mvm_power_update_
binding
(
mvm
,
vif
,
false
);
iwl_mvm_power_update_
mac
(
mvm
,
vif
);
mvmvif
->
ap_ibss_active
=
false
;
iwl_mvm_send_rm_bcast_sta
(
mvm
,
&
mvmvif
->
bcast_sta
);
out_unbind:
...
...
@@ -1062,6 +1347,8 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
iwl_mvm_bt_coex_vif_change
(
mvm
);
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_AP_IBSS
);
/* 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
);
...
...
@@ -1071,7 +1358,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
iwl_mvm_binding_remove_vif
(
mvm
,
vif
);
mvm
->
bound_vif_cnt
--
;
iwl_mvm_power_update_
binding
(
mvm
,
vif
,
false
);
iwl_mvm_power_update_
mac
(
mvm
,
vif
);
iwl_mvm_mac_ctxt_remove
(
mvm
,
vif
);
...
...
@@ -1085,26 +1372,20 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
u32
changes
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
enum
ieee80211_bss_change
ht_change
=
BSS_CHANGED_ERP_CTS_PROT
|
BSS_CHANGED_HT
|
BSS_CHANGED_BANDWIDTH
;
int
ret
;
/* Changes will be applied when the AP/IBSS is started */
if
(
!
mvmvif
->
ap_ibss_active
)
return
;
if
(
changes
&
ht_change
)
{
ret
=
iwl_mvm_mac_ctxt_changed
(
mvm
,
vif
);
if
(
ret
)
if
(
changes
&
(
BSS_CHANGED_ERP_CTS_PROT
|
BSS_CHANGED_HT
|
BSS_CHANGED_BANDWIDTH
)
&&
iwl_mvm_mac_ctxt_changed
(
mvm
,
vif
)
)
IWL_ERR
(
mvm
,
"failed to update MAC %pM
\n
"
,
vif
->
addr
);
}
/* Need to send a new beacon template to the FW */
if
(
changes
&
BSS_CHANGED_BEACON
)
{
if
(
iwl_mvm_mac_ctxt_beacon_changed
(
mvm
,
vif
))
if
(
changes
&
BSS_CHANGED_BEACON
&&
iwl_mvm_mac_ctxt_beacon_changed
(
mvm
,
vif
))
IWL_WARN
(
mvm
,
"Failed updating beacon data
\n
"
);
}
}
static
void
iwl_mvm_bss_info_changed
(
struct
ieee80211_hw
*
hw
,
...
...
@@ -1137,6 +1418,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
struct
cfg80211_scan_request
*
req
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_notification_wait
wait_scan_done
;
static
const
u8
scan_done_notif
[]
=
{
SCAN_OFFLOAD_COMPLETE
,
};
int
ret
;
if
(
req
->
n_channels
==
0
||
req
->
n_channels
>
MAX_NUM_SCAN_CHANNELS
)
...
...
@@ -1144,11 +1427,38 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
mutex_lock
(
&
mvm
->
mutex
);
if
(
mvm
->
scan_status
==
IWL_MVM_SCAN_NONE
)
ret
=
iwl_mvm_scan_request
(
mvm
,
vif
,
req
);
else
switch
(
mvm
->
scan_status
)
{
case
IWL_MVM_SCAN_SCHED
:
iwl_init_notification_wait
(
&
mvm
->
notif_wait
,
&
wait_scan_done
,
scan_done_notif
,
ARRAY_SIZE
(
scan_done_notif
),
NULL
,
NULL
);
iwl_mvm_sched_scan_stop
(
mvm
);
ret
=
iwl_wait_notification
(
&
mvm
->
notif_wait
,
&
wait_scan_done
,
HZ
);
if
(
ret
)
{
ret
=
-
EBUSY
;
goto
out
;
}
/* iwl_mvm_rx_scan_offload_complete_notif() will be called
* soon but will not reset the scan status as it won't be
* IWL_MVM_SCAN_SCHED any more since we queue the next scan
* immediately (below)
*/
break
;
case
IWL_MVM_SCAN_NONE
:
break
;
default:
ret
=
-
EBUSY
;
goto
out
;
}
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_SCAN
);
ret
=
iwl_mvm_scan_request
(
mvm
,
vif
,
req
);
if
(
ret
)
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_SCAN
);
out:
mutex_unlock
(
&
mvm
->
mutex
);
return
ret
;
...
...
@@ -1168,20 +1478,32 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
static
void
iwl_mvm_mac_allow_buffered_frames
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_sta
*
sta
,
u16
tid
,
struct
ieee80211_sta
*
sta
,
u16
tid
s
,
int
num_frames
,
enum
ieee80211_frame_release_type
reason
,
bool
more_data
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
/*
TODO: how do we tell the fw to send frames for a specific TID
*/
/*
Called when we need to transmit (a) frame(s) from mac80211
*/
/*
* The fw will send EOSP notification when the last frame will be
* transmitted.
*/
iwl_mvm_sta_modify_sleep_tx_count
(
mvm
,
sta
,
reason
,
num_frames
);
iwl_mvm_sta_modify_sleep_tx_count
(
mvm
,
sta
,
reason
,
num_frames
,
tids
,
more_data
,
false
);
}
static
void
iwl_mvm_mac_release_buffered_frames
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_sta
*
sta
,
u16
tids
,
int
num_frames
,
enum
ieee80211_frame_release_type
reason
,
bool
more_data
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
/* Called when we need to transmit (a) frame(s) from agg queue */
iwl_mvm_sta_modify_sleep_tx_count
(
mvm
,
sta
,
reason
,
num_frames
,
tids
,
more_data
,
true
);
}
static
void
iwl_mvm_mac_sta_notify
(
struct
ieee80211_hw
*
hw
,
...
...
@@ -1191,11 +1513,25 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
);
int
tid
;
switch
(
cmd
)
{
case
STA_NOTIFY_SLEEP
:
if
(
atomic_read
(
&
mvm
->
pending_frames
[
mvmsta
->
sta_id
])
>
0
)
ieee80211_sta_block_awake
(
hw
,
sta
,
true
);
spin_lock_bh
(
&
mvmsta
->
lock
);
for
(
tid
=
0
;
tid
<
IWL_MAX_TID_COUNT
;
tid
++
)
{
struct
iwl_mvm_tid_data
*
tid_data
;
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
if
(
tid_data
->
state
!=
IWL_AGG_ON
&&
tid_data
->
state
!=
IWL_EMPTYING_HW_QUEUE_DELBA
)
continue
;
if
(
iwl_mvm_tid_queued
(
tid_data
)
==
0
)
continue
;
ieee80211_sta_set_buffered
(
sta
,
tid
,
true
);
}
spin_unlock_bh
(
&
mvmsta
->
lock
);
/*
* The fw updates the STA to be asleep. Tx packets on the Tx
* queues to this station will not be transmitted. The fw will
...
...
@@ -1286,12 +1622,12 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
}
else
if
(
old_state
==
IEEE80211_STA_ASSOC
&&
new_state
==
IEEE80211_STA_AUTHORIZED
)
{
/* enable beacon filtering */
WARN_ON
(
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
));
WARN_ON
(
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
,
CMD_SYNC
));
ret
=
0
;
}
else
if
(
old_state
==
IEEE80211_STA_AUTHORIZED
&&
new_state
==
IEEE80211_STA_ASSOC
)
{
/* disable beacon filtering */
WARN_ON
(
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
));
WARN_ON
(
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
,
CMD_SYNC
));
ret
=
0
;
}
else
if
(
old_state
==
IEEE80211_STA_ASSOC
&&
new_state
==
IEEE80211_STA_AUTH
)
{
...
...
@@ -1756,7 +2092,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
* otherwise fw will complain.
*/
mvm
->
bound_vif_cnt
++
;
iwl_mvm_power_update_
binding
(
mvm
,
vif
,
true
);
iwl_mvm_power_update_
mac
(
mvm
,
vif
);
/* Setting the quota at this stage is only required for monitor
* interfaces. For the other types, the bss_info changed flow
...
...
@@ -1774,7 +2110,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
out_remove_binding:
iwl_mvm_binding_remove_vif
(
mvm
,
vif
);
mvm
->
bound_vif_cnt
--
;
iwl_mvm_power_update_
binding
(
mvm
,
vif
,
false
);
iwl_mvm_power_update_
mac
(
mvm
,
vif
);
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
if
(
ret
)
...
...
@@ -1807,7 +2143,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_binding_remove_vif
(
mvm
,
vif
);
mvm
->
bound_vif_cnt
--
;
iwl_mvm_power_update_
binding
(
mvm
,
vif
,
false
);
iwl_mvm_power_update_
mac
(
mvm
,
vif
);
out_unlock:
mvmvif
->
phy_ctxt
=
NULL
;
...
...
@@ -1874,8 +2210,9 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
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
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
,
CMD_SYNC
);
return
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
,
CMD_SYNC
);
}
return
-
EOPNOTSUPP
;
...
...
@@ -1914,6 +2251,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.
sta_state
=
iwl_mvm_mac_sta_state
,
.
sta_notify
=
iwl_mvm_mac_sta_notify
,
.
allow_buffered_frames
=
iwl_mvm_mac_allow_buffered_frames
,
.
release_buffered_frames
=
iwl_mvm_mac_release_buffered_frames
,
.
set_rts_threshold
=
iwl_mvm_mac_set_rts_threshold
,
.
sta_rc_update
=
iwl_mvm_sta_rc_update
,
.
conf_tx
=
iwl_mvm_mac_conf_tx
,
...
...
drivers/net/wireless/iwlwifi/mvm/mvm.h
View file @
e9c65316
...
...
@@ -92,7 +92,6 @@ enum iwl_mvm_tx_fifo {
};
extern
struct
ieee80211_ops
iwl_mvm_hw_ops
;
extern
const
struct
iwl_mvm_power_ops
pm_legacy_ops
;
extern
const
struct
iwl_mvm_power_ops
pm_mac_ops
;
/**
...
...
@@ -159,20 +158,6 @@ enum iwl_power_scheme {
IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
#define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2
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
);
void
(
*
power_update_binding
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
assign
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int
(
*
power_dbgfs_read
)(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
int
bufsz
);
#endif
};
#ifdef CONFIG_IWLWIFI_DEBUGFS
enum
iwl_dbgfs_pm_mask
{
MVM_DEBUGFS_PM_KEEP_ALIVE
=
BIT
(
0
),
...
...
@@ -239,6 +224,17 @@ enum iwl_mvm_smps_type_request {
NUM_IWL_MVM_SMPS_REQ
,
};
enum
iwl_mvm_ref_type
{
IWL_MVM_REF_UCODE_DOWN
,
IWL_MVM_REF_SCAN
,
IWL_MVM_REF_ROC
,
IWL_MVM_REF_P2P_CLIENT
,
IWL_MVM_REF_AP_IBSS
,
IWL_MVM_REF_USER
,
IWL_MVM_REF_COUNT
,
};
/**
* struct iwl_mvm_vif_bf_data - beacon filtering related data
* @bf_enabled: indicates if beacon filtering is enabled
...
...
@@ -270,6 +266,8 @@ struct iwl_mvm_vif_bf_data {
* should get quota etc.
* @monitor_active: indicates that monitor context is configured, and that the
* interface should get quota etc.
* @low_latency: indicates that this interface is in low-latency mode
* (VMACLowLatencyMode)
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
...
...
@@ -285,6 +283,7 @@ struct iwl_mvm_vif {
bool
uploaded
;
bool
ap_ibss_active
;
bool
monitor_active
;
bool
low_latency
;
struct
iwl_mvm_vif_bf_data
bf_data
;
u32
ap_beacon_time
;
...
...
@@ -333,14 +332,13 @@ struct iwl_mvm_vif {
struct
dentry
*
dbgfs_slink
;
struct
iwl_dbgfs_pm
dbgfs_pm
;
struct
iwl_dbgfs_bf
dbgfs_bf
;
struct
iwl_mac_power_cmd
mac_pwr_cmd
;
#endif
enum
ieee80211_smps_mode
smps_requests
[
NUM_IWL_MVM_SMPS_REQ
];
/* FW identified misbehaving AP */
u8
uapsd_misbehaving_bssid
[
ETH_ALEN
];
bool
pm_prevented
;
};
static
inline
struct
iwl_mvm_vif
*
...
...
@@ -415,6 +413,7 @@ struct iwl_tt_params {
* @ct_kill_exit: worker to exit thermal kill
* @dynamic_smps: Is thermal throttling enabled dynamic_smps?
* @tx_backoff: The current thremal throttling tx backoff in uSec.
* @min_backoff: The minimal tx backoff due to power restrictions
* @params: Parameters to configure the thermal throttling algorithm.
* @throttle: Is thermal throttling is active?
*/
...
...
@@ -422,6 +421,7 @@ struct iwl_mvm_tt_mgmt {
struct
delayed_work
ct_kill_exit
;
bool
dynamic_smps
;
u32
tx_backoff
;
u32
min_backoff
;
const
struct
iwl_tt_params
*
params
;
bool
throttle
;
};
...
...
@@ -457,6 +457,8 @@ struct iwl_mvm {
bool
init_ucode_complete
;
u32
error_event_table
;
u32
log_event_table
;
u32
umac_error_event_table
;
bool
support_umac_log
;
u32
ampdu_ref
;
...
...
@@ -470,7 +472,7 @@ struct iwl_mvm {
struct
iwl_nvm_data
*
nvm_data
;
/* NVM sections */
struct
iwl_nvm_section
nvm_sections
[
NVM_
NUM_OF
_SECTIONS
];
struct
iwl_nvm_section
nvm_sections
[
NVM_
MAX_NUM
_SECTIONS
];
/* EEPROM MAC addresses */
struct
mac_address
addresses
[
IWL_MVM_MAX_ADDRESSES
];
...
...
@@ -494,6 +496,17 @@ struct iwl_mvm {
/* rx chain antennas set through debugfs for the scan command */
u8
scan_rx_ant
;
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
/* broadcast filters to configure for each associated station */
const
struct
iwl_fw_bcast_filter
*
bcast_filters
;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct
{
u32
override
;
/* u32 for debugfs_create_bool */
struct
iwl_bcast_filter_cmd
cmd
;
}
dbgfs_bcast_filtering
;
#endif
#endif
/* Internal station */
struct
iwl_mvm_int_sta
aux_sta
;
...
...
@@ -526,6 +539,9 @@ struct iwl_mvm {
*/
unsigned
long
fw_key_table
[
BITS_TO_LONGS
(
STA_KEY_MAX_NUM
)];
/* A bitmap of reference types taken by the driver. */
unsigned
long
ref_bitmap
[
BITS_TO_LONGS
(
IWL_MVM_REF_COUNT
)];
u8
vif_count
;
/* -1 for always, 0 for never, >0 for that many times */
...
...
@@ -548,6 +564,10 @@ struct iwl_mvm {
#endif
#endif
/* d0i3 */
u8
d0i3_ap_sta_id
;
struct
work_struct
d0i3_exit_work
;
/* BT-Coex */
u8
bt_kill_msk
;
struct
iwl_bt_coex_profile_notif
last_bt_notif
;
...
...
@@ -557,8 +577,6 @@ struct iwl_mvm {
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
;
...
...
@@ -572,7 +590,9 @@ struct iwl_mvm {
u8
bound_vif_cnt
;
/* Indicate if device power save is allowed */
bool
ps_prevented
;
bool
ps_disabled
;
/* Indicate if device power management is allowed */
bool
pm_disabled
;
};
/* Extract MVM priv from op_mode and _hw */
...
...
@@ -595,6 +615,24 @@ static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
test_bit
(
IWL_MVM_STATUS_HW_CTKILL
,
&
mvm
->
status
);
}
static
inline
struct
iwl_mvm_sta
*
iwl_mvm_sta_from_staid_protected
(
struct
iwl_mvm
*
mvm
,
u8
sta_id
)
{
struct
ieee80211_sta
*
sta
;
if
(
sta_id
>=
ARRAY_SIZE
(
mvm
->
fw_id_to_mac_id
))
return
NULL
;
sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
));
/* This can happen if the station has been removed right now */
if
(
IS_ERR_OR_NULL
(
sta
))
return
NULL
;
return
iwl_mvm_sta_from_mac80211
(
sta
);
}
extern
const
u8
iwl_mvm_ac_to_tx_fifo
[];
struct
iwl_rate_info
{
...
...
@@ -661,6 +699,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm);
int
iwl_mvm_load_d3_fw
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_mac_setup_register
(
struct
iwl_mvm
*
mvm
);
bool
iwl_mvm_bcast_filter_build_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_bcast_filter_cmd
*
cmd
);
/*
* FW notifications / CMD responses handlers
...
...
@@ -773,48 +813,19 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
/* rate scaling */
int
iwl_mvm_send_lq_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_cmd
*
lq
,
bool
init
);
/* power managment */
static
inline
int
iwl_mvm_power_update_mode
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
return
mvm
->
pm_ops
->
power_update_mode
(
mvm
,
vif
);
}
static
inline
int
iwl_mvm_power_disable
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
return
mvm
->
pm_ops
->
power_disable
(
mvm
,
vif
);
}
/* power management */
int
iwl_power_legacy_set_cam_mode
(
struct
iwl_mvm
*
mvm
);
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
;
}
static
inline
void
iwl_mvm_power_update_binding
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
assign
)
{
if
(
mvm
->
pm_ops
->
power_update_binding
)
mvm
->
pm_ops
->
power_update_binding
(
mvm
,
vif
,
assign
);
}
int
iwl_mvm_power_update_device
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_power_update_mac
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
int
iwl_mvm_power_mac_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
int
bufsz
);
void
iwl_mvm_power_vif_assoc
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
int
iwl_mvm_power_uapsd_misbehaving_ap_notif
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
inline
int
iwl_mvm_power_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
int
bufsz
)
{
return
mvm
->
pm_ops
->
power_dbgfs_read
(
mvm
,
vif
,
buf
,
bufsz
);
}
#endif
int
iwl_mvm_leds_init
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_leds_exit
(
struct
iwl_mvm
*
mvm
);
...
...
@@ -841,6 +852,10 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
}
#endif
/* D0i3 */
void
iwl_mvm_ref
(
struct
iwl_mvm
*
mvm
,
enum
iwl_mvm_ref_type
ref_type
);
void
iwl_mvm_unref
(
struct
iwl_mvm
*
mvm
,
enum
iwl_mvm_ref_type
ref_type
);
/* BT Coex */
int
iwl_send_bt_prio_tbl
(
struct
iwl_mvm
*
mvm
);
int
iwl_send_bt_init_conf
(
struct
iwl_mvm
*
mvm
);
...
...
@@ -854,6 +869,7 @@ 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
);
int
iwl_mvm_bt_coex_reduced_txp
(
struct
iwl_mvm
*
mvm
,
u8
sta_id
,
bool
enable
);
enum
iwl_bt_kill_msk
{
BT_KILL_MSK_DEFAULT
,
...
...
@@ -875,25 +891,51 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
struct
iwl_beacon_filter_cmd
*
cmd
)
{}
#endif
int
iwl_mvm_update_d0i3_power_mode
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
enable
,
u32
flags
);
int
iwl_mvm_enable_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
struct
ieee80211_vif
*
vif
,
u32
flags
);
int
iwl_mvm_disable_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
int
iwl_mvm_beacon_filter_send_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_beacon_filter_cmd
*
cmd
);
struct
ieee80211_vif
*
vif
,
u32
flags
);
int
iwl_mvm_update_beacon_abort
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
enable
);
int
iwl_mvm_update_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
);
struct
ieee80211_vif
*
vif
,
bool
force
,
u32
flags
);
/* SMPS */
void
iwl_mvm_update_smps
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
enum
iwl_mvm_smps_type_request
req_type
,
enum
ieee80211_smps_mode
smps_request
);
/* Low latency */
int
iwl_mvm_update_low_latency
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
value
);
/* get VMACLowLatencyMode */
static
inline
bool
iwl_mvm_vif_low_latency
(
struct
iwl_mvm_vif
*
mvmvif
)
{
/*
* should this consider associated/active/... state?
*
* Normally low-latency should only be active on interfaces
* that are active, but at least with debugfs it can also be
* enabled on interfaces that aren't active. However, when
* interface aren't active then they aren't added into the
* binding, so this has no real impact. For now, just return
* the current desired low-latency state.
*/
return
mvmvif
->
low_latency
;
}
/* Thermal management and CT-kill */
void
iwl_mvm_tt_tx_backoff
(
struct
iwl_mvm
*
mvm
,
u32
backoff
);
void
iwl_mvm_tt_handler
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_tt_initialize
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_tt_initialize
(
struct
iwl_mvm
*
mvm
,
u32
min_backoff
);
void
iwl_mvm_tt_exit
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_set_hw_ctkill_state
(
struct
iwl_mvm
*
mvm
,
bool
state
);
...
...
drivers/net/wireless/iwlwifi/mvm/nvm.c
View file @
e9c65316
...
...
@@ -67,14 +67,6 @@
#include "iwl-eeprom-read.h"
#include "iwl-nvm-parse.h"
/* list of NVM sections we are allowed/need to read */
static
const
int
nvm_to_read
[]
=
{
NVM_SECTION_TYPE_HW
,
NVM_SECTION_TYPE_SW
,
NVM_SECTION_TYPE_CALIBRATION
,
NVM_SECTION_TYPE_PRODUCTION
,
};
/* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
#define IWL_MAX_NVM_SECTION_SIZE 7000
...
...
@@ -240,7 +232,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
/* Checking for required sections */
if
(
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_SW
].
data
||
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_HW
].
data
)
{
!
mvm
->
nvm_sections
[
mvm
->
cfg
->
nvm_hw_section_num
].
data
)
{
IWL_ERR
(
mvm
,
"Can't parse empty NVM sections
\n
"
);
return
NULL
;
}
...
...
@@ -248,7 +240,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
if
(
WARN_ON
(
!
mvm
->
cfg
))
return
NULL
;
hw
=
(
const
__le16
*
)
sections
[
NVM_SECTION_TYPE_HW
].
data
;
hw
=
(
const
__le16
*
)
sections
[
mvm
->
cfg
->
nvm_hw_section_num
].
data
;
sw
=
(
const
__le16
*
)
sections
[
NVM_SECTION_TYPE_SW
].
data
;
calib
=
(
const
__le16
*
)
sections
[
NVM_SECTION_TYPE_CALIBRATION
].
data
;
return
iwl_parse_nvm_data
(
mvm
->
trans
->
dev
,
mvm
->
cfg
,
hw
,
sw
,
calib
,
...
...
@@ -367,7 +359,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
break
;
}
if
(
WARN
(
section_id
>=
NVM_
NUM_OF
_SECTIONS
,
if
(
WARN
(
section_id
>=
NVM_
MAX_NUM
_SECTIONS
,
"Invalid NVM section ID %d
\n
"
,
section_id
))
{
ret
=
-
EINVAL
;
break
;
...
...
@@ -415,6 +407,9 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
int
ret
,
i
,
section
;
u8
*
nvm_buffer
,
*
temp
;
if
(
WARN_ON_ONCE
(
mvm
->
cfg
->
nvm_hw_section_num
>=
NVM_MAX_NUM_SECTIONS
))
return
-
EINVAL
;
/* load external NVM if configured */
if
(
iwlwifi_mod_params
.
nvm_file
)
{
/* move to External NVM flow */
...
...
@@ -422,6 +417,14 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
if
(
ret
)
return
ret
;
}
else
{
/* list of NVM sections we are allowed/need to read */
int
nvm_to_read
[]
=
{
mvm
->
cfg
->
nvm_hw_section_num
,
NVM_SECTION_TYPE_SW
,
NVM_SECTION_TYPE_CALIBRATION
,
NVM_SECTION_TYPE_PRODUCTION
,
};
/* Read From FW NVM */
IWL_DEBUG_EEPROM
(
mvm
->
trans
->
dev
,
"Read from NVM
\n
"
);
...
...
@@ -446,10 +449,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
#ifdef CONFIG_IWLWIFI_DEBUGFS
switch
(
section
)
{
case
NVM_SECTION_TYPE_HW
:
mvm
->
nvm_hw_blob
.
data
=
temp
;
mvm
->
nvm_hw_blob
.
size
=
ret
;
break
;
case
NVM_SECTION_TYPE_SW
:
mvm
->
nvm_sw_blob
.
data
=
temp
;
mvm
->
nvm_sw_blob
.
size
=
ret
;
...
...
@@ -463,6 +462,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
mvm
->
nvm_prod_blob
.
size
=
ret
;
break
;
default:
if
(
section
==
mvm
->
cfg
->
nvm_hw_section_num
)
{
mvm
->
nvm_hw_blob
.
data
=
temp
;
mvm
->
nvm_hw_blob
.
size
=
ret
;
break
;
}
WARN
(
1
,
"section: %d"
,
section
);
}
#endif
...
...
drivers/net/wireless/iwlwifi/mvm/ops.c
View file @
e9c65316
...
...
@@ -185,6 +185,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
* (PCIe power is lost before PERST# is asserted), causing ME FW
* to lose ownership and not being able to obtain it back.
*/
if
(
mvm
->
trans
->
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
iwl_set_bits_mask_prph
(
mvm
->
trans
,
APMG_PS_CTRL_REG
,
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS
,
~
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS
);
...
...
@@ -222,10 +223,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER
(
TIME_EVENT_NOTIFICATION
,
iwl_mvm_rx_time_event_notif
,
false
),
RX_HANDLER
(
EOSP_NOTIFICATION
,
iwl_mvm_rx_eosp_notif
,
false
),
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
,
fals
e
),
iwl_mvm_rx_scan_offload_complete_notif
,
tru
e
),
RX_HANDLER
(
MATCH_FOUND_NOTIFICATION
,
iwl_mvm_rx_sched_scan_results
,
false
),
...
...
@@ -284,9 +287,11 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD
(
BEACON_NOTIFICATION
),
CMD
(
BEACON_TEMPLATE_CMD
),
CMD
(
STATISTICS_NOTIFICATION
),
CMD
(
EOSP_NOTIFICATION
),
CMD
(
REDUCE_TX_POWER_CMD
),
CMD
(
TX_ANT_CONFIGURATION_CMD
),
CMD
(
D3_CONFIG_CMD
),
CMD
(
D0I3_END_CMD
),
CMD
(
PROT_OFFLOAD_CONFIG_CMD
),
CMD
(
OFFLOADS_QUERY_CMD
),
CMD
(
REMOTE_WAKE_CONFIG_CMD
),
...
...
@@ -309,6 +314,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD
(
BT_PROFILE_NOTIFICATION
),
CMD
(
BT_CONFIG
),
CMD
(
MCAST_FILTER_CMD
),
CMD
(
BCAST_FILTER_CMD
),
CMD
(
REPLY_SF_CFG_CMD
),
CMD
(
REPLY_BEACON_FILTERING_CMD
),
CMD
(
REPLY_THERMAL_MNG_BACKOFF
),
...
...
@@ -320,6 +326,24 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
/* this forward declaration can avoid to export the function */
static
void
iwl_mvm_async_handlers_wk
(
struct
work_struct
*
wk
);
static
void
iwl_mvm_d0i3_exit_work
(
struct
work_struct
*
wk
);
static
u32
calc_min_backoff
(
struct
iwl_trans
*
trans
,
const
struct
iwl_cfg
*
cfg
)
{
const
struct
iwl_pwr_tx_backoff
*
pwr_tx_backoff
=
cfg
->
pwr_tx_backoffs
;
if
(
!
pwr_tx_backoff
)
return
0
;
while
(
pwr_tx_backoff
->
pwr
)
{
if
(
trans
->
dflt_pwr_limit
>=
pwr_tx_backoff
->
pwr
)
return
pwr_tx_backoff
->
backoff
;
pwr_tx_backoff
++
;
}
return
0
;
}
static
struct
iwl_op_mode
*
iwl_op_mode_mvm_start
(
struct
iwl_trans
*
trans
,
const
struct
iwl_cfg
*
cfg
,
...
...
@@ -333,6 +357,14 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
TX_CMD
,
};
int
err
,
scan_size
;
u32
min_backoff
;
/*
* We use IWL_MVM_STATION_COUNT to check the validity of the station
* index all over the driver - check that its value corresponds to the
* array size.
*/
BUILD_BUG_ON
(
ARRAY_SIZE
(
mvm
->
fw_id_to_mac_id
)
!=
IWL_MVM_STATION_COUNT
);
/********************************
* 1. Allocating and configuring HW data
...
...
@@ -373,6 +405,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK
(
&
mvm
->
async_handlers_wk
,
iwl_mvm_async_handlers_wk
);
INIT_WORK
(
&
mvm
->
roc_done_wk
,
iwl_mvm_roc_done_wk
);
INIT_WORK
(
&
mvm
->
sta_drained_wk
,
iwl_mvm_sta_drained_wk
);
INIT_WORK
(
&
mvm
->
d0i3_exit_work
,
iwl_mvm_d0i3_exit_work
);
SET_IEEE80211_DEV
(
mvm
->
hw
,
mvm
->
trans
->
dev
);
...
...
@@ -421,7 +454,8 @@ 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
);
iwl_mvm_tt_initialize
(
mvm
);
min_backoff
=
calc_min_backoff
(
trans
,
cfg
);
iwl_mvm_tt_initialize
(
mvm
,
min_backoff
);
/*
* If the NVM exists in an external file,
...
...
@@ -462,13 +496,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if
(
err
)
goto
out_unregister
;
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT
)
mvm
->
pm_ops
=
&
pm_mac_ops
;
else
mvm
->
pm_ops
=
&
pm_legacy_ops
;
memset
(
&
mvm
->
rx_stats
,
0
,
sizeof
(
struct
mvm_statistics_rx
));
/* rpm starts with a taken ref. only set the appropriate bit here. */
set_bit
(
IWL_MVM_REF_UCODE_DOWN
,
mvm
->
ref_bitmap
);
return
op_mode
;
out_unregister:
...
...
@@ -508,7 +540,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
mvm
->
phy_db
=
NULL
;
iwl_free_nvm_data
(
mvm
->
nvm_data
);
for
(
i
=
0
;
i
<
NVM_
NUM_OF
_SECTIONS
;
i
++
)
for
(
i
=
0
;
i
<
NVM_
MAX_NUM
_SECTIONS
;
i
++
)
kfree
(
mvm
->
nvm_sections
[
i
].
data
);
ieee80211_free_hw
(
mvm
->
hw
);
...
...
@@ -702,6 +734,29 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
{
iwl_abort_notification_waits
(
&
mvm
->
notif_wait
);
/*
* This is a bit racy, but worst case we tell mac80211 about
* a stopped/aborted scan when that was already done which
* is not a problem. It is necessary to abort any os scan
* here because mac80211 requires having the scan cleared
* before restarting.
* We'll reset the scan_status to NONE in restart cleanup in
* the next start() call from mac80211. If restart isn't called
* (no fw restart) scan status will stay busy.
*/
switch
(
mvm
->
scan_status
)
{
case
IWL_MVM_SCAN_NONE
:
break
;
case
IWL_MVM_SCAN_OS
:
ieee80211_scan_completed
(
mvm
->
hw
,
true
);
break
;
case
IWL_MVM_SCAN_SCHED
:
/* Sched scan will be restarted by mac80211 in restart_hw. */
if
(
!
mvm
->
restart_fw
)
ieee80211_sched_scan_stopped
(
mvm
->
hw
);
break
;
}
/*
* If we're restarting already, don't cycle restarts.
* If INIT fw asserted, it will likely fail again.
...
...
@@ -733,25 +788,8 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
INIT_WORK
(
&
reprobe
->
work
,
iwl_mvm_reprobe_wk
);
schedule_work
(
&
reprobe
->
work
);
}
else
if
(
mvm
->
cur_ucode
==
IWL_UCODE_REGULAR
&&
mvm
->
restart_fw
)
{
/*
* This is a bit racy, but worst case we tell mac80211 about
* a stopped/aborted (sched) scan when that was already done
* which is not a problem. It is necessary to abort any scan
* here because mac80211 requires having the scan cleared
* before restarting.
* We'll reset the scan_status to NONE in restart cleanup in
* the next start() call from mac80211.
*/
switch
(
mvm
->
scan_status
)
{
case
IWL_MVM_SCAN_NONE
:
break
;
case
IWL_MVM_SCAN_OS
:
ieee80211_scan_completed
(
mvm
->
hw
,
true
);
break
;
case
IWL_MVM_SCAN_SCHED
:
ieee80211_sched_scan_stopped
(
mvm
->
hw
);
break
;
}
/* don't let the transport/FW power down */
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_UCODE_DOWN
);
if
(
mvm
->
restart_fw
>
0
)
mvm
->
restart_fw
--
;
...
...
@@ -778,6 +816,163 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
iwl_mvm_nic_restart
(
mvm
);
}
struct
iwl_d0i3_iter_data
{
struct
iwl_mvm
*
mvm
;
u8
ap_sta_id
;
u8
vif_count
;
};
static
void
iwl_mvm_enter_d0i3_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_d0i3_iter_data
*
data
=
_data
;
struct
iwl_mvm
*
mvm
=
data
->
mvm
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
u32
flags
=
CMD_ASYNC
|
CMD_HIGH_PRIO
|
CMD_SEND_IN_IDLE
;
IWL_DEBUG_RPM
(
mvm
,
"entering D0i3 - vif %pM
\n
"
,
vif
->
addr
);
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
!
vif
->
bss_conf
.
assoc
)
return
;
iwl_mvm_update_d0i3_power_mode
(
mvm
,
vif
,
true
,
flags
);
/*
* on init/association, mvm already configures POWER_TABLE_CMD
* and REPLY_MCAST_FILTER_CMD, so currently don't
* reconfigure them (we might want to use different
* params later on, though).
*/
data
->
ap_sta_id
=
mvmvif
->
ap_sta_id
;
data
->
vif_count
++
;
}
static
int
iwl_mvm_enter_d0i3
(
struct
iwl_op_mode
*
op_mode
)
{
struct
iwl_mvm
*
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
u32
flags
=
CMD_ASYNC
|
CMD_HIGH_PRIO
|
CMD_SEND_IN_IDLE
;
int
ret
;
struct
iwl_d0i3_iter_data
d0i3_iter_data
=
{
.
mvm
=
mvm
,
};
struct
iwl_wowlan_config_cmd
wowlan_config_cmd
=
{
.
wakeup_filter
=
cpu_to_le32
(
IWL_WOWLAN_WAKEUP_RX_FRAME
|
IWL_WOWLAN_WAKEUP_BEACON_MISS
|
IWL_WOWLAN_WAKEUP_LINK_CHANGE
|
IWL_WOWLAN_WAKEUP_BCN_FILTERING
),
};
struct
iwl_d3_manager_config
d3_cfg_cmd
=
{
.
min_sleep_time
=
cpu_to_le32
(
1000
),
};
IWL_DEBUG_RPM
(
mvm
,
"MVM entering D0i3
\n
"
);
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_enter_d0i3_iterator
,
&
d0i3_iter_data
);
if
(
d0i3_iter_data
.
vif_count
==
1
)
{
mvm
->
d0i3_ap_sta_id
=
d0i3_iter_data
.
ap_sta_id
;
}
else
{
WARN_ON_ONCE
(
d0i3_iter_data
.
vif_count
>
1
);
mvm
->
d0i3_ap_sta_id
=
IWL_MVM_STATION_COUNT
;
}
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
WOWLAN_CONFIGURATION
,
flags
,
sizeof
(
wowlan_config_cmd
),
&
wowlan_config_cmd
);
if
(
ret
)
return
ret
;
return
iwl_mvm_send_cmd_pdu
(
mvm
,
D3_CONFIG_CMD
,
flags
|
CMD_MAKE_TRANS_IDLE
,
sizeof
(
d3_cfg_cmd
),
&
d3_cfg_cmd
);
}
static
void
iwl_mvm_exit_d0i3_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm
*
mvm
=
_data
;
u32
flags
=
CMD_ASYNC
|
CMD_HIGH_PRIO
;
IWL_DEBUG_RPM
(
mvm
,
"exiting D0i3 - vif %pM
\n
"
,
vif
->
addr
);
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
!
vif
->
bss_conf
.
assoc
)
return
;
iwl_mvm_update_d0i3_power_mode
(
mvm
,
vif
,
false
,
flags
);
}
static
void
iwl_mvm_d0i3_disconnect_iter
(
void
*
data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm
*
mvm
=
data
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
vif
->
bss_conf
.
assoc
&&
mvm
->
d0i3_ap_sta_id
==
mvmvif
->
ap_sta_id
)
ieee80211_connection_loss
(
vif
);
}
static
void
iwl_mvm_d0i3_exit_work
(
struct
work_struct
*
wk
)
{
struct
iwl_mvm
*
mvm
=
container_of
(
wk
,
struct
iwl_mvm
,
d0i3_exit_work
);
struct
iwl_host_cmd
get_status_cmd
=
{
.
id
=
WOWLAN_GET_STATUSES
,
.
flags
=
CMD_SYNC
|
CMD_HIGH_PRIO
|
CMD_WANT_SKB
,
};
struct
iwl_wowlan_status_v6
*
status
;
int
ret
;
u32
disconnection_reasons
,
wakeup_reasons
;
mutex_lock
(
&
mvm
->
mutex
);
ret
=
iwl_mvm_send_cmd
(
mvm
,
&
get_status_cmd
);
if
(
ret
)
goto
out
;
if
(
!
get_status_cmd
.
resp_pkt
)
goto
out
;
status
=
(
void
*
)
get_status_cmd
.
resp_pkt
->
data
;
wakeup_reasons
=
le32_to_cpu
(
status
->
wakeup_reasons
);
IWL_DEBUG_RPM
(
mvm
,
"wakeup reasons: 0x%x
\n
"
,
wakeup_reasons
);
disconnection_reasons
=
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON
|
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH
;
if
(
wakeup_reasons
&
disconnection_reasons
)
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_d0i3_disconnect_iter
,
mvm
);
iwl_free_resp
(
&
get_status_cmd
);
out:
mutex_unlock
(
&
mvm
->
mutex
);
}
static
int
iwl_mvm_exit_d0i3
(
struct
iwl_op_mode
*
op_mode
)
{
struct
iwl_mvm
*
mvm
=
IWL_OP_MODE_GET_MVM
(
op_mode
);
u32
flags
=
CMD_ASYNC
|
CMD_HIGH_PRIO
|
CMD_SEND_IN_IDLE
|
CMD_WAKE_UP_TRANS
;
int
ret
;
IWL_DEBUG_RPM
(
mvm
,
"MVM exiting D0i3
\n
"
);
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
D0I3_END_CMD
,
flags
,
0
,
NULL
);
if
(
ret
)
goto
out
;
ieee80211_iterate_active_interfaces_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_exit_d0i3_iterator
,
mvm
);
out:
schedule_work
(
&
mvm
->
d0i3_exit_work
);
return
ret
;
}
static
const
struct
iwl_op_mode_ops
iwl_mvm_ops
=
{
.
start
=
iwl_op_mode_mvm_start
,
.
stop
=
iwl_op_mode_mvm_stop
,
...
...
@@ -789,4 +984,6 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = {
.
nic_error
=
iwl_mvm_nic_error
,
.
cmd_queue_full
=
iwl_mvm_cmd_queue_full
,
.
nic_config
=
iwl_mvm_nic_config
,
.
enter_d0i3
=
iwl_mvm_enter_d0i3
,
.
exit_d0i3
=
iwl_mvm_exit_d0i3
,
};
drivers/net/wireless/iwlwifi/mvm/power.c
View file @
e9c65316
...
...
@@ -74,15 +74,11 @@
#define POWER_KEEP_ALIVE_PERIOD_SEC 25
static
int
iwl_mvm_beacon_filter_send_cmd
(
struct
iwl_mvm
*
mvm
,
struct
iwl_beacon_filter_cmd
*
cmd
)
struct
iwl_beacon_filter_cmd
*
cmd
,
u32
flags
)
{
int
ret
;
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
REPLY_BEACON_FILTERING_CMD
,
CMD_SYNC
,
sizeof
(
struct
iwl_beacon_filter_cmd
),
cmd
);
if
(
!
ret
)
{
IWL_DEBUG_POWER
(
mvm
,
"ba_enable_beacon_abort is: %d
\n
"
,
le32_to_cpu
(
cmd
->
ba_enable_beacon_abort
));
IWL_DEBUG_POWER
(
mvm
,
"ba_escape_timer is: %d
\n
"
,
...
...
@@ -105,8 +101,9 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
le32_to_cpu
(
cmd
->
bf_temp_fast_filter
));
IWL_DEBUG_POWER
(
mvm
,
"bf_temp_slow_filter is: %d
\n
"
,
le32_to_cpu
(
cmd
->
bf_temp_slow_filter
));
}
return
ret
;
return
iwl_mvm_send_cmd_pdu
(
mvm
,
REPLY_BEACON_FILTERING_CMD
,
flags
,
sizeof
(
struct
iwl_beacon_filter_cmd
),
cmd
);
}
static
...
...
@@ -145,7 +142,7 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
mvmvif
->
bf_data
.
ba_enabled
=
enable
;
iwl_mvm_beacon_filter_set_cqm_params
(
mvm
,
vif
,
&
cmd
);
iwl_mvm_beacon_filter_debugfs_parameters
(
vif
,
&
cmd
);
return
iwl_mvm_beacon_filter_send_cmd
(
mvm
,
&
cmd
);
return
iwl_mvm_beacon_filter_send_cmd
(
mvm
,
&
cmd
,
CMD_SYNC
);
}
static
void
iwl_mvm_power_log
(
struct
iwl_mvm
*
mvm
,
...
...
@@ -301,8 +298,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
keep_alive
=
DIV_ROUND_UP
(
keep_alive
,
MSEC_PER_SEC
);
cmd
->
keep_alive_seconds
=
cpu_to_le16
(
keep_alive
);
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
||
mvm
->
ps_prevented
)
if
(
mvm
->
ps_disabled
)
return
;
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
...
...
@@ -312,7 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
mvmvif
->
dbgfs_pm
.
disable_power_off
)
cmd
->
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
#endif
if
(
!
vif
->
bss_conf
.
ps
||
mvmvif
->
pm_prevented
)
if
(
!
vif
->
bss_conf
.
ps
||
iwl_mvm_vif_low_latency
(
mvmvif
)
||
mvm
->
pm_disabled
)
return
;
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
);
...
...
@@ -419,11 +416,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
#endif
/* CONFIG_IWLWIFI_DEBUGFS */
}
static
int
iwl_mvm_power_
mac_update_mode
(
struct
iwl_mvm
*
mvm
,
static
int
iwl_mvm_power_
send_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
int
ret
;
bool
ba_enable
;
struct
iwl_mac_power_cmd
cmd
=
{};
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
)
...
...
@@ -435,56 +430,30 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
iwl_mvm_power_build_cmd
(
mvm
,
vif
,
&
cmd
);
iwl_mvm_power_log
(
mvm
,
&
cmd
);
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
MAC_PM_POWER_TABLE
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
if
(
ret
)
return
ret
;
ba_enable
=
!!
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
));
return
iwl_mvm_update_beacon_abort
(
mvm
,
vif
,
ba_enable
);
}
static
int
iwl_mvm_power_mac_disable
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mac_power_cmd
cmd
=
{};
struct
iwl_mvm_vif
*
mvmvif
__maybe_unused
=
iwl_mvm_vif_from_mac80211
(
vif
);
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
return
0
;
cmd
.
id_and_color
=
cpu_to_le32
(
FW_CMD_ID_AND_COLOR
(
mvmvif
->
id
,
mvmvif
->
color
));
if
(
iwlmvm_mod_params
.
power_scheme
!=
IWL_POWER_SCHEME_CAM
)
cmd
.
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_DISABLE_POWER_OFF
&&
mvmvif
->
dbgfs_pm
.
disable_power_off
)
cmd
.
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
memcpy
(
&
iwl_mvm_vif_from_mac80211
(
vif
)
->
mac_pwr_cmd
,
&
cmd
,
sizeof
(
cmd
));
#endif
iwl_mvm_power_log
(
mvm
,
&
cmd
);
return
iwl_mvm_send_cmd_pdu
(
mvm
,
MAC_PM_POWER_TABLE
,
CMD_
A
SYNC
,
return
iwl_mvm_send_cmd_pdu
(
mvm
,
MAC_PM_POWER_TABLE
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
}
static
int
_iwl_mvm_power_update_device
(
struct
iwl_mvm
*
mvm
,
bool
force_disable
)
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_PM_CMD_SUPPORT
))
return
0
;
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
||
force_disable
)
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
)
mvm
->
ps_disabled
=
true
;
if
(
mvm
->
ps_disabled
)
cmd
.
flags
|=
cpu_to_le16
(
DEVICE_POWER_FLAGS_CAM_MSK
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
...
...
@@ -501,11 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
&
cmd
);
}
static
int
iwl_mvm_power_update_device
(
struct
iwl_mvm
*
mvm
)
{
return
_iwl_mvm_power_update_device
(
mvm
,
false
);
}
void
iwl_mvm_power_vif_assoc
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
...
...
@@ -544,44 +508,137 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
return
0
;
}
static
void
iwl_mvm_power_binding_iterator
(
void
*
_data
,
u8
*
mac
,
struct
iwl_power_constraint
{
struct
ieee80211_vif
*
bf_vif
;
struct
ieee80211_vif
*
bss_vif
;
bool
pm_disabled
;
bool
ps_disabled
;
};
static
void
iwl_mvm_power_iterator
(
void
*
_data
,
u8
*
mac
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mvm
*
mvm
=
_data
;
int
ret
;
struct
iwl_power_constraint
*
power_iterator
=
_data
;
switch
(
ieee80211_vif_type_p2p
(
vif
))
{
case
NL80211_IFTYPE_P2P_DEVICE
:
break
;
case
NL80211_IFTYPE_P2P_GO
:
case
NL80211_IFTYPE_AP
:
/* no BSS power mgmt if we have an active AP */
if
(
mvmvif
->
ap_ibss_active
)
power_iterator
->
pm_disabled
=
true
;
break
;
case
NL80211_IFTYPE_MONITOR
:
/* no BSS power mgmt and no device power save */
power_iterator
->
pm_disabled
=
true
;
power_iterator
->
ps_disabled
=
true
;
break
;
case
NL80211_IFTYPE_P2P_CLIENT
:
/* no BSS power mgmt if we have a P2P client*/
power_iterator
->
pm_disabled
=
true
;
break
;
case
NL80211_IFTYPE_STATION
:
/* we should have only one BSS vif */
WARN_ON
(
power_iterator
->
bss_vif
);
power_iterator
->
bss_vif
=
vif
;
mvmvif
->
pm_prevented
=
(
mvm
->
bound_vif_cnt
<=
1
)
?
false
:
true
;
if
(
mvmvif
->
bf_data
.
bf_enabled
&&
!
WARN_ON
(
power_iterator
->
bf_vif
))
power_iterator
->
bf_vif
=
vif
;
break
;
ret
=
iwl_mvm_power_mac_update_mode
(
mvm
,
vif
);
WARN_ONCE
(
ret
,
"Failed to update power parameters on a specific vif
\n
"
);
default:
break
;
}
}
static
void
_iwl_mvm_power_update_binding
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
assign
)
static
void
iwl_mvm_power_get_global_constraint
(
struct
iwl_mvm
*
mvm
,
struct
iwl_power_constraint
*
constraint
)
{
if
(
vif
->
type
==
NL80211_IFTYPE_MONITOR
)
{
int
ret
=
_iwl_mvm_power_update_device
(
mvm
,
assign
);
mvm
->
ps_prevented
=
assign
;
WARN_ONCE
(
ret
,
"Failed to update power device state
\n
"
);
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
)
{
constraint
->
pm_disabled
=
true
;
constraint
->
ps_disabled
=
true
;
}
ieee80211_iterate_active_interfaces
(
mvm
->
hw
,
ieee80211_iterate_active_interfaces
_atomic
(
mvm
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_power_binding_iterator
,
mvm
);
iwl_mvm_power_iterator
,
constraint
);
/* TODO: remove this and determine this variable in the iterator */
if
(
mvm
->
bound_vif_cnt
>
1
)
constraint
->
pm_disabled
=
true
;
}
int
iwl_mvm_power_update_mac
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_power_constraint
constraint
=
{};
bool
ba_enable
;
int
ret
;
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT
))
return
0
;
iwl_mvm_power_get_global_constraint
(
mvm
,
&
constraint
);
mvm
->
ps_disabled
=
constraint
.
ps_disabled
;
mvm
->
pm_disabled
=
constraint
.
pm_disabled
;
/* don't update device power state unless we add / remove monitor */
if
(
vif
->
type
==
NL80211_IFTYPE_MONITOR
)
{
ret
=
iwl_mvm_power_update_device
(
mvm
);
if
(
ret
)
return
ret
;
}
ret
=
iwl_mvm_power_send_cmd
(
mvm
,
vif
);
if
(
ret
)
return
ret
;
if
(
constraint
.
bss_vif
&&
vif
!=
constraint
.
bss_vif
)
{
ret
=
iwl_mvm_power_send_cmd
(
mvm
,
constraint
.
bss_vif
);
if
(
ret
)
return
ret
;
}
if
(
!
constraint
.
bf_vif
)
return
0
;
vif
=
constraint
.
bf_vif
;
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
ba_enable
=
!
(
constraint
.
pm_disabled
||
constraint
.
ps_disabled
||
!
vif
->
bss_conf
.
ps
||
iwl_mvm_vif_low_latency
(
mvmvif
));
return
iwl_mvm_update_beacon_abort
(
mvm
,
constraint
.
bf_vif
,
ba_enable
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
int
iwl_mvm_power_mac_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
int
iwl_mvm_power_mac_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
int
bufsz
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mac_power_cmd
cmd
=
{};
int
pos
=
0
;
iwl_mvm_power_build_cmd
(
mvm
,
vif
,
&
cmd
);
if
(
WARN_ON
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT
)))
return
0
;
mutex_lock
(
&
mvm
->
mutex
);
memcpy
(
&
cmd
,
&
mvmvif
->
mac_pwr_cmd
,
sizeof
(
cmd
));
mutex_unlock
(
&
mvm
->
mutex
);
if
(
!
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD
))
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"disable_power_off = %d
\n
"
,
...
...
@@ -685,32 +742,46 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
}
#endif
int
iwl_mvm_enable_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
static
int
_iwl_mvm_enable_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_beacon_filter_cmd
*
cmd
,
u32
cmd_flags
,
bool
d0i3
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_beacon_filter_cmd
cmd
=
{
IWL_BF_CMD_CONFIG_DEFAULTS
,
.
bf_enable_beacon_filter
=
cpu_to_le32
(
1
),
};
int
ret
;
if
(
mvmvif
!=
mvm
->
bf_allowed_vif
||
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
return
0
;
iwl_mvm_beacon_filter_set_cqm_params
(
mvm
,
vif
,
&
cmd
);
iwl_mvm_beacon_filter_debugfs_parameters
(
vif
,
&
cmd
);
ret
=
iwl_mvm_beacon_filter_send_cmd
(
mvm
,
&
cmd
);
iwl_mvm_beacon_filter_set_cqm_params
(
mvm
,
vif
,
cmd
);
if
(
!
d0i3
)
iwl_mvm_beacon_filter_debugfs_parameters
(
vif
,
cmd
);
ret
=
iwl_mvm_beacon_filter_send_cmd
(
mvm
,
cmd
,
cmd_flags
);
if
(
!
ret
)
/* don't change bf_enabled in case of temporary d0i3 configuration */
if
(
!
ret
&&
!
d0i3
)
mvmvif
->
bf_data
.
bf_enabled
=
true
;
return
ret
;
}
int
iwl_mvm_enable_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
u32
flags
)
{
struct
iwl_beacon_filter_cmd
cmd
=
{
IWL_BF_CMD_CONFIG_DEFAULTS
,
.
bf_enable_beacon_filter
=
cpu_to_le32
(
1
),
};
return
_iwl_mvm_enable_beacon_filter
(
mvm
,
vif
,
&
cmd
,
flags
,
false
);
}
int
iwl_mvm_disable_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
struct
ieee80211_vif
*
vif
,
u32
flags
)
{
struct
iwl_beacon_filter_cmd
cmd
=
{};
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
...
...
@@ -720,7 +791,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
return
0
;
ret
=
iwl_mvm_beacon_filter_send_cmd
(
mvm
,
&
cmd
);
ret
=
iwl_mvm_beacon_filter_send_cmd
(
mvm
,
&
cmd
,
flags
);
if
(
!
ret
)
mvmvif
->
bf_data
.
bf_enabled
=
false
;
...
...
@@ -728,23 +799,89 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
return
ret
;
}
int
iwl_mvm_update_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
int
iwl_mvm_update_d0i3_power_mode
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
enable
,
u32
flags
)
{
int
ret
;
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
struct
iwl_mac_power_cmd
cmd
=
{};
if
(
!
mvmvif
->
bf_data
.
bf_enabled
)
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
return
0
;
return
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
);
}
if
(
!
vif
->
bss_conf
.
assoc
)
return
0
;
const
struct
iwl_mvm_power_ops
pm_mac_ops
=
{
.
power_update_mode
=
iwl_mvm_power_mac_update_mode
,
.
power_update_device_mode
=
iwl_mvm_power_update_device
,
.
power_disable
=
iwl_mvm_power_mac_disable
,
.
power_update_binding
=
_iwl_mvm_power_update_binding
,
iwl_mvm_power_build_cmd
(
mvm
,
vif
,
&
cmd
);
if
(
enable
)
{
/* configure skip over dtim up to 300 msec */
int
dtimper
=
mvm
->
hw
->
conf
.
ps_dtim_period
?:
1
;
int
dtimper_msec
=
dtimper
*
vif
->
bss_conf
.
beacon_int
;
if
(
WARN_ON
(
!
dtimper_msec
))
return
0
;
cmd
.
flags
|=
cpu_to_le16
(
POWER_FLAGS_SKIP_OVER_DTIM_MSK
);
cmd
.
skip_dtim_periods
=
300
/
dtimper_msec
;
}
iwl_mvm_power_log
(
mvm
,
&
cmd
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
.
power_dbgfs_read
=
iwl_mvm_power_mac_dbgfs_read
,
memcpy
(
&
mvmvif
->
mac_pwr_cmd
,
&
cmd
,
sizeof
(
cmd
));
#endif
};
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
MAC_PM_POWER_TABLE
,
flags
,
sizeof
(
cmd
),
&
cmd
);
if
(
ret
)
return
ret
;
/* configure beacon filtering */
if
(
mvmvif
!=
mvm
->
bf_allowed_vif
)
return
0
;
if
(
enable
)
{
struct
iwl_beacon_filter_cmd
cmd_bf
=
{
IWL_BF_CMD_CONFIG_D0I3
,
.
bf_enable_beacon_filter
=
cpu_to_le32
(
1
),
};
ret
=
_iwl_mvm_enable_beacon_filter
(
mvm
,
vif
,
&
cmd_bf
,
flags
,
true
);
}
else
{
if
(
mvmvif
->
bf_data
.
bf_enabled
)
ret
=
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
,
flags
);
else
ret
=
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
,
flags
);
}
return
ret
;
}
int
iwl_mvm_update_beacon_filter
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
force
,
u32
flags
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
if
(
mvmvif
!=
mvm
->
bf_allowed_vif
)
return
0
;
if
(
!
mvmvif
->
bf_data
.
bf_enabled
)
{
/* disable beacon filtering explicitly if force is true */
if
(
force
)
return
iwl_mvm_disable_beacon_filter
(
mvm
,
vif
,
flags
);
return
0
;
}
return
iwl_mvm_enable_beacon_filter
(
mvm
,
vif
,
flags
);
}
int
iwl_power_legacy_set_cam_mode
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_powertable_cmd
cmd
=
{
.
keep_alive_seconds
=
POWER_KEEP_ALIVE_PERIOD_SEC
,
};
return
iwl_mvm_send_cmd_pdu
(
mvm
,
POWER_TABLE_CMD
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
}
drivers/net/wireless/iwlwifi/mvm/power_legacy.c
deleted
100644 → 0
View file @
b28a960c
/******************************************************************************
*
* 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) 2012 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <net/mac80211.h>
#include "iwl-debug.h"
#include "mvm.h"
#include "iwl-modparams.h"
#include "fw-api-power.h"
#define POWER_KEEP_ALIVE_PERIOD_SEC 25
static
void
iwl_mvm_power_log
(
struct
iwl_mvm
*
mvm
,
struct
iwl_powertable_cmd
*
cmd
)
{
IWL_DEBUG_POWER
(
mvm
,
"Sending power table command for power level %d, flags = 0x%X
\n
"
,
iwlmvm_mod_params
.
power_scheme
,
le16_to_cpu
(
cmd
->
flags
));
IWL_DEBUG_POWER
(
mvm
,
"Keep alive = %u sec
\n
"
,
cmd
->
keep_alive_seconds
);
if
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
))
{
IWL_DEBUG_POWER
(
mvm
,
"Rx timeout = %u usec
\n
"
,
le32_to_cpu
(
cmd
->
rx_data_timeout
));
IWL_DEBUG_POWER
(
mvm
,
"Tx timeout = %u usec
\n
"
,
le32_to_cpu
(
cmd
->
tx_data_timeout
));
if
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_SKIP_OVER_DTIM_MSK
))
IWL_DEBUG_POWER
(
mvm
,
"DTIM periods to skip = %u
\n
"
,
le32_to_cpu
(
cmd
->
skip_dtim_periods
));
if
(
cmd
->
flags
&
cpu_to_le16
(
POWER_FLAGS_LPRX_ENA_MSK
))
IWL_DEBUG_POWER
(
mvm
,
"LP RX RSSI threshold = %u
\n
"
,
le32_to_cpu
(
cmd
->
lprx_rssi_threshold
));
}
}
static
void
iwl_mvm_power_build_cmd
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
iwl_powertable_cmd
*
cmd
)
{
struct
ieee80211_hw
*
hw
=
mvm
->
hw
;
struct
ieee80211_chanctx_conf
*
chanctx_conf
;
struct
ieee80211_channel
*
chan
;
int
dtimper
,
dtimper_msec
;
int
keep_alive
;
bool
radar_detect
=
false
;
struct
iwl_mvm_vif
*
mvmvif
__maybe_unused
=
iwl_mvm_vif_from_mac80211
(
vif
);
/*
* Regardless of power management state the driver must set
* keep alive period. FW will use it for sending keep alive NDPs
* immediately after association.
*/
cmd
->
keep_alive_seconds
=
POWER_KEEP_ALIVE_PERIOD_SEC
;
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
)
return
;
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
if
(
!
vif
->
bss_conf
.
assoc
)
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_DISABLE_POWER_OFF
&&
mvmvif
->
dbgfs_pm
.
disable_power_off
)
cmd
->
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
#endif
if
(
!
vif
->
bss_conf
.
ps
)
return
;
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
);
if
(
vif
->
bss_conf
.
beacon_rate
&&
(
vif
->
bss_conf
.
beacon_rate
->
bitrate
==
10
||
vif
->
bss_conf
.
beacon_rate
->
bitrate
==
60
))
{
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_LPRX_ENA_MSK
);
cmd
->
lprx_rssi_threshold
=
cpu_to_le32
(
POWER_LPRX_RSSI_THRESHOLD
);
}
dtimper
=
hw
->
conf
.
ps_dtim_period
?:
1
;
/* Check if radar detection is required on current channel */
rcu_read_lock
();
chanctx_conf
=
rcu_dereference
(
vif
->
chanctx_conf
);
WARN_ON
(
!
chanctx_conf
);
if
(
chanctx_conf
)
{
chan
=
chanctx_conf
->
def
.
chan
;
radar_detect
=
chan
->
flags
&
IEEE80211_CHAN_RADAR
;
}
rcu_read_unlock
();
/* Check skip over DTIM conditions */
if
(
!
radar_detect
&&
(
dtimper
<=
10
)
&&
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_LP
||
mvm
->
cur_ucode
==
IWL_UCODE_WOWLAN
))
{
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_SKIP_OVER_DTIM_MSK
);
cmd
->
skip_dtim_periods
=
cpu_to_le32
(
3
);
}
/* Check that keep alive period is at least 3 * DTIM */
dtimper_msec
=
dtimper
*
vif
->
bss_conf
.
beacon_int
;
keep_alive
=
max_t
(
int
,
3
*
dtimper_msec
,
MSEC_PER_SEC
*
cmd
->
keep_alive_seconds
);
keep_alive
=
DIV_ROUND_UP
(
keep_alive
,
MSEC_PER_SEC
);
cmd
->
keep_alive_seconds
=
keep_alive
;
if
(
mvm
->
cur_ucode
!=
IWL_UCODE_WOWLAN
)
{
cmd
->
rx_data_timeout
=
cpu_to_le32
(
100
*
USEC_PER_MSEC
);
cmd
->
tx_data_timeout
=
cpu_to_le32
(
100
*
USEC_PER_MSEC
);
}
else
{
cmd
->
rx_data_timeout
=
cpu_to_le32
(
10
*
USEC_PER_MSEC
);
cmd
->
tx_data_timeout
=
cpu_to_le32
(
10
*
USEC_PER_MSEC
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_KEEP_ALIVE
)
cmd
->
keep_alive_seconds
=
mvmvif
->
dbgfs_pm
.
keep_alive_seconds
;
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_SKIP_OVER_DTIM
)
{
if
(
mvmvif
->
dbgfs_pm
.
skip_over_dtim
)
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_SKIP_OVER_DTIM_MSK
);
else
cmd
->
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_SKIP_OVER_DTIM_MSK
);
}
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_RX_DATA_TIMEOUT
)
cmd
->
rx_data_timeout
=
cpu_to_le32
(
mvmvif
->
dbgfs_pm
.
rx_data_timeout
);
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
)
cmd
->
tx_data_timeout
=
cpu_to_le32
(
mvmvif
->
dbgfs_pm
.
tx_data_timeout
);
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS
)
cmd
->
skip_dtim_periods
=
cpu_to_le32
(
mvmvif
->
dbgfs_pm
.
skip_dtim_periods
);
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_LPRX_ENA
)
{
if
(
mvmvif
->
dbgfs_pm
.
lprx_ena
)
cmd
->
flags
|=
cpu_to_le16
(
POWER_FLAGS_LPRX_ENA_MSK
);
else
cmd
->
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_LPRX_ENA_MSK
);
}
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
)
cmd
->
lprx_rssi_threshold
=
cpu_to_le32
(
mvmvif
->
dbgfs_pm
.
lprx_rssi_threshold
);
#endif
/* CONFIG_IWLWIFI_DEBUGFS */
}
static
int
iwl_mvm_power_legacy_update_mode
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
int
ret
;
bool
ba_enable
;
struct
iwl_powertable_cmd
cmd
=
{};
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
return
0
;
/*
* TODO: The following vif_count verification is temporary condition.
* Avoid power mode update if more than one interface is currently
* active. Remove this condition when FW will support power management
* on multiple MACs.
*/
IWL_DEBUG_POWER
(
mvm
,
"Currently %d interfaces active
\n
"
,
mvm
->
vif_count
);
if
(
mvm
->
vif_count
>
1
)
return
0
;
iwl_mvm_power_build_cmd
(
mvm
,
vif
,
&
cmd
);
iwl_mvm_power_log
(
mvm
,
&
cmd
);
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
POWER_TABLE_CMD
,
CMD_SYNC
,
sizeof
(
cmd
),
&
cmd
);
if
(
ret
)
return
ret
;
ba_enable
=
!!
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
));
return
iwl_mvm_update_beacon_abort
(
mvm
,
vif
,
ba_enable
);
}
static
int
iwl_mvm_power_legacy_disable
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
)
{
struct
iwl_powertable_cmd
cmd
=
{};
struct
iwl_mvm_vif
*
mvmvif
__maybe_unused
=
iwl_mvm_vif_from_mac80211
(
vif
);
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
||
vif
->
p2p
)
return
0
;
if
(
iwlmvm_mod_params
.
power_scheme
!=
IWL_POWER_SCHEME_CAM
)
cmd
.
flags
|=
cpu_to_le16
(
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if
(
mvmvif
->
dbgfs_pm
.
mask
&
MVM_DEBUGFS_PM_DISABLE_POWER_OFF
&&
mvmvif
->
dbgfs_pm
.
disable_power_off
)
cmd
.
flags
&=
cpu_to_le16
(
~
POWER_FLAGS_POWER_SAVE_ENA_MSK
);
#endif
iwl_mvm_power_log
(
mvm
,
&
cmd
);
return
iwl_mvm_send_cmd_pdu
(
mvm
,
POWER_TABLE_CMD
,
CMD_ASYNC
,
sizeof
(
cmd
),
&
cmd
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
int
iwl_mvm_power_legacy_dbgfs_read
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
char
*
buf
,
int
bufsz
)
{
struct
iwl_powertable_cmd
cmd
=
{};
int
pos
=
0
;
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
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"skip_dtim_periods = %d
\n
"
,
le32_to_cpu
(
cmd
.
skip_dtim_periods
));
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
"
,
le16_to_cpu
(
cmd
.
flags
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"keep_alive = %d
\n
"
,
cmd
.
keep_alive_seconds
);
if
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK
))
{
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"skip_over_dtim = %d
\n
"
,
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_SKIP_OVER_DTIM_MSK
))
?
1
:
0
);
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"rx_data_timeout = %d
\n
"
,
le32_to_cpu
(
cmd
.
rx_data_timeout
));
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"tx_data_timeout = %d
\n
"
,
le32_to_cpu
(
cmd
.
tx_data_timeout
));
if
(
cmd
.
flags
&
cpu_to_le16
(
POWER_FLAGS_LPRX_ENA_MSK
))
pos
+=
scnprintf
(
buf
+
pos
,
bufsz
-
pos
,
"lprx_rssi_threshold = %d
\n
"
,
le32_to_cpu
(
cmd
.
lprx_rssi_threshold
));
}
return
pos
;
}
#endif
const
struct
iwl_mvm_power_ops
pm_legacy_ops
=
{
.
power_update_mode
=
iwl_mvm_power_legacy_update_mode
,
.
power_disable
=
iwl_mvm_power_legacy_disable
,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.
power_dbgfs_read
=
iwl_mvm_power_legacy_dbgfs_read
,
#endif
};
drivers/net/wireless/iwlwifi/mvm/quota.c
View file @
e9c65316
...
...
@@ -65,9 +65,14 @@
#include "fw-api.h"
#include "mvm.h"
#define QUOTA_100 IWL_MVM_MAX_QUOTA
#define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100)
struct
iwl_mvm_quota_iterator_data
{
int
n_interfaces
[
MAX_BINDINGS
];
int
colors
[
MAX_BINDINGS
];
int
low_latency
[
MAX_BINDINGS
];
int
n_low_latency_bindings
;
struct
ieee80211_vif
*
new_vif
;
};
...
...
@@ -107,22 +112,29 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_STATION
:
if
(
vif
->
bss_conf
.
assoc
)
data
->
n_interfaces
[
id
]
++
;
break
;
return
;
case
NL80211_IFTYPE_AP
:
case
NL80211_IFTYPE_ADHOC
:
if
(
mvmvif
->
ap_ibss_active
)
data
->
n_interfaces
[
id
]
++
;
break
;
return
;
case
NL80211_IFTYPE_MONITOR
:
if
(
mvmvif
->
monitor_active
)
data
->
n_interfaces
[
id
]
++
;
break
;
return
;
case
NL80211_IFTYPE_P2P_DEVICE
:
break
;
return
;
default:
WARN_ON_ONCE
(
1
);
break
;
return
;
}
data
->
n_interfaces
[
id
]
++
;
if
(
iwl_mvm_vif_low_latency
(
mvmvif
)
&&
!
data
->
low_latency
[
id
])
{
data
->
n_low_latency_bindings
++
;
data
->
low_latency
[
id
]
=
true
;
}
}
...
...
@@ -162,12 +174,13 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
int
iwl_mvm_update_quotas
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
newvif
)
{
struct
iwl_time_quota_cmd
cmd
=
{};
int
i
,
idx
,
ret
,
num_active_macs
,
quota
,
quota_rem
;
int
i
,
idx
,
ret
,
num_active_macs
,
quota
,
quota_rem
,
n_non_lowlat
;
struct
iwl_mvm_quota_iterator_data
data
=
{
.
n_interfaces
=
{},
.
colors
=
{
-
1
,
-
1
,
-
1
,
-
1
},
.
new_vif
=
newvif
,
};
u32
ll_max_duration
;
lockdep_assert_held
(
&
mvm
->
mutex
);
...
...
@@ -186,6 +199,21 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
iwl_mvm_quota_iterator
(
&
data
,
newvif
->
addr
,
newvif
);
}
switch
(
data
.
n_low_latency_bindings
)
{
case
0
:
/* no low latency - use default */
ll_max_duration
=
0
;
break
;
case
1
:
/* SingleBindingLowLatencyMode */
ll_max_duration
=
IWL_MVM_LOWLAT_SINGLE_BINDING_MAXDUR
;
break
;
case
2
:
/* DualBindingLowLatencyMode */
ll_max_duration
=
IWL_MVM_LOWLAT_DUAL_BINDING_MAXDUR
;
break
;
default:
/* MultiBindingLowLatencyMode */
ll_max_duration
=
0
;
break
;
}
/*
* The FW's scheduling session consists of
* IWL_MVM_MAX_QUOTA fragments. Divide these fragments
...
...
@@ -197,11 +225,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
num_active_macs
+=
data
.
n_interfaces
[
i
];
}
n_non_lowlat
=
num_active_macs
;
if
(
data
.
n_low_latency_bindings
==
1
)
{
for
(
i
=
0
;
i
<
MAX_BINDINGS
;
i
++
)
{
if
(
data
.
low_latency
[
i
])
{
n_non_lowlat
-=
data
.
n_interfaces
[
i
];
break
;
}
}
}
if
(
data
.
n_low_latency_bindings
==
1
&&
n_non_lowlat
)
{
/*
* Reserve quota for the low latency binding in case that
* there are several data bindings but only a single
* low latency one. Split the rest of the quota equally
* between the other data interfaces.
*/
quota
=
(
QUOTA_100
-
QUOTA_LOWLAT_MIN
)
/
n_non_lowlat
;
quota_rem
=
QUOTA_100
-
n_non_lowlat
*
quota
-
QUOTA_LOWLAT_MIN
;
}
else
if
(
num_active_macs
)
{
/*
* There are 0 or more than 1 low latency bindings, or all the
* data interfaces belong to the single low latency binding.
* Split the quota equally between the data interfaces.
*/
quota
=
QUOTA_100
/
num_active_macs
;
quota_rem
=
QUOTA_100
%
num_active_macs
;
}
else
{
/* values don't really matter - won't be used */
quota
=
0
;
quota_rem
=
0
;
if
(
num_active_macs
)
{
quota
=
IWL_MVM_MAX_QUOTA
/
num_active_macs
;
quota_rem
=
IWL_MVM_MAX_QUOTA
%
num_active_macs
;
}
for
(
idx
=
0
,
i
=
0
;
i
<
MAX_BINDINGS
;
i
++
)
{
...
...
@@ -211,19 +267,42 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
cmd
.
quotas
[
idx
].
id_and_color
=
cpu_to_le32
(
FW_CMD_ID_AND_COLOR
(
i
,
data
.
colors
[
i
]));
if
(
data
.
n_interfaces
[
i
]
<=
0
)
{
if
(
data
.
n_interfaces
[
i
]
<=
0
)
cmd
.
quotas
[
idx
].
quota
=
cpu_to_le32
(
0
);
cmd
.
quotas
[
idx
].
max_duration
=
cpu_to_le32
(
0
);
}
else
{
else
if
(
data
.
n_low_latency_bindings
==
1
&&
n_non_lowlat
&&
data
.
low_latency
[
i
])
/*
* There is more than one binding, but only one of the
* bindings is in low latency. For this case, allocate
* the minimal required quota for the low latency
* binding.
*/
cmd
.
quotas
[
idx
].
quota
=
cpu_to_le32
(
QUOTA_LOWLAT_MIN
);
else
cmd
.
quotas
[
idx
].
quota
=
cpu_to_le32
(
quota
*
data
.
n_interfaces
[
i
]);
WARN_ONCE
(
le32_to_cpu
(
cmd
.
quotas
[
idx
].
quota
)
>
QUOTA_100
,
"Binding=%d, quota=%u > max=%u
\n
"
,
idx
,
le32_to_cpu
(
cmd
.
quotas
[
idx
].
quota
),
QUOTA_100
);
if
(
data
.
n_interfaces
[
i
]
&&
!
data
.
low_latency
[
i
])
cmd
.
quotas
[
idx
].
max_duration
=
cpu_to_le32
(
ll_max_duration
);
else
cmd
.
quotas
[
idx
].
max_duration
=
cpu_to_le32
(
0
);
}
idx
++
;
}
/* Give the remainder of the session to the first binding */
le32_add_cpu
(
&
cmd
.
quotas
[
0
].
quota
,
quota_rem
);
/* Give the remainder of the session to the first data binding */
for
(
i
=
0
;
i
<
MAX_BINDINGS
;
i
++
)
{
if
(
le32_to_cpu
(
cmd
.
quotas
[
i
].
quota
)
!=
0
)
{
le32_add_cpu
(
&
cmd
.
quotas
[
i
].
quota
,
quota_rem
);
break
;
}
}
iwl_mvm_adjust_quota_for_noa
(
mvm
,
&
cmd
);
...
...
drivers/net/wireless/iwlwifi/mvm/rs.c
View file @
e9c65316
...
...
@@ -380,49 +380,49 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
* (2.4 GHz) band.
*/
static
s32
expected_tpt_legacy
[
IWL_RATE_COUNT
]
=
{
static
const
u16
expected_tpt_legacy
[
IWL_RATE_COUNT
]
=
{
7
,
13
,
35
,
58
,
40
,
57
,
72
,
98
,
121
,
154
,
177
,
186
,
0
,
0
,
0
};
/* 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
]
=
{
static
const
u16
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_siso_40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
static
const
u16
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
]
=
{
static
const
u16
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
]
=
{
static
const
u16
expected_tpt_mimo2_20MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
0
,
0
,
0
,
0
,
74
,
0
,
123
,
155
,
179
,
213
,
235
,
243
,
250
,
261
,
0
},
{
0
,
0
,
0
,
0
,
81
,
0
,
131
,
164
,
187
,
221
,
242
,
250
,
256
,
267
,
0
},
{
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
]
=
{
static
const
u16
expected_tpt_mimo2_40MHz
[
4
][
IWL_RATE_COUNT
]
=
{
{
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
]
=
{
static
const
u16
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
},
...
...
@@ -905,7 +905,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rate
->
bw
=
RATE_MCS_CHAN_WIDTH_20
;
WARN_ON_ONCE
(
rate
->
index
<
IWL_RATE_MCS_0_INDEX
&&
WARN_ON_ONCE
(
rate
->
index
<
IWL_RATE_MCS_0_INDEX
||
rate
->
index
>
IWL_RATE_MCS_9_INDEX
);
rate
->
index
=
rs_ht_to_legacy
[
rate
->
index
];
...
...
@@ -1169,12 +1169,12 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
lq_sta
->
visited_columns
=
0
;
}
static
s32
*
rs_get_expected_tpt_table
(
struct
iwl_lq_sta
*
lq_sta
,
static
const
u16
*
rs_get_expected_tpt_table
(
struct
iwl_lq_sta
*
lq_sta
,
const
struct
rs_tx_column
*
column
,
u32
bw
)
{
/* Used to choose among HT tables */
s32
(
*
ht_tbl_pointer
)[
IWL_RATE_COUNT
];
const
u16
(
*
ht_tbl_pointer
)[
IWL_RATE_COUNT
];
if
(
WARN_ON_ONCE
(
column
->
mode
!=
RS_LEGACY
&&
column
->
mode
!=
RS_SISO
&&
...
...
@@ -1262,9 +1262,8 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
s32
active_sr
=
active_tbl
->
win
[
index
].
success_ratio
;
s32
active_tpt
=
active_tbl
->
expected_tpt
[
index
];
/* expected "search" throughput */
s32
*
tpt_tbl
=
tbl
->
expected_tpt
;
const
u16
*
tpt_tbl
=
tbl
->
expected_tpt
;
s32
new_rate
,
high
,
low
,
start_hi
;
u16
high_low
;
...
...
@@ -1479,7 +1478,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
const
struct
rs_tx_column
*
next_col
;
allow_column_func_t
allow_func
;
u8
valid_ants
=
iwl_fw_valid_tx_ant
(
mvm
->
fw
);
s32
*
expected_tpt_tbl
;
const
u16
*
expected_tpt_tbl
;
s32
tpt
,
max_expected_tpt
;
for
(
i
=
0
;
i
<
MAX_NEXT_COLUMNS
;
i
++
)
{
...
...
drivers/net/wireless/iwlwifi/mvm/rs.h
View file @
e9c65316
...
...
@@ -277,7 +277,7 @@ enum rs_column {
struct
iwl_scale_tbl_info
{
struct
rs_rate
rate
;
enum
rs_column
column
;
s32
*
expected_tpt
;
/* throughput metrics; expected_tpt_G, etc. */
const
u16
*
expected_tpt
;
/* throughput metrics; expected_tpt_G, etc. */
struct
iwl_rate_scale_data
win
[
IWL_RATE_COUNT
];
/* rate histories */
};
...
...
drivers/net/wireless/iwlwifi/mvm/rx.c
View file @
e9c65316
...
...
@@ -129,22 +129,16 @@ static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm,
struct
ieee80211_rx_status
*
rx_status
)
{
int
rssi_a
,
rssi_b
,
rssi_a_dbm
,
rssi_b_dbm
,
max_rssi_dbm
;
int
rssi_all_band_a
,
rssi_all_band_b
;
u32
agc_a
,
agc_b
,
max_agc
;
u32
agc_a
,
agc_b
;
u32
val
;
val
=
le32_to_cpu
(
phy_info
->
non_cfg_phy
[
IWL_RX_INFO_AGC_IDX
]);
agc_a
=
(
val
&
IWL_OFDM_AGC_A_MSK
)
>>
IWL_OFDM_AGC_A_POS
;
agc_b
=
(
val
&
IWL_OFDM_AGC_B_MSK
)
>>
IWL_OFDM_AGC_B_POS
;
max_agc
=
max_t
(
u32
,
agc_a
,
agc_b
);
val
=
le32_to_cpu
(
phy_info
->
non_cfg_phy
[
IWL_RX_INFO_RSSI_AB_IDX
]);
rssi_a
=
(
val
&
IWL_OFDM_RSSI_INBAND_A_MSK
)
>>
IWL_OFDM_RSSI_A_POS
;
rssi_b
=
(
val
&
IWL_OFDM_RSSI_INBAND_B_MSK
)
>>
IWL_OFDM_RSSI_B_POS
;
rssi_all_band_a
=
(
val
&
IWL_OFDM_RSSI_ALLBAND_A_MSK
)
>>
IWL_OFDM_RSSI_ALLBAND_A_POS
;
rssi_all_band_b
=
(
val
&
IWL_OFDM_RSSI_ALLBAND_B_MSK
)
>>
IWL_OFDM_RSSI_ALLBAND_B_POS
;
/*
* dBm = rssi dB - agc dB - constant.
...
...
drivers/net/wireless/iwlwifi/mvm/scan.c
View file @
e9c65316
...
...
@@ -407,6 +407,8 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
mvm
->
scan_status
=
IWL_MVM_SCAN_NONE
;
ieee80211_scan_completed
(
mvm
->
hw
,
notif
->
status
!=
SCAN_COMP_STATUS_OK
);
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_SCAN
);
return
0
;
}
...
...
@@ -475,6 +477,7 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
if
(
iwl_mvm_is_radio_killed
(
mvm
))
{
ieee80211_scan_completed
(
mvm
->
hw
,
true
);
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_SCAN
);
mvm
->
scan_status
=
IWL_MVM_SCAN_NONE
;
return
;
}
...
...
@@ -487,7 +490,7 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
ret
=
iwl_mvm_send_cmd_pdu
(
mvm
,
SCAN_ABORT_CMD
,
CMD_SYNC
,
0
,
NULL
);
if
(
ret
)
{
IWL_ERR
(
mvm
,
"Couldn't send SCAN_ABORT_CMD: %d
\n
"
,
ret
);
/* mac80211's state will be cleaned in the
fw
_restart flow */
/* mac80211's state will be cleaned in the
nic
_restart flow */
goto
out_remove_notif
;
}
...
...
@@ -508,10 +511,15 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
struct
iwl_rx_packet
*
pkt
=
rxb_addr
(
rxb
);
struct
iwl_scan_offload_complete
*
scan_notif
=
(
void
*
)
pkt
->
data
;
/* scan status must be locked for proper checking */
lockdep_assert_held
(
&
mvm
->
mutex
);
IWL_DEBUG_SCAN
(
mvm
,
"Scheduled scan completed, status %s
\n
"
,
scan_notif
->
status
==
IWL_SCAN_OFFLOAD_COMPLETED
?
"completed"
:
"aborted"
);
/* might already be something else again, don't reset if so */
if
(
mvm
->
scan_status
==
IWL_MVM_SCAN_SCHED
)
mvm
->
scan_status
=
IWL_MVM_SCAN_NONE
;
ieee80211_sched_scan_stopped
(
mvm
->
hw
);
...
...
drivers/net/wireless/iwlwifi/mvm/sta.c
View file @
e9c65316
...
...
@@ -66,27 +66,27 @@
#include "sta.h"
#include "rs.h"
static
void
iwl_mvm_add_sta_cmd_v
6_to_v5
(
struct
iwl_mvm_add_sta_cmd_v6
*
cmd_v6
,
static
void
iwl_mvm_add_sta_cmd_v
7_to_v5
(
struct
iwl_mvm_add_sta_cmd_v7
*
cmd_v7
,
struct
iwl_mvm_add_sta_cmd_v5
*
cmd_v5
)
{
memset
(
cmd_v5
,
0
,
sizeof
(
*
cmd_v5
));
cmd_v5
->
add_modify
=
cmd_v
6
->
add_modify
;
cmd_v5
->
tid_disable_tx
=
cmd_v
6
->
tid_disable_tx
;
cmd_v5
->
mac_id_n_color
=
cmd_v
6
->
mac_id_n_color
;
memcpy
(
cmd_v5
->
addr
,
cmd_v
6
->
addr
,
ETH_ALEN
);
cmd_v5
->
sta_id
=
cmd_v
6
->
sta_id
;
cmd_v5
->
modify_mask
=
cmd_v
6
->
modify_mask
;
cmd_v5
->
station_flags
=
cmd_v
6
->
station_flags
;
cmd_v5
->
station_flags_msk
=
cmd_v
6
->
station_flags_msk
;
cmd_v5
->
add_immediate_ba_tid
=
cmd_v
6
->
add_immediate_ba_tid
;
cmd_v5
->
remove_immediate_ba_tid
=
cmd_v
6
->
remove_immediate_ba_tid
;
cmd_v5
->
add_immediate_ba_ssn
=
cmd_v
6
->
add_immediate_ba_ssn
;
cmd_v5
->
sleep_tx_count
=
cmd_v
6
->
sleep_tx_count
;
cmd_v5
->
sleep_state_flags
=
cmd_v
6
->
sleep_state_flags
;
cmd_v5
->
assoc_id
=
cmd_v
6
->
assoc_id
;
cmd_v5
->
beamform_flags
=
cmd_v
6
->
beamform_flags
;
cmd_v5
->
tfd_queue_msk
=
cmd_v
6
->
tfd_queue_msk
;
cmd_v5
->
add_modify
=
cmd_v
7
->
add_modify
;
cmd_v5
->
tid_disable_tx
=
cmd_v
7
->
tid_disable_tx
;
cmd_v5
->
mac_id_n_color
=
cmd_v
7
->
mac_id_n_color
;
memcpy
(
cmd_v5
->
addr
,
cmd_v
7
->
addr
,
ETH_ALEN
);
cmd_v5
->
sta_id
=
cmd_v
7
->
sta_id
;
cmd_v5
->
modify_mask
=
cmd_v
7
->
modify_mask
;
cmd_v5
->
station_flags
=
cmd_v
7
->
station_flags
;
cmd_v5
->
station_flags_msk
=
cmd_v
7
->
station_flags_msk
;
cmd_v5
->
add_immediate_ba_tid
=
cmd_v
7
->
add_immediate_ba_tid
;
cmd_v5
->
remove_immediate_ba_tid
=
cmd_v
7
->
remove_immediate_ba_tid
;
cmd_v5
->
add_immediate_ba_ssn
=
cmd_v
7
->
add_immediate_ba_ssn
;
cmd_v5
->
sleep_tx_count
=
cmd_v
7
->
sleep_tx_count
;
cmd_v5
->
sleep_state_flags
=
cmd_v
7
->
sleep_state_flags
;
cmd_v5
->
assoc_id
=
cmd_v
7
->
assoc_id
;
cmd_v5
->
beamform_flags
=
cmd_v
7
->
beamform_flags
;
cmd_v5
->
tfd_queue_msk
=
cmd_v
7
->
tfd_queue_msk
;
}
static
void
...
...
@@ -110,7 +110,7 @@ iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd,
}
static
int
iwl_mvm_send_add_sta_cmd_status
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_add_sta_cmd_v
6
*
cmd
,
struct
iwl_mvm_add_sta_cmd_v
7
*
cmd
,
int
*
status
)
{
struct
iwl_mvm_add_sta_cmd_v5
cmd_v5
;
...
...
@@ -119,14 +119,14 @@ static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm,
return
iwl_mvm_send_cmd_pdu_status
(
mvm
,
ADD_STA
,
sizeof
(
*
cmd
),
cmd
,
status
);
iwl_mvm_add_sta_cmd_v
6
_to_v5
(
cmd
,
&
cmd_v5
);
iwl_mvm_add_sta_cmd_v
7
_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_v
6
*
cmd
)
struct
iwl_mvm_add_sta_cmd_v
7
*
cmd
)
{
struct
iwl_mvm_add_sta_cmd_v5
cmd_v5
;
...
...
@@ -134,7 +134,7 @@ static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags,
return
iwl_mvm_send_cmd_pdu
(
mvm
,
ADD_STA
,
flags
,
sizeof
(
*
cmd
),
cmd
);
iwl_mvm_add_sta_cmd_v
6
_to_v5
(
cmd
,
&
cmd_v5
);
iwl_mvm_add_sta_cmd_v
7
_to_v5
(
cmd
,
&
cmd_v5
);
return
iwl_mvm_send_cmd_pdu
(
mvm
,
ADD_STA
,
flags
,
sizeof
(
cmd_v5
),
&
cmd_v5
);
...
...
@@ -175,19 +175,30 @@ static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm,
&
sta_cmd
);
}
static
int
iwl_mvm_find_free_sta_id
(
struct
iwl_mvm
*
mvm
)
static
int
iwl_mvm_find_free_sta_id
(
struct
iwl_mvm
*
mvm
,
enum
nl80211_iftype
iftype
)
{
int
sta_id
;
u32
reserved_ids
=
0
;
BUILD_BUG_ON
(
IWL_MVM_STATION_COUNT
>
32
);
WARN_ON_ONCE
(
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
));
lockdep_assert_held
(
&
mvm
->
mutex
);
/* d0i3/d3 assumes the AP's sta_id (of sta vif) is 0. reserve it. */
if
(
iftype
!=
NL80211_IFTYPE_STATION
)
reserved_ids
=
BIT
(
0
);
/* Don't take rcu_read_lock() since we are protected by mvm->mutex */
for
(
sta_id
=
0
;
sta_id
<
IWL_MVM_STATION_COUNT
;
sta_id
++
)
for
(
sta_id
=
0
;
sta_id
<
IWL_MVM_STATION_COUNT
;
sta_id
++
)
{
if
(
BIT
(
sta_id
)
&
reserved_ids
)
continue
;
if
(
!
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
)))
return
sta_id
;
}
return
IWL_MVM_STATION_COUNT
;
}
...
...
@@ -196,7 +207,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_v
6
add_sta_cmd
;
struct
iwl_mvm_add_sta_cmd_v
7
add_sta_cmd
;
int
ret
;
u32
status
;
u32
agg_size
=
0
,
mpdu_dens
=
0
;
...
...
@@ -312,7 +323,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
lockdep_assert_held
(
&
mvm
->
mutex
);
if
(
!
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
))
sta_id
=
iwl_mvm_find_free_sta_id
(
mvm
);
sta_id
=
iwl_mvm_find_free_sta_id
(
mvm
,
ieee80211_vif_type_p2p
(
vif
));
else
sta_id
=
mvm_sta
->
sta_id
;
...
...
@@ -368,7 +380,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_v
6
cmd
=
{};
struct
iwl_mvm_add_sta_cmd_v
7
cmd
=
{};
int
ret
;
u32
status
;
...
...
@@ -522,6 +534,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
/* unassoc - go ahead - remove the AP STA now */
mvmvif
->
ap_sta_id
=
IWL_MVM_STATION_COUNT
;
/* clear d0i3_ap_sta_id if no longer relevant */
if
(
mvm
->
d0i3_ap_sta_id
==
mvm_sta
->
sta_id
)
mvm
->
d0i3_ap_sta_id
=
IWL_MVM_STATION_COUNT
;
}
/*
...
...
@@ -560,10 +576,10 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
}
int
iwl_mvm_allocate_int_sta
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_int_sta
*
sta
,
u32
qmask
)
u32
qmask
,
enum
nl80211_iftype
iftype
)
{
if
(
!
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
))
{
sta
->
sta_id
=
iwl_mvm_find_free_sta_id
(
mvm
);
sta
->
sta_id
=
iwl_mvm_find_free_sta_id
(
mvm
,
iftype
);
if
(
WARN_ON_ONCE
(
sta
->
sta_id
==
IWL_MVM_STATION_COUNT
))
return
-
ENOSPC
;
}
...
...
@@ -587,13 +603,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_v
6
cmd
;
struct
iwl_mvm_add_sta_cmd_v
7
cmd
;
int
ret
;
u32
status
;
lockdep_assert_held
(
&
mvm
->
mutex
);
memset
(
&
cmd
,
0
,
sizeof
(
struct
iwl_mvm_add_sta_cmd_v
6
));
memset
(
&
cmd
,
0
,
sizeof
(
struct
iwl_mvm_add_sta_cmd_v
7
));
cmd
.
sta_id
=
sta
->
sta_id
;
cmd
.
mac_id_n_color
=
cpu_to_le32
(
FW_CMD_ID_AND_COLOR
(
mac_id
,
color
));
...
...
@@ -627,7 +643,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
lockdep_assert_held
(
&
mvm
->
mutex
);
/* Add the aux station, but without any queues */
ret
=
iwl_mvm_allocate_int_sta
(
mvm
,
&
mvm
->
aux_sta
,
0
);
ret
=
iwl_mvm_allocate_int_sta
(
mvm
,
&
mvm
->
aux_sta
,
0
,
NL80211_IFTYPE_UNSPECIFIED
);
if
(
ret
)
return
ret
;
...
...
@@ -699,7 +716,8 @@ int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held
(
&
mvm
->
mutex
);
qmask
=
iwl_mvm_mac_get_queues_mask
(
mvm
,
vif
);
ret
=
iwl_mvm_allocate_int_sta
(
mvm
,
bsta
,
qmask
);
ret
=
iwl_mvm_allocate_int_sta
(
mvm
,
bsta
,
qmask
,
ieee80211_vif_type_p2p
(
vif
));
if
(
ret
)
return
ret
;
...
...
@@ -735,7 +753,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_v
6
cmd
=
{};
struct
iwl_mvm_add_sta_cmd_v
7
cmd
=
{};
int
ret
;
u32
status
;
...
...
@@ -794,7 +812,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_v
6
cmd
=
{};
struct
iwl_mvm_add_sta_cmd_v
7
cmd
=
{};
int
ret
;
u32
status
;
...
...
@@ -833,7 +851,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
return
ret
;
}
static
const
u8
tid_to_ac
[]
=
{
static
const
u8
tid_to_
mac80211_
ac
[]
=
{
IEEE80211_AC_BE
,
IEEE80211_AC_BK
,
IEEE80211_AC_BK
,
...
...
@@ -844,6 +862,17 @@ static const u8 tid_to_ac[] = {
IEEE80211_AC_VO
,
};
static
const
u8
tid_to_ucode_ac
[]
=
{
AC_BE
,
AC_BK
,
AC_BK
,
AC_BE
,
AC_VI
,
AC_VI
,
AC_VO
,
AC_VO
,
};
int
iwl_mvm_sta_tx_agg_start
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
u16
tid
,
u16
*
ssn
)
{
...
...
@@ -874,7 +903,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
/* the new tx queue is still connected to the same mac80211 queue */
mvm
->
queue_to_mac80211
[
txq_id
]
=
vif
->
hw_queue
[
tid_to_ac
[
tid
]];
mvm
->
queue_to_mac80211
[
txq_id
]
=
vif
->
hw_queue
[
tid_to_
mac80211_
ac
[
tid
]];
spin_lock_bh
(
&
mvmsta
->
lock
);
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
...
...
@@ -916,7 +945,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
tid_data
->
ssn
=
0xffff
;
spin_unlock_bh
(
&
mvmsta
->
lock
);
fifo
=
iwl_mvm_ac_to_tx_fifo
[
tid_to_ac
[
tid
]];
fifo
=
iwl_mvm_ac_to_tx_fifo
[
tid_to_
mac80211_
ac
[
tid
]];
ret
=
iwl_mvm_sta_tx_agg
(
mvm
,
sta
,
tid
,
queue
,
true
);
if
(
ret
)
...
...
@@ -1411,7 +1440,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
);
struct
iwl_mvm_add_sta_cmd_v
6
cmd
=
{
struct
iwl_mvm_add_sta_cmd_v
7
cmd
=
{
.
add_modify
=
STA_MODE_MODIFY
,
.
sta_id
=
mvmsta
->
sta_id
,
.
station_flags_msk
=
cpu_to_le32
(
STA_FLG_PS
),
...
...
@@ -1427,28 +1456,102 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
void
iwl_mvm_sta_modify_sleep_tx_count
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
enum
ieee80211_frame_release_type
reason
,
u16
cnt
)
u16
cnt
,
u16
tids
,
bool
more_data
,
bool
agg
)
{
u16
sleep_state_flags
=
(
reason
==
IEEE80211_FRAME_RELEASE_UAPSD
)
?
STA_SLEEP_STATE_UAPSD
:
STA_SLEEP_STATE_PS_POLL
;
struct
iwl_mvm_sta
*
mvmsta
=
iwl_mvm_sta_from_mac80211
(
sta
);
struct
iwl_mvm_add_sta_cmd_v
6
cmd
=
{
struct
iwl_mvm_add_sta_cmd_v
7
cmd
=
{
.
add_modify
=
STA_MODE_MODIFY
,
.
sta_id
=
mvmsta
->
sta_id
,
.
modify_mask
=
STA_MODIFY_SLEEPING_STA_TX_COUNT
,
.
sleep_tx_count
=
cpu_to_le16
(
cnt
),
.
mac_id_n_color
=
cpu_to_le32
(
mvmsta
->
mac_id_n_color
),
/*
* Same modify mask for sleep_tx_count and sleep_state_flags so
* we must set the sleep_state_flags too.
*/
.
sleep_state_flags
=
cpu_to_le16
(
sleep_state_flags
),
};
int
ret
;
int
tid
,
ret
;
unsigned
long
_tids
=
tids
;
/* convert TIDs to ACs - we don't support TSPEC so that's OK
* Note that this field is reserved and unused by firmware not
* supporting GO uAPSD, so it's safe to always do this.
*/
for_each_set_bit
(
tid
,
&
_tids
,
IWL_MAX_TID_COUNT
)
cmd
.
awake_acs
|=
BIT
(
tid_to_ucode_ac
[
tid
]);
/* If we're releasing frames from aggregation queues then check if the
* all queues combined that we're releasing frames from have
* - more frames than the service period, in which case more_data
* needs to be set
* - fewer than 'cnt' frames, in which case we need to adjust the
* firmware command (but do that unconditionally)
*/
if
(
agg
)
{
int
remaining
=
cnt
;
spin_lock_bh
(
&
mvmsta
->
lock
);
for_each_set_bit
(
tid
,
&
_tids
,
IWL_MAX_TID_COUNT
)
{
struct
iwl_mvm_tid_data
*
tid_data
;
u16
n_queued
;
tid_data
=
&
mvmsta
->
tid_data
[
tid
];
if
(
WARN
(
tid_data
->
state
!=
IWL_AGG_ON
&&
tid_data
->
state
!=
IWL_EMPTYING_HW_QUEUE_DELBA
,
"TID %d state is %d
\n
"
,
tid
,
tid_data
->
state
))
{
spin_unlock_bh
(
&
mvmsta
->
lock
);
ieee80211_sta_eosp
(
sta
);
return
;
}
n_queued
=
iwl_mvm_tid_queued
(
tid_data
);
if
(
n_queued
>
remaining
)
{
more_data
=
true
;
remaining
=
0
;
break
;
}
remaining
-=
n_queued
;
}
spin_unlock_bh
(
&
mvmsta
->
lock
);
cmd
.
sleep_tx_count
=
cpu_to_le16
(
cnt
-
remaining
);
if
(
WARN_ON
(
cnt
-
remaining
==
0
))
{
ieee80211_sta_eosp
(
sta
);
return
;
}
}
/* Note: this is ignored by firmware not supporting GO uAPSD */
if
(
more_data
)
cmd
.
sleep_state_flags
|=
cpu_to_le16
(
STA_SLEEP_STATE_MOREDATA
);
if
(
reason
==
IEEE80211_FRAME_RELEASE_PSPOLL
)
{
mvmsta
->
next_status_eosp
=
true
;
cmd
.
sleep_state_flags
|=
cpu_to_le16
(
STA_SLEEP_STATE_PS_POLL
);
}
else
{
cmd
.
sleep_state_flags
|=
cpu_to_le16
(
STA_SLEEP_STATE_UAPSD
);
}
/* TODO: somehow the fw doesn't seem to take PS_POLL into account */
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
);
}
int
iwl_mvm_rx_eosp_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_mvm_eosp_notification
*
notif
=
(
void
*
)
pkt
->
data
;
struct
ieee80211_sta
*
sta
;
u32
sta_id
=
le32_to_cpu
(
notif
->
sta_id
);
if
(
WARN_ON_ONCE
(
sta_id
>=
IWL_MVM_STATION_COUNT
))
return
0
;
rcu_read_lock
();
sta
=
rcu_dereference
(
mvm
->
fw_id_to_mac_id
[
sta_id
]);
if
(
!
IS_ERR_OR_NULL
(
sta
))
ieee80211_sta_eosp
(
sta
);
rcu_read_unlock
();
return
0
;
}
drivers/net/wireless/iwlwifi/mvm/sta.h
View file @
e9c65316
...
...
@@ -195,24 +195,33 @@ struct iwl_mvm;
/**
* DOC: AP mode - PS
*
* When a station is asleep, the fw will set it as "asleep". All the
* non-aggregation frames to that station will be dropped by the fw
* (%TX_STATUS_FAIL_DEST_PS failure code).
* When a station is asleep, the fw will set it as "asleep". All frames on
* shared queues (i.e. non-aggregation queues) to that station will be dropped
* by the fw (%TX_STATUS_FAIL_DEST_PS failure code).
*
* AMPDUs are in a separate queue that is stopped by the fw. We just need to
* let mac80211 know
how many frames we have
in these queues so that it can
* let mac80211 know
when there are frames
in these queues so that it can
* properly handle trigger frames.
* When the a trigger frame is received, mac80211 tells the driver to send
* frames from the AMPDU queues or AC queue depending on which queue are
* delivery-enabled and what TID has frames to transmit (Note that mac80211 has
* all the knowledege since all the non-agg frames are buffered / filtered, and
* the driver tells mac80211 about agg frames). The driver needs to tell the fw
* to let frames out even if the station is asleep. This is done by
* %iwl_mvm_sta_modify_sleep_tx_count.
* When we receive a frame from that station with PM bit unset, the
* driver needs to let the fw know that this station isn't alseep any more.
* This is done by %iwl_mvm_sta_modify_ps_wake.
*
* TODO - EOSP handling
*
* When a trigger frame is received, mac80211 tells the driver to send frames
* from the AMPDU queues or sends frames to non-aggregation queues itself,
* depending on which ACs are delivery-enabled and what TID has frames to
* transmit. Note that mac80211 has all the knowledege since all the non-agg
* frames are buffered / filtered, and the driver tells mac80211 about agg
* frames). The driver needs to tell the fw to let frames out even if the
* station is asleep. This is done by %iwl_mvm_sta_modify_sleep_tx_count.
*
* When we receive a frame from that station with PM bit unset, the driver
* needs to let the fw know that this station isn't asleep any more. This is
* done by %iwl_mvm_sta_modify_ps_wake in response to mac80211 signalling the
* station's wakeup.
*
* For a GO, the Service Period might be cut short due to an absence period
* of the GO. In this (and all other cases) the firmware notifies us with the
* EOSP_NOTIFICATION, and we notify mac80211 of that. Further frames that we
* already sent to the device will be rejected again.
*
* See also "AP support for powersaving clients" in mac80211.h.
*/
/**
...
...
@@ -261,6 +270,12 @@ struct iwl_mvm_tid_data {
u16
ssn
;
};
static
inline
u16
iwl_mvm_tid_queued
(
struct
iwl_mvm_tid_data
*
tid_data
)
{
return
ieee80211_sn_sub
(
IEEE80211_SEQ_TO_SN
(
tid_data
->
seq_number
),
tid_data
->
next_reclaimed
);
}
/**
* struct iwl_mvm_sta - representation of a station in the driver
* @sta_id: the index of the station in the fw (will be replaced by id_n_color)
...
...
@@ -269,7 +284,11 @@ struct iwl_mvm_tid_data {
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
* tid.
* @max_agg_bufsize: the maximal size of the AGG buffer for this station
* @bt_reduced_txpower_dbg: debug mode in which %bt_reduced_txpower is forced
* by debugfs.
* @bt_reduced_txpower: is reduced tx power enabled for this station
* @next_status_eosp: the next reclaimed packet is a PS-Poll response and
* we need to signal the EOSP
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx
* and from Tx response flow, it needs a spinlock.
* @tid_data: per tid data. Look at %iwl_mvm_tid_data.
...
...
@@ -287,7 +306,9 @@ struct iwl_mvm_sta {
u32
mac_id_n_color
;
u16
tid_disable_agg
;
u8
max_agg_bufsize
;
bool
bt_reduced_txpower_dbg
;
bool
bt_reduced_txpower
;
bool
next_status_eosp
;
spinlock_t
lock
;
struct
iwl_mvm_tid_data
tid_data
[
IWL_MAX_TID_COUNT
];
struct
iwl_lq_sta
lq_sta
;
...
...
@@ -345,6 +366,10 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
struct
ieee80211_sta
*
sta
,
u32
iv32
,
u16
*
phase1key
);
int
iwl_mvm_rx_eosp_notif
(
struct
iwl_mvm
*
mvm
,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
);
/* AMPDU */
int
iwl_mvm_sta_rx_agg
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
int
tid
,
u16
ssn
,
bool
start
);
...
...
@@ -359,7 +384,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int
iwl_mvm_add_aux_sta
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_allocate_int_sta
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_int_sta
*
sta
,
u32
qmask
);
u32
qmask
,
enum
nl80211_iftype
iftype
);
void
iwl_mvm_dealloc_int_sta
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_int_sta
*
sta
);
int
iwl_mvm_send_bcast_sta
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
...
...
@@ -375,7 +400,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
void
iwl_mvm_sta_modify_sleep_tx_count
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_sta
*
sta
,
enum
ieee80211_frame_release_type
reason
,
u16
cnt
);
u16
cnt
,
u16
tids
,
bool
more_data
,
bool
agg
);
int
iwl_mvm_drain_sta
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_sta
*
mvmsta
,
bool
drain
);
...
...
drivers/net/wireless/iwlwifi/mvm/time-event.c
View file @
e9c65316
...
...
@@ -126,6 +126,7 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
* in iwl_mvm_te_handle_notif).
*/
clear_bit
(
IWL_MVM_STATUS_ROC_RUNNING
,
&
mvm
->
status
);
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_ROC
);
/*
* Of course, our status bit is just as racy as mac80211, so in
...
...
@@ -210,6 +211,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
if
(
te_data
->
vif
->
type
==
NL80211_IFTYPE_P2P_DEVICE
)
{
set_bit
(
IWL_MVM_STATUS_ROC_RUNNING
,
&
mvm
->
status
);
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_ROC
);
ieee80211_ready_on_channel
(
mvm
->
hw
);
}
}
else
{
...
...
drivers/net/wireless/iwlwifi/mvm/tt.c
View file @
e9c65316
...
...
@@ -403,7 +403,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
}
}
static
void
iwl_mvm_tt_tx_backoff
(
struct
iwl_mvm
*
mvm
,
u32
backoff
)
void
iwl_mvm_tt_tx_backoff
(
struct
iwl_mvm
*
mvm
,
u32
backoff
)
{
struct
iwl_host_cmd
cmd
=
{
.
id
=
REPLY_THERMAL_MNG_BACKOFF
,
...
...
@@ -412,6 +412,8 @@ static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
.
flags
=
CMD_SYNC
,
};
backoff
=
max
(
backoff
,
mvm
->
thermal_throttle
.
min_backoff
);
if
(
iwl_mvm_send_cmd
(
mvm
,
&
cmd
)
==
0
)
{
IWL_DEBUG_TEMP
(
mvm
,
"Set Thermal Tx backoff to: %u
\n
"
,
backoff
);
...
...
@@ -534,7 +536,7 @@ static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
.
support_tx_backoff
=
true
,
};
void
iwl_mvm_tt_initialize
(
struct
iwl_mvm
*
mvm
)
void
iwl_mvm_tt_initialize
(
struct
iwl_mvm
*
mvm
,
u32
min_backoff
)
{
struct
iwl_mvm_tt_mgmt
*
tt
=
&
mvm
->
thermal_throttle
;
...
...
@@ -546,6 +548,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm)
tt
->
params
=
&
iwl7000_tt_params
;
tt
->
throttle
=
false
;
tt
->
min_backoff
=
min_backoff
;
INIT_DELAYED_WORK
(
&
tt
->
ct_kill_exit
,
check_exit_ctkill
);
}
...
...
drivers/net/wireless/iwlwifi/mvm/tx.c
View file @
e9c65316
...
...
@@ -377,6 +377,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
tx_cmd
=
(
struct
iwl_tx_cmd
*
)
dev_cmd
->
payload
;
/* From now on, we cannot access info->control */
/*
* we handle that entirely ourselves -- for uAPSD the firmware
* will always send a notification, and for PS-Poll responses
* we'll notify mac80211 when getting frame status
*/
info
->
flags
&=
~
IEEE80211_TX_STATUS_EOSP
;
spin_lock
(
&
mvmsta
->
lock
);
if
(
ieee80211_is_data_qos
(
fc
)
&&
!
ieee80211_is_qos_nullfunc
(
fc
))
{
...
...
@@ -437,6 +444,17 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
lockdep_assert_held
(
&
mvmsta
->
lock
);
if
((
tid_data
->
state
==
IWL_AGG_ON
||
tid_data
->
state
==
IWL_EMPTYING_HW_QUEUE_DELBA
)
&&
iwl_mvm_tid_queued
(
tid_data
)
==
0
)
{
/*
* Now that this aggregation queue is empty tell mac80211 so it
* knows we no longer have frames buffered for the station on
* this TID (for the TIM bitmap calculation.)
*/
ieee80211_sta_set_buffered
(
sta
,
tid
,
false
);
}
if
(
tid_data
->
ssn
!=
tid_data
->
next_reclaimed
)
return
;
...
...
@@ -674,6 +692,11 @@ 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
);
}
if
(
mvmsta
->
next_status_eosp
)
{
mvmsta
->
next_status_eosp
=
false
;
ieee80211_sta_eosp
(
sta
);
}
}
else
{
sta
=
NULL
;
mvmsta
=
NULL
;
...
...
drivers/net/wireless/iwlwifi/mvm/utils.c
View file @
e9c65316
...
...
@@ -376,9 +376,67 @@ struct iwl_error_event_table {
u32
flow_handler
;
/* FH read/write pointers, RX credit */
}
__packed
;
/*
* UMAC error struct - relevant starting from family 8000 chip.
* Note: This structure is read from the device with IO accesses,
* and the reading already does the endian conversion. As it is
* read with u32-sized accesses, any members with a different size
* need to be ordered correctly though!
*/
struct
iwl_umac_error_event_table
{
u32
valid
;
/* (nonzero) valid, (0) log is empty */
u32
error_id
;
/* type of error */
u32
pc
;
/* program counter */
u32
blink1
;
/* branch link */
u32
blink2
;
/* branch link */
u32
ilink1
;
/* interrupt link */
u32
ilink2
;
/* interrupt link */
u32
data1
;
/* error-specific data */
u32
data2
;
/* error-specific data */
u32
line
;
/* source code line of error */
u32
umac_ver
;
/* umac version */
}
__packed
;
#define ERROR_START_OFFSET (1 * sizeof(u32))
#define ERROR_ELEM_SIZE (7 * sizeof(u32))
static
void
iwl_mvm_dump_umac_error_log
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_trans
*
trans
=
mvm
->
trans
;
struct
iwl_umac_error_event_table
table
;
u32
base
;
base
=
mvm
->
umac_error_event_table
;
if
(
base
<
0x800000
||
base
>=
0x80C000
)
{
IWL_ERR
(
mvm
,
"Not valid error log pointer 0x%08X for %s uCode
\n
"
,
base
,
(
mvm
->
cur_ucode
==
IWL_UCODE_INIT
)
?
"Init"
:
"RT"
);
return
;
}
iwl_trans_read_mem_bytes
(
trans
,
base
,
&
table
,
sizeof
(
table
));
if
(
ERROR_START_OFFSET
<=
table
.
valid
*
ERROR_ELEM_SIZE
)
{
IWL_ERR
(
trans
,
"Start IWL Error Log Dump:
\n
"
);
IWL_ERR
(
trans
,
"Status: 0x%08lX, count: %d
\n
"
,
mvm
->
status
,
table
.
valid
);
}
IWL_ERR
(
mvm
,
"0x%08X | %-28s
\n
"
,
table
.
error_id
,
desc_lookup
(
table
.
error_id
));
IWL_ERR
(
mvm
,
"0x%08X | umac uPc
\n
"
,
table
.
pc
);
IWL_ERR
(
mvm
,
"0x%08X | umac branchlink1
\n
"
,
table
.
blink1
);
IWL_ERR
(
mvm
,
"0x%08X | umac branchlink2
\n
"
,
table
.
blink2
);
IWL_ERR
(
mvm
,
"0x%08X | umac interruptlink1
\n
"
,
table
.
ilink1
);
IWL_ERR
(
mvm
,
"0x%08X | umac interruptlink2
\n
"
,
table
.
ilink2
);
IWL_ERR
(
mvm
,
"0x%08X | umac data1
\n
"
,
table
.
data1
);
IWL_ERR
(
mvm
,
"0x%08X | umac data2
\n
"
,
table
.
data2
);
IWL_ERR
(
mvm
,
"0x%08X | umac version
\n
"
,
table
.
umac_ver
);
}
void
iwl_mvm_dump_nic_error_log
(
struct
iwl_mvm
*
mvm
)
{
struct
iwl_trans
*
trans
=
mvm
->
trans
;
...
...
@@ -394,7 +452,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
base
=
mvm
->
fw
->
inst_errlog_ptr
;
}
if
(
base
<
0x800000
||
base
>=
0x80C000
)
{
if
(
base
<
0x800000
)
{
IWL_ERR
(
mvm
,
"Not valid error log pointer 0x%08X for %s uCode
\n
"
,
base
,
...
...
@@ -451,13 +509,17 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
IWL_ERR
(
mvm
,
"0x%08X | lmpm_pmg_sel
\n
"
,
table
.
lmpm_pmg_sel
);
IWL_ERR
(
mvm
,
"0x%08X | timestamp
\n
"
,
table
.
u_timestamp
);
IWL_ERR
(
mvm
,
"0x%08X | flow_handler
\n
"
,
table
.
flow_handler
);
if
(
mvm
->
support_umac_log
)
iwl_mvm_dump_umac_error_log
(
mvm
);
}
void
iwl_mvm_dump_sram
(
struct
iwl_mvm
*
mvm
)
{
const
struct
fw_img
*
img
;
int
ofs
,
len
=
0
;
u8
*
buf
;
int
i
;
__le32
*
buf
;
if
(
!
mvm
->
ucode_loaded
)
return
;
...
...
@@ -471,7 +533,12 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm)
return
;
iwl_trans_read_mem_bytes
(
mvm
->
trans
,
ofs
,
buf
,
len
);
iwl_print_hex_error
(
mvm
->
trans
,
buf
,
len
);
len
=
len
>>
2
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
IWL_ERR
(
mvm
,
"0x%08X
\n
"
,
le32_to_cpu
(
buf
[
i
]));
/* Add a small delay to let syslog catch up */
udelay
(
10
);
}
kfree
(
buf
);
}
...
...
@@ -514,7 +581,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum
ieee80211_smps_mode
smps_request
)
{
struct
iwl_mvm_vif
*
mvmvif
;
enum
ieee80211_smps_mode
smps_mode
=
IEEE80211_SMPS_AUTOMATIC
;
enum
ieee80211_smps_mode
smps_mode
;
int
i
;
lockdep_assert_held
(
&
mvm
->
mutex
);
...
...
@@ -523,6 +590,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if
(
num_of_ant
(
iwl_fw_valid_rx_ant
(
mvm
->
fw
))
==
1
)
return
;
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
smps_mode
=
IEEE80211_SMPS_OFF
;
else
smps_mode
=
IEEE80211_SMPS_AUTOMATIC
;
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
mvmvif
->
smps_requests
[
req_type
]
=
smps_request
;
for
(
i
=
0
;
i
<
NUM_IWL_MVM_SMPS_REQ
;
i
++
)
{
...
...
@@ -536,3 +608,22 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
ieee80211_request_smps
(
vif
,
smps_mode
);
}
int
iwl_mvm_update_low_latency
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
bool
value
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
int
res
;
lockdep_assert_held
(
&
mvm
->
mutex
);
mvmvif
->
low_latency
=
value
;
res
=
iwl_mvm_update_quotas
(
mvm
,
NULL
);
if
(
res
)
return
res
;
iwl_mvm_bt_coex_vif_change
(
mvm
);
return
iwl_mvm_power_update_mac
(
mvm
,
vif
);
}
drivers/net/wireless/iwlwifi/pcie/drv.c
View file @
e9c65316
...
...
@@ -66,6 +66,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include <linux/acpi.h>
#include "iwl-trans.h"
#include "iwl-drv.h"
...
...
@@ -385,12 +386,91 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{
IWL_PCI_DEVICE
(
0x095A
,
0x5590
,
iwl7265_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x095B
,
0x5290
,
iwl7265_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x095A
,
0x5490
,
iwl7265_2ac_cfg
)},
/* 8000 Series */
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0010
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F4
,
0x0030
,
iwl8260_2ac_cfg
)},
#endif
/* CONFIG_IWLMVM */
{
0
}
}
;
MODULE_DEVICE_TABLE
(
pci
,
iwl_hw_card_ids
);
#ifdef CONFIG_ACPI
#define SPL_METHOD "SPLC"
#define SPL_DOMAINTYPE_MODULE BIT(0)
#define SPL_DOMAINTYPE_WIFI BIT(1)
#define SPL_DOMAINTYPE_WIGIG BIT(2)
#define SPL_DOMAINTYPE_RFEM BIT(3)
static
u64
splx_get_pwr_limit
(
struct
iwl_trans
*
trans
,
union
acpi_object
*
splx
)
{
union
acpi_object
*
limits
,
*
domain_type
,
*
power_limit
;
if
(
splx
->
type
!=
ACPI_TYPE_PACKAGE
||
splx
->
package
.
count
!=
2
||
splx
->
package
.
elements
[
0
].
type
!=
ACPI_TYPE_INTEGER
||
splx
->
package
.
elements
[
0
].
integer
.
value
!=
0
)
{
IWL_ERR
(
trans
,
"Unsupported splx structure"
);
return
0
;
}
limits
=
&
splx
->
package
.
elements
[
1
];
if
(
limits
->
type
!=
ACPI_TYPE_PACKAGE
||
limits
->
package
.
count
<
2
||
limits
->
package
.
elements
[
0
].
type
!=
ACPI_TYPE_INTEGER
||
limits
->
package
.
elements
[
1
].
type
!=
ACPI_TYPE_INTEGER
)
{
IWL_ERR
(
trans
,
"Invalid limits element"
);
return
0
;
}
domain_type
=
&
limits
->
package
.
elements
[
0
];
power_limit
=
&
limits
->
package
.
elements
[
1
];
if
(
!
(
domain_type
->
integer
.
value
&
SPL_DOMAINTYPE_WIFI
))
{
IWL_DEBUG_INFO
(
trans
,
"WiFi power is not limited"
);
return
0
;
}
return
power_limit
->
integer
.
value
;
}
static
void
set_dflt_pwr_limit
(
struct
iwl_trans
*
trans
,
struct
pci_dev
*
pdev
)
{
acpi_handle
pxsx_handle
;
acpi_handle
handle
;
struct
acpi_buffer
splx
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
acpi_status
status
;
pxsx_handle
=
ACPI_HANDLE
(
&
pdev
->
dev
);
if
(
!
pxsx_handle
)
{
IWL_ERR
(
trans
,
"Could not retrieve root port ACPI handle"
);
return
;
}
/* Get the method's handle */
status
=
acpi_get_handle
(
pxsx_handle
,
(
acpi_string
)
SPL_METHOD
,
&
handle
);
if
(
ACPI_FAILURE
(
status
))
{
IWL_DEBUG_INFO
(
trans
,
"SPL method not found"
);
return
;
}
/* Call SPLC with no arguments */
status
=
acpi_evaluate_object
(
handle
,
NULL
,
NULL
,
&
splx
);
if
(
ACPI_FAILURE
(
status
))
{
IWL_ERR
(
trans
,
"SPLC invocation failed (0x%x)"
,
status
);
return
;
}
trans
->
dflt_pwr_limit
=
splx_get_pwr_limit
(
trans
,
splx
.
pointer
);
IWL_DEBUG_INFO
(
trans
,
"Default power limit set to %lld"
,
trans
->
dflt_pwr_limit
);
kfree
(
splx
.
pointer
);
}
#else
/* CONFIG_ACPI */
static
void
set_dflt_pwr_limit
(
struct
iwl_trans
*
trans
,
struct
pci_dev
*
pdev
)
{}
#endif
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
...
...
@@ -415,6 +495,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto
out_free_trans
;
}
set_dflt_pwr_limit
(
iwl_trans
,
pdev
);
/* register transport layer debugfs here */
ret
=
iwl_trans_dbgfs_register
(
iwl_trans
,
iwl_trans
->
dbgfs_dir
);
if
(
ret
)
...
...
drivers/net/wireless/iwlwifi/pcie/rx.c
View file @
e9c65316
...
...
@@ -802,10 +802,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
static
u32
iwl_pcie_int_cause_non_ict
(
struct
iwl_trans
*
trans
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
u32
inta
;
lockdep_assert_held
(
&
trans_pcie
->
irq_lock
);
lockdep_assert_held
(
&
IWL_TRANS_GET_PCIE_TRANS
(
trans
)
->
irq_lock
);
trace_iwlwifi_dev_irq
(
trans
->
dev
);
...
...
drivers/net/wireless/iwlwifi/pcie/trans.c
View file @
e9c65316
...
...
@@ -89,6 +89,7 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC
static
void
iwl_pcie_apm_config
(
struct
iwl_trans
*
trans
)
{
...
...
@@ -132,6 +133,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
*/
/* Disable L0S exit timer (platform NMI Work/Around) */
if
(
trans
->
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
iwl_set_bit
(
trans
,
CSR_GIO_CHICKEN_BITS
,
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER
);
...
...
@@ -203,11 +205,13 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
/*
* Enable DMA clock and wait for it to stabilize.
*
* Write to "CLK_EN_REG"; "1" bits enable clocks, while "0"
bits
*
do not disable clocks. This preserves any hardware bits already
* set by default in "CLK_CTRL_REG" after reset.
* Write to "CLK_EN_REG"; "1" bits enable clocks, while "0"
*
bits do not disable clocks. This preserves any hardware
*
bits already
set by default in "CLK_CTRL_REG" after reset.
*/
iwl_write_prph
(
trans
,
APMG_CLK_EN_REG
,
APMG_CLK_VAL_DMA_CLK_RQT
);
if
(
trans
->
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
{
iwl_write_prph
(
trans
,
APMG_CLK_EN_REG
,
APMG_CLK_VAL_DMA_CLK_RQT
);
udelay
(
20
);
/* Disable L1-Active */
...
...
@@ -215,7 +219,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
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
);
iwl_write_prph
(
trans
,
APMG_RTC_INT_STT_REG
,
APMG_RTC_INT_STT_RFKILL
);
}
set_bit
(
STATUS_DEVICE_ENABLED
,
&
trans
->
status
);
...
...
@@ -273,6 +279,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
spin_unlock
(
&
trans_pcie
->
irq_lock
);
if
(
trans
->
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
iwl_pcie_set_pwr
(
trans
,
false
);
iwl_op_mode_nic_config
(
trans
->
op_mode
);
...
...
@@ -435,78 +442,106 @@ 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
)
static
int
iwl_pcie_load_cpu_secured_sections
(
struct
iwl_trans
*
trans
,
const
struct
fw_img
*
image
,
int
cpu
,
int
*
first_ucode_section
)
{
int
shift_param
;
u32
address
;
int
ret
=
0
;
int
i
,
ret
=
0
;
u32
last_read_idx
=
0
;
if
(
cpu
==
1
)
{
shift_param
=
0
;
address
=
CSR_SECURE_BOOT_CPU1_STATUS_ADDR
;
*
first_ucode_section
=
0
;
}
else
{
shift_param
=
16
;
address
=
CSR_SECURE_BOOT_CPU2_STATUS_ADDR
;
(
*
first_ucode_section
)
++
;
}
/* set CPU to started */
iwl_trans_set_bits_mask
(
trans
,
CSR_UCODE_LOAD_STATUS_ADDR
,
CSR_CPU_STATUS_LOADING_STARTED
<<
shift_param
,
1
);
for
(
i
=
*
first_ucode_section
;
i
<
IWL_UCODE_SECTION_MAX
;
i
++
)
{
last_read_idx
=
i
;
/* 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
);
if
(
!
image
->
sec
[
i
].
data
||
image
->
sec
[
i
].
offset
==
CPU1_CPU2_SEPARATOR_SECTION
)
{
IWL_DEBUG_FW
(
trans
,
"Break since Data not valid or Empty section, sec = %d
\n
"
,
i
);
break
;
}
/* set last loaded block */
iwl_trans_set_bits_mask
(
trans
,
if
(
i
==
(
*
first_ucode_section
)
+
1
)
/* set CPU to started */
iwl_set_bits_prph
(
trans
,
CSR_UCODE_LOAD_STATUS_ADDR
,
CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
<<
shift_param
,
1
);
LMPM_CPU_HDRS_LOADING_COMPLETED
<<
shift_param
);
ret
=
iwl_pcie_load_section
(
trans
,
i
,
&
image
->
sec
[
i
]);
if
(
ret
)
return
ret
;
}
/* image loading complete */
iwl_
trans_set_bits_mask
(
trans
,
iwl_
set_bits_prph
(
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
;
LMPM_CPU_UCODE_LOADING_COMPLETED
<<
shift_param
);
*
first_ucode_section
=
last_read_idx
;
return
0
;
}
static
int
iwl_pcie_load_cpu_sections
(
struct
iwl_trans
*
trans
,
const
struct
fw_img
*
image
,
int
cpu
,
int
*
first_ucode_section
)
{
int
shift_param
;
int
i
,
ret
=
0
;
u32
last_read_idx
=
0
;
if
(
cpu
==
1
)
{
shift_param
=
0
;
*
first_ucode_section
=
0
;
}
else
{
shift_param
=
16
;
(
*
first_ucode_section
)
++
;
}
/* 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
);
for
(
i
=
*
first_ucode_section
;
i
<
IWL_UCODE_SECTION_MAX
;
i
++
)
{
last_read_idx
=
i
;
if
(
ret
<
0
)
{
IWL_ERR
(
trans
,
"Time out on secure boot process
\n
"
);
if
(
!
image
->
sec
[
i
].
data
||
image
->
sec
[
i
].
offset
==
CPU1_CPU2_SEPARATOR_SECTION
)
{
IWL_DEBUG_FW
(
trans
,
"Break since Data not valid or Empty section, sec = %d
\n
"
,
i
);
break
;
}
ret
=
iwl_pcie_load_section
(
trans
,
i
,
&
image
->
sec
[
i
]);
if
(
ret
)
return
ret
;
}
if
(
trans
->
cfg
->
device_family
==
IWL_DEVICE_FAMILY_8000
)
iwl_set_bits_prph
(
trans
,
CSR_UCODE_LOAD_STATUS_ADDR
,
(
LMPM_CPU_UCODE_LOADING_COMPLETED
|
LMPM_CPU_HDRS_LOADING_COMPLETED
|
LMPM_CPU_UCODE_LOADING_STARTED
)
<<
shift_param
);
*
first_ucode_section
=
last_read_idx
;
return
0
;
}
static
int
iwl_pcie_load_given_ucode
(
struct
iwl_trans
*
trans
,
const
struct
fw_img
*
image
)
{
int
i
,
ret
=
0
;
int
ret
=
0
;
int
first_ucode_section
;
IWL_DEBUG_FW
(
trans
,
"working with %s image
\n
"
,
...
...
@@ -518,52 +553,67 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
/* 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
]);
iwl_write_prph
(
trans
,
LMPM_SECURE_INSPECTOR_CODE_ADDR
,
LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE
);
iwl_write_prph
(
trans
,
LMPM_SECURE_INSPECTOR_DATA_ADDR
,
LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE
);
/* set CPU1 header address */
iwl_write_prph
(
trans
,
LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR
,
LMPM_SECURE_CPU1_HDR_MEM_SPACE
);
/* load to FW the binary Secured sections of CPU1 */
ret
=
iwl_pcie_load_cpu_secured_sections
(
trans
,
image
,
1
,
&
first_ucode_section
);
if
(
ret
)
return
ret
;
}
/* 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
);
}
else
{
/* load to FW the binary Non secured sections of CPU1 */
ret
=
iwl_pcie_load_cpu_sections
(
trans
,
image
,
1
,
&
first_ucode_section
);
if
(
ret
)
return
ret
;
}
else
{
/* Remove all resets to allow NIC to operate */
iwl_write32
(
trans
,
CSR_RESET
,
0
);
}
if
(
image
->
is_dual_cpus
)
{
/* set CPU2 header address */
iwl_write_prph
(
trans
,
LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR
,
LMPM_SECURE_CPU2_HDR_MEM_SPACE
);
/* 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
(
image
->
is_secure
)
ret
=
iwl_pcie_load_cpu_secured_sections
(
trans
,
image
,
2
,
&
first_ucode_section
);
else
ret
=
iwl_pcie_load_cpu_sections
(
trans
,
image
,
2
,
&
first_ucode_section
);
if
(
ret
)
return
ret
;
}
/* release CPU reset */
if
(
trans
->
cfg
->
device_family
==
IWL_DEVICE_FAMILY_8000
)
iwl_write_prph
(
trans
,
RELEASE_CPU_RESET
,
RELEASE_CPU_RESET_BIT
);
else
iwl_write32
(
trans
,
CSR_RESET
,
0
);
if
(
image
->
is_secure
)
{
/* set CPU2 for secure protocol */
ret
=
iwl_pcie_secure_set
(
trans
,
2
);
if
(
ret
)
/* wait for image verification to complete */
ret
=
iwl_poll_prph_bit
(
trans
,
LMPM_SECURE_BOOT_CPU1_STATUS_ADDR
,
LMPM_SECURE_BOOT_STATUS_SUCCESS
,
LMPM_SECURE_BOOT_STATUS_SUCCESS
,
LMPM_SECURE_TIME_OUT
);
if
(
ret
<
0
)
{
IWL_ERR
(
trans
,
"Time out on secure boot process
\n
"
);
return
ret
;
}
}
...
...
@@ -1407,16 +1457,15 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
{
struct
iwl_trans
*
trans
=
file
->
private_data
;
char
*
buf
=
NULL
;
int
pos
=
0
;
ssize_t
ret
=
-
EFAULT
;
ssize_t
ret
;
ret
=
pos
=
iwl_dump_fh
(
trans
,
&
buf
);
if
(
buf
)
{
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
pos
);
ret
=
iwl_dump_fh
(
trans
,
&
buf
);
if
(
ret
<
0
)
return
ret
;
if
(
!
buf
)
return
-
EINVAL
;
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
ret
);
kfree
(
buf
);
}
return
ret
;
}
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
View file @
e9c65316
...
...
@@ -705,6 +705,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
reg_val
|
FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN
);
/* Enable L1-Active */
if
(
trans
->
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
iwl_clear_bits_prph
(
trans
,
APMG_PCIDEV_STT_REG
,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS
);
}
...
...
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