535 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 11static 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 44void 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 56void 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 72u8 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 82u8 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 92bool 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 102bool 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 112void 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 131static 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 else137 rtlpriv->btcoexist.btc_context =138 kzalloc(sizeof(struct btc_coexist), GFP_KERNEL);139}140 141static 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 150void 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 158void 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 165void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv)166{167 rtl_btc_free_variable(rtlpriv);168}169 170void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv)171{172 /* move ant_num, bt_type and single_ant_path to173 * exhalbtc_bind_bt_coex_withadapter()174 */175}176 177void 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 187void 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 rtl_dbg(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 204void 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 214void 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, and225 * this will cause btcoex in wrong state.226 */227 exhalbtc_scan_notify(btcoexist, 1);228 exhalbtc_scan_notify(btcoexist, 0);229 }230}231 232void 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 242void 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 252void 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 264void 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 274void 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 285void 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 296void 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 306void 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 316void 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 rtl_dbg(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,387 "btmpinfo complete req_num=%d\n", seq);388 389 complete(&btcoexist->bt_mp_comp);390}391 392bool 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 402bool 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 429bool 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 else440 return false;441}442 443void 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 453void 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 else467 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 479void 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 491struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)492{493 return &rtl_btc_operation;494}495EXPORT_SYMBOL(rtl_btc_get_ops_pointer);496 497 498enum 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 512u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)513{514 return rtlpriv->btcoexist.btc_info.btcoexist;515}516 517MODULE_AUTHOR("Page He <page_he@realsil.com.cn>");518MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");519MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");520MODULE_LICENSE("GPL");521MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");522 523static int __init rtl_btcoexist_module_init(void)524{525 return 0;526}527 528static void __exit rtl_btcoexist_module_exit(void)529{530 return;531}532 533module_init(rtl_btcoexist_module_init);534module_exit(rtl_btcoexist_module_exit);535