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-2020, 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 arg = {
  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                             &arg, sizeof(arg));
  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 arg = { };
  96
  97        if (filter_bssid)
  98                arg.bssid_filter = 1;
  99        if (!filter_prbreq)
 100                arg.fwd_probe_req = 1;
 101        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER,
 102                             &arg, sizeof(arg));
 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 *arg;
 110        int buf_len = struct_size(arg, ie_table, tbl_len);
 111
 112        arg = kzalloc(buf_len, GFP_KERNEL);
 113        if (!arg)
 114                return -ENOMEM;
 115        arg->num_of_info_elmts = cpu_to_le32(tbl_len);
 116        memcpy(arg->ie_table, tbl, flex_array_size(arg, ie_table, tbl_len));
 117        ret = hif_write_mib(wvif->wdev, wvif->id,
 118                            HIF_MIB_ID_BEACON_FILTER_TABLE, arg, buf_len);
 119        kfree(arg);
 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 arg = {
 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                             &arg, sizeof(arg));
 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 arg = { };
 165
 166        WARN(required && !capable, "incoherent arguments");
 167        if (capable) {
 168                arg.pmf_enable = 1;
 169                arg.host_enc_auth_frames = 1;
 170        }
 171        if (!required)
 172                arg.unpmf_allowed = 1;
 173        return hif_write_mib(wvif->wdev, wvif->id,
 174                             HIF_MIB_ID_PROTECTED_MGMT_POLICY,
 175                             &arg, sizeof(arg));
 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 arg = {
 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                             &arg, sizeof(arg));
 188}
 189
 190int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
 191                             bool greenfield, bool short_preamble)
 192{
 193        struct hif_mib_set_association_mode arg = {
 194                .preambtype_use = 1,
 195                .mode = 1,
 196                .spacing = 1,
 197                .short_preamble = short_preamble,
 198                .greenfield = greenfield,
 199                .mpdu_start_spacing = ampdu_density,
 200        };
 201
 202        return hif_write_mib(wvif->wdev, wvif->id,
 203                             HIF_MIB_ID_SET_ASSOCIATION_MODE, &arg, sizeof(arg));
 204}
 205
 206int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif,
 207                                 int policy_index, u8 *rates)
 208{
 209        struct hif_mib_set_tx_rate_retry_policy *arg;
 210        size_t size = struct_size(arg, tx_rate_retry_policy, 1);
 211        int ret;
 212
 213        arg = kzalloc(size, GFP_KERNEL);
 214        if (!arg)
 215                return -ENOMEM;
 216        arg->num_tx_rate_policies = 1;
 217        arg->tx_rate_retry_policy[0].policy_index = policy_index;
 218        arg->tx_rate_retry_policy[0].short_retry_count = 255;
 219        arg->tx_rate_retry_policy[0].long_retry_count = 255;
 220        arg->tx_rate_retry_policy[0].first_rate_sel = 1;
 221        arg->tx_rate_retry_policy[0].terminate = 1;
 222        arg->tx_rate_retry_policy[0].count_init = 1;
 223        memcpy(&arg->tx_rate_retry_policy[0].rates, rates,
 224               sizeof(arg->tx_rate_retry_policy[0].rates));
 225        ret = hif_write_mib(wvif->wdev, wvif->id,
 226                            HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size);
 227        kfree(arg);
 228        return ret;
 229}
 230
 231int hif_keep_alive_period(struct wfx_vif *wvif, int period)
 232{
 233        struct hif_mib_keep_alive_period arg = {
 234                .keep_alive_period = cpu_to_le16(period),
 235        };
 236
 237        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD,
 238                             &arg, sizeof(arg));
 239};
 240
 241int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr)
 242{
 243        struct hif_mib_arp_ip_addr_table arg = {
 244                .condition_idx = idx,
 245                .arp_enable = HIF_ARP_NS_FILTERING_DISABLE,
 246        };
 247
 248        if (addr) {
 249                // Caution: type of addr is __be32
 250                memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address));
 251                arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE;
 252        }
 253        return hif_write_mib(wvif->wdev, wvif->id,
 254                             HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE,
 255                             &arg, sizeof(arg));
 256}
 257
 258int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable)
 259{
 260        struct hif_mib_gl_set_multi_msg arg = {
 261                .enable_multi_tx_conf = enable,
 262        };
 263
 264        return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG,
 265                             &arg, sizeof(arg));
 266}
 267
 268int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val)
 269{
 270        struct hif_mib_set_uapsd_information arg = { };
 271
 272        if (val & BIT(IEEE80211_AC_VO))
 273                arg.trig_voice = 1;
 274        if (val & BIT(IEEE80211_AC_VI))
 275                arg.trig_video = 1;
 276        if (val & BIT(IEEE80211_AC_BE))
 277                arg.trig_be = 1;
 278        if (val & BIT(IEEE80211_AC_BK))
 279                arg.trig_bckgrnd = 1;
 280        return hif_write_mib(wvif->wdev, wvif->id,
 281                             HIF_MIB_ID_SET_UAPSD_INFORMATION,
 282                             &arg, sizeof(arg));
 283}
 284
 285int hif_erp_use_protection(struct wfx_vif *wvif, bool enable)
 286{
 287        struct hif_mib_non_erp_protection arg = {
 288                .use_cts_to_self = enable,
 289        };
 290
 291        return hif_write_mib(wvif->wdev, wvif->id,
 292                             HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg));
 293}
 294
 295int hif_slot_time(struct wfx_vif *wvif, int val)
 296{
 297        struct hif_mib_slot_time arg = {
 298                .slot_time = cpu_to_le32(val),
 299        };
 300
 301        return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME,
 302                             &arg, sizeof(arg));
 303}
 304
 305int hif_wep_default_key_id(struct wfx_vif *wvif, int val)
 306{
 307        struct hif_mib_wep_default_key_id arg = {
 308                .wep_default_key_id = val,
 309        };
 310
 311        return hif_write_mib(wvif->wdev, wvif->id,
 312                             HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID,
 313                             &arg, sizeof(arg));
 314}
 315
 316int hif_rts_threshold(struct wfx_vif *wvif, int val)
 317{
 318        struct hif_mib_dot11_rts_threshold arg = {
 319                .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF),
 320        };
 321
 322        return hif_write_mib(wvif->wdev, wvif->id,
 323                             HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg));
 324}
 325