diff mbox series

[5/7] rtw88: 8821c: add query rx desc support

Message ID 20200520052335.22466-6-yhchuang@realtek.com (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show
Series rtw88: 8821c: add basic function routines | expand

Commit Message

Tony Chuang May 20, 2020, 5:23 a.m. UTC
From: Tzu-En Huang <tehuang@realtek.com>

In different situtation, driver is able to get the current
environment status from the information in rx packets.

For rx packets, rx descriptor describes the current condition
of the received packet. Add the function to query rx descriptor for
8821c.

Signed-off-by: Tzu-En Huang <tehuang@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/rtw8821c.c | 104 ++++++++++++++++++
 drivers/net/wireless/realtek/rtw88/rtw8821c.h |  16 +++
 2 files changed, 120 insertions(+)

Comments

Sebastian Andrzej Siewior May 28, 2020, 4:09 p.m. UTC | #1
On 2020-05-20 13:23:33 [+0800], yhchuang@realtek.com wrote:
> From: Tzu-En Huang <tehuang@realtek.com>
> 
> In different situtation, driver is able to get the current
> environment status from the information in rx packets.

Some RX packets contain also information about environment status. 

Implement rtw_chip_ops::query_rx_desc() for 8821c. Parse the RX
descriptor which describes the current condition of the received packet.
 
> --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
> @@ -366,6 +366,109 @@ static void rtw8821c_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw,
>  	rtw8821c_set_channel_rxdfir(rtwdev, bw);
>  }
>  
> +static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status,
> +				   struct rtw_rx_pkt_stat *pkt_stat)
> +{
> +	s8 min_rx_power = -120;
> +	u8 pwdb = GET_PHY_STAT_P0_PWDB(phy_status);
> +
> +	if (pwdb >= -57)

Isn't pwdb always >= -57 since its type is unsigned?

> +		pkt_stat->rx_power[RF_PATH_A] = pwdb - 100;
> +	else
> +		pkt_stat->rx_power[RF_PATH_A] = pwdb - 102;
> +	pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
> +	pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
> +	pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A],
> +				     min_rx_power);
> +}
> +static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
> +				   struct rtw_rx_pkt_stat *pkt_stat,
> +				   struct ieee80211_rx_status *rx_status)
> +{
> +	struct ieee80211_hdr *hdr;
> +	u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
> +	u8 *phy_status = NULL;
> +
> +	memset(pkt_stat, 0, sizeof(*pkt_stat));
> +
> +	pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
> +	pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
> +	pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
> +	pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc);
> +	pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
> +	pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
> +	pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
> +	pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
> +	pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
> +	pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
> +	pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc);
> +	pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
> +
> +	/* drv_info_sz is in unit of 8-bytes */
> +	pkt_stat->drv_info_sz *= 8;
> +
> +	/* c2h cmd pkt's rx/phy status is not interested */
> +	if (pkt_stat->is_c2h)
> +		return;
> +
> +	hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
> +				       pkt_stat->drv_info_sz);

I would feel safer if you could ensure that that hdr is within valid buffer bounds.
So that hdr and hdr + sizeof(*hdr)- 1 doesn't point outside of rx_desc.

> +	if (pkt_stat->phy_status) {
> +		phy_status = rx_desc + desc_sz + pkt_stat->shift;

and here, too.

> +		query_phy_status(rtwdev, phy_status, pkt_stat);
> +	}
> +
> +	rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
> +}
> +
>  static void
>  rtw8821c_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
>  {

Sebastian
Tony Chuang May 29, 2020, 5:58 a.m. UTC | #2
...
> > +static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
> > +				   struct rtw_rx_pkt_stat *pkt_stat,
> > +				   struct ieee80211_rx_status *rx_status)
> > +{
> > +	struct ieee80211_hdr *hdr;
> > +	u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
> > +	u8 *phy_status = NULL;
> > +
> > +	memset(pkt_stat, 0, sizeof(*pkt_stat));
> > +
> > +	pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
> > +	pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
> > +	pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
> > +	pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc);
> > +	pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
> > +	pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
> > +	pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
> > +	pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
> > +	pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
> > +	pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
> > +	pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc);
> > +	pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
> > +
> > +	/* drv_info_sz is in unit of 8-bytes */
> > +	pkt_stat->drv_info_sz *= 8;
> > +
> > +	/* c2h cmd pkt's rx/phy status is not interested */
> > +	if (pkt_stat->is_c2h)
> > +		return;
> > +
> > +	hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
> > +				       pkt_stat->drv_info_sz);
> 
> I would feel safer if you could ensure that that hdr is within valid buffer bounds.
> So that hdr and hdr + sizeof(*hdr)- 1 doesn't point outside of rx_desc.
> 
> > +	if (pkt_stat->phy_status) {
> > +		phy_status = rx_desc + desc_sz + pkt_stat->shift;
> 
> and here, too.
> 
> > +		query_phy_status(rtwdev, phy_status, pkt_stat);
> > +	}
> > +
> > +	rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
> > +}
> > +
> >  static void
> >  rtw8821c_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path,
> u8 rs)
> >  {
> 

I can try to merge the RX query code in 8821C/8822B/8822C.
Looks like they are much the same.

Yan-Hsuan
diff mbox series

Patch

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
index e3b52caf9ab3..ce75715a0e83 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
@@ -366,6 +366,109 @@  static void rtw8821c_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 	rtw8821c_set_channel_rxdfir(rtwdev, bw);
 }
 
