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;
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 	seq = tmp_buf[2] >> 4;
336 	data = &tmp_buf[3];
337 
338 	/* BT Firmware version response */
339 	switch (seq) {
340 	case BT_SEQ_GET_BT_VERSION:
341 		bt_real_fw_ver = tmp_buf[3] | (tmp_buf[4] << 8);
342 		bt_fw_ver = tmp_buf[5];
343 
344 		btcoexist->bt_info.bt_real_fw_ver = bt_real_fw_ver;
345 		btcoexist->bt_info.bt_fw_ver = bt_fw_ver;
346 		break;
347 	case BT_SEQ_GET_AFH_MAP_L:
348 		btcoexist->bt_info.afh_map_l = le32_to_cpu(*(__le32 *)data);
349 		break;
350 	case BT_SEQ_GET_AFH_MAP_M:
351 		btcoexist->bt_info.afh_map_m = le32_to_cpu(*(__le32 *)data);
352 		break;
353 	case BT_SEQ_GET_AFH_MAP_H:
354 		btcoexist->bt_info.afh_map_h = le16_to_cpu(*(__le16 *)data);
355 		break;
356 	case BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE:
357 		btcoexist->bt_info.bt_supported_feature = tmp_buf[3] |
358 							  (tmp_buf[4] << 8);
359 		break;
360 	case BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION:
361 		btcoexist->bt_info.bt_supported_version = tmp_buf[3] |
362 							  (tmp_buf[4] << 8);
363 		break;
364 	case BT_SEQ_GET_BT_ANT_DET_VAL:
365 		btcoexist->bt_info.bt_ant_det_val = tmp_buf[3];
366 		break;
367 	case BT_SEQ_GET_BT_BLE_SCAN_PARA:
368 		btcoexist->bt_info.bt_ble_scan_para = tmp_buf[3] |
369 						      (tmp_buf[4] << 8) |
370 						      (tmp_buf[5] << 16) |
371 						      (tmp_buf[6] << 24);
372 		break;
373 	case BT_SEQ_GET_BT_BLE_SCAN_TYPE:
374 		btcoexist->bt_info.bt_ble_scan_type = tmp_buf[3];
375 		break;
376 	case BT_SEQ_GET_BT_DEVICE_INFO:
377 		btcoexist->bt_info.bt_device_info =
378 						le32_to_cpu(*(__le32 *)data);
379 		break;
380 	case BT_OP_GET_BT_FORBIDDEN_SLOT_VAL:
381 		btcoexist->bt_info.bt_forb_slot_val =
382 						le32_to_cpu(*(__le32 *)data);
383 		break;
384 	}
385 
386 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
387 		 "btmpinfo complete req_num=%d\n", seq);
388 
389 	complete(&btcoexist->bt_mp_comp);
390 }
391 
392 bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv)
393 {
394 	struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
395 
396 	if (!btcoexist)
397 		return false;
398 
399 	return btcoexist->bt_info.limited_dig;
400 }
401 
402 bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
403 {
404 	bool bt_change_edca = false;
405 	u32 cur_edca_val;
406 	u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b;
407 	u32 edca_hs;
408 	u32 edca_addr = 0x504;
409 
410 	cur_edca_val = rtl_read_dword(rtlpriv, edca_addr);
411 	if (halbtc_is_wifi_uplink(rtlpriv)) {
412 		if (cur_edca_val != edca_bt_hs_uplink) {
413 			edca_hs = edca_bt_hs_uplink;
414 			bt_change_edca = true;
415 		}
416 	} else {
417 		if (cur_edca_val != edca_bt_hs_downlink) {
418 			edca_hs = edca_bt_hs_downlink;
419 			bt_change_edca = true;
420 		}
421 	}
422 
423 	if (bt_change_edca)
424 		rtl_write_dword(rtlpriv, edca_addr, edca_hs);
425 
426 	return true;
427 }
428 
429 bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
430 {
431 	struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
432 
433 	if (!btcoexist)
434 		return true;
435 
436 	/* It seems 'bt_disabled' is never be initialized or set. */
437 	if (btcoexist->bt_info.bt_disabled)
438 		return true;
439 	else
440 		return false;
441 }
442 
443 void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
444 {
445 	struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
446 
447 	if (!btcoexist)
448 		return;
449 
450 	return exhalbtc_special_packet_notify(btcoexist, pkt_type);
451 }
452 
453 void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type,
454 				bool scanning)
455 {
456 	struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
457 	u8 type = BTC_NOT_SWITCH;
458 
459 	if (!btcoexist)
460 		return;
461 
462 	switch (band_type) {
463 	case BAND_ON_2_4G:
464 		if (scanning)
465 			type = BTC_SWITCH_TO_24G;
466 		else
467 			type = BTC_SWITCH_TO_24G_NOFORSCAN;
468 		break;
469 
470 	case BAND_ON_5G:
471 		type = BTC_SWITCH_TO_5G;
472 		break;
473 	}
474 
475 	if (type != BTC_NOT_SWITCH)
476 		exhalbtc_switch_band_notify(btcoexist, type);
477 }
478 
479 void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type,
480 					 bool scanning)
481 {
482 	struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
483 	u8 is_5g = (band_type == BAND_ON_5G);
484 
485 	if (!wifionly_cfg)
486 		return;
487 
488 	exhalbtc_switch_band_notify_wifi_only(wifionly_cfg, is_5g);
489 }
490 
491 struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
492 {
493 	return &rtl_btc_operation;
494 }
495 EXPORT_SYMBOL(rtl_btc_get_ops_pointer);
496 
497 
498 enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
499 {
500 	struct rtl_priv *rtlpriv = rtl_priv(hw);
501 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
502 	enum rt_media_status    m_status = RT_MEDIA_DISCONNECT;
503 
504 	u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
505 
506 	if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
507 		m_status = RT_MEDIA_CONNECT;
508 
509 	return m_status;
510 }
511 
512 u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)
513 {
514 	return rtlpriv->btcoexist.btc_info.btcoexist;
515 }
516 
517 MODULE_AUTHOR("Page He	<page_he@realsil.com.cn>");
518 MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>");
519 MODULE_AUTHOR("Larry Finger	<Larry.FInger@lwfinger.net>");
520 MODULE_LICENSE("GPL");
521 MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
522 
523 static int __init rtl_btcoexist_module_init(void)
524 {
525 	return 0;
526 }
527 
528 static void __exit rtl_btcoexist_module_exit(void)
529 {
530 	return;
531 }
532 
533 module_init(rtl_btcoexist_module_init);
534 module_exit(rtl_btcoexist_module_exit);
535