Commit 5614618e authored by Johannes Berg's avatar Johannes Berg
Browse files

mac80211: support drivers reporting VHT RX



Add support to mac80211 for having drivers report
received VHT MCS information.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent db9c64cf
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -717,7 +717,11 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
 *	(including FCS) was received.
 * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
 * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
 * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
 * @RX_FLAG_40MHZ: HT40 (40 MHz) was used
 * @RX_FLAG_80MHZ: 80 MHz was used
 * @RX_FLAG_80P80MHZ: 80+80 MHz was used
 * @RX_FLAG_160MHZ: 160 MHz was used
 * @RX_FLAG_SHORT_GI: Short guard interval was used
 * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present.
 *	Valid only for data frames (mainly A-MPDU)
@@ -760,6 +764,10 @@ enum mac80211_rx_flags {
	RX_FLAG_AMPDU_DELIM_CRC_ERROR	= BIT(19),
	RX_FLAG_AMPDU_DELIM_CRC_KNOWN	= BIT(20),
	RX_FLAG_MACTIME_END		= BIT(21),
	RX_FLAG_VHT			= BIT(22),
	RX_FLAG_80MHZ			= BIT(23),
	RX_FLAG_80P80MHZ		= BIT(24),
	RX_FLAG_160MHZ			= BIT(25),
};

/**
@@ -780,7 +788,8 @@ enum mac80211_rx_flags {
 *	@IEEE80211_HW_SIGNAL_*
 * @antenna: antenna used
 * @rate_idx: index of data rate into band's supported rates or MCS index if
 *	HT rates are use (RX_FLAG_HT)
 *	HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
 * @vht_nss: number of streams (VHT only)
 * @flag: %RX_FLAG_*
 * @rx_flags: internal RX flags for mac80211
 * @ampdu_reference: A-MPDU reference number, must be a different value for
@@ -803,6 +812,7 @@ struct ieee80211_rx_status {
	u16 vendor_radiotap_len;
	u16 freq;
	u8 rate_idx;
	u8 vht_nss;
	u8 rx_flags;
	u8 band;
	u8 antenna;
+23 −3
Original line number Diff line number Diff line
@@ -374,7 +374,8 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in
{
	enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);

	if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
	if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
	    !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) {
		struct ieee80211_supported_band *sband;
		sband = sta->local->hw.wiphy->bands[band];
		rate->legacy = sband->bitrates[idx].bitrate;
@@ -444,13 +445,32 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
	sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);

	sinfo->rxrate.flags = 0;
	if (sta->last_rx_rate_flag & RX_FLAG_HT)
	if (sta->last_rx_rate_flag & RX_FLAG_HT) {
		sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
		sinfo->rxrate.mcs = sta->last_rx_rate_idx;
	} else if (sta->last_rx_rate_flag & RX_FLAG_VHT) {
		sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
		sinfo->rxrate.nss = sta->last_rx_rate_vht_nss;
		sinfo->rxrate.mcs = sta->last_rx_rate_idx;
	} else {
		struct ieee80211_supported_band *sband;

		sband = sta->local->hw.wiphy->bands[
				ieee80211_get_sdata_band(sta->sdata)];
		sinfo->rxrate.legacy =
			sband->bitrates[sta->last_rx_rate_idx].bitrate;
	}

	if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
		sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
	if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
		sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
	rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
	if (sta->last_rx_rate_flag & RX_FLAG_80MHZ)
		sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
	if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ)
		sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
	if (sta->last_rx_rate_flag & RX_FLAG_160MHZ)
		sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;

	if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
+15 −5
Original line number Diff line number Diff line
@@ -193,7 +193,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
	pos++;

	/* IEEE80211_RADIOTAP_RATE */
	if (!rate || status->flag & RX_FLAG_HT) {
	if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) {
		/*
		 * Without rate information don't add it. If we have,
		 * MCS information is a separate field in radiotap,
@@ -213,7 +213,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
	if (status->band == IEEE80211_BAND_5GHZ)
		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
				   pos);
	else if (status->flag & RX_FLAG_HT)
	else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
		put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
				   pos);
	else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
@@ -1356,6 +1356,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
			if (ieee80211_is_data(hdr->frame_control)) {
				sta->last_rx_rate_idx = status->rate_idx;
				sta->last_rx_rate_flag = status->flag;
				sta->last_rx_rate_vht_nss = status->vht_nss;
			}
		}
	} else if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -1367,6 +1368,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
		if (ieee80211_is_data(hdr->frame_control)) {
			sta->last_rx_rate_idx = status->rate_idx;
			sta->last_rx_rate_flag = status->flag;
			sta->last_rx_rate_vht_nss = status->vht_nss;
		}
	}

@@ -2710,7 +2712,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
		status = IEEE80211_SKB_RXCB((rx->skb));

		sband = rx->local->hw.wiphy->bands[status->band];
		if (!(status->flag & RX_FLAG_HT))
		if (!(status->flag & RX_FLAG_HT) &&
		    !(status->flag & RX_FLAG_VHT))
			rate = &sband->bitrates[status->rate_idx];

		ieee80211_rx_cooked_monitor(rx, rate);
@@ -2877,8 +2880,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
		} else if (!rx->sta) {
			int rate_idx;
			if (status->flag & RX_FLAG_HT)
				rate_idx = 0; /* TODO: HT rates */
			if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
				rate_idx = 0; /* TODO: HT/VHT rates */
			else
				rate_idx = status->rate_idx;
			ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
@@ -3154,6 +3157,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
				 status->rate_idx,
				 status->rate_idx))
				goto drop;
		} else if (status->flag & RX_FLAG_VHT) {
			if (WARN_ONCE(status->rate_idx > 9 ||
				      !status->vht_nss ||
				      status->vht_nss > 8,
				      "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
				      status->rate_idx, status->vht_nss))
				goto drop;
		} else {
			if (WARN_ON(status->rate_idx >= sband->n_bitrates))
				goto drop;
+3 −1
Original line number Diff line number Diff line
@@ -227,6 +227,7 @@ struct sta_ampdu_mlme {
 *	"the" transmit rate
 * @last_rx_rate_idx: rx status rate index of the last data packet
 * @last_rx_rate_flag: rx status flag of the last data packet
 * @last_rx_rate_vht_nss: rx status nss of last data packet
 * @lock: used for locking all fields that require locking, see comments
 *	in the header file.
 * @drv_unblock_wk: used for driver PS unblocking
@@ -343,7 +344,8 @@ struct sta_info {
	unsigned long tx_fragments;
	struct ieee80211_tx_rate last_tx_rate;
	int last_rx_rate_idx;
	int last_rx_rate_flag;
	u32 last_rx_rate_flag;
	u8 last_rx_rate_vht_nss;
	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];

	/*
+14 −0
Original line number Diff line number Diff line
@@ -2069,6 +2069,20 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
			ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
		if (status->flag & RX_FLAG_SHORT_GI)
			ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
	} else if (status->flag & RX_FLAG_VHT) {
		ri.flags |= RATE_INFO_FLAGS_VHT_MCS;
		ri.mcs = status->rate_idx;
		ri.nss = status->vht_nss;
		if (status->flag & RX_FLAG_40MHZ)
			ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
		if (status->flag & RX_FLAG_80MHZ)
			ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
		if (status->flag & RX_FLAG_80P80MHZ)
			ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
		if (status->flag & RX_FLAG_160MHZ)
			ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
		if (status->flag & RX_FLAG_SHORT_GI)
			ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
	} else {
		struct ieee80211_supported_band *sband;