Merge remote-tracking branches 'asoc/topic/wm8753', 'asoc/topic/wm8770', 'asoc/topic...
[linux-block.git] / drivers / net / wireless / intel / iwlwifi / mvm / rs-fw.c
CommitLineData
9f66a397
GG
1/******************************************************************************
2 *
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.
5 *
6 * GPL LICENSE SUMMARY
7 *
8 * Copyright(c) 2017 Intel Deutschland GmbH
9 *
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
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * The full GNU General Public License is included in this distribution
20 * in the file called COPYING.
21 *
22 * Contact Information:
23 * Intel Linux Wireless <linuxwifi@intel.com>
24 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
25 *
26 * BSD LICENSE
27 *
28 * Copyright(c) 2017 Intel Deutschland GmbH
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 *
35 * * Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in
39 * the documentation and/or other materials provided with the
40 * distribution.
41 * * Neither the name Intel Corporation nor the names of its
42 * contributors may be used to endorse or promote products derived
43 * from this software without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
49 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
55 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 *
57 *****************************************************************************/
58#include "rs.h"
59#include "fw-api.h"
60#include "sta.h"
61#include "iwl-op-mode.h"
62#include "mvm.h"
63
110b32f0
GG
64static u8 rs_fw_bw_from_sta_bw(struct ieee80211_sta *sta)
65{
66 switch (sta->bandwidth) {
67 case IEEE80211_STA_RX_BW_160:
68 return IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ;
69 case IEEE80211_STA_RX_BW_80:
70 return IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ;
71 case IEEE80211_STA_RX_BW_40:
72 return IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ;
73 case IEEE80211_STA_RX_BW_20:
74 default:
75 return IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ;
76 }
77}
78
79static u8 rs_fw_set_active_chains(u8 chains)
80{
81 u8 fw_chains = 0;
82
83 if (chains & ANT_A)
84 fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK;
85 if (chains & ANT_B)
86 fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK;
87 if (chains & ANT_C)
88 fw_chains |= IWL_TLC_MNG_CHAIN_C_MSK;
89
90 return fw_chains;
91}
92
93static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
94{
95 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
96 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
97 u8 supp = 0;
98
99 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
100 supp |= IWL_TLC_MNG_SGI_20MHZ_MSK;
101 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
102 supp |= IWL_TLC_MNG_SGI_40MHZ_MSK;
103 if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)
104 supp |= IWL_TLC_MNG_SGI_80MHZ_MSK;
105 if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160)
106 supp |= IWL_TLC_MNG_SGI_160MHZ_MSK;
107
108 return supp;
109}
110
111static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm,
112 struct ieee80211_sta *sta)
113{
114 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
115 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
116 bool vht_ena = vht_cap && vht_cap->vht_supported;
117 u16 flags = IWL_TLC_MNG_CFG_FLAGS_CCK_MSK |
118 IWL_TLC_MNG_CFG_FLAGS_DCM_MSK |
119 IWL_TLC_MNG_CFG_FLAGS_DD_MSK;
120
121 if (mvm->cfg->ht_params->stbc &&
122 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
123 ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) ||
124 (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))))
125 flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
126
127 if (mvm->cfg->ht_params->ldpc &&
128 ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) ||
129 (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
130 flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
131
132 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
133 (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
134 (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE))
135 flags |= IWL_TLC_MNG_CFG_FLAGS_BF_MSK;
136
137 return flags;
138}
139
140static
141int rs_fw_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap,
142 int nss)
143{
144 u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) &
145 (0x3 << (2 * (nss - 1)));
146 rx_mcs >>= (2 * (nss - 1));
147
148 switch (rx_mcs) {
149 case IEEE80211_VHT_MCS_SUPPORT_0_7:
150 return IWL_TLC_MNG_HT_RATE_MCS7;
151 case IEEE80211_VHT_MCS_SUPPORT_0_8:
152 return IWL_TLC_MNG_HT_RATE_MCS8;
153 case IEEE80211_VHT_MCS_SUPPORT_0_9:
154 return IWL_TLC_MNG_HT_RATE_MCS9;
155 default:
156 WARN_ON_ONCE(1);
157 break;
158 }
159
160 return 0;
161}
162
163static void rs_fw_vht_set_enabled_rates(struct ieee80211_sta *sta,
164 struct ieee80211_sta_vht_cap *vht_cap,
165 struct iwl_tlc_config_cmd *cmd)
166{
167 u16 supp;
168 int i, highest_mcs;
169
170 for (i = 0; i < sta->rx_nss; i++) {
171 if (i == MAX_RS_ANT_NUM)
172 break;
173
174 highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, i + 1);
175 if (!highest_mcs)
176 continue;
177
178 supp = BIT(highest_mcs + 1) - 1;
179 if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
180 supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);
181
182 cmd->ht_supp_rates[i] = cpu_to_le16(supp);
183 }
184}
185
186static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
187 struct ieee80211_supported_band *sband,
188 struct iwl_tlc_config_cmd *cmd)
189{
190 int i;
191 unsigned long tmp;
192 unsigned long supp; /* must be unsigned long for for_each_set_bit */
193 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
194 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
195
196 /* non HT rates */
197 supp = 0;
198 tmp = sta->supp_rates[sband->band];
199 for_each_set_bit(i, &tmp, BITS_PER_LONG)
200 supp |= BIT(sband->bitrates[i].hw_value);
201
202 cmd->non_ht_supp_rates = cpu_to_le16(supp);
203 cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
204
205 /* HT/VHT rates */
206 if (vht_cap && vht_cap->vht_supported) {
207 cmd->mode = IWL_TLC_MNG_MODE_VHT;
208 rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
209 } else if (ht_cap && ht_cap->ht_supported) {
210 cmd->mode = IWL_TLC_MNG_MODE_HT;
211 cmd->ht_supp_rates[0] = cpu_to_le16(ht_cap->mcs.rx_mask[0]);
212 cmd->ht_supp_rates[1] = cpu_to_le16(ht_cap->mcs.rx_mask[1]);
213 }
214}
215
46d372af
GG
216static void rs_fw_tlc_mng_notif_req_config(struct iwl_mvm *mvm, u8 sta_id)
217{
218 u32 cmd_id = iwl_cmd_id(TLC_MNG_NOTIF_REQ_CMD, DATA_PATH_GROUP, 0);
219 struct iwl_tlc_notif_req_config_cmd cfg_cmd = {
220 .sta_id = sta_id,
221 .flags = cpu_to_le16(IWL_TLC_NOTIF_INIT_RATE_MSK),
222 .interval = cpu_to_le16(IWL_TLC_NOTIF_REQ_INTERVAL),
223 };
224 int ret;
225
226 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd);
227 if (ret)
228 IWL_ERR(mvm, "Failed to send TLC notif request (%d)\n", ret);
229}
230
231void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
232{
233 struct iwl_tlc_update_notif *notif;
234 struct iwl_mvm_sta *mvmsta;
235 struct iwl_lq_sta_rs_fw *lq_sta;
236
237 notif = (void *)pkt->data;
238 mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, notif->sta_id);
239
240 if (!mvmsta) {
241 IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n",
242 notif->sta_id);
243 return;
244 }
245
246 lq_sta = &mvmsta->lq_sta.rs_fw;
247
248 if (le16_to_cpu(notif->flags) & IWL_TLC_NOTIF_INIT_RATE_MSK) {
249 lq_sta->last_rate_n_flags =
250 le32_to_cpu(notif->values[IWL_TLC_NOTIF_INIT_RATE_POS]);
251 IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n",
252 lq_sta->last_rate_n_flags);
253 }
254}
255
9f66a397
GG
256void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
257 enum nl80211_band band)
258{
110b32f0
GG
259 struct ieee80211_hw *hw = mvm->hw;
260 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
261 struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
262 u32 cmd_id = iwl_cmd_id(TLC_MNG_CONFIG_CMD, DATA_PATH_GROUP, 0);
263 struct ieee80211_supported_band *sband;
264 struct iwl_tlc_config_cmd cfg_cmd = {
265 .sta_id = mvmsta->sta_id,
266 .max_supp_ch_width = rs_fw_bw_from_sta_bw(sta),
267 .flags = cpu_to_le16(rs_fw_set_config_flags(mvm, sta)),
268 .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
269 .max_supp_ss = sta->rx_nss,
270 .max_ampdu_cnt = cpu_to_le32(mvmsta->max_agg_bufsize),
271 .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta),
272 };
273 int ret;
274
275 memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
276
277#ifdef CONFIG_IWLWIFI_DEBUGFS
278 iwl_mvm_reset_frame_stats(mvm);
279#endif
280 sband = hw->wiphy->bands[band];
281 rs_fw_set_supp_rates(sta, sband, &cfg_cmd);
282
283 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd);
284 if (ret)
285 IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret);
46d372af
GG
286
287 rs_fw_tlc_mng_notif_req_config(mvm, cfg_cmd.sta_id);
110b32f0
GG
288}
289
290int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
291 bool enable)
292{
293 /* TODO: need to introduce a new FW cmd since LQ cmd is not relevant */
294 IWL_DEBUG_RATE(mvm, "tx protection - not implemented yet.\n");
295 return 0;
9f66a397
GG
296}
297
298void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta)
299{
300 struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
301
302 IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
303
304 lq_sta->pers.drv = mvm;
305 lq_sta->pers.sta_id = mvmsta->sta_id;
306 lq_sta->pers.chains = 0;
307 memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
308 lq_sta->pers.last_rssi = S8_MIN;
309 lq_sta->last_rate_n_flags = 0;
310
59365b9e 311#ifdef CONFIG_MAC80211_DEBUGFS
9f66a397
GG
312 lq_sta->pers.dbg_fixed_rate = 0;
313#endif
314}