aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/wfx/hif_tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/wfx/hif_tx.c')
-rw-r--r--drivers/staging/wfx/hif_tx.c164
1 files changed, 107 insertions, 57 deletions
diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c
index cb7cddcb9815..2428363371fa 100644
--- a/drivers/staging/wfx/hif_tx.c
+++ b/drivers/staging/wfx/hif_tx.c
@@ -6,7 +6,6 @@
* Copyright (c) 2017-2019, Silicon Laboratories, Inc.
* Copyright (c) 2010, ST-Ericsson
*/
-#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include "hif_tx.h"
@@ -221,41 +220,59 @@ int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val,
return ret;
}
-int hif_scan(struct wfx_vif *wvif, const struct wfx_scan_params *arg)
+int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
+ int chan_start_idx, int chan_num)
{
int ret, i;
struct hif_msg *hif;
- struct hif_ssid_def *ssids;
- size_t buf_len = sizeof(struct hif_req_start_scan) +
- arg->scan_req.num_of_channels * sizeof(u8) +
- arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def);
- struct hif_req_start_scan *body = wfx_alloc_hif(buf_len, &hif);
- u8 *ptr = (u8 *) body + sizeof(*body);
-
- WARN(arg->scan_req.num_of_channels > HIF_API_MAX_NB_CHANNELS, "invalid params");
- WARN(arg->scan_req.num_of_ssi_ds > 2, "invalid params");
- WARN(arg->scan_req.band > 1, "invalid params");
-
- // FIXME: This API is unnecessary complex, fixing NumOfChannels and
- // adding a member SsidDef at end of struct hif_req_start_scan would
- // simplify that a lot.
- memcpy(body, &arg->scan_req, sizeof(*body));
- cpu_to_le32s(&body->min_channel_time);
- cpu_to_le32s(&body->max_channel_time);
- cpu_to_le32s(&body->tx_power_level);
- memcpy(ptr, arg->ssids,
- arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def));
- ssids = (struct hif_ssid_def *) ptr;
- for (i = 0; i < body->num_of_ssi_ds; ++i)
- cpu_to_le32s(&ssids[i].ssid_length);
- ptr += arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def);
- memcpy(ptr, arg->ch, arg->scan_req.num_of_channels * sizeof(u8));
- ptr += arg->scan_req.num_of_channels * sizeof(u8);
- WARN(buf_len != ptr - (u8 *) body, "allocation size mismatch");
+ size_t buf_len =
+ sizeof(struct hif_req_start_scan_alt) + chan_num * sizeof(u8);
+ struct hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
+ int tmo_chan_fg, tmo_chan_bg, tmo;
+
+ WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params");
+ WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params");
+
+ compiletime_assert(IEEE80211_MAX_SSID_LEN == HIF_API_SSID_SIZE,
+ "API inconsistency");
+ 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;
+ // Background scan is always a good idea
+ body->scan_type.type = 1;
+ body->scan_flags.fbg = 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;
+ }
+ tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU;
+ tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay;
+ tmo_chan_fg *= body->num_of_probe_requests;
+ tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg);
+
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;
+ return ret ? ret : usecs_to_jiffies(tmo);
}
int hif_stop_scan(struct wfx_vif *wvif)
@@ -271,18 +288,29 @@ int hif_stop_scan(struct wfx_vif *wvif)
return ret;
}
-int hif_join(struct wfx_vif *wvif, const struct hif_req_join *arg)
+int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+ const struct ieee80211_channel *channel, const u8 *ssidie)
{
int ret;
struct hif_msg *hif;
struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif);
- memcpy(body, arg, sizeof(struct hif_req_join));
- cpu_to_le16s(&body->channel_number);
- cpu_to_le16s(&body->atim_window);
- cpu_to_le32s(&body->ssid_length);
- cpu_to_le32s(&body->beacon_interval);
- cpu_to_le32s(&body->basic_rate_set);
+ WARN_ON(!conf->basic_rates);
+ body->infrastructure_bss_mode = !conf->ibss_joined;
+ body->short_preamble = conf->use_short_preamble;
+ if (channel && channel->flags & IEEE80211_CHAN_NO_IR)
+ body->probe_for_join = 0;
+ else
+ body->probe_for_join = 1;
+ body->channel_number = cpu_to_le16(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 (!conf->ibss_joined && ssidie) {
+ body->ssid_length = cpu_to_le32(ssidie[1]);
+ memcpy(body->ssid, &ssidie[2], ssidie[1]);
+ }
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
kfree(hif);
@@ -341,19 +369,28 @@ int hif_remove_key(struct wfx_dev *wdev, int idx)
return ret;
}
-int hif_set_edca_queue_params(struct wfx_vif *wvif,
- const struct hif_req_edca_queue_params *arg)
+int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
+ const struct ieee80211_tx_queue_params *arg)
{
int ret;
struct hif_msg *hif;
struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body),
&hif);
- // NOTE: queues numerotation are not the same between WFx and Linux
- memcpy(body, arg, sizeof(*body));
- cpu_to_le16s(&body->cw_min);
- cpu_to_le16s(&body->cw_max);
- cpu_to_le16s(&body->tx_op_limit);
+ if (!body)
+ return -ENOMEM;
+
+ WARN_ON(arg->aifs > 255);
+ 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);
@@ -361,43 +398,57 @@ int hif_set_edca_queue_params(struct wfx_vif *wvif,
return ret;
}
-int hif_set_pm(struct wfx_vif *wvif, const struct hif_req_set_pm_mode *arg)
+int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
{
int ret;
struct hif_msg *hif;
struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif);
- memcpy(body, arg, sizeof(*body));
+ if (!body)
+ return -ENOMEM;
+
+ if (ps) {
+ body->pm_mode.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->pm_mode.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 hif_start(struct wfx_vif *wvif, const struct hif_req_start *arg)
+int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+ const struct ieee80211_channel *channel)
{
int ret;
struct hif_msg *hif;
struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
- memcpy(body, arg, sizeof(*body));
- cpu_to_le16s(&body->channel_number);
- cpu_to_le32s(&body->beacon_interval);
- cpu_to_le32s(&body->basic_rate_set);
+ body->dtim_period = conf->dtim_period,
+ body->short_preamble = conf->use_short_preamble,
+ body->channel_number = cpu_to_le16(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 hif_beacon_transmit(struct wfx_vif *wvif, bool enable_beaconing)
+int hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
{
int ret;
struct hif_msg *hif;
struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body),
&hif);
- body->enable_beaconing = enable_beaconing ? 1 : 0;
+ 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);
@@ -421,16 +472,15 @@ int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id)
return ret;
}
-int hif_update_ie(struct wfx_vif *wvif, const struct hif_ie_flags *target_frame,
- const u8 *ies, size_t ies_len)
+int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
{
int ret;
struct hif_msg *hif;
int buf_len = sizeof(struct hif_req_update_ie) + ies_len;
struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif);
- memcpy(&body->ie_flags, target_frame, sizeof(struct hif_ie_flags));
- body->num_i_es = cpu_to_le16(1);
+ body->ie_flags.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);