Merge tag 'riscv-for-linus-5.14-rc7' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / staging / wfx / hif_tx_mib.c
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
17 int 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
28 int 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
45 int 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
67 int 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
82 int 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
92 int 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
105 int 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
123 int 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
135 int 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
146 int 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
162 int 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
178 int 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
190 int 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
206 int 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
231 int 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
241 int 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
258 int 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
268 int 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
285 int 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
295 int 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
305 int 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
316 int 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 }