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, 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
 393bool 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
 403bool 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
 430bool 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
 444void 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
 454void 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
 480void 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
 492struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
 493{
 494        return &rtl_btc_operation;
 495}
 496EXPORT_SYMBOL(rtl_btc_get_ops_pointer);
 497
 498
 499enum 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
 513u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)
 514{
 515        return rtlpriv->btcoexist.btc_info.btcoexist;
 516}
 517
 518MODULE_AUTHOR("Page He  <page_he@realsil.com.cn>");
 519MODULE_AUTHOR("Realtek WlanFAE  <wlanfae@realtek.com>");
 520MODULE_AUTHOR("Larry Finger     <Larry.FInger@lwfinger.net>");
 521MODULE_LICENSE("GPL");
 522MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
 523
 524static int __init rtl_btcoexist_module_init(void)
 525{
 526        return 0;
 527}
 528
 529static void __exit rtl_btcoexist_module_exit(void)
 530{
 531        return;
 532}
 533
 534module_init(rtl_btcoexist_module_init);
 535module_exit(rtl_btcoexist_module_exit);
 536