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