summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw89/sar.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-08-29 11:33:01 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2023-08-29 11:33:01 -0700
commitbd6c11bc43c496cddfc6cf603b5d45365606dbd5 (patch)
tree36318fa68f784d397111991177d65bd6325189c4 /drivers/net/wireless/realtek/rtw89/sar.c
parent68cf01760bc0891074e813b9bb06d2696cac1c01 (diff)
parentc873512ef3a39cc1a605b7a5ff2ad0a33d619aa8 (diff)
Merge tag 'net-next-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Paolo Abeni: "Core: - Increase size limits for to-be-sent skb frag allocations. This allows tun, tap devices and packet sockets to better cope with large writes operations - Store netdevs in an xarray, to simplify iterating over netdevs - Refactor nexthop selection for multipath routes - Improve sched class lifetime handling - Add backup nexthop ID support for bridge - Implement drop reasons support in openvswitch - Several data races annotations and fixes - Constify the sk parameter of routing functions - Prepend kernel version to netconsole message Protocols: - Implement support for TCP probing the peer being under memory pressure - Remove hard coded limitation on IPv6 specific info placement inside the socket struct - Get rid of sysctl_tcp_adv_win_scale and use an auto-estimated per socket scaling factor - Scaling-up the IPv6 expired route GC via a separated list of expiring routes - In-kernel support for the TLS alert protocol - Better support for UDP reuseport with connected sockets - Add NEXT-C-SID support for SRv6 End.X behavior, reducing the SR header size - Get rid of additional ancillary per MPTCP connection struct socket - Implement support for BPF-based MPTCP packet schedulers - Format MPTCP subtests selftests results in TAP - Several new SMC 2.1 features including unique experimental options, max connections per lgr negotiation, max links per lgr negotiation BPF: - Multi-buffer support in AF_XDP - Add multi uprobe BPF links for attaching multiple uprobes and usdt probes, which is significantly faster and saves extra fds - Implement an fd-based tc BPF attach API (TCX) and BPF link support on top of it - Add SO_REUSEPORT support for TC bpf_sk_assign - Support new instructions from cpu v4 to simplify the generated code and feature completeness, for x86, arm64, riscv64 - Support defragmenting IPv(4|6) packets in BPF - Teach verifier actual bounds of bpf_get_smp_processor_id() and fix perf+libbpf issue related to custom section handling - Introduce bpf map element count and enable it for all program types - Add a BPF hook in sys_socket() to change the protocol ID from IPPROTO_TCP to IPPROTO_MPTCP to cover migration for legacy - Introduce bpf_me_mcache_free_rcu() and fix OOM under stress - Add uprobe support for the bpf_get_func_ip helper - Check skb ownership against full socket - Support for up to 12 arguments in BPF trampoline - Extend link_info for kprobe_multi and perf_event links Netfilter: - Speed-up process exit by aborting ruleset validation if a fatal signal is pending - Allow NLA_POLICY_MASK to be used with BE16/BE32 types Driver API: - Page pool optimizations, to improve data locality and cache usage - Introduce ndo_hwtstamp_get() and ndo_hwtstamp_set() to avoid the need for raw ioctl() handling in drivers - Simplify genetlink dump operations (doit/dumpit) providing them the common information already populated in struct genl_info - Extend and use the yaml devlink specs to [re]generate the split ops - Introduce devlink selective dumps, to allow SF filtering SF based on handle and other attributes - Add yaml netlink spec for netlink-raw families, allow route, link and address related queries via the ynl tool - Remove phylink legacy mode support - Support offload LED blinking to phy - Add devlink port function attributes for IPsec New hardware / drivers: - Ethernet: - Broadcom ASP 2.0 (72165) ethernet controller - MediaTek MT7988 SoC - Texas Instruments AM654 SoC - Texas Instruments IEP driver - Atheros qca8081 phy - Marvell 88Q2110 phy - NXP TJA1120 phy - WiFi: - MediaTek mt7981 support - Can: - Kvaser SmartFusion2 PCI Express devices - Allwinner T113 controllers - Texas Instruments tcan4552/4553 chips - Bluetooth: - Intel Gale Peak - Qualcomm WCN3988 and WCN7850 - NXP AW693 and IW624 - Mediatek MT2925 Drivers: - Ethernet NICs: - nVidia/Mellanox: - mlx5: - support UDP encapsulation in packet offload mode - IPsec packet offload support in eswitch mode - improve aRFS observability by adding new set of counters - extends MACsec offload support to cover RoCE traffic - dynamic completion EQs - mlx4: - convert to use auxiliary bus instead of custom interface logic - Intel - ice: - implement switchdev bridge offload, even for LAG interfaces - implement SRIOV support for LAG interfaces - igc: - add support for multiple in-flight TX timestamps - Broadcom: - bnxt: - use the unified RX page pool buffers for XDP and non-XDP - use the NAPI skb allocation cache - OcteonTX2: - support Round Robin scheduling HTB offload - TC flower offload support for SPI field - Freescale: - add XDP_TX feature support - AMD: - ionic: add support for PCI FLR event - sfc: - basic conntrack offload - introduce eth, ipv4 and ipv6 pedit offloads - ST Microelectronics: - stmmac: maximze PTP timestamping resolution - Virtual NICs: - Microsoft vNIC: - batch ringing RX queue doorbell on receiving packets - add page pool for RX buffers - Virtio vNIC: - add per queue interrupt coalescing support - Google vNIC: - add queue-page-list mode support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add port range matching tc-flower offload - permit enslavement to netdevices with uppers - Ethernet embedded switches: - Marvell (mv88e6xxx): - convert to phylink_pcs - Renesas: - r8A779fx: add speed change support - rzn1: enables vlan support - Ethernet PHYs: - convert mv88e6xxx to phylink_pcs - WiFi: - Qualcomm Wi-Fi 7 (ath12k): - extremely High Throughput (EHT) PHY support - RealTek (rtl8xxxu): - enable AP mode for: RTL8192FU, RTL8710BU (RTL8188GU), RTL8192EU and RTL8723BU - RealTek (rtw89): - Introduce Time Averaged SAR (TAS) support - Connector: - support for event filtering" * tag 'net-next-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1806 commits) net: ethernet: mtk_wed: minor change in wed_{tx,rx}info_show net: ethernet: mtk_wed: add some more info in wed_txinfo_show handler net: stmmac: clarify difference between "interface" and "phy_interface" r8152: add vendor/device ID pair for D-Link DUB-E250 devlink: move devlink_notify_register/unregister() to dev.c devlink: move small_ops definition into netlink.c devlink: move tracepoint definitions into core.c devlink: push linecard related code into separate file devlink: push rate related code into separate file devlink: push trap related code into separate file devlink: use tracepoint_enabled() helper devlink: push region related code into separate file devlink: push param related code into separate file devlink: push resource related code into separate file devlink: push dpipe related code into separate file devlink: move and rename devlink_dpipe_send_and_alloc_skb() helper devlink: push shared buffer related code into separate file devlink: push port related code into separate file devlink: push object register/unregister notifications into separate helpers inet: fix IP_TRANSPARENT error handling ...
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/sar.c')
-rw-r--r--drivers/net/wireless/realtek/rtw89/sar.c220
1 files changed, 209 insertions, 11 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c
index dfccae81c380..aed05b026c6c 100644
--- a/drivers/net/wireless/realtek/rtw89/sar.c
+++ b/drivers/net/wireless/realtek/rtw89/sar.c
@@ -2,9 +2,16 @@
/* Copyright(c) 2019-2020 Realtek Corporation
*/
+#include "acpi.h"
#include "debug.h"
+#include "phy.h"
+#include "reg.h"
#include "sar.h"
+#define RTW89_TAS_FACTOR 2 /* unit: 0.25 dBm */
+#define RTW89_TAS_DPR_GAP (1 << RTW89_TAS_FACTOR)
+#define RTW89_TAS_DELTA (2 << RTW89_TAS_FACTOR)
+
static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev,
u32 center_freq)
{
@@ -78,17 +85,15 @@ static const struct rtw89_sar_span rtw89_sar_overlapping_6ghz[] = {
RTW89_DECL_SAR_6GHZ_SPAN(6885, SUBBAND_7_H, SUBBAND_8),
};
-static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, s32 *cfg)
+static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev,
+ u32 center_freq, s32 *cfg)
{
struct rtw89_sar_cfg_common *rtwsar = &rtwdev->sar.cfg_common;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- enum rtw89_band band = chan->band_type;
- u32 center_freq = chan->freq;
const struct rtw89_sar_span *span = NULL;
enum rtw89_sar_subband subband_l, subband_h;
int idx;
- if (band == RTW89_BAND_6G) {
+ if (center_freq >= RTW89_SAR_6GHZ_SPAN_HEAD) {
idx = RTW89_SAR_6GHZ_SPAN_IDX(center_freq);
/* To decrease size of rtw89_sar_overlapping_6ghz[],
* RTW89_SAR_6GHZ_SPAN_IDX() truncates the leading NULLs
@@ -108,8 +113,8 @@ static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, s32 *cfg)
}
rtw89_debug(rtwdev, RTW89_DBG_SAR,
- "for {band %u, center_freq %u}, SAR subband: {%u, %u}\n",
- band, center_freq, subband_l, subband_h);
+ "center_freq %u: SAR subband {%u, %u}\n",
+ center_freq, subband_l, subband_h);
if (!rtwsar->set[subband_l] && !rtwsar->set[subband_h])
return -ENODATA;
@@ -157,11 +162,35 @@ static s8 rtw89_txpwr_sar_to_mac(struct rtw89_dev *rtwdev, u8 fct, s32 cfg)
RTW89_SAR_TXPWR_MAC_MAX);
}
-s8 rtw89_query_sar(struct rtw89_dev *rtwdev)
+static s8 rtw89_txpwr_tas_to_sar(const struct rtw89_sar_handler *sar_hdl,
+ s8 cfg)
+{
+ const u8 fct = sar_hdl->txpwr_factor_sar;
+
+ if (fct > RTW89_TAS_FACTOR)
+ return cfg << (fct - RTW89_TAS_FACTOR);
+ else
+ return cfg >> (RTW89_TAS_FACTOR - fct);
+}
+
+static s8 rtw89_txpwr_sar_to_tas(const struct rtw89_sar_handler *sar_hdl,
+ s8 cfg)
+{
+ const u8 fct = sar_hdl->txpwr_factor_sar;
+
+ if (fct > RTW89_TAS_FACTOR)
+ return cfg >> (fct - RTW89_TAS_FACTOR);
+ else
+ return cfg << (RTW89_TAS_FACTOR - fct);
+}
+
+s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq)
{
const enum rtw89_sar_sources src = rtwdev->sar.src;
/* its members are protected by rtw89_sar_set_src() */
const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src];
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ s8 delta;
int ret;
s32 cfg;
u8 fct;
@@ -171,16 +200,30 @@ s8 rtw89_query_sar(struct rtw89_dev *rtwdev)
if (src == RTW89_SAR_SOURCE_NONE)
return RTW89_SAR_TXPWR_MAC_MAX;
- ret = sar_hdl->query_sar_config(rtwdev, &cfg);
+ ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg);
if (ret)
return RTW89_SAR_TXPWR_MAC_MAX;
+ if (tas->enable) {
+ switch (tas->state) {
+ case RTW89_TAS_STATE_DPR_OFF:
+ return RTW89_SAR_TXPWR_MAC_MAX;
+ case RTW89_TAS_STATE_DPR_ON:
+ delta = rtw89_txpwr_tas_to_sar(sar_hdl, tas->delta);
+ cfg -= delta;
+ break;
+ case RTW89_TAS_STATE_DPR_FORBID:
+ default:
+ break;
+ }
+ }
+
fct = sar_hdl->txpwr_factor_sar;
return rtw89_txpwr_sar_to_mac(rtwdev, fct, cfg);
}
-void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev)
+void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev, u32 center_freq)
{
const enum rtw89_sar_sources src = rtwdev->sar.src;
/* its members are protected by rtw89_sar_set_src() */
@@ -199,7 +242,7 @@ void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev)
seq_printf(m, "source: %d (%s)\n", src, sar_hdl->descr_sar_source);
- ret = sar_hdl->query_sar_config(rtwdev, &cfg);
+ ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg);
if (ret) {
seq_printf(m, "config: return code: %d\n", ret);
seq_printf(m, "assign: max setting: %d (unit: 1/%lu dBm)\n",
@@ -212,6 +255,19 @@ void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev)
seq_printf(m, "config: %d (unit: 1/%lu dBm)\n", cfg, BIT(fct));
}
+void rtw89_print_tas(struct seq_file *m, struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+
+ if (!tas->enable) {
+ seq_puts(m, "no TAS is applied\n");
+ return;
+ }
+
+ seq_printf(m, "DPR gap: %d\n", tas->dpr_gap);
+ seq_printf(m, "TAS delta: %d\n", tas->delta);
+}
+
static int rtw89_apply_sar_common(struct rtw89_dev *rtwdev,
const struct rtw89_sar_cfg_common *sar)
{
@@ -292,3 +348,145 @@ int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
return rtw89_apply_sar_common(rtwdev, &sar_common);
}
+
+static void rtw89_tas_state_update(struct rtw89_dev *rtwdev)
+{
+ const enum rtw89_sar_sources src = rtwdev->sar.src;
+ /* its members are protected by rtw89_sar_set_src() */
+ const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src];
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ s32 txpwr_avg = tas->total_txpwr / RTW89_TAS_MAX_WINDOW / PERCENT;
+ s32 dpr_on_threshold, dpr_off_threshold, cfg;
+ enum rtw89_tas_state state = tas->state;
+ const struct rtw89_chan *chan;
+ int ret;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ if (src == RTW89_SAR_SOURCE_NONE)
+ return;
+
+ chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ ret = sar_hdl->query_sar_config(rtwdev, chan->freq, &cfg);
+ if (ret)
+ return;
+
+ cfg = rtw89_txpwr_sar_to_tas(sar_hdl, cfg);
+
+ if (tas->delta >= cfg) {
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "TAS delta exceed SAR limit\n");
+ state = RTW89_TAS_STATE_DPR_FORBID;
+ goto out;
+ }
+
+ dpr_on_threshold = cfg;
+ dpr_off_threshold = cfg - tas->dpr_gap;
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "DPR_ON thold: %d, DPR_OFF thold: %d, txpwr_avg: %d\n",
+ dpr_on_threshold, dpr_off_threshold, txpwr_avg);
+
+ if (txpwr_avg >= dpr_on_threshold)
+ state = RTW89_TAS_STATE_DPR_ON;
+ else if (txpwr_avg < dpr_off_threshold)
+ state = RTW89_TAS_STATE_DPR_OFF;
+
+out:
+ if (tas->state == state)
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "TAS old state: %d, new state: %d\n", tas->state, state);
+ tas->state = state;
+ rtw89_core_set_chip_txpwr(rtwdev);
+}
+
+void rtw89_tas_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ int ret;
+ u8 val;
+
+ ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &val);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "acpi: cannot get TAS: %d\n", ret);
+ return;
+ }
+
+ switch (val) {
+ case 0:
+ tas->enable = false;
+ break;
+ case 1:
+ tas->enable = true;
+ break;
+ default:
+ break;
+ }
+
+ if (!tas->enable) {
+ rtw89_debug(rtwdev, RTW89_DBG_SAR, "TAS not enable\n");
+ return;
+ }
+
+ tas->dpr_gap = RTW89_TAS_DPR_GAP;
+ tas->delta = RTW89_TAS_DELTA;
+}
+
+void rtw89_tas_reset(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+
+ if (!tas->enable)
+ return;
+
+ memset(&tas->txpwr_history, 0, sizeof(tas->txpwr_history));
+ tas->total_txpwr = 0;
+ tas->cur_idx = 0;
+ tas->state = RTW89_TAS_STATE_DPR_OFF;
+}
+
+static const struct rtw89_reg_def txpwr_regs[] = {
+ {R_PATH0_TXPWR, B_PATH0_TXPWR},
+ {R_PATH1_TXPWR, B_PATH1_TXPWR},
+};
+
+void rtw89_tas_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const enum rtw89_sar_sources src = rtwdev->sar.src;
+ u8 max_nss_num = rtwdev->chip->rf_path_num;
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ s16 tmp, txpwr, instant_txpwr = 0;
+ u32 val;
+ int i;
+
+ if (!tas->enable || src == RTW89_SAR_SOURCE_NONE)
+ return;
+
+ if (env->ccx_watchdog_result != RTW89_PHY_ENV_MON_IFS_CLM)
+ return;
+
+ for (i = 0; i < max_nss_num; i++) {
+ val = rtw89_phy_read32_mask(rtwdev, txpwr_regs[i].addr,
+ txpwr_regs[i].mask);
+ tmp = sign_extend32(val, 8);
+ if (tmp <= 0)
+ return;
+ instant_txpwr += tmp;
+ }
+
+ instant_txpwr /= max_nss_num;
+ /* in unit of 0.25 dBm multiply by percentage */
+ txpwr = instant_txpwr * env->ifs_clm_tx_ratio;
+ tas->total_txpwr += txpwr - tas->txpwr_history[tas->cur_idx];
+ tas->txpwr_history[tas->cur_idx] = txpwr;
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "instant_txpwr: %d, tx_ratio: %d, txpwr: %d\n",
+ instant_txpwr, env->ifs_clm_tx_ratio, txpwr);
+
+ tas->cur_idx = (tas->cur_idx + 1) % RTW89_TAS_MAX_WINDOW;
+
+ rtw89_tas_state_update(rtwdev);
+}