1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2009-2013 Realtek Corporation.*/
5 #include <linux/vmalloc.h>
6 #include <linux/module.h>
9 #include "halbt_precomp.h"
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
,
44 void rtl_btc_display_bt_coex_info(struct rtl_priv
*rtlpriv
, struct seq_file
*m
)
46 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
49 seq_puts(m
, "btc_coexist context is NULL!\n");
53 exhalbtc_display_bt_coex_info(btcoexist
, m
);
56 void rtl_btc_record_pwr_mode(struct rtl_priv
*rtlpriv
, u8
*buf
, u8 len
)
58 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
64 safe_len
= sizeof(btcoexist
->pwr_mode_val
);
69 memcpy(btcoexist
->pwr_mode_val
, buf
, safe_len
);
72 u8
rtl_btc_get_lps_val(struct rtl_priv
*rtlpriv
)
74 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
79 return btcoexist
->bt_info
.lps_val
;
82 u8
rtl_btc_get_rpwm_val(struct rtl_priv
*rtlpriv
)
84 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
89 return btcoexist
->bt_info
.rpwm_val
;
92 bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv
*rtlpriv
)
94 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
99 return btcoexist
->bt_info
.bt_ctrl_lps
;
102 bool rtl_btc_is_bt_lps_on(struct rtl_priv
*rtlpriv
)
104 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
109 return btcoexist
->bt_info
.bt_lps_on
;
112 void rtl_btc_get_ampdu_cfg(struct rtl_priv
*rtlpriv
, u8
*reject_agg
,
113 u8
*ctrl_agg_size
, u8
*agg_size
)
115 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
119 *ctrl_agg_size
= false;
124 *reject_agg
= btcoexist
->bt_info
.reject_agg_pkt
;
126 *ctrl_agg_size
= btcoexist
->bt_info
.bt_ctrl_agg_buf_size
;
128 *agg_size
= btcoexist
->bt_info
.agg_buf_size
;
131 static void rtl_btc_alloc_variable(struct rtl_priv
*rtlpriv
, bool wifi_only
)
134 rtlpriv
->btcoexist
.wifi_only_context
=
135 kzalloc(sizeof(struct wifi_only_cfg
), GFP_KERNEL
);
137 rtlpriv
->btcoexist
.btc_context
=
138 kzalloc(sizeof(struct btc_coexist
), GFP_KERNEL
);
141 static void rtl_btc_free_variable(struct rtl_priv
*rtlpriv
)
143 kfree(rtlpriv
->btcoexist
.btc_context
);
144 rtlpriv
->btcoexist
.btc_context
= NULL
;
146 kfree(rtlpriv
->btcoexist
.wifi_only_context
);
147 rtlpriv
->btcoexist
.wifi_only_context
= NULL
;
150 void rtl_btc_init_variables(struct rtl_priv
*rtlpriv
)
152 rtl_btc_alloc_variable(rtlpriv
, false);
154 exhalbtc_initlize_variables(rtlpriv
);
155 exhalbtc_bind_bt_coex_withadapter(rtlpriv
);
158 void rtl_btc_init_variables_wifi_only(struct rtl_priv
*rtlpriv
)
160 rtl_btc_alloc_variable(rtlpriv
, true);
162 exhalbtc_initlize_variables_wifi_only(rtlpriv
);
165 void rtl_btc_deinit_variables(struct rtl_priv
*rtlpriv
)
167 rtl_btc_free_variable(rtlpriv
);
170 void rtl_btc_init_hal_vars(struct rtl_priv
*rtlpriv
)
172 /* move ant_num, bt_type and single_ant_path to
173 * exhalbtc_bind_bt_coex_withadapter()
177 void rtl_btc_power_on_setting(struct rtl_priv
*rtlpriv
)
179 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
184 exhalbtc_power_on_setting(btcoexist
);
187 void rtl_btc_init_hw_config(struct rtl_priv
*rtlpriv
)
189 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
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
);
200 exhalbtc_init_hw_config(btcoexist
, !bt_exist
);
201 exhalbtc_init_coex_dm(btcoexist
);
204 void rtl_btc_init_hw_config_wifi_only(struct rtl_priv
*rtlpriv
)
206 struct wifi_only_cfg
*wifionly_cfg
= rtl_btc_wifi_only(rtlpriv
);
211 exhalbtc_init_hw_config_wifi_only(wifionly_cfg
);
214 void rtl_btc_ips_notify(struct rtl_priv
*rtlpriv
, u8 type
)
216 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
221 exhalbtc_ips_notify(btcoexist
, type
);
224 /* In some situation, it doesn't scan after leaving IPS, and
225 * this will cause btcoex in wrong state.
227 exhalbtc_scan_notify(btcoexist
, 1);
228 exhalbtc_scan_notify(btcoexist
, 0);
232 void rtl_btc_lps_notify(struct rtl_priv
*rtlpriv
, u8 type
)
234 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
239 exhalbtc_lps_notify(btcoexist
, type
);
242 void rtl_btc_scan_notify(struct rtl_priv
*rtlpriv
, u8 scantype
)
244 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
249 exhalbtc_scan_notify(btcoexist
, scantype
);
252 void rtl_btc_scan_notify_wifi_only(struct rtl_priv
*rtlpriv
, u8 scantype
)
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
);
261 exhalbtc_scan_notify_wifi_only(wifionly_cfg
, is_5g
);
264 void rtl_btc_connect_notify(struct rtl_priv
*rtlpriv
, u8 action
)
266 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
271 exhalbtc_connect_notify(btcoexist
, action
);
274 void rtl_btc_mediastatus_notify(struct rtl_priv
*rtlpriv
,
275 enum rt_media_status mstatus
)
277 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
282 exhalbtc_mediastatus_notify(btcoexist
, mstatus
);
285 void rtl_btc_periodical(struct rtl_priv
*rtlpriv
)
287 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
292 /*rtl_bt_dm_monitor();*/
293 exhalbtc_periodical(btcoexist
);
296 void rtl_btc_halt_notify(struct rtl_priv
*rtlpriv
)
298 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
303 exhalbtc_halt_notify(btcoexist
);
306 void rtl_btc_btinfo_notify(struct rtl_priv
*rtlpriv
, u8
*tmp_buf
, u8 length
)
308 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
313 exhalbtc_bt_info_notify(btcoexist
, tmp_buf
, length
);
316 void rtl_btc_btmpinfo_notify(struct rtl_priv
*rtlpriv
, u8
*tmp_buf
, u8 length
)
318 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
327 if ((length
< 4) || (!tmp_buf
))
331 /* not response from BT FW then exit*/
332 if (extid
!= 1) /* C2H_TRIG_BY_BT_FW = 1 */
335 seq
= tmp_buf
[2] >> 4;
338 /* BT Firmware version response */
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];
344 btcoexist
->bt_info
.bt_real_fw_ver
= bt_real_fw_ver
;
345 btcoexist
->bt_info
.bt_fw_ver
= bt_fw_ver
;
347 case BT_SEQ_GET_AFH_MAP_L
:
348 btcoexist
->bt_info
.afh_map_l
= le32_to_cpu(*(__le32
*)data
);
350 case BT_SEQ_GET_AFH_MAP_M
:
351 btcoexist
->bt_info
.afh_map_m
= le32_to_cpu(*(__le32
*)data
);
353 case BT_SEQ_GET_AFH_MAP_H
:
354 btcoexist
->bt_info
.afh_map_h
= le16_to_cpu(*(__le16
*)data
);
356 case BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE
:
357 btcoexist
->bt_info
.bt_supported_feature
= tmp_buf
[3] |
360 case BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION
:
361 btcoexist
->bt_info
.bt_supported_version
= tmp_buf
[3] |
364 case BT_SEQ_GET_BT_ANT_DET_VAL
:
365 btcoexist
->bt_info
.bt_ant_det_val
= tmp_buf
[3];
367 case BT_SEQ_GET_BT_BLE_SCAN_PARA
:
368 btcoexist
->bt_info
.bt_ble_scan_para
= tmp_buf
[3] |
373 case BT_SEQ_GET_BT_BLE_SCAN_TYPE
:
374 btcoexist
->bt_info
.bt_ble_scan_type
= tmp_buf
[3];
376 case BT_SEQ_GET_BT_DEVICE_INFO
:
377 btcoexist
->bt_info
.bt_device_info
=
378 le32_to_cpu(*(__le32
*)data
);
380 case BT_OP_GET_BT_FORBIDDEN_SLOT_VAL
:
381 btcoexist
->bt_info
.bt_forb_slot_val
=
382 le32_to_cpu(*(__le32
*)data
);
386 RT_TRACE(rtlpriv
, COMP_BT_COEXIST
, DBG_LOUD
,
387 "btmpinfo complete req_num=%d\n", seq
);
389 complete(&btcoexist
->bt_mp_comp
);
392 bool rtl_btc_is_limited_dig(struct rtl_priv
*rtlpriv
)
394 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
399 return btcoexist
->bt_info
.limited_dig
;
402 bool rtl_btc_is_disable_edca_turbo(struct rtl_priv
*rtlpriv
)
404 bool bt_change_edca
= false;
406 u32 edca_bt_hs_uplink
= 0x5ea42b, edca_bt_hs_downlink
= 0x5ea42b;
408 u32 edca_addr
= 0x504;
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;
417 if (cur_edca_val
!= edca_bt_hs_downlink
) {
418 edca_hs
= edca_bt_hs_downlink
;
419 bt_change_edca
= true;
424 rtl_write_dword(rtlpriv
, edca_addr
, edca_hs
);
429 bool rtl_btc_is_bt_disabled(struct rtl_priv
*rtlpriv
)
431 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
436 /* It seems 'bt_disabled' is never be initialized or set. */
437 if (btcoexist
->bt_info
.bt_disabled
)
443 void rtl_btc_special_packet_notify(struct rtl_priv
*rtlpriv
, u8 pkt_type
)
445 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
450 return exhalbtc_special_packet_notify(btcoexist
, pkt_type
);
453 void rtl_btc_switch_band_notify(struct rtl_priv
*rtlpriv
, u8 band_type
,
456 struct btc_coexist
*btcoexist
= rtl_btc_coexist(rtlpriv
);
457 u8 type
= BTC_NOT_SWITCH
;
465 type
= BTC_SWITCH_TO_24G
;
467 type
= BTC_SWITCH_TO_24G_NOFORSCAN
;
471 type
= BTC_SWITCH_TO_5G
;
475 if (type
!= BTC_NOT_SWITCH
)
476 exhalbtc_switch_band_notify(btcoexist
, type
);
479 void rtl_btc_switch_band_notify_wifionly(struct rtl_priv
*rtlpriv
, u8 band_type
,
482 struct wifi_only_cfg
*wifionly_cfg
= rtl_btc_wifi_only(rtlpriv
);
483 u8 is_5g
= (band_type
== BAND_ON_5G
);
488 exhalbtc_switch_band_notify_wifi_only(wifionly_cfg
, is_5g
);
491 struct rtl_btc_ops
*rtl_btc_get_ops_pointer(void)
493 return &rtl_btc_operation
;
495 EXPORT_SYMBOL(rtl_btc_get_ops_pointer
);
498 enum rt_media_status
mgnt_link_status_query(struct ieee80211_hw
*hw
)
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
;
504 u8 bibss
= (mac
->opmode
== NL80211_IFTYPE_ADHOC
) ? 1 : 0;
506 if (bibss
|| rtlpriv
->mac80211
.link_state
>= MAC80211_LINKED
)
507 m_status
= RT_MEDIA_CONNECT
;
512 u8
rtl_get_hwpg_bt_exist(struct rtl_priv
*rtlpriv
)
514 return rtlpriv
->btcoexist
.btc_info
.btcoexist
;
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");
523 static int __init
rtl_btcoexist_module_init(void)
528 static void __exit
rtl_btcoexist_module_exit(void)
533 module_init(rtl_btcoexist_module_init
);
534 module_exit(rtl_btcoexist_module_exit
);