From patchwork Fri Feb 7 09:28:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 216510 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4C1B6C352A3 for ; Fri, 7 Feb 2020 09:28:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 213CC20838 for ; Fri, 7 Feb 2020 09:28:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726819AbgBGJ2y (ORCPT ); Fri, 7 Feb 2020 04:28:54 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44677 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726451AbgBGJ2y (ORCPT ); Fri, 7 Feb 2020 04:28:54 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179SlkG018552, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (RTEXMB06.realtek.com.tw[172.21.6.99]) by rtits2.realtek.com.tw (8.15.2/2.57/5.78) with ESMTPS id 0179SlkG018552 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:47 +0800 Received: from RTEXMB05.realtek.com.tw (172.21.6.98) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1779.2; Fri, 7 Feb 2020 17:28:47 +0800 Received: from RTEXMB06.realtek.com.tw (172.21.6.99) by RTEXMB05.realtek.com.tw (172.21.6.98) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1779.2; Fri, 7 Feb 2020 17:28:47 +0800 Received: from RTITCASV01.realtek.com.tw (172.21.6.18) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.1.1779.2 via Frontend Transport; Fri, 7 Feb 2020 17:28:47 +0800 Received: from localhost.localdomain (172.21.68.128) by RTITCASV01.realtek.com.tw (172.21.6.18) with Microsoft SMTP Server id 14.3.468.0; Fri, 7 Feb 2020 17:28:46 +0800 From: To: CC: , , Subject: [PATCH 1/8] rtw88: sar: add SAR of TX power limit Date: Fri, 7 Feb 2020 17:28:37 +0800 Message-ID: <20200207092844.29175-2-yhchuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200207092844.29175-1-yhchuang@realtek.com> References: <20200207092844.29175-1-yhchuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.68.128] Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Ping-Ke Shih Originally, there are three factors of TX power: 1) TX base power, calibrated manually and programmed in efuse. 2) By-rate power, an offset to increase power depends on TX rate. 3) TX limit power, an offset to contraint the max power. So, driver can get the TX power index by using: TX_POWER_IDX = tx_base_power + min(by-rate, limit) To take SAR into consideration, we can treat it as another limit of the TX power. Then driver can get the TX power by using: TX_POWER_IDX = tx_base_power + min(by-rate, limit, sar) Note that the values stored in driver are not presented in dBm, so driver needs to also convert the power limit indexes of SAR with tx_scale_factor, then get the difference to the TX base power. rtw_phy_set_tx_power_sar() will convert the values of SAR power in unit of 0.125d Bm (sar_q3) and store them in tx_pwr_sar_{2,5}g[regd][path][rs][ch]. Since certain SAR tables have single one table that isn't regulatory domain specific, parser can apply to all 'regd' or only one domain RTW_REGD_WW that SAR TX power limit can be applied no matter which regulatory domain is selected. Because driver get 'sar' argument by rtw_phy_get_tx_power_limit() with rule sar = is_existing(tx_pwr_sar_{2,5}g[regd]) ? tx_pwr_sar_{2,5}g[regd] : tx_pwr_sar_{2,5}g[RTW_REGD_WW]; There are various sources of SAR table, but it is expected to adopt only one source. So, save current source of rtw_sar_sources to prevent more than one source are adopted. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang --- drivers/net/wireless/realtek/rtw88/debug.c | 14 +- drivers/net/wireless/realtek/rtw88/main.h | 17 ++ drivers/net/wireless/realtek/rtw88/phy.c | 173 +++++++++++++++++---- drivers/net/wireless/realtek/rtw88/phy.h | 3 + 4 files changed, 175 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 5a181e01ebef..3ec15a49ecc9 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -530,8 +530,8 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) u8 ch = hal->current_channel; u8 regd = rtwdev->regd.txpwr_regd; - seq_printf(m, "%-4s %-10s %-3s%6s %-4s %4s (%-4s %-4s)\n", - "path", "rate", "pwr", "", "base", "", "byr", "lmt"); + seq_printf(m, "%-4s %-10s %-3s%6s %-4s %4s (%-4s %-4s %-4s)\n", + "path", "rate", "pwr", "", "base", "", "byr", "lmt", "sar"); mutex_lock(&hal->tx_power_mutex); for (path = RF_PATH_A; path <= RF_PATH_B; path++) { @@ -553,13 +553,15 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) seq_printf(m, "%4c ", path + 'A'); rtw_print_rate(m, rate); - seq_printf(m, " %3u(0x%02x) %4u %4d (%4d %4d)\n", + seq_printf(m, " %3u(0x%02x) %4u %4d (%4d %4d %4d)\n", hal->tx_pwr_tbl[path][rate], hal->tx_pwr_tbl[path][rate], pwr_param.pwr_base, - min_t(s8, pwr_param.pwr_offset, - pwr_param.pwr_limit), - pwr_param.pwr_offset, pwr_param.pwr_limit); + min3(pwr_param.pwr_offset, + pwr_param.pwr_limit, + pwr_param.pwr_sar), + pwr_param.pwr_offset, pwr_param.pwr_limit, + pwr_param.pwr_sar); } } diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index f334d201bfb5..b4e9e18f89a5 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -386,6 +386,13 @@ enum rtw_wow_flags { RTW_WOW_FLAG_MAX, }; +enum rtw_sar_sources { + RTW_SAR_SOURCE_NONE, + RTW_SAR_SOURCE_VNDCMD, + RTW_SAR_SOURCE_ACPI_STATIC, + RTW_SAR_SOURCE_ACPI_DYNAMIC, +}; + /* the power index is represented by differences, which cck-1s & ht40-1s are * the base values, so for 1s's differences, there are only ht20 & ofdm */ @@ -1513,6 +1520,10 @@ struct rtw_fw_state { u16 h2c_version; }; +struct rtw_sar { + enum rtw_sar_sources source; +}; + struct rtw_hal { u32 rcr; @@ -1558,6 +1569,10 @@ struct rtw_hal { [RTW_CHANNEL_WIDTH_MAX] [RTW_RATE_SECTION_MAX] [RTW_MAX_CHANNEL_NUM_5G]; + s8 tx_pwr_sar_2g[RTW_REGD_MAX][RTW_RF_PATH_MAX][RTW_RATE_SECTION_MAX] + [RTW_MAX_CHANNEL_NUM_2G]; + s8 tx_pwr_sar_5g[RTW_REGD_MAX][RTW_RF_PATH_MAX][RTW_RATE_SECTION_MAX] + [RTW_MAX_CHANNEL_NUM_5G]; s8 tx_pwr_tbl[RTW_RF_PATH_MAX] [DESC_RATE_MAX]; }; @@ -1630,6 +1645,8 @@ struct rtw_dev { struct rtw_fw_state wow_fw; struct rtw_wow_param wow; + struct rtw_sar sar; + /* hci related data, must be last */ u8 priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index eea9d888fbf1..930757c07b46 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -1295,6 +1295,94 @@ static void rtw_phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band, } } +static void +rtw_phy_set_tx_power_sar_by_chidx(struct rtw_dev *rtwdev, u8 regd, u8 rfpath, + u8 band, u8 rs, u8 ch_idx, s8 sar) +{ + struct rtw_hal *hal = &rtwdev->hal; + s8 base; + s8 ww_sar; + s8 s; + + if (band == PHY_BAND_2G) { + base = hal->tx_pwr_by_rate_base_2g[rfpath][rs]; + s = sar - base; + hal->tx_pwr_sar_2g[regd][rfpath][rs][ch_idx] = s; + if (regd == RTW_REGD_WW) + return; + ww_sar = hal->tx_pwr_sar_2g[RTW_REGD_WW][rfpath][rs][ch_idx]; + ww_sar = min(ww_sar, s); + hal->tx_pwr_sar_2g[RTW_REGD_WW][rfpath][rs][ch_idx] = ww_sar; + } else { + base = hal->tx_pwr_by_rate_base_5g[rfpath][rs]; + s = sar - base; + hal->tx_pwr_sar_5g[regd][rfpath][rs][ch_idx] = s; + if (regd == RTW_REGD_WW) + return; + ww_sar = hal->tx_pwr_sar_5g[RTW_REGD_WW][rfpath][rs][ch_idx]; + ww_sar = min(ww_sar, s); + hal->tx_pwr_sar_5g[RTW_REGD_WW][rfpath][rs][ch_idx] = ww_sar; + } +} + +static void +rtw_phy_set_tx_power_sar_by_range(struct rtw_dev *rtwdev, u8 regd, u8 rfpath, + u8 band, u8 chidx_start, u8 chidx_end, u8 sar_q3) +{ + u8 rs; + u8 ch_idx; + s8 sar; + + if (regd >= RTW_REGD_MAX || rfpath >= RTW_RF_PATH_MAX) + return; + + sar = sar_q3 >> (3 - (int)rtwdev->chip->txgi_factor); + + for (ch_idx = chidx_start; ch_idx <= chidx_end; ch_idx++) + for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) + rtw_phy_set_tx_power_sar_by_chidx(rtwdev, regd, rfpath, + band, rs, ch_idx, sar); +} + +void rtw_phy_set_tx_power_sar(struct rtw_dev *rtwdev, u8 regd, u8 rfpath, + u8 ch_start, u8 ch_end, u8 sar_q3) +{ + u8 band_start, band_end; + int chidx_start, chidx_end; + + band_start = ch_start <= 14 ? PHY_BAND_2G : PHY_BAND_5G; + band_end = ch_end <= 14 ? PHY_BAND_2G : PHY_BAND_5G; + + if (band_start == band_end) { + chidx_start = rtw_channel_to_idx(band_start, ch_start); + chidx_end = rtw_channel_to_idx(band_start, ch_end); + if (chidx_start < 0 || chidx_end < 0) + goto err; + rtw_phy_set_tx_power_sar_by_range(rtwdev, regd, rfpath, band_start, + chidx_start, chidx_end, sar_q3); + return; + } + + chidx_start = rtw_channel_to_idx(PHY_BAND_2G, ch_start); + if (chidx_start < 0) + goto err; + rtw_phy_set_tx_power_sar_by_range(rtwdev, regd, rfpath, PHY_BAND_2G, + chidx_start, RTW_MAX_CHANNEL_NUM_2G - 1, + sar_q3); + + chidx_end = rtw_channel_to_idx(PHY_BAND_5G, ch_end); + if (chidx_end < 0) + goto err; + rtw_phy_set_tx_power_sar_by_range(rtwdev, regd, rfpath, PHY_BAND_5G, + 0, chidx_end, sar_q3); + + return; + +err: + rtw_warn(rtwdev, "SAR: invalid channel (start/end)=(%d/%d)\n", + ch_start, ch_end); +} + /* cross-reference 5G power limits if values are not assigned */ static void rtw_xref_5g_txpwr_lmt(struct rtw_dev *rtwdev, u8 regd, @@ -1676,9 +1764,10 @@ static u8 rtw_phy_get_5g_tx_power_index(struct rtw_dev *rtwdev, return tx_power; } -static s8 rtw_phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band, - enum rtw_bandwidth bw, u8 rf_path, - u8 rate, u8 channel, u8 regd) +static void rtw_phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band, + enum rtw_bandwidth bw, u8 rf_path, + u8 rate, u8 channel, u8 regd, + struct rtw_power_params *pwr_param) { struct rtw_hal *hal = &rtwdev->hal; u8 *cch_by_bw = hal->cch_by_bw; @@ -1687,9 +1776,10 @@ static s8 rtw_phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band, int ch_idx; u8 cur_bw, cur_ch; s8 cur_lmt; + s8 sar, sar_ww; if (regd > RTW_REGD_WW) - return power_limit; + goto err; if (rate >= DESC_RATE1M && rate <= DESC_RATE11M) rs = RTW_RATE_SECTION_CCK; @@ -1729,44 +1819,68 @@ static s8 rtw_phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band, power_limit = min_t(s8, cur_lmt, power_limit); } - return power_limit; + ch_idx = rtw_channel_to_idx(band, channel); + if (ch_idx < 0) + goto err; + + if (band == PHY_BAND_2G) { + sar = hal->tx_pwr_sar_2g[regd][rf_path][rs][ch_idx]; + sar_ww = hal->tx_pwr_sar_2g[RTW_REGD_WW][rf_path][rs][ch_idx]; + } else { + sar = hal->tx_pwr_sar_5g[regd][rf_path][rs][ch_idx]; + sar_ww = hal->tx_pwr_sar_5g[RTW_REGD_WW][rf_path][rs][ch_idx]; + } + if (sar >= rtwdev->chip->max_power_index) + sar = sar_ww; + + pwr_param->pwr_sar = sar; + pwr_param->pwr_limit = power_limit; + return; err: WARN(1, "invalid arguments, band=%d, bw=%d, path=%d, rate=%d, ch=%d\n", band, bw, rf_path, rate, channel); - return (s8)rtwdev->chip->max_power_index; + pwr_param->pwr_sar = (s8)rtwdev->chip->max_power_index; + pwr_param->pwr_limit = (s8)rtwdev->chip->max_power_index; } -void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, - u8 ch, u8 regd, struct rtw_power_params *pwr_param) +static void rtw_phy_get_tx_power_base(struct rtw_dev *rtwdev, u8 band, + enum rtw_bandwidth bw, u8 path, u8 rate, + u8 ch, struct rtw_power_params *pwr_param) { struct rtw_hal *hal = &rtwdev->hal; struct rtw_txpwr_idx *pwr_idx; - u8 group, band; - u8 *base = &pwr_param->pwr_base; - s8 *offset = &pwr_param->pwr_offset; - s8 *limit = &pwr_param->pwr_limit; + u8 group; + u8 base; + s8 offset; pwr_idx = &rtwdev->efuse.txpwr_idx_table[path]; group = rtw_get_channel_group(ch); /* base power index for 2.4G/5G */ - if (IS_CH_2G_BAND(ch)) { - band = PHY_BAND_2G; - *base = rtw_phy_get_2g_tx_power_index(rtwdev, - &pwr_idx->pwr_idx_2g, - bw, rate, group); - *offset = hal->tx_pwr_by_rate_offset_2g[path][rate]; + if (band == PHY_BAND_2G) { + base = rtw_phy_get_2g_tx_power_index(rtwdev, + &pwr_idx->pwr_idx_2g, + bw, rate, group); + offset = hal->tx_pwr_by_rate_offset_2g[path][rate]; } else { - band = PHY_BAND_5G; - *base = rtw_phy_get_5g_tx_power_index(rtwdev, - &pwr_idx->pwr_idx_5g, - bw, rate, group); - *offset = hal->tx_pwr_by_rate_offset_5g[path][rate]; + base = rtw_phy_get_5g_tx_power_index(rtwdev, + &pwr_idx->pwr_idx_5g, + bw, rate, group); + offset = hal->tx_pwr_by_rate_offset_5g[path][rate]; } - *limit = rtw_phy_get_tx_power_limit(rtwdev, band, bw, path, - rate, ch, regd); + pwr_param->pwr_base = base; + pwr_param->pwr_offset = offset; +} + +void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, + u8 ch, u8 regd, struct rtw_power_params *pwr_param) +{ + u8 band = IS_CH_2G_BAND(ch) ? PHY_BAND_2G : PHY_BAND_5G; + + rtw_phy_get_tx_power_base(rtwdev, band, bw, path, rate, ch, pwr_param); + rtw_phy_get_tx_power_limit(rtwdev, band, bw, path, rate, ch, regd, pwr_param); } u8 @@ -1781,7 +1895,8 @@ rtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate, channel, regd, &pwr_param); tx_power = pwr_param.pwr_base; - offset = min_t(s8, pwr_param.pwr_offset, pwr_param.pwr_limit); + offset = min3(pwr_param.pwr_offset, pwr_param.pwr_limit, + pwr_param.pwr_sar); if (rtwdev->chip->en_dis_dpd) offset += rtw_phy_get_dis_dpd_by_rate_diff(rtwdev, rate); @@ -1970,6 +2085,12 @@ void rtw_phy_init_tx_power(struct rtw_dev *rtwdev) for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) rtw_phy_init_tx_power_limit(rtwdev, regd, bw, rs); + + /* init tx power sar */ + memset(hal->tx_pwr_sar_2g, rtwdev->chip->max_power_index, + sizeof(hal->tx_pwr_sar_2g)); + memset(hal->tx_pwr_sar_5g, rtwdev->chip->max_power_index, + sizeof(hal->tx_pwr_sar_5g)); } void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index af916d8784cd..ba9b28a6c0bc 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -139,12 +139,15 @@ struct rtw_power_params { u8 pwr_base; s8 pwr_offset; s8 pwr_limit; + s8 pwr_sar; }; void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, u8 ch, u8 regd, struct rtw_power_params *pwr_param); +void rtw_phy_set_tx_power_sar(struct rtw_dev *rtwdev, u8 regd, u8 rfpath, + u8 ch_start, u8 ch_end, u8 sar_q3); enum rtw_phy_cck_pd_lv { CCK_PD_LV0, From patchwork Fri Feb 7 09:28:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 216509 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50BFEC352A4 for ; Fri, 7 Feb 2020 09:28:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 284DB20726 for ; Fri, 7 Feb 2020 09:28:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726899AbgBGJ25 (ORCPT ); Fri, 7 Feb 2020 04:28:57 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44688 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726586AbgBGJ24 (ORCPT ); Fri, 7 Feb 2020 04:28:56 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179Sog4018564, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (RTEXMB06.realtek.com.tw[172.21.6.99]) by rtits2.realtek.com.tw (8.15.2/2.57/5.78) with ESMTPS id 0179Sog4018564 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:50 +0800 Received: from RTEXMB05.realtek.com.tw (172.21.6.98) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1779.2; Fri, 7 Feb 2020 17:28:50 +0800 Received: from RTEXMB06.realtek.com.tw (172.21.6.99) by RTEXMB05.realtek.com.tw (172.21.6.98) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1779.2; Fri, 7 Feb 2020 17:28:50 +0800 Received: from RTITCASV01.realtek.com.tw (172.21.6.18) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.1.1779.2 via Frontend Transport; Fri, 7 Feb 2020 17:28:50 +0800 Received: from localhost.localdomain (172.21.68.128) by RTITCASV01.realtek.com.tw (172.21.6.18) with Microsoft SMTP Server id 14.3.468.0; Fri, 7 Feb 2020 17:28:49 +0800 From: To: CC: , , Subject: [PATCH 4/8] rtw88: sar: Load static SAR table from ACPI WRDS method Date: Fri, 7 Feb 2020 17:28:40 +0800 Message-ID: <20200207092844.29175-5-yhchuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200207092844.29175-1-yhchuang@realtek.com> References: <20200207092844.29175-1-yhchuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.68.128] Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Ping-Ke Shih ACPI WRDS method returns static SAR table that contains two chains (RF paths) and five power limit data for each chain. The limit data are corresponding to certain ranges of frequency, such as 2.4G band, 5.15~5.35G etc. The data is in Q.3 notation that is the same with SAR entry function, so we don't need to convert its quantity. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang --- drivers/net/wireless/realtek/rtw88/Makefile | 1 + drivers/net/wireless/realtek/rtw88/main.c | 2 + drivers/net/wireless/realtek/rtw88/sar.c | 200 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/sar.h | 10 + 4 files changed, 213 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw88/sar.c create mode 100644 drivers/net/wireless/realtek/rtw88/sar.h diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 935333f734a9..0e141edfd174 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -17,6 +17,7 @@ rtw88-y += main.o \ bf.o \ wow.o \ vndcmd.o \ + sar.o \ regd.o rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 7156a06eea74..23cbb00e16b1 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -16,6 +16,7 @@ #include "debug.h" #include "bf.h" #include "vndcmd.h" +#include "sar.h" unsigned int rtw_fw_lps_deep_mode; EXPORT_SYMBOL(rtw_fw_lps_deep_mode); @@ -1305,6 +1306,7 @@ static int rtw_chip_board_info_setup(struct rtw_dev *rtwdev) rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl); rtw_phy_tx_power_by_rate_config(hal); rtw_phy_tx_power_limit_config(hal); + rtw_sar_load_table(rtwdev); return 0; } diff --git a/drivers/net/wireless/realtek/rtw88/sar.c b/drivers/net/wireless/realtek/rtw88/sar.c new file mode 100644 index 000000000000..f15366ce1046 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/sar.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include +#include "main.h" +#include "debug.h" +#include "phy.h" +#include "sar.h" + +#define RTW_SAR_WRDS_CHAIN_NR 2 + +enum rtw_sar_limit_index { + RTW_SAR_LMT_CH1_14, + RTW_SAR_LMT_CH36_64, + RTW_SAR_LMT_UND1, + RTW_SAR_LMT_CH100_144, + RTW_SAR_LMT_CH149_165, + + RTW_SAR_LMT_TOTAL_NR, +}; + +struct rtw_sar_limits { + s8 limit[RTW_SAR_LMT_TOTAL_NR]; +}; + +struct rtw_sar_wrds { + struct rtw_sar_limits chain[RTW_SAR_WRDS_CHAIN_NR]; +}; + +#define ACPI_WRDS_METHOD "WRDS" +#define ACPI_WRDS_SIZE sizeof(struct rtw_sar_wrds) +#define ACPI_WRDS_TOTAL_SIZE (sizeof(struct rtw_sar_wrds) + 2) +#define ACPI_WIFI_DOMAIN 0x07 + +#ifdef CONFIG_ACPI +static union acpi_object *rtw_sar_get_acpiobj(struct rtw_dev *rtwdev, + const char *method) +{ + struct device *dev = rtwdev->dev; + acpi_handle root_handle; + acpi_handle handle; + acpi_status status; + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + + /* Check device handler */ + root_handle = ACPI_HANDLE(dev); + if (!root_handle) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: Could not retireve root port ACPI handle\n"); + return NULL; + } + + /* Get method's handler */ + status = acpi_get_handle(root_handle, (acpi_string)method, &handle); + if (ACPI_FAILURE(status)) { + rtw_dbg(rtwdev, RTW_DBG_REGD, "SAR: %s method not found (0x%x)\n", + method, status); + return NULL; + } + + /* Call specific method with no argument */ + status = acpi_evaluate_object(handle, NULL, NULL, &buf); + if (ACPI_FAILURE(status)) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: %s invocation failed (0x%x)\n", method, status); + return NULL; + } + + return buf.pointer; +} + +static union acpi_object *rtw_sar_get_wifi_pkt(struct rtw_dev *rtwdev, + union acpi_object *obj, + u32 element_count) +{ + union acpi_object *wifi_pkg; + u32 i; + + if (obj->type != ACPI_TYPE_PACKAGE || + obj->package.count < 2 || + obj->package.elements[0].type != ACPI_TYPE_INTEGER || + obj->package.elements[0].integer.value != 0) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: Unsupported wifi package structure\n"); + return NULL; + } + + /* loop through all the packages to find the one for WiFi */ + for (i = 1; i < obj->package.count; i++) { + union acpi_object *domain; + + wifi_pkg = &obj->package.elements[i]; + + /* Skip anything that is not a package with the right amount of + * elements (i.e. domain_type, enabled/disabled plus the sar + * table size.) + */ + if (wifi_pkg->type != ACPI_TYPE_PACKAGE || + wifi_pkg->package.count != element_count) + continue; + + domain = &wifi_pkg->package.elements[0]; + if (domain->type == ACPI_TYPE_INTEGER && + domain->integer.value == ACPI_WIFI_DOMAIN) + return wifi_pkg; + } + + return NULL; +} + +static void *rtw_sar_get_wrds_table(struct rtw_dev *rtwdev) +{ + union acpi_object *wrds, *wrds_pkg; + int i, idx = 2; + u8 *wrds_raw = NULL; + + wrds = rtw_sar_get_acpiobj(rtwdev, ACPI_WRDS_METHOD); + if (!wrds) + return NULL; + + wrds_pkg = rtw_sar_get_wifi_pkt(rtwdev, wrds, ACPI_WRDS_TOTAL_SIZE); + if (!wrds_pkg) + goto out; + + /* WiFiSarEnable 0: ignore BIOS config; 1: use BIOS config */ + if (wrds_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + wrds_pkg->package.elements[1].integer.value == 0) + goto out; + + wrds_raw = kmalloc(ACPI_WRDS_SIZE, GFP_KERNEL); + if (!wrds_raw) + goto out; + + /* read elements[2~11] */ + for (i = 0; i < ACPI_WRDS_SIZE; i++) { + union acpi_object *entry; + + entry = &wrds_pkg->package.elements[idx++]; + if (entry->type != ACPI_TYPE_INTEGER || + entry->integer.value > U8_MAX) { + kfree(wrds_raw); + wrds_raw = NULL; + goto out; + } + + wrds_raw[i] = entry->integer.value; + } +out: + kfree(wrds); + + return wrds_raw; +} + +static void rtw_sar_apply_wrds(struct rtw_dev *rtwdev, + const struct rtw_sar_wrds *wrds) +{ + int path; + + for (path = 0; path < RTW_SAR_WRDS_CHAIN_NR; path++) { + rtw_phy_set_tx_power_sar(rtwdev, RTW_REGD_WW, path, 1, 14, + wrds->chain[path].limit[RTW_SAR_LMT_CH1_14]); + rtw_phy_set_tx_power_sar(rtwdev, RTW_REGD_WW, path, 36, 64, + wrds->chain[path].limit[RTW_SAR_LMT_CH36_64]); + rtw_phy_set_tx_power_sar(rtwdev, RTW_REGD_WW, path, 100, 144, + wrds->chain[path].limit[RTW_SAR_LMT_CH100_144]); + rtw_phy_set_tx_power_sar(rtwdev, RTW_REGD_WW, path, 149, 165, + wrds->chain[path].limit[RTW_SAR_LMT_CH149_165]); + } + + rtwdev->sar.source = RTW_SAR_SOURCE_ACPI_STATIC; +} + +static int rtw_sar_load_static_tables(struct rtw_dev *rtwdev) +{ + struct rtw_sar_wrds *wrds; + + wrds = rtw_sar_get_wrds_table(rtwdev); + if (!wrds) + return -ENOENT; + + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: Apply WRDS to TX power\n"); + + rtw_sar_apply_wrds(rtwdev, wrds); + kfree(wrds); + + return 0; +} +#else +static int rtw_sar_load_static_tables(struct rtw_dev *rtwdev) +{ + return -ENOENT; +} +#endif /* CONFIG_ACPI */ + +void rtw_sar_load_table(struct rtw_dev *rtwdev) +{ + rtw_sar_load_static_tables(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw88/sar.h b/drivers/net/wireless/realtek/rtw88/sar.h new file mode 100644 index 000000000000..632de7ed58c3 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/sar.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW_SAR_H_ +#define __RTW_SAR_H_ + +void rtw_sar_load_table(struct rtw_dev *rtwdev); + +#endif From patchwork Fri Feb 7 09:28:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 216508 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5289CC352A2 for ; Fri, 7 Feb 2020 09:29:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3558221741 for ; Fri, 7 Feb 2020 09:29:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726999AbgBGJ3A (ORCPT ); Fri, 7 Feb 2020 04:29:00 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44694 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726901AbgBGJ3A (ORCPT ); Fri, 7 Feb 2020 04:29:00 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179Srm0018582, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (RTEXMB06.realtek.com.tw[172.21.6.99]) by rtits2.realtek.com.tw (8.15.2/2.57/5.78) with ESMTPS id 0179Srm0018582 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:53 +0800 Received: from RTEXMB06.realtek.com.tw (172.21.6.99) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1779.2; Fri, 7 Feb 2020 17:28:53 +0800 Received: from RTITCASV01.realtek.com.tw (172.21.6.18) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.1.1779.2 via Frontend Transport; Fri, 7 Feb 2020 17:28:53 +0800 Received: from localhost.localdomain (172.21.68.128) by RTITCASV01.realtek.com.tw (172.21.6.18) with Microsoft SMTP Server id 14.3.468.0; Fri, 7 Feb 2020 17:28:52 +0800 From: To: CC: , , Subject: [PATCH 7/8] rtw88: sar: add sar_work to poll if dynamic SAR table is changed Date: Fri, 7 Feb 2020 17:28:43 +0800 Message-ID: <20200207092844.29175-8-yhchuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200207092844.29175-1-yhchuang@realtek.com> References: <20200207092844.29175-1-yhchuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.68.128] Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Ping-Ke Shih RWSI is used to tell driver operating mode is changed. For example, a notebook PC can also play as a tablet. Driver detects RWSI in period of 10 seconds, and reconfigure SAR power limit if RWSI values are changed. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang --- drivers/net/wireless/realtek/rtw88/main.c | 4 ++ drivers/net/wireless/realtek/rtw88/main.h | 1 + drivers/net/wireless/realtek/rtw88/sar.c | 56 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/sar.h | 3 ++ 4 files changed, 64 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 039703f1ccb9..bb90dce0a70d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -892,6 +892,8 @@ int rtw_core_start(struct rtw_dev *rtwdev) ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, RTW_WATCH_DOG_DELAY_TIME); + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->sar.work, + RTW_SAR_DELAY_TIME); set_bit(RTW_FLAG_RUNNING, rtwdev->flags); @@ -912,6 +914,7 @@ void rtw_core_stop(struct rtw_dev *rtwdev) clear_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); cancel_delayed_work_sync(&rtwdev->watch_dog_work); + cancel_delayed_work_sync(&rtwdev->sar.work); cancel_delayed_work_sync(&coex->bt_relink_work); cancel_delayed_work_sync(&coex->bt_reenable_work); cancel_delayed_work_sync(&coex->defreeze_work); @@ -1370,6 +1373,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) (unsigned long)rtwdev); INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work); + INIT_DELAYED_WORK(&rtwdev->sar.work, rtw_sar_work); INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work); INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work); INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index bf5e66930424..ae7a4a080cfa 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1530,6 +1530,7 @@ struct rtw_sar { union rtw_sar_rwsi *rwsi; union rtw_sar_rwgs *rwgs; const struct rtw_sar_read *read; + struct delayed_work work; }; struct rtw_hal { diff --git a/drivers/net/wireless/realtek/rtw88/sar.c b/drivers/net/wireless/realtek/rtw88/sar.c index 80b8913d1a49..2bc6da4e5fcf 100644 --- a/drivers/net/wireless/realtek/rtw88/sar.c +++ b/drivers/net/wireless/realtek/rtw88/sar.c @@ -547,6 +547,45 @@ static void rtw_sar_apply_dynamic_tables(struct rtw_dev *rtwdev) rtwdev->sar.source = RTW_SAR_SOURCE_ACPI_DYNAMIC; } +static bool rtw_sar_is_rwsi_changed(struct rtw_dev *rtwdev) +{ + union rtw_sar_rwsi *rwsi, *old; + bool valid; + int len; + + if (rtwdev->sar.source != RTW_SAR_SOURCE_ACPI_DYNAMIC) + return false; + + if (!rtwdev->sar.rwrd || !rtwdev->sar.rwsi || !rtwdev->sar.rwgs) + return false; + + rwsi = rtw_sar_get_raw_table(rtwdev, ACPI_RWSI_METHOD, &len); + if (!rwsi) + return false; + valid = is_valid_rwsi(rtwdev, rtwdev->sar.rwrd, rwsi, len); + if (!valid) { + kfree(rwsi); + return false; + } + + if (memcmp(rwsi, rtwdev->sar.rwsi, len) == 0) { + kfree(rwsi); + return true; + } + + old = rtwdev->sar.rwsi; + rtwdev->sar.rwsi = rwsi; + kfree(old); + + rtw_dbg(rtwdev, RTW_DBG_REGD, "SAR: RWSI is changed\n"); + + rtw_sar_apply_dynamic_tables(rtwdev); + + rtw_phy_set_tx_power_level(rtwdev, rtwdev->hal.current_channel); + + return true; +} + static int rtw_sar_load_dynamic_tables(struct rtw_dev *rtwdev) { struct rtw_sar_rwrd *rwrd; @@ -605,6 +644,11 @@ static int rtw_sar_load_static_tables(struct rtw_dev *rtwdev) return -ENOENT; } +static bool rtw_sar_is_rwsi_changed(struct rtw_dev *rtwdev) +{ + return false; +} + static int rtw_sar_load_dynamic_tables(struct rtw_dev *rtwdev) { return -ENOENT; @@ -628,3 +672,15 @@ void rtw_sar_release_table(struct rtw_dev *rtwdev) kfree(rtwdev->sar.rwsi); kfree(rtwdev->sar.rwgs); } + +void rtw_sar_work(struct work_struct *work) +{ + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, + sar.work.work); + + if (!rtw_sar_is_rwsi_changed(rtwdev)) + return; + + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->sar.work, + RTW_SAR_DELAY_TIME); +} diff --git a/drivers/net/wireless/realtek/rtw88/sar.h b/drivers/net/wireless/realtek/rtw88/sar.h index 16ceae5bf79e..154f7bce6759 100644 --- a/drivers/net/wireless/realtek/rtw88/sar.h +++ b/drivers/net/wireless/realtek/rtw88/sar.h @@ -7,5 +7,8 @@ void rtw_sar_load_table(struct rtw_dev *rtwdev); void rtw_sar_release_table(struct rtw_dev *rtwdev); +void rtw_sar_work(struct work_struct *work); + +#define RTW_SAR_DELAY_TIME (10 * HZ) #endif From patchwork Fri Feb 7 09:28:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 216507 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 249EFC352A2 for ; Fri, 7 Feb 2020 09:29:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EF80F20726 for ; Fri, 7 Feb 2020 09:29:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727005AbgBGJ3B (ORCPT ); Fri, 7 Feb 2020 04:29:01 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44698 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726982AbgBGJ3B (ORCPT ); Fri, 7 Feb 2020 04:29:01 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179StA4018590, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (RTEXMB06.realtek.com.tw[172.21.6.99]) by rtits2.realtek.com.tw (8.15.2/2.57/5.78) with ESMTPS id 0179StA4018590 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:55 +0800 Received: from RTEXDAG02.realtek.com.tw (172.21.6.101) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1779.2; Fri, 7 Feb 2020 17:28:54 +0800 Received: from RTEXMB06.realtek.com.tw (172.21.6.99) by RTEXDAG02.realtek.com.tw (172.21.6.101) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1779.2; Fri, 7 Feb 2020 17:28:54 +0800 Received: from RTITCASV01.realtek.com.tw (172.21.6.18) by RTEXMB06.realtek.com.tw (172.21.6.99) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.1.1779.2 via Frontend Transport; Fri, 7 Feb 2020 17:28:54 +0800 Received: from localhost.localdomain (172.21.68.128) by RTITCASV01.realtek.com.tw (172.21.6.18) with Microsoft SMTP Server id 14.3.468.0; Fri, 7 Feb 2020 17:28:53 +0800 From: To: CC: , , Subject: [PATCH 8/8] rtw88: sar: dump sar information via debugfs Date: Fri, 7 Feb 2020 17:28:44 +0800 Message-ID: <20200207092844.29175-9-yhchuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200207092844.29175-1-yhchuang@realtek.com> References: <20200207092844.29175-1-yhchuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.68.128] Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Ping-Ke Shih To know detail of SAR information, we add a debugfs entry to dump the raw content written in ACPI, and also dump the translated data (real number in decimal). The output looks like Customer ID: 0x5048 WiFiEnable: 0x1 Total SAR Table Count: 3 Current SAR Table Index: (02 02 02 02) Dump RWRD SAR RAW DATA. (Total Count: 60) 01: 0e 0c 0c 0c 0c 0e 0c 0c 0c 0c 0e 0c 0c 0c 0c 12 10 10 12 12 02: 08 03 03 03 03 08 03 03 03 03 08 03 03 03 03 12 10 10 12 12 03: 04 ff ff ff ff 04 ff ff ff ff 04 ff ff ff ff 12 10 10 12 12 Show SAR PowerLimit: 2.4G Antenna 0: [14.0] dBm 2.4G Antenna 1: [14.0] dBm 5G Antenna 0: [11.500, 11.500, 11.500, 11.500, ] dBm 5G Antenna 1: [11.500, 11.500, 11.500, 11.500, ] dBm Dump Geo-SAR Table RAW DATA. (Total Count: 30) geo-0: 10 04 08 01 01 0f 04 0c 01 01 geo-1: 0c 02 06 03 03 06 04 08 03 03 geo-2: 10 03 03 03 03 0f 03 03 03 03 Show Geo-SAR PowerLimit: 2G Geo Table Index: 1 5G Geo Table Index: 1 2GHz: Max Power: [16.0] dBm Ant-0 delta value: [1.0] dB Ant-1 delta value: [3.0] dB 5GHz: Max Power: [13.0] dBm Ant-0 delta value: [2.0] dB Ant-1 delta value: [4.0] dB Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang --- drivers/net/wireless/realtek/rtw88/debug.c | 16 ++++ drivers/net/wireless/realtek/rtw88/sar.c | 92 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/sar.h | 1 + 3 files changed, 109 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 3ec15a49ecc9..ee73b125ac0e 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -9,6 +9,7 @@ #include "fw.h" #include "debug.h" #include "phy.h" +#include "sar.h" #ifdef CONFIG_RTW88_DEBUGFS @@ -696,6 +697,16 @@ static int rtw_debugfs_get_phy_info(struct seq_file *m, void *v) return 0; } +static int rtw_debugfs_get_sar(struct seq_file *m, void *v) +{ + struct rtw_debugfs_priv *debugfs_priv = m->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + + rtw_sar_dump_via_debugfs(rtwdev, m); + + return 0; +} + #define rtw_debug_impl_mac(page, addr) \ static struct rtw_debugfs_priv rtw_debug_priv_mac_ ##page = { \ .cb_read = rtw_debug_get_mac_page, \ @@ -786,6 +797,10 @@ static struct rtw_debugfs_priv rtw_debug_priv_phy_info = { .cb_read = rtw_debugfs_get_phy_info, }; +static struct rtw_debugfs_priv rtw_debug_priv_sar = { + .cb_read = rtw_debugfs_get_sar, +}; + #define rtw_debugfs_add_core(name, mode, fopname, parent) \ do { \ rtw_debug_priv_ ##name.rtwdev = rtwdev; \ @@ -816,6 +831,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) rtw_debugfs_add_rw(dump_cam); rtw_debugfs_add_rw(rsvd_page); rtw_debugfs_add_r(phy_info); + rtw_debugfs_add_r(sar); rtw_debugfs_add_r(mac_0); rtw_debugfs_add_r(mac_1); rtw_debugfs_add_r(mac_2); diff --git a/drivers/net/wireless/realtek/rtw88/sar.c b/drivers/net/wireless/realtek/rtw88/sar.c index 2bc6da4e5fcf..62689c002e25 100644 --- a/drivers/net/wireless/realtek/rtw88/sar.c +++ b/drivers/net/wireless/realtek/rtw88/sar.c @@ -298,6 +298,7 @@ struct rtw_sar_read { const struct rtw_sar_geo_map *gm, *gm_end; int rwsi_sz; int rwgs_sz; + int rwgs_geos; }; static int rwsi_mode_hp(struct rtw_dev *rtwdev, int path) @@ -333,6 +334,7 @@ static const struct rtw_sar_read sar_read_hp = { .gm_end = geo_map_hp + ARRAY_SIZE(geo_map_hp), .rwsi_sz = sizeof(struct rtw_sar_rwsi_hp), .rwgs_sz = sizeof(struct rtw_sar_rwgs_hp), + .rwgs_geos = RTW_SAR_RWGS_HP_NR, }; static int rwsi_mode_rt(struct rtw_dev *rtwdev, int path) @@ -364,6 +366,7 @@ static const struct rtw_sar_read sar_read_rt = { .gm_end = geo_map_rt + ARRAY_SIZE(geo_map_rt), .rwsi_sz = sizeof(struct rtw_sar_rwsi_rt), .rwgs_sz = sizeof(struct rtw_sar_rwgs_rt), + .rwgs_geos = RTW_SAR_RWGS_RT_NR, }; static u8 *rtw_sar_get_raw_package(struct rtw_dev *rtwdev, @@ -504,6 +507,88 @@ static bool is_valid_rwgs(struct rtw_dev *rtwdev, const struct rtw_sar_rwrd *rwr return false; } +#ifdef CONFIG_RTW88_DEBUGFS +void rtw_sar_dump_via_debugfs(struct rtw_dev *rtwdev, struct seq_file *m) +{ +#define q3_int(q3) ((q3) >> 3) +#define q3_fra(q3) (((q3) & 0x7) * 125) + + const struct rtw_sar_rwrd *rwrd = rtwdev->sar.rwrd; + const union rtw_sar_rwsi *rwsi = rtwdev->sar.rwsi; + const union rtw_sar_rwgs *rwgs = rtwdev->sar.rwgs; + const struct rtw_sar_read *r = rtwdev->sar.read; + int q3; + int mode; + int path; + int chidx; + int gi; + int band; + + if (!rwrd || !rwsi || !rwgs || !r) { + seq_puts(m, "(No SAR data)\n"); + return; + } + + seq_printf(m, "Customer ID: 0x%04x\n", rwrd->id); + seq_printf(m, "WiFiEnable: 0x%x\n", rwrd->en); + seq_printf(m, "Total SAR Table Count: %d\n", rwrd->count); + seq_printf(m, "Current SAR Table Index: (%*ph)\n", r->rwsi_sz, rwsi); + seq_puts(m, "\n"); + + seq_printf(m, "Dump RWRD SAR RAW DATA. (Total Count: %ld)\n", + rwrd->count * sizeof(rwrd->mode[0])); + for (mode = 0; mode < rwrd->count; mode++) + seq_printf(m, "%02x: %20ph\n", mode + 1, &rwrd->mode[mode]); + seq_puts(m, "\n"); + + seq_puts(m, "Show SAR PowerLimit:\n"); + for (path = 0; path < 2; path++) { + mode = r->rwsi_mode(rtwdev, path); + q3 = r->rwrd_base_q3(rtwdev, mode, path, RTW_SAR_LMT_CH1_14); + seq_printf(m, "2.4G Antenna %d: [%d.%d] dBm\n", path, + q3_int(q3), q3_fra(q3)); + } + seq_puts(m, "\n"); + + for (path = 0; path < 2; path++) { + mode = r->rwsi_mode(rtwdev, path); + seq_printf(m, "5G Antenna %d: [", path); + for (chidx = RTW_SAR_LMT_CH36_64; chidx <= RTW_SAR_LMT_CH149_165; + chidx++) { + q3 = r->rwrd_base_q3(rtwdev, mode, path, chidx); + seq_printf(m, "%d.%d, ", q3_int(q3), q3_fra(q3)); + } + seq_puts(m, "] dBm\n"); + } + seq_puts(m, "\n"); + + seq_printf(m, "Dump Geo-SAR Table RAW DATA. (Total Count: %d)\n", + r->rwgs_sz); + for (gi = 0; gi < r->rwgs_geos; gi++) { + seq_printf(m, "geo-%d: %*ph\n", gi, r->rwgs_sz / r->rwgs_geos, + (u8 *)rwgs + gi * (r->rwgs_sz / r->rwgs_geos)); + } + seq_puts(m, "\n"); + + gi = 1; /* take index 1 as an example */ + seq_puts(m, "Show Geo-SAR PowerLimit:\n"); + seq_printf(m, "2G Geo Table Index: %d\n", gi); + seq_printf(m, "5G Geo Table Index: %d\n", gi); + for (band = RTW_SAR_RWGS_2G; band < RTW_SAR_RWGS_BAND_NR; band++) { + seq_puts(m, "\n"); + seq_printf(m, "%dGHz:\n", band == 0 ? 2 : 5); + q3 = r->rwgs_max_q3(rtwdev, gi, band); + seq_printf(m, "Max Power: [%d.%d] dBm\n", q3_int(q3), + q3_fra(q3)); + for (path = 0; path < 2; path++) { + q3 = r->rwgs_delta_q3(rtwdev, gi, path, band); + seq_printf(m, "Ant-%d delta value: [%d.%d] dB\n", path, + q3_int(q3), q3_fra(q3)); + } + } +} +#endif + static void rtw_sar_apply_dynamic_tables(struct rtw_dev *rtwdev) { struct rtw_hal *hal = &rtwdev->hal; @@ -653,6 +738,13 @@ static int rtw_sar_load_dynamic_tables(struct rtw_dev *rtwdev) { return -ENOENT; } + +#ifdef CONFIG_RTW88_DEBUGFS +void rtw_sar_dump_via_debugfs(struct rtw_dev *rtwdev, struct seq_file *m) +{ + seq_puts(m, "(No SAR data)\n"); +} +#endif #endif /* CONFIG_ACPI */ void rtw_sar_load_table(struct rtw_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw88/sar.h b/drivers/net/wireless/realtek/rtw88/sar.h index 154f7bce6759..1f7d877a3797 100644 --- a/drivers/net/wireless/realtek/rtw88/sar.h +++ b/drivers/net/wireless/realtek/rtw88/sar.h @@ -8,6 +8,7 @@ void rtw_sar_load_table(struct rtw_dev *rtwdev); void rtw_sar_release_table(struct rtw_dev *rtwdev); void rtw_sar_work(struct work_struct *work); +void rtw_sar_dump_via_debugfs(struct rtw_dev *rtwdev, struct seq_file *m); #define RTW_SAR_DELAY_TIME (10 * HZ)