/*
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "wil6210.h"
#include "wmi.h"
#define CHAN60G(_channel, _flags) { \
.band = IEEE80211_BAND_60GHZ, \
.center_freq = 56160 + (2160 * (_channel)), \
.hw_value = (_channel), \
.flags = (_flags), \
.max_antenna_gain = 0, \
.max_power = 40, \
}
static struct ieee80211_channel wil_60ghz_channels[] = {
CHAN60G(1, 0),
CHAN60G(2, 0),
CHAN60G(3, 0),
/* channel 4 not supported yet */
};
static struct ieee80211_supported_band wil_band_60ghz = {
.channels = wil_60ghz_channels,
.n_channels = ARRAY_SIZE(wil_60ghz_channels),
.ht_cap = {
.ht_supported = true,
.cap = 0, /* TODO */
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */
.mcs = {
/* MCS 1..12 - SC PHY */
.rx_mask = {0xfe, 0x1f}, /* 1..12 */
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */
},
},
};
static const struct ieee80211_txrx_stypes
wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_STATION] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
},
[NL80211_IFTYPE_AP] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
},
[NL80211_IFTYPE_P2P_CLIENT] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
},
[NL80211_IFTYPE_P2P_GO] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
},
};
static const u32 wil_cipher_suites[] = {
WLAN_CIPHER_SUITE_GCMP,
};
int wil_iftype_nl2wmi(enum nl80211_iftype type)
{
static const struct {
enum nl80211_iftype nl;
enum wmi_network_type wmi;
} __nl2wmi[] = {
{NL80211_IFTYPE_ADHOC, WMI_NETTYPE_ADHOC},
{NL80211_IFTYPE_STATION, WMI_NETTYPE_INFRA},
{NL80211_IFTYPE_AP, WMI_NETTYPE_AP},
{NL80211_IFTYPE_P2P_CLIENT, WMI_NETTYPE_P2P},
{NL80211_IFTYPE_P2P_GO, WMI_NETTYPE_P2P},
{NL80211_IFTYPE_MONITOR, WMI_NETTYPE_ADHOC}, /* FIXME */
};
uint i;
for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) {
if (__nl2wmi[i].nl == type)
return __nl2wmi[i].wmi;
}
return -EOPNOTSUPP;
}
int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
struct station_info *sinfo)
{
struct wmi_notify_req_cmd cmd = {
.cid = cid,
.interval_usec = 0,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
struct wmi_notify_req_done_event evt;
} __packed reply;
struct wil_net_stats *stats = &wil->sta[cid].stats;
int rc;
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
if (rc)
return rc;
wil_dbg_wmi(wil, "Link status for CID %d: {\n"
" MCS %d TSF 0x%016llx\n"
" BF status 0x%08x SNR 0x%08x SQI %d%%\n"
" Tx Tpt %d goodput %d Rx goodput %d\n"
" Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
cid, le16_to_cpu(reply.evt.bf_mcs),
le64_to_cpu(reply.evt.tsf), reply.evt.status,
le32_to_cpu(reply.evt.snr_val),
reply.evt.sqi,
le32_to_cpu(reply.evt.tx_tpt),
le32_to_cpu(reply.evt.tx_goodput),
le32_to_cpu(reply.evt.rx_goodput),
le16_to_cpu(reply.evt.my_rx_sector),
le16_to_cpu(reply.evt.my_tx_sector),
le16_to_cpu(reply.evt.other_rx_sector),
le16_to_cpu(reply.evt.other_tx_sector));
sinfo->generation = wil->sinfo_gen;
sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) |
BIT(NL80211_STA_INFO_TX_BYTES) |
BIT(NL80211_STA_INFO_RX_PACKETS) |
BIT(NL80211_STA_INFO_TX_PACKETS) |
BIT(NL80211_STA_INFO_RX_BITRATE) |
BIT(NL80211_STA_INFO_TX_BITRATE) |
BIT(NL80211_STA_INFO_RX_DROP_MISC) |
BIT(NL80211_STA_INFO_TX_FAILED);
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
sinfo->rxrate.mcs = stats->last_mcs_rx;
sinfo->