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