power: Add MT7921E SAR control into set_wifi_transmit_power
BUG=b:188752295
TEST=Modify chromeos-base/chromeos-config-bsp-asurada to include
{non-,}tablet-mode-power-table-mtk, verify set_wifi_transmit_power
on DUT.
TEST=Modify chromeos-base/chromeos-config-bsp-asurada to include
{non-,}tablet-mode-power-table-mtk and a power config,
`tast run $DUT wifi.SetTXPower` succeeds.
Change-Id: Id17eb32b4ed9b0668e8dd535de74568972a41b90
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2970167
Reviewed-by: Brian Norris <briannorris@chromium.org>
Tested-by: Joshua Emele <jemele@chromium.org>
Commit-Queue: Joshua Emele <jemele@chromium.org>
(cherry picked from commit 1691c0a882836c5181bca21d250d8a9fc8114916)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/3184569
Reviewed-by: Ren Kuo <ren.kuo@quanta.corp-partner.google.com>
Reviewed-by: Kerker Yang <kerker@chromium.org>
Tested-by: Ren Kuo <ren.kuo@quanta.corp-partner.google.com>
Commit-Queue: Kerker Yang <kerker@chromium.org>
diff --git a/power_manager/powerd/set_wifi_transmit_power.cc b/power_manager/powerd/set_wifi_transmit_power.cc
index c2004f3..05da2bd 100644
--- a/power_manager/powerd/set_wifi_transmit_power.cc
+++ b/power_manager/powerd/set_wifi_transmit_power.cc
@@ -104,7 +104,7 @@
return NL_OK;
}
-enum class WirelessDriver { NONE, MWIFIEX, IWL, ATH10K, RTW };
+enum class WirelessDriver { NONE, MWIFIEX, IWL, ATH10K, RTW, MTK };
enum RealtekVndcmdSARBand {
REALTEK_VNDCMD_ATTR_SAR_BAND_2g = 0,
@@ -163,6 +163,7 @@
{"mwifiex_sdio", WirelessDriver::MWIFIEX},
{"rtw_pci", WirelessDriver::RTW},
{"rtw_8822ce", WirelessDriver::RTW},
+ {"mt7921e", WirelessDriver::MTK},
};
// .../device/driver symlink should point at the driver's module.
@@ -399,6 +400,127 @@
CHECK(!nla_nest_end(msg, sar_capa)) << "Failed in nla_nest_end";
}
+// The mt7921 driver configures index 0 for 2g and indexes 1-4 for 5g. This
+// dependency is a bit fragile and can break if the underlying assumption
+// changes. Since the mt7921 driver already publishes its capabilities (see
+// crrev.com/c/3009850), this could use the driver capability to find the index
+// and frequency band mapping to avoid enums like these (b/172377638).
+enum MtkSARBand {
+ kMtkSarBand2g = 0,
+ kMtkSarBand5g1 = 1,
+ kMtkSarBand5g2 = 2,
+ kMtkSarBand5g3 = 3,
+ kMtkSarBand5g4 = 4,
+};
+
+std::map<enum MtkSARBand, uint8_t> GetMtkChromeosConfigPowerTable(
+ bool tablet, power_manager::WifiRegDomain domain) {
+ std::map<enum MtkSARBand, uint8_t> power_table = {};
+ auto config = std::make_unique<brillo::CrosConfig>();
+ CHECK(config->Init()) << "Could not find config";
+ std::string wifi_power_table_path =
+ tablet ? "/wifi/tablet-mode-power-table-mtk"
+ : "/wifi/non-tablet-mode-power-table-mtk";
+ std::string wifi_geo_power_table_path;
+ switch (domain) {
+ case power_manager::WifiRegDomain::FCC:
+ wifi_geo_power_table_path = "/wifi/fcc-power-table-mtk";
+ break;
+ case power_manager::WifiRegDomain::EU:
+ wifi_geo_power_table_path = "/wifi/eu-power-table-mtk";
+ break;
+ case power_manager::WifiRegDomain::REST_OF_WORLD:
+ wifi_geo_power_table_path = "/wifi/rest-of-world-power-table-mtk";
+ break;
+ case power_manager::WifiRegDomain::NONE:
+ break;
+ }
+
+ int limit_2g = UINT8_MAX, limit_5g = UINT8_MAX, offset_2g = 0, offset_5g = 0;
+ if (domain != power_manager::WifiRegDomain::NONE) {
+ std::string geo_string;
+ if (config->GetString(wifi_geo_power_table_path, "limit-2g", &geo_string)) {
+ limit_2g = std::stoi(geo_string);
+ }
+ if (config->GetString(wifi_geo_power_table_path, "limit-5g", &geo_string)) {
+ limit_5g = std::stoi(geo_string);
+ }
+ if (config->GetString(wifi_geo_power_table_path, "offset-2g",
+ &geo_string)) {
+ offset_2g = std::stoi(geo_string);
+ }
+ if (config->GetString(wifi_geo_power_table_path, "offset-5g",
+ &geo_string)) {
+ offset_5g = std::stoi(geo_string);
+ }
+ }
+
+ std::string value;
+ int power_limit = UINT8_MAX;
+
+ CHECK(config->GetString(wifi_power_table_path, "limit-2g", &value))
+ << "Could not get ChromeosConfig power table: " << wifi_power_table_path;
+ power_limit = std::stoi(value) + offset_2g;
+ CHECK(power_limit >= 0 && power_limit <= UINT8_MAX)
+ << "Invalid power limit configs. Limit value cannot exceed 255.";
+ power_table[kMtkSarBand2g] = std::min(power_limit, limit_2g);
+
+ CHECK(config->GetString(wifi_power_table_path, "limit-5g-1", &value))
+ << "Could not get ChromeosConfig power table.";
+ power_limit = std::stoi(value) + offset_5g;
+ CHECK(power_limit >= 0 && power_limit <= UINT8_MAX)
+ << "Invalid power limit configs. Limit value cannot exceed 255.";
+ power_table[kMtkSarBand5g1] = std::min(power_limit, limit_5g);
+
+ CHECK(config->GetString(wifi_power_table_path, "limit-5g-2", &value))
+ << "Could not get ChromeosConfig power table.";
+ power_limit = std::stoi(value) + offset_5g;
+ CHECK(power_limit >= 0 && power_limit <= UINT8_MAX)
+ << "Invalid power limit configs. Limit value cannot exceed 255.";
+ power_table[kMtkSarBand5g2] = std::min(power_limit, limit_5g);
+
+ CHECK(config->GetString(wifi_power_table_path, "limit-5g-3", &value))
+ << "Could not get ChromeosConfig power table.";
+ power_limit = std::stoi(value) + offset_5g;
+ CHECK(power_limit >= 0 && power_limit <= UINT8_MAX)
+ << "Invalid power limit configs. Limit value cannot exceed 255.";
+ power_table[kMtkSarBand5g3] = std::min(power_limit, limit_5g);
+
+ CHECK(config->GetString(wifi_power_table_path, "limit-5g-4", &value))
+ << "Could not get ChromeosConfig power table.";
+ power_limit = std::stoi(value) + offset_5g;
+ CHECK(power_limit >= 0 && power_limit <= UINT8_MAX)
+ << "Invalid power limit configs. Limit value cannot exceed 255.";
+ power_table[kMtkSarBand5g4] = std::min(power_limit, limit_5g);
+
+ return power_table;
+}
+
+// Fill in nl80211 message for the mtk driver.
+void FillMessageMTK(struct nl_msg* msg,
+ bool tablet,
+ power_manager::WifiRegDomain domain) {
+ struct nlattr* sar_capa =
+ nla_nest_start(msg, NL80211_ATTR_SAR_SPEC | NLA_F_NESTED);
+ nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, NL80211_SAR_TYPE_POWER);
+ struct nlattr* specs =
+ nla_nest_start(msg, NL80211_SAR_ATTR_SPECS | NLA_F_NESTED);
+ int i = 0;
+
+ for (const auto& limit : GetMtkChromeosConfigPowerTable(tablet, domain)) {
+ struct nlattr* sub_freq_range = nla_nest_start(msg, ++i | NLA_F_NESTED);
+ CHECK(sub_freq_range) << "Failed to execute nla_nest_start";
+ CHECK(!nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_RANGE_INDEX, limit.first))
+ << "Failed to put frequency index";
+ CHECK(!nla_put_s32(msg, NL80211_SAR_ATTR_SPECS_POWER, limit.second))
+ << "Failed to put band power";
+ CHECK(!nla_nest_end(msg, sub_freq_range)) << "Failed in nla_nest_end";
+ }
+
+ CHECK(!nla_nest_end(msg, specs)) << "Failed in nla_nest_end";
+ CHECK(!nla_nest_end(msg, sar_capa)) << "Failed in nla_nest_end";
+}
+
class PowerSetter {
public:
PowerSetter() : nl_sock_(nl_socket_alloc()), cb_(nl_cb_alloc(NL_CB_DEFAULT)) {
@@ -438,11 +560,11 @@
struct nl_msg* msg = nlmsg_alloc();
CHECK(msg);
- // The command set for Ath10k and other platform (Rtw, Intel) use different
- // APIs.
+ // The command set for Ath10k and MTK, other platform (Rtw, Intel) use
+ // different APIs.
// TODO(b/172377638): Use common API for all platforms and fallback to
// vendor API if common API is not supported.
- if (driver == WirelessDriver::ATH10K)
+ if (driver == WirelessDriver::ATH10K || driver == WirelessDriver::MTK)
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, nl_family_id_, 0, 0,
NL80211_CMD_SET_SAR_SPECS, 0);
else
@@ -466,6 +588,9 @@
case WirelessDriver::ATH10K:
FillMessageAth10k(msg, tablet);
break;
+ case WirelessDriver::MTK:
+ FillMessageMTK(msg, tablet, domain);
+ break;
case WirelessDriver::NONE:
NOTREACHED() << "No driver found";
}