1 // SPDX-License-Identifier: GPL-2.0-only
3 * Implementation of the host-to-chip commands (aka request/confirmation) of the
6 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
7 * Copyright (c) 2010, ST-Ericsson
9 #include <linux/etherdevice.h>
18 void wfx_init_hif_cmd(struct wfx_hif_cmd
*hif_cmd
)
20 init_completion(&hif_cmd
->ready
);
21 init_completion(&hif_cmd
->done
);
22 mutex_init(&hif_cmd
->lock
);
25 static void wfx_fill_header(struct wfx_hif_msg
*hif
, int if_id
, unsigned int cmd
, size_t size
)
30 WARN(cmd
> 0x3f, "invalid hardware command %#.2x", cmd
);
31 WARN(size
> 0xFFF, "requested buffer is too large: %zu bytes", size
);
32 WARN(if_id
> 0x3, "invalid interface ID %d", if_id
);
34 hif
->len
= cpu_to_le16(size
+ 4);
36 hif
->interface
= if_id
;
39 static void *wfx_alloc_hif(size_t body_len
, struct wfx_hif_msg
**hif
)
41 *hif
= kzalloc(sizeof(struct wfx_hif_msg
) + body_len
, GFP_KERNEL
);
48 static u32
wfx_rate_mask_to_hw(struct wfx_dev
*wdev
, u32 rates
)
52 /* The device only supports 2GHz */
53 struct ieee80211_supported_band
*sband
= wdev
->hw
->wiphy
->bands
[NL80211_BAND_2GHZ
];
55 for (i
= 0; i
< sband
->n_bitrates
; i
++) {
57 if (i
>= sband
->n_bitrates
)
58 dev_warn(wdev
->dev
, "unsupported basic rate\n");
60 ret
|= BIT(sband
->bitrates
[i
].hw_value
);
66 int wfx_cmd_send(struct wfx_dev
*wdev
, struct wfx_hif_msg
*request
,
67 void *reply
, size_t reply_len
, bool no_reply
)
69 const char *mib_name
= "";
70 const char *mib_sep
= "";
71 int cmd
= request
->id
;
72 int vif
= request
->interface
;
75 /* Do not wait for any reply if chip is frozen */
76 if (wdev
->chip_frozen
)
79 mutex_lock(&wdev
->hif_cmd
.lock
);
80 WARN(wdev
->hif_cmd
.buf_send
, "data locking error");
82 /* Note: call to complete() below has an implicit memory barrier that hopefully protect
85 wdev
->hif_cmd
.buf_send
= request
;
86 wdev
->hif_cmd
.buf_recv
= reply
;
87 wdev
->hif_cmd
.len_recv
= reply_len
;
88 complete(&wdev
->hif_cmd
.ready
);
90 wfx_bh_request_tx(wdev
);
93 /* Chip won't reply. Ensure the wq has send the buffer before to continue. */
94 flush_workqueue(wdev
->bh_wq
);
100 wfx_bh_poll_irq(wdev
);
102 ret
= wait_for_completion_timeout(&wdev
->hif_cmd
.done
, 1 * HZ
);
104 dev_err(wdev
->dev
, "chip is abnormally long to answer\n");
105 reinit_completion(&wdev
->hif_cmd
.ready
);
106 ret
= wait_for_completion_timeout(&wdev
->hif_cmd
.done
, 3 * HZ
);
109 dev_err(wdev
->dev
, "chip did not answer\n");
110 wfx_pending_dump_old_frames(wdev
, 3000);
111 wdev
->chip_frozen
= true;
112 reinit_completion(&wdev
->hif_cmd
.done
);
115 ret
= wdev
->hif_cmd
.ret
;
119 wdev
->hif_cmd
.buf_send
= NULL
;
120 mutex_unlock(&wdev
->hif_cmd
.lock
);
123 (cmd
== HIF_REQ_ID_READ_MIB
|| cmd
== HIF_REQ_ID_WRITE_MIB
)) {
124 mib_name
= wfx_get_mib_name(((u16
*)request
)[2]);
128 dev_err(wdev
->dev
, "hardware request %s%s%s (%#.2x) on vif %d returned error %d\n",
129 wfx_get_hif_name(cmd
), mib_sep
, mib_name
, cmd
, vif
, ret
);
131 dev_warn(wdev
->dev
, "hardware request %s%s%s (%#.2x) on vif %d returned status %d\n",
132 wfx_get_hif_name(cmd
), mib_sep
, mib_name
, cmd
, vif
, ret
);
137 /* This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any request anymore.
138 * Obviously, only call this function during device unregister.
140 int wfx_hif_shutdown(struct wfx_dev
*wdev
)
143 struct wfx_hif_msg
*hif
;
145 wfx_alloc_hif(0, &hif
);
148 wfx_fill_header(hif
, -1, HIF_REQ_ID_SHUT_DOWN
, 0);
149 ret
= wfx_cmd_send(wdev
, hif
, NULL
, 0, true);
150 if (wdev
->pdata
.gpio_wakeup
)
151 gpiod_set_value(wdev
->pdata
.gpio_wakeup
, 0);
153 wfx_control_reg_write(wdev
, 0);
158 int wfx_hif_configuration(struct wfx_dev
*wdev
, const u8
*conf
, size_t len
)
161 size_t buf_len
= sizeof(struct wfx_hif_req_configuration
) + len
;
162 struct wfx_hif_msg
*hif
;
163 struct wfx_hif_req_configuration
*body
= wfx_alloc_hif(buf_len
, &hif
);
167 body
->length
= cpu_to_le16(len
);
168 memcpy(body
->pds_data
, conf
, len
);
169 wfx_fill_header(hif
, -1, HIF_REQ_ID_CONFIGURATION
, buf_len
);
170 ret
= wfx_cmd_send(wdev
, hif
, NULL
, 0, false);
175 int wfx_hif_reset(struct wfx_vif
*wvif
, bool reset_stat
)
178 struct wfx_hif_msg
*hif
;
179 struct wfx_hif_req_reset
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
183 body
->reset_stat
= reset_stat
;
184 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_RESET
, sizeof(*body
));
185 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
190 int wfx_hif_read_mib(struct wfx_dev
*wdev
, int vif_id
, u16 mib_id
, void *val
, size_t val_len
)
193 struct wfx_hif_msg
*hif
;
194 int buf_len
= sizeof(struct wfx_hif_cnf_read_mib
) + val_len
;
195 struct wfx_hif_req_read_mib
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
196 struct wfx_hif_cnf_read_mib
*reply
= kmalloc(buf_len
, GFP_KERNEL
);
198 if (!body
|| !reply
) {
202 body
->mib_id
= cpu_to_le16(mib_id
);
203 wfx_fill_header(hif
, vif_id
, HIF_REQ_ID_READ_MIB
, sizeof(*body
));
204 ret
= wfx_cmd_send(wdev
, hif
, reply
, buf_len
, false);
206 if (!ret
&& mib_id
!= le16_to_cpu(reply
->mib_id
)) {
207 dev_warn(wdev
->dev
, "%s: confirmation mismatch request\n", __func__
);
211 dev_err(wdev
->dev
, "buffer is too small to receive %s (%zu < %d)\n",
212 wfx_get_mib_name(mib_id
), val_len
, le16_to_cpu(reply
->length
));
214 memcpy(val
, &reply
->mib_data
, le16_to_cpu(reply
->length
));
216 memset(val
, 0xFF, val_len
);
223 int wfx_hif_write_mib(struct wfx_dev
*wdev
, int vif_id
, u16 mib_id
, void *val
, size_t val_len
)
226 struct wfx_hif_msg
*hif
;
227 int buf_len
= sizeof(struct wfx_hif_req_write_mib
) + val_len
;
228 struct wfx_hif_req_write_mib
*body
= wfx_alloc_hif(buf_len
, &hif
);
232 body
->mib_id
= cpu_to_le16(mib_id
);
233 body
->length
= cpu_to_le16(val_len
);
234 memcpy(&body
->mib_data
, val
, val_len
);
235 wfx_fill_header(hif
, vif_id
, HIF_REQ_ID_WRITE_MIB
, buf_len
);
236 ret
= wfx_cmd_send(wdev
, hif
, NULL
, 0, false);
241 /* Hijack scan request to implement Remain-On-Channel */
242 int wfx_hif_scan_uniq(struct wfx_vif
*wvif
, struct ieee80211_channel
*chan
, int duration
)
245 struct wfx_hif_msg
*hif
;
246 size_t buf_len
= sizeof(struct wfx_hif_req_start_scan_alt
) + sizeof(u8
);
247 struct wfx_hif_req_start_scan_alt
*body
= wfx_alloc_hif(buf_len
, &hif
);
251 body
->num_of_ssids
= HIF_API_MAX_NB_SSIDS
;
252 body
->maintain_current_bss
= 1;
253 body
->disallow_ps
= 1;
254 body
->tx_power_level
= cpu_to_le32(chan
->max_power
);
255 body
->num_of_channels
= 1;
256 body
->channel_list
[0] = chan
->hw_value
;
257 body
->max_transmit_rate
= API_RATE_INDEX_B_1MBPS
;
258 body
->min_channel_time
= cpu_to_le32(duration
);
259 body
->max_channel_time
= cpu_to_le32(duration
* 110 / 100);
260 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_START_SCAN
, buf_len
);
261 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
266 int wfx_hif_scan(struct wfx_vif
*wvif
, struct cfg80211_scan_request
*req
,
267 int chan_start_idx
, int chan_num
)
270 struct wfx_hif_msg
*hif
;
271 size_t buf_len
= sizeof(struct wfx_hif_req_start_scan_alt
) + chan_num
* sizeof(u8
);
272 struct wfx_hif_req_start_scan_alt
*body
= wfx_alloc_hif(buf_len
, &hif
);
274 WARN(chan_num
> HIF_API_MAX_NB_CHANNELS
, "invalid params");
275 WARN(req
->n_ssids
> HIF_API_MAX_NB_SSIDS
, "invalid params");
279 for (i
= 0; i
< req
->n_ssids
; i
++) {
280 memcpy(body
->ssid_def
[i
].ssid
, req
->ssids
[i
].ssid
, IEEE80211_MAX_SSID_LEN
);
281 body
->ssid_def
[i
].ssid_length
= cpu_to_le32(req
->ssids
[i
].ssid_len
);
283 body
->num_of_ssids
= HIF_API_MAX_NB_SSIDS
;
284 body
->maintain_current_bss
= 1;
285 body
->disallow_ps
= 1;
286 body
->tx_power_level
= cpu_to_le32(req
->channels
[chan_start_idx
]->max_power
);
287 body
->num_of_channels
= chan_num
;
288 for (i
= 0; i
< chan_num
; i
++)
289 body
->channel_list
[i
] = req
->channels
[i
+ chan_start_idx
]->hw_value
;
291 body
->max_transmit_rate
= API_RATE_INDEX_G_6MBPS
;
293 body
->max_transmit_rate
= API_RATE_INDEX_B_1MBPS
;
294 if (req
->channels
[chan_start_idx
]->flags
& IEEE80211_CHAN_NO_IR
) {
295 body
->min_channel_time
= cpu_to_le32(50);
296 body
->max_channel_time
= cpu_to_le32(150);
298 body
->min_channel_time
= cpu_to_le32(10);
299 body
->max_channel_time
= cpu_to_le32(50);
300 body
->num_of_probe_requests
= 2;
301 body
->probe_delay
= 100;
304 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_START_SCAN
, buf_len
);
305 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
310 int wfx_hif_stop_scan(struct wfx_vif
*wvif
)
313 struct wfx_hif_msg
*hif
;
314 /* body associated to HIF_REQ_ID_STOP_SCAN is empty */
315 wfx_alloc_hif(0, &hif
);
319 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_STOP_SCAN
, 0);
320 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
325 int wfx_hif_join(struct wfx_vif
*wvif
, const struct ieee80211_bss_conf
*conf
,
326 struct ieee80211_channel
*channel
, const u8
*ssid
, int ssid_len
)
328 struct ieee80211_vif
*vif
= container_of(conf
, struct ieee80211_vif
,
331 struct wfx_hif_msg
*hif
;
332 struct wfx_hif_req_join
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
334 WARN_ON(!conf
->beacon_int
);
335 WARN_ON(!conf
->basic_rates
);
336 WARN_ON(sizeof(body
->ssid
) < ssid_len
);
337 WARN(!vif
->cfg
.ibss_joined
&& !ssid_len
, "joining an unknown BSS");
340 body
->infrastructure_bss_mode
= !vif
->cfg
.ibss_joined
;
341 body
->short_preamble
= conf
->use_short_preamble
;
342 body
->probe_for_join
= !(channel
->flags
& IEEE80211_CHAN_NO_IR
);
343 body
->channel_number
= channel
->hw_value
;
344 body
->beacon_interval
= cpu_to_le32(conf
->beacon_int
);
345 body
->basic_rate_set
= cpu_to_le32(wfx_rate_mask_to_hw(wvif
->wdev
, conf
->basic_rates
));
346 memcpy(body
->bssid
, conf
->bssid
, sizeof(body
->bssid
));
348 body
->ssid_length
= cpu_to_le32(ssid_len
);
349 memcpy(body
->ssid
, ssid
, ssid_len
);
351 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_JOIN
, sizeof(*body
));
352 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
357 int wfx_hif_set_bss_params(struct wfx_vif
*wvif
, int aid
, int beacon_lost_count
)
360 struct wfx_hif_msg
*hif
;
361 struct wfx_hif_req_set_bss_params
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
365 body
->aid
= cpu_to_le16(aid
);
366 body
->beacon_lost_count
= beacon_lost_count
;
367 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_SET_BSS_PARAMS
, sizeof(*body
));
368 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
373 int wfx_hif_add_key(struct wfx_dev
*wdev
, const struct wfx_hif_req_add_key
*arg
)
376 struct wfx_hif_msg
*hif
;
377 /* FIXME: only send necessary bits */
378 struct wfx_hif_req_add_key
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
382 /* FIXME: swap bytes as necessary in body */
383 memcpy(body
, arg
, sizeof(*body
));
384 if (wfx_api_older_than(wdev
, 1, 5))
385 /* Legacy firmwares expect that add_key to be sent on right interface. */
386 wfx_fill_header(hif
, arg
->int_id
, HIF_REQ_ID_ADD_KEY
, sizeof(*body
));
388 wfx_fill_header(hif
, -1, HIF_REQ_ID_ADD_KEY
, sizeof(*body
));
389 ret
= wfx_cmd_send(wdev
, hif
, NULL
, 0, false);
394 int wfx_hif_remove_key(struct wfx_dev
*wdev
, int idx
)
397 struct wfx_hif_msg
*hif
;
398 struct wfx_hif_req_remove_key
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
402 body
->entry_index
= idx
;
403 wfx_fill_header(hif
, -1, HIF_REQ_ID_REMOVE_KEY
, sizeof(*body
));
404 ret
= wfx_cmd_send(wdev
, hif
, NULL
, 0, false);
409 int wfx_hif_set_edca_queue_params(struct wfx_vif
*wvif
, u16 queue
,
410 const struct ieee80211_tx_queue_params
*arg
)
413 struct wfx_hif_msg
*hif
;
414 struct wfx_hif_req_edca_queue_params
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
419 WARN_ON(arg
->aifs
> 255);
422 body
->aifsn
= arg
->aifs
;
423 body
->cw_min
= cpu_to_le16(arg
->cw_min
);
424 body
->cw_max
= cpu_to_le16(arg
->cw_max
);
425 body
->tx_op_limit
= cpu_to_le16(arg
->txop
* USEC_PER_TXOP
);
426 body
->queue_id
= 3 - queue
;
427 /* API 2.0 has changed queue IDs values */
428 if (wfx_api_older_than(wvif
->wdev
, 2, 0) && queue
== IEEE80211_AC_BE
)
429 body
->queue_id
= HIF_QUEUE_ID_BACKGROUND
;
430 if (wfx_api_older_than(wvif
->wdev
, 2, 0) && queue
== IEEE80211_AC_BK
)
431 body
->queue_id
= HIF_QUEUE_ID_BESTEFFORT
;
432 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_EDCA_QUEUE_PARAMS
, sizeof(*body
));
433 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
438 int wfx_hif_set_pm(struct wfx_vif
*wvif
, bool ps
, int dynamic_ps_timeout
)
441 struct wfx_hif_msg
*hif
;
442 struct wfx_hif_req_set_pm_mode
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
451 /* Firmware does not support more than 128ms */
452 body
->fast_psm_idle_period
= min(dynamic_ps_timeout
* 2, 255);
453 if (body
->fast_psm_idle_period
)
456 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_SET_PM_MODE
, sizeof(*body
));
457 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
462 int wfx_hif_start(struct wfx_vif
*wvif
, const struct ieee80211_bss_conf
*conf
,
463 const struct ieee80211_channel
*channel
)
465 struct ieee80211_vif
*vif
= container_of(conf
, struct ieee80211_vif
,
468 struct wfx_hif_msg
*hif
;
469 struct wfx_hif_req_start
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
471 WARN_ON(!conf
->beacon_int
);
474 body
->dtim_period
= conf
->dtim_period
;
475 body
->short_preamble
= conf
->use_short_preamble
;
476 body
->channel_number
= channel
->hw_value
;
477 body
->beacon_interval
= cpu_to_le32(conf
->beacon_int
);
478 body
->basic_rate_set
= cpu_to_le32(wfx_rate_mask_to_hw(wvif
->wdev
, conf
->basic_rates
));
479 body
->ssid_length
= vif
->cfg
.ssid_len
;
480 memcpy(body
->ssid
, vif
->cfg
.ssid
, vif
->cfg
.ssid_len
);
481 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_START
, sizeof(*body
));
482 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
487 int wfx_hif_beacon_transmit(struct wfx_vif
*wvif
, bool enable
)
490 struct wfx_hif_msg
*hif
;
491 struct wfx_hif_req_beacon_transmit
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
495 body
->enable_beaconing
= enable
? 1 : 0;
496 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_BEACON_TRANSMIT
, sizeof(*body
));
497 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
502 int wfx_hif_map_link(struct wfx_vif
*wvif
, bool unmap
, u8
*mac_addr
, int sta_id
, bool mfp
)
505 struct wfx_hif_msg
*hif
;
506 struct wfx_hif_req_map_link
*body
= wfx_alloc_hif(sizeof(*body
), &hif
);
511 ether_addr_copy(body
->mac_addr
, mac_addr
);
512 body
->mfpc
= mfp
? 1 : 0;
513 body
->unmap
= unmap
? 1 : 0;
514 body
->peer_sta_id
= sta_id
;
515 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_MAP_LINK
, sizeof(*body
));
516 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);
521 int wfx_hif_update_ie_beacon(struct wfx_vif
*wvif
, const u8
*ies
, size_t ies_len
)
524 struct wfx_hif_msg
*hif
;
525 int buf_len
= sizeof(struct wfx_hif_req_update_ie
) + ies_len
;
526 struct wfx_hif_req_update_ie
*body
= wfx_alloc_hif(buf_len
, &hif
);
531 body
->num_ies
= cpu_to_le16(1);
532 memcpy(body
->ie
, ies
, ies_len
);
533 wfx_fill_header(hif
, wvif
->id
, HIF_REQ_ID_UPDATE_IE
, buf_len
);
534 ret
= wfx_cmd_send(wvif
->wdev
, hif
, NULL
, 0, false);