qtnfmac: use per-band HT/VHT info from wireless device

HT/VHT capabilities must be reported per each band supported by a radio,
not for all bands on a radio. Furthermore, driver better not assume
any capabilities and just use whetever is reported by device itself.

To support this, convert "get channels" command into "get band info"
command. Difference is that it may also carry HT/VHT capabilities along
with channels information.

While at it, also add "num_bitrates" field to "get band info" command,
for future use.

Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Igor Mitsyanko
2017-10-30 18:04:47 -07:00
committed by Kalle Valo
parent bd99a3013b
commit e294cbfda0
5 changed files with 84 additions and 59 deletions

View File

@@ -1115,19 +1115,50 @@ qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac,
sizeof(mac_info->vht_cap));
}
static void qtnf_cmd_resp_band_fill_htcap(const u8 *info,
struct ieee80211_sta_ht_cap *bcap)
{
const struct ieee80211_ht_cap *ht_cap =
(const struct ieee80211_ht_cap *)info;
bcap->ht_supported = true;
bcap->cap = le16_to_cpu(ht_cap->cap_info);
bcap->ampdu_factor =
ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
bcap->ampdu_density =
(ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >>
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
memcpy(&bcap->mcs, &ht_cap->mcs, sizeof(bcap->mcs));
}
static void qtnf_cmd_resp_band_fill_vhtcap(const u8 *info,
struct ieee80211_sta_vht_cap *bcap)
{
const struct ieee80211_vht_cap *vht_cap =
(const struct ieee80211_vht_cap *)info;
bcap->vht_supported = true;
bcap->cap = le32_to_cpu(vht_cap->vht_cap_info);
memcpy(&bcap->vht_mcs, &vht_cap->supp_mcs, sizeof(bcap->vht_mcs));
}
static int
qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band,
struct qlink_resp_get_chan_info *resp,
size_t payload_len)
qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
struct qlink_resp_band_info_get *resp,
size_t payload_len)
{
u16 tlv_type;
size_t tlv_len;
size_t tlv_dlen;
const struct qlink_tlv_hdr *tlv;
const struct qlink_tlv_channel *qchan;
struct ieee80211_channel *chan;
unsigned int chidx = 0;
u32 qflags;
memset(&band->ht_cap, 0, sizeof(band->ht_cap));
memset(&band->vht_cap, 0, sizeof(band->vht_cap));
if (band->channels) {
if (band->n_channels == resp->num_chans) {
memset(band->channels, 0,
@@ -1155,7 +1186,8 @@ qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band,
while (payload_len >= sizeof(*tlv)) {
tlv_type = le16_to_cpu(tlv->type);
tlv_len = le16_to_cpu(tlv->len) + sizeof(*tlv);
tlv_dlen = le16_to_cpu(tlv->len);
tlv_len = tlv_dlen + sizeof(*tlv);
if (tlv_len > payload_len) {
pr_warn("malformed TLV 0x%.2X; LEN: %zu\n",
@@ -1241,13 +1273,32 @@ qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band,
chan->hw_value, chan->flags, chan->max_power,
chan->max_reg_power);
break;
case WLAN_EID_HT_CAPABILITY:
if (unlikely(tlv_dlen !=
sizeof(struct ieee80211_ht_cap))) {
pr_err("bad HTCAP TLV len %zu\n", tlv_dlen);
goto error_ret;
}
qtnf_cmd_resp_band_fill_htcap(tlv->val, &band->ht_cap);
break;
case WLAN_EID_VHT_CAPABILITY:
if (unlikely(tlv_dlen !=
sizeof(struct ieee80211_vht_cap))) {
pr_err("bad VHTCAP TLV len %zu\n", tlv_dlen);
goto error_ret;
}
qtnf_cmd_resp_band_fill_vhtcap(tlv->val,
&band->vht_cap);
break;
default:
pr_warn("unknown TLV type: %#x\n", tlv_type);
break;
}
payload_len -= tlv_len;
tlv = (struct qlink_tlv_hdr *)((u8 *)tlv + tlv_len);
tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_dlen);
}
if (payload_len) {
@@ -1469,13 +1520,13 @@ out:
return ret;
}
int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
struct ieee80211_supported_band *band)
int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,
struct ieee80211_supported_band *band)
{
struct sk_buff *cmd_skb, *resp_skb = NULL;
size_t info_len;
struct qlink_cmd_chans_info_get *cmd;
struct qlink_resp_get_chan_info *resp;
struct qlink_cmd_band_info_get *cmd;
struct qlink_resp_band_info_get *resp;
u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
u8 qband;
@@ -1495,12 +1546,12 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
}
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
QLINK_CMD_CHANS_INFO_GET,
QLINK_CMD_BAND_INFO_GET,
sizeof(*cmd));
if (!cmd_skb)
return -ENOMEM;
cmd = (struct qlink_cmd_chans_info_get *)cmd_skb->data;
cmd = (struct qlink_cmd_band_info_get *)cmd_skb->data;
cmd->band = qband;
qtnf_bus_lock(mac->bus);
@@ -1517,7 +1568,7 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
goto out;
}
resp = (struct qlink_resp_get_chan_info *)resp_skb->data;
resp = (struct qlink_resp_band_info_get *)resp_skb->data;
if (resp->band != qband) {
pr_err("MAC%u: reply band %u != cmd band %u\n", mac->macid,
resp->band, qband);
@@ -1525,7 +1576,7 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
goto out;
}
ret = qtnf_cmd_resp_fill_channels_info(band, resp, info_len);
ret = qtnf_cmd_resp_fill_band_info(band, resp, info_len);
out:
qtnf_bus_unlock(mac->bus);