+static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status,
+				   struct rtw_rx_pkt_stat *pkt_stat)
+{
+	s8 min_rx_power = -120;
+	u8 pwdb = GET_PHY_STAT_P0_PWDB(phy_status);
+
+	if (pwdb >= -57)
+		pkt_stat->rx_power[RF_PATH_A] = pwdb - 100;
+	else
+		pkt_stat->rx_power[RF_PATH_A] = pwdb - 102;
+	pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
+	pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
+	pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A],
+				     min_rx_power);
+}
+
+static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status,
+				   struct rtw_rx_pkt_stat *pkt_stat)
+{
+	u8 rxsc, bw;
+	s8 min_rx_power = -120;
+
+	if (pkt_stat->rate > DESC_RATE11M && pkt_stat->rate < DESC_RATEMCS0)
+		rxsc = GET_PHY_STAT_P1_L_RXSC(phy_status);
+	else
+		rxsc = GET_PHY_STAT_P1_HT_RXSC(phy_status);
+
+	if (rxsc >= 1 && rxsc <= 8)
+		bw = RTW_CHANNEL_WIDTH_20;
+	else if (rxsc >= 9 && rxsc <= 12)
+		bw = RTW_CHANNEL_WIDTH_40;
+	else if (rxsc >= 13)
+		bw = RTW_CHANNEL_WIDTH_80;
+	else
+		bw = GET_PHY_STAT_P1_RF_MODE(phy_status);
+
+	pkt_stat->rx_power[RF_PATH_A] = GET_PHY_STAT_P1_PWDB_A(phy_status) - 110;
+	pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
+	pkt_stat->bw = bw;
+	pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A],
+				     min_rx_power);
+}
+
+static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
+			     struct rtw_rx_pkt_stat *pkt_stat)
+{
+	u8 page;
+
+	page = *phy_status & 0xf;
+
+	switch (page) {
+	case 0:
+		query_phy_status_page0(rtwdev, phy_status, pkt_stat);
+		break;
+	case 1:
+		query_phy_status_page1(rtwdev, phy_status, pkt_stat);
+		break;
+	default:
+		rtw_warn(rtwdev, "unused phy status page (%d)\n", page);
+		return;
+	}
+}
+
+static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
+				   struct rtw_rx_pkt_stat *pkt_stat,
+				   struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_hdr *hdr;
+	u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
+	u8 *phy_status = NULL;
+
+	memset(pkt_stat, 0, sizeof(*pkt_stat));
+
+	pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
+	pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
+	pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
+	pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc);
+	pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
+	pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
+	pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
+	pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
+	pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
+	pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
+	pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc);
+	pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
+
+	/* drv_info_sz is in unit of 8-bytes */
+	pkt_stat->drv_info_sz *= 8;
+
+	/* c2h cmd pkt's rx/phy status is not interested */
+	if (pkt_stat->is_c2h)
+		return;
+
+	hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
+				       pkt_stat->drv_info_sz);
+	if (pkt_stat->phy_status) {
+		phy_status = rx_desc + desc_sz + pkt_stat->shift;
+		query_phy_status(rtwdev, phy_status, pkt_stat);
+	}
+
+	rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
+}
+
 static void
 rtw8821c_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
 {
@@ -833,6 +936,7 @@  static struct rtw_prioq_addrs prioq_addrs_8821c = {
 static struct rtw_chip_ops rtw8821c_ops = {
 	.phy_set_param		= rtw8821c_phy_set_param,
 	.read_efuse		= rtw8821c_read_efuse,
+	.query_rx_desc		= rtw8821c_query_rx_desc,
 	.set_channel		= rtw8821c_set_channel,
 	.mac_init		= rtw8821c_mac_init,
 	.read_rf		= rtw_phy_read_rf,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
index b30487640828..fbf71f71b6ad 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
@@ -145,6 +145,22 @@  _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
 #define WLAN_RX_TSF_CFG		(WLAN_CCK_RX_TSF | (WLAN_OFDM_RX_TSF) << 8)
 #define WLAN_PRE_TXCNT_TIME_TH		0x1E4
 
+/* phy status page0 */
+#define GET_PHY_STAT_P0_PWDB(phy_stat)                                         \
+	le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
+
+/* phy status page1 */
+#define GET_PHY_STAT_P1_PWDB_A(phy_stat)                                       \
+	le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
+#define GET_PHY_STAT_P1_PWDB_B(phy_stat)                                       \
+	le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(23, 16))
+#define GET_PHY_STAT_P1_RF_MODE(phy_stat)                                      \
+	le32_get_bits(*((__le32 *)(phy_stat) + 0x03), GENMASK(29, 28))
+#define GET_PHY_STAT_P1_L_RXSC(phy_stat)                                       \
+	le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8))
+#define GET_PHY_STAT_P1_HT_RXSC(phy_stat)                                      \
+	le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12))
+
 #define REG_INIRTS_RATE_SEL 0x0480
 #define REG_HTSTFWT	0x800
 #define REG_RXPSEL	0x808