2020-05-20 05:24:29

by Tony Chuang

[permalink] [raw]
Subject: [PATCH 5/7] rtw88: 8821c: add query rx desc support

From: Tzu-En Huang <[email protected]>

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 <[email protected]>
Signed-off-by: Yan-Hsuan Chuang <[email protected]>
---
drivers/net/wireless/realtek/rtw88/rtw8821c.c | 104 ++++++++++++++++++
drivers/net/wireless/realtek/rtw88/rtw8821c.h | 16 +++
2 files changed, 120 insertions(+)

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
--
2.17.1


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

On 2020-05-20 13:23:33 [+0800], [email protected] wrote:
> From: Tzu-En Huang <[email protected]>
>
> 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

2020-05-29 06:02:49

by Tony Chuang

[permalink] [raw]
Subject: RE: [PATCH 5/7] rtw88: 8821c: add query rx desc support


...
> > +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