linux/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
<<
>>
Prefs
   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
  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        else
 137                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 to
 173         * 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        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
 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, 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
 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        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
 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        else
 440                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                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
 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