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