Commit bc1efd73 authored by Sebastian Gottschall's avatar Sebastian Gottschall Committed by Kalle Valo

ath10k: add VHT160 support

This patch adds full VHT160 support for QCA9984 chipsets Tested on Netgear
R7800. 80+80 is possible, but disabled so far since it seems to contain
glitches like missing vht station flags (this may be firmware or mac80211
related).
Signed-off-by: default avatarSebastian Gottschall <s.gottschall@dd-wrt.com>
[kvalo@qca.qualcomm.com: refactoring and fix few warnings]
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 06efdbe7
...@@ -702,6 +702,10 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, ...@@ -702,6 +702,10 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
/* 80MHZ */ /* 80MHZ */
case 2: case 2:
status->vht_flag |= RX_VHT_FLAG_80MHZ; status->vht_flag |= RX_VHT_FLAG_80MHZ;
break;
case 3:
status->vht_flag |= RX_VHT_FLAG_160MHZ;
break;
} }
status->flag |= RX_FLAG_VHT; status->flag |= RX_FLAG_VHT;
...@@ -926,7 +930,7 @@ static void ath10k_process_rx(struct ath10k *ar, ...@@ -926,7 +930,7 @@ static void ath10k_process_rx(struct ath10k *ar,
*status = *rx_status; *status = *rx_status;
ath10k_dbg(ar, ATH10K_DBG_DATA, ath10k_dbg(ar, ATH10K_DBG_DATA,
"rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%llx fcs-err %i mic-err %i amsdu-more %i\n", "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%llx fcs-err %i mic-err %i amsdu-more %i\n",
skb, skb,
skb->len, skb->len,
ieee80211_get_SA(hdr), ieee80211_get_SA(hdr),
...@@ -940,6 +944,7 @@ static void ath10k_process_rx(struct ath10k *ar, ...@@ -940,6 +944,7 @@ static void ath10k_process_rx(struct ath10k *ar,
status->flag & RX_FLAG_VHT ? "vht" : "", status->flag & RX_FLAG_VHT ? "vht" : "",
status->flag & RX_FLAG_40MHZ ? "40" : "", status->flag & RX_FLAG_40MHZ ? "40" : "",
status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
status->vht_flag & RX_VHT_FLAG_160MHZ ? "160" : "",
status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
status->rate_idx, status->rate_idx,
status->vht_nss, status->vht_nss,
......
...@@ -569,10 +569,14 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) ...@@ -569,10 +569,14 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef)
case NL80211_CHAN_WIDTH_80: case NL80211_CHAN_WIDTH_80:
phymode = MODE_11AC_VHT80; phymode = MODE_11AC_VHT80;
break; break;
case NL80211_CHAN_WIDTH_160:
phymode = MODE_11AC_VHT160;
break;
case NL80211_CHAN_WIDTH_80P80:
phymode = MODE_11AC_VHT80_80;
break;
case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10: case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
phymode = MODE_UNKNOWN; phymode = MODE_UNKNOWN;
break; break;
} }
...@@ -971,6 +975,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) ...@@ -971,6 +975,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
arg.vdev_id = vdev_id; arg.vdev_id = vdev_id;
arg.channel.freq = channel->center_freq; arg.channel.freq = channel->center_freq;
arg.channel.band_center_freq1 = chandef->center_freq1; arg.channel.band_center_freq1 = chandef->center_freq1;
arg.channel.band_center_freq2 = chandef->center_freq2;
/* TODO setup this dynamically, what in case we /* TODO setup this dynamically, what in case we
don't have any vifs? */ don't have any vifs? */
...@@ -1417,6 +1422,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, ...@@ -1417,6 +1422,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
arg.channel.freq = chandef->chan->center_freq; arg.channel.freq = chandef->chan->center_freq;
arg.channel.band_center_freq1 = chandef->center_freq1; arg.channel.band_center_freq1 = chandef->center_freq1;
arg.channel.band_center_freq2 = chandef->center_freq2;
arg.channel.mode = chan_to_phymode(chandef); arg.channel.mode = chan_to_phymode(chandef);
arg.channel.min_power = 0; arg.channel.min_power = 0;
...@@ -2480,6 +2486,9 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, ...@@ -2480,6 +2486,9 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
if (sta->bandwidth == IEEE80211_STA_RX_BW_80) if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
arg->peer_flags |= ar->wmi.peer_flags->bw80; arg->peer_flags |= ar->wmi.peer_flags->bw80;
if (sta->bandwidth == IEEE80211_STA_RX_BW_160)
arg->peer_flags |= ar->wmi.peer_flags->bw160;
arg->peer_vht_rates.rx_max_rate = arg->peer_vht_rates.rx_max_rate =
__le16_to_cpu(vht_cap->vht_mcs.rx_highest); __le16_to_cpu(vht_cap->vht_mcs.rx_highest);
arg->peer_vht_rates.rx_mcs_set = arg->peer_vht_rates.rx_mcs_set =
...@@ -2536,6 +2545,18 @@ static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta) ...@@ -2536,6 +2545,18 @@ static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
static enum wmi_phy_mode ath10k_mac_get_phymode_vht(struct ath10k *ar, static enum wmi_phy_mode ath10k_mac_get_phymode_vht(struct ath10k *ar,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
if (sta->bandwidth == IEEE80211_STA_RX_BW_160) {
switch (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
return MODE_11AC_VHT160;
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
return MODE_11AC_VHT80_80;
default:
/* not sure if this is a valid case? */
return MODE_11AC_VHT160;
}
}
if (sta->bandwidth == IEEE80211_STA_RX_BW_80) if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
return MODE_11AC_VHT80; return MODE_11AC_VHT80;
...@@ -4321,6 +4342,13 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) ...@@ -4321,6 +4342,13 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
vht_cap.cap |= val; vht_cap.cap |= val;
} }
/* Currently the firmware seems to be buggy, don't enable 80+80
* mode until that's resolved.
*/
if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) &&
!(ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
mcs_map = 0; mcs_map = 0;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i))) if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
...@@ -6979,6 +7007,9 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, ...@@ -6979,6 +7007,9 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
bw = WMI_PEER_CHWIDTH_80MHZ; bw = WMI_PEER_CHWIDTH_80MHZ;
break; break;
case IEEE80211_STA_RX_BW_160: case IEEE80211_STA_RX_BW_160:
bw = WMI_PEER_CHWIDTH_160MHZ;
break;
default:
ath10k_warn(ar, "Invalid bandwidth %d in rc update for %pM\n", ath10k_warn(ar, "Invalid bandwidth %d in rc update for %pM\n",
sta->bandwidth, sta->addr); sta->bandwidth, sta->addr);
bw = WMI_PEER_CHWIDTH_20MHZ; bw = WMI_PEER_CHWIDTH_20MHZ;
......
...@@ -3637,6 +3637,7 @@ static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { ...@@ -3637,6 +3637,7 @@ static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
.vht = WMI_TLV_PEER_VHT, .vht = WMI_TLV_PEER_VHT,
.bw80 = WMI_TLV_PEER_80MHZ, .bw80 = WMI_TLV_PEER_80MHZ,
.pmf = WMI_TLV_PEER_PMF, .pmf = WMI_TLV_PEER_PMF,
.bw160 = WMI_TLV_PEER_160MHZ,
}; };
/************/ /************/
......
...@@ -543,6 +543,7 @@ enum wmi_tlv_peer_flags { ...@@ -543,6 +543,7 @@ enum wmi_tlv_peer_flags {
WMI_TLV_PEER_VHT = 0x02000000, WMI_TLV_PEER_VHT = 0x02000000,
WMI_TLV_PEER_80MHZ = 0x04000000, WMI_TLV_PEER_80MHZ = 0x04000000,
WMI_TLV_PEER_PMF = 0x08000000, WMI_TLV_PEER_PMF = 0x08000000,
WMI_TLV_PEER_160MHZ = 0x20000000,
}; };
enum wmi_tlv_tag { enum wmi_tlv_tag {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "wmi-ops.h" #include "wmi-ops.h"
#include "p2p.h" #include "p2p.h"
#include "hw.h" #include "hw.h"
#include "hif.h"
#define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9 #define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9
#define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ) #define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ)
...@@ -1574,6 +1575,7 @@ static const struct wmi_peer_flags_map wmi_peer_flags_map = { ...@@ -1574,6 +1575,7 @@ static const struct wmi_peer_flags_map wmi_peer_flags_map = {
.bw80 = WMI_PEER_80MHZ, .bw80 = WMI_PEER_80MHZ,
.vht_2g = WMI_PEER_VHT_2G, .vht_2g = WMI_PEER_VHT_2G,
.pmf = WMI_PEER_PMF, .pmf = WMI_PEER_PMF,
.bw160 = WMI_PEER_160MHZ,
}; };
static const struct wmi_peer_flags_map wmi_10x_peer_flags_map = { static const struct wmi_peer_flags_map wmi_10x_peer_flags_map = {
...@@ -1591,6 +1593,7 @@ static const struct wmi_peer_flags_map wmi_10x_peer_flags_map = { ...@@ -1591,6 +1593,7 @@ static const struct wmi_peer_flags_map wmi_10x_peer_flags_map = {
.spatial_mux = WMI_10X_PEER_SPATIAL_MUX, .spatial_mux = WMI_10X_PEER_SPATIAL_MUX,
.vht = WMI_10X_PEER_VHT, .vht = WMI_10X_PEER_VHT,
.bw80 = WMI_10X_PEER_80MHZ, .bw80 = WMI_10X_PEER_80MHZ,
.bw160 = WMI_10X_PEER_160MHZ,
}; };
static const struct wmi_peer_flags_map wmi_10_2_peer_flags_map = { static const struct wmi_peer_flags_map wmi_10_2_peer_flags_map = {
...@@ -1610,6 +1613,7 @@ static const struct wmi_peer_flags_map wmi_10_2_peer_flags_map = { ...@@ -1610,6 +1613,7 @@ static const struct wmi_peer_flags_map wmi_10_2_peer_flags_map = {
.bw80 = WMI_10_2_PEER_80MHZ, .bw80 = WMI_10_2_PEER_80MHZ,
.vht_2g = WMI_10_2_PEER_VHT_2G, .vht_2g = WMI_10_2_PEER_VHT_2G,
.pmf = WMI_10_2_PEER_PMF, .pmf = WMI_10_2_PEER_PMF,
.bw160 = WMI_10_2_PEER_160MHZ,
}; };
void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
...@@ -1634,7 +1638,10 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, ...@@ -1634,7 +1638,10 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
ch->mhz = __cpu_to_le32(arg->freq); ch->mhz = __cpu_to_le32(arg->freq);
ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1); ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
ch->band_center_freq2 = 0; if (arg->mode == MODE_11AC_VHT80_80)
ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq2);
else
ch->band_center_freq2 = 0;
ch->min_power = arg->min_power; ch->min_power = arg->min_power;
ch->max_power = arg->max_power; ch->max_power = arg->max_power;
ch->reg_power = arg->max_reg_power; ch->reg_power = arg->max_reg_power;
......
...@@ -1728,8 +1728,10 @@ enum wmi_phy_mode { ...@@ -1728,8 +1728,10 @@ enum wmi_phy_mode {
MODE_11AC_VHT20_2G = 11, MODE_11AC_VHT20_2G = 11,
MODE_11AC_VHT40_2G = 12, MODE_11AC_VHT40_2G = 12,
MODE_11AC_VHT80_2G = 13, MODE_11AC_VHT80_2G = 13,
MODE_UNKNOWN = 14, MODE_11AC_VHT80_80 = 14,
MODE_MAX = 14 MODE_11AC_VHT160 = 15,
MODE_UNKNOWN = 16,
MODE_MAX = 16
}; };
static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode) static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode)
...@@ -1757,6 +1759,10 @@ static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode) ...@@ -1757,6 +1759,10 @@ static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode)
return "11ac-vht40"; return "11ac-vht40";
case MODE_11AC_VHT80: case MODE_11AC_VHT80:
return "11ac-vht80"; return "11ac-vht80";
case MODE_11AC_VHT160:
return "11ac-vht160";
case MODE_11AC_VHT80_80:
return "11ac-vht80+80";
case MODE_11AC_VHT20_2G: case MODE_11AC_VHT20_2G:
return "11ac-vht20-2g"; return "11ac-vht20-2g";
case MODE_11AC_VHT40_2G: case MODE_11AC_VHT40_2G:
...@@ -1811,6 +1817,7 @@ struct wmi_channel { ...@@ -1811,6 +1817,7 @@ struct wmi_channel {
struct wmi_channel_arg { struct wmi_channel_arg {
u32 freq; u32 freq;
u32 band_center_freq1; u32 band_center_freq1;
u32 band_center_freq2;
bool passive; bool passive;
bool allow_ibss; bool allow_ibss;
bool allow_ht; bool allow_ht;
...@@ -1875,9 +1882,18 @@ enum wmi_channel_change_cause { ...@@ -1875,9 +1882,18 @@ enum wmi_channel_change_cause {
#define WMI_VHT_CAP_MAX_MPDU_LEN_MASK 0x00000003 #define WMI_VHT_CAP_MAX_MPDU_LEN_MASK 0x00000003
#define WMI_VHT_CAP_RX_LDPC 0x00000010 #define WMI_VHT_CAP_RX_LDPC 0x00000010
#define WMI_VHT_CAP_SGI_80MHZ 0x00000020 #define WMI_VHT_CAP_SGI_80MHZ 0x00000020
#define WMI_VHT_CAP_SGI_160MHZ 0x00000040
#define WMI_VHT_CAP_TX_STBC 0x00000080 #define WMI_VHT_CAP_TX_STBC 0x00000080
#define WMI_VHT_CAP_RX_STBC_MASK 0x00000300 #define WMI_VHT_CAP_RX_STBC_MASK 0x00000300
#define WMI_VHT_CAP_RX_STBC_MASK_SHIFT 8 #define WMI_VHT_CAP_RX_STBC_MASK_SHIFT 8
#define WMI_VHT_CAP_SU_BFER 0x00000800
#define WMI_VHT_CAP_SU_BFEE 0x00001000
#define WMI_VHT_CAP_MAX_CS_ANT_MASK 0x0000E000
#define WMI_VHT_CAP_MAX_CS_ANT_MASK_SHIFT 13
#define WMI_VHT_CAP_MAX_SND_DIM_MASK 0x00070000
#define WMI_VHT_CAP_MAX_SND_DIM_MASK_SHIFT 16
#define WMI_VHT_CAP_MU_BFER 0x00080000
#define WMI_VHT_CAP_MU_BFEE 0x00100000
#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP 0x03800000 #define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP 0x03800000
#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT 23 #define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT 23
#define WMI_VHT_CAP_RX_FIXED_ANT 0x10000000 #define WMI_VHT_CAP_RX_FIXED_ANT 0x10000000
...@@ -1926,6 +1942,8 @@ enum { ...@@ -1926,6 +1942,8 @@ enum {
REGDMN_MODE_11AC_VHT40PLUS = 0x40000, /* 5Ghz, VHT40 + channels */ REGDMN_MODE_11AC_VHT40PLUS = 0x40000, /* 5Ghz, VHT40 + channels */
REGDMN_MODE_11AC_VHT40MINUS = 0x80000, /* 5Ghz VHT40 - channels */ REGDMN_MODE_11AC_VHT40MINUS = 0x80000, /* 5Ghz VHT40 - channels */
REGDMN_MODE_11AC_VHT80 = 0x100000, /* 5Ghz, VHT80 channels */ REGDMN_MODE_11AC_VHT80 = 0x100000, /* 5Ghz, VHT80 channels */
REGDMN_MODE_11AC_VHT160 = 0x200000, /* 5Ghz, VHT160 channels */
REGDMN_MODE_11AC_VHT80_80 = 0x400000, /* 5Ghz, VHT80+80 channels */
REGDMN_MODE_ALL = 0xffffffff REGDMN_MODE_ALL = 0xffffffff
}; };
...@@ -5783,6 +5801,7 @@ enum wmi_peer_chwidth { ...@@ -5783,6 +5801,7 @@ enum wmi_peer_chwidth {
WMI_PEER_CHWIDTH_20MHZ = 0, WMI_PEER_CHWIDTH_20MHZ = 0,
WMI_PEER_CHWIDTH_40MHZ = 1, WMI_PEER_CHWIDTH_40MHZ = 1,
WMI_PEER_CHWIDTH_80MHZ = 2, WMI_PEER_CHWIDTH_80MHZ = 2,
WMI_PEER_CHWIDTH_160MHZ = 3,
}; };
enum wmi_peer_param { enum wmi_peer_param {
...@@ -5873,6 +5892,7 @@ struct wmi_peer_flags_map { ...@@ -5873,6 +5892,7 @@ struct wmi_peer_flags_map {
u32 bw80; u32 bw80;
u32 vht_2g; u32 vht_2g;
u32 pmf; u32 pmf;
u32 bw160;
}; };
enum wmi_peer_flags { enum wmi_peer_flags {
...@@ -5892,6 +5912,7 @@ enum wmi_peer_flags { ...@@ -5892,6 +5912,7 @@ enum wmi_peer_flags {
WMI_PEER_80MHZ = 0x04000000, WMI_PEER_80MHZ = 0x04000000,
WMI_PEER_VHT_2G = 0x08000000, WMI_PEER_VHT_2G = 0x08000000,
WMI_PEER_PMF = 0x10000000, WMI_PEER_PMF = 0x10000000,
WMI_PEER_160MHZ = 0x20000000
}; };
enum wmi_10x_peer_flags { enum wmi_10x_peer_flags {
...@@ -5909,6 +5930,7 @@ enum wmi_10x_peer_flags { ...@@ -5909,6 +5930,7 @@ enum wmi_10x_peer_flags {
WMI_10X_PEER_SPATIAL_MUX = 0x00200000, WMI_10X_PEER_SPATIAL_MUX = 0x00200000,
WMI_10X_PEER_VHT = 0x02000000, WMI_10X_PEER_VHT = 0x02000000,
WMI_10X_PEER_80MHZ = 0x04000000, WMI_10X_PEER_80MHZ = 0x04000000,
WMI_10X_PEER_160MHZ = 0x20000000
}; };
enum wmi_10_2_peer_flags { enum wmi_10_2_peer_flags {
...@@ -5928,6 +5950,7 @@ enum wmi_10_2_peer_flags { ...@@ -5928,6 +5950,7 @@ enum wmi_10_2_peer_flags {
WMI_10_2_PEER_80MHZ = 0x04000000, WMI_10_2_PEER_80MHZ = 0x04000000,
WMI_10_2_PEER_VHT_2G = 0x08000000, WMI_10_2_PEER_VHT_2G = 0x08000000,
WMI_10_2_PEER_PMF = 0x10000000, WMI_10_2_PEER_PMF = 0x10000000,
WMI_10_2_PEER_160MHZ = 0x20000000
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment