linux/drivers/staging/rtlwifi/btcoexist/rtl_btc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2009-2013  Realtek Corporation.
   5 *
   6 * Contact Information:
   7 * wlanfae <wlanfae@realtek.com>
   8 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
   9 * Hsinchu 300, Taiwan.
  10 *
  11 * Larry Finger <Larry.Finger@lwfinger.net>
  12 *
  13 *****************************************************************************/
  14#include "../wifi.h"
  15#include <linux/vmalloc.h>
  16#include <linux/module.h>
  17
  18#include "rtl_btc.h"
  19#include "halbt_precomp.h"
  20
  21static struct rtl_btc_ops rtl_btc_operation = {
  22        .btc_init_variables = rtl_btc_init_variables,
  23        .btc_init_variables_wifi_only = rtl_btc_init_variables_wifi_only,
  24        .btc_deinit_variables = rtl_btc_deinit_variables,
  25        .btc_init_hal_vars = rtl_btc_init_hal_vars,
  26        .btc_power_on_setting = rtl_btc_power_on_setting,
  27        .btc_init_hw_config = rtl_btc_init_hw_config,
  28        .btc_init_hw_config_wifi_only = rtl_btc_init_hw_config_wifi_only,
  29        .btc_ips_notify = rtl_btc_ips_notify,
  30        .btc_lps_notify = rtl_btc_lps_notify,
  31        .btc_scan_notify = rtl_btc_scan_notify,
  32        .btc_scan_notify_wifi_only = rtl_btc_scan_notify_wifi_only,
  33        .btc_connect_notify = rtl_btc_connect_notify,
  34        .btc_mediastatus_notify = rtl_btc_mediastatus_notify,
  35        .btc_periodical = rtl_btc_periodical,
  36        .btc_halt_notify = rtl_btc_halt_notify,
  37        .btc_btinfo_notify = rtl_btc_btinfo_notify,
  38        .btc_btmpinfo_notify = rtl_btc_btmpinfo_notify,
  39        .btc_is_limited_dig = rtl_btc_is_limited_dig,
  40        .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
  41        .btc_is_bt_disabled = rtl_btc_is_bt_disabled,
  42        .btc_special_packet_notify = rtl_btc_special_packet_notify,
  43        .btc_switch_band_notify = rtl_btc_switch_band_notify,
  44        .btc_switch_band_notify_wifi_only = rtl_btc_switch_band_notify_wifionly,
  45        .btc_record_pwr_mode = rtl_btc_record_pwr_mode,
  46        .btc_get_lps_val = rtl_btc_get_lps_val,
  47        .btc_get_rpwm_val = rtl_btc_get_rpwm_val,
  48        .btc_is_bt_ctrl_lps = rtl_btc_is_bt_ctrl_lps,
  49        .btc_is_bt_lps_on = rtl_btc_is_bt_lps_on,
  50        .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg,
  51        .btc_display_bt_coex_info = rtl_btc_display_bt_coex_info,
  52};
  53
  54void rtl_btc_display_bt_coex_info(struct rtl_priv *rtlpriv, struct seq_file *m)
  55{
  56        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  57
  58        if (!btcoexist) {
  59                seq_puts(m, "btc_coexist context is NULL!\n");
  60                return;
  61        }
  62
  63        exhalbtc_display_bt_coex_info(btcoexist, m);
  64}
  65
  66void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len)
  67{
  68        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  69        u8 safe_len;
  70
  71        if (!btcoexist)
  72                return;
  73
  74        safe_len = sizeof(btcoexist->pwr_mode_val);
  75
  76        if (safe_len > len)
  77                safe_len = len;
  78
  79        memcpy(btcoexist->pwr_mode_val, buf, safe_len);
  80}
  81
  82u8 rtl_btc_get_lps_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.lps_val;
  90}
  91
  92u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv)
  93{
  94        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
  95
  96        if (!btcoexist)
  97                return 0;
  98
  99        return btcoexist->bt_info.rpwm_val;
 100}
 101
 102bool rtl_btc_is_bt_ctrl_lps(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_ctrl_lps;
 110}
 111
 112bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv)
 113{
 114        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 115
 116        if (!btcoexist)
 117                return false;
 118
 119        return btcoexist->bt_info.bt_lps_on;
 120}
 121
 122void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg,
 123                           u8 *ctrl_agg_size, u8 *agg_size)
 124{
 125        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 126
 127        if (!btcoexist) {
 128                *reject_agg = false;
 129                *ctrl_agg_size = false;
 130                return;
 131        }
 132
 133        if (reject_agg)
 134                *reject_agg = btcoexist->bt_info.reject_agg_pkt;
 135        if (ctrl_agg_size)
 136                *ctrl_agg_size = btcoexist->bt_info.bt_ctrl_agg_buf_size;
 137        if (agg_size)
 138                *agg_size = btcoexist->bt_info.agg_buf_size;
 139}
 140
 141static void rtl_btc_alloc_variable(struct rtl_priv *rtlpriv, bool wifi_only)
 142{
 143        if (wifi_only)
 144                rtlpriv->btcoexist.wifi_only_context =
 145                        kzalloc(sizeof(struct wifi_only_cfg), GFP_KERNEL);
 146        else
 147                rtlpriv->btcoexist.btc_context =
 148                        kzalloc(sizeof(struct btc_coexist), GFP_KERNEL);
 149}
 150
 151static void rtl_btc_free_variable(struct rtl_priv *rtlpriv)
 152{
 153        kfree(rtlpriv->btcoexist.btc_context);
 154        rtlpriv->btcoexist.btc_context = NULL;
 155
 156        kfree(rtlpriv->btcoexist.wifi_only_context);
 157        rtlpriv->btcoexist.wifi_only_context = NULL;
 158}
 159
 160void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
 161{
 162        rtl_btc_alloc_variable(rtlpriv, false);
 163
 164        exhalbtc_initlize_variables(rtlpriv);
 165        exhalbtc_bind_bt_coex_withadapter(rtlpriv);
 166}
 167
 168void rtl_btc_init_variables_wifi_only(struct rtl_priv *rtlpriv)
 169{
 170        rtl_btc_alloc_variable(rtlpriv, true);
 171
 172        exhalbtc_initlize_variables_wifi_only(rtlpriv);
 173}
 174
 175void rtl_btc_deinit_variables(struct rtl_priv *rtlpriv)
 176{
 177        rtl_btc_free_variable(rtlpriv);
 178}
 179
 180void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv)
 181{
 182        /* move ant_num, bt_type and single_ant_path to
 183         * exhalbtc_bind_bt_coex_withadapter()
 184         */
 185}
 186
 187void rtl_btc_power_on_setting(struct rtl_priv *rtlpriv)
 188{
 189        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 190
 191        if (!btcoexist)
 192                return;
 193
 194        exhalbtc_power_on_setting(btcoexist);
 195}
 196
 197void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
 198{
 199        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 200
 201        u8 bt_exist;
 202
 203        bt_exist = rtl_get_hwpg_bt_exist(rtlpriv);
 204        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 205                 "%s, bt_exist is %d\n", __func__, bt_exist);
 206
 207        if (!btcoexist)
 208                return;
 209
 210        exhalbtc_init_hw_config(btcoexist, !bt_exist);
 211        exhalbtc_init_coex_dm(btcoexist);
 212}
 213
 214void rtl_btc_init_hw_config_wifi_only(struct rtl_priv *rtlpriv)
 215{
 216        struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
 217
 218        if (!wifionly_cfg)
 219                return;
 220
 221        exhalbtc_init_hw_config_wifi_only(wifionly_cfg);
 222}
 223
 224void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
 225{
 226        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 227
 228        if (!btcoexist)
 229                return;
 230
 231        exhalbtc_ips_notify(btcoexist, type);
 232
 233        if (type == ERFON) {
 234                /*
 235                 * In some situation, it doesn't scan after leaving IPS, and
 236                 * this will cause btcoex in wrong state.
 237                 */
 238                exhalbtc_scan_notify(btcoexist, 1);
 239                exhalbtc_scan_notify(btcoexist, 0);
 240        }
 241}
 242
 243void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type)
 244{
 245        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 246
 247        if (!btcoexist)
 248                return;
 249
 250        exhalbtc_lps_notify(btcoexist, type);
 251}
 252
 253void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
 254{
 255        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 256
 257        if (!btcoexist)
 258                return;
 259
 260        exhalbtc_scan_notify(btcoexist, scantype);
 261}
 262
 263void rtl_btc_scan_notify_wifi_only(struct rtl_priv *rtlpriv, u8 scantype)
 264{
 265        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 266        struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
 267        u8 is_5g = (rtlhal->current_bandtype == BAND_ON_5G);
 268
 269        if (!wifionly_cfg)
 270                return;
 271
 272        exhalbtc_scan_notify_wifi_only(wifionly_cfg, is_5g);
 273}
 274
 275void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
 276{
 277        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 278
 279        if (!btcoexist)
 280                return;
 281
 282        exhalbtc_connect_notify(btcoexist, action);
 283}
 284
 285void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
 286                                enum rt_media_status mstatus)
 287{
 288        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 289
 290        if (!btcoexist)
 291                return;
 292
 293        exhalbtc_mediastatus_notify(btcoexist, mstatus);
 294}
 295
 296void rtl_btc_periodical(struct rtl_priv *rtlpriv)
 297{
 298        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 299
 300        if (!btcoexist)
 301                return;
 302
 303        /*rtl_bt_dm_monitor();*/
 304        exhalbtc_periodical(btcoexist);
 305}
 306
 307void rtl_btc_halt_notify(struct rtl_priv *rtlpriv)
 308{
 309        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 310
 311        if (!btcoexist)
 312                return;
 313
 314        exhalbtc_halt_notify(btcoexist);
 315}
 316
 317void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
 318{
 319        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 320
 321        if (!btcoexist)
 322                return;
 323
 324        exhalbtc_bt_info_notify(btcoexist, tmp_buf, length);
 325}
 326
 327void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
 328{
 329        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 330        u8 extid, seq, len;
 331        u16 bt_real_fw_ver;
 332        u8 bt_fw_ver;
 333        u8 *data;
 334
 335        if (!btcoexist)
 336                return;
 337
 338        if ((length < 4) || (!tmp_buf))
 339                return;
 340
 341        extid = tmp_buf[0];
 342        /* not response from BT FW then exit*/
 343        if (extid != 1) /* C2H_TRIG_BY_BT_FW = 1 */
 344                return;
 345
 346        len = tmp_buf[1] >> 4;
 347        seq = tmp_buf[2] >> 4;
 348        data = &tmp_buf[3];
 349
 350        /* BT Firmware version response */
 351        switch (seq) {
 352        case BT_SEQ_GET_BT_VERSION:
 353                bt_real_fw_ver = tmp_buf[3] | (tmp_buf[4] << 8);
 354                bt_fw_ver = tmp_buf[5];
 355
 356                btcoexist->bt_info.bt_real_fw_ver = bt_real_fw_ver;
 357                btcoexist->bt_info.bt_fw_ver = bt_fw_ver;
 358                break;
 359        case BT_SEQ_GET_AFH_MAP_L:
 360                btcoexist->bt_info.afh_map_l = le32_to_cpu(*(__le32 *)data);
 361                break;
 362        case BT_SEQ_GET_AFH_MAP_M:
 363                btcoexist->bt_info.afh_map_m = le32_to_cpu(*(__le32 *)data);
 364                break;
 365        case BT_SEQ_GET_AFH_MAP_H:
 366                btcoexist->bt_info.afh_map_h = le16_to_cpu(*(__le16 *)data);
 367                break;
 368        case BT_SEQ_GET_BT_COEX_SUPPORTED_FEATURE:
 369                btcoexist->bt_info.bt_supported_feature = tmp_buf[3] |
 370                                                          (tmp_buf[4] << 8);
 371                break;
 372        case BT_SEQ_GET_BT_COEX_SUPPORTED_VERSION:
 373                btcoexist->bt_info.bt_supported_version = tmp_buf[3] |
 374                                                          (tmp_buf[4] << 8);
 375                break;
 376        case BT_SEQ_GET_BT_ANT_DET_VAL:
 377                btcoexist->bt_info.bt_ant_det_val = tmp_buf[3];
 378                break;
 379        case BT_SEQ_GET_BT_BLE_SCAN_PARA:
 380                btcoexist->bt_info.bt_ble_scan_para = tmp_buf[3] |
 381                                                      (tmp_buf[4] << 8) |
 382                                                      (tmp_buf[5] << 16) |
 383                                                      (tmp_buf[6] << 24);
 384                break;
 385        case BT_SEQ_GET_BT_BLE_SCAN_TYPE:
 386                btcoexist->bt_info.bt_ble_scan_type = tmp_buf[3];
 387                break;
 388        }
 389
 390        RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
 391                 "btmpinfo complete req_num=%d\n", seq);
 392
 393        complete(&btcoexist->bt_mp_comp);
 394}
 395
 396bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv)
 397{
 398        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 399
 400        if (!btcoexist)
 401                return false;
 402
 403        return btcoexist->bt_info.limited_dig;
 404}
 405
 406bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
 407{
 408        bool bt_change_edca = false;
 409        u32 cur_edca_val;
 410        u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b;
 411        u32 edca_hs;
 412        u32 edca_addr = 0x504;
 413
 414        cur_edca_val = rtl_read_dword(rtlpriv, edca_addr);
 415        if (halbtc_is_wifi_uplink(rtlpriv)) {
 416                if (cur_edca_val != edca_bt_hs_uplink) {
 417                        edca_hs = edca_bt_hs_uplink;
 418                        bt_change_edca = true;
 419                }
 420        } else {
 421                if (cur_edca_val != edca_bt_hs_downlink) {
 422                        edca_hs = edca_bt_hs_downlink;
 423                        bt_change_edca = true;
 424                }
 425        }
 426
 427        if (bt_change_edca)
 428                rtl_write_dword(rtlpriv, edca_addr, edca_hs);
 429
 430        return true;
 431}
 432
 433bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
 434{
 435        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 436
 437        if (!btcoexist)
 438                return true;
 439
 440        /* It seems 'bt_disabled' is never be initialized or set. */
 441        if (btcoexist->bt_info.bt_disabled)
 442                return true;
 443        else
 444                return false;
 445}
 446
 447void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
 448{
 449        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 450
 451        if (!btcoexist)
 452                return;
 453
 454        return exhalbtc_special_packet_notify(btcoexist, pkt_type);
 455}
 456
 457void rtl_btc_switch_band_notify(struct rtl_priv *rtlpriv, u8 band_type,
 458                                bool scanning)
 459{
 460        struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
 461        u8 type = BTC_NOT_SWITCH;
 462
 463        if (!btcoexist)
 464                return;
 465
 466        switch (band_type) {
 467        case BAND_ON_2_4G:
 468                if (scanning)
 469                        type = BTC_SWITCH_TO_24G;
 470                else
 471                        type = BTC_SWITCH_TO_24G_NOFORSCAN;
 472                break;
 473
 474        case BAND_ON_5G:
 475                type = BTC_SWITCH_TO_5G;
 476                break;
 477        }
 478
 479        if (type != BTC_NOT_SWITCH)
 480                exhalbtc_switch_band_notify(btcoexist, type);
 481}
 482
 483void rtl_btc_switch_band_notify_wifionly(struct rtl_priv *rtlpriv, u8 band_type,
 484                                         bool scanning)
 485{
 486        struct wifi_only_cfg *wifionly_cfg = rtl_btc_wifi_only(rtlpriv);
 487        u8 is_5g = (band_type == BAND_ON_5G);
 488
 489        if (!wifionly_cfg)
 490                return;
 491
 492        exhalbtc_switch_band_notify_wifi_only(wifionly_cfg, is_5g);
 493}
 494
 495struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
 496{
 497        return &rtl_btc_operation;
 498}
 499
 500enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
 501{
 502        struct rtl_priv *rtlpriv = rtl_priv(hw);
 503        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 504        enum rt_media_status    m_status = RT_MEDIA_DISCONNECT;
 505
 506        u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
 507
 508        if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
 509                m_status = RT_MEDIA_CONNECT;
 510
 511        return m_status;
 512}
 513
 514u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)
 515{
 516        return rtlpriv->btcoexist.btc_info.btcoexist;
 517}
 518