1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Implementation of the host-to-chip MIBs of the hardware 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 17 int wfx_hif_set_output_power(struct wfx_vif *wvif, int val) 18 { 19 struct wfx_hif_mib_current_tx_power_level arg = { 20 .power_level = cpu_to_le32(val * 10), 21 }; 22 23 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, 24 &arg, sizeof(arg)); 25 } 26 27 int wfx_hif_set_beacon_wakeup_period(struct wfx_vif *wvif, 28 unsigned int dtim_interval, unsigned int listen_interval) 29 { 30 struct wfx_hif_mib_beacon_wake_up_period arg = { 31 .wakeup_period_min = dtim_interval, 32 .receive_dtim = 0, 33 .wakeup_period_max = listen_interval, 34 }; 35 36 if (dtim_interval > 0xFF || listen_interval > 0xFFFF) 37 return -EINVAL; 38 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_WAKEUP_PERIOD, 39 &arg, sizeof(arg)); 40 } 41 42 int wfx_hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, int rssi_thold, int rssi_hyst) 43 { 44 struct wfx_hif_mib_rcpi_rssi_threshold arg = { 45 .rolling_average_count = 8, 46 .detection = 1, 47 }; 48 49 if (!rssi_thold && !rssi_hyst) { 50 arg.upperthresh = 1; 51 arg.lowerthresh = 1; 52 } else { 53 arg.upper_threshold = rssi_thold + rssi_hyst; 54 arg.upper_threshold = (arg.upper_threshold + 110) * 2; 55 arg.lower_threshold = rssi_thold; 56 arg.lower_threshold = (arg.lower_threshold + 110) * 2; 57 } 58 59 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RCPI_RSSI_THRESHOLD, 60 &arg, sizeof(arg)); 61 } 62 63 int wfx_hif_get_counters_table(struct wfx_dev *wdev, int vif_id, 64 struct wfx_hif_mib_extended_count_table *arg) 65 { 66 if (wfx_api_older_than(wdev, 1, 3)) { 67 /* extended_count_table is wider than count_table */ 68 memset(arg, 0xFF, sizeof(*arg)); 69 return wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE, 70 arg, sizeof(struct wfx_hif_mib_count_table)); 71 } else { 72 return wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, 73 arg, sizeof(struct wfx_hif_mib_extended_count_table)); 74 } 75 } 76 77 int wfx_hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) 78 { 79 struct wfx_hif_mib_mac_address arg = { }; 80 81 if (mac) 82 ether_addr_copy(arg.mac_addr, mac); 83 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, 84 &arg, sizeof(arg)); 85 } 86 87 int wfx_hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, bool filter_prbreq) 88 { 89 struct wfx_hif_mib_rx_filter arg = { }; 90 91 if (filter_bssid) 92 arg.bssid_filter = 1; 93 if (!filter_prbreq) 94 arg.fwd_probe_req = 1; 95 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, &arg, sizeof(arg)); 96 } 97 98 int wfx_hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, 99 const struct wfx_hif_ie_table_entry *tbl) 100 { 101 int ret; 102 struct wfx_hif_mib_bcn_filter_table *arg; 103 int buf_len = struct_size(arg, ie_table, tbl_len); 104 105 arg = kzalloc(buf_len, GFP_KERNEL); 106 if (!arg) 107 return -ENOMEM; 108 arg->num_of_info_elmts = cpu_to_le32(tbl_len); 109 memcpy(arg->ie_table, tbl, flex_array_size(arg, ie_table, tbl_len)); 110 ret = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_TABLE, 111 arg, buf_len); 112 kfree(arg); 113 return ret; 114 } 115 116 int wfx_hif_beacon_filter_control(struct wfx_vif *wvif, int enable, int beacon_count) 117 { 118 struct wfx_hif_mib_bcn_filter_enable arg = { 119 .enable = cpu_to_le32(enable), 120 .bcn_count = cpu_to_le32(beacon_count), 121 }; 122 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_ENABLE, 123 &arg, sizeof(arg)); 124 } 125 126 int wfx_hif_set_operational_mode(struct wfx_dev *wdev, enum wfx_hif_op_power_mode mode) 127 { 128 struct wfx_hif_mib_gl_operational_power_mode arg = { 129 .power_mode = mode, 130 .wup_ind_activation = 1, 131 }; 132 133 return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, 134 &arg, sizeof(arg)); 135 } 136 137 int wfx_hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, 138 u8 frame_type, int init_rate) 139 { 140 struct wfx_hif_mib_template_frame *arg; 141 142 WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big"); 143 skb_push(skb, 4); 144 arg = (struct wfx_hif_mib_template_frame *)skb->data; 145 skb_pull(skb, 4); 146 arg->init_rate = init_rate; 147 arg->frame_type = frame_type; 148 arg->frame_length = cpu_to_le16(skb->len); 149 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, 150 arg, sizeof(*arg) + skb->len); 151 } 152 153 int wfx_hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) 154 { 155 struct wfx_hif_mib_protected_mgmt_policy arg = { }; 156 157 WARN(required && !capable, "incoherent arguments"); 158 if (capable) { 159 arg.pmf_enable = 1; 160 arg.host_enc_auth_frames = 1; 161 } 162 if (!required) 163 arg.unpmf_allowed = 1; 164 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_PROTECTED_MGMT_POLICY, 165 &arg, sizeof(arg)); 166 } 167 168 int wfx_hif_set_block_ack_policy(struct wfx_vif *wvif, u8 tx_tid_policy, u8 rx_tid_policy) 169 { 170 struct wfx_hif_mib_block_ack_policy arg = { 171 .block_ack_tx_tid_policy = tx_tid_policy, 172 .block_ack_rx_tid_policy = rx_tid_policy, 173 }; 174 175 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, 176 &arg, sizeof(arg)); 177 } 178 179 int wfx_hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, 180 bool greenfield, bool short_preamble) 181 { 182 struct wfx_hif_mib_set_association_mode arg = { 183 .preambtype_use = 1, 184 .mode = 1, 185 .spacing = 1, 186 .short_preamble = short_preamble, 187 .greenfield = greenfield, 188 .mpdu_start_spacing = ampdu_density, 189 }; 190 191 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_ASSOCIATION_MODE, 192 &arg, sizeof(arg)); 193 } 194 195 int wfx_hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, int policy_index, u8 *rates) 196 { 197 struct wfx_hif_mib_set_tx_rate_retry_policy *arg; 198 size_t size = struct_size(arg, tx_rate_retry_policy, 1); 199 int ret; 200 201 arg = kzalloc(size, GFP_KERNEL); 202 if (!arg) 203 return -ENOMEM; 204 arg->num_tx_rate_policies = 1; 205 arg->tx_rate_retry_policy[0].policy_index = policy_index; 206 arg->tx_rate_retry_policy[0].short_retry_count = 255; 207 arg->tx_rate_retry_policy[0].long_retry_count = 255; 208 arg->tx_rate_retry_policy[0].first_rate_sel = 1; 209 arg->tx_rate_retry_policy[0].terminate = 1; 210 arg->tx_rate_retry_policy[0].count_init = 1; 211 memcpy(&arg->tx_rate_retry_policy[0].rates, rates, 212 sizeof(arg->tx_rate_retry_policy[0].rates)); 213 ret = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, 214 arg, size); 215 kfree(arg); 216 return ret; 217 } 218 219 int wfx_hif_keep_alive_period(struct wfx_vif *wvif, int period) 220 { 221 struct wfx_hif_mib_keep_alive_period arg = { 222 .keep_alive_period = cpu_to_le16(period), 223 }; 224 225 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, 226 &arg, sizeof(arg)); 227 }; 228 229 int wfx_hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr) 230 { 231 struct wfx_hif_mib_arp_ip_addr_table arg = { 232 .condition_idx = idx, 233 .arp_enable = HIF_ARP_NS_FILTERING_DISABLE, 234 }; 235 236 if (addr) { 237 /* Caution: type of addr is __be32 */ 238 memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address)); 239 arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE; 240 } 241 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, 242 &arg, sizeof(arg)); 243 } 244 245 int wfx_hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable) 246 { 247 struct wfx_hif_mib_gl_set_multi_msg arg = { 248 .enable_multi_tx_conf = enable, 249 }; 250 251 return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, &arg, sizeof(arg)); 252 } 253 254 int wfx_hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val) 255 { 256 struct wfx_hif_mib_set_uapsd_information arg = { }; 257 258 if (val & BIT(IEEE80211_AC_VO)) 259 arg.trig_voice = 1; 260 if (val & BIT(IEEE80211_AC_VI)) 261 arg.trig_video = 1; 262 if (val & BIT(IEEE80211_AC_BE)) 263 arg.trig_be = 1; 264 if (val & BIT(IEEE80211_AC_BK)) 265 arg.trig_bckgrnd = 1; 266 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_UAPSD_INFORMATION, 267 &arg, sizeof(arg)); 268 } 269 270 int wfx_hif_erp_use_protection(struct wfx_vif *wvif, bool enable) 271 { 272 struct wfx_hif_mib_non_erp_protection arg = { 273 .use_cts_to_self = enable, 274 }; 275 276 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_NON_ERP_PROTECTION, 277 &arg, sizeof(arg)); 278 } 279 280 int wfx_hif_slot_time(struct wfx_vif *wvif, int val) 281 { 282 struct wfx_hif_mib_slot_time arg = { 283 .slot_time = cpu_to_le32(val), 284 }; 285 286 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, &arg, sizeof(arg)); 287 } 288 289 int wfx_hif_wep_default_key_id(struct wfx_vif *wvif, int val) 290 { 291 struct wfx_hif_mib_wep_default_key_id arg = { 292 .wep_default_key_id = val, 293 }; 294 295 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, 296 &arg, sizeof(arg)); 297 } 298 299 int wfx_hif_rts_threshold(struct wfx_vif *wvif, int val) 300 { 301 struct wfx_hif_mib_dot11_rts_threshold arg = { 302 .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF), 303 }; 304 305 return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_RTS_THRESHOLD, 306 &arg, sizeof(arg)); 307 } 308