Commit 699c7730 authored by Tzu-En Huang's avatar Tzu-En Huang Committed by Kalle Valo
Browse files

rtw88: report tx rate to mac80211 stack



Whenever the firmware increases/decreases the bit rate used
to transmit to a peer, it sends an RA report through C2H to
driver. Driver can then record the bit rate in the peer's
struct rtw_sta_info, and report to mac80211 when it asks us
for the statistics of the sta by ieee80211_ops::sta_statistics

Signed-off-by: default avatarTzu-En Huang <tehuang@realtek.com>
Signed-off-by: default avatarYan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 46ebb174
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "reg.h"
#include "sec.h"
#include "debug.h"
#include "util.h"

static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
				      struct sk_buff *skb)
@@ -28,6 +29,75 @@ static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
	}
}

struct rtw_fw_iter_ra_data {
	struct rtw_dev *rtwdev;
	u8 *payload;
};

static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta)
{
	struct rtw_fw_iter_ra_data *ra_data = data;
	struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
	u8 mac_id, rate, sgi, bw;
	u8 mcs, nss;
	u32 bit_rate;

	mac_id = GET_RA_REPORT_MACID(ra_data->payload);
	if (si->mac_id != mac_id)
		return;

	si->ra_report.txrate.flags = 0;

	rate = GET_RA_REPORT_RATE(ra_data->payload);
	sgi = GET_RA_REPORT_SGI(ra_data->payload);
	bw = GET_RA_REPORT_BW(ra_data->payload);

	if (rate < DESC_RATEMCS0) {
		si->ra_report.txrate.legacy = rtw_desc_to_bitrate(rate);
		goto legacy;
	}

	rtw_desc_to_mcsrate(rate, &mcs, &nss);
	if (rate >= DESC_RATEVHT1SS_MCS0)
		si->ra_report.txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
	else if (rate >= DESC_RATEMCS0)
		si->ra_report.txrate.flags |= RATE_INFO_FLAGS_MCS;

	if (rate >= DESC_RATEMCS0) {
		si->ra_report.txrate.mcs = mcs;
		si->ra_report.txrate.nss = nss;
	}

	if (sgi)
		si->ra_report.txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;

	if (bw == RTW_CHANNEL_WIDTH_80)
		si->ra_report.txrate.bw = RATE_INFO_BW_80;
	else if (bw == RTW_CHANNEL_WIDTH_40)
		si->ra_report.txrate.bw = RATE_INFO_BW_40;
	else
		si->ra_report.txrate.bw = RATE_INFO_BW_20;

legacy:
	bit_rate = cfg80211_calculate_bitrate(&si->ra_report.txrate);

	si->ra_report.desc_rate = rate;
	si->ra_report.bit_rate = bit_rate;
}

static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload,
				    u8 length)
{
	struct rtw_fw_iter_ra_data ra_data;

	if (WARN(length < 7, "invalid ra report c2h length\n"))
		return;

	ra_data.rtwdev = rtwdev;
	ra_data.payload = payload;
	rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data);
}

void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
{
	struct rtw_c2h_cmd *c2h;
@@ -50,6 +120,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
	case C2H_HALMAC:
		rtw_fw_c2h_cmd_handle_ext(rtwdev, skb);
		break;
	case C2H_RA_RPT:
		rtw_fw_ra_report_handle(rtwdev, c2h->payload, len);
		break;
	default:
		break;
	}
+6 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
enum rtw_c2h_cmd_id {
	C2H_BT_INFO = 0x09,
	C2H_BT_MP_INFO = 0x0b,
	C2H_RA_RPT = 0x0c,
	C2H_HW_FEATURE_REPORT = 0x19,
	C2H_WLAN_INFO = 0x27,
	C2H_HW_FEATURE_DUMP = 0xfd,
@@ -119,6 +120,11 @@ struct rtw_rsvd_page {
#define GET_CCX_REPORT_SEQNUM(c2h_payload)	(c2h_payload[8] & 0xfc)
#define GET_CCX_REPORT_STATUS(c2h_payload)	(c2h_payload[9] & 0xc0)

#define GET_RA_REPORT_RATE(c2h_payload)		(c2h_payload[0] & 0x7f)
#define GET_RA_REPORT_SGI(c2h_payload)		((c2h_payload[0] & 0x80) >> 7)
#define GET_RA_REPORT_BW(c2h_payload)		(c2h_payload[6])
#define GET_RA_REPORT_MACID(c2h_payload)	(c2h_payload[1])

/* PKT H2C */
#define H2C_PKT_CMD_ID 0xFF
#define H2C_PKT_CATEGORY 0x01
+12 −0
Original line number Diff line number Diff line
@@ -578,6 +578,17 @@ static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
	return 0;
}

static void rtw_ops_sta_statistics(struct ieee80211_hw *hw,
				   struct ieee80211_vif *vif,
				   struct ieee80211_sta *sta,
				   struct station_info *sinfo)
{
	struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;

	sinfo->txrate = si->ra_report.txrate;
	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}

const struct ieee80211_ops rtw_ops = {
	.tx			= rtw_ops_tx,
	.wake_tx_queue		= rtw_ops_wake_tx_queue,
@@ -596,5 +607,6 @@ const struct ieee80211_ops rtw_ops = {
	.sw_scan_complete	= rtw_ops_sw_scan_complete,
	.mgd_prepare_tx		= rtw_ops_mgd_prepare_tx,
	.set_rts_threshold	= rtw_ops_set_rts_threshold,
	.sta_statistics		= rtw_ops_sta_statistics,
};
EXPORT_SYMBOL(rtw_ops);
+12 −0
Original line number Diff line number Diff line
@@ -86,6 +86,18 @@ static struct ieee80211_rate rtw_ratetable[] = {
	{.bitrate = 540, .hw_value = 0x0b,},
};

u16 rtw_desc_to_bitrate(u8 desc_rate)
{
	struct ieee80211_rate rate;

	if (WARN(desc_rate >= ARRAY_SIZE(rtw_ratetable), "invalid desc rate\n"))
		return 0;

	rate = rtw_ratetable[desc_rate];

	return rate.bitrate;
}

static struct ieee80211_supported_band rtw_band_2ghz = {
	.band = NL80211_BAND_2GHZ,

+10 −0
Original line number Diff line number Diff line
@@ -592,6 +592,12 @@ struct rtw_tx_report {
	struct timer_list purge_timer;
};

struct rtw_ra_report {
	struct rate_info txrate;
	u32 bit_rate;
	u8 desc_rate;
};

struct rtw_txq {
	struct list_head list;

@@ -623,6 +629,8 @@ struct rtw_sta_info {
	u64 ra_mask;

	DECLARE_BITMAP(tid_ba, IEEE80211_NUM_TIDS);

	struct rtw_ra_report ra_report;
};

struct rtw_vif {
@@ -1430,6 +1438,7 @@ bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val);
bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value);
void rtw_restore_reg(struct rtw_dev *rtwdev,
		     struct rtw_backup_info *bckp, u32 num);
void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss);
void rtw_set_channel(struct rtw_dev *rtwdev);
void rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
			 u32 config);
@@ -1442,5 +1451,6 @@ int rtw_core_init(struct rtw_dev *rtwdev);
void rtw_core_deinit(struct rtw_dev *rtwdev);
int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw);
void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw);
u16 rtw_desc_to_bitrate(u8 desc_rate);

#endif
Loading