linux/drivers/staging/wfx/hif_tx_mib.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API.
   4 *
   5 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
   6 * Copyright (c) 2010, ST-Ericsson
   7 * Copyright (C) 2010, ST-Ericsson SA
   8 */
   9
  10#include <linux/etherdevice.h>
  11
  12#include "wfx.h"
  13#include "hif_tx.h"
  14#include "hif_tx_mib.h"
  15#include "hif_api_mib.h"
  16
  17int hif_set_output_power(struct wfx_vif *wvif, int val)
  18{
  19        struct hif_mib_current_tx_power_level arg = {
  20                .power_level = cpu_to_le32(val * 10),
  21        };
  22
  23        return hif_write_mib(wvif->wdev, wvif->id,
  24                             HIF_MIB_ID_CURRENT_TX_POWER_LEVEL,
  25                             &arg, sizeof(arg));
  26}
  27
  28int hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
  29                                 unsigned int dtim_interval,
  30                                 unsigned int listen_interval)
  31{
  32        struct hif_mib_beacon_wake_up_period val = {
  33                .wakeup_period_min = dtim_interval,
  34                .receive_dtim = 0,
  35                .wakeup_period_max = listen_interval,
  36        };
  37
  38        if (dtim_interval > 0xFF || listen_interval > 0xFFFF)
  39                return -EINVAL;
  40        return hif_write_mib(wvif->wdev, wvif->id,
  41                             HIF_MIB_ID_BEACON_WAKEUP_PERIOD,
  42                             &val, sizeof(val));
  43}
  44
  45int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif,
  46                                int rssi_thold, int rssi_hyst)
  47{
  48        struct hif_mib_rcpi_rssi_threshold arg = {
  49                .rolling_average_count = 8,
  50                .detection = 1,
  51        };
  52
  53        if (!rssi_thold && !rssi_hyst) {
  54                arg.upperthresh = 1;
  55                arg.lowerthresh = 1;
  56        } else {
  57                arg.upper_threshold = rssi_thold + rssi_hyst;
  58                arg.upper_threshold = (arg.upper_threshold + 110) * 2;
  59                arg.lower_threshold = rssi_thold;
  60                arg.lower_threshold = (arg.lower_threshold + 110) * 2;
  61        }
  62
  63        return hif_write_mib(wvif->wdev, wvif->id,
  64                             HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg));
  65}
  66
  67int hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
  68                           struct hif_mib_extended_count_table *arg)
  69{
  70        if (wfx_api_older_than(wdev, 1, 3)) {
  71                // extended_count_table is wider than count_table
  72                memset(arg, 0xFF, sizeof(*arg));
  73                return hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE,
  74                                    arg, sizeof(struct hif_mib_count_table));
  75        } else {
  76                return hif_read_mib(wdev, vif_id,
  77                                    HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg,
  78                                sizeof(struct hif_mib_extended_count_table));
  79        }
  80}
  81
  82int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac)
  83{
  84        struct hif_mib_mac_address msg = { };
  85
  86        if (mac)
  87                ether_addr_copy(msg.mac_addr, mac);
  88        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS,
  89                             &msg, sizeof(msg));
  90}
  91
  92int hif_set_rx_filter(struct wfx_vif *wvif,
  93                      bool filter_bssid, bool filter_prbreq)
  94{
  95        struct hif_mib_rx_filter val = { };
  96
  97        if (filter_bssid)
  98                val.bssid_filter = 1;
  99        if (!filter_prbreq)
 100                val.fwd_probe_req = 1;
 101        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER,
 102                             &val, sizeof(val));
 103}
 104
 105int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
 106                                const struct hif_ie_table_entry *tbl)
 107{
 108        int ret;
 109        struct hif_mib_bcn_filter_table *val;
 110        int buf_len = struct_size(val, ie_table, tbl_len);
 111
 112        val = kzalloc(buf_len, GFP_KERNEL);
 113        if (!val)
 114                return -ENOMEM;
 115        val->num_of_info_elmts = cpu_to_le32(tbl_len);
 116        memcpy(val->ie_table, tbl, tbl_len * sizeof(*tbl));
 117        ret = hif_write_mib(wvif->wdev, wvif->id,
 118                            HIF_MIB_ID_BEACON_FILTER_TABLE, val, buf_len);
 119        kfree(val);
 120        return ret;
 121}
 122
 123int hif_beacon_filter_control(struct wfx_vif *wvif,
 124                              int enable, int beacon_count)
 125{
 126        struct hif_mib_bcn_filter_enable arg = {
 127                .enable = cpu_to_le32(enable),
 128                .bcn_count = cpu_to_le32(beacon_count),
 129        };
 130        return hif_write_mib(wvif->wdev, wvif->id,
 131                             HIF_MIB_ID_BEACON_FILTER_ENABLE,
 132                             &arg, sizeof(arg));
 133}
 134
 135int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode)
 136{
 137        struct hif_mib_gl_operational_power_mode val = {
 138                .power_mode = mode,
 139                .wup_ind_activation = 1,
 140        };
 141
 142        return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE,
 143                             &val, sizeof(val));
 144}
 145
 146int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
 147                           u8 frame_type, int init_rate)
 148{
 149        struct hif_mib_template_frame *arg;
 150
 151        WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big");
 152        skb_push(skb, 4);
 153        arg = (struct hif_mib_template_frame *)skb->data;
 154        skb_pull(skb, 4);
 155        arg->init_rate = init_rate;
 156        arg->frame_type = frame_type;
 157        arg->frame_length = cpu_to_le16(skb->len);
 158        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME,
 159                             arg, sizeof(*arg) + skb->len);
 160}
 161
 162int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required)
 163{
 164        struct hif_mib_protected_mgmt_policy val = { };
 165
 166        WARN(required && !capable, "incoherent arguments");
 167        if (capable) {
 168                val.pmf_enable = 1;
 169                val.host_enc_auth_frames = 1;
 170        }
 171        if (!required)
 172                val.unpmf_allowed = 1;
 173        return hif_write_mib(wvif->wdev, wvif->id,
 174                             HIF_MIB_ID_PROTECTED_MGMT_POLICY,
 175                             &val, sizeof(val));
 176}
 177
 178int hif_set_block_ack_policy(struct wfx_vif *wvif,
 179                             u8 tx_tid_policy, u8 rx_tid_policy)
 180{
 181        struct hif_mib_block_ack_policy val = {
 182                .block_ack_tx_tid_policy = tx_tid_policy,
 183                .block_ack_rx_tid_policy = rx_tid_policy,
 184        };
 185
 186        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY,
 187                             &val, sizeof(val));
 188}
 189
 190int hif_set_association_mode(struct wfx_vif *wvif,
 191                             struct ieee80211_bss_conf *info)
 192{
 193        struct ieee80211_sta *sta = NULL;
 194        struct hif_mib_set_association_mode val = {
 195                .preambtype_use = 1,
 196                .mode = 1,
 197                .spacing = 1,
 198                .short_preamble = info->use_short_preamble,
 199        };
 200
 201        rcu_read_lock(); // protect sta
 202        if (info->bssid && !info->ibss_joined)
 203                sta = ieee80211_find_sta(wvif->vif, info->bssid);
 204
 205        // FIXME: it is strange to not retrieve all information from bss_info
 206        if (sta && sta->ht_cap.ht_supported) {
 207                val.mpdu_start_spacing = sta->ht_cap.ampdu_density;
 208                if (!(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT))
 209                        val.greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
 210        }
 211        rcu_read_unlock();
 212
 213        return hif_write_mib(wvif->wdev, wvif->id,
 214                             HIF_MIB_ID_SET_ASSOCIATION_MODE, &val, sizeof(val));
 215}
 216
 217int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif,
 218                                 int policy_index, u8 *rates)
 219{
 220        struct hif_mib_set_tx_rate_retry_policy *arg;
 221        size_t size = struct_size(arg, tx_rate_retry_policy, 1);
 222        int ret;
 223
 224        arg = kzalloc(size, GFP_KERNEL);
 225        if (!arg)
 226                return -ENOMEM;
 227        arg->num_tx_rate_policies = 1;
 228        arg->tx_rate_retry_policy[0].policy_index = policy_index;
 229        arg->tx_rate_retry_policy[0].short_retry_count = 255;
 230        arg->tx_rate_retry_policy[0].long_retry_count = 255;
 231        arg->tx_rate_retry_policy[0].first_rate_sel = 1;
 232        arg->tx_rate_retry_policy[0].terminate = 1;
 233        arg->tx_rate_retry_policy[0].count_init = 1;
 234        memcpy(&arg->tx_rate_retry_policy[0].rates, rates,
 235               sizeof(arg->tx_rate_retry_policy[0].rates));
 236        ret = hif_write_mib(wvif->wdev, wvif->id,
 237                            HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size);
 238        kfree(arg);
 239        return ret;
 240}
 241
 242int hif_set_mac_addr_condition(struct wfx_vif *wvif,
 243                               int idx, const u8 *mac_addr)
 244{
 245        struct hif_mib_mac_addr_data_frame_condition val = {
 246                .condition_idx = idx,
 247                .address_type = HIF_MAC_ADDR_A1,
 248        };
 249
 250        ether_addr_copy(val.mac_address, mac_addr);
 251        return hif_write_mib(wvif->wdev, wvif->id,
 252                             HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION,
 253                             &val, sizeof(val));
 254}
 255
 256int hif_set_uc_mc_bc_condition(struct wfx_vif *wvif, int idx, u8 allowed_frames)
 257{
 258        struct hif_mib_uc_mc_bc_data_frame_condition val = {
 259                .condition_idx = idx,
 260                .allowed_frames = allowed_frames,
 261        };
 262
 263        return hif_write_mib(wvif->wdev, wvif->id,
 264                             HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION,
 265                             &val, sizeof(val));
 266}
 267
 268int hif_set_config_data_filter(struct wfx_vif *wvif, bool enable, int idx,
 269                               int mac_filters, int frames_types_filters)
 270{
 271        struct hif_mib_config_data_filter val = {
 272                .enable = enable,
 273                .filter_idx = idx,
 274                .mac_cond = mac_filters,
 275                .uc_mc_bc_cond = frames_types_filters,
 276        };
 277
 278        return hif_write_mib(wvif->wdev, wvif->id,
 279                             HIF_MIB_ID_CONFIG_DATA_FILTER, &val, sizeof(val));
 280}
 281
 282int hif_set_data_filtering(struct wfx_vif *wvif, bool enable, bool invert)
 283{
 284        struct hif_mib_set_data_filtering val = {
 285                .enable = enable,
 286                .invert_matching = invert,
 287        };
 288
 289        return hif_write_mib(wvif->wdev, wvif->id,
 290                             HIF_MIB_ID_SET_DATA_FILTERING, &val, sizeof(val));
 291}
 292
 293int hif_keep_alive_period(struct wfx_vif *wvif, int period)
 294{
 295        struct hif_mib_keep_alive_period arg = {
 296                .keep_alive_period = cpu_to_le16(period),
 297        };
 298
 299        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD,
 300                             &arg, sizeof(arg));
 301};
 302
 303int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr)
 304{
 305        struct hif_mib_arp_ip_addr_table arg = {
 306                .condition_idx = idx,
 307                .arp_enable = HIF_ARP_NS_FILTERING_DISABLE,
 308        };
 309
 310        if (addr) {
 311                // Caution: type of addr is __be32
 312                memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address));
 313                arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE;
 314        }
 315        return hif_write_mib(wvif->wdev, wvif->id,
 316                             HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE,
 317                             &arg, sizeof(arg));
 318}
 319
 320int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable)
 321{
 322        struct hif_mib_gl_set_multi_msg arg = {
 323                .enable_multi_tx_conf = enable,
 324        };
 325
 326        return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG,
 327                             &arg, sizeof(arg));
 328}
 329
 330int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val)
 331{
 332        struct hif_mib_set_uapsd_information arg = { };
 333
 334        if (val & BIT(IEEE80211_AC_VO))
 335                arg.trig_voice = 1;
 336        if (val & BIT(IEEE80211_AC_VI))
 337                arg.trig_video = 1;
 338        if (val & BIT(IEEE80211_AC_BE))
 339                arg.trig_be = 1;
 340        if (val & BIT(IEEE80211_AC_BK))
 341                arg.trig_bckgrnd = 1;
 342        return hif_write_mib(wvif->wdev, wvif->id,
 343                             HIF_MIB_ID_SET_UAPSD_INFORMATION,
 344                             &arg, sizeof(arg));
 345}
 346
 347int hif_erp_use_protection(struct wfx_vif *wvif, bool enable)
 348{
 349        struct hif_mib_non_erp_protection arg = {
 350                .use_cts_to_self = enable,
 351        };
 352
 353        return hif_write_mib(wvif->wdev, wvif->id,
 354                             HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg));
 355}
 356
 357int hif_slot_time(struct wfx_vif *wvif, int val)
 358{
 359        struct hif_mib_slot_time arg = {
 360                .slot_time = cpu_to_le32(val),
 361        };
 362
 363        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME,
 364                             &arg, sizeof(arg));
 365}
 366
 367int hif_wep_default_key_id(struct wfx_vif *wvif, int val)
 368{
 369        struct hif_mib_wep_default_key_id arg = {
 370                .wep_default_key_id = val,
 371        };
 372
 373        return hif_write_mib(wvif->wdev, wvif->id,
 374                             HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID,
 375                             &arg, sizeof(arg));
 376}
 377
 378int hif_rts_threshold(struct wfx_vif *wvif, int val)
 379{
 380        struct hif_mib_dot11_rts_threshold arg = {
 381                .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF),
 382        };
 383
 384        return hif_write_mib(wvif->wdev, wvif->id,
 385                             HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg));
 386}
 387