Commit fb14996c2a555322ae2610d783e614430b259592
Committed by
Greg Kroah-Hartman
1 parent
4e709ff658
iwlwifi: mvm: check TLV flag before trying to use hotspot firmware commands
commit 5ac6c72e594471acfa5b00210c51d533a73413ad upstream. Older firmwares do not provide support for the HOT_SPOT_CMD command. Check for the appropriate TLV flag that declares hotspot support in the firmware to prevent a firmware assertion failure that can be triggered from the userspace, Signed-off-by: Luciano Coelho <luciano.coelho@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 2 changed files with 12 additions and 4 deletions Inline Diff
drivers/net/wireless/iwlwifi/iwl-fw.h
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | 3 | * This file is provided under a dual BSD/GPLv2 license. When using or |
4 | * redistributing this file, you may do so under either license. | 4 | * redistributing this file, you may do so under either license. |
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, but | 14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. | 17 | * General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, |
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called COPYING. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | 38 | * are met: |
39 | * | 39 | * |
40 | * * Redistributions of source code must retain the above copyright | 40 | * * Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. | 41 | * notice, this list of conditions and the following disclaimer. |
42 | * * Redistributions in binary form must reproduce the above copyright | 42 | * * Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in | 43 | * notice, this list of conditions and the following disclaimer in |
44 | * the documentation and/or other materials provided with the | 44 | * the documentation and/or other materials provided with the |
45 | * distribution. | 45 | * distribution. |
46 | * * Neither the name Intel Corporation nor the names of its | 46 | * * Neither the name Intel Corporation nor the names of its |
47 | * contributors may be used to endorse or promote products derived | 47 | * contributors may be used to endorse or promote products derived |
48 | * from this software without specific prior written permission. | 48 | * from this software without specific prior written permission. |
49 | * | 49 | * |
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | *****************************************************************************/ | 61 | *****************************************************************************/ |
62 | 62 | ||
63 | #ifndef __iwl_fw_h__ | 63 | #ifndef __iwl_fw_h__ |
64 | #define __iwl_fw_h__ | 64 | #define __iwl_fw_h__ |
65 | #include <linux/types.h> | 65 | #include <linux/types.h> |
66 | #include <net/mac80211.h> | 66 | #include <net/mac80211.h> |
67 | 67 | ||
68 | #include "iwl-fw-file.h" | 68 | #include "iwl-fw-file.h" |
69 | 69 | ||
70 | /** | 70 | /** |
71 | * enum iwl_ucode_tlv_flag - ucode API flags | 71 | * enum iwl_ucode_tlv_flag - ucode API flags |
72 | * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously | 72 | * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously |
73 | * was a separate TLV but moved here to save space. | 73 | * was a separate TLV but moved here to save space. |
74 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, | 74 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, |
75 | * treats good CRC threshold as a boolean | 75 | * treats good CRC threshold as a boolean |
76 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). | 76 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). |
77 | * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. | 77 | * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. |
78 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS | 78 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS |
79 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD | 79 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD |
80 | * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan | 80 | * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan |
81 | * offload profile config command. | 81 | * offload profile config command. |
82 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six | 82 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six |
83 | * (rather than two) IPv6 addresses | 83 | * (rather than two) IPv6 addresses |
84 | * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element | 84 | * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element |
85 | * from the probe request template. | 85 | * from the probe request template. |
86 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) | 86 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) |
87 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) | 87 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) |
88 | * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC | 88 | * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC |
89 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and | 89 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and |
90 | * P2P client interfaces simultaneously if they are in different bindings. | 90 | * P2P client interfaces simultaneously if they are in different bindings. |
91 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and | 91 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and |
92 | * P2P client interfaces simultaneously if they are in same bindings. | 92 | * P2P client interfaces simultaneously if they are in same bindings. |
93 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD | 93 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD |
94 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save | 94 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save |
95 | * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. | 95 | * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. |
96 | * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients | 96 | * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients |
97 | * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. | 97 | * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. |
98 | */ | 98 | */ |
99 | enum iwl_ucode_tlv_flag { | 99 | enum iwl_ucode_tlv_flag { |
100 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | 100 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), |
101 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), | 101 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), |
102 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), | 102 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), |
103 | IWL_UCODE_TLV_FLAGS_P2P = BIT(3), | 103 | IWL_UCODE_TLV_FLAGS_P2P = BIT(3), |
104 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), | 104 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), |
105 | IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), | 105 | IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), |
106 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), | 106 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), |
107 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), | 107 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), |
108 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), | 108 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), |
109 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), | 109 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), |
110 | IWL_UCODE_TLV_FLAGS_P2P_PM = BIT(21), | 110 | IWL_UCODE_TLV_FLAGS_P2P_PM = BIT(21), |
111 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), | 111 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), |
112 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = BIT(23), | 112 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = BIT(23), |
113 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), | 113 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), |
114 | IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), | 114 | IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), |
115 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), | 115 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), |
116 | IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), | 116 | IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), |
117 | IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), | 117 | IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), |
118 | }; | 118 | }; |
119 | 119 | ||
120 | /** | 120 | /** |
121 | * enum iwl_ucode_tlv_api - ucode api | 121 | * enum iwl_ucode_tlv_api - ucode api |
122 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. | 122 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. |
123 | * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification | 123 | * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification |
124 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex | 124 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex |
125 | * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. | 125 | * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. |
126 | * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. | 126 | * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. |
127 | * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. | 127 | * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. |
128 | */ | 128 | */ |
129 | enum iwl_ucode_tlv_api { | 129 | enum iwl_ucode_tlv_api { |
130 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), | 130 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), |
131 | IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), | 131 | IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), |
132 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), | 132 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), |
133 | IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), | 133 | IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), |
134 | IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), | 134 | IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), |
135 | IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), | 135 | IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), |
136 | }; | 136 | }; |
137 | 137 | ||
138 | /** | 138 | /** |
139 | * enum iwl_ucode_tlv_capa - ucode capabilities | 139 | * enum iwl_ucode_tlv_capa - ucode capabilities |
140 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | 140 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 |
141 | * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command | ||
141 | */ | 142 | */ |
142 | enum iwl_ucode_tlv_capa { | 143 | enum iwl_ucode_tlv_capa { |
143 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | 144 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), |
145 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), | ||
144 | }; | 146 | }; |
145 | 147 | ||
146 | /* The default calibrate table size if not specified by firmware file */ | 148 | /* The default calibrate table size if not specified by firmware file */ |
147 | #define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 | 149 | #define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 |
148 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 | 150 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 |
149 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 | 151 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 |
150 | 152 | ||
151 | /* The default max probe length if not specified by the firmware file */ | 153 | /* The default max probe length if not specified by the firmware file */ |
152 | #define IWL_DEFAULT_MAX_PROBE_LENGTH 200 | 154 | #define IWL_DEFAULT_MAX_PROBE_LENGTH 200 |
153 | 155 | ||
154 | /** | 156 | /** |
155 | * enum iwl_ucode_type | 157 | * enum iwl_ucode_type |
156 | * | 158 | * |
157 | * The type of ucode. | 159 | * The type of ucode. |
158 | * | 160 | * |
159 | * @IWL_UCODE_REGULAR: Normal runtime ucode | 161 | * @IWL_UCODE_REGULAR: Normal runtime ucode |
160 | * @IWL_UCODE_INIT: Initial ucode | 162 | * @IWL_UCODE_INIT: Initial ucode |
161 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode | 163 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode |
162 | */ | 164 | */ |
163 | enum iwl_ucode_type { | 165 | enum iwl_ucode_type { |
164 | IWL_UCODE_REGULAR, | 166 | IWL_UCODE_REGULAR, |
165 | IWL_UCODE_INIT, | 167 | IWL_UCODE_INIT, |
166 | IWL_UCODE_WOWLAN, | 168 | IWL_UCODE_WOWLAN, |
167 | IWL_UCODE_TYPE_MAX, | 169 | IWL_UCODE_TYPE_MAX, |
168 | }; | 170 | }; |
169 | 171 | ||
170 | /* | 172 | /* |
171 | * enumeration of ucode section. | 173 | * enumeration of ucode section. |
172 | * This enumeration is used directly for older firmware (before 16.0). | 174 | * This enumeration is used directly for older firmware (before 16.0). |
173 | * For new firmware, there can be up to 4 sections (see below) but the | 175 | * For new firmware, there can be up to 4 sections (see below) but the |
174 | * first one packaged into the firmware file is the DATA section and | 176 | * first one packaged into the firmware file is the DATA section and |
175 | * some debugging code accesses that. | 177 | * some debugging code accesses that. |
176 | */ | 178 | */ |
177 | enum iwl_ucode_sec { | 179 | enum iwl_ucode_sec { |
178 | IWL_UCODE_SECTION_DATA, | 180 | IWL_UCODE_SECTION_DATA, |
179 | IWL_UCODE_SECTION_INST, | 181 | IWL_UCODE_SECTION_INST, |
180 | }; | 182 | }; |
181 | /* | 183 | /* |
182 | * For 16.0 uCode and above, there is no differentiation between sections, | 184 | * For 16.0 uCode and above, there is no differentiation between sections, |
183 | * just an offset to the HW address. | 185 | * just an offset to the HW address. |
184 | */ | 186 | */ |
185 | #define IWL_UCODE_SECTION_MAX 12 | 187 | #define IWL_UCODE_SECTION_MAX 12 |
186 | #define IWL_API_ARRAY_SIZE 1 | 188 | #define IWL_API_ARRAY_SIZE 1 |
187 | #define IWL_CAPABILITIES_ARRAY_SIZE 1 | 189 | #define IWL_CAPABILITIES_ARRAY_SIZE 1 |
188 | #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC | 190 | #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC |
189 | 191 | ||
190 | struct iwl_ucode_capabilities { | 192 | struct iwl_ucode_capabilities { |
191 | u32 max_probe_length; | 193 | u32 max_probe_length; |
192 | u32 n_scan_channels; | 194 | u32 n_scan_channels; |
193 | u32 standard_phy_calibration_size; | 195 | u32 standard_phy_calibration_size; |
194 | u32 flags; | 196 | u32 flags; |
195 | u32 api[IWL_API_ARRAY_SIZE]; | 197 | u32 api[IWL_API_ARRAY_SIZE]; |
196 | u32 capa[IWL_CAPABILITIES_ARRAY_SIZE]; | 198 | u32 capa[IWL_CAPABILITIES_ARRAY_SIZE]; |
197 | }; | 199 | }; |
198 | 200 | ||
199 | /* one for each uCode image (inst/data, init/runtime/wowlan) */ | 201 | /* one for each uCode image (inst/data, init/runtime/wowlan) */ |
200 | struct fw_desc { | 202 | struct fw_desc { |
201 | const void *data; /* vmalloc'ed data */ | 203 | const void *data; /* vmalloc'ed data */ |
202 | u32 len; /* size in bytes */ | 204 | u32 len; /* size in bytes */ |
203 | u32 offset; /* offset in the device */ | 205 | u32 offset; /* offset in the device */ |
204 | }; | 206 | }; |
205 | 207 | ||
206 | struct fw_img { | 208 | struct fw_img { |
207 | struct fw_desc sec[IWL_UCODE_SECTION_MAX]; | 209 | struct fw_desc sec[IWL_UCODE_SECTION_MAX]; |
208 | bool is_secure; | 210 | bool is_secure; |
209 | bool is_dual_cpus; | 211 | bool is_dual_cpus; |
210 | }; | 212 | }; |
211 | 213 | ||
212 | struct iwl_sf_region { | 214 | struct iwl_sf_region { |
213 | u32 addr; | 215 | u32 addr; |
214 | u32 size; | 216 | u32 size; |
215 | }; | 217 | }; |
216 | 218 | ||
217 | /* uCode version contains 4 values: Major/Minor/API/Serial */ | 219 | /* uCode version contains 4 values: Major/Minor/API/Serial */ |
218 | #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) | 220 | #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) |
219 | #define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) | 221 | #define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) |
220 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) | 222 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) |
221 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) | 223 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) |
222 | 224 | ||
223 | /* | 225 | /* |
224 | * Calibration control struct. | 226 | * Calibration control struct. |
225 | * Sent as part of the phy configuration command. | 227 | * Sent as part of the phy configuration command. |
226 | * @flow_trigger: bitmap for which calibrations to perform according to | 228 | * @flow_trigger: bitmap for which calibrations to perform according to |
227 | * flow triggers. | 229 | * flow triggers. |
228 | * @event_trigger: bitmap for which calibrations to perform according to | 230 | * @event_trigger: bitmap for which calibrations to perform according to |
229 | * event triggers. | 231 | * event triggers. |
230 | */ | 232 | */ |
231 | struct iwl_tlv_calib_ctrl { | 233 | struct iwl_tlv_calib_ctrl { |
232 | __le32 flow_trigger; | 234 | __le32 flow_trigger; |
233 | __le32 event_trigger; | 235 | __le32 event_trigger; |
234 | } __packed; | 236 | } __packed; |
235 | 237 | ||
236 | enum iwl_fw_phy_cfg { | 238 | enum iwl_fw_phy_cfg { |
237 | FW_PHY_CFG_RADIO_TYPE_POS = 0, | 239 | FW_PHY_CFG_RADIO_TYPE_POS = 0, |
238 | FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, | 240 | FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, |
239 | FW_PHY_CFG_RADIO_STEP_POS = 2, | 241 | FW_PHY_CFG_RADIO_STEP_POS = 2, |
240 | FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, | 242 | FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, |
241 | FW_PHY_CFG_RADIO_DASH_POS = 4, | 243 | FW_PHY_CFG_RADIO_DASH_POS = 4, |
242 | FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, | 244 | FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, |
243 | FW_PHY_CFG_TX_CHAIN_POS = 16, | 245 | FW_PHY_CFG_TX_CHAIN_POS = 16, |
244 | FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, | 246 | FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, |
245 | FW_PHY_CFG_RX_CHAIN_POS = 20, | 247 | FW_PHY_CFG_RX_CHAIN_POS = 20, |
246 | FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, | 248 | FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, |
247 | }; | 249 | }; |
248 | 250 | ||
249 | #define IWL_UCODE_MAX_CS 1 | 251 | #define IWL_UCODE_MAX_CS 1 |
250 | 252 | ||
251 | /** | 253 | /** |
252 | * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. | 254 | * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. |
253 | * @cipher: a cipher suite selector | 255 | * @cipher: a cipher suite selector |
254 | * @flags: cipher scheme flags (currently reserved for a future use) | 256 | * @flags: cipher scheme flags (currently reserved for a future use) |
255 | * @hdr_len: a size of MPDU security header | 257 | * @hdr_len: a size of MPDU security header |
256 | * @pn_len: a size of PN | 258 | * @pn_len: a size of PN |
257 | * @pn_off: an offset of pn from the beginning of the security header | 259 | * @pn_off: an offset of pn from the beginning of the security header |
258 | * @key_idx_off: an offset of key index byte in the security header | 260 | * @key_idx_off: an offset of key index byte in the security header |
259 | * @key_idx_mask: a bit mask of key_idx bits | 261 | * @key_idx_mask: a bit mask of key_idx bits |
260 | * @key_idx_shift: bit shift needed to get key_idx | 262 | * @key_idx_shift: bit shift needed to get key_idx |
261 | * @mic_len: mic length in bytes | 263 | * @mic_len: mic length in bytes |
262 | * @hw_cipher: a HW cipher index used in host commands | 264 | * @hw_cipher: a HW cipher index used in host commands |
263 | */ | 265 | */ |
264 | struct iwl_fw_cipher_scheme { | 266 | struct iwl_fw_cipher_scheme { |
265 | __le32 cipher; | 267 | __le32 cipher; |
266 | u8 flags; | 268 | u8 flags; |
267 | u8 hdr_len; | 269 | u8 hdr_len; |
268 | u8 pn_len; | 270 | u8 pn_len; |
269 | u8 pn_off; | 271 | u8 pn_off; |
270 | u8 key_idx_off; | 272 | u8 key_idx_off; |
271 | u8 key_idx_mask; | 273 | u8 key_idx_mask; |
272 | u8 key_idx_shift; | 274 | u8 key_idx_shift; |
273 | u8 mic_len; | 275 | u8 mic_len; |
274 | u8 hw_cipher; | 276 | u8 hw_cipher; |
275 | } __packed; | 277 | } __packed; |
276 | 278 | ||
277 | /** | 279 | /** |
278 | * struct iwl_fw_cscheme_list - a cipher scheme list | 280 | * struct iwl_fw_cscheme_list - a cipher scheme list |
279 | * @size: a number of entries | 281 | * @size: a number of entries |
280 | * @cs: cipher scheme entries | 282 | * @cs: cipher scheme entries |
281 | */ | 283 | */ |
282 | struct iwl_fw_cscheme_list { | 284 | struct iwl_fw_cscheme_list { |
283 | u8 size; | 285 | u8 size; |
284 | struct iwl_fw_cipher_scheme cs[]; | 286 | struct iwl_fw_cipher_scheme cs[]; |
285 | } __packed; | 287 | } __packed; |
286 | 288 | ||
287 | /** | 289 | /** |
288 | * struct iwl_fw - variables associated with the firmware | 290 | * struct iwl_fw - variables associated with the firmware |
289 | * | 291 | * |
290 | * @ucode_ver: ucode version from the ucode file | 292 | * @ucode_ver: ucode version from the ucode file |
291 | * @fw_version: firmware version string | 293 | * @fw_version: firmware version string |
292 | * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan. | 294 | * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan. |
293 | * @ucode_capa: capabilities parsed from the ucode file. | 295 | * @ucode_capa: capabilities parsed from the ucode file. |
294 | * @enhance_sensitivity_table: device can do enhanced sensitivity. | 296 | * @enhance_sensitivity_table: device can do enhanced sensitivity. |
295 | * @init_evtlog_ptr: event log offset for init ucode. | 297 | * @init_evtlog_ptr: event log offset for init ucode. |
296 | * @init_evtlog_size: event log size for init ucode. | 298 | * @init_evtlog_size: event log size for init ucode. |
297 | * @init_errlog_ptr: error log offfset for init ucode. | 299 | * @init_errlog_ptr: error log offfset for init ucode. |
298 | * @inst_evtlog_ptr: event log offset for runtime ucode. | 300 | * @inst_evtlog_ptr: event log offset for runtime ucode. |
299 | * @inst_evtlog_size: event log size for runtime ucode. | 301 | * @inst_evtlog_size: event log size for runtime ucode. |
300 | * @inst_errlog_ptr: error log offfset for runtime ucode. | 302 | * @inst_errlog_ptr: error log offfset for runtime ucode. |
301 | * @mvm_fw: indicates this is MVM firmware | 303 | * @mvm_fw: indicates this is MVM firmware |
302 | * @cipher_scheme: optional external cipher scheme. | 304 | * @cipher_scheme: optional external cipher scheme. |
303 | */ | 305 | */ |
304 | struct iwl_fw { | 306 | struct iwl_fw { |
305 | u32 ucode_ver; | 307 | u32 ucode_ver; |
306 | 308 | ||
307 | char fw_version[ETHTOOL_FWVERS_LEN]; | 309 | char fw_version[ETHTOOL_FWVERS_LEN]; |
308 | 310 | ||
309 | /* ucode images */ | 311 | /* ucode images */ |
310 | struct fw_img img[IWL_UCODE_TYPE_MAX]; | 312 | struct fw_img img[IWL_UCODE_TYPE_MAX]; |
311 | 313 | ||
312 | struct iwl_ucode_capabilities ucode_capa; | 314 | struct iwl_ucode_capabilities ucode_capa; |
313 | bool enhance_sensitivity_table; | 315 | bool enhance_sensitivity_table; |
314 | 316 | ||
315 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 317 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
316 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 318 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
317 | 319 | ||
318 | struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; | 320 | struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; |
319 | u32 phy_config; | 321 | u32 phy_config; |
320 | u8 valid_tx_ant; | 322 | u8 valid_tx_ant; |
321 | u8 valid_rx_ant; | 323 | u8 valid_rx_ant; |
322 | 324 | ||
323 | bool mvm_fw; | 325 | bool mvm_fw; |
324 | 326 | ||
325 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; | 327 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; |
326 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; | 328 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; |
327 | }; | 329 | }; |
328 | 330 | ||
329 | #endif /* __iwl_fw_h__ */ | 331 | #endif /* __iwl_fw_h__ */ |
330 | 332 |
drivers/net/wireless/iwlwifi/mvm/mac80211.c
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | 3 | * This file is provided under a dual BSD/GPLv2 license. When using or |
4 | * redistributing this file, you may do so under either license. | 4 | * redistributing this file, you may do so under either license. |
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, but | 14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. | 17 | * General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, |
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called COPYING. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | 38 | * are met: |
39 | * | 39 | * |
40 | * * Redistributions of source code must retain the above copyright | 40 | * * Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. | 41 | * notice, this list of conditions and the following disclaimer. |
42 | * * Redistributions in binary form must reproduce the above copyright | 42 | * * Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in | 43 | * notice, this list of conditions and the following disclaimer in |
44 | * the documentation and/or other materials provided with the | 44 | * the documentation and/or other materials provided with the |
45 | * distribution. | 45 | * distribution. |
46 | * * Neither the name Intel Corporation nor the names of its | 46 | * * Neither the name Intel Corporation nor the names of its |
47 | * contributors may be used to endorse or promote products derived | 47 | * contributors may be used to endorse or promote products derived |
48 | * from this software without specific prior written permission. | 48 | * from this software without specific prior written permission. |
49 | * | 49 | * |
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include <linux/kernel.h> | 63 | #include <linux/kernel.h> |
64 | #include <linux/slab.h> | 64 | #include <linux/slab.h> |
65 | #include <linux/skbuff.h> | 65 | #include <linux/skbuff.h> |
66 | #include <linux/netdevice.h> | 66 | #include <linux/netdevice.h> |
67 | #include <linux/etherdevice.h> | 67 | #include <linux/etherdevice.h> |
68 | #include <linux/ip.h> | 68 | #include <linux/ip.h> |
69 | #include <linux/if_arp.h> | 69 | #include <linux/if_arp.h> |
70 | #include <net/mac80211.h> | 70 | #include <net/mac80211.h> |
71 | #include <net/ieee80211_radiotap.h> | 71 | #include <net/ieee80211_radiotap.h> |
72 | #include <net/tcp.h> | 72 | #include <net/tcp.h> |
73 | 73 | ||
74 | #include "iwl-op-mode.h" | 74 | #include "iwl-op-mode.h" |
75 | #include "iwl-io.h" | 75 | #include "iwl-io.h" |
76 | #include "mvm.h" | 76 | #include "mvm.h" |
77 | #include "sta.h" | 77 | #include "sta.h" |
78 | #include "time-event.h" | 78 | #include "time-event.h" |
79 | #include "iwl-eeprom-parse.h" | 79 | #include "iwl-eeprom-parse.h" |
80 | #include "fw-api-scan.h" | 80 | #include "fw-api-scan.h" |
81 | #include "iwl-phy-db.h" | 81 | #include "iwl-phy-db.h" |
82 | #include "testmode.h" | 82 | #include "testmode.h" |
83 | #include "iwl-fw-error-dump.h" | 83 | #include "iwl-fw-error-dump.h" |
84 | #include "iwl-prph.h" | 84 | #include "iwl-prph.h" |
85 | 85 | ||
86 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { | 86 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { |
87 | { | 87 | { |
88 | .max = 1, | 88 | .max = 1, |
89 | .types = BIT(NL80211_IFTYPE_STATION), | 89 | .types = BIT(NL80211_IFTYPE_STATION), |
90 | }, | 90 | }, |
91 | { | 91 | { |
92 | .max = 1, | 92 | .max = 1, |
93 | .types = BIT(NL80211_IFTYPE_AP) | | 93 | .types = BIT(NL80211_IFTYPE_AP) | |
94 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | 94 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
95 | BIT(NL80211_IFTYPE_P2P_GO), | 95 | BIT(NL80211_IFTYPE_P2P_GO), |
96 | }, | 96 | }, |
97 | { | 97 | { |
98 | .max = 1, | 98 | .max = 1, |
99 | .types = BIT(NL80211_IFTYPE_P2P_DEVICE), | 99 | .types = BIT(NL80211_IFTYPE_P2P_DEVICE), |
100 | }, | 100 | }, |
101 | }; | 101 | }; |
102 | 102 | ||
103 | static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { | 103 | static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { |
104 | { | 104 | { |
105 | .num_different_channels = 1, | 105 | .num_different_channels = 1, |
106 | .max_interfaces = 3, | 106 | .max_interfaces = 3, |
107 | .limits = iwl_mvm_limits, | 107 | .limits = iwl_mvm_limits, |
108 | .n_limits = ARRAY_SIZE(iwl_mvm_limits), | 108 | .n_limits = ARRAY_SIZE(iwl_mvm_limits), |
109 | }, | 109 | }, |
110 | }; | 110 | }; |
111 | 111 | ||
112 | #ifdef CONFIG_PM_SLEEP | 112 | #ifdef CONFIG_PM_SLEEP |
113 | static const struct nl80211_wowlan_tcp_data_token_feature | 113 | static const struct nl80211_wowlan_tcp_data_token_feature |
114 | iwl_mvm_wowlan_tcp_token_feature = { | 114 | iwl_mvm_wowlan_tcp_token_feature = { |
115 | .min_len = 0, | 115 | .min_len = 0, |
116 | .max_len = 255, | 116 | .max_len = 255, |
117 | .bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS, | 117 | .bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS, |
118 | }; | 118 | }; |
119 | 119 | ||
120 | static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { | 120 | static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { |
121 | .tok = &iwl_mvm_wowlan_tcp_token_feature, | 121 | .tok = &iwl_mvm_wowlan_tcp_token_feature, |
122 | .data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN - | 122 | .data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN - |
123 | sizeof(struct ethhdr) - | 123 | sizeof(struct ethhdr) - |
124 | sizeof(struct iphdr) - | 124 | sizeof(struct iphdr) - |
125 | sizeof(struct tcphdr), | 125 | sizeof(struct tcphdr), |
126 | .data_interval_max = 65535, /* __le16 in API */ | 126 | .data_interval_max = 65535, /* __le16 in API */ |
127 | .wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN - | 127 | .wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN - |
128 | sizeof(struct ethhdr) - | 128 | sizeof(struct ethhdr) - |
129 | sizeof(struct iphdr) - | 129 | sizeof(struct iphdr) - |
130 | sizeof(struct tcphdr), | 130 | sizeof(struct tcphdr), |
131 | .seq = true, | 131 | .seq = true, |
132 | }; | 132 | }; |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | 135 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING |
136 | /* | 136 | /* |
137 | * Use the reserved field to indicate magic values. | 137 | * Use the reserved field to indicate magic values. |
138 | * these values will only be used internally by the driver, | 138 | * these values will only be used internally by the driver, |
139 | * and won't make it to the fw (reserved will be 0). | 139 | * and won't make it to the fw (reserved will be 0). |
140 | * BC_FILTER_MAGIC_IP - configure the val of this attribute to | 140 | * BC_FILTER_MAGIC_IP - configure the val of this attribute to |
141 | * be the vif's ip address. in case there is not a single | 141 | * be the vif's ip address. in case there is not a single |
142 | * ip address (0, or more than 1), this attribute will | 142 | * ip address (0, or more than 1), this attribute will |
143 | * be skipped. | 143 | * be skipped. |
144 | * BC_FILTER_MAGIC_MAC - set the val of this attribute to | 144 | * BC_FILTER_MAGIC_MAC - set the val of this attribute to |
145 | * the LSB bytes of the vif's mac address | 145 | * the LSB bytes of the vif's mac address |
146 | */ | 146 | */ |
147 | enum { | 147 | enum { |
148 | BC_FILTER_MAGIC_NONE = 0, | 148 | BC_FILTER_MAGIC_NONE = 0, |
149 | BC_FILTER_MAGIC_IP, | 149 | BC_FILTER_MAGIC_IP, |
150 | BC_FILTER_MAGIC_MAC, | 150 | BC_FILTER_MAGIC_MAC, |
151 | }; | 151 | }; |
152 | 152 | ||
153 | static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { | 153 | static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { |
154 | { | 154 | { |
155 | /* arp */ | 155 | /* arp */ |
156 | .discard = 0, | 156 | .discard = 0, |
157 | .frame_type = BCAST_FILTER_FRAME_TYPE_ALL, | 157 | .frame_type = BCAST_FILTER_FRAME_TYPE_ALL, |
158 | .attrs = { | 158 | .attrs = { |
159 | { | 159 | { |
160 | /* frame type - arp, hw type - ethernet */ | 160 | /* frame type - arp, hw type - ethernet */ |
161 | .offset_type = | 161 | .offset_type = |
162 | BCAST_FILTER_OFFSET_PAYLOAD_START, | 162 | BCAST_FILTER_OFFSET_PAYLOAD_START, |
163 | .offset = sizeof(rfc1042_header), | 163 | .offset = sizeof(rfc1042_header), |
164 | .val = cpu_to_be32(0x08060001), | 164 | .val = cpu_to_be32(0x08060001), |
165 | .mask = cpu_to_be32(0xffffffff), | 165 | .mask = cpu_to_be32(0xffffffff), |
166 | }, | 166 | }, |
167 | { | 167 | { |
168 | /* arp dest ip */ | 168 | /* arp dest ip */ |
169 | .offset_type = | 169 | .offset_type = |
170 | BCAST_FILTER_OFFSET_PAYLOAD_START, | 170 | BCAST_FILTER_OFFSET_PAYLOAD_START, |
171 | .offset = sizeof(rfc1042_header) + 2 + | 171 | .offset = sizeof(rfc1042_header) + 2 + |
172 | sizeof(struct arphdr) + | 172 | sizeof(struct arphdr) + |
173 | ETH_ALEN + sizeof(__be32) + | 173 | ETH_ALEN + sizeof(__be32) + |
174 | ETH_ALEN, | 174 | ETH_ALEN, |
175 | .mask = cpu_to_be32(0xffffffff), | 175 | .mask = cpu_to_be32(0xffffffff), |
176 | /* mark it as special field */ | 176 | /* mark it as special field */ |
177 | .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP), | 177 | .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP), |
178 | }, | 178 | }, |
179 | }, | 179 | }, |
180 | }, | 180 | }, |
181 | { | 181 | { |
182 | /* dhcp offer bcast */ | 182 | /* dhcp offer bcast */ |
183 | .discard = 0, | 183 | .discard = 0, |
184 | .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4, | 184 | .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4, |
185 | .attrs = { | 185 | .attrs = { |
186 | { | 186 | { |
187 | /* udp dest port - 68 (bootp client)*/ | 187 | /* udp dest port - 68 (bootp client)*/ |
188 | .offset_type = BCAST_FILTER_OFFSET_IP_END, | 188 | .offset_type = BCAST_FILTER_OFFSET_IP_END, |
189 | .offset = offsetof(struct udphdr, dest), | 189 | .offset = offsetof(struct udphdr, dest), |
190 | .val = cpu_to_be32(0x00440000), | 190 | .val = cpu_to_be32(0x00440000), |
191 | .mask = cpu_to_be32(0xffff0000), | 191 | .mask = cpu_to_be32(0xffff0000), |
192 | }, | 192 | }, |
193 | { | 193 | { |
194 | /* dhcp - lsb bytes of client hw address */ | 194 | /* dhcp - lsb bytes of client hw address */ |
195 | .offset_type = BCAST_FILTER_OFFSET_IP_END, | 195 | .offset_type = BCAST_FILTER_OFFSET_IP_END, |
196 | .offset = 38, | 196 | .offset = 38, |
197 | .mask = cpu_to_be32(0xffffffff), | 197 | .mask = cpu_to_be32(0xffffffff), |
198 | /* mark it as special field */ | 198 | /* mark it as special field */ |
199 | .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC), | 199 | .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC), |
200 | }, | 200 | }, |
201 | }, | 201 | }, |
202 | }, | 202 | }, |
203 | /* last filter must be empty */ | 203 | /* last filter must be empty */ |
204 | {}, | 204 | {}, |
205 | }; | 205 | }; |
206 | #endif | 206 | #endif |
207 | 207 | ||
208 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | 208 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) |
209 | { | 209 | { |
210 | if (!iwl_mvm_is_d0i3_supported(mvm)) | 210 | if (!iwl_mvm_is_d0i3_supported(mvm)) |
211 | return; | 211 | return; |
212 | 212 | ||
213 | IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); | 213 | IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); |
214 | spin_lock_bh(&mvm->refs_lock); | 214 | spin_lock_bh(&mvm->refs_lock); |
215 | mvm->refs[ref_type]++; | 215 | mvm->refs[ref_type]++; |
216 | spin_unlock_bh(&mvm->refs_lock); | 216 | spin_unlock_bh(&mvm->refs_lock); |
217 | iwl_trans_ref(mvm->trans); | 217 | iwl_trans_ref(mvm->trans); |
218 | } | 218 | } |
219 | 219 | ||
220 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | 220 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) |
221 | { | 221 | { |
222 | if (!iwl_mvm_is_d0i3_supported(mvm)) | 222 | if (!iwl_mvm_is_d0i3_supported(mvm)) |
223 | return; | 223 | return; |
224 | 224 | ||
225 | IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); | 225 | IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); |
226 | spin_lock_bh(&mvm->refs_lock); | 226 | spin_lock_bh(&mvm->refs_lock); |
227 | WARN_ON(!mvm->refs[ref_type]--); | 227 | WARN_ON(!mvm->refs[ref_type]--); |
228 | spin_unlock_bh(&mvm->refs_lock); | 228 | spin_unlock_bh(&mvm->refs_lock); |
229 | iwl_trans_unref(mvm->trans); | 229 | iwl_trans_unref(mvm->trans); |
230 | } | 230 | } |
231 | 231 | ||
232 | static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm, | 232 | static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm, |
233 | enum iwl_mvm_ref_type except_ref) | 233 | enum iwl_mvm_ref_type except_ref) |
234 | { | 234 | { |
235 | int i, j; | 235 | int i, j; |
236 | 236 | ||
237 | if (!iwl_mvm_is_d0i3_supported(mvm)) | 237 | if (!iwl_mvm_is_d0i3_supported(mvm)) |
238 | return; | 238 | return; |
239 | 239 | ||
240 | spin_lock_bh(&mvm->refs_lock); | 240 | spin_lock_bh(&mvm->refs_lock); |
241 | for (i = 0; i < IWL_MVM_REF_COUNT; i++) { | 241 | for (i = 0; i < IWL_MVM_REF_COUNT; i++) { |
242 | if (except_ref == i || !mvm->refs[i]) | 242 | if (except_ref == i || !mvm->refs[i]) |
243 | continue; | 243 | continue; |
244 | 244 | ||
245 | IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n", | 245 | IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n", |
246 | i, mvm->refs[i]); | 246 | i, mvm->refs[i]); |
247 | for (j = 0; j < mvm->refs[i]; j++) | 247 | for (j = 0; j < mvm->refs[i]; j++) |
248 | iwl_trans_unref(mvm->trans); | 248 | iwl_trans_unref(mvm->trans); |
249 | mvm->refs[i] = 0; | 249 | mvm->refs[i] = 0; |
250 | } | 250 | } |
251 | spin_unlock_bh(&mvm->refs_lock); | 251 | spin_unlock_bh(&mvm->refs_lock); |
252 | } | 252 | } |
253 | 253 | ||
254 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | 254 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) |
255 | { | 255 | { |
256 | iwl_mvm_ref(mvm, ref_type); | 256 | iwl_mvm_ref(mvm, ref_type); |
257 | 257 | ||
258 | if (!wait_event_timeout(mvm->d0i3_exit_waitq, | 258 | if (!wait_event_timeout(mvm->d0i3_exit_waitq, |
259 | !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), | 259 | !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), |
260 | HZ)) { | 260 | HZ)) { |
261 | WARN_ON_ONCE(1); | 261 | WARN_ON_ONCE(1); |
262 | iwl_mvm_unref(mvm, ref_type); | 262 | iwl_mvm_unref(mvm, ref_type); |
263 | return -EIO; | 263 | return -EIO; |
264 | } | 264 | } |
265 | 265 | ||
266 | return 0; | 266 | return 0; |
267 | } | 267 | } |
268 | 268 | ||
269 | static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) | 269 | static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) |
270 | { | 270 | { |
271 | int i; | 271 | int i; |
272 | 272 | ||
273 | memset(mvm->phy_ctxts, 0, sizeof(mvm->phy_ctxts)); | 273 | memset(mvm->phy_ctxts, 0, sizeof(mvm->phy_ctxts)); |
274 | for (i = 0; i < NUM_PHY_CTX; i++) { | 274 | for (i = 0; i < NUM_PHY_CTX; i++) { |
275 | mvm->phy_ctxts[i].id = i; | 275 | mvm->phy_ctxts[i].id = i; |
276 | mvm->phy_ctxts[i].ref = 0; | 276 | mvm->phy_ctxts[i].ref = 0; |
277 | } | 277 | } |
278 | } | 278 | } |
279 | 279 | ||
280 | static int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm) | 280 | static int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm) |
281 | { | 281 | { |
282 | /* we create the 802.11 header and SSID element */ | 282 | /* we create the 802.11 header and SSID element */ |
283 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) | 283 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) |
284 | return mvm->fw->ucode_capa.max_probe_length - 24 - 2; | 284 | return mvm->fw->ucode_capa.max_probe_length - 24 - 2; |
285 | return mvm->fw->ucode_capa.max_probe_length - 24 - 34; | 285 | return mvm->fw->ucode_capa.max_probe_length - 24 - 34; |
286 | } | 286 | } |
287 | 287 | ||
288 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 288 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
289 | { | 289 | { |
290 | struct ieee80211_hw *hw = mvm->hw; | 290 | struct ieee80211_hw *hw = mvm->hw; |
291 | int num_mac, ret, i; | 291 | int num_mac, ret, i; |
292 | 292 | ||
293 | /* Tell mac80211 our characteristics */ | 293 | /* Tell mac80211 our characteristics */ |
294 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 294 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
295 | IEEE80211_HW_SPECTRUM_MGMT | | 295 | IEEE80211_HW_SPECTRUM_MGMT | |
296 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 296 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
297 | IEEE80211_HW_QUEUE_CONTROL | | 297 | IEEE80211_HW_QUEUE_CONTROL | |
298 | IEEE80211_HW_WANT_MONITOR_VIF | | 298 | IEEE80211_HW_WANT_MONITOR_VIF | |
299 | IEEE80211_HW_SUPPORTS_PS | | 299 | IEEE80211_HW_SUPPORTS_PS | |
300 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | 300 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | |
301 | IEEE80211_HW_AMPDU_AGGREGATION | | 301 | IEEE80211_HW_AMPDU_AGGREGATION | |
302 | IEEE80211_HW_TIMING_BEACON_ONLY | | 302 | IEEE80211_HW_TIMING_BEACON_ONLY | |
303 | IEEE80211_HW_CONNECTION_MONITOR | | 303 | IEEE80211_HW_CONNECTION_MONITOR | |
304 | IEEE80211_HW_CHANCTX_STA_CSA | | 304 | IEEE80211_HW_CHANCTX_STA_CSA | |
305 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | 305 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | |
306 | IEEE80211_HW_SUPPORTS_STATIC_SMPS; | 306 | IEEE80211_HW_SUPPORTS_STATIC_SMPS; |
307 | 307 | ||
308 | hw->queues = mvm->first_agg_queue; | 308 | hw->queues = mvm->first_agg_queue; |
309 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; | 309 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
310 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | | 310 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | |
311 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; | 311 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; |
312 | hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC; | 312 | hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC; |
313 | hw->rate_control_algorithm = "iwl-mvm-rs"; | 313 | hw->rate_control_algorithm = "iwl-mvm-rs"; |
314 | 314 | ||
315 | /* | 315 | /* |
316 | * Enable 11w if advertised by firmware and software crypto | 316 | * Enable 11w if advertised by firmware and software crypto |
317 | * is not enabled (as the firmware will interpret some mgmt | 317 | * is not enabled (as the firmware will interpret some mgmt |
318 | * packets, so enabling it with software crypto isn't safe) | 318 | * packets, so enabling it with software crypto isn't safe) |
319 | */ | 319 | */ |
320 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && | 320 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && |
321 | !iwlwifi_mod_params.sw_crypto) | 321 | !iwlwifi_mod_params.sw_crypto) |
322 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 322 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
323 | 323 | ||
324 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && | 324 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && |
325 | IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && | 325 | IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && |
326 | !iwlwifi_mod_params.uapsd_disable) { | 326 | !iwlwifi_mod_params.uapsd_disable) { |
327 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; | 327 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; |
328 | hw->uapsd_queues = IWL_UAPSD_AC_INFO; | 328 | hw->uapsd_queues = IWL_UAPSD_AC_INFO; |
329 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | 329 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; |
330 | } | 330 | } |
331 | 331 | ||
332 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 332 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) |
333 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; | 333 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; |
334 | 334 | ||
335 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); | 335 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); |
336 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); | 336 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); |
337 | hw->chanctx_data_size = sizeof(u16); | 337 | hw->chanctx_data_size = sizeof(u16); |
338 | 338 | ||
339 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 339 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
340 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | 340 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
341 | BIT(NL80211_IFTYPE_AP) | | 341 | BIT(NL80211_IFTYPE_AP) | |
342 | BIT(NL80211_IFTYPE_P2P_GO) | | 342 | BIT(NL80211_IFTYPE_P2P_GO) | |
343 | BIT(NL80211_IFTYPE_P2P_DEVICE) | | 343 | BIT(NL80211_IFTYPE_P2P_DEVICE) | |
344 | BIT(NL80211_IFTYPE_ADHOC); | 344 | BIT(NL80211_IFTYPE_ADHOC); |
345 | 345 | ||
346 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 346 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
347 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | | 347 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | |
348 | REGULATORY_DISABLE_BEACON_HINTS; | 348 | REGULATORY_DISABLE_BEACON_HINTS; |
349 | 349 | ||
350 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) | 350 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) |
351 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 351 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
352 | 352 | ||
353 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_CSA_FLOW) | 353 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_CSA_FLOW) |
354 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; | 354 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
355 | 355 | ||
356 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; | 356 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; |
357 | hw->wiphy->n_iface_combinations = | 357 | hw->wiphy->n_iface_combinations = |
358 | ARRAY_SIZE(iwl_mvm_iface_combinations); | 358 | ARRAY_SIZE(iwl_mvm_iface_combinations); |
359 | 359 | ||
360 | hw->wiphy->max_remain_on_channel_duration = 10000; | 360 | hw->wiphy->max_remain_on_channel_duration = 10000; |
361 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; | 361 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; |
362 | 362 | ||
363 | /* Extract MAC address */ | 363 | /* Extract MAC address */ |
364 | memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); | 364 | memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); |
365 | hw->wiphy->addresses = mvm->addresses; | 365 | hw->wiphy->addresses = mvm->addresses; |
366 | hw->wiphy->n_addresses = 1; | 366 | hw->wiphy->n_addresses = 1; |
367 | 367 | ||
368 | /* Extract additional MAC addresses if available */ | 368 | /* Extract additional MAC addresses if available */ |
369 | num_mac = (mvm->nvm_data->n_hw_addrs > 1) ? | 369 | num_mac = (mvm->nvm_data->n_hw_addrs > 1) ? |
370 | min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1; | 370 | min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1; |
371 | 371 | ||
372 | for (i = 1; i < num_mac; i++) { | 372 | for (i = 1; i < num_mac; i++) { |
373 | memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr, | 373 | memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr, |
374 | ETH_ALEN); | 374 | ETH_ALEN); |
375 | mvm->addresses[i].addr[5]++; | 375 | mvm->addresses[i].addr[5]++; |
376 | hw->wiphy->n_addresses++; | 376 | hw->wiphy->n_addresses++; |
377 | } | 377 | } |
378 | 378 | ||
379 | iwl_mvm_reset_phy_ctxts(mvm); | 379 | iwl_mvm_reset_phy_ctxts(mvm); |
380 | 380 | ||
381 | hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm); | 381 | hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm); |
382 | 382 | ||
383 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; | 383 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; |
384 | 384 | ||
385 | if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) | 385 | if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) |
386 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | 386 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = |
387 | &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | 387 | &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; |
388 | if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) | 388 | if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) |
389 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 389 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = |
390 | &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | 390 | &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; |
391 | 391 | ||
392 | hw->wiphy->hw_version = mvm->trans->hw_id; | 392 | hw->wiphy->hw_version = mvm->trans->hw_id; |
393 | 393 | ||
394 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | 394 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) |
395 | hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; | 395 | hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; |
396 | else | 396 | else |
397 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 397 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; |
398 | 398 | ||
399 | if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) { | 399 | if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) { |
400 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | 400 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
401 | hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; | 401 | hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; |
402 | hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; | 402 | hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; |
403 | /* we create the 802.11 header and zero length SSID IE. */ | 403 | /* we create the 802.11 header and zero length SSID IE. */ |
404 | hw->wiphy->max_sched_scan_ie_len = | 404 | hw->wiphy->max_sched_scan_ie_len = |
405 | SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; | 405 | SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; |
406 | } | 406 | } |
407 | 407 | ||
408 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | | 408 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | |
409 | NL80211_FEATURE_LOW_PRIORITY_SCAN | | 409 | NL80211_FEATURE_LOW_PRIORITY_SCAN | |
410 | NL80211_FEATURE_P2P_GO_OPPPS; | 410 | NL80211_FEATURE_P2P_GO_OPPPS; |
411 | 411 | ||
412 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 412 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; |
413 | 413 | ||
414 | /* currently FW API supports only one optional cipher scheme */ | 414 | /* currently FW API supports only one optional cipher scheme */ |
415 | if (mvm->fw->cs[0].cipher) { | 415 | if (mvm->fw->cs[0].cipher) { |
416 | mvm->hw->n_cipher_schemes = 1; | 416 | mvm->hw->n_cipher_schemes = 1; |
417 | mvm->hw->cipher_schemes = &mvm->fw->cs[0]; | 417 | mvm->hw->cipher_schemes = &mvm->fw->cs[0]; |
418 | } | 418 | } |
419 | 419 | ||
420 | #ifdef CONFIG_PM_SLEEP | 420 | #ifdef CONFIG_PM_SLEEP |
421 | if (iwl_mvm_is_d0i3_supported(mvm) && | 421 | if (iwl_mvm_is_d0i3_supported(mvm) && |
422 | device_can_wakeup(mvm->trans->dev)) { | 422 | device_can_wakeup(mvm->trans->dev)) { |
423 | mvm->wowlan.flags = WIPHY_WOWLAN_ANY; | 423 | mvm->wowlan.flags = WIPHY_WOWLAN_ANY; |
424 | hw->wiphy->wowlan = &mvm->wowlan; | 424 | hw->wiphy->wowlan = &mvm->wowlan; |
425 | } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && | 425 | } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && |
426 | mvm->trans->ops->d3_suspend && | 426 | mvm->trans->ops->d3_suspend && |
427 | mvm->trans->ops->d3_resume && | 427 | mvm->trans->ops->d3_resume && |
428 | device_can_wakeup(mvm->trans->dev)) { | 428 | device_can_wakeup(mvm->trans->dev)) { |
429 | mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | 429 | mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | |
430 | WIPHY_WOWLAN_DISCONNECT | | 430 | WIPHY_WOWLAN_DISCONNECT | |
431 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | | 431 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | |
432 | WIPHY_WOWLAN_RFKILL_RELEASE; | 432 | WIPHY_WOWLAN_RFKILL_RELEASE; |
433 | if (!iwlwifi_mod_params.sw_crypto) | 433 | if (!iwlwifi_mod_params.sw_crypto) |
434 | mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | | 434 | mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | |
435 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | | 435 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | |
436 | WIPHY_WOWLAN_4WAY_HANDSHAKE; | 436 | WIPHY_WOWLAN_4WAY_HANDSHAKE; |
437 | 437 | ||
438 | mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; | 438 | mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; |
439 | mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; | 439 | mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; |
440 | mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; | 440 | mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; |
441 | mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; | 441 | mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; |
442 | hw->wiphy->wowlan = &mvm->wowlan; | 442 | hw->wiphy->wowlan = &mvm->wowlan; |
443 | } | 443 | } |
444 | #endif | 444 | #endif |
445 | 445 | ||
446 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | 446 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING |
447 | /* assign default bcast filtering configuration */ | 447 | /* assign default bcast filtering configuration */ |
448 | mvm->bcast_filters = iwl_mvm_default_bcast_filters; | 448 | mvm->bcast_filters = iwl_mvm_default_bcast_filters; |
449 | #endif | 449 | #endif |
450 | 450 | ||
451 | ret = iwl_mvm_leds_init(mvm); | 451 | ret = iwl_mvm_leds_init(mvm); |
452 | if (ret) | 452 | if (ret) |
453 | return ret; | 453 | return ret; |
454 | 454 | ||
455 | ret = ieee80211_register_hw(mvm->hw); | 455 | ret = ieee80211_register_hw(mvm->hw); |
456 | if (ret) | 456 | if (ret) |
457 | iwl_mvm_leds_exit(mvm); | 457 | iwl_mvm_leds_exit(mvm); |
458 | 458 | ||
459 | return ret; | 459 | return ret; |
460 | } | 460 | } |
461 | 461 | ||
462 | static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm, | 462 | static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm, |
463 | struct ieee80211_sta *sta, | 463 | struct ieee80211_sta *sta, |
464 | struct sk_buff *skb) | 464 | struct sk_buff *skb) |
465 | { | 465 | { |
466 | struct iwl_mvm_sta *mvmsta; | 466 | struct iwl_mvm_sta *mvmsta; |
467 | bool defer = false; | 467 | bool defer = false; |
468 | 468 | ||
469 | /* | 469 | /* |
470 | * double check the IN_D0I3 flag both before and after | 470 | * double check the IN_D0I3 flag both before and after |
471 | * taking the spinlock, in order to prevent taking | 471 | * taking the spinlock, in order to prevent taking |
472 | * the spinlock when not needed. | 472 | * the spinlock when not needed. |
473 | */ | 473 | */ |
474 | if (likely(!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))) | 474 | if (likely(!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))) |
475 | return false; | 475 | return false; |
476 | 476 | ||
477 | spin_lock(&mvm->d0i3_tx_lock); | 477 | spin_lock(&mvm->d0i3_tx_lock); |
478 | /* | 478 | /* |
479 | * testing the flag again ensures the skb dequeue | 479 | * testing the flag again ensures the skb dequeue |
480 | * loop (on d0i3 exit) hasn't run yet. | 480 | * loop (on d0i3 exit) hasn't run yet. |
481 | */ | 481 | */ |
482 | if (!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) | 482 | if (!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) |
483 | goto out; | 483 | goto out; |
484 | 484 | ||
485 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | 485 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
486 | if (mvmsta->sta_id == IWL_MVM_STATION_COUNT || | 486 | if (mvmsta->sta_id == IWL_MVM_STATION_COUNT || |
487 | mvmsta->sta_id != mvm->d0i3_ap_sta_id) | 487 | mvmsta->sta_id != mvm->d0i3_ap_sta_id) |
488 | goto out; | 488 | goto out; |
489 | 489 | ||
490 | __skb_queue_tail(&mvm->d0i3_tx, skb); | 490 | __skb_queue_tail(&mvm->d0i3_tx, skb); |
491 | ieee80211_stop_queues(mvm->hw); | 491 | ieee80211_stop_queues(mvm->hw); |
492 | 492 | ||
493 | /* trigger wakeup */ | 493 | /* trigger wakeup */ |
494 | iwl_mvm_ref(mvm, IWL_MVM_REF_TX); | 494 | iwl_mvm_ref(mvm, IWL_MVM_REF_TX); |
495 | iwl_mvm_unref(mvm, IWL_MVM_REF_TX); | 495 | iwl_mvm_unref(mvm, IWL_MVM_REF_TX); |
496 | 496 | ||
497 | defer = true; | 497 | defer = true; |
498 | out: | 498 | out: |
499 | spin_unlock(&mvm->d0i3_tx_lock); | 499 | spin_unlock(&mvm->d0i3_tx_lock); |
500 | return defer; | 500 | return defer; |
501 | } | 501 | } |
502 | 502 | ||
503 | static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | 503 | static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, |
504 | struct ieee80211_tx_control *control, | 504 | struct ieee80211_tx_control *control, |
505 | struct sk_buff *skb) | 505 | struct sk_buff *skb) |
506 | { | 506 | { |
507 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 507 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
508 | struct ieee80211_sta *sta = control->sta; | 508 | struct ieee80211_sta *sta = control->sta; |
509 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 509 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
510 | struct ieee80211_hdr *hdr = (void *)skb->data; | 510 | struct ieee80211_hdr *hdr = (void *)skb->data; |
511 | 511 | ||
512 | if (iwl_mvm_is_radio_killed(mvm)) { | 512 | if (iwl_mvm_is_radio_killed(mvm)) { |
513 | IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); | 513 | IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); |
514 | goto drop; | 514 | goto drop; |
515 | } | 515 | } |
516 | 516 | ||
517 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && | 517 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && |
518 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) && | 518 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) && |
519 | !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) | 519 | !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) |
520 | goto drop; | 520 | goto drop; |
521 | 521 | ||
522 | /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ | 522 | /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ |
523 | if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER && | 523 | if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER && |
524 | ieee80211_is_mgmt(hdr->frame_control) && | 524 | ieee80211_is_mgmt(hdr->frame_control) && |
525 | !ieee80211_is_deauth(hdr->frame_control) && | 525 | !ieee80211_is_deauth(hdr->frame_control) && |
526 | !ieee80211_is_disassoc(hdr->frame_control) && | 526 | !ieee80211_is_disassoc(hdr->frame_control) && |
527 | !ieee80211_is_action(hdr->frame_control))) | 527 | !ieee80211_is_action(hdr->frame_control))) |
528 | sta = NULL; | 528 | sta = NULL; |
529 | 529 | ||
530 | if (sta) { | 530 | if (sta) { |
531 | if (iwl_mvm_defer_tx(mvm, sta, skb)) | 531 | if (iwl_mvm_defer_tx(mvm, sta, skb)) |
532 | return; | 532 | return; |
533 | if (iwl_mvm_tx_skb(mvm, skb, sta)) | 533 | if (iwl_mvm_tx_skb(mvm, skb, sta)) |
534 | goto drop; | 534 | goto drop; |
535 | return; | 535 | return; |
536 | } | 536 | } |
537 | 537 | ||
538 | if (iwl_mvm_tx_skb_non_sta(mvm, skb)) | 538 | if (iwl_mvm_tx_skb_non_sta(mvm, skb)) |
539 | goto drop; | 539 | goto drop; |
540 | return; | 540 | return; |
541 | drop: | 541 | drop: |
542 | ieee80211_free_txskb(hw, skb); | 542 | ieee80211_free_txskb(hw, skb); |
543 | } | 543 | } |
544 | 544 | ||
545 | static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) | 545 | static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) |
546 | { | 546 | { |
547 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) | 547 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) |
548 | return false; | 548 | return false; |
549 | return true; | 549 | return true; |
550 | } | 550 | } |
551 | 551 | ||
552 | static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) | 552 | static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) |
553 | { | 553 | { |
554 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) | 554 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) |
555 | return false; | 555 | return false; |
556 | if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) | 556 | if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) |
557 | return true; | 557 | return true; |
558 | 558 | ||
559 | /* enabled by default */ | 559 | /* enabled by default */ |
560 | return true; | 560 | return true; |
561 | } | 561 | } |
562 | 562 | ||
563 | static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | 563 | static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, |
564 | struct ieee80211_vif *vif, | 564 | struct ieee80211_vif *vif, |
565 | enum ieee80211_ampdu_mlme_action action, | 565 | enum ieee80211_ampdu_mlme_action action, |
566 | struct ieee80211_sta *sta, u16 tid, | 566 | struct ieee80211_sta *sta, u16 tid, |
567 | u16 *ssn, u8 buf_size) | 567 | u16 *ssn, u8 buf_size) |
568 | { | 568 | { |
569 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 569 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
570 | int ret; | 570 | int ret; |
571 | bool tx_agg_ref = false; | 571 | bool tx_agg_ref = false; |
572 | 572 | ||
573 | IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", | 573 | IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", |
574 | sta->addr, tid, action); | 574 | sta->addr, tid, action); |
575 | 575 | ||
576 | if (!(mvm->nvm_data->sku_cap_11n_enable)) | 576 | if (!(mvm->nvm_data->sku_cap_11n_enable)) |
577 | return -EACCES; | 577 | return -EACCES; |
578 | 578 | ||
579 | /* return from D0i3 before starting a new Tx aggregation */ | 579 | /* return from D0i3 before starting a new Tx aggregation */ |
580 | switch (action) { | 580 | switch (action) { |
581 | case IEEE80211_AMPDU_TX_START: | 581 | case IEEE80211_AMPDU_TX_START: |
582 | case IEEE80211_AMPDU_TX_STOP_CONT: | 582 | case IEEE80211_AMPDU_TX_STOP_CONT: |
583 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | 583 | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
584 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | 584 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
585 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 585 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
586 | /* | 586 | /* |
587 | * for tx start, wait synchronously until D0i3 exit to | 587 | * for tx start, wait synchronously until D0i3 exit to |
588 | * get the correct sequence number for the tid. | 588 | * get the correct sequence number for the tid. |
589 | * additionally, some other ampdu actions use direct | 589 | * additionally, some other ampdu actions use direct |
590 | * target access, which is not handled automatically | 590 | * target access, which is not handled automatically |
591 | * by the trans layer (unlike commands), so wait for | 591 | * by the trans layer (unlike commands), so wait for |
592 | * d0i3 exit in these cases as well. | 592 | * d0i3 exit in these cases as well. |
593 | */ | 593 | */ |
594 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_TX_AGG); | 594 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_TX_AGG); |
595 | if (ret) | 595 | if (ret) |
596 | return ret; | 596 | return ret; |
597 | 597 | ||
598 | tx_agg_ref = true; | 598 | tx_agg_ref = true; |
599 | break; | 599 | break; |
600 | default: | 600 | default: |
601 | break; | 601 | break; |
602 | } | 602 | } |
603 | 603 | ||
604 | mutex_lock(&mvm->mutex); | 604 | mutex_lock(&mvm->mutex); |
605 | 605 | ||
606 | switch (action) { | 606 | switch (action) { |
607 | case IEEE80211_AMPDU_RX_START: | 607 | case IEEE80211_AMPDU_RX_START: |
608 | if (!iwl_enable_rx_ampdu(mvm->cfg)) { | 608 | if (!iwl_enable_rx_ampdu(mvm->cfg)) { |
609 | ret = -EINVAL; | 609 | ret = -EINVAL; |
610 | break; | 610 | break; |
611 | } | 611 | } |
612 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true); | 612 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true); |
613 | break; | 613 | break; |
614 | case IEEE80211_AMPDU_RX_STOP: | 614 | case IEEE80211_AMPDU_RX_STOP: |
615 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); | 615 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); |
616 | break; | 616 | break; |
617 | case IEEE80211_AMPDU_TX_START: | 617 | case IEEE80211_AMPDU_TX_START: |
618 | if (!iwl_enable_tx_ampdu(mvm->cfg)) { | 618 | if (!iwl_enable_tx_ampdu(mvm->cfg)) { |
619 | ret = -EINVAL; | 619 | ret = -EINVAL; |
620 | break; | 620 | break; |
621 | } | 621 | } |
622 | ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn); | 622 | ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn); |
623 | break; | 623 | break; |
624 | case IEEE80211_AMPDU_TX_STOP_CONT: | 624 | case IEEE80211_AMPDU_TX_STOP_CONT: |
625 | ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid); | 625 | ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid); |
626 | break; | 626 | break; |
627 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | 627 | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
628 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | 628 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
629 | ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid); | 629 | ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid); |
630 | break; | 630 | break; |
631 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 631 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
632 | ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); | 632 | ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); |
633 | break; | 633 | break; |
634 | default: | 634 | default: |
635 | WARN_ON_ONCE(1); | 635 | WARN_ON_ONCE(1); |
636 | ret = -EINVAL; | 636 | ret = -EINVAL; |
637 | break; | 637 | break; |
638 | } | 638 | } |
639 | mutex_unlock(&mvm->mutex); | 639 | mutex_unlock(&mvm->mutex); |
640 | 640 | ||
641 | /* | 641 | /* |
642 | * If the tid is marked as started, we won't use it for offloaded | 642 | * If the tid is marked as started, we won't use it for offloaded |
643 | * traffic on the next D0i3 entry. It's safe to unref. | 643 | * traffic on the next D0i3 entry. It's safe to unref. |
644 | */ | 644 | */ |
645 | if (tx_agg_ref) | 645 | if (tx_agg_ref) |
646 | iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); | 646 | iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); |
647 | 647 | ||
648 | return ret; | 648 | return ret; |
649 | } | 649 | } |
650 | 650 | ||
651 | static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, | 651 | static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, |
652 | struct ieee80211_vif *vif) | 652 | struct ieee80211_vif *vif) |
653 | { | 653 | { |
654 | struct iwl_mvm *mvm = data; | 654 | struct iwl_mvm *mvm = data; |
655 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 655 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
656 | 656 | ||
657 | mvmvif->uploaded = false; | 657 | mvmvif->uploaded = false; |
658 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 658 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
659 | 659 | ||
660 | /* does this make sense at all? */ | 660 | /* does this make sense at all? */ |
661 | mvmvif->color++; | 661 | mvmvif->color++; |
662 | 662 | ||
663 | spin_lock_bh(&mvm->time_event_lock); | 663 | spin_lock_bh(&mvm->time_event_lock); |
664 | iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); | 664 | iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); |
665 | spin_unlock_bh(&mvm->time_event_lock); | 665 | spin_unlock_bh(&mvm->time_event_lock); |
666 | 666 | ||
667 | mvmvif->phy_ctxt = NULL; | 667 | mvmvif->phy_ctxt = NULL; |
668 | memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); | 668 | memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); |
669 | } | 669 | } |
670 | 670 | ||
671 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 671 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
672 | static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | 672 | static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) |
673 | { | 673 | { |
674 | struct iwl_fw_error_dump_file *dump_file; | 674 | struct iwl_fw_error_dump_file *dump_file; |
675 | struct iwl_fw_error_dump_data *dump_data; | 675 | struct iwl_fw_error_dump_data *dump_data; |
676 | struct iwl_fw_error_dump_info *dump_info; | 676 | struct iwl_fw_error_dump_info *dump_info; |
677 | struct iwl_mvm_dump_ptrs *fw_error_dump; | 677 | struct iwl_mvm_dump_ptrs *fw_error_dump; |
678 | const struct fw_img *img; | 678 | const struct fw_img *img; |
679 | u32 sram_len, sram_ofs; | 679 | u32 sram_len, sram_ofs; |
680 | u32 file_len, rxf_len; | 680 | u32 file_len, rxf_len; |
681 | unsigned long flags; | 681 | unsigned long flags; |
682 | int reg_val; | 682 | int reg_val; |
683 | 683 | ||
684 | lockdep_assert_held(&mvm->mutex); | 684 | lockdep_assert_held(&mvm->mutex); |
685 | 685 | ||
686 | if (mvm->fw_error_dump) | 686 | if (mvm->fw_error_dump) |
687 | return; | 687 | return; |
688 | 688 | ||
689 | fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL); | 689 | fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL); |
690 | if (!fw_error_dump) | 690 | if (!fw_error_dump) |
691 | return; | 691 | return; |
692 | 692 | ||
693 | img = &mvm->fw->img[mvm->cur_ucode]; | 693 | img = &mvm->fw->img[mvm->cur_ucode]; |
694 | sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; | 694 | sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; |
695 | sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; | 695 | sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; |
696 | 696 | ||
697 | /* reading buffer size */ | 697 | /* reading buffer size */ |
698 | reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); | 698 | reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); |
699 | rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; | 699 | rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; |
700 | 700 | ||
701 | /* the register holds the value divided by 128 */ | 701 | /* the register holds the value divided by 128 */ |
702 | rxf_len = rxf_len << 7; | 702 | rxf_len = rxf_len << 7; |
703 | 703 | ||
704 | file_len = sizeof(*dump_file) + | 704 | file_len = sizeof(*dump_file) + |
705 | sizeof(*dump_data) * 3 + | 705 | sizeof(*dump_data) * 3 + |
706 | sram_len + | 706 | sram_len + |
707 | rxf_len + | 707 | rxf_len + |
708 | sizeof(*dump_info); | 708 | sizeof(*dump_info); |
709 | 709 | ||
710 | dump_file = vzalloc(file_len); | 710 | dump_file = vzalloc(file_len); |
711 | if (!dump_file) { | 711 | if (!dump_file) { |
712 | kfree(fw_error_dump); | 712 | kfree(fw_error_dump); |
713 | return; | 713 | return; |
714 | } | 714 | } |
715 | 715 | ||
716 | fw_error_dump->op_mode_ptr = dump_file; | 716 | fw_error_dump->op_mode_ptr = dump_file; |
717 | 717 | ||
718 | dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); | 718 | dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); |
719 | dump_data = (void *)dump_file->data; | 719 | dump_data = (void *)dump_file->data; |
720 | 720 | ||
721 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); | 721 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); |
722 | dump_data->len = cpu_to_le32(sizeof(*dump_info)); | 722 | dump_data->len = cpu_to_le32(sizeof(*dump_info)); |
723 | dump_info = (void *) dump_data->data; | 723 | dump_info = (void *) dump_data->data; |
724 | dump_info->device_family = | 724 | dump_info->device_family = |
725 | mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? | 725 | mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? |
726 | cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : | 726 | cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : |
727 | cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); | 727 | cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); |
728 | memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, | 728 | memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, |
729 | sizeof(dump_info->fw_human_readable)); | 729 | sizeof(dump_info->fw_human_readable)); |
730 | strncpy(dump_info->dev_human_readable, mvm->cfg->name, | 730 | strncpy(dump_info->dev_human_readable, mvm->cfg->name, |
731 | sizeof(dump_info->dev_human_readable)); | 731 | sizeof(dump_info->dev_human_readable)); |
732 | strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, | 732 | strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, |
733 | sizeof(dump_info->bus_human_readable)); | 733 | sizeof(dump_info->bus_human_readable)); |
734 | 734 | ||
735 | dump_data = iwl_fw_error_next_data(dump_data); | 735 | dump_data = iwl_fw_error_next_data(dump_data); |
736 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); | 736 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); |
737 | dump_data->len = cpu_to_le32(rxf_len); | 737 | dump_data->len = cpu_to_le32(rxf_len); |
738 | 738 | ||
739 | if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { | 739 | if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { |
740 | u32 *rxf = (void *)dump_data->data; | 740 | u32 *rxf = (void *)dump_data->data; |
741 | int i; | 741 | int i; |
742 | 742 | ||
743 | for (i = 0; i < (rxf_len / sizeof(u32)); i++) { | 743 | for (i = 0; i < (rxf_len / sizeof(u32)); i++) { |
744 | iwl_trans_write_prph(mvm->trans, | 744 | iwl_trans_write_prph(mvm->trans, |
745 | RXF_LD_FENCE_OFFSET_ADDR, | 745 | RXF_LD_FENCE_OFFSET_ADDR, |
746 | i * sizeof(u32)); | 746 | i * sizeof(u32)); |
747 | rxf[i] = iwl_trans_read_prph(mvm->trans, | 747 | rxf[i] = iwl_trans_read_prph(mvm->trans, |
748 | RXF_FIFO_RD_FENCE_ADDR); | 748 | RXF_FIFO_RD_FENCE_ADDR); |
749 | } | 749 | } |
750 | iwl_trans_release_nic_access(mvm->trans, &flags); | 750 | iwl_trans_release_nic_access(mvm->trans, &flags); |
751 | } | 751 | } |
752 | 752 | ||
753 | dump_data = iwl_fw_error_next_data(dump_data); | 753 | dump_data = iwl_fw_error_next_data(dump_data); |
754 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); | 754 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); |
755 | dump_data->len = cpu_to_le32(sram_len); | 755 | dump_data->len = cpu_to_le32(sram_len); |
756 | iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, | 756 | iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, |
757 | sram_len); | 757 | sram_len); |
758 | 758 | ||
759 | fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); | 759 | fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); |
760 | fw_error_dump->op_mode_len = file_len; | 760 | fw_error_dump->op_mode_len = file_len; |
761 | if (fw_error_dump->trans_ptr) | 761 | if (fw_error_dump->trans_ptr) |
762 | file_len += fw_error_dump->trans_ptr->len; | 762 | file_len += fw_error_dump->trans_ptr->len; |
763 | dump_file->file_len = cpu_to_le32(file_len); | 763 | dump_file->file_len = cpu_to_le32(file_len); |
764 | mvm->fw_error_dump = fw_error_dump; | 764 | mvm->fw_error_dump = fw_error_dump; |
765 | } | 765 | } |
766 | #endif | 766 | #endif |
767 | 767 | ||
768 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | 768 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) |
769 | { | 769 | { |
770 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 770 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
771 | static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; | 771 | static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; |
772 | 772 | ||
773 | iwl_mvm_fw_error_dump(mvm); | 773 | iwl_mvm_fw_error_dump(mvm); |
774 | 774 | ||
775 | /* notify the userspace about the error we had */ | 775 | /* notify the userspace about the error we had */ |
776 | kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); | 776 | kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); |
777 | #endif | 777 | #endif |
778 | 778 | ||
779 | iwl_trans_stop_device(mvm->trans); | 779 | iwl_trans_stop_device(mvm->trans); |
780 | 780 | ||
781 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 781 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
782 | mvm->calibrating = false; | 782 | mvm->calibrating = false; |
783 | 783 | ||
784 | /* just in case one was running */ | 784 | /* just in case one was running */ |
785 | ieee80211_remain_on_channel_expired(mvm->hw); | 785 | ieee80211_remain_on_channel_expired(mvm->hw); |
786 | 786 | ||
787 | ieee80211_iterate_active_interfaces_atomic( | 787 | ieee80211_iterate_active_interfaces_atomic( |
788 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | 788 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
789 | iwl_mvm_cleanup_iterator, mvm); | 789 | iwl_mvm_cleanup_iterator, mvm); |
790 | 790 | ||
791 | mvm->p2p_device_vif = NULL; | 791 | mvm->p2p_device_vif = NULL; |
792 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | 792 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; |
793 | 793 | ||
794 | iwl_mvm_reset_phy_ctxts(mvm); | 794 | iwl_mvm_reset_phy_ctxts(mvm); |
795 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 795 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
796 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); | 796 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); |
797 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 797 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
798 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); | 798 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); |
799 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); | 799 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); |
800 | memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old)); | 800 | memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old)); |
801 | memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk)); | 801 | memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk)); |
802 | memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk)); | 802 | memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk)); |
803 | 803 | ||
804 | ieee80211_wake_queues(mvm->hw); | 804 | ieee80211_wake_queues(mvm->hw); |
805 | 805 | ||
806 | /* cleanup all stale references (scan, roc), but keep the | 806 | /* cleanup all stale references (scan, roc), but keep the |
807 | * ucode_down ref until reconfig is complete */ | 807 | * ucode_down ref until reconfig is complete */ |
808 | iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); | 808 | iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); |
809 | 809 | ||
810 | mvm->vif_count = 0; | 810 | mvm->vif_count = 0; |
811 | mvm->rx_ba_sessions = 0; | 811 | mvm->rx_ba_sessions = 0; |
812 | } | 812 | } |
813 | 813 | ||
814 | static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | 814 | static int iwl_mvm_mac_start(struct ieee80211_hw *hw) |
815 | { | 815 | { |
816 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 816 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
817 | int ret; | 817 | int ret; |
818 | 818 | ||
819 | mutex_lock(&mvm->mutex); | 819 | mutex_lock(&mvm->mutex); |
820 | 820 | ||
821 | /* Clean up some internal and mac80211 state on restart */ | 821 | /* Clean up some internal and mac80211 state on restart */ |
822 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 822 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
823 | iwl_mvm_restart_cleanup(mvm); | 823 | iwl_mvm_restart_cleanup(mvm); |
824 | 824 | ||
825 | ret = iwl_mvm_up(mvm); | 825 | ret = iwl_mvm_up(mvm); |
826 | 826 | ||
827 | if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 827 | if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { |
828 | /* Something went wrong - we need to finish some cleanup | 828 | /* Something went wrong - we need to finish some cleanup |
829 | * that normally iwl_mvm_mac_restart_complete() below | 829 | * that normally iwl_mvm_mac_restart_complete() below |
830 | * would do. | 830 | * would do. |
831 | */ | 831 | */ |
832 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 832 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
833 | iwl_mvm_d0i3_enable_tx(mvm, NULL); | 833 | iwl_mvm_d0i3_enable_tx(mvm, NULL); |
834 | } | 834 | } |
835 | 835 | ||
836 | mutex_unlock(&mvm->mutex); | 836 | mutex_unlock(&mvm->mutex); |
837 | 837 | ||
838 | return ret; | 838 | return ret; |
839 | } | 839 | } |
840 | 840 | ||
841 | static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) | 841 | static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) |
842 | { | 842 | { |
843 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 843 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
844 | int ret; | 844 | int ret; |
845 | 845 | ||
846 | mutex_lock(&mvm->mutex); | 846 | mutex_lock(&mvm->mutex); |
847 | 847 | ||
848 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 848 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
849 | iwl_mvm_d0i3_enable_tx(mvm, NULL); | 849 | iwl_mvm_d0i3_enable_tx(mvm, NULL); |
850 | ret = iwl_mvm_update_quotas(mvm, NULL); | 850 | ret = iwl_mvm_update_quotas(mvm, NULL); |
851 | if (ret) | 851 | if (ret) |
852 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", | 852 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", |
853 | ret); | 853 | ret); |
854 | 854 | ||
855 | /* allow transport/FW low power modes */ | 855 | /* allow transport/FW low power modes */ |
856 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | 856 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); |
857 | 857 | ||
858 | mutex_unlock(&mvm->mutex); | 858 | mutex_unlock(&mvm->mutex); |
859 | } | 859 | } |
860 | 860 | ||
861 | static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | 861 | static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) |
862 | { | 862 | { |
863 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 863 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
864 | 864 | ||
865 | flush_work(&mvm->d0i3_exit_work); | 865 | flush_work(&mvm->d0i3_exit_work); |
866 | flush_work(&mvm->async_handlers_wk); | 866 | flush_work(&mvm->async_handlers_wk); |
867 | 867 | ||
868 | mutex_lock(&mvm->mutex); | 868 | mutex_lock(&mvm->mutex); |
869 | 869 | ||
870 | /* disallow low power states when the FW is down */ | 870 | /* disallow low power states when the FW is down */ |
871 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); | 871 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); |
872 | 872 | ||
873 | /* async_handlers_wk is now blocked */ | 873 | /* async_handlers_wk is now blocked */ |
874 | 874 | ||
875 | /* | 875 | /* |
876 | * The work item could be running or queued if the | 876 | * The work item could be running or queued if the |
877 | * ROC time event stops just as we get here. | 877 | * ROC time event stops just as we get here. |
878 | */ | 878 | */ |
879 | cancel_work_sync(&mvm->roc_done_wk); | 879 | cancel_work_sync(&mvm->roc_done_wk); |
880 | 880 | ||
881 | iwl_trans_stop_device(mvm->trans); | 881 | iwl_trans_stop_device(mvm->trans); |
882 | 882 | ||
883 | iwl_mvm_async_handlers_purge(mvm); | 883 | iwl_mvm_async_handlers_purge(mvm); |
884 | /* async_handlers_list is empty and will stay empty: HW is stopped */ | 884 | /* async_handlers_list is empty and will stay empty: HW is stopped */ |
885 | 885 | ||
886 | /* the fw is stopped, the aux sta is dead: clean up driver state */ | 886 | /* the fw is stopped, the aux sta is dead: clean up driver state */ |
887 | iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); | 887 | iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); |
888 | 888 | ||
889 | mutex_unlock(&mvm->mutex); | 889 | mutex_unlock(&mvm->mutex); |
890 | 890 | ||
891 | /* | 891 | /* |
892 | * The worker might have been waiting for the mutex, let it run and | 892 | * The worker might have been waiting for the mutex, let it run and |
893 | * discover that its list is now empty. | 893 | * discover that its list is now empty. |
894 | */ | 894 | */ |
895 | cancel_work_sync(&mvm->async_handlers_wk); | 895 | cancel_work_sync(&mvm->async_handlers_wk); |
896 | } | 896 | } |
897 | 897 | ||
898 | static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) | 898 | static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) |
899 | { | 899 | { |
900 | u16 i; | 900 | u16 i; |
901 | 901 | ||
902 | lockdep_assert_held(&mvm->mutex); | 902 | lockdep_assert_held(&mvm->mutex); |
903 | 903 | ||
904 | for (i = 0; i < NUM_PHY_CTX; i++) | 904 | for (i = 0; i < NUM_PHY_CTX; i++) |
905 | if (!mvm->phy_ctxts[i].ref) | 905 | if (!mvm->phy_ctxts[i].ref) |
906 | return &mvm->phy_ctxts[i]; | 906 | return &mvm->phy_ctxts[i]; |
907 | 907 | ||
908 | IWL_ERR(mvm, "No available PHY context\n"); | 908 | IWL_ERR(mvm, "No available PHY context\n"); |
909 | return NULL; | 909 | return NULL; |
910 | } | 910 | } |
911 | 911 | ||
912 | static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 912 | static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
913 | s8 tx_power) | 913 | s8 tx_power) |
914 | { | 914 | { |
915 | /* FW is in charge of regulatory enforcement */ | 915 | /* FW is in charge of regulatory enforcement */ |
916 | struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = { | 916 | struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = { |
917 | .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id, | 917 | .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id, |
918 | .pwr_restriction = cpu_to_le16(tx_power), | 918 | .pwr_restriction = cpu_to_le16(tx_power), |
919 | }; | 919 | }; |
920 | 920 | ||
921 | return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, | 921 | return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, |
922 | sizeof(reduce_txpwr_cmd), | 922 | sizeof(reduce_txpwr_cmd), |
923 | &reduce_txpwr_cmd); | 923 | &reduce_txpwr_cmd); |
924 | } | 924 | } |
925 | 925 | ||
926 | static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | 926 | static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, |
927 | struct ieee80211_vif *vif) | 927 | struct ieee80211_vif *vif) |
928 | { | 928 | { |
929 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 929 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
930 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 930 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
931 | int ret; | 931 | int ret; |
932 | 932 | ||
933 | /* | 933 | /* |
934 | * make sure D0i3 exit is completed, otherwise a target access | 934 | * make sure D0i3 exit is completed, otherwise a target access |
935 | * during tx queue configuration could be done when still in | 935 | * during tx queue configuration could be done when still in |
936 | * D0i3 state. | 936 | * D0i3 state. |
937 | */ | 937 | */ |
938 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_ADD_IF); | 938 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_ADD_IF); |
939 | if (ret) | 939 | if (ret) |
940 | return ret; | 940 | return ret; |
941 | 941 | ||
942 | /* | 942 | /* |
943 | * Not much to do here. The stack will not allow interface | 943 | * Not much to do here. The stack will not allow interface |
944 | * types or combinations that we didn't advertise, so we | 944 | * types or combinations that we didn't advertise, so we |
945 | * don't really have to check the types. | 945 | * don't really have to check the types. |
946 | */ | 946 | */ |
947 | 947 | ||
948 | mutex_lock(&mvm->mutex); | 948 | mutex_lock(&mvm->mutex); |
949 | 949 | ||
950 | /* Allocate resources for the MAC context, and add it to the fw */ | 950 | /* Allocate resources for the MAC context, and add it to the fw */ |
951 | ret = iwl_mvm_mac_ctxt_init(mvm, vif); | 951 | ret = iwl_mvm_mac_ctxt_init(mvm, vif); |
952 | if (ret) | 952 | if (ret) |
953 | goto out_unlock; | 953 | goto out_unlock; |
954 | 954 | ||
955 | /* Counting number of interfaces is needed for legacy PM */ | 955 | /* Counting number of interfaces is needed for legacy PM */ |
956 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) | 956 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) |
957 | mvm->vif_count++; | 957 | mvm->vif_count++; |
958 | 958 | ||
959 | /* | 959 | /* |
960 | * The AP binding flow can be done only after the beacon | 960 | * The AP binding flow can be done only after the beacon |
961 | * template is configured (which happens only in the mac80211 | 961 | * template is configured (which happens only in the mac80211 |
962 | * start_ap() flow), and adding the broadcast station can happen | 962 | * start_ap() flow), and adding the broadcast station can happen |
963 | * only after the binding. | 963 | * only after the binding. |
964 | * In addition, since modifying the MAC before adding a bcast | 964 | * In addition, since modifying the MAC before adding a bcast |
965 | * station is not allowed by the FW, delay the adding of MAC context to | 965 | * station is not allowed by the FW, delay the adding of MAC context to |
966 | * the point where we can also add the bcast station. | 966 | * the point where we can also add the bcast station. |
967 | * In short: there's not much we can do at this point, other than | 967 | * In short: there's not much we can do at this point, other than |
968 | * allocating resources :) | 968 | * allocating resources :) |
969 | */ | 969 | */ |
970 | if (vif->type == NL80211_IFTYPE_AP || | 970 | if (vif->type == NL80211_IFTYPE_AP || |
971 | vif->type == NL80211_IFTYPE_ADHOC) { | 971 | vif->type == NL80211_IFTYPE_ADHOC) { |
972 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | 972 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); |
973 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, | 973 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, |
974 | qmask, | 974 | qmask, |
975 | ieee80211_vif_type_p2p(vif)); | 975 | ieee80211_vif_type_p2p(vif)); |
976 | if (ret) { | 976 | if (ret) { |
977 | IWL_ERR(mvm, "Failed to allocate bcast sta\n"); | 977 | IWL_ERR(mvm, "Failed to allocate bcast sta\n"); |
978 | goto out_release; | 978 | goto out_release; |
979 | } | 979 | } |
980 | 980 | ||
981 | iwl_mvm_vif_dbgfs_register(mvm, vif); | 981 | iwl_mvm_vif_dbgfs_register(mvm, vif); |
982 | goto out_unlock; | 982 | goto out_unlock; |
983 | } | 983 | } |
984 | 984 | ||
985 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); | 985 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); |
986 | if (ret) | 986 | if (ret) |
987 | goto out_release; | 987 | goto out_release; |
988 | 988 | ||
989 | ret = iwl_mvm_power_update_mac(mvm); | 989 | ret = iwl_mvm_power_update_mac(mvm); |
990 | if (ret) | 990 | if (ret) |
991 | goto out_release; | 991 | goto out_release; |
992 | 992 | ||
993 | /* beacon filtering */ | 993 | /* beacon filtering */ |
994 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); | 994 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); |
995 | if (ret) | 995 | if (ret) |
996 | goto out_remove_mac; | 996 | goto out_remove_mac; |
997 | 997 | ||
998 | if (!mvm->bf_allowed_vif && | 998 | if (!mvm->bf_allowed_vif && |
999 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { | 999 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { |
1000 | mvm->bf_allowed_vif = mvmvif; | 1000 | mvm->bf_allowed_vif = mvmvif; |
1001 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | | 1001 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | |
1002 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; | 1002 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; |
1003 | } | 1003 | } |
1004 | 1004 | ||
1005 | /* | 1005 | /* |
1006 | * P2P_DEVICE interface does not have a channel context assigned to it, | 1006 | * P2P_DEVICE interface does not have a channel context assigned to it, |
1007 | * so a dedicated PHY context is allocated to it and the corresponding | 1007 | * so a dedicated PHY context is allocated to it and the corresponding |
1008 | * MAC context is bound to it at this stage. | 1008 | * MAC context is bound to it at this stage. |
1009 | */ | 1009 | */ |
1010 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 1010 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
1011 | 1011 | ||
1012 | mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | 1012 | mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); |
1013 | if (!mvmvif->phy_ctxt) { | 1013 | if (!mvmvif->phy_ctxt) { |
1014 | ret = -ENOSPC; | 1014 | ret = -ENOSPC; |
1015 | goto out_free_bf; | 1015 | goto out_free_bf; |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | 1018 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); |
1019 | ret = iwl_mvm_binding_add_vif(mvm, vif); | 1019 | ret = iwl_mvm_binding_add_vif(mvm, vif); |
1020 | if (ret) | 1020 | if (ret) |
1021 | goto out_unref_phy; | 1021 | goto out_unref_phy; |
1022 | 1022 | ||
1023 | ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | 1023 | ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); |
1024 | if (ret) | 1024 | if (ret) |
1025 | goto out_unbind; | 1025 | goto out_unbind; |
1026 | 1026 | ||
1027 | /* Save a pointer to p2p device vif, so it can later be used to | 1027 | /* Save a pointer to p2p device vif, so it can later be used to |
1028 | * update the p2p device MAC when a GO is started/stopped */ | 1028 | * update the p2p device MAC when a GO is started/stopped */ |
1029 | mvm->p2p_device_vif = vif; | 1029 | mvm->p2p_device_vif = vif; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | iwl_mvm_vif_dbgfs_register(mvm, vif); | 1032 | iwl_mvm_vif_dbgfs_register(mvm, vif); |
1033 | goto out_unlock; | 1033 | goto out_unlock; |
1034 | 1034 | ||
1035 | out_unbind: | 1035 | out_unbind: |
1036 | iwl_mvm_binding_remove_vif(mvm, vif); | 1036 | iwl_mvm_binding_remove_vif(mvm, vif); |
1037 | out_unref_phy: | 1037 | out_unref_phy: |
1038 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | 1038 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
1039 | out_free_bf: | 1039 | out_free_bf: |
1040 | if (mvm->bf_allowed_vif == mvmvif) { | 1040 | if (mvm->bf_allowed_vif == mvmvif) { |
1041 | mvm->bf_allowed_vif = NULL; | 1041 | mvm->bf_allowed_vif = NULL; |
1042 | vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | | 1042 | vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | |
1043 | IEEE80211_VIF_SUPPORTS_CQM_RSSI); | 1043 | IEEE80211_VIF_SUPPORTS_CQM_RSSI); |
1044 | } | 1044 | } |
1045 | out_remove_mac: | 1045 | out_remove_mac: |
1046 | mvmvif->phy_ctxt = NULL; | 1046 | mvmvif->phy_ctxt = NULL; |
1047 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 1047 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
1048 | out_release: | 1048 | out_release: |
1049 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) | 1049 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) |
1050 | mvm->vif_count--; | 1050 | mvm->vif_count--; |
1051 | 1051 | ||
1052 | iwl_mvm_mac_ctxt_release(mvm, vif); | 1052 | iwl_mvm_mac_ctxt_release(mvm, vif); |
1053 | out_unlock: | 1053 | out_unlock: |
1054 | mutex_unlock(&mvm->mutex); | 1054 | mutex_unlock(&mvm->mutex); |
1055 | 1055 | ||
1056 | iwl_mvm_unref(mvm, IWL_MVM_REF_ADD_IF); | 1056 | iwl_mvm_unref(mvm, IWL_MVM_REF_ADD_IF); |
1057 | 1057 | ||
1058 | return ret; | 1058 | return ret; |
1059 | } | 1059 | } |
1060 | 1060 | ||
1061 | static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, | 1061 | static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, |
1062 | struct ieee80211_vif *vif) | 1062 | struct ieee80211_vif *vif) |
1063 | { | 1063 | { |
1064 | u32 tfd_msk = 0, ac; | 1064 | u32 tfd_msk = 0, ac; |
1065 | 1065 | ||
1066 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 1066 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
1067 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | 1067 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) |
1068 | tfd_msk |= BIT(vif->hw_queue[ac]); | 1068 | tfd_msk |= BIT(vif->hw_queue[ac]); |
1069 | 1069 | ||
1070 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | 1070 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) |
1071 | tfd_msk |= BIT(vif->cab_queue); | 1071 | tfd_msk |= BIT(vif->cab_queue); |
1072 | 1072 | ||
1073 | if (tfd_msk) { | 1073 | if (tfd_msk) { |
1074 | mutex_lock(&mvm->mutex); | 1074 | mutex_lock(&mvm->mutex); |
1075 | iwl_mvm_flush_tx_path(mvm, tfd_msk, true); | 1075 | iwl_mvm_flush_tx_path(mvm, tfd_msk, true); |
1076 | mutex_unlock(&mvm->mutex); | 1076 | mutex_unlock(&mvm->mutex); |
1077 | } | 1077 | } |
1078 | 1078 | ||
1079 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 1079 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
1080 | /* | 1080 | /* |
1081 | * Flush the ROC worker which will flush the OFFCHANNEL queue. | 1081 | * Flush the ROC worker which will flush the OFFCHANNEL queue. |
1082 | * We assume here that all the packets sent to the OFFCHANNEL | 1082 | * We assume here that all the packets sent to the OFFCHANNEL |
1083 | * queue are sent in ROC session. | 1083 | * queue are sent in ROC session. |
1084 | */ | 1084 | */ |
1085 | flush_work(&mvm->roc_done_wk); | 1085 | flush_work(&mvm->roc_done_wk); |
1086 | } else { | 1086 | } else { |
1087 | /* | 1087 | /* |
1088 | * By now, all the AC queues are empty. The AGG queues are | 1088 | * By now, all the AC queues are empty. The AGG queues are |
1089 | * empty too. We already got all the Tx responses for all the | 1089 | * empty too. We already got all the Tx responses for all the |
1090 | * packets in the queues. The drain work can have been | 1090 | * packets in the queues. The drain work can have been |
1091 | * triggered. Flush it. | 1091 | * triggered. Flush it. |
1092 | */ | 1092 | */ |
1093 | flush_work(&mvm->sta_drained_wk); | 1093 | flush_work(&mvm->sta_drained_wk); |
1094 | } | 1094 | } |
1095 | } | 1095 | } |
1096 | 1096 | ||
1097 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | 1097 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, |
1098 | struct ieee80211_vif *vif) | 1098 | struct ieee80211_vif *vif) |
1099 | { | 1099 | { |
1100 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1100 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1101 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1101 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1102 | 1102 | ||
1103 | iwl_mvm_prepare_mac_removal(mvm, vif); | 1103 | iwl_mvm_prepare_mac_removal(mvm, vif); |
1104 | 1104 | ||
1105 | mutex_lock(&mvm->mutex); | 1105 | mutex_lock(&mvm->mutex); |
1106 | 1106 | ||
1107 | if (mvm->bf_allowed_vif == mvmvif) { | 1107 | if (mvm->bf_allowed_vif == mvmvif) { |
1108 | mvm->bf_allowed_vif = NULL; | 1108 | mvm->bf_allowed_vif = NULL; |
1109 | vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | | 1109 | vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | |
1110 | IEEE80211_VIF_SUPPORTS_CQM_RSSI); | 1110 | IEEE80211_VIF_SUPPORTS_CQM_RSSI); |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | iwl_mvm_vif_dbgfs_clean(mvm, vif); | 1113 | iwl_mvm_vif_dbgfs_clean(mvm, vif); |
1114 | 1114 | ||
1115 | /* | 1115 | /* |
1116 | * For AP/GO interface, the tear down of the resources allocated to the | 1116 | * For AP/GO interface, the tear down of the resources allocated to the |
1117 | * interface is be handled as part of the stop_ap flow. | 1117 | * interface is be handled as part of the stop_ap flow. |
1118 | */ | 1118 | */ |
1119 | if (vif->type == NL80211_IFTYPE_AP || | 1119 | if (vif->type == NL80211_IFTYPE_AP || |
1120 | vif->type == NL80211_IFTYPE_ADHOC) { | 1120 | vif->type == NL80211_IFTYPE_ADHOC) { |
1121 | #ifdef CONFIG_NL80211_TESTMODE | 1121 | #ifdef CONFIG_NL80211_TESTMODE |
1122 | if (vif == mvm->noa_vif) { | 1122 | if (vif == mvm->noa_vif) { |
1123 | mvm->noa_vif = NULL; | 1123 | mvm->noa_vif = NULL; |
1124 | mvm->noa_duration = 0; | 1124 | mvm->noa_duration = 0; |
1125 | } | 1125 | } |
1126 | #endif | 1126 | #endif |
1127 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | 1127 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); |
1128 | goto out_release; | 1128 | goto out_release; |
1129 | } | 1129 | } |
1130 | 1130 | ||
1131 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 1131 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
1132 | mvm->p2p_device_vif = NULL; | 1132 | mvm->p2p_device_vif = NULL; |
1133 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1133 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); |
1134 | iwl_mvm_binding_remove_vif(mvm, vif); | 1134 | iwl_mvm_binding_remove_vif(mvm, vif); |
1135 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | 1135 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
1136 | mvmvif->phy_ctxt = NULL; | 1136 | mvmvif->phy_ctxt = NULL; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) | 1139 | if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) |
1140 | mvm->vif_count--; | 1140 | mvm->vif_count--; |
1141 | 1141 | ||
1142 | iwl_mvm_power_update_mac(mvm); | 1142 | iwl_mvm_power_update_mac(mvm); |
1143 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 1143 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
1144 | 1144 | ||
1145 | out_release: | 1145 | out_release: |
1146 | iwl_mvm_mac_ctxt_release(mvm, vif); | 1146 | iwl_mvm_mac_ctxt_release(mvm, vif); |
1147 | mutex_unlock(&mvm->mutex); | 1147 | mutex_unlock(&mvm->mutex); |
1148 | } | 1148 | } |
1149 | 1149 | ||
1150 | static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) | 1150 | static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) |
1151 | { | 1151 | { |
1152 | return 0; | 1152 | return 0; |
1153 | } | 1153 | } |
1154 | 1154 | ||
1155 | struct iwl_mvm_mc_iter_data { | 1155 | struct iwl_mvm_mc_iter_data { |
1156 | struct iwl_mvm *mvm; | 1156 | struct iwl_mvm *mvm; |
1157 | int port_id; | 1157 | int port_id; |
1158 | }; | 1158 | }; |
1159 | 1159 | ||
1160 | static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac, | 1160 | static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac, |
1161 | struct ieee80211_vif *vif) | 1161 | struct ieee80211_vif *vif) |
1162 | { | 1162 | { |
1163 | struct iwl_mvm_mc_iter_data *data = _data; | 1163 | struct iwl_mvm_mc_iter_data *data = _data; |
1164 | struct iwl_mvm *mvm = data->mvm; | 1164 | struct iwl_mvm *mvm = data->mvm; |
1165 | struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd; | 1165 | struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd; |
1166 | int ret, len; | 1166 | int ret, len; |
1167 | 1167 | ||
1168 | /* if we don't have free ports, mcast frames will be dropped */ | 1168 | /* if we don't have free ports, mcast frames will be dropped */ |
1169 | if (WARN_ON_ONCE(data->port_id >= MAX_PORT_ID_NUM)) | 1169 | if (WARN_ON_ONCE(data->port_id >= MAX_PORT_ID_NUM)) |
1170 | return; | 1170 | return; |
1171 | 1171 | ||
1172 | if (vif->type != NL80211_IFTYPE_STATION || | 1172 | if (vif->type != NL80211_IFTYPE_STATION || |
1173 | !vif->bss_conf.assoc) | 1173 | !vif->bss_conf.assoc) |
1174 | return; | 1174 | return; |
1175 | 1175 | ||
1176 | cmd->port_id = data->port_id++; | 1176 | cmd->port_id = data->port_id++; |
1177 | memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); | 1177 | memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); |
1178 | len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4); | 1178 | len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4); |
1179 | 1179 | ||
1180 | ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd); | 1180 | ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd); |
1181 | if (ret) | 1181 | if (ret) |
1182 | IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret); | 1182 | IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret); |
1183 | } | 1183 | } |
1184 | 1184 | ||
1185 | static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm) | 1185 | static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm) |
1186 | { | 1186 | { |
1187 | struct iwl_mvm_mc_iter_data iter_data = { | 1187 | struct iwl_mvm_mc_iter_data iter_data = { |
1188 | .mvm = mvm, | 1188 | .mvm = mvm, |
1189 | }; | 1189 | }; |
1190 | 1190 | ||
1191 | lockdep_assert_held(&mvm->mutex); | 1191 | lockdep_assert_held(&mvm->mutex); |
1192 | 1192 | ||
1193 | if (WARN_ON_ONCE(!mvm->mcast_filter_cmd)) | 1193 | if (WARN_ON_ONCE(!mvm->mcast_filter_cmd)) |
1194 | return; | 1194 | return; |
1195 | 1195 | ||
1196 | ieee80211_iterate_active_interfaces_atomic( | 1196 | ieee80211_iterate_active_interfaces_atomic( |
1197 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 1197 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
1198 | iwl_mvm_mc_iface_iterator, &iter_data); | 1198 | iwl_mvm_mc_iface_iterator, &iter_data); |
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, | 1201 | static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, |
1202 | struct netdev_hw_addr_list *mc_list) | 1202 | struct netdev_hw_addr_list *mc_list) |
1203 | { | 1203 | { |
1204 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1204 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1205 | struct iwl_mcast_filter_cmd *cmd; | 1205 | struct iwl_mcast_filter_cmd *cmd; |
1206 | struct netdev_hw_addr *addr; | 1206 | struct netdev_hw_addr *addr; |
1207 | int addr_count = netdev_hw_addr_list_count(mc_list); | 1207 | int addr_count = netdev_hw_addr_list_count(mc_list); |
1208 | bool pass_all = false; | 1208 | bool pass_all = false; |
1209 | int len; | 1209 | int len; |
1210 | 1210 | ||
1211 | if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) { | 1211 | if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) { |
1212 | pass_all = true; | 1212 | pass_all = true; |
1213 | addr_count = 0; | 1213 | addr_count = 0; |
1214 | } | 1214 | } |
1215 | 1215 | ||
1216 | len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); | 1216 | len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); |
1217 | cmd = kzalloc(len, GFP_ATOMIC); | 1217 | cmd = kzalloc(len, GFP_ATOMIC); |
1218 | if (!cmd) | 1218 | if (!cmd) |
1219 | return 0; | 1219 | return 0; |
1220 | 1220 | ||
1221 | if (pass_all) { | 1221 | if (pass_all) { |
1222 | cmd->pass_all = 1; | 1222 | cmd->pass_all = 1; |
1223 | return (u64)(unsigned long)cmd; | 1223 | return (u64)(unsigned long)cmd; |
1224 | } | 1224 | } |
1225 | 1225 | ||
1226 | netdev_hw_addr_list_for_each(addr, mc_list) { | 1226 | netdev_hw_addr_list_for_each(addr, mc_list) { |
1227 | IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %pM\n", | 1227 | IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %pM\n", |
1228 | cmd->count, addr->addr); | 1228 | cmd->count, addr->addr); |
1229 | memcpy(&cmd->addr_list[cmd->count * ETH_ALEN], | 1229 | memcpy(&cmd->addr_list[cmd->count * ETH_ALEN], |
1230 | addr->addr, ETH_ALEN); | 1230 | addr->addr, ETH_ALEN); |
1231 | cmd->count++; | 1231 | cmd->count++; |
1232 | } | 1232 | } |
1233 | 1233 | ||
1234 | return (u64)(unsigned long)cmd; | 1234 | return (u64)(unsigned long)cmd; |
1235 | } | 1235 | } |
1236 | 1236 | ||
1237 | static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, | 1237 | static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, |
1238 | unsigned int changed_flags, | 1238 | unsigned int changed_flags, |
1239 | unsigned int *total_flags, | 1239 | unsigned int *total_flags, |
1240 | u64 multicast) | 1240 | u64 multicast) |
1241 | { | 1241 | { |
1242 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1242 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1243 | struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast; | 1243 | struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast; |
1244 | 1244 | ||
1245 | mutex_lock(&mvm->mutex); | 1245 | mutex_lock(&mvm->mutex); |
1246 | 1246 | ||
1247 | /* replace previous configuration */ | 1247 | /* replace previous configuration */ |
1248 | kfree(mvm->mcast_filter_cmd); | 1248 | kfree(mvm->mcast_filter_cmd); |
1249 | mvm->mcast_filter_cmd = cmd; | 1249 | mvm->mcast_filter_cmd = cmd; |
1250 | 1250 | ||
1251 | if (!cmd) | 1251 | if (!cmd) |
1252 | goto out; | 1252 | goto out; |
1253 | 1253 | ||
1254 | iwl_mvm_recalc_multicast(mvm); | 1254 | iwl_mvm_recalc_multicast(mvm); |
1255 | out: | 1255 | out: |
1256 | mutex_unlock(&mvm->mutex); | 1256 | mutex_unlock(&mvm->mutex); |
1257 | *total_flags = 0; | 1257 | *total_flags = 0; |
1258 | } | 1258 | } |
1259 | 1259 | ||
1260 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | 1260 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING |
1261 | struct iwl_bcast_iter_data { | 1261 | struct iwl_bcast_iter_data { |
1262 | struct iwl_mvm *mvm; | 1262 | struct iwl_mvm *mvm; |
1263 | struct iwl_bcast_filter_cmd *cmd; | 1263 | struct iwl_bcast_filter_cmd *cmd; |
1264 | u8 current_filter; | 1264 | u8 current_filter; |
1265 | }; | 1265 | }; |
1266 | 1266 | ||
1267 | static void | 1267 | static void |
1268 | iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif, | 1268 | iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif, |
1269 | const struct iwl_fw_bcast_filter *in_filter, | 1269 | const struct iwl_fw_bcast_filter *in_filter, |
1270 | struct iwl_fw_bcast_filter *out_filter) | 1270 | struct iwl_fw_bcast_filter *out_filter) |
1271 | { | 1271 | { |
1272 | struct iwl_fw_bcast_filter_attr *attr; | 1272 | struct iwl_fw_bcast_filter_attr *attr; |
1273 | int i; | 1273 | int i; |
1274 | 1274 | ||
1275 | memcpy(out_filter, in_filter, sizeof(*out_filter)); | 1275 | memcpy(out_filter, in_filter, sizeof(*out_filter)); |
1276 | 1276 | ||
1277 | for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) { | 1277 | for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) { |
1278 | attr = &out_filter->attrs[i]; | 1278 | attr = &out_filter->attrs[i]; |
1279 | 1279 | ||
1280 | if (!attr->mask) | 1280 | if (!attr->mask) |
1281 | break; | 1281 | break; |
1282 | 1282 | ||
1283 | switch (attr->reserved1) { | 1283 | switch (attr->reserved1) { |
1284 | case cpu_to_le16(BC_FILTER_MAGIC_IP): | 1284 | case cpu_to_le16(BC_FILTER_MAGIC_IP): |
1285 | if (vif->bss_conf.arp_addr_cnt != 1) { | 1285 | if (vif->bss_conf.arp_addr_cnt != 1) { |
1286 | attr->mask = 0; | 1286 | attr->mask = 0; |
1287 | continue; | 1287 | continue; |
1288 | } | 1288 | } |
1289 | 1289 | ||
1290 | attr->val = vif->bss_conf.arp_addr_list[0]; | 1290 | attr->val = vif->bss_conf.arp_addr_list[0]; |
1291 | break; | 1291 | break; |
1292 | case cpu_to_le16(BC_FILTER_MAGIC_MAC): | 1292 | case cpu_to_le16(BC_FILTER_MAGIC_MAC): |
1293 | attr->val = *(__be32 *)&vif->addr[2]; | 1293 | attr->val = *(__be32 *)&vif->addr[2]; |
1294 | break; | 1294 | break; |
1295 | default: | 1295 | default: |
1296 | break; | 1296 | break; |
1297 | } | 1297 | } |
1298 | attr->reserved1 = 0; | 1298 | attr->reserved1 = 0; |
1299 | out_filter->num_attrs++; | 1299 | out_filter->num_attrs++; |
1300 | } | 1300 | } |
1301 | } | 1301 | } |
1302 | 1302 | ||
1303 | static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac, | 1303 | static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac, |
1304 | struct ieee80211_vif *vif) | 1304 | struct ieee80211_vif *vif) |
1305 | { | 1305 | { |
1306 | struct iwl_bcast_iter_data *data = _data; | 1306 | struct iwl_bcast_iter_data *data = _data; |
1307 | struct iwl_mvm *mvm = data->mvm; | 1307 | struct iwl_mvm *mvm = data->mvm; |
1308 | struct iwl_bcast_filter_cmd *cmd = data->cmd; | 1308 | struct iwl_bcast_filter_cmd *cmd = data->cmd; |
1309 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1309 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1310 | struct iwl_fw_bcast_mac *bcast_mac; | 1310 | struct iwl_fw_bcast_mac *bcast_mac; |
1311 | int i; | 1311 | int i; |
1312 | 1312 | ||
1313 | if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs))) | 1313 | if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs))) |
1314 | return; | 1314 | return; |
1315 | 1315 | ||
1316 | bcast_mac = &cmd->macs[mvmvif->id]; | 1316 | bcast_mac = &cmd->macs[mvmvif->id]; |
1317 | 1317 | ||
1318 | /* | 1318 | /* |
1319 | * enable filtering only for associated stations, but not for P2P | 1319 | * enable filtering only for associated stations, but not for P2P |
1320 | * Clients | 1320 | * Clients |
1321 | */ | 1321 | */ |
1322 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p || | 1322 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p || |
1323 | !vif->bss_conf.assoc) | 1323 | !vif->bss_conf.assoc) |
1324 | return; | 1324 | return; |
1325 | 1325 | ||
1326 | bcast_mac->default_discard = 1; | 1326 | bcast_mac->default_discard = 1; |
1327 | 1327 | ||
1328 | /* copy all configured filters */ | 1328 | /* copy all configured filters */ |
1329 | for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) { | 1329 | for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) { |
1330 | /* | 1330 | /* |
1331 | * Make sure we don't exceed our filters limit. | 1331 | * Make sure we don't exceed our filters limit. |
1332 | * if there is still a valid filter to be configured, | 1332 | * if there is still a valid filter to be configured, |
1333 | * be on the safe side and just allow bcast for this mac. | 1333 | * be on the safe side and just allow bcast for this mac. |
1334 | */ | 1334 | */ |
1335 | if (WARN_ON_ONCE(data->current_filter >= | 1335 | if (WARN_ON_ONCE(data->current_filter >= |
1336 | ARRAY_SIZE(cmd->filters))) { | 1336 | ARRAY_SIZE(cmd->filters))) { |
1337 | bcast_mac->default_discard = 0; | 1337 | bcast_mac->default_discard = 0; |
1338 | bcast_mac->attached_filters = 0; | 1338 | bcast_mac->attached_filters = 0; |
1339 | break; | 1339 | break; |
1340 | } | 1340 | } |
1341 | 1341 | ||
1342 | iwl_mvm_set_bcast_filter(vif, | 1342 | iwl_mvm_set_bcast_filter(vif, |
1343 | &mvm->bcast_filters[i], | 1343 | &mvm->bcast_filters[i], |
1344 | &cmd->filters[data->current_filter]); | 1344 | &cmd->filters[data->current_filter]); |
1345 | 1345 | ||
1346 | /* skip current filter if it contains no attributes */ | 1346 | /* skip current filter if it contains no attributes */ |
1347 | if (!cmd->filters[data->current_filter].num_attrs) | 1347 | if (!cmd->filters[data->current_filter].num_attrs) |
1348 | continue; | 1348 | continue; |
1349 | 1349 | ||
1350 | /* attach the filter to current mac */ | 1350 | /* attach the filter to current mac */ |
1351 | bcast_mac->attached_filters |= | 1351 | bcast_mac->attached_filters |= |
1352 | cpu_to_le16(BIT(data->current_filter)); | 1352 | cpu_to_le16(BIT(data->current_filter)); |
1353 | 1353 | ||
1354 | data->current_filter++; | 1354 | data->current_filter++; |
1355 | } | 1355 | } |
1356 | } | 1356 | } |
1357 | 1357 | ||
1358 | bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, | 1358 | bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, |
1359 | struct iwl_bcast_filter_cmd *cmd) | 1359 | struct iwl_bcast_filter_cmd *cmd) |
1360 | { | 1360 | { |
1361 | struct iwl_bcast_iter_data iter_data = { | 1361 | struct iwl_bcast_iter_data iter_data = { |
1362 | .mvm = mvm, | 1362 | .mvm = mvm, |
1363 | .cmd = cmd, | 1363 | .cmd = cmd, |
1364 | }; | 1364 | }; |
1365 | 1365 | ||
1366 | memset(cmd, 0, sizeof(*cmd)); | 1366 | memset(cmd, 0, sizeof(*cmd)); |
1367 | cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters); | 1367 | cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters); |
1368 | cmd->max_macs = ARRAY_SIZE(cmd->macs); | 1368 | cmd->max_macs = ARRAY_SIZE(cmd->macs); |
1369 | 1369 | ||
1370 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1370 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
1371 | /* use debugfs filters/macs if override is configured */ | 1371 | /* use debugfs filters/macs if override is configured */ |
1372 | if (mvm->dbgfs_bcast_filtering.override) { | 1372 | if (mvm->dbgfs_bcast_filtering.override) { |
1373 | memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters, | 1373 | memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters, |
1374 | sizeof(cmd->filters)); | 1374 | sizeof(cmd->filters)); |
1375 | memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs, | 1375 | memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs, |
1376 | sizeof(cmd->macs)); | 1376 | sizeof(cmd->macs)); |
1377 | return true; | 1377 | return true; |
1378 | } | 1378 | } |
1379 | #endif | 1379 | #endif |
1380 | 1380 | ||
1381 | /* if no filters are configured, do nothing */ | 1381 | /* if no filters are configured, do nothing */ |
1382 | if (!mvm->bcast_filters) | 1382 | if (!mvm->bcast_filters) |
1383 | return false; | 1383 | return false; |
1384 | 1384 | ||
1385 | /* configure and attach these filters for each associated sta vif */ | 1385 | /* configure and attach these filters for each associated sta vif */ |
1386 | ieee80211_iterate_active_interfaces( | 1386 | ieee80211_iterate_active_interfaces( |
1387 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 1387 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
1388 | iwl_mvm_bcast_filter_iterator, &iter_data); | 1388 | iwl_mvm_bcast_filter_iterator, &iter_data); |
1389 | 1389 | ||
1390 | return true; | 1390 | return true; |
1391 | } | 1391 | } |
1392 | static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, | 1392 | static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, |
1393 | struct ieee80211_vif *vif) | 1393 | struct ieee80211_vif *vif) |
1394 | { | 1394 | { |
1395 | struct iwl_bcast_filter_cmd cmd; | 1395 | struct iwl_bcast_filter_cmd cmd; |
1396 | 1396 | ||
1397 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING)) | 1397 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING)) |
1398 | return 0; | 1398 | return 0; |
1399 | 1399 | ||
1400 | if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) | 1400 | if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) |
1401 | return 0; | 1401 | return 0; |
1402 | 1402 | ||
1403 | return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, | 1403 | return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, |
1404 | sizeof(cmd), &cmd); | 1404 | sizeof(cmd), &cmd); |
1405 | } | 1405 | } |
1406 | #else | 1406 | #else |
1407 | static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, | 1407 | static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, |
1408 | struct ieee80211_vif *vif) | 1408 | struct ieee80211_vif *vif) |
1409 | { | 1409 | { |
1410 | return 0; | 1410 | return 0; |
1411 | } | 1411 | } |
1412 | #endif | 1412 | #endif |
1413 | 1413 | ||
1414 | static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) | 1414 | static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) |
1415 | { | 1415 | { |
1416 | struct ieee80211_sta *sta; | 1416 | struct ieee80211_sta *sta; |
1417 | struct iwl_mvm_sta *mvmsta; | 1417 | struct iwl_mvm_sta *mvmsta; |
1418 | int i; | 1418 | int i; |
1419 | 1419 | ||
1420 | lockdep_assert_held(&mvm->mutex); | 1420 | lockdep_assert_held(&mvm->mutex); |
1421 | 1421 | ||
1422 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | 1422 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { |
1423 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | 1423 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], |
1424 | lockdep_is_held(&mvm->mutex)); | 1424 | lockdep_is_held(&mvm->mutex)); |
1425 | if (!sta || IS_ERR(sta) || !sta->tdls) | 1425 | if (!sta || IS_ERR(sta) || !sta->tdls) |
1426 | continue; | 1426 | continue; |
1427 | 1427 | ||
1428 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1428 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1429 | ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, | 1429 | ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, |
1430 | NL80211_TDLS_TEARDOWN, | 1430 | NL80211_TDLS_TEARDOWN, |
1431 | WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, | 1431 | WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, |
1432 | GFP_KERNEL); | 1432 | GFP_KERNEL); |
1433 | } | 1433 | } |
1434 | } | 1434 | } |
1435 | 1435 | ||
1436 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | 1436 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, |
1437 | struct ieee80211_vif *vif, | 1437 | struct ieee80211_vif *vif, |
1438 | struct ieee80211_bss_conf *bss_conf, | 1438 | struct ieee80211_bss_conf *bss_conf, |
1439 | u32 changes) | 1439 | u32 changes) |
1440 | { | 1440 | { |
1441 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1441 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1442 | int ret; | 1442 | int ret; |
1443 | 1443 | ||
1444 | /* | 1444 | /* |
1445 | * Re-calculate the tsf id, as the master-slave relations depend on the | 1445 | * Re-calculate the tsf id, as the master-slave relations depend on the |
1446 | * beacon interval, which was not known when the station interface was | 1446 | * beacon interval, which was not known when the station interface was |
1447 | * added. | 1447 | * added. |
1448 | */ | 1448 | */ |
1449 | if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) | 1449 | if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) |
1450 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); | 1450 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); |
1451 | 1451 | ||
1452 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); | 1452 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); |
1453 | if (ret) | 1453 | if (ret) |
1454 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | 1454 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); |
1455 | 1455 | ||
1456 | if (changes & BSS_CHANGED_ASSOC) { | 1456 | if (changes & BSS_CHANGED_ASSOC) { |
1457 | if (bss_conf->assoc) { | 1457 | if (bss_conf->assoc) { |
1458 | /* add quota for this interface */ | 1458 | /* add quota for this interface */ |
1459 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1459 | ret = iwl_mvm_update_quotas(mvm, NULL); |
1460 | if (ret) { | 1460 | if (ret) { |
1461 | IWL_ERR(mvm, "failed to update quotas\n"); | 1461 | IWL_ERR(mvm, "failed to update quotas\n"); |
1462 | return; | 1462 | return; |
1463 | } | 1463 | } |
1464 | 1464 | ||
1465 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, | 1465 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, |
1466 | &mvm->status)) { | 1466 | &mvm->status)) { |
1467 | /* | 1467 | /* |
1468 | * If we're restarting then the firmware will | 1468 | * If we're restarting then the firmware will |
1469 | * obviously have lost synchronisation with | 1469 | * obviously have lost synchronisation with |
1470 | * the AP. It will attempt to synchronise by | 1470 | * the AP. It will attempt to synchronise by |
1471 | * itself, but we can make it more reliable by | 1471 | * itself, but we can make it more reliable by |
1472 | * scheduling a session protection time event. | 1472 | * scheduling a session protection time event. |
1473 | * | 1473 | * |
1474 | * The firmware needs to receive a beacon to | 1474 | * The firmware needs to receive a beacon to |
1475 | * catch up with synchronisation, use 110% of | 1475 | * catch up with synchronisation, use 110% of |
1476 | * the beacon interval. | 1476 | * the beacon interval. |
1477 | * | 1477 | * |
1478 | * Set a large maximum delay to allow for more | 1478 | * Set a large maximum delay to allow for more |
1479 | * than a single interface. | 1479 | * than a single interface. |
1480 | */ | 1480 | */ |
1481 | u32 dur = (11 * vif->bss_conf.beacon_int) / 10; | 1481 | u32 dur = (11 * vif->bss_conf.beacon_int) / 10; |
1482 | iwl_mvm_protect_session(mvm, vif, dur, dur, | 1482 | iwl_mvm_protect_session(mvm, vif, dur, dur, |
1483 | 5 * dur); | 1483 | 5 * dur); |
1484 | } | 1484 | } |
1485 | 1485 | ||
1486 | iwl_mvm_sf_update(mvm, vif, false); | 1486 | iwl_mvm_sf_update(mvm, vif, false); |
1487 | iwl_mvm_power_vif_assoc(mvm, vif); | 1487 | iwl_mvm_power_vif_assoc(mvm, vif); |
1488 | if (vif->p2p) | 1488 | if (vif->p2p) |
1489 | iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT); | 1489 | iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT); |
1490 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 1490 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
1491 | /* | 1491 | /* |
1492 | * If update fails - SF might be running in associated | 1492 | * If update fails - SF might be running in associated |
1493 | * mode while disassociated - which is forbidden. | 1493 | * mode while disassociated - which is forbidden. |
1494 | */ | 1494 | */ |
1495 | WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false), | 1495 | WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false), |
1496 | "Failed to update SF upon disassociation\n"); | 1496 | "Failed to update SF upon disassociation\n"); |
1497 | 1497 | ||
1498 | /* remove AP station now that the MAC is unassoc */ | 1498 | /* remove AP station now that the MAC is unassoc */ |
1499 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 1499 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
1500 | if (ret) | 1500 | if (ret) |
1501 | IWL_ERR(mvm, "failed to remove AP station\n"); | 1501 | IWL_ERR(mvm, "failed to remove AP station\n"); |
1502 | 1502 | ||
1503 | if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) | 1503 | if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) |
1504 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | 1504 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; |
1505 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 1505 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
1506 | /* remove quota for this interface */ | 1506 | /* remove quota for this interface */ |
1507 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1507 | ret = iwl_mvm_update_quotas(mvm, NULL); |
1508 | if (ret) | 1508 | if (ret) |
1509 | IWL_ERR(mvm, "failed to update quotas\n"); | 1509 | IWL_ERR(mvm, "failed to update quotas\n"); |
1510 | 1510 | ||
1511 | if (vif->p2p) | 1511 | if (vif->p2p) |
1512 | iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT); | 1512 | iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT); |
1513 | } | 1513 | } |
1514 | 1514 | ||
1515 | iwl_mvm_recalc_multicast(mvm); | 1515 | iwl_mvm_recalc_multicast(mvm); |
1516 | iwl_mvm_configure_bcast_filter(mvm, vif); | 1516 | iwl_mvm_configure_bcast_filter(mvm, vif); |
1517 | 1517 | ||
1518 | /* reset rssi values */ | 1518 | /* reset rssi values */ |
1519 | mvmvif->bf_data.ave_beacon_signal = 0; | 1519 | mvmvif->bf_data.ave_beacon_signal = 0; |
1520 | 1520 | ||
1521 | iwl_mvm_bt_coex_vif_change(mvm); | 1521 | iwl_mvm_bt_coex_vif_change(mvm); |
1522 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, | 1522 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, |
1523 | IEEE80211_SMPS_AUTOMATIC); | 1523 | IEEE80211_SMPS_AUTOMATIC); |
1524 | } else if (changes & BSS_CHANGED_BEACON_INFO) { | 1524 | } else if (changes & BSS_CHANGED_BEACON_INFO) { |
1525 | /* | 1525 | /* |
1526 | * We received a beacon _after_ association so | 1526 | * We received a beacon _after_ association so |
1527 | * remove the session protection. | 1527 | * remove the session protection. |
1528 | */ | 1528 | */ |
1529 | iwl_mvm_remove_time_event(mvm, mvmvif, | 1529 | iwl_mvm_remove_time_event(mvm, mvmvif, |
1530 | &mvmvif->time_event_data); | 1530 | &mvmvif->time_event_data); |
1531 | } | 1531 | } |
1532 | 1532 | ||
1533 | if (changes & BSS_CHANGED_BEACON_INFO) { | 1533 | if (changes & BSS_CHANGED_BEACON_INFO) { |
1534 | iwl_mvm_sf_update(mvm, vif, false); | 1534 | iwl_mvm_sf_update(mvm, vif, false); |
1535 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); | 1535 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { | 1538 | if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { |
1539 | ret = iwl_mvm_power_update_mac(mvm); | 1539 | ret = iwl_mvm_power_update_mac(mvm); |
1540 | if (ret) | 1540 | if (ret) |
1541 | IWL_ERR(mvm, "failed to update power mode\n"); | 1541 | IWL_ERR(mvm, "failed to update power mode\n"); |
1542 | } | 1542 | } |
1543 | 1543 | ||
1544 | if (changes & BSS_CHANGED_TXPOWER) { | 1544 | if (changes & BSS_CHANGED_TXPOWER) { |
1545 | IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", | 1545 | IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", |
1546 | bss_conf->txpower); | 1546 | bss_conf->txpower); |
1547 | iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); | 1547 | iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); |
1548 | } | 1548 | } |
1549 | 1549 | ||
1550 | if (changes & BSS_CHANGED_CQM) { | 1550 | if (changes & BSS_CHANGED_CQM) { |
1551 | IWL_DEBUG_MAC80211(mvm, "cqm info_changed\n"); | 1551 | IWL_DEBUG_MAC80211(mvm, "cqm info_changed\n"); |
1552 | /* reset cqm events tracking */ | 1552 | /* reset cqm events tracking */ |
1553 | mvmvif->bf_data.last_cqm_event = 0; | 1553 | mvmvif->bf_data.last_cqm_event = 0; |
1554 | if (mvmvif->bf_data.bf_enabled) { | 1554 | if (mvmvif->bf_data.bf_enabled) { |
1555 | ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); | 1555 | ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); |
1556 | if (ret) | 1556 | if (ret) |
1557 | IWL_ERR(mvm, | 1557 | IWL_ERR(mvm, |
1558 | "failed to update CQM thresholds\n"); | 1558 | "failed to update CQM thresholds\n"); |
1559 | } | 1559 | } |
1560 | } | 1560 | } |
1561 | 1561 | ||
1562 | if (changes & BSS_CHANGED_ARP_FILTER) { | 1562 | if (changes & BSS_CHANGED_ARP_FILTER) { |
1563 | IWL_DEBUG_MAC80211(mvm, "arp filter changed\n"); | 1563 | IWL_DEBUG_MAC80211(mvm, "arp filter changed\n"); |
1564 | iwl_mvm_configure_bcast_filter(mvm, vif); | 1564 | iwl_mvm_configure_bcast_filter(mvm, vif); |
1565 | } | 1565 | } |
1566 | } | 1566 | } |
1567 | 1567 | ||
1568 | static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | 1568 | static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, |
1569 | struct ieee80211_vif *vif) | 1569 | struct ieee80211_vif *vif) |
1570 | { | 1570 | { |
1571 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1571 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1572 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1572 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1573 | int ret; | 1573 | int ret; |
1574 | 1574 | ||
1575 | /* | 1575 | /* |
1576 | * iwl_mvm_mac_ctxt_add() might read directly from the device | 1576 | * iwl_mvm_mac_ctxt_add() might read directly from the device |
1577 | * (the system time), so make sure it is available. | 1577 | * (the system time), so make sure it is available. |
1578 | */ | 1578 | */ |
1579 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP); | 1579 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP); |
1580 | if (ret) | 1580 | if (ret) |
1581 | return ret; | 1581 | return ret; |
1582 | 1582 | ||
1583 | mutex_lock(&mvm->mutex); | 1583 | mutex_lock(&mvm->mutex); |
1584 | 1584 | ||
1585 | /* Send the beacon template */ | 1585 | /* Send the beacon template */ |
1586 | ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif); | 1586 | ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif); |
1587 | if (ret) | 1587 | if (ret) |
1588 | goto out_unlock; | 1588 | goto out_unlock; |
1589 | 1589 | ||
1590 | /* | 1590 | /* |
1591 | * Re-calculate the tsf id, as the master-slave relations depend on the | 1591 | * Re-calculate the tsf id, as the master-slave relations depend on the |
1592 | * beacon interval, which was not known when the AP interface was added. | 1592 | * beacon interval, which was not known when the AP interface was added. |
1593 | */ | 1593 | */ |
1594 | if (vif->type == NL80211_IFTYPE_AP) | 1594 | if (vif->type == NL80211_IFTYPE_AP) |
1595 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); | 1595 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); |
1596 | 1596 | ||
1597 | /* Add the mac context */ | 1597 | /* Add the mac context */ |
1598 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); | 1598 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); |
1599 | if (ret) | 1599 | if (ret) |
1600 | goto out_unlock; | 1600 | goto out_unlock; |
1601 | 1601 | ||
1602 | /* Perform the binding */ | 1602 | /* Perform the binding */ |
1603 | ret = iwl_mvm_binding_add_vif(mvm, vif); | 1603 | ret = iwl_mvm_binding_add_vif(mvm, vif); |
1604 | if (ret) | 1604 | if (ret) |
1605 | goto out_remove; | 1605 | goto out_remove; |
1606 | 1606 | ||
1607 | /* Send the bcast station. At this stage the TBTT and DTIM time events | 1607 | /* Send the bcast station. At this stage the TBTT and DTIM time events |
1608 | * are added and applied to the scheduler */ | 1608 | * are added and applied to the scheduler */ |
1609 | ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | 1609 | ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); |
1610 | if (ret) | 1610 | if (ret) |
1611 | goto out_unbind; | 1611 | goto out_unbind; |
1612 | 1612 | ||
1613 | /* must be set before quota calculations */ | 1613 | /* must be set before quota calculations */ |
1614 | mvmvif->ap_ibss_active = true; | 1614 | mvmvif->ap_ibss_active = true; |
1615 | 1615 | ||
1616 | /* power updated needs to be done before quotas */ | 1616 | /* power updated needs to be done before quotas */ |
1617 | iwl_mvm_power_update_mac(mvm); | 1617 | iwl_mvm_power_update_mac(mvm); |
1618 | 1618 | ||
1619 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1619 | ret = iwl_mvm_update_quotas(mvm, NULL); |
1620 | if (ret) | 1620 | if (ret) |
1621 | goto out_quota_failed; | 1621 | goto out_quota_failed; |
1622 | 1622 | ||
1623 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ | 1623 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ |
1624 | if (vif->p2p && mvm->p2p_device_vif) | 1624 | if (vif->p2p && mvm->p2p_device_vif) |
1625 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); | 1625 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); |
1626 | 1626 | ||
1627 | iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS); | 1627 | iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS); |
1628 | 1628 | ||
1629 | iwl_mvm_bt_coex_vif_change(mvm); | 1629 | iwl_mvm_bt_coex_vif_change(mvm); |
1630 | 1630 | ||
1631 | /* we don't support TDLS during DCM */ | 1631 | /* we don't support TDLS during DCM */ |
1632 | if (iwl_mvm_phy_ctx_count(mvm) > 1) | 1632 | if (iwl_mvm_phy_ctx_count(mvm) > 1) |
1633 | iwl_mvm_teardown_tdls_peers(mvm); | 1633 | iwl_mvm_teardown_tdls_peers(mvm); |
1634 | 1634 | ||
1635 | mutex_unlock(&mvm->mutex); | 1635 | mutex_unlock(&mvm->mutex); |
1636 | return 0; | 1636 | return 0; |
1637 | 1637 | ||
1638 | out_quota_failed: | 1638 | out_quota_failed: |
1639 | iwl_mvm_power_update_mac(mvm); | 1639 | iwl_mvm_power_update_mac(mvm); |
1640 | mvmvif->ap_ibss_active = false; | 1640 | mvmvif->ap_ibss_active = false; |
1641 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1641 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); |
1642 | out_unbind: | 1642 | out_unbind: |
1643 | iwl_mvm_binding_remove_vif(mvm, vif); | 1643 | iwl_mvm_binding_remove_vif(mvm, vif); |
1644 | out_remove: | 1644 | out_remove: |
1645 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 1645 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
1646 | out_unlock: | 1646 | out_unlock: |
1647 | mutex_unlock(&mvm->mutex); | 1647 | mutex_unlock(&mvm->mutex); |
1648 | iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP); | 1648 | iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP); |
1649 | return ret; | 1649 | return ret; |
1650 | } | 1650 | } |
1651 | 1651 | ||
1652 | static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, | 1652 | static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, |
1653 | struct ieee80211_vif *vif) | 1653 | struct ieee80211_vif *vif) |
1654 | { | 1654 | { |
1655 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1655 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1656 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1656 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1657 | 1657 | ||
1658 | iwl_mvm_prepare_mac_removal(mvm, vif); | 1658 | iwl_mvm_prepare_mac_removal(mvm, vif); |
1659 | 1659 | ||
1660 | mutex_lock(&mvm->mutex); | 1660 | mutex_lock(&mvm->mutex); |
1661 | 1661 | ||
1662 | /* Handle AP stop while in CSA */ | 1662 | /* Handle AP stop while in CSA */ |
1663 | if (rcu_access_pointer(mvm->csa_vif) == vif) { | 1663 | if (rcu_access_pointer(mvm->csa_vif) == vif) { |
1664 | iwl_mvm_remove_time_event(mvm, mvmvif, | 1664 | iwl_mvm_remove_time_event(mvm, mvmvif, |
1665 | &mvmvif->time_event_data); | 1665 | &mvmvif->time_event_data); |
1666 | RCU_INIT_POINTER(mvm->csa_vif, NULL); | 1666 | RCU_INIT_POINTER(mvm->csa_vif, NULL); |
1667 | } | 1667 | } |
1668 | 1668 | ||
1669 | if (rcu_access_pointer(mvm->csa_tx_blocked_vif) == vif) { | 1669 | if (rcu_access_pointer(mvm->csa_tx_blocked_vif) == vif) { |
1670 | RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); | 1670 | RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); |
1671 | mvm->csa_tx_block_bcn_timeout = 0; | 1671 | mvm->csa_tx_block_bcn_timeout = 0; |
1672 | } | 1672 | } |
1673 | 1673 | ||
1674 | mvmvif->ap_ibss_active = false; | 1674 | mvmvif->ap_ibss_active = false; |
1675 | mvm->ap_last_beacon_gp2 = 0; | 1675 | mvm->ap_last_beacon_gp2 = 0; |
1676 | 1676 | ||
1677 | iwl_mvm_bt_coex_vif_change(mvm); | 1677 | iwl_mvm_bt_coex_vif_change(mvm); |
1678 | 1678 | ||
1679 | iwl_mvm_unref(mvm, IWL_MVM_REF_AP_IBSS); | 1679 | iwl_mvm_unref(mvm, IWL_MVM_REF_AP_IBSS); |
1680 | 1680 | ||
1681 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ | 1681 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ |
1682 | if (vif->p2p && mvm->p2p_device_vif) | 1682 | if (vif->p2p && mvm->p2p_device_vif) |
1683 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); | 1683 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); |
1684 | 1684 | ||
1685 | iwl_mvm_update_quotas(mvm, NULL); | 1685 | iwl_mvm_update_quotas(mvm, NULL); |
1686 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1686 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); |
1687 | iwl_mvm_binding_remove_vif(mvm, vif); | 1687 | iwl_mvm_binding_remove_vif(mvm, vif); |
1688 | 1688 | ||
1689 | iwl_mvm_power_update_mac(mvm); | 1689 | iwl_mvm_power_update_mac(mvm); |
1690 | 1690 | ||
1691 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 1691 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
1692 | 1692 | ||
1693 | mutex_unlock(&mvm->mutex); | 1693 | mutex_unlock(&mvm->mutex); |
1694 | } | 1694 | } |
1695 | 1695 | ||
1696 | static void | 1696 | static void |
1697 | iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, | 1697 | iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, |
1698 | struct ieee80211_vif *vif, | 1698 | struct ieee80211_vif *vif, |
1699 | struct ieee80211_bss_conf *bss_conf, | 1699 | struct ieee80211_bss_conf *bss_conf, |
1700 | u32 changes) | 1700 | u32 changes) |
1701 | { | 1701 | { |
1702 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1702 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1703 | 1703 | ||
1704 | /* Changes will be applied when the AP/IBSS is started */ | 1704 | /* Changes will be applied when the AP/IBSS is started */ |
1705 | if (!mvmvif->ap_ibss_active) | 1705 | if (!mvmvif->ap_ibss_active) |
1706 | return; | 1706 | return; |
1707 | 1707 | ||
1708 | if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | | 1708 | if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | |
1709 | BSS_CHANGED_BANDWIDTH) && | 1709 | BSS_CHANGED_BANDWIDTH) && |
1710 | iwl_mvm_mac_ctxt_changed(mvm, vif, false)) | 1710 | iwl_mvm_mac_ctxt_changed(mvm, vif, false)) |
1711 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | 1711 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); |
1712 | 1712 | ||
1713 | /* Need to send a new beacon template to the FW */ | 1713 | /* Need to send a new beacon template to the FW */ |
1714 | if (changes & BSS_CHANGED_BEACON && | 1714 | if (changes & BSS_CHANGED_BEACON && |
1715 | iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) | 1715 | iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) |
1716 | IWL_WARN(mvm, "Failed updating beacon data\n"); | 1716 | IWL_WARN(mvm, "Failed updating beacon data\n"); |
1717 | } | 1717 | } |
1718 | 1718 | ||
1719 | static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | 1719 | static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, |
1720 | struct ieee80211_vif *vif, | 1720 | struct ieee80211_vif *vif, |
1721 | struct ieee80211_bss_conf *bss_conf, | 1721 | struct ieee80211_bss_conf *bss_conf, |
1722 | u32 changes) | 1722 | u32 changes) |
1723 | { | 1723 | { |
1724 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1724 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1725 | 1725 | ||
1726 | /* | 1726 | /* |
1727 | * iwl_mvm_bss_info_changed_station() might call | 1727 | * iwl_mvm_bss_info_changed_station() might call |
1728 | * iwl_mvm_protect_session(), which reads directly from | 1728 | * iwl_mvm_protect_session(), which reads directly from |
1729 | * the device (the system time), so make sure it is available. | 1729 | * the device (the system time), so make sure it is available. |
1730 | */ | 1730 | */ |
1731 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED)) | 1731 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED)) |
1732 | return; | 1732 | return; |
1733 | 1733 | ||
1734 | mutex_lock(&mvm->mutex); | 1734 | mutex_lock(&mvm->mutex); |
1735 | 1735 | ||
1736 | if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) | 1736 | if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) |
1737 | iwl_mvm_scan_offload_stop(mvm, true); | 1737 | iwl_mvm_scan_offload_stop(mvm, true); |
1738 | 1738 | ||
1739 | switch (vif->type) { | 1739 | switch (vif->type) { |
1740 | case NL80211_IFTYPE_STATION: | 1740 | case NL80211_IFTYPE_STATION: |
1741 | iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes); | 1741 | iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes); |
1742 | break; | 1742 | break; |
1743 | case NL80211_IFTYPE_AP: | 1743 | case NL80211_IFTYPE_AP: |
1744 | case NL80211_IFTYPE_ADHOC: | 1744 | case NL80211_IFTYPE_ADHOC: |
1745 | iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes); | 1745 | iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes); |
1746 | break; | 1746 | break; |
1747 | default: | 1747 | default: |
1748 | /* shouldn't happen */ | 1748 | /* shouldn't happen */ |
1749 | WARN_ON_ONCE(1); | 1749 | WARN_ON_ONCE(1); |
1750 | } | 1750 | } |
1751 | 1751 | ||
1752 | mutex_unlock(&mvm->mutex); | 1752 | mutex_unlock(&mvm->mutex); |
1753 | iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED); | 1753 | iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED); |
1754 | } | 1754 | } |
1755 | 1755 | ||
1756 | static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm, | 1756 | static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm, |
1757 | enum iwl_scan_status scan_type) | 1757 | enum iwl_scan_status scan_type) |
1758 | { | 1758 | { |
1759 | int ret; | 1759 | int ret; |
1760 | bool wait_for_handlers = false; | 1760 | bool wait_for_handlers = false; |
1761 | 1761 | ||
1762 | mutex_lock(&mvm->mutex); | 1762 | mutex_lock(&mvm->mutex); |
1763 | 1763 | ||
1764 | if (mvm->scan_status != scan_type) { | 1764 | if (mvm->scan_status != scan_type) { |
1765 | ret = 0; | 1765 | ret = 0; |
1766 | /* make sure there are no pending notifications */ | 1766 | /* make sure there are no pending notifications */ |
1767 | wait_for_handlers = true; | 1767 | wait_for_handlers = true; |
1768 | goto out; | 1768 | goto out; |
1769 | } | 1769 | } |
1770 | 1770 | ||
1771 | switch (scan_type) { | 1771 | switch (scan_type) { |
1772 | case IWL_MVM_SCAN_SCHED: | 1772 | case IWL_MVM_SCAN_SCHED: |
1773 | ret = iwl_mvm_scan_offload_stop(mvm, true); | 1773 | ret = iwl_mvm_scan_offload_stop(mvm, true); |
1774 | break; | 1774 | break; |
1775 | case IWL_MVM_SCAN_OS: | 1775 | case IWL_MVM_SCAN_OS: |
1776 | ret = iwl_mvm_cancel_scan(mvm); | 1776 | ret = iwl_mvm_cancel_scan(mvm); |
1777 | break; | 1777 | break; |
1778 | case IWL_MVM_SCAN_NONE: | 1778 | case IWL_MVM_SCAN_NONE: |
1779 | default: | 1779 | default: |
1780 | WARN_ON_ONCE(1); | 1780 | WARN_ON_ONCE(1); |
1781 | ret = -EINVAL; | 1781 | ret = -EINVAL; |
1782 | break; | 1782 | break; |
1783 | } | 1783 | } |
1784 | if (ret) | 1784 | if (ret) |
1785 | goto out; | 1785 | goto out; |
1786 | 1786 | ||
1787 | wait_for_handlers = true; | 1787 | wait_for_handlers = true; |
1788 | out: | 1788 | out: |
1789 | mutex_unlock(&mvm->mutex); | 1789 | mutex_unlock(&mvm->mutex); |
1790 | 1790 | ||
1791 | /* make sure we consume the completion notification */ | 1791 | /* make sure we consume the completion notification */ |
1792 | if (wait_for_handlers) | 1792 | if (wait_for_handlers) |
1793 | iwl_mvm_wait_for_async_handlers(mvm); | 1793 | iwl_mvm_wait_for_async_handlers(mvm); |
1794 | 1794 | ||
1795 | return ret; | 1795 | return ret; |
1796 | } | 1796 | } |
1797 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | 1797 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, |
1798 | struct ieee80211_vif *vif, | 1798 | struct ieee80211_vif *vif, |
1799 | struct ieee80211_scan_request *hw_req) | 1799 | struct ieee80211_scan_request *hw_req) |
1800 | { | 1800 | { |
1801 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1801 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1802 | struct cfg80211_scan_request *req = &hw_req->req; | 1802 | struct cfg80211_scan_request *req = &hw_req->req; |
1803 | int ret; | 1803 | int ret; |
1804 | 1804 | ||
1805 | if (req->n_channels == 0 || | 1805 | if (req->n_channels == 0 || |
1806 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) | 1806 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) |
1807 | return -EINVAL; | 1807 | return -EINVAL; |
1808 | 1808 | ||
1809 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); | 1809 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); |
1810 | if (ret) | 1810 | if (ret) |
1811 | return ret; | 1811 | return ret; |
1812 | 1812 | ||
1813 | mutex_lock(&mvm->mutex); | 1813 | mutex_lock(&mvm->mutex); |
1814 | 1814 | ||
1815 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { | 1815 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { |
1816 | ret = -EBUSY; | 1816 | ret = -EBUSY; |
1817 | goto out; | 1817 | goto out; |
1818 | } | 1818 | } |
1819 | 1819 | ||
1820 | iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); | 1820 | iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); |
1821 | 1821 | ||
1822 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 1822 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) |
1823 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); | 1823 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); |
1824 | else | 1824 | else |
1825 | ret = iwl_mvm_scan_request(mvm, vif, req); | 1825 | ret = iwl_mvm_scan_request(mvm, vif, req); |
1826 | 1826 | ||
1827 | if (ret) | 1827 | if (ret) |
1828 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | 1828 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); |
1829 | out: | 1829 | out: |
1830 | mutex_unlock(&mvm->mutex); | 1830 | mutex_unlock(&mvm->mutex); |
1831 | return ret; | 1831 | return ret; |
1832 | } | 1832 | } |
1833 | 1833 | ||
1834 | static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, | 1834 | static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, |
1835 | struct ieee80211_vif *vif) | 1835 | struct ieee80211_vif *vif) |
1836 | { | 1836 | { |
1837 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1837 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1838 | 1838 | ||
1839 | mutex_lock(&mvm->mutex); | 1839 | mutex_lock(&mvm->mutex); |
1840 | 1840 | ||
1841 | iwl_mvm_cancel_scan(mvm); | 1841 | iwl_mvm_cancel_scan(mvm); |
1842 | 1842 | ||
1843 | mutex_unlock(&mvm->mutex); | 1843 | mutex_unlock(&mvm->mutex); |
1844 | } | 1844 | } |
1845 | 1845 | ||
1846 | static void | 1846 | static void |
1847 | iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, | 1847 | iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, |
1848 | struct ieee80211_sta *sta, u16 tids, | 1848 | struct ieee80211_sta *sta, u16 tids, |
1849 | int num_frames, | 1849 | int num_frames, |
1850 | enum ieee80211_frame_release_type reason, | 1850 | enum ieee80211_frame_release_type reason, |
1851 | bool more_data) | 1851 | bool more_data) |
1852 | { | 1852 | { |
1853 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1853 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1854 | 1854 | ||
1855 | /* Called when we need to transmit (a) frame(s) from mac80211 */ | 1855 | /* Called when we need to transmit (a) frame(s) from mac80211 */ |
1856 | 1856 | ||
1857 | iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, | 1857 | iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, |
1858 | tids, more_data, false); | 1858 | tids, more_data, false); |
1859 | } | 1859 | } |
1860 | 1860 | ||
1861 | static void | 1861 | static void |
1862 | iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, | 1862 | iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, |
1863 | struct ieee80211_sta *sta, u16 tids, | 1863 | struct ieee80211_sta *sta, u16 tids, |
1864 | int num_frames, | 1864 | int num_frames, |
1865 | enum ieee80211_frame_release_type reason, | 1865 | enum ieee80211_frame_release_type reason, |
1866 | bool more_data) | 1866 | bool more_data) |
1867 | { | 1867 | { |
1868 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1868 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1869 | 1869 | ||
1870 | /* Called when we need to transmit (a) frame(s) from agg queue */ | 1870 | /* Called when we need to transmit (a) frame(s) from agg queue */ |
1871 | 1871 | ||
1872 | iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, | 1872 | iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, |
1873 | tids, more_data, true); | 1873 | tids, more_data, true); |
1874 | } | 1874 | } |
1875 | 1875 | ||
1876 | static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | 1876 | static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, |
1877 | struct ieee80211_vif *vif, | 1877 | struct ieee80211_vif *vif, |
1878 | enum sta_notify_cmd cmd, | 1878 | enum sta_notify_cmd cmd, |
1879 | struct ieee80211_sta *sta) | 1879 | struct ieee80211_sta *sta) |
1880 | { | 1880 | { |
1881 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1881 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1882 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1882 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1883 | int tid; | 1883 | int tid; |
1884 | 1884 | ||
1885 | switch (cmd) { | 1885 | switch (cmd) { |
1886 | case STA_NOTIFY_SLEEP: | 1886 | case STA_NOTIFY_SLEEP: |
1887 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) | 1887 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) |
1888 | ieee80211_sta_block_awake(hw, sta, true); | 1888 | ieee80211_sta_block_awake(hw, sta, true); |
1889 | spin_lock_bh(&mvmsta->lock); | 1889 | spin_lock_bh(&mvmsta->lock); |
1890 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { | 1890 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { |
1891 | struct iwl_mvm_tid_data *tid_data; | 1891 | struct iwl_mvm_tid_data *tid_data; |
1892 | 1892 | ||
1893 | tid_data = &mvmsta->tid_data[tid]; | 1893 | tid_data = &mvmsta->tid_data[tid]; |
1894 | if (tid_data->state != IWL_AGG_ON && | 1894 | if (tid_data->state != IWL_AGG_ON && |
1895 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) | 1895 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) |
1896 | continue; | 1896 | continue; |
1897 | if (iwl_mvm_tid_queued(tid_data) == 0) | 1897 | if (iwl_mvm_tid_queued(tid_data) == 0) |
1898 | continue; | 1898 | continue; |
1899 | ieee80211_sta_set_buffered(sta, tid, true); | 1899 | ieee80211_sta_set_buffered(sta, tid, true); |
1900 | } | 1900 | } |
1901 | spin_unlock_bh(&mvmsta->lock); | 1901 | spin_unlock_bh(&mvmsta->lock); |
1902 | /* | 1902 | /* |
1903 | * The fw updates the STA to be asleep. Tx packets on the Tx | 1903 | * The fw updates the STA to be asleep. Tx packets on the Tx |
1904 | * queues to this station will not be transmitted. The fw will | 1904 | * queues to this station will not be transmitted. The fw will |
1905 | * send a Tx response with TX_STATUS_FAIL_DEST_PS. | 1905 | * send a Tx response with TX_STATUS_FAIL_DEST_PS. |
1906 | */ | 1906 | */ |
1907 | break; | 1907 | break; |
1908 | case STA_NOTIFY_AWAKE: | 1908 | case STA_NOTIFY_AWAKE: |
1909 | if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) | 1909 | if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) |
1910 | break; | 1910 | break; |
1911 | iwl_mvm_sta_modify_ps_wake(mvm, sta); | 1911 | iwl_mvm_sta_modify_ps_wake(mvm, sta); |
1912 | break; | 1912 | break; |
1913 | default: | 1913 | default: |
1914 | break; | 1914 | break; |
1915 | } | 1915 | } |
1916 | } | 1916 | } |
1917 | 1917 | ||
1918 | static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, | 1918 | static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, |
1919 | struct ieee80211_vif *vif, | 1919 | struct ieee80211_vif *vif, |
1920 | struct ieee80211_sta *sta) | 1920 | struct ieee80211_sta *sta) |
1921 | { | 1921 | { |
1922 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1922 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1923 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 1923 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
1924 | 1924 | ||
1925 | /* | 1925 | /* |
1926 | * This is called before mac80211 does RCU synchronisation, | 1926 | * This is called before mac80211 does RCU synchronisation, |
1927 | * so here we already invalidate our internal RCU-protected | 1927 | * so here we already invalidate our internal RCU-protected |
1928 | * station pointer. The rest of the code will thus no longer | 1928 | * station pointer. The rest of the code will thus no longer |
1929 | * be able to find the station this way, and we don't rely | 1929 | * be able to find the station this way, and we don't rely |
1930 | * on further RCU synchronisation after the sta_state() | 1930 | * on further RCU synchronisation after the sta_state() |
1931 | * callback deleted the station. | 1931 | * callback deleted the station. |
1932 | */ | 1932 | */ |
1933 | mutex_lock(&mvm->mutex); | 1933 | mutex_lock(&mvm->mutex); |
1934 | if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id])) | 1934 | if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id])) |
1935 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], | 1935 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], |
1936 | ERR_PTR(-ENOENT)); | 1936 | ERR_PTR(-ENOENT)); |
1937 | mutex_unlock(&mvm->mutex); | 1937 | mutex_unlock(&mvm->mutex); |
1938 | } | 1938 | } |
1939 | 1939 | ||
1940 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 1940 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
1941 | { | 1941 | { |
1942 | struct ieee80211_sta *sta; | 1942 | struct ieee80211_sta *sta; |
1943 | struct iwl_mvm_sta *mvmsta; | 1943 | struct iwl_mvm_sta *mvmsta; |
1944 | int count = 0; | 1944 | int count = 0; |
1945 | int i; | 1945 | int i; |
1946 | 1946 | ||
1947 | lockdep_assert_held(&mvm->mutex); | 1947 | lockdep_assert_held(&mvm->mutex); |
1948 | 1948 | ||
1949 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | 1949 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { |
1950 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | 1950 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], |
1951 | lockdep_is_held(&mvm->mutex)); | 1951 | lockdep_is_held(&mvm->mutex)); |
1952 | if (!sta || IS_ERR(sta) || !sta->tdls) | 1952 | if (!sta || IS_ERR(sta) || !sta->tdls) |
1953 | continue; | 1953 | continue; |
1954 | 1954 | ||
1955 | if (vif) { | 1955 | if (vif) { |
1956 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1956 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1957 | if (mvmsta->vif != vif) | 1957 | if (mvmsta->vif != vif) |
1958 | continue; | 1958 | continue; |
1959 | } | 1959 | } |
1960 | 1960 | ||
1961 | count++; | 1961 | count++; |
1962 | } | 1962 | } |
1963 | 1963 | ||
1964 | return count; | 1964 | return count; |
1965 | } | 1965 | } |
1966 | 1966 | ||
1967 | static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, | 1967 | static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, |
1968 | struct ieee80211_vif *vif, | 1968 | struct ieee80211_vif *vif, |
1969 | bool sta_added) | 1969 | bool sta_added) |
1970 | { | 1970 | { |
1971 | int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); | 1971 | int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); |
1972 | 1972 | ||
1973 | /* | 1973 | /* |
1974 | * Disable ps when the first TDLS sta is added and re-enable it | 1974 | * Disable ps when the first TDLS sta is added and re-enable it |
1975 | * when the last TDLS sta is removed | 1975 | * when the last TDLS sta is removed |
1976 | */ | 1976 | */ |
1977 | if ((tdls_sta_cnt == 1 && sta_added) || | 1977 | if ((tdls_sta_cnt == 1 && sta_added) || |
1978 | (tdls_sta_cnt == 0 && !sta_added)) | 1978 | (tdls_sta_cnt == 0 && !sta_added)) |
1979 | iwl_mvm_power_update_mac(mvm); | 1979 | iwl_mvm_power_update_mac(mvm); |
1980 | } | 1980 | } |
1981 | 1981 | ||
1982 | static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | 1982 | static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, |
1983 | struct ieee80211_vif *vif, | 1983 | struct ieee80211_vif *vif, |
1984 | struct ieee80211_sta *sta, | 1984 | struct ieee80211_sta *sta, |
1985 | enum ieee80211_sta_state old_state, | 1985 | enum ieee80211_sta_state old_state, |
1986 | enum ieee80211_sta_state new_state) | 1986 | enum ieee80211_sta_state new_state) |
1987 | { | 1987 | { |
1988 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1988 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1989 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1989 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1990 | int ret; | 1990 | int ret; |
1991 | 1991 | ||
1992 | IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n", | 1992 | IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n", |
1993 | sta->addr, old_state, new_state); | 1993 | sta->addr, old_state, new_state); |
1994 | 1994 | ||
1995 | /* this would be a mac80211 bug ... but don't crash */ | 1995 | /* this would be a mac80211 bug ... but don't crash */ |
1996 | if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) | 1996 | if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) |
1997 | return -EINVAL; | 1997 | return -EINVAL; |
1998 | 1998 | ||
1999 | /* if a STA is being removed, reuse its ID */ | 1999 | /* if a STA is being removed, reuse its ID */ |
2000 | flush_work(&mvm->sta_drained_wk); | 2000 | flush_work(&mvm->sta_drained_wk); |
2001 | 2001 | ||
2002 | mutex_lock(&mvm->mutex); | 2002 | mutex_lock(&mvm->mutex); |
2003 | if (old_state == IEEE80211_STA_NOTEXIST && | 2003 | if (old_state == IEEE80211_STA_NOTEXIST && |
2004 | new_state == IEEE80211_STA_NONE) { | 2004 | new_state == IEEE80211_STA_NONE) { |
2005 | /* | 2005 | /* |
2006 | * Firmware bug - it'll crash if the beacon interval is less | 2006 | * Firmware bug - it'll crash if the beacon interval is less |
2007 | * than 16. We can't avoid connecting at all, so refuse the | 2007 | * than 16. We can't avoid connecting at all, so refuse the |
2008 | * station state change, this will cause mac80211 to abandon | 2008 | * station state change, this will cause mac80211 to abandon |
2009 | * attempts to connect to this AP, and eventually wpa_s will | 2009 | * attempts to connect to this AP, and eventually wpa_s will |
2010 | * blacklist the AP... | 2010 | * blacklist the AP... |
2011 | */ | 2011 | */ |
2012 | if (vif->type == NL80211_IFTYPE_STATION && | 2012 | if (vif->type == NL80211_IFTYPE_STATION && |
2013 | vif->bss_conf.beacon_int < 16) { | 2013 | vif->bss_conf.beacon_int < 16) { |
2014 | IWL_ERR(mvm, | 2014 | IWL_ERR(mvm, |
2015 | "AP %pM beacon interval is %d, refusing due to firmware bug!\n", | 2015 | "AP %pM beacon interval is %d, refusing due to firmware bug!\n", |
2016 | sta->addr, vif->bss_conf.beacon_int); | 2016 | sta->addr, vif->bss_conf.beacon_int); |
2017 | ret = -EINVAL; | 2017 | ret = -EINVAL; |
2018 | goto out_unlock; | 2018 | goto out_unlock; |
2019 | } | 2019 | } |
2020 | 2020 | ||
2021 | if (sta->tdls && | 2021 | if (sta->tdls && |
2022 | (vif->p2p || | 2022 | (vif->p2p || |
2023 | iwl_mvm_tdls_sta_count(mvm, NULL) == | 2023 | iwl_mvm_tdls_sta_count(mvm, NULL) == |
2024 | IWL_MVM_TDLS_STA_COUNT || | 2024 | IWL_MVM_TDLS_STA_COUNT || |
2025 | iwl_mvm_phy_ctx_count(mvm) > 1)) { | 2025 | iwl_mvm_phy_ctx_count(mvm) > 1)) { |
2026 | IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n"); | 2026 | IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n"); |
2027 | ret = -EBUSY; | 2027 | ret = -EBUSY; |
2028 | goto out_unlock; | 2028 | goto out_unlock; |
2029 | } | 2029 | } |
2030 | 2030 | ||
2031 | ret = iwl_mvm_add_sta(mvm, vif, sta); | 2031 | ret = iwl_mvm_add_sta(mvm, vif, sta); |
2032 | if (sta->tdls && ret == 0) | 2032 | if (sta->tdls && ret == 0) |
2033 | iwl_mvm_recalc_tdls_state(mvm, vif, true); | 2033 | iwl_mvm_recalc_tdls_state(mvm, vif, true); |
2034 | } else if (old_state == IEEE80211_STA_NONE && | 2034 | } else if (old_state == IEEE80211_STA_NONE && |
2035 | new_state == IEEE80211_STA_AUTH) { | 2035 | new_state == IEEE80211_STA_AUTH) { |
2036 | /* | 2036 | /* |
2037 | * EBS may be disabled due to previous failures reported by FW. | 2037 | * EBS may be disabled due to previous failures reported by FW. |
2038 | * Reset EBS status here assuming environment has been changed. | 2038 | * Reset EBS status here assuming environment has been changed. |
2039 | */ | 2039 | */ |
2040 | mvm->last_ebs_successful = true; | 2040 | mvm->last_ebs_successful = true; |
2041 | ret = 0; | 2041 | ret = 0; |
2042 | } else if (old_state == IEEE80211_STA_AUTH && | 2042 | } else if (old_state == IEEE80211_STA_AUTH && |
2043 | new_state == IEEE80211_STA_ASSOC) { | 2043 | new_state == IEEE80211_STA_ASSOC) { |
2044 | ret = iwl_mvm_update_sta(mvm, vif, sta); | 2044 | ret = iwl_mvm_update_sta(mvm, vif, sta); |
2045 | if (ret == 0) | 2045 | if (ret == 0) |
2046 | iwl_mvm_rs_rate_init(mvm, sta, | 2046 | iwl_mvm_rs_rate_init(mvm, sta, |
2047 | mvmvif->phy_ctxt->channel->band, | 2047 | mvmvif->phy_ctxt->channel->band, |
2048 | true); | 2048 | true); |
2049 | } else if (old_state == IEEE80211_STA_ASSOC && | 2049 | } else if (old_state == IEEE80211_STA_ASSOC && |
2050 | new_state == IEEE80211_STA_AUTHORIZED) { | 2050 | new_state == IEEE80211_STA_AUTHORIZED) { |
2051 | 2051 | ||
2052 | /* we don't support TDLS during DCM */ | 2052 | /* we don't support TDLS during DCM */ |
2053 | if (iwl_mvm_phy_ctx_count(mvm) > 1) | 2053 | if (iwl_mvm_phy_ctx_count(mvm) > 1) |
2054 | iwl_mvm_teardown_tdls_peers(mvm); | 2054 | iwl_mvm_teardown_tdls_peers(mvm); |
2055 | 2055 | ||
2056 | /* enable beacon filtering */ | 2056 | /* enable beacon filtering */ |
2057 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); | 2057 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); |
2058 | ret = 0; | 2058 | ret = 0; |
2059 | } else if (old_state == IEEE80211_STA_AUTHORIZED && | 2059 | } else if (old_state == IEEE80211_STA_AUTHORIZED && |
2060 | new_state == IEEE80211_STA_ASSOC) { | 2060 | new_state == IEEE80211_STA_ASSOC) { |
2061 | /* disable beacon filtering */ | 2061 | /* disable beacon filtering */ |
2062 | WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, 0)); | 2062 | WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, 0)); |
2063 | ret = 0; | 2063 | ret = 0; |
2064 | } else if (old_state == IEEE80211_STA_ASSOC && | 2064 | } else if (old_state == IEEE80211_STA_ASSOC && |
2065 | new_state == IEEE80211_STA_AUTH) { | 2065 | new_state == IEEE80211_STA_AUTH) { |
2066 | ret = 0; | 2066 | ret = 0; |
2067 | } else if (old_state == IEEE80211_STA_AUTH && | 2067 | } else if (old_state == IEEE80211_STA_AUTH && |
2068 | new_state == IEEE80211_STA_NONE) { | 2068 | new_state == IEEE80211_STA_NONE) { |
2069 | ret = 0; | 2069 | ret = 0; |
2070 | } else if (old_state == IEEE80211_STA_NONE && | 2070 | } else if (old_state == IEEE80211_STA_NONE && |
2071 | new_state == IEEE80211_STA_NOTEXIST) { | 2071 | new_state == IEEE80211_STA_NOTEXIST) { |
2072 | ret = iwl_mvm_rm_sta(mvm, vif, sta); | 2072 | ret = iwl_mvm_rm_sta(mvm, vif, sta); |
2073 | if (sta->tdls) | 2073 | if (sta->tdls) |
2074 | iwl_mvm_recalc_tdls_state(mvm, vif, false); | 2074 | iwl_mvm_recalc_tdls_state(mvm, vif, false); |
2075 | } else { | 2075 | } else { |
2076 | ret = -EIO; | 2076 | ret = -EIO; |
2077 | } | 2077 | } |
2078 | out_unlock: | 2078 | out_unlock: |
2079 | mutex_unlock(&mvm->mutex); | 2079 | mutex_unlock(&mvm->mutex); |
2080 | 2080 | ||
2081 | return ret; | 2081 | return ret; |
2082 | } | 2082 | } |
2083 | 2083 | ||
2084 | static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | 2084 | static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) |
2085 | { | 2085 | { |
2086 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2086 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2087 | 2087 | ||
2088 | mvm->rts_threshold = value; | 2088 | mvm->rts_threshold = value; |
2089 | 2089 | ||
2090 | return 0; | 2090 | return 0; |
2091 | } | 2091 | } |
2092 | 2092 | ||
2093 | static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, | 2093 | static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, |
2094 | struct ieee80211_vif *vif, | 2094 | struct ieee80211_vif *vif, |
2095 | struct ieee80211_sta *sta, u32 changed) | 2095 | struct ieee80211_sta *sta, u32 changed) |
2096 | { | 2096 | { |
2097 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2097 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2098 | 2098 | ||
2099 | if (vif->type == NL80211_IFTYPE_STATION && | 2099 | if (vif->type == NL80211_IFTYPE_STATION && |
2100 | changed & IEEE80211_RC_NSS_CHANGED) | 2100 | changed & IEEE80211_RC_NSS_CHANGED) |
2101 | iwl_mvm_sf_update(mvm, vif, false); | 2101 | iwl_mvm_sf_update(mvm, vif, false); |
2102 | } | 2102 | } |
2103 | 2103 | ||
2104 | static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, | 2104 | static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, |
2105 | struct ieee80211_vif *vif, u16 ac, | 2105 | struct ieee80211_vif *vif, u16 ac, |
2106 | const struct ieee80211_tx_queue_params *params) | 2106 | const struct ieee80211_tx_queue_params *params) |
2107 | { | 2107 | { |
2108 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2108 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2109 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 2109 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
2110 | 2110 | ||
2111 | mvmvif->queue_params[ac] = *params; | 2111 | mvmvif->queue_params[ac] = *params; |
2112 | 2112 | ||
2113 | /* | 2113 | /* |
2114 | * No need to update right away, we'll get BSS_CHANGED_QOS | 2114 | * No need to update right away, we'll get BSS_CHANGED_QOS |
2115 | * The exception is P2P_DEVICE interface which needs immediate update. | 2115 | * The exception is P2P_DEVICE interface which needs immediate update. |
2116 | */ | 2116 | */ |
2117 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 2117 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
2118 | int ret; | 2118 | int ret; |
2119 | 2119 | ||
2120 | mutex_lock(&mvm->mutex); | 2120 | mutex_lock(&mvm->mutex); |
2121 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); | 2121 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); |
2122 | mutex_unlock(&mvm->mutex); | 2122 | mutex_unlock(&mvm->mutex); |
2123 | return ret; | 2123 | return ret; |
2124 | } | 2124 | } |
2125 | return 0; | 2125 | return 0; |
2126 | } | 2126 | } |
2127 | 2127 | ||
2128 | static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, | 2128 | static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, |
2129 | struct ieee80211_vif *vif) | 2129 | struct ieee80211_vif *vif) |
2130 | { | 2130 | { |
2131 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2131 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2132 | u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS, | 2132 | u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS, |
2133 | 200 + vif->bss_conf.beacon_int); | 2133 | 200 + vif->bss_conf.beacon_int); |
2134 | u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS, | 2134 | u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS, |
2135 | 100 + vif->bss_conf.beacon_int); | 2135 | 100 + vif->bss_conf.beacon_int); |
2136 | 2136 | ||
2137 | if (WARN_ON_ONCE(vif->bss_conf.assoc)) | 2137 | if (WARN_ON_ONCE(vif->bss_conf.assoc)) |
2138 | return; | 2138 | return; |
2139 | 2139 | ||
2140 | /* | 2140 | /* |
2141 | * iwl_mvm_protect_session() reads directly from the device | 2141 | * iwl_mvm_protect_session() reads directly from the device |
2142 | * (the system time), so make sure it is available. | 2142 | * (the system time), so make sure it is available. |
2143 | */ | 2143 | */ |
2144 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX)) | 2144 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX)) |
2145 | return; | 2145 | return; |
2146 | 2146 | ||
2147 | mutex_lock(&mvm->mutex); | 2147 | mutex_lock(&mvm->mutex); |
2148 | /* Try really hard to protect the session and hear a beacon */ | 2148 | /* Try really hard to protect the session and hear a beacon */ |
2149 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); | 2149 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); |
2150 | mutex_unlock(&mvm->mutex); | 2150 | mutex_unlock(&mvm->mutex); |
2151 | 2151 | ||
2152 | iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); | 2152 | iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); |
2153 | } | 2153 | } |
2154 | 2154 | ||
2155 | static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | 2155 | static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, |
2156 | struct ieee80211_vif *vif) | 2156 | struct ieee80211_vif *vif) |
2157 | { | 2157 | { |
2158 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2158 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2159 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; | 2159 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; |
2160 | 2160 | ||
2161 | /* | 2161 | /* |
2162 | * iwl_mvm_protect_session() reads directly from the device | 2162 | * iwl_mvm_protect_session() reads directly from the device |
2163 | * (the system time), so make sure it is available. | 2163 | * (the system time), so make sure it is available. |
2164 | */ | 2164 | */ |
2165 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) | 2165 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) |
2166 | return; | 2166 | return; |
2167 | 2167 | ||
2168 | mutex_lock(&mvm->mutex); | 2168 | mutex_lock(&mvm->mutex); |
2169 | /* Protect the session to hear the TDLS setup response on the channel */ | 2169 | /* Protect the session to hear the TDLS setup response on the channel */ |
2170 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100); | 2170 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100); |
2171 | mutex_unlock(&mvm->mutex); | 2171 | mutex_unlock(&mvm->mutex); |
2172 | 2172 | ||
2173 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); | 2173 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); |
2174 | } | 2174 | } |
2175 | 2175 | ||
2176 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | 2176 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, |
2177 | struct ieee80211_vif *vif, | 2177 | struct ieee80211_vif *vif, |
2178 | struct cfg80211_sched_scan_request *req, | 2178 | struct cfg80211_sched_scan_request *req, |
2179 | struct ieee80211_scan_ies *ies) | 2179 | struct ieee80211_scan_ies *ies) |
2180 | { | 2180 | { |
2181 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2181 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2182 | int ret; | 2182 | int ret; |
2183 | 2183 | ||
2184 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); | 2184 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); |
2185 | if (ret) | 2185 | if (ret) |
2186 | return ret; | 2186 | return ret; |
2187 | 2187 | ||
2188 | mutex_lock(&mvm->mutex); | 2188 | mutex_lock(&mvm->mutex); |
2189 | 2189 | ||
2190 | if (!iwl_mvm_is_idle(mvm)) { | 2190 | if (!iwl_mvm_is_idle(mvm)) { |
2191 | ret = -EBUSY; | 2191 | ret = -EBUSY; |
2192 | goto out; | 2192 | goto out; |
2193 | } | 2193 | } |
2194 | 2194 | ||
2195 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { | 2195 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { |
2196 | ret = -EBUSY; | 2196 | ret = -EBUSY; |
2197 | goto out; | 2197 | goto out; |
2198 | } | 2198 | } |
2199 | 2199 | ||
2200 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | 2200 | mvm->scan_status = IWL_MVM_SCAN_SCHED; |
2201 | 2201 | ||
2202 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | 2202 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { |
2203 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); | 2203 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); |
2204 | if (ret) | 2204 | if (ret) |
2205 | goto err; | 2205 | goto err; |
2206 | } | 2206 | } |
2207 | 2207 | ||
2208 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | 2208 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); |
2209 | if (ret) | 2209 | if (ret) |
2210 | goto err; | 2210 | goto err; |
2211 | 2211 | ||
2212 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 2212 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) |
2213 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); | 2213 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); |
2214 | else | 2214 | else |
2215 | ret = iwl_mvm_sched_scan_start(mvm, req); | 2215 | ret = iwl_mvm_sched_scan_start(mvm, req); |
2216 | 2216 | ||
2217 | if (!ret) | 2217 | if (!ret) |
2218 | goto out; | 2218 | goto out; |
2219 | err: | 2219 | err: |
2220 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 2220 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
2221 | out: | 2221 | out: |
2222 | mutex_unlock(&mvm->mutex); | 2222 | mutex_unlock(&mvm->mutex); |
2223 | return ret; | 2223 | return ret; |
2224 | } | 2224 | } |
2225 | 2225 | ||
2226 | static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | 2226 | static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, |
2227 | struct ieee80211_vif *vif) | 2227 | struct ieee80211_vif *vif) |
2228 | { | 2228 | { |
2229 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2229 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2230 | int ret; | 2230 | int ret; |
2231 | 2231 | ||
2232 | mutex_lock(&mvm->mutex); | 2232 | mutex_lock(&mvm->mutex); |
2233 | ret = iwl_mvm_scan_offload_stop(mvm, false); | 2233 | ret = iwl_mvm_scan_offload_stop(mvm, false); |
2234 | mutex_unlock(&mvm->mutex); | 2234 | mutex_unlock(&mvm->mutex); |
2235 | iwl_mvm_wait_for_async_handlers(mvm); | 2235 | iwl_mvm_wait_for_async_handlers(mvm); |
2236 | 2236 | ||
2237 | return ret; | 2237 | return ret; |
2238 | } | 2238 | } |
2239 | 2239 | ||
2240 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | 2240 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, |
2241 | enum set_key_cmd cmd, | 2241 | enum set_key_cmd cmd, |
2242 | struct ieee80211_vif *vif, | 2242 | struct ieee80211_vif *vif, |
2243 | struct ieee80211_sta *sta, | 2243 | struct ieee80211_sta *sta, |
2244 | struct ieee80211_key_conf *key) | 2244 | struct ieee80211_key_conf *key) |
2245 | { | 2245 | { |
2246 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2246 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2247 | int ret; | 2247 | int ret; |
2248 | 2248 | ||
2249 | if (iwlwifi_mod_params.sw_crypto) { | 2249 | if (iwlwifi_mod_params.sw_crypto) { |
2250 | IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); | 2250 | IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); |
2251 | return -EOPNOTSUPP; | 2251 | return -EOPNOTSUPP; |
2252 | } | 2252 | } |
2253 | 2253 | ||
2254 | switch (key->cipher) { | 2254 | switch (key->cipher) { |
2255 | case WLAN_CIPHER_SUITE_TKIP: | 2255 | case WLAN_CIPHER_SUITE_TKIP: |
2256 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 2256 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
2257 | /* fall-through */ | 2257 | /* fall-through */ |
2258 | case WLAN_CIPHER_SUITE_CCMP: | 2258 | case WLAN_CIPHER_SUITE_CCMP: |
2259 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 2259 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
2260 | break; | 2260 | break; |
2261 | case WLAN_CIPHER_SUITE_AES_CMAC: | 2261 | case WLAN_CIPHER_SUITE_AES_CMAC: |
2262 | WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE)); | 2262 | WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE)); |
2263 | break; | 2263 | break; |
2264 | case WLAN_CIPHER_SUITE_WEP40: | 2264 | case WLAN_CIPHER_SUITE_WEP40: |
2265 | case WLAN_CIPHER_SUITE_WEP104: | 2265 | case WLAN_CIPHER_SUITE_WEP104: |
2266 | /* | 2266 | /* |
2267 | * Support for TX only, at least for now, so accept | 2267 | * Support for TX only, at least for now, so accept |
2268 | * the key and do nothing else. Then mac80211 will | 2268 | * the key and do nothing else. Then mac80211 will |
2269 | * pass it for TX but we don't have to use it for RX. | 2269 | * pass it for TX but we don't have to use it for RX. |
2270 | */ | 2270 | */ |
2271 | return 0; | 2271 | return 0; |
2272 | default: | 2272 | default: |
2273 | /* currently FW supports only one optional cipher scheme */ | 2273 | /* currently FW supports only one optional cipher scheme */ |
2274 | if (hw->n_cipher_schemes && | 2274 | if (hw->n_cipher_schemes && |
2275 | hw->cipher_schemes->cipher == key->cipher) | 2275 | hw->cipher_schemes->cipher == key->cipher) |
2276 | key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; | 2276 | key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; |
2277 | else | 2277 | else |
2278 | return -EOPNOTSUPP; | 2278 | return -EOPNOTSUPP; |
2279 | } | 2279 | } |
2280 | 2280 | ||
2281 | mutex_lock(&mvm->mutex); | 2281 | mutex_lock(&mvm->mutex); |
2282 | 2282 | ||
2283 | switch (cmd) { | 2283 | switch (cmd) { |
2284 | case SET_KEY: | 2284 | case SET_KEY: |
2285 | if ((vif->type == NL80211_IFTYPE_ADHOC || | 2285 | if ((vif->type == NL80211_IFTYPE_ADHOC || |
2286 | vif->type == NL80211_IFTYPE_AP) && !sta) { | 2286 | vif->type == NL80211_IFTYPE_AP) && !sta) { |
2287 | /* | 2287 | /* |
2288 | * GTK on AP interface is a TX-only key, return 0; | 2288 | * GTK on AP interface is a TX-only key, return 0; |
2289 | * on IBSS they're per-station and because we're lazy | 2289 | * on IBSS they're per-station and because we're lazy |
2290 | * we don't support them for RX, so do the same. | 2290 | * we don't support them for RX, so do the same. |
2291 | */ | 2291 | */ |
2292 | ret = 0; | 2292 | ret = 0; |
2293 | key->hw_key_idx = STA_KEY_IDX_INVALID; | 2293 | key->hw_key_idx = STA_KEY_IDX_INVALID; |
2294 | break; | 2294 | break; |
2295 | } | 2295 | } |
2296 | 2296 | ||
2297 | IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); | 2297 | IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); |
2298 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false); | 2298 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false); |
2299 | if (ret) { | 2299 | if (ret) { |
2300 | IWL_WARN(mvm, "set key failed\n"); | 2300 | IWL_WARN(mvm, "set key failed\n"); |
2301 | /* | 2301 | /* |
2302 | * can't add key for RX, but we don't need it | 2302 | * can't add key for RX, but we don't need it |
2303 | * in the device for TX so still return 0 | 2303 | * in the device for TX so still return 0 |
2304 | */ | 2304 | */ |
2305 | key->hw_key_idx = STA_KEY_IDX_INVALID; | 2305 | key->hw_key_idx = STA_KEY_IDX_INVALID; |
2306 | ret = 0; | 2306 | ret = 0; |
2307 | } | 2307 | } |
2308 | 2308 | ||
2309 | break; | 2309 | break; |
2310 | case DISABLE_KEY: | 2310 | case DISABLE_KEY: |
2311 | if (key->hw_key_idx == STA_KEY_IDX_INVALID) { | 2311 | if (key->hw_key_idx == STA_KEY_IDX_INVALID) { |
2312 | ret = 0; | 2312 | ret = 0; |
2313 | break; | 2313 | break; |
2314 | } | 2314 | } |
2315 | 2315 | ||
2316 | IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); | 2316 | IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); |
2317 | ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); | 2317 | ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); |
2318 | break; | 2318 | break; |
2319 | default: | 2319 | default: |
2320 | ret = -EINVAL; | 2320 | ret = -EINVAL; |
2321 | } | 2321 | } |
2322 | 2322 | ||
2323 | mutex_unlock(&mvm->mutex); | 2323 | mutex_unlock(&mvm->mutex); |
2324 | return ret; | 2324 | return ret; |
2325 | } | 2325 | } |
2326 | 2326 | ||
2327 | static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, | 2327 | static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, |
2328 | struct ieee80211_vif *vif, | 2328 | struct ieee80211_vif *vif, |
2329 | struct ieee80211_key_conf *keyconf, | 2329 | struct ieee80211_key_conf *keyconf, |
2330 | struct ieee80211_sta *sta, | 2330 | struct ieee80211_sta *sta, |
2331 | u32 iv32, u16 *phase1key) | 2331 | u32 iv32, u16 *phase1key) |
2332 | { | 2332 | { |
2333 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2333 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2334 | 2334 | ||
2335 | if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) | 2335 | if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) |
2336 | return; | 2336 | return; |
2337 | 2337 | ||
2338 | iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key); | 2338 | iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key); |
2339 | } | 2339 | } |
2340 | 2340 | ||
2341 | 2341 | ||
2342 | static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait, | 2342 | static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait, |
2343 | struct iwl_rx_packet *pkt, void *data) | 2343 | struct iwl_rx_packet *pkt, void *data) |
2344 | { | 2344 | { |
2345 | struct iwl_mvm *mvm = | 2345 | struct iwl_mvm *mvm = |
2346 | container_of(notif_wait, struct iwl_mvm, notif_wait); | 2346 | container_of(notif_wait, struct iwl_mvm, notif_wait); |
2347 | struct iwl_hs20_roc_res *resp; | 2347 | struct iwl_hs20_roc_res *resp; |
2348 | int resp_len = iwl_rx_packet_payload_len(pkt); | 2348 | int resp_len = iwl_rx_packet_payload_len(pkt); |
2349 | struct iwl_mvm_time_event_data *te_data = data; | 2349 | struct iwl_mvm_time_event_data *te_data = data; |
2350 | 2350 | ||
2351 | if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD)) | 2351 | if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD)) |
2352 | return true; | 2352 | return true; |
2353 | 2353 | ||
2354 | if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { | 2354 | if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { |
2355 | IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n"); | 2355 | IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n"); |
2356 | return true; | 2356 | return true; |
2357 | } | 2357 | } |
2358 | 2358 | ||
2359 | resp = (void *)pkt->data; | 2359 | resp = (void *)pkt->data; |
2360 | 2360 | ||
2361 | IWL_DEBUG_TE(mvm, | 2361 | IWL_DEBUG_TE(mvm, |
2362 | "Aux ROC: Recieved response from ucode: status=%d uid=%d\n", | 2362 | "Aux ROC: Recieved response from ucode: status=%d uid=%d\n", |
2363 | resp->status, resp->event_unique_id); | 2363 | resp->status, resp->event_unique_id); |
2364 | 2364 | ||
2365 | te_data->uid = le32_to_cpu(resp->event_unique_id); | 2365 | te_data->uid = le32_to_cpu(resp->event_unique_id); |
2366 | IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n", | 2366 | IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n", |
2367 | te_data->uid); | 2367 | te_data->uid); |
2368 | 2368 | ||
2369 | spin_lock_bh(&mvm->time_event_lock); | 2369 | spin_lock_bh(&mvm->time_event_lock); |
2370 | list_add_tail(&te_data->list, &mvm->aux_roc_te_list); | 2370 | list_add_tail(&te_data->list, &mvm->aux_roc_te_list); |
2371 | spin_unlock_bh(&mvm->time_event_lock); | 2371 | spin_unlock_bh(&mvm->time_event_lock); |
2372 | 2372 | ||
2373 | return true; | 2373 | return true; |
2374 | } | 2374 | } |
2375 | 2375 | ||
2376 | #define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000 | 2376 | #define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000 |
2377 | static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, | 2377 | static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, |
2378 | struct ieee80211_channel *channel, | 2378 | struct ieee80211_channel *channel, |
2379 | struct ieee80211_vif *vif, | 2379 | struct ieee80211_vif *vif, |
2380 | int duration) | 2380 | int duration) |
2381 | { | 2381 | { |
2382 | int res, time_reg = DEVICE_SYSTEM_TIME_REG; | 2382 | int res, time_reg = DEVICE_SYSTEM_TIME_REG; |
2383 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 2383 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
2384 | struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data; | 2384 | struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data; |
2385 | static const u8 time_event_response[] = { HOT_SPOT_CMD }; | 2385 | static const u8 time_event_response[] = { HOT_SPOT_CMD }; |
2386 | struct iwl_notification_wait wait_time_event; | 2386 | struct iwl_notification_wait wait_time_event; |
2387 | struct iwl_hs20_roc_req aux_roc_req = { | 2387 | struct iwl_hs20_roc_req aux_roc_req = { |
2388 | .action = cpu_to_le32(FW_CTXT_ACTION_ADD), | 2388 | .action = cpu_to_le32(FW_CTXT_ACTION_ADD), |
2389 | .id_and_color = | 2389 | .id_and_color = |
2390 | cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)), | 2390 | cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)), |
2391 | .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id), | 2391 | .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id), |
2392 | /* Set the channel info data */ | 2392 | /* Set the channel info data */ |
2393 | .channel_info.band = (channel->band == IEEE80211_BAND_2GHZ) ? | 2393 | .channel_info.band = (channel->band == IEEE80211_BAND_2GHZ) ? |
2394 | PHY_BAND_24 : PHY_BAND_5, | 2394 | PHY_BAND_24 : PHY_BAND_5, |
2395 | .channel_info.channel = channel->hw_value, | 2395 | .channel_info.channel = channel->hw_value, |
2396 | .channel_info.width = PHY_VHT_CHANNEL_MODE20, | 2396 | .channel_info.width = PHY_VHT_CHANNEL_MODE20, |
2397 | /* Set the time and duration */ | 2397 | /* Set the time and duration */ |
2398 | .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)), | 2398 | .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)), |
2399 | .apply_time_max_delay = | 2399 | .apply_time_max_delay = |
2400 | cpu_to_le32(MSEC_TO_TU(AUX_ROC_MAX_DELAY_ON_CHANNEL)), | 2400 | cpu_to_le32(MSEC_TO_TU(AUX_ROC_MAX_DELAY_ON_CHANNEL)), |
2401 | .duration = cpu_to_le32(MSEC_TO_TU(duration)), | 2401 | .duration = cpu_to_le32(MSEC_TO_TU(duration)), |
2402 | }; | 2402 | }; |
2403 | 2403 | ||
2404 | /* Set the node address */ | 2404 | /* Set the node address */ |
2405 | memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); | 2405 | memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); |
2406 | 2406 | ||
2407 | lockdep_assert_held(&mvm->mutex); | 2407 | lockdep_assert_held(&mvm->mutex); |
2408 | 2408 | ||
2409 | spin_lock_bh(&mvm->time_event_lock); | 2409 | spin_lock_bh(&mvm->time_event_lock); |
2410 | 2410 | ||
2411 | if (WARN_ON(te_data->id == HOT_SPOT_CMD)) { | 2411 | if (WARN_ON(te_data->id == HOT_SPOT_CMD)) { |
2412 | spin_unlock_bh(&mvm->time_event_lock); | 2412 | spin_unlock_bh(&mvm->time_event_lock); |
2413 | return -EIO; | 2413 | return -EIO; |
2414 | } | 2414 | } |
2415 | 2415 | ||
2416 | te_data->vif = vif; | 2416 | te_data->vif = vif; |
2417 | te_data->duration = duration; | 2417 | te_data->duration = duration; |
2418 | te_data->id = HOT_SPOT_CMD; | 2418 | te_data->id = HOT_SPOT_CMD; |
2419 | 2419 | ||
2420 | spin_unlock_bh(&mvm->time_event_lock); | 2420 | spin_unlock_bh(&mvm->time_event_lock); |
2421 | 2421 | ||
2422 | /* | 2422 | /* |
2423 | * Use a notification wait, which really just processes the | 2423 | * Use a notification wait, which really just processes the |
2424 | * command response and doesn't wait for anything, in order | 2424 | * command response and doesn't wait for anything, in order |
2425 | * to be able to process the response and get the UID inside | 2425 | * to be able to process the response and get the UID inside |
2426 | * the RX path. Using CMD_WANT_SKB doesn't work because it | 2426 | * the RX path. Using CMD_WANT_SKB doesn't work because it |
2427 | * stores the buffer and then wakes up this thread, by which | 2427 | * stores the buffer and then wakes up this thread, by which |
2428 | * time another notification (that the time event started) | 2428 | * time another notification (that the time event started) |
2429 | * might already be processed unsuccessfully. | 2429 | * might already be processed unsuccessfully. |
2430 | */ | 2430 | */ |
2431 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | 2431 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, |
2432 | time_event_response, | 2432 | time_event_response, |
2433 | ARRAY_SIZE(time_event_response), | 2433 | ARRAY_SIZE(time_event_response), |
2434 | iwl_mvm_rx_aux_roc, te_data); | 2434 | iwl_mvm_rx_aux_roc, te_data); |
2435 | 2435 | ||
2436 | res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req), | 2436 | res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req), |
2437 | &aux_roc_req); | 2437 | &aux_roc_req); |
2438 | 2438 | ||
2439 | if (res) { | 2439 | if (res) { |
2440 | IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res); | 2440 | IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res); |
2441 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | 2441 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); |
2442 | goto out_clear_te; | 2442 | goto out_clear_te; |
2443 | } | 2443 | } |
2444 | 2444 | ||
2445 | /* No need to wait for anything, so just pass 1 (0 isn't valid) */ | 2445 | /* No need to wait for anything, so just pass 1 (0 isn't valid) */ |
2446 | res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1); | 2446 | res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1); |
2447 | /* should never fail */ | 2447 | /* should never fail */ |
2448 | WARN_ON_ONCE(res); | 2448 | WARN_ON_ONCE(res); |
2449 | 2449 | ||
2450 | if (res) { | 2450 | if (res) { |
2451 | out_clear_te: | 2451 | out_clear_te: |
2452 | spin_lock_bh(&mvm->time_event_lock); | 2452 | spin_lock_bh(&mvm->time_event_lock); |
2453 | iwl_mvm_te_clear_data(mvm, te_data); | 2453 | iwl_mvm_te_clear_data(mvm, te_data); |
2454 | spin_unlock_bh(&mvm->time_event_lock); | 2454 | spin_unlock_bh(&mvm->time_event_lock); |
2455 | } | 2455 | } |
2456 | 2456 | ||
2457 | return res; | 2457 | return res; |
2458 | } | 2458 | } |
2459 | 2459 | ||
2460 | static int iwl_mvm_roc(struct ieee80211_hw *hw, | 2460 | static int iwl_mvm_roc(struct ieee80211_hw *hw, |
2461 | struct ieee80211_vif *vif, | 2461 | struct ieee80211_vif *vif, |
2462 | struct ieee80211_channel *channel, | 2462 | struct ieee80211_channel *channel, |
2463 | int duration, | 2463 | int duration, |
2464 | enum ieee80211_roc_type type) | 2464 | enum ieee80211_roc_type type) |
2465 | { | 2465 | { |
2466 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2466 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2467 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 2467 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
2468 | struct cfg80211_chan_def chandef; | 2468 | struct cfg80211_chan_def chandef; |
2469 | struct iwl_mvm_phy_ctxt *phy_ctxt; | 2469 | struct iwl_mvm_phy_ctxt *phy_ctxt; |
2470 | int ret, i; | 2470 | int ret, i; |
2471 | 2471 | ||
2472 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, | 2472 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, |
2473 | duration, type); | 2473 | duration, type); |
2474 | 2474 | ||
2475 | mutex_lock(&mvm->mutex); | 2475 | mutex_lock(&mvm->mutex); |
2476 | 2476 | ||
2477 | switch (vif->type) { | 2477 | switch (vif->type) { |
2478 | case NL80211_IFTYPE_STATION: | 2478 | case NL80211_IFTYPE_STATION: |
2479 | /* Use aux roc framework (HS20) */ | 2479 | if (mvm->fw->ucode_capa.capa[0] & |
2480 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | 2480 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) { |
2481 | vif, duration); | 2481 | /* Use aux roc framework (HS20) */ |
2482 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | ||
2483 | vif, duration); | ||
2484 | goto out_unlock; | ||
2485 | } | ||
2486 | IWL_ERR(mvm, "hotspot not supported\n"); | ||
2487 | ret = -EINVAL; | ||
2482 | goto out_unlock; | 2488 | goto out_unlock; |
2483 | case NL80211_IFTYPE_P2P_DEVICE: | 2489 | case NL80211_IFTYPE_P2P_DEVICE: |
2484 | /* handle below */ | 2490 | /* handle below */ |
2485 | break; | 2491 | break; |
2486 | default: | 2492 | default: |
2487 | IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type); | 2493 | IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type); |
2488 | ret = -EINVAL; | 2494 | ret = -EINVAL; |
2489 | goto out_unlock; | 2495 | goto out_unlock; |
2490 | } | 2496 | } |
2491 | 2497 | ||
2492 | for (i = 0; i < NUM_PHY_CTX; i++) { | 2498 | for (i = 0; i < NUM_PHY_CTX; i++) { |
2493 | phy_ctxt = &mvm->phy_ctxts[i]; | 2499 | phy_ctxt = &mvm->phy_ctxts[i]; |
2494 | if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt) | 2500 | if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt) |
2495 | continue; | 2501 | continue; |
2496 | 2502 | ||
2497 | if (phy_ctxt->ref && channel == phy_ctxt->channel) { | 2503 | if (phy_ctxt->ref && channel == phy_ctxt->channel) { |
2498 | /* | 2504 | /* |
2499 | * Unbind the P2P_DEVICE from the current PHY context, | 2505 | * Unbind the P2P_DEVICE from the current PHY context, |
2500 | * and if the PHY context is not used remove it. | 2506 | * and if the PHY context is not used remove it. |
2501 | */ | 2507 | */ |
2502 | ret = iwl_mvm_binding_remove_vif(mvm, vif); | 2508 | ret = iwl_mvm_binding_remove_vif(mvm, vif); |
2503 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) | 2509 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) |
2504 | goto out_unlock; | 2510 | goto out_unlock; |
2505 | 2511 | ||
2506 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | 2512 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
2507 | 2513 | ||
2508 | /* Bind the P2P_DEVICE to the current PHY Context */ | 2514 | /* Bind the P2P_DEVICE to the current PHY Context */ |
2509 | mvmvif->phy_ctxt = phy_ctxt; | 2515 | mvmvif->phy_ctxt = phy_ctxt; |
2510 | 2516 | ||
2511 | ret = iwl_mvm_binding_add_vif(mvm, vif); | 2517 | ret = iwl_mvm_binding_add_vif(mvm, vif); |
2512 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) | 2518 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) |
2513 | goto out_unlock; | 2519 | goto out_unlock; |
2514 | 2520 | ||
2515 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | 2521 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); |
2516 | goto schedule_time_event; | 2522 | goto schedule_time_event; |
2517 | } | 2523 | } |
2518 | } | 2524 | } |
2519 | 2525 | ||
2520 | /* Need to update the PHY context only if the ROC channel changed */ | 2526 | /* Need to update the PHY context only if the ROC channel changed */ |
2521 | if (channel == mvmvif->phy_ctxt->channel) | 2527 | if (channel == mvmvif->phy_ctxt->channel) |
2522 | goto schedule_time_event; | 2528 | goto schedule_time_event; |
2523 | 2529 | ||
2524 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); | 2530 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); |
2525 | 2531 | ||
2526 | /* | 2532 | /* |
2527 | * Change the PHY context configuration as it is currently referenced | 2533 | * Change the PHY context configuration as it is currently referenced |
2528 | * only by the P2P Device MAC | 2534 | * only by the P2P Device MAC |
2529 | */ | 2535 | */ |
2530 | if (mvmvif->phy_ctxt->ref == 1) { | 2536 | if (mvmvif->phy_ctxt->ref == 1) { |
2531 | ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt, | 2537 | ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt, |
2532 | &chandef, 1, 1); | 2538 | &chandef, 1, 1); |
2533 | if (ret) | 2539 | if (ret) |
2534 | goto out_unlock; | 2540 | goto out_unlock; |
2535 | } else { | 2541 | } else { |
2536 | /* | 2542 | /* |
2537 | * The PHY context is shared with other MACs. Need to remove the | 2543 | * The PHY context is shared with other MACs. Need to remove the |
2538 | * P2P Device from the binding, allocate an new PHY context and | 2544 | * P2P Device from the binding, allocate an new PHY context and |
2539 | * create a new binding | 2545 | * create a new binding |
2540 | */ | 2546 | */ |
2541 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | 2547 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); |
2542 | if (!phy_ctxt) { | 2548 | if (!phy_ctxt) { |
2543 | ret = -ENOSPC; | 2549 | ret = -ENOSPC; |
2544 | goto out_unlock; | 2550 | goto out_unlock; |
2545 | } | 2551 | } |
2546 | 2552 | ||
2547 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef, | 2553 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef, |
2548 | 1, 1); | 2554 | 1, 1); |
2549 | if (ret) { | 2555 | if (ret) { |
2550 | IWL_ERR(mvm, "Failed to change PHY context\n"); | 2556 | IWL_ERR(mvm, "Failed to change PHY context\n"); |
2551 | goto out_unlock; | 2557 | goto out_unlock; |
2552 | } | 2558 | } |
2553 | 2559 | ||
2554 | /* Unbind the P2P_DEVICE from the current PHY context */ | 2560 | /* Unbind the P2P_DEVICE from the current PHY context */ |
2555 | ret = iwl_mvm_binding_remove_vif(mvm, vif); | 2561 | ret = iwl_mvm_binding_remove_vif(mvm, vif); |
2556 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) | 2562 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) |
2557 | goto out_unlock; | 2563 | goto out_unlock; |
2558 | 2564 | ||
2559 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | 2565 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
2560 | 2566 | ||
2561 | /* Bind the P2P_DEVICE to the new allocated PHY context */ | 2567 | /* Bind the P2P_DEVICE to the new allocated PHY context */ |
2562 | mvmvif->phy_ctxt = phy_ctxt; | 2568 | mvmvif->phy_ctxt = phy_ctxt; |
2563 | 2569 | ||
2564 | ret = iwl_mvm_binding_add_vif(mvm, vif); | 2570 | ret = iwl_mvm_binding_add_vif(mvm, vif); |
2565 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) | 2571 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) |
2566 | goto out_unlock; | 2572 | goto out_unlock; |
2567 | 2573 | ||
2568 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | 2574 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); |
2569 | } | 2575 | } |
2570 | 2576 | ||
2571 | schedule_time_event: | 2577 | schedule_time_event: |
2572 | /* Schedule the time events */ | 2578 | /* Schedule the time events */ |
2573 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type); | 2579 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type); |
2574 | 2580 | ||
2575 | out_unlock: | 2581 | out_unlock: |
2576 | mutex_unlock(&mvm->mutex); | 2582 | mutex_unlock(&mvm->mutex); |
2577 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | 2583 | IWL_DEBUG_MAC80211(mvm, "leave\n"); |
2578 | return ret; | 2584 | return ret; |
2579 | } | 2585 | } |
2580 | 2586 | ||
2581 | static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) | 2587 | static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) |
2582 | { | 2588 | { |
2583 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2589 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2584 | 2590 | ||
2585 | IWL_DEBUG_MAC80211(mvm, "enter\n"); | 2591 | IWL_DEBUG_MAC80211(mvm, "enter\n"); |
2586 | 2592 | ||
2587 | mutex_lock(&mvm->mutex); | 2593 | mutex_lock(&mvm->mutex); |
2588 | iwl_mvm_stop_p2p_roc(mvm); | 2594 | iwl_mvm_stop_p2p_roc(mvm); |
2589 | mutex_unlock(&mvm->mutex); | 2595 | mutex_unlock(&mvm->mutex); |
2590 | 2596 | ||
2591 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | 2597 | IWL_DEBUG_MAC80211(mvm, "leave\n"); |
2592 | return 0; | 2598 | return 0; |
2593 | } | 2599 | } |
2594 | 2600 | ||
2595 | static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, | 2601 | static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, |
2596 | struct ieee80211_chanctx_conf *ctx) | 2602 | struct ieee80211_chanctx_conf *ctx) |
2597 | { | 2603 | { |
2598 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; | 2604 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
2599 | struct iwl_mvm_phy_ctxt *phy_ctxt; | 2605 | struct iwl_mvm_phy_ctxt *phy_ctxt; |
2600 | int ret; | 2606 | int ret; |
2601 | 2607 | ||
2602 | lockdep_assert_held(&mvm->mutex); | 2608 | lockdep_assert_held(&mvm->mutex); |
2603 | 2609 | ||
2604 | IWL_DEBUG_MAC80211(mvm, "Add channel context\n"); | 2610 | IWL_DEBUG_MAC80211(mvm, "Add channel context\n"); |
2605 | 2611 | ||
2606 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | 2612 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); |
2607 | if (!phy_ctxt) { | 2613 | if (!phy_ctxt) { |
2608 | ret = -ENOSPC; | 2614 | ret = -ENOSPC; |
2609 | goto out; | 2615 | goto out; |
2610 | } | 2616 | } |
2611 | 2617 | ||
2612 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def, | 2618 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def, |
2613 | ctx->rx_chains_static, | 2619 | ctx->rx_chains_static, |
2614 | ctx->rx_chains_dynamic); | 2620 | ctx->rx_chains_dynamic); |
2615 | if (ret) { | 2621 | if (ret) { |
2616 | IWL_ERR(mvm, "Failed to add PHY context\n"); | 2622 | IWL_ERR(mvm, "Failed to add PHY context\n"); |
2617 | goto out; | 2623 | goto out; |
2618 | } | 2624 | } |
2619 | 2625 | ||
2620 | iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt); | 2626 | iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt); |
2621 | *phy_ctxt_id = phy_ctxt->id; | 2627 | *phy_ctxt_id = phy_ctxt->id; |
2622 | out: | 2628 | out: |
2623 | return ret; | 2629 | return ret; |
2624 | } | 2630 | } |
2625 | 2631 | ||
2626 | static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, | 2632 | static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, |
2627 | struct ieee80211_chanctx_conf *ctx) | 2633 | struct ieee80211_chanctx_conf *ctx) |
2628 | { | 2634 | { |
2629 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2635 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2630 | int ret; | 2636 | int ret; |
2631 | 2637 | ||
2632 | mutex_lock(&mvm->mutex); | 2638 | mutex_lock(&mvm->mutex); |
2633 | ret = __iwl_mvm_add_chanctx(mvm, ctx); | 2639 | ret = __iwl_mvm_add_chanctx(mvm, ctx); |
2634 | mutex_unlock(&mvm->mutex); | 2640 | mutex_unlock(&mvm->mutex); |
2635 | 2641 | ||
2636 | return ret; | 2642 | return ret; |
2637 | } | 2643 | } |
2638 | 2644 | ||
2639 | static void __iwl_mvm_remove_chanctx(struct iwl_mvm *mvm, | 2645 | static void __iwl_mvm_remove_chanctx(struct iwl_mvm *mvm, |
2640 | struct ieee80211_chanctx_conf *ctx) | 2646 | struct ieee80211_chanctx_conf *ctx) |
2641 | { | 2647 | { |
2642 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; | 2648 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
2643 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | 2649 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; |
2644 | 2650 | ||
2645 | lockdep_assert_held(&mvm->mutex); | 2651 | lockdep_assert_held(&mvm->mutex); |
2646 | 2652 | ||
2647 | iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt); | 2653 | iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt); |
2648 | } | 2654 | } |
2649 | 2655 | ||
2650 | static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, | 2656 | static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, |
2651 | struct ieee80211_chanctx_conf *ctx) | 2657 | struct ieee80211_chanctx_conf *ctx) |
2652 | { | 2658 | { |
2653 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2659 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2654 | 2660 | ||
2655 | mutex_lock(&mvm->mutex); | 2661 | mutex_lock(&mvm->mutex); |
2656 | __iwl_mvm_remove_chanctx(mvm, ctx); | 2662 | __iwl_mvm_remove_chanctx(mvm, ctx); |
2657 | mutex_unlock(&mvm->mutex); | 2663 | mutex_unlock(&mvm->mutex); |
2658 | } | 2664 | } |
2659 | 2665 | ||
2660 | static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, | 2666 | static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, |
2661 | struct ieee80211_chanctx_conf *ctx, | 2667 | struct ieee80211_chanctx_conf *ctx, |
2662 | u32 changed) | 2668 | u32 changed) |
2663 | { | 2669 | { |
2664 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2670 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2665 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; | 2671 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
2666 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | 2672 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; |
2667 | 2673 | ||
2668 | if (WARN_ONCE((phy_ctxt->ref > 1) && | 2674 | if (WARN_ONCE((phy_ctxt->ref > 1) && |
2669 | (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | | 2675 | (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | |
2670 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS | | 2676 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS | |
2671 | IEEE80211_CHANCTX_CHANGE_RADAR | | 2677 | IEEE80211_CHANCTX_CHANGE_RADAR | |
2672 | IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)), | 2678 | IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)), |
2673 | "Cannot change PHY. Ref=%d, changed=0x%X\n", | 2679 | "Cannot change PHY. Ref=%d, changed=0x%X\n", |
2674 | phy_ctxt->ref, changed)) | 2680 | phy_ctxt->ref, changed)) |
2675 | return; | 2681 | return; |
2676 | 2682 | ||
2677 | mutex_lock(&mvm->mutex); | 2683 | mutex_lock(&mvm->mutex); |
2678 | iwl_mvm_bt_coex_vif_change(mvm); | 2684 | iwl_mvm_bt_coex_vif_change(mvm); |
2679 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def, | 2685 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def, |
2680 | ctx->rx_chains_static, | 2686 | ctx->rx_chains_static, |
2681 | ctx->rx_chains_dynamic); | 2687 | ctx->rx_chains_dynamic); |
2682 | mutex_unlock(&mvm->mutex); | 2688 | mutex_unlock(&mvm->mutex); |
2683 | } | 2689 | } |
2684 | 2690 | ||
2685 | static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | 2691 | static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, |
2686 | struct ieee80211_vif *vif, | 2692 | struct ieee80211_vif *vif, |
2687 | struct ieee80211_chanctx_conf *ctx, | 2693 | struct ieee80211_chanctx_conf *ctx, |
2688 | bool switching_chanctx) | 2694 | bool switching_chanctx) |
2689 | { | 2695 | { |
2690 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; | 2696 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
2691 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | 2697 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; |
2692 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 2698 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
2693 | int ret; | 2699 | int ret; |
2694 | 2700 | ||
2695 | lockdep_assert_held(&mvm->mutex); | 2701 | lockdep_assert_held(&mvm->mutex); |
2696 | 2702 | ||
2697 | mvmvif->phy_ctxt = phy_ctxt; | 2703 | mvmvif->phy_ctxt = phy_ctxt; |
2698 | 2704 | ||
2699 | switch (vif->type) { | 2705 | switch (vif->type) { |
2700 | case NL80211_IFTYPE_AP: | 2706 | case NL80211_IFTYPE_AP: |
2701 | /* Unless it's a CSA flow we have nothing to do here */ | 2707 | /* Unless it's a CSA flow we have nothing to do here */ |
2702 | if (vif->csa_active) { | 2708 | if (vif->csa_active) { |
2703 | mvmvif->ap_ibss_active = true; | 2709 | mvmvif->ap_ibss_active = true; |
2704 | break; | 2710 | break; |
2705 | } | 2711 | } |
2706 | case NL80211_IFTYPE_ADHOC: | 2712 | case NL80211_IFTYPE_ADHOC: |
2707 | /* | 2713 | /* |
2708 | * The AP binding flow is handled as part of the start_ap flow | 2714 | * The AP binding flow is handled as part of the start_ap flow |
2709 | * (in bss_info_changed), similarly for IBSS. | 2715 | * (in bss_info_changed), similarly for IBSS. |
2710 | */ | 2716 | */ |
2711 | ret = 0; | 2717 | ret = 0; |
2712 | goto out; | 2718 | goto out; |
2713 | case NL80211_IFTYPE_STATION: | 2719 | case NL80211_IFTYPE_STATION: |
2714 | case NL80211_IFTYPE_MONITOR: | 2720 | case NL80211_IFTYPE_MONITOR: |
2715 | break; | 2721 | break; |
2716 | default: | 2722 | default: |
2717 | ret = -EINVAL; | 2723 | ret = -EINVAL; |
2718 | goto out; | 2724 | goto out; |
2719 | } | 2725 | } |
2720 | 2726 | ||
2721 | ret = iwl_mvm_binding_add_vif(mvm, vif); | 2727 | ret = iwl_mvm_binding_add_vif(mvm, vif); |
2722 | if (ret) | 2728 | if (ret) |
2723 | goto out; | 2729 | goto out; |
2724 | 2730 | ||
2725 | /* | 2731 | /* |
2726 | * Power state must be updated before quotas, | 2732 | * Power state must be updated before quotas, |
2727 | * otherwise fw will complain. | 2733 | * otherwise fw will complain. |
2728 | */ | 2734 | */ |
2729 | iwl_mvm_power_update_mac(mvm); | 2735 | iwl_mvm_power_update_mac(mvm); |
2730 | 2736 | ||
2731 | /* Setting the quota at this stage is only required for monitor | 2737 | /* Setting the quota at this stage is only required for monitor |
2732 | * interfaces. For the other types, the bss_info changed flow | 2738 | * interfaces. For the other types, the bss_info changed flow |
2733 | * will handle quota settings. | 2739 | * will handle quota settings. |
2734 | */ | 2740 | */ |
2735 | if (vif->type == NL80211_IFTYPE_MONITOR) { | 2741 | if (vif->type == NL80211_IFTYPE_MONITOR) { |
2736 | mvmvif->monitor_active = true; | 2742 | mvmvif->monitor_active = true; |
2737 | ret = iwl_mvm_update_quotas(mvm, NULL); | 2743 | ret = iwl_mvm_update_quotas(mvm, NULL); |
2738 | if (ret) | 2744 | if (ret) |
2739 | goto out_remove_binding; | 2745 | goto out_remove_binding; |
2740 | } | 2746 | } |
2741 | 2747 | ||
2742 | /* Handle binding during CSA */ | 2748 | /* Handle binding during CSA */ |
2743 | if ((vif->type == NL80211_IFTYPE_AP) || | 2749 | if ((vif->type == NL80211_IFTYPE_AP) || |
2744 | (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) { | 2750 | (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) { |
2745 | iwl_mvm_update_quotas(mvm, NULL); | 2751 | iwl_mvm_update_quotas(mvm, NULL); |
2746 | iwl_mvm_mac_ctxt_changed(mvm, vif, false); | 2752 | iwl_mvm_mac_ctxt_changed(mvm, vif, false); |
2747 | } | 2753 | } |
2748 | 2754 | ||
2749 | goto out; | 2755 | goto out; |
2750 | 2756 | ||
2751 | out_remove_binding: | 2757 | out_remove_binding: |
2752 | iwl_mvm_binding_remove_vif(mvm, vif); | 2758 | iwl_mvm_binding_remove_vif(mvm, vif); |
2753 | iwl_mvm_power_update_mac(mvm); | 2759 | iwl_mvm_power_update_mac(mvm); |
2754 | out: | 2760 | out: |
2755 | if (ret) | 2761 | if (ret) |
2756 | mvmvif->phy_ctxt = NULL; | 2762 | mvmvif->phy_ctxt = NULL; |
2757 | return ret; | 2763 | return ret; |
2758 | } | 2764 | } |
2759 | static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | 2765 | static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, |
2760 | struct ieee80211_vif *vif, | 2766 | struct ieee80211_vif *vif, |
2761 | struct ieee80211_chanctx_conf *ctx) | 2767 | struct ieee80211_chanctx_conf *ctx) |
2762 | { | 2768 | { |
2763 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2769 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2764 | int ret; | 2770 | int ret; |
2765 | 2771 | ||
2766 | mutex_lock(&mvm->mutex); | 2772 | mutex_lock(&mvm->mutex); |
2767 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vif, ctx, false); | 2773 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vif, ctx, false); |
2768 | mutex_unlock(&mvm->mutex); | 2774 | mutex_unlock(&mvm->mutex); |
2769 | 2775 | ||
2770 | return ret; | 2776 | return ret; |
2771 | } | 2777 | } |
2772 | 2778 | ||
2773 | static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | 2779 | static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, |
2774 | struct ieee80211_vif *vif, | 2780 | struct ieee80211_vif *vif, |
2775 | struct ieee80211_chanctx_conf *ctx, | 2781 | struct ieee80211_chanctx_conf *ctx, |
2776 | bool switching_chanctx) | 2782 | bool switching_chanctx) |
2777 | { | 2783 | { |
2778 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 2784 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
2779 | struct ieee80211_vif *disabled_vif = NULL; | 2785 | struct ieee80211_vif *disabled_vif = NULL; |
2780 | 2786 | ||
2781 | lockdep_assert_held(&mvm->mutex); | 2787 | lockdep_assert_held(&mvm->mutex); |
2782 | 2788 | ||
2783 | iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); | 2789 | iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); |
2784 | 2790 | ||
2785 | switch (vif->type) { | 2791 | switch (vif->type) { |
2786 | case NL80211_IFTYPE_ADHOC: | 2792 | case NL80211_IFTYPE_ADHOC: |
2787 | goto out; | 2793 | goto out; |
2788 | case NL80211_IFTYPE_MONITOR: | 2794 | case NL80211_IFTYPE_MONITOR: |
2789 | mvmvif->monitor_active = false; | 2795 | mvmvif->monitor_active = false; |
2790 | break; | 2796 | break; |
2791 | case NL80211_IFTYPE_AP: | 2797 | case NL80211_IFTYPE_AP: |
2792 | /* This part is triggered only during CSA */ | 2798 | /* This part is triggered only during CSA */ |
2793 | if (!vif->csa_active || !mvmvif->ap_ibss_active) | 2799 | if (!vif->csa_active || !mvmvif->ap_ibss_active) |
2794 | goto out; | 2800 | goto out; |
2795 | 2801 | ||
2796 | /* Set CS bit on all the stations */ | 2802 | /* Set CS bit on all the stations */ |
2797 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); | 2803 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); |
2798 | 2804 | ||
2799 | /* Save blocked iface, the timeout is set on the next beacon */ | 2805 | /* Save blocked iface, the timeout is set on the next beacon */ |
2800 | rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif); | 2806 | rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif); |
2801 | 2807 | ||
2802 | mvmvif->ap_ibss_active = false; | 2808 | mvmvif->ap_ibss_active = false; |
2803 | break; | 2809 | break; |
2804 | case NL80211_IFTYPE_STATION: | 2810 | case NL80211_IFTYPE_STATION: |
2805 | if (!switching_chanctx) | 2811 | if (!switching_chanctx) |
2806 | break; | 2812 | break; |
2807 | 2813 | ||
2808 | disabled_vif = vif; | 2814 | disabled_vif = vif; |
2809 | 2815 | ||
2810 | iwl_mvm_mac_ctxt_changed(mvm, vif, true); | 2816 | iwl_mvm_mac_ctxt_changed(mvm, vif, true); |
2811 | break; | 2817 | break; |
2812 | default: | 2818 | default: |
2813 | break; | 2819 | break; |
2814 | } | 2820 | } |
2815 | 2821 | ||
2816 | iwl_mvm_update_quotas(mvm, disabled_vif); | 2822 | iwl_mvm_update_quotas(mvm, disabled_vif); |
2817 | iwl_mvm_binding_remove_vif(mvm, vif); | 2823 | iwl_mvm_binding_remove_vif(mvm, vif); |
2818 | 2824 | ||
2819 | out: | 2825 | out: |
2820 | mvmvif->phy_ctxt = NULL; | 2826 | mvmvif->phy_ctxt = NULL; |
2821 | iwl_mvm_power_update_mac(mvm); | 2827 | iwl_mvm_power_update_mac(mvm); |
2822 | } | 2828 | } |
2823 | 2829 | ||
2824 | static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | 2830 | static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, |
2825 | struct ieee80211_vif *vif, | 2831 | struct ieee80211_vif *vif, |
2826 | struct ieee80211_chanctx_conf *ctx) | 2832 | struct ieee80211_chanctx_conf *ctx) |
2827 | { | 2833 | { |
2828 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2834 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2829 | 2835 | ||
2830 | mutex_lock(&mvm->mutex); | 2836 | mutex_lock(&mvm->mutex); |
2831 | __iwl_mvm_unassign_vif_chanctx(mvm, vif, ctx, false); | 2837 | __iwl_mvm_unassign_vif_chanctx(mvm, vif, ctx, false); |
2832 | mutex_unlock(&mvm->mutex); | 2838 | mutex_unlock(&mvm->mutex); |
2833 | } | 2839 | } |
2834 | 2840 | ||
2835 | static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, | 2841 | static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, |
2836 | struct ieee80211_vif_chanctx_switch *vifs, | 2842 | struct ieee80211_vif_chanctx_switch *vifs, |
2837 | int n_vifs, | 2843 | int n_vifs, |
2838 | enum ieee80211_chanctx_switch_mode mode) | 2844 | enum ieee80211_chanctx_switch_mode mode) |
2839 | { | 2845 | { |
2840 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2846 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2841 | int ret; | 2847 | int ret; |
2842 | 2848 | ||
2843 | /* we only support SWAP_CONTEXTS and with a single-vif right now */ | 2849 | /* we only support SWAP_CONTEXTS and with a single-vif right now */ |
2844 | if (mode != CHANCTX_SWMODE_SWAP_CONTEXTS || n_vifs > 1) | 2850 | if (mode != CHANCTX_SWMODE_SWAP_CONTEXTS || n_vifs > 1) |
2845 | return -EOPNOTSUPP; | 2851 | return -EOPNOTSUPP; |
2846 | 2852 | ||
2847 | mutex_lock(&mvm->mutex); | 2853 | mutex_lock(&mvm->mutex); |
2848 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); | 2854 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); |
2849 | __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); | 2855 | __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); |
2850 | 2856 | ||
2851 | ret = __iwl_mvm_add_chanctx(mvm, vifs[0].new_ctx); | 2857 | ret = __iwl_mvm_add_chanctx(mvm, vifs[0].new_ctx); |
2852 | if (ret) { | 2858 | if (ret) { |
2853 | IWL_ERR(mvm, "failed to add new_ctx during channel switch\n"); | 2859 | IWL_ERR(mvm, "failed to add new_ctx during channel switch\n"); |
2854 | goto out_reassign; | 2860 | goto out_reassign; |
2855 | } | 2861 | } |
2856 | 2862 | ||
2857 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx, | 2863 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx, |
2858 | true); | 2864 | true); |
2859 | if (ret) { | 2865 | if (ret) { |
2860 | IWL_ERR(mvm, | 2866 | IWL_ERR(mvm, |
2861 | "failed to assign new_ctx during channel switch\n"); | 2867 | "failed to assign new_ctx during channel switch\n"); |
2862 | goto out_remove; | 2868 | goto out_remove; |
2863 | } | 2869 | } |
2864 | 2870 | ||
2865 | /* we don't support TDLS during DCM - can be caused by channel switch */ | 2871 | /* we don't support TDLS during DCM - can be caused by channel switch */ |
2866 | if (iwl_mvm_phy_ctx_count(mvm) > 1) | 2872 | if (iwl_mvm_phy_ctx_count(mvm) > 1) |
2867 | iwl_mvm_teardown_tdls_peers(mvm); | 2873 | iwl_mvm_teardown_tdls_peers(mvm); |
2868 | 2874 | ||
2869 | goto out; | 2875 | goto out; |
2870 | 2876 | ||
2871 | out_remove: | 2877 | out_remove: |
2872 | __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx); | 2878 | __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx); |
2873 | 2879 | ||
2874 | out_reassign: | 2880 | out_reassign: |
2875 | ret = __iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx); | 2881 | ret = __iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx); |
2876 | if (ret) { | 2882 | if (ret) { |
2877 | IWL_ERR(mvm, "failed to add old_ctx back after failure.\n"); | 2883 | IWL_ERR(mvm, "failed to add old_ctx back after failure.\n"); |
2878 | goto out_restart; | 2884 | goto out_restart; |
2879 | } | 2885 | } |
2880 | 2886 | ||
2881 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, | 2887 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, |
2882 | true); | 2888 | true); |
2883 | if (ret) { | 2889 | if (ret) { |
2884 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); | 2890 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); |
2885 | goto out_restart; | 2891 | goto out_restart; |
2886 | } | 2892 | } |
2887 | 2893 | ||
2888 | goto out; | 2894 | goto out; |
2889 | 2895 | ||
2890 | out_restart: | 2896 | out_restart: |
2891 | /* things keep failing, better restart the hw */ | 2897 | /* things keep failing, better restart the hw */ |
2892 | iwl_mvm_nic_restart(mvm, false); | 2898 | iwl_mvm_nic_restart(mvm, false); |
2893 | 2899 | ||
2894 | out: | 2900 | out: |
2895 | mutex_unlock(&mvm->mutex); | 2901 | mutex_unlock(&mvm->mutex); |
2896 | return ret; | 2902 | return ret; |
2897 | } | 2903 | } |
2898 | 2904 | ||
2899 | static int iwl_mvm_set_tim(struct ieee80211_hw *hw, | 2905 | static int iwl_mvm_set_tim(struct ieee80211_hw *hw, |
2900 | struct ieee80211_sta *sta, | 2906 | struct ieee80211_sta *sta, |
2901 | bool set) | 2907 | bool set) |
2902 | { | 2908 | { |
2903 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2909 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2904 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 2910 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
2905 | 2911 | ||
2906 | if (!mvm_sta || !mvm_sta->vif) { | 2912 | if (!mvm_sta || !mvm_sta->vif) { |
2907 | IWL_ERR(mvm, "Station is not associated to a vif\n"); | 2913 | IWL_ERR(mvm, "Station is not associated to a vif\n"); |
2908 | return -EINVAL; | 2914 | return -EINVAL; |
2909 | } | 2915 | } |
2910 | 2916 | ||
2911 | return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); | 2917 | return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); |
2912 | } | 2918 | } |
2913 | 2919 | ||
2914 | #ifdef CONFIG_NL80211_TESTMODE | 2920 | #ifdef CONFIG_NL80211_TESTMODE |
2915 | static const struct nla_policy iwl_mvm_tm_policy[IWL_MVM_TM_ATTR_MAX + 1] = { | 2921 | static const struct nla_policy iwl_mvm_tm_policy[IWL_MVM_TM_ATTR_MAX + 1] = { |
2916 | [IWL_MVM_TM_ATTR_CMD] = { .type = NLA_U32 }, | 2922 | [IWL_MVM_TM_ATTR_CMD] = { .type = NLA_U32 }, |
2917 | [IWL_MVM_TM_ATTR_NOA_DURATION] = { .type = NLA_U32 }, | 2923 | [IWL_MVM_TM_ATTR_NOA_DURATION] = { .type = NLA_U32 }, |
2918 | [IWL_MVM_TM_ATTR_BEACON_FILTER_STATE] = { .type = NLA_U32 }, | 2924 | [IWL_MVM_TM_ATTR_BEACON_FILTER_STATE] = { .type = NLA_U32 }, |
2919 | }; | 2925 | }; |
2920 | 2926 | ||
2921 | static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, | 2927 | static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, |
2922 | struct ieee80211_vif *vif, | 2928 | struct ieee80211_vif *vif, |
2923 | void *data, int len) | 2929 | void *data, int len) |
2924 | { | 2930 | { |
2925 | struct nlattr *tb[IWL_MVM_TM_ATTR_MAX + 1]; | 2931 | struct nlattr *tb[IWL_MVM_TM_ATTR_MAX + 1]; |
2926 | int err; | 2932 | int err; |
2927 | u32 noa_duration; | 2933 | u32 noa_duration; |
2928 | 2934 | ||
2929 | err = nla_parse(tb, IWL_MVM_TM_ATTR_MAX, data, len, iwl_mvm_tm_policy); | 2935 | err = nla_parse(tb, IWL_MVM_TM_ATTR_MAX, data, len, iwl_mvm_tm_policy); |
2930 | if (err) | 2936 | if (err) |
2931 | return err; | 2937 | return err; |
2932 | 2938 | ||
2933 | if (!tb[IWL_MVM_TM_ATTR_CMD]) | 2939 | if (!tb[IWL_MVM_TM_ATTR_CMD]) |
2934 | return -EINVAL; | 2940 | return -EINVAL; |
2935 | 2941 | ||
2936 | switch (nla_get_u32(tb[IWL_MVM_TM_ATTR_CMD])) { | 2942 | switch (nla_get_u32(tb[IWL_MVM_TM_ATTR_CMD])) { |
2937 | case IWL_MVM_TM_CMD_SET_NOA: | 2943 | case IWL_MVM_TM_CMD_SET_NOA: |
2938 | if (!vif || vif->type != NL80211_IFTYPE_AP || !vif->p2p || | 2944 | if (!vif || vif->type != NL80211_IFTYPE_AP || !vif->p2p || |
2939 | !vif->bss_conf.enable_beacon || | 2945 | !vif->bss_conf.enable_beacon || |
2940 | !tb[IWL_MVM_TM_ATTR_NOA_DURATION]) | 2946 | !tb[IWL_MVM_TM_ATTR_NOA_DURATION]) |
2941 | return -EINVAL; | 2947 | return -EINVAL; |
2942 | 2948 | ||
2943 | noa_duration = nla_get_u32(tb[IWL_MVM_TM_ATTR_NOA_DURATION]); | 2949 | noa_duration = nla_get_u32(tb[IWL_MVM_TM_ATTR_NOA_DURATION]); |
2944 | if (noa_duration >= vif->bss_conf.beacon_int) | 2950 | if (noa_duration >= vif->bss_conf.beacon_int) |
2945 | return -EINVAL; | 2951 | return -EINVAL; |
2946 | 2952 | ||
2947 | mvm->noa_duration = noa_duration; | 2953 | mvm->noa_duration = noa_duration; |
2948 | mvm->noa_vif = vif; | 2954 | mvm->noa_vif = vif; |
2949 | 2955 | ||
2950 | return iwl_mvm_update_quotas(mvm, NULL); | 2956 | return iwl_mvm_update_quotas(mvm, NULL); |
2951 | case IWL_MVM_TM_CMD_SET_BEACON_FILTER: | 2957 | case IWL_MVM_TM_CMD_SET_BEACON_FILTER: |
2952 | /* must be associated client vif - ignore authorized */ | 2958 | /* must be associated client vif - ignore authorized */ |
2953 | if (!vif || vif->type != NL80211_IFTYPE_STATION || | 2959 | if (!vif || vif->type != NL80211_IFTYPE_STATION || |
2954 | !vif->bss_conf.assoc || !vif->bss_conf.dtim_period || | 2960 | !vif->bss_conf.assoc || !vif->bss_conf.dtim_period || |
2955 | !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]) | 2961 | !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]) |
2956 | return -EINVAL; | 2962 | return -EINVAL; |
2957 | 2963 | ||
2958 | if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) | 2964 | if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) |
2959 | return iwl_mvm_enable_beacon_filter(mvm, vif, 0); | 2965 | return iwl_mvm_enable_beacon_filter(mvm, vif, 0); |
2960 | return iwl_mvm_disable_beacon_filter(mvm, vif, 0); | 2966 | return iwl_mvm_disable_beacon_filter(mvm, vif, 0); |
2961 | } | 2967 | } |
2962 | 2968 | ||
2963 | return -EOPNOTSUPP; | 2969 | return -EOPNOTSUPP; |
2964 | } | 2970 | } |
2965 | 2971 | ||
2966 | static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, | 2972 | static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, |
2967 | struct ieee80211_vif *vif, | 2973 | struct ieee80211_vif *vif, |
2968 | void *data, int len) | 2974 | void *data, int len) |
2969 | { | 2975 | { |
2970 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2976 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2971 | int err; | 2977 | int err; |
2972 | 2978 | ||
2973 | mutex_lock(&mvm->mutex); | 2979 | mutex_lock(&mvm->mutex); |
2974 | err = __iwl_mvm_mac_testmode_cmd(mvm, vif, data, len); | 2980 | err = __iwl_mvm_mac_testmode_cmd(mvm, vif, data, len); |
2975 | mutex_unlock(&mvm->mutex); | 2981 | mutex_unlock(&mvm->mutex); |
2976 | 2982 | ||
2977 | return err; | 2983 | return err; |
2978 | } | 2984 | } |
2979 | #endif | 2985 | #endif |
2980 | 2986 | ||
2981 | static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw, | 2987 | static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw, |
2982 | struct ieee80211_vif *vif, | 2988 | struct ieee80211_vif *vif, |
2983 | struct cfg80211_chan_def *chandef) | 2989 | struct cfg80211_chan_def *chandef) |
2984 | { | 2990 | { |
2985 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2991 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2986 | struct ieee80211_vif *csa_vif; | 2992 | struct ieee80211_vif *csa_vif; |
2987 | 2993 | ||
2988 | mutex_lock(&mvm->mutex); | 2994 | mutex_lock(&mvm->mutex); |
2989 | 2995 | ||
2990 | csa_vif = rcu_dereference_protected(mvm->csa_vif, | 2996 | csa_vif = rcu_dereference_protected(mvm->csa_vif, |
2991 | lockdep_is_held(&mvm->mutex)); | 2997 | lockdep_is_held(&mvm->mutex)); |
2992 | if (WARN(csa_vif && csa_vif->csa_active, | 2998 | if (WARN(csa_vif && csa_vif->csa_active, |
2993 | "Another CSA is already in progress")) | 2999 | "Another CSA is already in progress")) |
2994 | goto out_unlock; | 3000 | goto out_unlock; |
2995 | 3001 | ||
2996 | IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n", | 3002 | IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n", |
2997 | chandef->center_freq1); | 3003 | chandef->center_freq1); |
2998 | rcu_assign_pointer(mvm->csa_vif, vif); | 3004 | rcu_assign_pointer(mvm->csa_vif, vif); |
2999 | 3005 | ||
3000 | out_unlock: | 3006 | out_unlock: |
3001 | mutex_unlock(&mvm->mutex); | 3007 | mutex_unlock(&mvm->mutex); |
3002 | } | 3008 | } |
3003 | 3009 | ||
3004 | static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, | 3010 | static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, |
3005 | struct ieee80211_vif *vif, u32 queues, bool drop) | 3011 | struct ieee80211_vif *vif, u32 queues, bool drop) |
3006 | { | 3012 | { |
3007 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 3013 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
3008 | struct iwl_mvm_vif *mvmvif; | 3014 | struct iwl_mvm_vif *mvmvif; |
3009 | struct iwl_mvm_sta *mvmsta; | 3015 | struct iwl_mvm_sta *mvmsta; |
3010 | 3016 | ||
3011 | if (!vif || vif->type != NL80211_IFTYPE_STATION) | 3017 | if (!vif || vif->type != NL80211_IFTYPE_STATION) |
3012 | return; | 3018 | return; |
3013 | 3019 | ||
3014 | mutex_lock(&mvm->mutex); | 3020 | mutex_lock(&mvm->mutex); |
3015 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | 3021 | mvmvif = iwl_mvm_vif_from_mac80211(vif); |
3016 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); | 3022 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); |
3017 | 3023 | ||
3018 | if (WARN_ON_ONCE(!mvmsta)) | 3024 | if (WARN_ON_ONCE(!mvmsta)) |
3019 | goto done; | 3025 | goto done; |
3020 | 3026 | ||
3021 | if (drop) { | 3027 | if (drop) { |
3022 | if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true)) | 3028 | if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true)) |
3023 | IWL_ERR(mvm, "flush request fail\n"); | 3029 | IWL_ERR(mvm, "flush request fail\n"); |
3024 | } else { | 3030 | } else { |
3025 | iwl_trans_wait_tx_queue_empty(mvm->trans, | 3031 | iwl_trans_wait_tx_queue_empty(mvm->trans, |
3026 | mvmsta->tfd_queue_msk); | 3032 | mvmsta->tfd_queue_msk); |
3027 | } | 3033 | } |
3028 | done: | 3034 | done: |
3029 | mutex_unlock(&mvm->mutex); | 3035 | mutex_unlock(&mvm->mutex); |
3030 | } | 3036 | } |
3031 | 3037 | ||
3032 | const struct ieee80211_ops iwl_mvm_hw_ops = { | 3038 | const struct ieee80211_ops iwl_mvm_hw_ops = { |
3033 | .tx = iwl_mvm_mac_tx, | 3039 | .tx = iwl_mvm_mac_tx, |
3034 | .ampdu_action = iwl_mvm_mac_ampdu_action, | 3040 | .ampdu_action = iwl_mvm_mac_ampdu_action, |
3035 | .start = iwl_mvm_mac_start, | 3041 | .start = iwl_mvm_mac_start, |
3036 | .restart_complete = iwl_mvm_mac_restart_complete, | 3042 | .restart_complete = iwl_mvm_mac_restart_complete, |
3037 | .stop = iwl_mvm_mac_stop, | 3043 | .stop = iwl_mvm_mac_stop, |
3038 | .add_interface = iwl_mvm_mac_add_interface, | 3044 | .add_interface = iwl_mvm_mac_add_interface, |
3039 | .remove_interface = iwl_mvm_mac_remove_interface, | 3045 | .remove_interface = iwl_mvm_mac_remove_interface, |
3040 | .config = iwl_mvm_mac_config, | 3046 | .config = iwl_mvm_mac_config, |
3041 | .prepare_multicast = iwl_mvm_prepare_multicast, | 3047 | .prepare_multicast = iwl_mvm_prepare_multicast, |
3042 | .configure_filter = iwl_mvm_configure_filter, | 3048 | .configure_filter = iwl_mvm_configure_filter, |
3043 | .bss_info_changed = iwl_mvm_bss_info_changed, | 3049 | .bss_info_changed = iwl_mvm_bss_info_changed, |
3044 | .hw_scan = iwl_mvm_mac_hw_scan, | 3050 | .hw_scan = iwl_mvm_mac_hw_scan, |
3045 | .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan, | 3051 | .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan, |
3046 | .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove, | 3052 | .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove, |
3047 | .sta_state = iwl_mvm_mac_sta_state, | 3053 | .sta_state = iwl_mvm_mac_sta_state, |
3048 | .sta_notify = iwl_mvm_mac_sta_notify, | 3054 | .sta_notify = iwl_mvm_mac_sta_notify, |
3049 | .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, | 3055 | .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, |
3050 | .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, | 3056 | .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, |
3051 | .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, | 3057 | .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, |
3052 | .sta_rc_update = iwl_mvm_sta_rc_update, | 3058 | .sta_rc_update = iwl_mvm_sta_rc_update, |
3053 | .conf_tx = iwl_mvm_mac_conf_tx, | 3059 | .conf_tx = iwl_mvm_mac_conf_tx, |
3054 | .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, | 3060 | .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, |
3055 | .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, | 3061 | .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, |
3056 | .flush = iwl_mvm_mac_flush, | 3062 | .flush = iwl_mvm_mac_flush, |
3057 | .sched_scan_start = iwl_mvm_mac_sched_scan_start, | 3063 | .sched_scan_start = iwl_mvm_mac_sched_scan_start, |
3058 | .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, | 3064 | .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, |
3059 | .set_key = iwl_mvm_mac_set_key, | 3065 | .set_key = iwl_mvm_mac_set_key, |
3060 | .update_tkip_key = iwl_mvm_mac_update_tkip_key, | 3066 | .update_tkip_key = iwl_mvm_mac_update_tkip_key, |
3061 | .remain_on_channel = iwl_mvm_roc, | 3067 | .remain_on_channel = iwl_mvm_roc, |
3062 | .cancel_remain_on_channel = iwl_mvm_cancel_roc, | 3068 | .cancel_remain_on_channel = iwl_mvm_cancel_roc, |
3063 | .add_chanctx = iwl_mvm_add_chanctx, | 3069 | .add_chanctx = iwl_mvm_add_chanctx, |
3064 | .remove_chanctx = iwl_mvm_remove_chanctx, | 3070 | .remove_chanctx = iwl_mvm_remove_chanctx, |
3065 | .change_chanctx = iwl_mvm_change_chanctx, | 3071 | .change_chanctx = iwl_mvm_change_chanctx, |
3066 | .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, | 3072 | .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, |
3067 | .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, | 3073 | .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, |
3068 | .switch_vif_chanctx = iwl_mvm_switch_vif_chanctx, | 3074 | .switch_vif_chanctx = iwl_mvm_switch_vif_chanctx, |
3069 | 3075 | ||
3070 | .start_ap = iwl_mvm_start_ap_ibss, | 3076 | .start_ap = iwl_mvm_start_ap_ibss, |
3071 | .stop_ap = iwl_mvm_stop_ap_ibss, | 3077 | .stop_ap = iwl_mvm_stop_ap_ibss, |
3072 | .join_ibss = iwl_mvm_start_ap_ibss, | 3078 | .join_ibss = iwl_mvm_start_ap_ibss, |
3073 | .leave_ibss = iwl_mvm_stop_ap_ibss, | 3079 | .leave_ibss = iwl_mvm_stop_ap_ibss, |
3074 | 3080 | ||
3075 | .set_tim = iwl_mvm_set_tim, | 3081 | .set_tim = iwl_mvm_set_tim, |
3076 | 3082 | ||
3077 | .channel_switch_beacon = iwl_mvm_channel_switch_beacon, | 3083 | .channel_switch_beacon = iwl_mvm_channel_switch_beacon, |
3078 | 3084 | ||
3079 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) | 3085 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) |
3080 | 3086 | ||
3081 | #ifdef CONFIG_PM_SLEEP | 3087 | #ifdef CONFIG_PM_SLEEP |
3082 | /* look at d3.c */ | 3088 | /* look at d3.c */ |
3083 | .suspend = iwl_mvm_suspend, | 3089 | .suspend = iwl_mvm_suspend, |
3084 | .resume = iwl_mvm_resume, | 3090 | .resume = iwl_mvm_resume, |
3085 | .set_wakeup = iwl_mvm_set_wakeup, | 3091 | .set_wakeup = iwl_mvm_set_wakeup, |
3086 | .set_rekey_data = iwl_mvm_set_rekey_data, | 3092 | .set_rekey_data = iwl_mvm_set_rekey_data, |
3087 | #if IS_ENABLED(CONFIG_IPV6) | 3093 | #if IS_ENABLED(CONFIG_IPV6) |
3088 | .ipv6_addr_change = iwl_mvm_ipv6_addr_change, | 3094 | .ipv6_addr_change = iwl_mvm_ipv6_addr_change, |
3089 | #endif | 3095 | #endif |
3090 | .set_default_unicast_key = iwl_mvm_set_default_unicast_key, | 3096 | .set_default_unicast_key = iwl_mvm_set_default_unicast_key, |
3091 | #endif | 3097 | #endif |
3092 | }; | 3098 | }; |
3093 | 3099 |