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