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: 11370071 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4C5E3112B 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 21BA521741 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:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 11370069 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 80AEF112B for ; Fri, 7 Feb 2020 09:28:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 69A8420726 for ; Fri, 7 Feb 2020 09:28:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726857AbgBGJ2z (ORCPT ); Fri, 7 Feb 2020 04:28:55 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44680 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726586AbgBGJ2y (ORCPT ); Fri, 7 Feb 2020 04:28:54 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179Smsj018556, 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 0179Smsj018556 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:48 +0800 Received: from RTEXMB03.realtek.com.tw (172.21.6.96) 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:48 +0800 Received: from RTEXMB06.realtek.com.tw (172.21.6.99) by RTEXMB03.realtek.com.tw (172.21.6.96) 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:48 +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:48 +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:47 +0800 From: To: CC: , , Subject: [PATCH 2/8] nl80211: vendor-cmd: realtek: Add vendor command to set SAR power limit Date: Fri, 7 Feb 2020 17:28:38 +0800 Message-ID: <20200207092844.29175-3-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 This is added to set SAR power limit, but doesn't replace existing functionality. Use 'iw' to set SAR power limit with ${p1,p2,p3,p4,p5} for five sub-bands: sudo iw dev wlan0 vendor send 0x00E04C 0x88 0x68 0x00 0x01 0x80 0x14 0x00 0x01 0x80 0x08 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x05 0x00 0x03 0x00 $p1 0x00 0x00 0x00 0x14 0x00 0x02 0x80 0x08 0x00 0x02 0x00 0x01 0x00 0x00 0x00 0x05 0x00 0x03 0x00 $p2 0x00 0x00 0x00 0x14 0x00 0x03 0x80 0x08 0x00 0x02 0x00 0x02 0x00 0x00 0x00 0x05 0x00 0x03 0x00 $p3 0x00 0x00 0x00 0x14 0x00 0x04 0x80 0x08 0x00 0x02 0x00 0x03 0x00 0x00 0x00 0x05 0x00 0x03 0x00 $p4 0x00 0x00 0x00 0x14 0x00 0x05 0x80 0x08 0x00 0x02 0x00 0x04 0x00 0x00 0x00 0x05 0x00 0x03 0x00 $p5 0x00 0x00 0x00 Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang --- include/uapi/nl80211-vnd-realtek.h | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 include/uapi/nl80211-vnd-realtek.h diff --git a/include/uapi/nl80211-vnd-realtek.h b/include/uapi/nl80211-vnd-realtek.h new file mode 100644 index 000000000000..6b71de8d7cdf --- /dev/null +++ b/include/uapi/nl80211-vnd-realtek.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ +#ifndef _UAPI_NL80211_VND_REALTEK_H +#define _UAPI_NL80211_VND_REALTEK_H + +/** + * This vendor ID is the value of atrribute %NL80211_ATTR_VENDOR_ID used by + * %NL80211_CMD_VENDOR to send vendor command. + */ +#define REALTEK_NL80211_VENDOR_ID 0x00E04C + +/** + * enum realtek_nl80211_vndcmd - supported vendor subcmds + * + * @REALTEK_NL80211_VNDCMD_SET_SAR: set SAR power limit + * %realtek_vndcmd_sar_band within attribute %REALTEK_VNDCMD_ATTR_SAR_BAND + * and corresponding power limit attribute %REALTEK_VNDCMD_ATTR_SAR_POWER. + * The two attributes are in nested attribute %REALTEK_VNDCMD_ATTR_SAR_RULES. + */ +enum realtek_nl80211_vndcmd { + REALTEK_NL80211_VNDCMD_SET_SAR = 0x88, +}; + +/** + * enum realtek_vndcmd_sar_band - bands of SAR power limit + * + * @REALTEK_VNDCMD_SAR_BAND_2G: all channels of 2G band + * @REALTEK_VNDCMD_SAR_BAND_5G_BAND1: channels of 5G band1 (5.15~5.35G) + * @REALTEK_VNDCMD_SAR_BAND_5G_BAND2: channels of 5G band2 (5.35~5.47G) + * 5G band2 isn't used by rtw88 by now, so don't need to set SAR power + * limit for this band. But we still enumerate this band as a placeholder + * for the furture. + * @REALTEK_VNDCMD_SAR_BAND_5G_BAND3: channels of 5G band3 (5.47~5.725G) + * @REALTEK_VNDCMD_SAR_BAND_5G_BAND4: channels of 5G band4 (5.725~5.95G) + */ +enum realtek_vndcmd_sar_band { + REALTEK_VNDCMD_SAR_BAND_2G, + REALTEK_VNDCMD_SAR_BAND_5G_BAND1, + REALTEK_VNDCMD_SAR_BAND_5G_BAND2, + REALTEK_VNDCMD_SAR_BAND_5G_BAND3, + REALTEK_VNDCMD_SAR_BAND_5G_BAND4, + + REALTEK_VNDCMD_SAR_BAND_NR, +}; + +/** + * enum realtek_vndcmd_sar_rule_attr - attributes of vendor command + * %REALTEK_NL80211_VNDCMD_SET_SAR + * + * @REALTEK_VNDCMD_ATTR_SAR_RULES: nested attribute to hold SAR rules containing + * band and corresponding power limit. + * + * @REALTEK_VNDCMD_ATTR_SAR_BAND: an attribute within %REALTEK_VNDCMD_ATTR_SAR_RULES, + * and its value is %realtek_vndcmd_sar_band (u32 data type). + * @REALTEK_VNDCMD_ATTR_SAR_POWER: an attribute within %REALTEK_VNDCMD_ATTR_SAR_RULES. + * SAR power limit is 'u8' type and in unit of 0.125 dBm, so its range is + * 0 to 31.875 dBm. + */ +enum realtek_vndcmd_sar_rule_attr { + __REALTEK_VNDCMD_SAR_RULE_ATTR_INVALID, + + REALTEK_VNDCMD_ATTR_SAR_RULES, + REALTEK_VNDCMD_ATTR_SAR_BAND, + REALTEK_VNDCMD_ATTR_SAR_POWER, + + /* keep last */ + __REALTEK_VNDCMD_SAR_RULE_ATTR_AFTER_LAST, + REALTEK_VNDCMD_SAR_RULE_ATTR_MAX = __REALTEK_VNDCMD_SAR_RULE_ATTR_AFTER_LAST - 1, +}; + +#endif /* _UAPI_NL80211_VND_REALTEK_H */ From patchwork Fri Feb 7 09:28:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 11370073 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 46D1914B4 for ; Fri, 7 Feb 2020 09:28:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 25B2E20838 for ; Fri, 7 Feb 2020 09:28:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726894AbgBGJ24 (ORCPT ); Fri, 7 Feb 2020 04:28:56 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44685 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726451AbgBGJ2z (ORCPT ); Fri, 7 Feb 2020 04:28:55 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179SnTE018560, 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 0179SnTE018560 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:49 +0800 Received: from RTEXMB01.realtek.com.tw (172.21.6.94) 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:49 +0800 Received: from RTEXMB06.realtek.com.tw (172.21.6.99) by RTEXMB01.realtek.com.tw (172.21.6.94) 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:49 +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:49 +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:48 +0800 From: To: CC: , , Subject: [PATCH 3/8] rtw88: vndcmd: sar: Apply SAR power limit via vendor command Date: Fri, 7 Feb 2020 17:28:39 +0800 Message-ID: <20200207092844.29175-4-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 Use 'iw' vendor command to send SAR power limit table to driver that converts power limit unit from dBm to rtw88's power_index. When channel is changed, SAR power limit plays as a constraint to calculate TX power. When a vendor command is recevied, kernel log shows like rtw_pci 0000:03:00.0: set SAR power limit 16.500 on band 0 rtw_pci 0000:03:00.0: set SAR power limit 13.125 on band 1 rtw_pci 0000:03:00.0: set SAR power limit 18.000 on band 3 rtw_pci 0000:03:00.0: set SAR power limit 19.000 on band 4 Then, apply SAR power limit to all regions if no other SAR source is in use. 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/vndcmd.c | 131 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/vndcmd.h | 10 ++ 4 files changed, 144 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw88/vndcmd.c create mode 100644 drivers/net/wireless/realtek/rtw88/vndcmd.h diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index cac148d13cf1..935333f734a9 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -16,6 +16,7 @@ rtw88-y += main.o \ sec.o \ bf.o \ wow.o \ + vndcmd.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 2845d2838f7b..7156a06eea74 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -15,6 +15,7 @@ #include "tx.h" #include "debug.h" #include "bf.h" +#include "vndcmd.h" unsigned int rtw_fw_lps_deep_mode; EXPORT_SYMBOL(rtw_fw_lps_deep_mode); @@ -1498,6 +1499,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) SET_IEEE80211_PERM_ADDR(hw, rtwdev->efuse.addr); rtw_regd_init(rtwdev, rtw_regd_notifier); + rtw_register_vndcmd(hw); ret = ieee80211_register_hw(hw); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw88/vndcmd.c b/drivers/net/wireless/realtek/rtw88/vndcmd.c new file mode 100644 index 000000000000..64c68239d28d --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/vndcmd.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include + +#include "main.h" +#include "phy.h" +#include "debug.h" + +static const struct nla_policy +rtw_sar_rule_policy[REALTEK_VNDCMD_SAR_RULE_ATTR_MAX + 1] = { + [REALTEK_VNDCMD_ATTR_SAR_RULES] = { .type = NLA_NESTED_ARRAY }, + [REALTEK_VNDCMD_ATTR_SAR_BAND] = { .type = NLA_U32 }, + [REALTEK_VNDCMD_ATTR_SAR_POWER] = { .type = NLA_U8 }, +}; + +static const struct sar_band2ch { + u8 ch_start; + u8 ch_end; +} sar_band2chs[REALTEK_VNDCMD_SAR_BAND_NR] = { + [REALTEK_VNDCMD_SAR_BAND_2G] = { .ch_start = 1, .ch_end = 14 }, + [REALTEK_VNDCMD_SAR_BAND_5G_BAND1] = { .ch_start = 36, .ch_end = 64 }, + /* REALTEK_VNDCMD_SAR_BAND_5G_BAND2 isn't used by now. */ + [REALTEK_VNDCMD_SAR_BAND_5G_BAND3] = { .ch_start = 100, .ch_end = 144 }, + [REALTEK_VNDCMD_SAR_BAND_5G_BAND4] = { .ch_start = 149, .ch_end = 165 }, +}; + +static int rtw_apply_vndcmd_sar(struct rtw_dev *rtwdev, u32 band, u8 power) +{ + const struct sar_band2ch *sar_band2ch; + u8 path, rd; + + if (band >= REALTEK_VNDCMD_SAR_BAND_NR) + return -EINVAL; + + sar_band2ch = &sar_band2chs[band]; + if (!sar_band2ch->ch_start || !sar_band2ch->ch_end) + return 0; + + /* SAR values from vendor command apply to all regulatory domains, + * and we can still ensure TX power under power limit because of + * "tx_power = base + min(by_rate, limit, sar)". + */ + for (path = 0; path < rtwdev->hal.rf_path_num; path++) + for (rd = 0; rd < RTW_REGD_MAX; rd++) + rtw_phy_set_tx_power_sar(rtwdev, rd, path, + sar_band2ch->ch_start, + sar_band2ch->ch_end, power); + + rtw_info(rtwdev, "set SAR power limit %u.%03u on band %u\n", + power >> 3, (power & 7) * 125, band); + + rtwdev->sar.source = RTW_SAR_SOURCE_VNDCMD; + + return 0; +} + +static int rtw_vndcmd_set_sar(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct rtw_dev *rtwdev = hw->priv; + struct rtw_hal *hal = &rtwdev->hal; + struct nlattr *tb_root[REALTEK_VNDCMD_SAR_RULE_ATTR_MAX + 1]; + struct nlattr *tb[REALTEK_VNDCMD_SAR_RULE_ATTR_MAX + 1]; + struct nlattr *nl_sar_rule; + int rem_sar_rules, r; + u32 band; + u8 power; + + if (rtwdev->sar.source != RTW_SAR_SOURCE_NONE && + rtwdev->sar.source != RTW_SAR_SOURCE_VNDCMD) { + rtw_info(rtwdev, "SAR source 0x%x is in use", rtwdev->sar.source); + return -EBUSY; + } + + r = nla_parse(tb_root, REALTEK_VNDCMD_SAR_RULE_ATTR_MAX, data, data_len, + rtw_sar_rule_policy, NULL); + if (r) { + rtw_warn(rtwdev, "invalid SAR attr\n"); + return r; + } + + if (!tb_root[REALTEK_VNDCMD_ATTR_SAR_RULES]) { + rtw_warn(rtwdev, "no SAR rule attr\n"); + return -EINVAL; + } + + nla_for_each_nested(nl_sar_rule, tb_root[REALTEK_VNDCMD_ATTR_SAR_RULES], + rem_sar_rules) { + r = nla_parse_nested(tb, REALTEK_VNDCMD_SAR_RULE_ATTR_MAX, + nl_sar_rule, rtw_sar_rule_policy, NULL); + if (r) + return r; + if (!tb[REALTEK_VNDCMD_ATTR_SAR_BAND]) + return -EINVAL; + if (!tb[REALTEK_VNDCMD_ATTR_SAR_POWER]) + return -EINVAL; + + band = nla_get_u32(tb[REALTEK_VNDCMD_ATTR_SAR_BAND]); + power = nla_get_u8(tb[REALTEK_VNDCMD_ATTR_SAR_POWER]); + + r = rtw_apply_vndcmd_sar(rtwdev, band, power); + if (r) + return r; + } + + rtw_phy_set_tx_power_level(rtwdev, hal->current_channel); + + return 0; +} + +static const struct wiphy_vendor_command rtw88_vendor_commands[] = { + { + .info = { + .vendor_id = REALTEK_NL80211_VENDOR_ID, + .subcmd = REALTEK_NL80211_VNDCMD_SET_SAR, + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .doit = rtw_vndcmd_set_sar, + .policy = rtw_sar_rule_policy, + .maxattr = REALTEK_VNDCMD_SAR_RULE_ATTR_MAX, + } +}; + +void rtw_register_vndcmd(struct ieee80211_hw *hw) +{ + hw->wiphy->vendor_commands = rtw88_vendor_commands; + hw->wiphy->n_vendor_commands = ARRAY_SIZE(rtw88_vendor_commands); +} diff --git a/drivers/net/wireless/realtek/rtw88/vndcmd.h b/drivers/net/wireless/realtek/rtw88/vndcmd.h new file mode 100644 index 000000000000..c56f69f9bf36 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/vndcmd.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW_VNDCMD_H__ +#define __RTW_VNDCMD_H__ + +void rtw_register_vndcmd(struct ieee80211_hw *hw); + +#endif /* __RTW_VNDCMD_H__ */ 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: 11370075 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 49FD014B4 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 2874120838 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:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 11370083 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1B64C112B for ; Fri, 7 Feb 2020 09:29:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EEDC020726 for ; Fri, 7 Feb 2020 09:29:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726988AbgBGJ3A (ORCPT ); Fri, 7 Feb 2020 04:29:00 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44691 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726586AbgBGJ27 (ORCPT ); Fri, 7 Feb 2020 04:28:59 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179SpEa018568, 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 0179SpEa018568 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:51 +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:51 +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:51 +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:50 +0800 From: To: CC: , , Subject: [PATCH 5/8] rtw88: sar: Load dynamic SAR table from ACPI methods Date: Fri, 7 Feb 2020 17:28:41 +0800 Message-ID: <20200207092844.29175-6-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 Three tables RWRD, RWSI and RWGS are defined to support SAR power limit proposed by Realtek. RWRD describes main power limit values that can support more than one mode, tablet, lid close and etc. RWSI is used to indicate which mode is operating, so driver must apply SAR power limit corresponding to the mode. Since each country (geography) has some different SAR power limit values, RWGS is introduced to adjust power limit mentioned in RWRD if stack hints driver that regulatory domain is changed. RWRD contains customer ID, SAR enable, table count and SAR power limit. With different customer ID, the formats of RWRD, RWSI and RWGS are different, such as the number of fields in table and precision of power limit value (in Q-notation). By now, two customer IDs are supported, RT and HP. 'table count' indicates total number of tables corresponding to operating modes, and selected by WRSI. To validate RWSI and RWGS tables, we check if read length and sizeof() are equal. But these checking statements depend on RWRD's ID are little verbose, so I use two predefined values, rwsi_sz and rwgs_sz, would be easy to understand the code. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang --- drivers/net/wireless/realtek/rtw88/main.c | 2 + drivers/net/wireless/realtek/rtw88/main.h | 8 + drivers/net/wireless/realtek/rtw88/sar.c | 301 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/sar.h | 1 + 4 files changed, 312 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 23cbb00e16b1..039703f1ccb9 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1449,6 +1449,8 @@ void rtw_core_deinit(struct rtw_dev *rtwdev) kfree(rsvd_pkt); } + rtw_sar_release_table(rtwdev); + mutex_destroy(&rtwdev->mutex); mutex_destroy(&rtwdev->coex.mutex); mutex_destroy(&rtwdev->hal.tx_power_mutex); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index b4e9e18f89a5..bf5e66930424 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -46,6 +46,10 @@ extern struct rtw_chip_info rtw8822c_hw_spec; #define RTW_MAX_CHANNEL_NUM_5G 49 struct rtw_dev; +struct rtw_sar_rwrd; +union rtw_sar_rwsi; +union rtw_sar_rwgs; +struct rtw_sar_read; enum rtw_hci_type { RTW_HCI_TYPE_PCIE, @@ -1522,6 +1526,10 @@ struct rtw_fw_state { struct rtw_sar { enum rtw_sar_sources source; + struct rtw_sar_rwrd *rwrd; + union rtw_sar_rwsi *rwsi; + union rtw_sar_rwgs *rwgs; + const struct rtw_sar_read *read; }; struct rtw_hal { diff --git a/drivers/net/wireless/realtek/rtw88/sar.c b/drivers/net/wireless/realtek/rtw88/sar.c index f15366ce1046..d81a6511f138 100644 --- a/drivers/net/wireless/realtek/rtw88/sar.c +++ b/drivers/net/wireless/realtek/rtw88/sar.c @@ -187,14 +187,315 @@ static int rtw_sar_load_static_tables(struct rtw_dev *rtwdev) return 0; } + +#define ACPI_RWRD_METHOD "RWRD" +#define ACPI_RWSI_METHOD "RWSI" +#define ACPI_RWGS_METHOD "RWGS" + +#define RTW_SAR_RWRD_ID_HP 0x5048 +#define RTW_SAR_RWRD_ID_RT 0x5452 + +#define RTW_SAR_RWRD_CHAIN_NR 4 + +struct rtw_sar_rwrd { + u16 id; + u8 en; + u8 count; + struct { + struct rtw_sar_limits chain[RTW_SAR_RWRD_CHAIN_NR]; + } mode[0]; +} __packed; + +struct rtw_sar_rwsi_hp { + u8 index[RTW_SAR_RWRD_CHAIN_NR]; +} __packed; + +struct rtw_sar_rwsi_rt { + u8 index; +} __packed; + +union rtw_sar_rwsi { + struct rtw_sar_rwsi_hp hp; + struct rtw_sar_rwsi_rt rt; +}; + +enum rtw_sar_rwgs_band { + RTW_SAR_RWGS_2G, + RTW_SAR_RWGS_5G, + RTW_SAR_RWGS_BAND_NR, +}; + +enum rtw_sar_rwgs_geo_hp { + RTW_SAR_RWGS_HP_FCC_IC, + RTW_SAR_RWGS_HP_ETSI_MKK, + RTW_SAR_RWGS_HP_WW_KCC, + + RTW_SAR_RWGS_HP_NR, +}; + +struct rtw_sar_rwgs_hp { + struct { + struct { + s8 max; /* Q1 + 10 */ + s8 delta[4]; /* Q1 */ + } band[RTW_SAR_RWGS_BAND_NR]; + } geo[RTW_SAR_RWGS_HP_NR]; +} __packed; + +enum rtw_sar_rwgs_geo_rt { + RTW_SAR_RWGS_RT_FCC, + RTW_SAR_RWGS_RT_CE, + RTW_SAR_RWGS_RT_MKK, + RTW_SAR_RWGS_RT_IC, + RTW_SAR_RWGS_RT_KCC, + RTW_SAR_RWGS_RT_WW, + + RTW_SAR_RWGS_RT_NR, +}; + +struct rtw_sar_rwgs_rt { + struct { + struct { + u8 max; /* Q3 */ + s8 delta; /* Q1 */ + } band[RTW_SAR_RWGS_BAND_NR]; + } geo[RTW_SAR_RWGS_RT_NR]; +} __packed; + +union rtw_sar_rwgs { + struct rtw_sar_rwgs_hp hp; + struct rtw_sar_rwgs_rt rt; +}; + +struct rtw_sar_read { + int rwsi_sz; + int rwgs_sz; +}; + +static const struct rtw_sar_read sar_read_hp = { + .rwsi_sz = sizeof(struct rtw_sar_rwsi_hp), + .rwgs_sz = sizeof(struct rtw_sar_rwgs_hp), +}; + +static const struct rtw_sar_read sar_read_rt = { + .rwsi_sz = sizeof(struct rtw_sar_rwsi_rt), + .rwgs_sz = sizeof(struct rtw_sar_rwgs_rt), +}; + +static u8 *rtw_sar_get_raw_package(struct rtw_dev *rtwdev, + union acpi_object *obj, int *len) +{ + u8 *raw; + u32 i; + + if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count <= 0) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: Unsupported obj to dump\n"); + return NULL; + } + + raw = kmalloc(obj->package.count, GFP_KERNEL); + if (!raw) + return NULL; + + for (i = 0; i < obj->package.count; i++) { + union acpi_object *element; + + element = &obj->package.elements[i]; + + if (element->type != ACPI_TYPE_INTEGER) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: Unexpected element type\n"); + kfree(raw); + return NULL; + } + + raw[i] = (u8)element->integer.value; + } + + *len = obj->package.count; + + return raw; +} + +static void *rtw_sar_get_raw_table(struct rtw_dev *rtwdev, const char *method, + int *len) +{ + union acpi_object *obj; + u8 *raw; + + obj = rtw_sar_get_acpiobj(rtwdev, method); + if (!obj) + return NULL; + + raw = rtw_sar_get_raw_package(rtwdev, obj, len); + kfree(obj); + + return raw; +} + +static bool is_valid_rwrd(struct rtw_dev *rtwdev, const struct rtw_sar_rwrd *rwrd, + int len) +{ + if (len < sizeof(*rwrd)) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: RWRD: len %d is too short\n", len); + return false; + } + + switch (rwrd->id) { + case RTW_SAR_RWRD_ID_HP: + rtwdev->sar.read = &sar_read_hp; + break; + case RTW_SAR_RWRD_ID_RT: + rtwdev->sar.read = &sar_read_rt; + break; + default: + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: RWRD: ID %04x isn't supported\n", rwrd->id); + return false; + } + + if (sizeof(*rwrd) + rwrd->count * sizeof(rwrd->mode[0]) != len) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: RWRD: len(%d) doesn't match count(%d)\n", + len, rwrd->count); + return false; + } + + return true; +} + +static bool is_valid_rwsi_idx(struct rtw_dev *rtwdev, const struct rtw_sar_rwrd *rwrd, + const u8 index[], int len) +{ + /* index range is one based. i.e. 1 <= index[] <= rwrd->count */ + int i; + + for (i = 0; i < len; i++) + if (index[i] < 1 || index[i] > rwrd->count) { + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: RWSI: index is out of range\n"); + return false; + } + + return true; +} + +static bool is_valid_rwsi(struct rtw_dev *rtwdev, const struct rtw_sar_rwrd *rwrd, + const union rtw_sar_rwsi *rwsi, int len) +{ + const struct rtw_sar_read *r = rtwdev->sar.read; + + if (r->rwsi_sz != len) + goto err; + + if (rwrd->id == RTW_SAR_RWRD_ID_HP && + is_valid_rwsi_idx(rtwdev, rwrd, rwsi->hp.index, RTW_SAR_RWRD_CHAIN_NR)) + return true; + + if (rwrd->id == RTW_SAR_RWRD_ID_RT && + is_valid_rwsi_idx(rtwdev, rwrd, &rwsi->rt.index, 1)) { + return true; + } + +err: + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: RWSI: len doesn't match struct size\n"); + + return false; +} + +static bool is_valid_rwgs(struct rtw_dev *rtwdev, const struct rtw_sar_rwrd *rwrd, + const union rtw_sar_rwgs *rwgs, int len) +{ + const struct rtw_sar_read *r = rtwdev->sar.read; + + if (r->rwgs_sz == len) + return true; + + rtw_dbg(rtwdev, RTW_DBG_REGD, + "SAR: RWGS: len doesn't match struct size\n"); + + return false; +} + +static int rtw_sar_load_dynamic_tables(struct rtw_dev *rtwdev) +{ + struct rtw_sar_rwrd *rwrd; + union rtw_sar_rwsi *rwsi; + union rtw_sar_rwgs *rwgs; + int len; + bool valid; + + rwrd = rtw_sar_get_raw_table(rtwdev, ACPI_RWRD_METHOD, &len); + if (!rwrd) + goto out; + valid = is_valid_rwrd(rtwdev, rwrd, len); + if (!valid) + goto out_rwrd; + if (!rwrd->en) { + rtw_dbg(rtwdev, RTW_DBG_REGD, "SAR: RWRD isn't enabled\n"); + goto out_rwrd; + } + + rwsi = rtw_sar_get_raw_table(rtwdev, ACPI_RWSI_METHOD, &len); + if (!rwsi) + goto out_rwrd; + valid = is_valid_rwsi(rtwdev, rwrd, rwsi, len); + if (!valid) + goto out_rwsi; + + rwgs = rtw_sar_get_raw_table(rtwdev, ACPI_RWGS_METHOD, &len); + if (!rwgs) + goto out_rwsi; + valid = is_valid_rwgs(rtwdev, rwrd, rwgs, len); + if (!valid) + goto out_rwgs; + + rtwdev->sar.rwrd = rwrd; + rtwdev->sar.rwsi = rwsi; + rtwdev->sar.rwgs = rwgs; + + rtw_dbg(rtwdev, RTW_DBG_REGD, "SAR: RWRD/RWSI/RWGS is adopted\n"); + + return 0; + +out_rwgs: + kfree(rwgs); +out_rwsi: + kfree(rwsi); +out_rwrd: + kfree(rwrd); +out: + return -ENOENT; +} #else static int rtw_sar_load_static_tables(struct rtw_dev *rtwdev) { return -ENOENT; } + +static int rtw_sar_load_dynamic_tables(struct rtw_dev *rtwdev) +{ + return -ENOENT; +} #endif /* CONFIG_ACPI */ void rtw_sar_load_table(struct rtw_dev *rtwdev) { + int ret; + + ret = rtw_sar_load_dynamic_tables(rtwdev); + if (!ret) + return; /* if dynamic SAR table is loaded, ignore static SAR table */ + rtw_sar_load_static_tables(rtwdev); } + +void rtw_sar_release_table(struct rtw_dev *rtwdev) +{ + kfree(rtwdev->sar.rwrd); + kfree(rtwdev->sar.rwsi); + kfree(rtwdev->sar.rwgs); +} diff --git a/drivers/net/wireless/realtek/rtw88/sar.h b/drivers/net/wireless/realtek/rtw88/sar.h index 632de7ed58c3..16ceae5bf79e 100644 --- a/drivers/net/wireless/realtek/rtw88/sar.h +++ b/drivers/net/wireless/realtek/rtw88/sar.h @@ -6,5 +6,6 @@ #define __RTW_SAR_H_ void rtw_sar_load_table(struct rtw_dev *rtwdev); +void rtw_sar_release_table(struct rtw_dev *rtwdev); #endif From patchwork Fri Feb 7 09:28:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Chuang X-Patchwork-Id: 11370079 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B6E5314B4 for ; Fri, 7 Feb 2020 09:29:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9660920838 for ; Fri, 7 Feb 2020 09:29:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726936AbgBGJ27 (ORCPT ); Fri, 7 Feb 2020 04:28:59 -0500 Received: from rtits2.realtek.com ([211.75.126.72]:44692 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726901AbgBGJ26 (ORCPT ); Fri, 7 Feb 2020 04:28:58 -0500 Authenticated-By: X-SpamFilter-By: BOX Solutions SpamTrap 5.62 with qID 0179SrTY018573, 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 0179SrTY018573 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Feb 2020 17:28:53 +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:52 +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:52 +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:52 +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:51 +0800 From: To: CC: , , Subject: [PATCH 6/8] rtw88: sar: apply dynamic SAR table to tx power limit Date: Fri, 7 Feb 2020 17:28:42 +0800 Message-ID: <20200207092844.29175-7-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 We apply four frequency ranges to calculate TX power, though RWRD defines five ranges. RWGS is used to adjust SAR power limit value and define the upper bound corresponding to geography. Some sar_read::ops are added to convert to proper unit, because the units and fields of SAR power limit for each customer ID are different. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang --- drivers/net/wireless/realtek/rtw88/sar.c | 129 +++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/sar.c b/drivers/net/wireless/realtek/rtw88/sar.c index d81a6511f138..80b8913d1a49 100644 --- a/drivers/net/wireless/realtek/rtw88/sar.c +++ b/drivers/net/wireless/realtek/rtw88/sar.c @@ -267,17 +267,101 @@ union rtw_sar_rwgs { struct rtw_sar_rwgs_rt rt; }; +struct rtw_sar_geo_map { + int idx; /* index of rwgs.geo[] */ + int rd; /* RTW_REGD_xxx */ +}; + +static const struct rtw_sar_geo_map geo_map_hp[] = { + {RTW_SAR_RWGS_HP_FCC_IC, RTW_REGD_FCC}, + {RTW_SAR_RWGS_HP_FCC_IC, RTW_REGD_IC}, + {RTW_SAR_RWGS_HP_ETSI_MKK, RTW_REGD_ETSI}, + {RTW_SAR_RWGS_HP_ETSI_MKK, RTW_REGD_MKK}, + {RTW_SAR_RWGS_HP_WW_KCC, RTW_REGD_KCC}, + {RTW_SAR_RWGS_HP_WW_KCC, RTW_REGD_WW}, +}; + +static const struct rtw_sar_geo_map geo_map_rt[] = { + {RTW_SAR_RWGS_RT_FCC, RTW_REGD_FCC}, + {RTW_SAR_RWGS_RT_CE, RTW_REGD_ETSI}, + {RTW_SAR_RWGS_RT_MKK, RTW_REGD_MKK}, + {RTW_SAR_RWGS_RT_IC, RTW_REGD_IC}, + {RTW_SAR_RWGS_RT_KCC, RTW_REGD_KCC}, + {RTW_SAR_RWGS_RT_WW, RTW_REGD_WW}, +}; + struct rtw_sar_read { + int (*rwsi_mode)(struct rtw_dev *rtwdev, int path); + int (*rwrd_base_q3)(struct rtw_dev *rtwdev, int mode, int path, int chidx); + int (*rwgs_delta_q3)(struct rtw_dev *rtwdev, int gi, int path, int band); + int (*rwgs_max_q3)(struct rtw_dev *rtwdev, int gi, int band); + const struct rtw_sar_geo_map *gm, *gm_end; int rwsi_sz; int rwgs_sz; }; +static int rwsi_mode_hp(struct rtw_dev *rtwdev, int path) +{ + return rtwdev->sar.rwsi->hp.index[path] - 1; +} + +static int rwrd_base_q3_hp(struct rtw_dev *rtwdev, int mode, int path, int chidx) +{ + int sar; + + sar = rtwdev->sar.rwrd->mode[mode].chain[path].limit[chidx]; + + return (10 << 3) + (sar << 2); +} + +static int rwgs_delta_q3_hp(struct rtw_dev *rtwdev, int gi, int path, int band) +{ + return rtwdev->sar.rwgs->hp.geo[gi].band[band].delta[path] << 2; +} + +static int rwgs_max_q3_hp(struct rtw_dev *rtwdev, int gi, int band) +{ + return (10 << 3) + (rtwdev->sar.rwgs->hp.geo[gi].band[band].max << 2); +} + static const struct rtw_sar_read sar_read_hp = { + .rwsi_mode = rwsi_mode_hp, + .rwrd_base_q3 = rwrd_base_q3_hp, + .rwgs_delta_q3 = rwgs_delta_q3_hp, + .rwgs_max_q3 = rwgs_max_q3_hp, + .gm = geo_map_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), }; +static int rwsi_mode_rt(struct rtw_dev *rtwdev, int path) +{ + return rtwdev->sar.rwsi->rt.index - 1; +} + +static int rwrd_base_q3_rt(struct rtw_dev *rtwdev, int mode, int path, int chidx) +{ + return rtwdev->sar.rwrd->mode[mode].chain[path].limit[chidx] << 3; +} + +static int rwgs_delta_q3_rt(struct rtw_dev *rtwdev, int gi, int path, int band) +{ + return rtwdev->sar.rwgs->rt.geo[gi].band[band].delta << 2; +} + +static int rwgs_max_q3_rt(struct rtw_dev *rtwdev, int gi, int band) +{ + return rtwdev->sar.rwgs->rt.geo[gi].band[band].max; +} + static const struct rtw_sar_read sar_read_rt = { + .rwsi_mode = rwsi_mode_rt, + .rwrd_base_q3 = rwrd_base_q3_rt, + .rwgs_delta_q3 = rwgs_delta_q3_rt, + .rwgs_max_q3 = rwgs_max_q3_rt, + .gm = geo_map_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), }; @@ -420,6 +504,49 @@ static bool is_valid_rwgs(struct rtw_dev *rtwdev, const struct rtw_sar_rwrd *rwr return false; } +static void rtw_sar_apply_dynamic_tables(struct rtw_dev *rtwdev) +{ + struct rtw_hal *hal = &rtwdev->hal; + const struct rtw_sar_read *r = rtwdev->sar.read; + const struct rtw_sar_geo_map *gm = r->gm; + const struct rtw_sar_geo_map *gm_end = r->gm_end; + int path_num = min_t(int, RTW_SAR_RWRD_CHAIN_NR, hal->rf_path_num); + int path, mode; + int sar, delta, max; + + for (; gm < gm_end; gm++) { + for (path = 0; path < path_num; path++) { + mode = r->rwsi_mode(rtwdev, path); + + /* 2.4G part */ + delta = r->rwgs_delta_q3(rtwdev, gm->idx, path, RTW_SAR_RWGS_2G); + max = r->rwgs_max_q3(rtwdev, gm->idx, RTW_SAR_RWGS_2G); + + sar = r->rwrd_base_q3(rtwdev, mode, path, RTW_SAR_LMT_CH1_14); + sar = min(sar + delta, max); + rtw_phy_set_tx_power_sar(rtwdev, gm->rd, path, 1, 14, sar); + + /* 5G part */ + delta = r->rwgs_delta_q3(rtwdev, gm->idx, path, RTW_SAR_RWGS_5G); + max = r->rwgs_max_q3(rtwdev, gm->idx, RTW_SAR_RWGS_5G); + + sar = r->rwrd_base_q3(rtwdev, mode, path, RTW_SAR_LMT_CH36_64); + sar = min(sar + delta, max); + rtw_phy_set_tx_power_sar(rtwdev, gm->rd, path, 36, 64, sar); + + sar = r->rwrd_base_q3(rtwdev, mode, path, RTW_SAR_LMT_CH100_144); + sar = min(sar + delta, max); + rtw_phy_set_tx_power_sar(rtwdev, gm->rd, path, 100, 144, sar); + + sar = r->rwrd_base_q3(rtwdev, mode, path, RTW_SAR_LMT_CH149_165); + sar = min(sar + delta, max); + rtw_phy_set_tx_power_sar(rtwdev, gm->rd, path, 149, 165, sar); + } + } + + rtwdev->sar.source = RTW_SAR_SOURCE_ACPI_DYNAMIC; +} + static int rtw_sar_load_dynamic_tables(struct rtw_dev *rtwdev) { struct rtw_sar_rwrd *rwrd; @@ -457,6 +584,8 @@ static int rtw_sar_load_dynamic_tables(struct rtw_dev *rtwdev) rtwdev->sar.rwsi = rwsi; rtwdev->sar.rwgs = rwgs; + rtw_sar_apply_dynamic_tables(rtwdev); + rtw_dbg(rtwdev, RTW_DBG_REGD, "SAR: RWRD/RWSI/RWGS is adopted\n"); return 0; 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: 11370081 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 493271820 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 32DA520726 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: 11370085 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1C3C7112B 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 EFC2520838 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)