linux/drivers/net/wireless/realtek/rtw88/mac80211.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/* Copyright(c) 2018-2019  Realtek Corporation
   3 */
   4
   5#include "main.h"
   6#include "sec.h"
   7#include "tx.h"
   8#include "fw.h"
   9#include "mac.h"
  10#include "coex.h"
  11#include "ps.h"
  12#include "reg.h"
  13#include "debug.h"
  14
  15static void rtw_ops_tx(struct ieee80211_hw *hw,
  16                       struct ieee80211_tx_control *control,
  17                       struct sk_buff *skb)
  18{
  19        struct rtw_dev *rtwdev = hw->priv;
  20        struct rtw_tx_pkt_info pkt_info = {0};
  21
  22        if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING))
  23                goto out;
  24
  25        rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb);
  26        if (rtw_hci_tx(rtwdev, &pkt_info, skb))
  27                goto out;
  28
  29        return;
  30
  31out:
  32        ieee80211_free_txskb(hw, skb);
  33}
  34
  35static int rtw_ops_start(struct ieee80211_hw *hw)
  36{
  37        struct rtw_dev *rtwdev = hw->priv;
  38        int ret;
  39
  40        mutex_lock(&rtwdev->mutex);
  41        ret = rtw_core_start(rtwdev);
  42        mutex_unlock(&rtwdev->mutex);
  43
  44        return ret;
  45}
  46
  47static void rtw_ops_stop(struct ieee80211_hw *hw)
  48{
  49        struct rtw_dev *rtwdev = hw->priv;
  50
  51        mutex_lock(&rtwdev->mutex);
  52        rtw_core_stop(rtwdev);
  53        mutex_unlock(&rtwdev->mutex);
  54}
  55
  56static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
  57{
  58        struct rtw_dev *rtwdev = hw->priv;
  59        int ret = 0;
  60
  61        mutex_lock(&rtwdev->mutex);
  62
  63        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
  64                if (hw->conf.flags & IEEE80211_CONF_IDLE) {
  65                        rtw_enter_ips(rtwdev);
  66                } else {
  67                        ret = rtw_leave_ips(rtwdev);
  68                        if (ret) {
  69                                rtw_err(rtwdev, "failed to leave idle state\n");
  70                                goto out;
  71                        }
  72                }
  73        }
  74
  75        if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
  76                rtw_set_channel(rtwdev);
  77
  78out:
  79        mutex_unlock(&rtwdev->mutex);
  80        return ret;
  81}
  82
  83static const struct rtw_vif_port rtw_vif_port[] = {
  84        [0] = {
  85                .mac_addr       = {.addr = 0x0610},
  86                .bssid          = {.addr = 0x0618},
  87                .net_type       = {.addr = 0x0100, .mask = 0x30000},
  88                .aid            = {.addr = 0x06a8, .mask = 0x7ff},
  89                .bcn_ctrl       = {.addr = 0x0550, .mask = 0xff},
  90        },
  91        [1] = {
  92                .mac_addr       = {.addr = 0x0700},
  93                .bssid          = {.addr = 0x0708},
  94                .net_type       = {.addr = 0x0100, .mask = 0xc0000},
  95                .aid            = {.addr = 0x0710, .mask = 0x7ff},
  96                .bcn_ctrl       = {.addr = 0x0551, .mask = 0xff},
  97        },
  98        [2] = {
  99                .mac_addr       = {.addr = 0x1620},
 100                .bssid          = {.addr = 0x1628},
 101                .net_type       = {.addr = 0x1100, .mask = 0x3},
 102                .aid            = {.addr = 0x1600, .mask = 0x7ff},
 103                .bcn_ctrl       = {.addr = 0x0578, .mask = 0xff},
 104        },
 105        [3] = {
 106                .mac_addr       = {.addr = 0x1630},
 107                .bssid          = {.addr = 0x1638},
 108                .net_type       = {.addr = 0x1100, .mask = 0xc},
 109                .aid            = {.addr = 0x1604, .mask = 0x7ff},
 110                .bcn_ctrl       = {.addr = 0x0579, .mask = 0xff},
 111        },
 112        [4] = {
 113                .mac_addr       = {.addr = 0x1640},
 114                .bssid          = {.addr = 0x1648},
 115                .net_type       = {.addr = 0x1100, .mask = 0x30},
 116                .aid            = {.addr = 0x1608, .mask = 0x7ff},
 117                .bcn_ctrl       = {.addr = 0x057a, .mask = 0xff},
 118        },
 119};
 120
 121static int rtw_ops_add_interface(struct ieee80211_hw *hw,
 122                                 struct ieee80211_vif *vif)
 123{
 124        struct rtw_dev *rtwdev = hw->priv;
 125        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
 126        enum rtw_net_type net_type;
 127        u32 config = 0;
 128        u8 port = 0;
 129        u8 bcn_ctrl = 0;
 130
 131        rtwvif->port = port;
 132        rtwvif->vif = vif;
 133        rtwvif->stats.tx_unicast = 0;
 134        rtwvif->stats.rx_unicast = 0;
 135        rtwvif->stats.tx_cnt = 0;
 136        rtwvif->stats.rx_cnt = 0;
 137        rtwvif->in_lps = false;
 138        rtwvif->conf = &rtw_vif_port[port];
 139
 140        mutex_lock(&rtwdev->mutex);
 141
 142        switch (vif->type) {
 143        case NL80211_IFTYPE_AP:
 144        case NL80211_IFTYPE_MESH_POINT:
 145                net_type = RTW_NET_AP_MODE;
 146                bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
 147                break;
 148        case NL80211_IFTYPE_ADHOC:
 149                net_type = RTW_NET_AD_HOC;
 150                bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
 151                break;
 152        case NL80211_IFTYPE_STATION:
 153        default:
 154                net_type = RTW_NET_NO_LINK;
 155                bcn_ctrl = BIT_EN_BCN_FUNCTION;
 156                break;
 157        }
 158
 159        ether_addr_copy(rtwvif->mac_addr, vif->addr);
 160        config |= PORT_SET_MAC_ADDR;
 161        rtwvif->net_type = net_type;
 162        config |= PORT_SET_NET_TYPE;
 163        rtwvif->bcn_ctrl = bcn_ctrl;
 164        config |= PORT_SET_BCN_CTRL;
 165        rtw_vif_port_config(rtwdev, rtwvif, config);
 166
 167        mutex_unlock(&rtwdev->mutex);
 168
 169        rtw_info(rtwdev, "start vif %pM on port %d\n", vif->addr, rtwvif->port);
 170        return 0;
 171}
 172
 173static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
 174                                     struct ieee80211_vif *vif)
 175{
 176        struct rtw_dev *rtwdev = hw->priv;
 177        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
 178        u32 config = 0;
 179
 180        rtw_info(rtwdev, "stop vif %pM on port %d\n", vif->addr, rtwvif->port);
 181
 182        mutex_lock(&rtwdev->mutex);
 183
 184        eth_zero_addr(rtwvif->mac_addr);
 185        config |= PORT_SET_MAC_ADDR;
 186        rtwvif->net_type = RTW_NET_NO_LINK;
 187        config |= PORT_SET_NET_TYPE;
 188        rtwvif->bcn_ctrl = 0;
 189        config |= PORT_SET_BCN_CTRL;
 190        rtw_vif_port_config(rtwdev, rtwvif, config);
 191
 192        mutex_unlock(&rtwdev->mutex);
 193}
 194
 195static void rtw_ops_configure_filter(struct ieee80211_hw *hw,
 196                                     unsigned int changed_flags,
 197                                     unsigned int *new_flags,
 198                                     u64 multicast)
 199{
 200        struct rtw_dev *rtwdev = hw->priv;
 201
 202        *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL |
 203                      FIF_BCN_PRBRESP_PROMISC;
 204
 205        mutex_lock(&rtwdev->mutex);
 206
 207        if (changed_flags & FIF_ALLMULTI) {
 208                if (*new_flags & FIF_ALLMULTI)
 209                        rtwdev->hal.rcr |= BIT_AM | BIT_AB;
 210                else
 211                        rtwdev->hal.rcr &= ~(BIT_AM | BIT_AB);
 212        }
 213        if (changed_flags & FIF_FCSFAIL) {
 214                if (*new_flags & FIF_FCSFAIL)
 215                        rtwdev->hal.rcr |= BIT_ACRC32;
 216                else
 217                        rtwdev->hal.rcr &= ~(BIT_ACRC32);
 218        }
 219        if (changed_flags & FIF_OTHER_BSS) {
 220                if (*new_flags & FIF_OTHER_BSS)
 221                        rtwdev->hal.rcr |= BIT_AAP;
 222                else
 223                        rtwdev->hal.rcr &= ~(BIT_AAP);
 224        }
 225        if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
 226                if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
 227                        rtwdev->hal.rcr &= ~(BIT_CBSSID_BCN | BIT_CBSSID_DATA);
 228                else
 229                        rtwdev->hal.rcr |= BIT_CBSSID_BCN;
 230        }
 231
 232        rtw_dbg(rtwdev, RTW_DBG_RX,
 233                "config rx filter, changed=0x%08x, new=0x%08x, rcr=0x%08x\n",
 234                changed_flags, *new_flags, rtwdev->hal.rcr);
 235
 236        rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);
 237
 238        mutex_unlock(&rtwdev->mutex);
 239}
 240
 241static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
 242                                     struct ieee80211_vif *vif,
 243                                     struct ieee80211_bss_conf *conf,
 244                                     u32 changed)
 245{
 246        struct rtw_dev *rtwdev = hw->priv;
 247        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
 248        u32 config = 0;
 249
 250        mutex_lock(&rtwdev->mutex);
 251
 252        if (changed & BSS_CHANGED_ASSOC) {
 253                struct rtw_chip_info *chip = rtwdev->chip;
 254                enum rtw_net_type net_type;
 255
 256                if (conf->assoc) {
 257                        rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH);
 258                        net_type = RTW_NET_MGD_LINKED;
 259                        chip->ops->phy_calibration(rtwdev);
 260
 261                        rtwvif->aid = conf->aid;
 262                        rtw_add_rsvd_page(rtwdev, RSVD_PS_POLL, true);
 263                        rtw_add_rsvd_page(rtwdev, RSVD_QOS_NULL, true);
 264                        rtw_add_rsvd_page(rtwdev, RSVD_NULL, true);
 265                        rtw_fw_download_rsvd_page(rtwdev, vif);
 266                        rtw_send_rsvd_page_h2c(rtwdev);
 267                        rtw_coex_media_status_notify(rtwdev, conf->assoc);
 268                } else {
 269                        net_type = RTW_NET_NO_LINK;
 270                        rtwvif->aid = 0;
 271                        rtw_reset_rsvd_page(rtwdev);
 272                }
 273
 274                rtwvif->net_type = net_type;
 275                config |= PORT_SET_NET_TYPE;
 276                config |= PORT_SET_AID;
 277        }
 278
 279        if (changed & BSS_CHANGED_BSSID) {
 280                ether_addr_copy(rtwvif->bssid, conf->bssid);
 281                config |= PORT_SET_BSSID;
 282        }
 283
 284        if (changed & BSS_CHANGED_BEACON)
 285                rtw_fw_download_rsvd_page(rtwdev, vif);
 286
 287        rtw_vif_port_config(rtwdev, rtwvif, config);
 288
 289        mutex_unlock(&rtwdev->mutex);
 290}
 291
 292static u8 rtw_acquire_macid(struct rtw_dev *rtwdev)
 293{
 294        unsigned long mac_id;
 295
 296        mac_id = find_first_zero_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM);
 297        if (mac_id < RTW_MAX_MAC_ID_NUM)
 298                set_bit(mac_id, rtwdev->mac_id_map);
 299
 300        return mac_id;
 301}
 302
 303static void rtw_release_macid(struct rtw_dev *rtwdev, u8 mac_id)
 304{
 305        clear_bit(mac_id, rtwdev->mac_id_map);
 306}
 307
 308static int rtw_ops_sta_add(struct ieee80211_hw *hw,
 309                           struct ieee80211_vif *vif,
 310                           struct ieee80211_sta *sta)
 311{
 312        struct rtw_dev *rtwdev = hw->priv;
 313        struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
 314        int ret = 0;
 315
 316        mutex_lock(&rtwdev->mutex);
 317
 318        si->mac_id = rtw_acquire_macid(rtwdev);
 319        if (si->mac_id >= RTW_MAX_MAC_ID_NUM) {
 320                ret = -ENOSPC;
 321                goto out;
 322        }
 323
 324        si->sta = sta;
 325        si->vif = vif;
 326        si->init_ra_lv = 1;
 327        ewma_rssi_init(&si->avg_rssi);
 328
 329        rtw_update_sta_info(rtwdev, si);
 330        rtw_fw_media_status_report(rtwdev, si->mac_id, true);
 331
 332        rtwdev->sta_cnt++;
 333
 334        rtw_info(rtwdev, "sta %pM joined with macid %d\n",
 335                 sta->addr, si->mac_id);
 336
 337out:
 338        mutex_unlock(&rtwdev->mutex);
 339        return ret;
 340}
 341
 342static int rtw_ops_sta_remove(struct ieee80211_hw *hw,
 343                              struct ieee80211_vif *vif,
 344                              struct ieee80211_sta *sta)
 345{
 346        struct rtw_dev *rtwdev = hw->priv;
 347        struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
 348
 349        mutex_lock(&rtwdev->mutex);
 350
 351        rtw_release_macid(rtwdev, si->mac_id);
 352        rtw_fw_media_status_report(rtwdev, si->mac_id, false);
 353
 354        rtwdev->sta_cnt--;
 355
 356        rtw_info(rtwdev, "sta %pM with macid %d left\n",
 357                 sta->addr, si->mac_id);
 358
 359        mutex_unlock(&rtwdev->mutex);
 360        return 0;
 361}
 362
 363static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 364                           struct ieee80211_vif *vif, struct ieee80211_sta *sta,
 365                           struct ieee80211_key_conf *key)
 366{
 367        struct rtw_dev *rtwdev = hw->priv;
 368        struct rtw_sec_desc *sec = &rtwdev->sec;
 369        u8 hw_key_type;
 370        u8 hw_key_idx;
 371        int ret = 0;
 372
 373        switch (key->cipher) {
 374        case WLAN_CIPHER_SUITE_WEP40:
 375                hw_key_type = RTW_CAM_WEP40;
 376                break;
 377        case WLAN_CIPHER_SUITE_WEP104:
 378                hw_key_type = RTW_CAM_WEP104;
 379                break;
 380        case WLAN_CIPHER_SUITE_TKIP:
 381                hw_key_type = RTW_CAM_TKIP;
 382                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 383                break;
 384        case WLAN_CIPHER_SUITE_CCMP:
 385                hw_key_type = RTW_CAM_AES;
 386                key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
 387                break;
 388        case WLAN_CIPHER_SUITE_AES_CMAC:
 389        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 390        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 391        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
 392                /* suppress error messages */
 393                return -EOPNOTSUPP;
 394        default:
 395                return -ENOTSUPP;
 396        }
 397
 398        mutex_lock(&rtwdev->mutex);
 399
 400        if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
 401                hw_key_idx = rtw_sec_get_free_cam(sec);
 402        } else {
 403                /* multiple interfaces? */
 404                hw_key_idx = key->keyidx;
 405        }
 406
 407        if (hw_key_idx > sec->total_cam_num) {
 408                ret = -ENOSPC;
 409                goto out;
 410        }
 411
 412        switch (cmd) {
 413        case SET_KEY:
 414                /* need sw generated IV */
 415                key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 416                key->hw_key_idx = hw_key_idx;
 417                rtw_sec_write_cam(rtwdev, sec, sta, key,
 418                                  hw_key_type, hw_key_idx);
 419                break;
 420        case DISABLE_KEY:
 421                rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx);
 422                break;
 423        }
 424
 425out:
 426        mutex_unlock(&rtwdev->mutex);
 427
 428        return ret;
 429}
 430
 431static int rtw_ops_ampdu_action(struct ieee80211_hw *hw,
 432                                struct ieee80211_vif *vif,
 433                                struct ieee80211_ampdu_params *params)
 434{
 435        struct ieee80211_sta *sta = params->sta;
 436        u16 tid = params->tid;
 437
 438        switch (params->action) {
 439        case IEEE80211_AMPDU_TX_START:
 440                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 441                break;
 442        case IEEE80211_AMPDU_TX_STOP_CONT:
 443        case IEEE80211_AMPDU_TX_STOP_FLUSH:
 444        case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 445                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 446                break;
 447        case IEEE80211_AMPDU_TX_OPERATIONAL:
 448        case IEEE80211_AMPDU_RX_START:
 449        case IEEE80211_AMPDU_RX_STOP:
 450                break;
 451        default:
 452                WARN_ON(1);
 453                return -ENOTSUPP;
 454        }
 455
 456        return 0;
 457}
 458
 459static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw,
 460                                  struct ieee80211_vif *vif,
 461                                  const u8 *mac_addr)
 462{
 463        struct rtw_dev *rtwdev = hw->priv;
 464        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
 465        u32 config = 0;
 466
 467        rtw_leave_lps(rtwdev, rtwvif);
 468
 469        mutex_lock(&rtwdev->mutex);
 470
 471        ether_addr_copy(rtwvif->mac_addr, mac_addr);
 472        config |= PORT_SET_MAC_ADDR;
 473        rtw_vif_port_config(rtwdev, rtwvif, config);
 474
 475        rtw_coex_scan_notify(rtwdev, COEX_SCAN_START);
 476
 477        rtw_flag_set(rtwdev, RTW_FLAG_DIG_DISABLE);
 478        rtw_flag_set(rtwdev, RTW_FLAG_SCANNING);
 479
 480        mutex_unlock(&rtwdev->mutex);
 481}
 482
 483static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
 484                                     struct ieee80211_vif *vif)
 485{
 486        struct rtw_dev *rtwdev = hw->priv;
 487        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
 488        u32 config = 0;
 489
 490        mutex_lock(&rtwdev->mutex);
 491
 492        rtw_flag_clear(rtwdev, RTW_FLAG_SCANNING);
 493        rtw_flag_clear(rtwdev, RTW_FLAG_DIG_DISABLE);
 494
 495        ether_addr_copy(rtwvif->mac_addr, vif->addr);
 496        config |= PORT_SET_MAC_ADDR;
 497        rtw_vif_port_config(rtwdev, rtwvif, config);
 498
 499        rtw_coex_scan_notify(rtwdev, COEX_SCAN_FINISH);
 500
 501        mutex_unlock(&rtwdev->mutex);
 502}
 503
 504static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,
 505                                   struct ieee80211_vif *vif,
 506                                   u16 duration)
 507{
 508        struct rtw_dev *rtwdev = hw->priv;
 509
 510        mutex_lock(&rtwdev->mutex);
 511        rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START);
 512        mutex_unlock(&rtwdev->mutex);
 513}
 514
 515const struct ieee80211_ops rtw_ops = {
 516        .tx                     = rtw_ops_tx,
 517        .start                  = rtw_ops_start,
 518        .stop                   = rtw_ops_stop,
 519        .config                 = rtw_ops_config,
 520        .add_interface          = rtw_ops_add_interface,
 521        .remove_interface       = rtw_ops_remove_interface,
 522        .configure_filter       = rtw_ops_configure_filter,
 523        .bss_info_changed       = rtw_ops_bss_info_changed,
 524        .sta_add                = rtw_ops_sta_add,
 525        .sta_remove             = rtw_ops_sta_remove,
 526        .set_key                = rtw_ops_set_key,
 527        .ampdu_action           = rtw_ops_ampdu_action,
 528        .sw_scan_start          = rtw_ops_sw_scan_start,
 529        .sw_scan_complete       = rtw_ops_sw_scan_complete,
 530        .mgd_prepare_tx         = rtw_ops_mgd_prepare_tx,
 531};
 532EXPORT_SYMBOL(rtw_ops);
 533