Here is the big set of staging driver updates for 5.19-rc1. Lots of forward progress happened this development cycle, one driver (wfx wireless driver) got merged into the real portion of the kernel, and another one (unisys) was removed as no one is around anymore to take care of it and no one has the hardware. Combined with loads of tiny driver cleanups overall we removed 13k lines of code from the tree, a nice improvement. Other than the wfx and unisys driver changes the major points of this merge is: - r8188eu driver cleanups. So many cleanups. It's amazing just how many things have been cleaned up here, and yet, how many remain to go. Lots of work happened here, and it doesn't look to slow down any time soon. - other wifi driver cleanups. Not as many as the r8188eu driver, but still pretty impressive from a janitorial point of view. - bcm2853 driver cleanups - other very minor driver cleanups All of these have been in the linux-next tree for weeks with no reported issues. Note, you will have a merge conflict in the drivers/net/wireless/silabs/wfx/sta.c file, please just take the change that came in from the wifi tree. We thought as I had pulled the same merge point from the wifi developers this type of conflict wouldn't have happened, but for some reason git flags it as something to pay attention to and couldn't resolve it itself. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYpnfqA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynbFQCfbr7wdJYsNfVd0nXlDUw9EQtbhR8AoM5Y31Ni hBJs6fa/HMGfLnrmN2Xi =BQyT -----END PGP SIGNATURE----- Merge tag 'staging-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging Pull staging driver updates from Greg KH: "Here is the big set of staging driver updates for 5.19-rc1. Lots of forward progress happened this development cycle, one driver (wfx wireless driver) got merged into the real portion of the kernel, and another one (unisys) was removed as no one is around anymore to take care of it and no one has the hardware. Combined with loads of tiny driver cleanups overall we removed 13k lines of code from the tree, a nice improvement. Other than the wfx and unisys driver changes the major points of this merge is: - r8188eu driver cleanups. So many cleanups. It's amazing just how many things have been cleaned up here, and yet, how many remain to go. Lots of work happened here, and it doesn't look to slow down any time soon. - other wifi driver cleanups. Not as many as the r8188eu driver, but still pretty impressive from a janitorial point of view. - bcm2853 driver cleanups - other very minor driver cleanups All of these have been in the linux-next tree for weeks with no reported issues" * tag 'staging-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (363 commits) staging: r8188eu: remove include/rtw_debug.h staging: r8188eu: prevent ->Ssid overflow in rtw_wx_set_scan() staging: r8188eu: delete rtw_wx_read/write32() staging: r8188eu: Remove multiple assignments staging: r8188eu: add check for kzalloc staging: r8188eu: fix warnings in rtw_wlan_util staging: r8188eu: fix warnings in rtw_pwrctrl staging: r8188eu: fix warnings in rtw_p2p staging: rtl8712: fix uninit-value in r871xu_drv_init() staging: rtl8712: fix uninit-value in usb_read8() and friends staging: rtl8712: add error handler in r8712_usbctrl_vendorreq() staging: r8188eu: remove _drv_ defines from include/rtw_debug.h staging: vc04_services: remove unused macro staging: rtl8192u: remove null check after call container_of() staging: rtl8192e: remove null check after call container_of() staging: ks7010: remove null check after call container_of() staging: r8188eu: remove HW_VAR_AC_PARAM_BE from SetHwReg8188EU() staging: r8188eu: assoc_rsp and assoc_rsp_len are not used staging: r8188eu: last_rx_mgnt_pkts is set but not used staging: r8188eu: simplify error handling in recv_func_prehandle ...
490 lines
14 KiB
C
490 lines
14 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Implementation of the host-to-chip commands (aka request/confirmation) of the
|
|
* hardware API.
|
|
*
|
|
* Copyright (c) 2017-2020, Silicon Laboratories, Inc.
|
|
* Copyright (c) 2010, ST-Ericsson
|
|
*/
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include "hif_tx.h"
|
|
#include "wfx.h"
|
|
#include "bh.h"
|
|
#include "hwio.h"
|
|
#include "debug.h"
|
|
#include "sta.h"
|
|
|
|
void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
|
|
{
|
|
init_completion(&hif_cmd->ready);
|
|
init_completion(&hif_cmd->done);
|
|
mutex_init(&hif_cmd->lock);
|
|
}
|
|
|
|
static void wfx_fill_header(struct wfx_hif_msg *hif, int if_id, unsigned int cmd, size_t size)
|
|
{
|
|
if (if_id == -1)
|
|
if_id = 2;
|
|
|
|
WARN(cmd > 0x3f, "invalid hardware command %#.2x", cmd);
|
|
WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
|
|
WARN(if_id > 0x3, "invalid interface ID %d", if_id);
|
|
|
|
hif->len = cpu_to_le16(size + 4);
|
|
hif->id = cmd;
|
|
hif->interface = if_id;
|
|
}
|
|
|
|
static void *wfx_alloc_hif(size_t body_len, struct wfx_hif_msg **hif)
|
|
{
|
|
*hif = kzalloc(sizeof(struct wfx_hif_msg) + body_len, GFP_KERNEL);
|
|
if (*hif)
|
|
return (*hif)->body;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
int wfx_cmd_send(struct wfx_dev *wdev, struct wfx_hif_msg *request,
|
|
void *reply, size_t reply_len, bool no_reply)
|
|
{
|
|
const char *mib_name = "";
|
|
const char *mib_sep = "";
|
|
int cmd = request->id;
|
|
int vif = request->interface;
|
|
int ret;
|
|
|
|
/* Do not wait for any reply if chip is frozen */
|
|
if (wdev->chip_frozen)
|
|
return -ETIMEDOUT;
|
|
|
|
mutex_lock(&wdev->hif_cmd.lock);
|
|
WARN(wdev->hif_cmd.buf_send, "data locking error");
|
|
|
|
/* Note: call to complete() below has an implicit memory barrier that hopefully protect
|
|
* buf_send
|
|
*/
|
|
wdev->hif_cmd.buf_send = request;
|
|
wdev->hif_cmd.buf_recv = reply;
|
|
wdev->hif_cmd.len_recv = reply_len;
|
|
complete(&wdev->hif_cmd.ready);
|
|
|
|
wfx_bh_request_tx(wdev);
|
|
|
|
if (no_reply) {
|
|
/* Chip won't reply. Ensure the wq has send the buffer before to continue. */
|
|
flush_workqueue(wdev->bh_wq);
|
|
ret = 0;
|
|
goto end;
|
|
}
|
|
|
|
if (wdev->poll_irq)
|
|
wfx_bh_poll_irq(wdev);
|
|
|
|
ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
|
|
if (!ret) {
|
|
dev_err(wdev->dev, "chip is abnormally long to answer\n");
|
|
reinit_completion(&wdev->hif_cmd.ready);
|
|
ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ);
|
|
}
|
|
if (!ret) {
|
|
dev_err(wdev->dev, "chip did not answer\n");
|
|
wfx_pending_dump_old_frames(wdev, 3000);
|
|
wdev->chip_frozen = true;
|
|
reinit_completion(&wdev->hif_cmd.done);
|
|
ret = -ETIMEDOUT;
|
|
} else {
|
|
ret = wdev->hif_cmd.ret;
|
|
}
|
|
|
|
end:
|
|
wdev->hif_cmd.buf_send = NULL;
|
|
mutex_unlock(&wdev->hif_cmd.lock);
|
|
|
|
if (ret &&
|
|
(cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) {
|
|
mib_name = wfx_get_mib_name(((u16 *)request)[2]);
|
|
mib_sep = "/";
|
|
}
|
|
if (ret < 0)
|
|
dev_err(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned error %d\n",
|
|
wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
|
|
if (ret > 0)
|
|
dev_warn(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned status %d\n",
|
|
wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any request anymore.
|
|
* Obviously, only call this function during device unregister.
|
|
*/
|
|
int wfx_hif_shutdown(struct wfx_dev *wdev)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
|
|
wfx_alloc_hif(0, &hif);
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
|
|
ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
|
|
if (wdev->pdata.gpio_wakeup)
|
|
gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
|
|
else
|
|
wfx_control_reg_write(wdev, 0);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
|
|
{
|
|
int ret;
|
|
size_t buf_len = sizeof(struct wfx_hif_req_configuration) + len;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->length = cpu_to_le16(len);
|
|
memcpy(body->pds_data, conf, len);
|
|
wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
|
|
ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->reset_stat = reset_stat;
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
int buf_len = sizeof(struct wfx_hif_cnf_read_mib) + val_len;
|
|
struct wfx_hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
struct wfx_hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
|
|
|
|
if (!body || !reply) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
body->mib_id = cpu_to_le16(mib_id);
|
|
wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body));
|
|
ret = wfx_cmd_send(wdev, hif, reply, buf_len, false);
|
|
|
|
if (!ret && mib_id != le16_to_cpu(reply->mib_id)) {
|
|
dev_warn(wdev->dev, "%s: confirmation mismatch request\n", __func__);
|
|
ret = -EIO;
|
|
}
|
|
if (ret == -ENOMEM)
|
|
dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n",
|
|
wfx_get_mib_name(mib_id), val_len, le16_to_cpu(reply->length));
|
|
if (!ret)
|
|
memcpy(val, &reply->mib_data, le16_to_cpu(reply->length));
|
|
else
|
|
memset(val, 0xFF, val_len);
|
|
out:
|
|
kfree(hif);
|
|
kfree(reply);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
int buf_len = sizeof(struct wfx_hif_req_write_mib) + val_len;
|
|
struct wfx_hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->mib_id = cpu_to_le16(mib_id);
|
|
body->length = cpu_to_le16(val_len);
|
|
memcpy(&body->mib_data, val, val_len);
|
|
wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len);
|
|
ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
|
|
int chan_start_idx, int chan_num)
|
|
{
|
|
int ret, i;
|
|
struct wfx_hif_msg *hif;
|
|
size_t buf_len = sizeof(struct wfx_hif_req_start_scan_alt) + chan_num * sizeof(u8);
|
|
struct wfx_hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
|
|
|
|
WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params");
|
|
WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params");
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
for (i = 0; i < req->n_ssids; i++) {
|
|
memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid, IEEE80211_MAX_SSID_LEN);
|
|
body->ssid_def[i].ssid_length = cpu_to_le32(req->ssids[i].ssid_len);
|
|
}
|
|
body->num_of_ssids = HIF_API_MAX_NB_SSIDS;
|
|
body->maintain_current_bss = 1;
|
|
body->disallow_ps = 1;
|
|
body->tx_power_level = cpu_to_le32(req->channels[chan_start_idx]->max_power);
|
|
body->num_of_channels = chan_num;
|
|
for (i = 0; i < chan_num; i++)
|
|
body->channel_list[i] = req->channels[i + chan_start_idx]->hw_value;
|
|
if (req->no_cck)
|
|
body->max_transmit_rate = API_RATE_INDEX_G_6MBPS;
|
|
else
|
|
body->max_transmit_rate = API_RATE_INDEX_B_1MBPS;
|
|
if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) {
|
|
body->min_channel_time = cpu_to_le32(50);
|
|
body->max_channel_time = cpu_to_le32(150);
|
|
} else {
|
|
body->min_channel_time = cpu_to_le32(10);
|
|
body->max_channel_time = cpu_to_le32(50);
|
|
body->num_of_probe_requests = 2;
|
|
body->probe_delay = 100;
|
|
}
|
|
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len);
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_stop_scan(struct wfx_vif *wvif)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
/* body associated to HIF_REQ_ID_STOP_SCAN is empty */
|
|
wfx_alloc_hif(0, &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0);
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
|
|
struct ieee80211_channel *channel, const u8 *ssid, int ssid_len)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
WARN_ON(!conf->beacon_int);
|
|
WARN_ON(!conf->basic_rates);
|
|
WARN_ON(sizeof(body->ssid) < ssid_len);
|
|
WARN(!conf->ibss_joined && !ssid_len, "joining an unknown BSS");
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->infrastructure_bss_mode = !conf->ibss_joined;
|
|
body->short_preamble = conf->use_short_preamble;
|
|
body->probe_for_join = !(channel->flags & IEEE80211_CHAN_NO_IR);
|
|
body->channel_number = channel->hw_value;
|
|
body->beacon_interval = cpu_to_le32(conf->beacon_int);
|
|
body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
|
|
memcpy(body->bssid, conf->bssid, sizeof(body->bssid));
|
|
if (ssid) {
|
|
body->ssid_length = cpu_to_le32(ssid_len);
|
|
memcpy(body->ssid, ssid, ssid_len);
|
|
}
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_set_bss_params *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->aid = cpu_to_le16(aid);
|
|
body->beacon_lost_count = beacon_lost_count;
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
/* FIXME: only send necessary bits */
|
|
struct wfx_hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
/* FIXME: swap bytes as necessary in body */
|
|
memcpy(body, arg, sizeof(*body));
|
|
if (wfx_api_older_than(wdev, 1, 5))
|
|
/* Legacy firmwares expect that add_key to be sent on right interface. */
|
|
wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY, sizeof(*body));
|
|
else
|
|
wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body));
|
|
ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_remove_key(struct wfx_dev *wdev, int idx)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->entry_index = idx;
|
|
wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body));
|
|
ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
|
|
const struct ieee80211_tx_queue_params *arg)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!body)
|
|
return -ENOMEM;
|
|
|
|
WARN_ON(arg->aifs > 255);
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->aifsn = arg->aifs;
|
|
body->cw_min = cpu_to_le16(arg->cw_min);
|
|
body->cw_max = cpu_to_le16(arg->cw_max);
|
|
body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP);
|
|
body->queue_id = 3 - queue;
|
|
/* API 2.0 has changed queue IDs values */
|
|
if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE)
|
|
body->queue_id = HIF_QUEUE_ID_BACKGROUND;
|
|
if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK)
|
|
body->queue_id = HIF_QUEUE_ID_BESTEFFORT;
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!body)
|
|
return -ENOMEM;
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
if (ps) {
|
|
body->enter_psm = 1;
|
|
/* Firmware does not support more than 128ms */
|
|
body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255);
|
|
if (body->fast_psm_idle_period)
|
|
body->fast_psm = 1;
|
|
}
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
|
|
const struct ieee80211_channel *channel)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
WARN_ON(!conf->beacon_int);
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->dtim_period = conf->dtim_period;
|
|
body->short_preamble = conf->use_short_preamble;
|
|
body->channel_number = channel->hw_value;
|
|
body->beacon_interval = cpu_to_le32(conf->beacon_int);
|
|
body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
|
|
body->ssid_length = conf->ssid_len;
|
|
memcpy(body->ssid, conf->ssid, conf->ssid_len);
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->enable_beaconing = enable ? 1 : 0;
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
struct wfx_hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
if (mac_addr)
|
|
ether_addr_copy(body->mac_addr, mac_addr);
|
|
body->mfpc = mfp ? 1 : 0;
|
|
body->unmap = unmap ? 1 : 0;
|
|
body->peer_sta_id = sta_id;
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body));
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|
|
|
|
int wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
|
|
{
|
|
int ret;
|
|
struct wfx_hif_msg *hif;
|
|
int buf_len = sizeof(struct wfx_hif_req_update_ie) + ies_len;
|
|
struct wfx_hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif);
|
|
|
|
if (!hif)
|
|
return -ENOMEM;
|
|
body->beacon = 1;
|
|
body->num_ies = cpu_to_le16(1);
|
|
memcpy(body->ie, ies, ies_len);
|
|
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len);
|
|
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
|
|
kfree(hif);
|
|
return ret;
|
|
}
|