GNU Linux-libre 4.19.268-gnu1
[releases.git] / drivers / staging / rtlwifi / btcoexist / rtl_btc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2009-2013  Realtek Corporation.
5  *
6  * Contact Information:
7  * wlanfae <wlanfae@realtek.com>
8  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
9  * Hsinchu 300, Taiwan.
10  *
11  * Larry Finger <Larry.Finger@lwfinger.net>
12  *
13  *****************************************************************************/
14 #include "../wifi.h"
15 #include <linux/vmalloc.h>
16 #include <linux/module.h>
17
18 #include "rtl_btc.h"
19 #include "halbt_precomp.h"
20
21 static struct rtl_btc_ops rtl_btc_operation = {
22         .btc_init_variables = rtl_btc_init_variables,
23         .btc_init_variables_wifi_only = rtl_btc_init_variables_wifi_only,
24         .btc_deinit_variables = rtl_btc_deinit_variables,
25         .btc_init_hal_vars = rtl_btc_init_hal_vars,
26         .btc_power_on_setting = rtl_btc_power_on_setting,
27         .btc_init_hw_config = rtl_btc_init_hw_config,
28         .btc_init_hw_config_wifi_only = rtl_btc_init_hw_config_wifi_only,
29         .btc_ips_notify = rtl_btc_ips_notify,
30         .btc_lps_notify = rtl_btc_lps_notify,
31         .btc_scan_notify = rtl_btc_scan_notify,
32         .btc_scan_notify_wifi_only = rtl_btc_scan_notify_wifi_only,
33         .btc_connect_notify = rtl_btc_connect_notify,
34         .btc_mediastatus_notify = rtl_btc_mediastatus_notify,
35         .btc_periodical = rtl_btc_periodical,
36         .btc_halt_notify = rtl_btc_halt_notify,
37         .btc_btinfo_notify = rtl_btc_btinfo_notify,
38         .btc_btmpinfo_notify = rtl_btc_btmpinfo_notify,
39         .btc_is_limited_dig = rtl_btc_is_limited_dig,
40         .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
41         .btc_is_bt_disabled = rtl_btc_is_bt_disabled,
42         .btc_special_packet_notify = rtl_btc_special_packet_notify,
43         .btc_switch_band_notify = rtl_btc_switch_band_notify,
44         .btc_switch_band_notify_wifi_only = rtl_btc_switch_band_notify_wifionly,
45         .btc_record_pwr_mode = rtl_btc_record_pwr_mode,
46         .btc_get_lps_val = rtl_btc_get_lps_val,
47         .btc_get_rpwm_val = rtl_btc_get_rpwm_val,
48         .btc_is_bt_ctrl_lps = rtl_btc_is_bt_ctrl_lps,
49         .btc_is_bt_lps_on = rtl_btc_is_bt_lps_on,
50         .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg,
51         .btc_display_bt_coex_info = rtl_btc_display_bt_coex_info,
52 };
53
54 void rtl_btc_display_bt_coex_info(struct rtl_priv *rtlpriv, struct seq_file *m)
55 {
56         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
57
58         if (!btcoexist) {
59                 seq_puts(m, "btc_coexist context is NULL!\n");
60                 return;
61         }
62
63         exhalbtc_display_bt_coex_info(btcoexist, m);
64 }
65
66 void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len)
67 {
68         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
69         u8 safe_len;
70
71         if (!btcoexist)
72                 return;
73
74         safe_len = sizeof(btcoexist->pwr_mode_val);
75
76         if (safe_len > len)
77                 safe_len = len;
78
79         memcpy(btcoexist->pwr_mode_val, buf, safe_len);
80 }
81
82 u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv)
83 {
84         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
85
86         if (!btcoexist)
87                 return 0;
88
89         return btcoexist->bt_info.lps_val;
90 }
91
92 u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv)
93 {
94         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
95
96         if (!btcoexist)
97                 return 0;
98
99         return btcoexist->bt_info.rpwm_val;
100 }
101
102 bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv)
103 {
104         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
105
106         if (!btcoexist)
107                 return false;
108
109         return btcoexist->bt_info.bt_ctrl_lps;
110 }
111
112 bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv)
113 {
114         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
115
116         if (!btcoexist)
117                 return false;
118
119         return btcoexist->bt_info.bt_lps_on;
120 }
121
122 void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg,
123                            u8 *ctrl_agg_size, u8 *agg_size)
124 {
125         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
126
127         if (!btcoexist) {
128                 *reject_agg = false;
129                 *ctrl_agg_size = false;
130                 return;
131         }
132
133         if (reject_agg)
134                 *reject_agg = btcoexist->bt_info.reject_agg_pkt;
135         if (ctrl_agg_size)
136                 *ctrl_agg_size = btcoexist->bt_info.bt_ctrl_agg_buf_size;
137         if (agg_size)
138                 *agg_size = btcoexist->bt_info.agg_buf_size;
139 }
140
141 static void rtl_btc_alloc_variable(struct rtl_priv *rtlpriv, bool wifi_only)
142 {
143         if (wifi_only)
144                 rtlpriv->btcoexist.wifi_only_context =
145                         kzalloc(sizeof(struct wifi_only_cfg), GFP_KERNEL);
146         else
147                 rtlpriv->btcoexist.btc_context =
148                         kzalloc(sizeof(struct btc_coexist), GFP_KERNEL);
149 }
150
151 static void rtl_btc_free_variable(struct rtl_priv *rtlpriv)
152 {
153         kfree(rtlpriv->btcoexist.btc_context);
154         rtlpriv->btcoexist.btc_context = NULL;
155
156         kfree(rtlpriv->btcoexist.wifi_only_context);
157         rtlpriv->btcoexist.wifi_only_context = NULL;
158 }
159
160 void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
161 {
162         rtl_btc_alloc_variable(rtlpriv, false);
163
164         exhalbtc_initlize_variables(rtlpriv);
165         exhalbtc_bind_bt_coex_withadapter(rtlpriv);
166 }
167
168 void rtl_btc_init_variables_wifi_only(struct rtl_priv *rtlpriv)
169 {
170         rtl_btc_alloc_variable(rtlpriv, true);
171
172         exhalbtc_initlize_variables_wifi_only(rtlpriv);
173 }
174
175 void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv)
176 {
177         rtl_btc_free_variable(rtlpriv);
178 }
179
180 void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv)
181 {
182         /* move ant_num, bt_type and single_ant_path to
183          * exhalbtc_bind_bt_coex_withadapter()
184          */
185 }
186
187 void rtl_btc_power_on_setting(struct rtl_priv *rtlpriv)
188 {
189         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
190
191         if (!btcoexist)
192                 return;
193
194         exhalbtc_power_on_setting(btcoexist);
195 }
196
197 void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
198 {
199         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
200
201         u8 bt_exist;
202
203         bt_exist = rtl_get_hwpg_bt_exist(rtlpriv);
204         RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
205                  "%s, bt_exist is %d\n", __func__, bt_exist);
206
207         if (!btcoexist)
208                 return;
209
210         exhalbtc_init_hw_config(btcoexist, !bt_exist);
211         exhalbtc_init_coex_dm(btcoexist);
212 }
213
214 void rtl_btc_init_hw_config_wifi_only(struct rtl_priv *rtlpriv)
215 {
216         struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
217
218         if (!wifionly_cfg)
219                 return;
220
221         exhalbtc_init_hw_config_wifi_only(wifionly_cfg);
222 }
223
224 void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
225 {
226         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
227
228         if (!btcoexist)
229                 return;
230
231         exhalbtc_ips_notify(btcoexist, type);
232
233         if (type == ERFON) {
234                 /*
235                  * In some situation, it doesn't scan after leaving IPS, and
236                  * this will cause btcoex in wrong state.
237                  */
238                 exhalbtc_scan_notify(btcoexist, 1);
239                 exhalbtc_scan_notify(btcoexist, 0);
240         }
241 }
242
243 void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type)
244 {
245         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
246
247         if (!btcoexist)
248                 return;
249
250         exhalbtc_lps_notify(btcoexist, type);
251 }
252
253 void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
254 {
255         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
256
257         if (!btcoexist)
258                 return;
259
260         exhalbtc_scan_notify(btcoexist, scantype);
261 }
262
263 void rtl_btc_scan_notify_wifi_only(struct rtl_priv *rtlpriv, u8 scantype)
264 {
265         struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
266         struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
267         u8 is_5g = (rtlhal->current_bandtype == BAND_ON_5G);
268
269         if (!wifionly_cfg)
270                 return;
271
272         exhalbtc_scan_notify_wifi_only(wifionly_cfg, is_5g);
273 }
274
275 void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
276 {
277         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
278
279         if (!btcoexist)
280                 return;
281
282         exhalbtc_connect_notify(btcoexist, action);
283 }
284
285 void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
286                                 enum rt_media_status mstatus)
287 {
288         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
289
290         if (!btcoexist)
291                 return;
292
293         exhalbtc_mediastatus_notify(btcoexist, mstatus);
294 }
295
296 void rtl_btc_periodical(struct rtl_priv *rtlpriv)
297 {
298         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
299
300         if (!btcoexist)
301                 return;
302
303         /*rtl_bt_dm_monitor();*/
304         exhalbtc_periodical(btcoexist);
305 }
306
307 void rtl_btc_halt_notify(struct rtl_priv *rtlpriv)
308 {
309         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
310
311         if (!btcoexist)
312                 return;
313
314         exhalbtc_halt_notify(btcoexist);
315 }
316
317 void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
318 {
319         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
320
321         if (!btcoexist)
322                 return;
323
324         exhalbtc_bt_info_notify(btcoexist, tmp_buf, length);
325 }
326
327 void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
328 {
329         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
330         u8 extid, seq, len;
331         u16 bt_real_fw_ver;
332         u8 bt_fw_ver;
333         u8 *data;
334
335         if (!btcoexist)
336                 return;
337
338         if ((length < 4) || (!tmp_buf))
339                 return;
340
341         extid = tmp_buf[0];
342         /* not response from BT FW then exit*/
343         if (extid != 1) /* C2H_TRIG_BY_BT_FW = 1 */
344                 return;
345
346         len = tmp_buf[1] >> 4;
347         seq = tmp_buf[2] >> 4;
348         data = &tmp_buf[3];
349
350         /* BT Firmware version response */
351         switch (seq) {
352         case BT_SEQ_GET_BT_VERSION:
353                 bt_real_fw_ver = tmp_buf[3] | (tmp_buf[4] << 8);
354                 bt_fw_ver = tmp_buf[5];
355
356                 btcoexist->bt_info.bt_real_fw_ver = bt_real_fw_ver;
357                 btcoexist->bt_info.bt_fw_ver = bt_fw_ver;
358                 break;
359         case BT_SEQ_GET_AFH_MAP_L:
360                 btcoexist->bt_info.afh_map_l = le32_to_cpu(*(__le32 *)data);
361                 break;
362         case BT_SEQ_GET_AFH_MAP_M:
363                 btcoexist->bt_info.afh_map_m = le32_to_cpu(*(__le32 *)data);
364                 break;
365         case BT_SEQ_GET_AFH_MAP_H:
366                 btcoexist->bt_info.afh_map_h = le16_to_cpu(*(__le16 *)data);
367                 break;
368         case BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE:
369                 btcoexist->bt_info.bt_supported_feature = tmp_buf[3] |
370                                                           (tmp_buf[4] << 8);
371                 break;
372         case BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION:
373                 btcoexist->bt_info.bt_supported_version = tmp_buf[3] |
374                                                           (tmp_buf[4] << 8);
375                 break;
376         case BT_SEQ_GET_BT_ANT_DET_VAL:
377                 btcoexist->bt_info.bt_ant_det_val = tmp_buf[3];
378                 break;
379         case BT_SEQ_GET_BT_BLE_SCAN_PARA:
380                 btcoexist->bt_info.bt_ble_scan_para = tmp_buf[3] |
381                                                       (tmp_buf[4] << 8) |
382                                                       (tmp_buf[5] << 16) |
383                                                       (tmp_buf[6] << 24);
384                 break;
385         case BT_SEQ_GET_BT_BLE_SCAN_TYPE:
386                 btcoexist->bt_info.bt_ble_scan_type = tmp_buf[3];
387                 break;
388         }
389
390         RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
391                  "btmpinfo complete req_num=%d\n", seq);
392
393         complete(&btcoexist->bt_mp_comp);
394 }
395
396 bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv)
397 {
398         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
399
400         if (!btcoexist)
401                 return false;
402
403         return btcoexist->bt_info.limited_dig;
404 }
405
406 bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
407 {
408         bool bt_change_edca = false;
409         u32 cur_edca_val;
410         u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b;
411         u32 edca_hs;
412         u32 edca_addr = 0x504;
413
414         cur_edca_val = rtl_read_dword(rtlpriv, edca_addr);
415         if (halbtc_is_wifi_uplink(rtlpriv)) {
416                 if (cur_edca_val != edca_bt_hs_uplink) {
417                         edca_hs = edca_bt_hs_uplink;
418                         bt_change_edca = true;
419                 }
420         } else {
421                 if (cur_edca_val != edca_bt_hs_downlink) {
422                         edca_hs = edca_bt_hs_downlink;
423                         bt_change_edca = true;
424                 }
425         }
426
427         if (bt_change_edca)
428                 rtl_write_dword(rtlpriv, edca_addr, edca_hs);
429
430         return true;
431 }
432
433 bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
434 {
435         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
436
437         if (!btcoexist)
438                 return true;
439
440         /* It seems 'bt_disabled' is never be initialized or set. */
441         if (btcoexist->bt_info.bt_disabled)
442                 return true;
443         else
444                 return false;
445 }
446
447 void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
448 {
449         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
450
451         if (!btcoexist)
452                 return;
453
454         return exhalbtc_special_packet_notify(btcoexist, pkt_type);
455 }
456
457 void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type,
458                                 bool scanning)
459 {
460         struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
461         u8 type = BTC_NOT_SWITCH;
462
463         if (!btcoexist)
464                 return;
465
466         switch (band_type) {
467         case BAND_ON_2_4G:
468                 if (scanning)
469                         type = BTC_SWITCH_TO_24G;
470                 else
471                         type = BTC_SWITCH_TO_24G_NOFORSCAN;
472                 break;
473
474         case BAND_ON_5G:
475                 type = BTC_SWITCH_TO_5G;
476                 break;
477         }
478
479         if (type != BTC_NOT_SWITCH)
480                 exhalbtc_switch_band_notify(btcoexist, type);
481 }
482
483 void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type,
484                                          bool scanning)
485 {
486         struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
487         u8 is_5g = (band_type == BAND_ON_5G);
488
489         if (!wifionly_cfg)
490                 return;
491
492         exhalbtc_switch_band_notify_wifi_only(wifionly_cfg, is_5g);
493 }
494
495 struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
496 {
497         return &rtl_btc_operation;
498 }
499
500 enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
501 {
502         struct rtl_priv *rtlpriv = rtl_priv(hw);
503         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
504         enum rt_media_status    m_status = RT_MEDIA_DISCONNECT;
505
506         u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
507
508         if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
509                 m_status = RT_MEDIA_CONNECT;
510
511         return m_status;
512 }
513
514 u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)
515 {
516         return rtlpriv->btcoexist.btc_info.btcoexist;
517 }