0001
0002
0003
0004
0005 #include "debug.h"
0006 #include "sar.h"
0007
0008 static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev,
0009 u32 center_freq)
0010 {
0011 switch (center_freq) {
0012 default:
0013 rtw89_debug(rtwdev, RTW89_DBG_SAR,
0014 "center freq: %u to SAR subband is unhandled\n",
0015 center_freq);
0016 fallthrough;
0017 case 2412 ... 2484:
0018 return RTW89_SAR_2GHZ_SUBBAND;
0019 case 5180 ... 5320:
0020 return RTW89_SAR_5GHZ_SUBBAND_1_2;
0021 case 5500 ... 5720:
0022 return RTW89_SAR_5GHZ_SUBBAND_2_E;
0023 case 5745 ... 5825:
0024 return RTW89_SAR_5GHZ_SUBBAND_3;
0025 case 5955 ... 6155:
0026 return RTW89_SAR_6GHZ_SUBBAND_5_L;
0027 case 6175 ... 6415:
0028 return RTW89_SAR_6GHZ_SUBBAND_5_H;
0029 case 6435 ... 6515:
0030 return RTW89_SAR_6GHZ_SUBBAND_6;
0031 case 6535 ... 6695:
0032 return RTW89_SAR_6GHZ_SUBBAND_7_L;
0033 case 6715 ... 6855:
0034 return RTW89_SAR_6GHZ_SUBBAND_7_H;
0035
0036
0037
0038
0039
0040
0041 case 6895 ... 7115:
0042 return RTW89_SAR_6GHZ_SUBBAND_8;
0043 }
0044 }
0045
0046 struct rtw89_sar_span {
0047 enum rtw89_sar_subband subband_low;
0048 enum rtw89_sar_subband subband_high;
0049 };
0050
0051 #define RTW89_SAR_SPAN_VALID(span) ((span)->subband_high)
0052
0053 #define RTW89_SAR_6GHZ_SPAN_HEAD 6145
0054 #define RTW89_SAR_6GHZ_SPAN_IDX(center_freq) \
0055 ((((int)(center_freq) - RTW89_SAR_6GHZ_SPAN_HEAD) / 5) / 2)
0056
0057 #define RTW89_DECL_SAR_6GHZ_SPAN(center_freq, subband_l, subband_h) \
0058 [RTW89_SAR_6GHZ_SPAN_IDX(center_freq)] = { \
0059 .subband_low = RTW89_SAR_6GHZ_ ## subband_l, \
0060 .subband_high = RTW89_SAR_6GHZ_ ## subband_h, \
0061 }
0062
0063
0064
0065
0066 static const struct rtw89_sar_span rtw89_sar_overlapping_6ghz[] = {
0067 RTW89_DECL_SAR_6GHZ_SPAN(6145, SUBBAND_5_L, SUBBAND_5_H),
0068 RTW89_DECL_SAR_6GHZ_SPAN(6165, SUBBAND_5_L, SUBBAND_5_H),
0069 RTW89_DECL_SAR_6GHZ_SPAN(6185, SUBBAND_5_L, SUBBAND_5_H),
0070 RTW89_DECL_SAR_6GHZ_SPAN(6505, SUBBAND_6, SUBBAND_7_L),
0071 RTW89_DECL_SAR_6GHZ_SPAN(6525, SUBBAND_6, SUBBAND_7_L),
0072 RTW89_DECL_SAR_6GHZ_SPAN(6545, SUBBAND_6, SUBBAND_7_L),
0073 RTW89_DECL_SAR_6GHZ_SPAN(6665, SUBBAND_7_L, SUBBAND_7_H),
0074 RTW89_DECL_SAR_6GHZ_SPAN(6705, SUBBAND_7_L, SUBBAND_7_H),
0075 RTW89_DECL_SAR_6GHZ_SPAN(6825, SUBBAND_7_H, SUBBAND_8),
0076 RTW89_DECL_SAR_6GHZ_SPAN(6865, SUBBAND_7_H, SUBBAND_8),
0077 RTW89_DECL_SAR_6GHZ_SPAN(6875, SUBBAND_7_H, SUBBAND_8),
0078 RTW89_DECL_SAR_6GHZ_SPAN(6885, SUBBAND_7_H, SUBBAND_8),
0079 };
0080
0081 static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, s32 *cfg)
0082 {
0083 struct rtw89_sar_cfg_common *rtwsar = &rtwdev->sar.cfg_common;
0084 struct rtw89_hal *hal = &rtwdev->hal;
0085 enum rtw89_band band = hal->current_band_type;
0086 u32 center_freq = hal->current_freq;
0087 const struct rtw89_sar_span *span = NULL;
0088 enum rtw89_sar_subband subband_l, subband_h;
0089 int idx;
0090
0091 if (band == RTW89_BAND_6G) {
0092 idx = RTW89_SAR_6GHZ_SPAN_IDX(center_freq);
0093
0094
0095
0096
0097
0098 if (idx >= 0 && idx < ARRAY_SIZE(rtw89_sar_overlapping_6ghz))
0099 span = &rtw89_sar_overlapping_6ghz[idx];
0100 }
0101
0102 if (span && RTW89_SAR_SPAN_VALID(span)) {
0103 subband_l = span->subband_low;
0104 subband_h = span->subband_high;
0105 } else {
0106 subband_l = rtw89_sar_get_subband(rtwdev, center_freq);
0107 subband_h = subband_l;
0108 }
0109
0110 rtw89_debug(rtwdev, RTW89_DBG_SAR,
0111 "for {band %u, center_freq %u}, SAR subband: {%u, %u}\n",
0112 band, center_freq, subband_l, subband_h);
0113
0114 if (!rtwsar->set[subband_l] && !rtwsar->set[subband_h])
0115 return -ENODATA;
0116
0117 if (!rtwsar->set[subband_l])
0118 *cfg = rtwsar->cfg[subband_h];
0119 else if (!rtwsar->set[subband_h])
0120 *cfg = rtwsar->cfg[subband_l];
0121 else
0122 *cfg = min(rtwsar->cfg[subband_l], rtwsar->cfg[subband_h]);
0123
0124 return 0;
0125 }
0126
0127 static const
0128 struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = {
0129 [RTW89_SAR_SOURCE_COMMON] = {
0130 .descr_sar_source = "RTW89_SAR_SOURCE_COMMON",
0131 .txpwr_factor_sar = 2,
0132 .query_sar_config = rtw89_query_sar_config_common,
0133 },
0134 };
0135
0136 #define rtw89_sar_set_src(_dev, _src, _cfg_name, _cfg_data) \
0137 do { \
0138 typeof(_src) _s = (_src); \
0139 typeof(_dev) _d = (_dev); \
0140 BUILD_BUG_ON(!rtw89_sar_handlers[_s].descr_sar_source); \
0141 BUILD_BUG_ON(!rtw89_sar_handlers[_s].query_sar_config); \
0142 lockdep_assert_held(&_d->mutex); \
0143 _d->sar._cfg_name = *(_cfg_data); \
0144 _d->sar.src = _s; \
0145 } while (0)
0146
0147 static s8 rtw89_txpwr_sar_to_mac(struct rtw89_dev *rtwdev, u8 fct, s32 cfg)
0148 {
0149 const u8 fct_mac = rtwdev->chip->txpwr_factor_mac;
0150 s32 cfg_mac;
0151
0152 cfg_mac = fct > fct_mac ?
0153 cfg >> (fct - fct_mac) : cfg << (fct_mac - fct);
0154
0155 return (s8)clamp_t(s32, cfg_mac,
0156 RTW89_SAR_TXPWR_MAC_MIN,
0157 RTW89_SAR_TXPWR_MAC_MAX);
0158 }
0159
0160 s8 rtw89_query_sar(struct rtw89_dev *rtwdev)
0161 {
0162 const enum rtw89_sar_sources src = rtwdev->sar.src;
0163
0164 const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src];
0165 int ret;
0166 s32 cfg;
0167 u8 fct;
0168
0169 lockdep_assert_held(&rtwdev->mutex);
0170
0171 if (src == RTW89_SAR_SOURCE_NONE)
0172 return RTW89_SAR_TXPWR_MAC_MAX;
0173
0174 ret = sar_hdl->query_sar_config(rtwdev, &cfg);
0175 if (ret)
0176 return RTW89_SAR_TXPWR_MAC_MAX;
0177
0178 fct = sar_hdl->txpwr_factor_sar;
0179
0180 return rtw89_txpwr_sar_to_mac(rtwdev, fct, cfg);
0181 }
0182
0183 void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev)
0184 {
0185 const enum rtw89_sar_sources src = rtwdev->sar.src;
0186
0187 const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src];
0188 const u8 fct_mac = rtwdev->chip->txpwr_factor_mac;
0189 int ret;
0190 s32 cfg;
0191 u8 fct;
0192
0193 lockdep_assert_held(&rtwdev->mutex);
0194
0195 if (src == RTW89_SAR_SOURCE_NONE) {
0196 seq_puts(m, "no SAR is applied\n");
0197 return;
0198 }
0199
0200 seq_printf(m, "source: %d (%s)\n", src, sar_hdl->descr_sar_source);
0201
0202 ret = sar_hdl->query_sar_config(rtwdev, &cfg);
0203 if (ret) {
0204 seq_printf(m, "config: return code: %d\n", ret);
0205 seq_printf(m, "assign: max setting: %d (unit: 1/%lu dBm)\n",
0206 RTW89_SAR_TXPWR_MAC_MAX, BIT(fct_mac));
0207 return;
0208 }
0209
0210 fct = sar_hdl->txpwr_factor_sar;
0211
0212 seq_printf(m, "config: %d (unit: 1/%lu dBm)\n", cfg, BIT(fct));
0213 }
0214
0215 static int rtw89_apply_sar_common(struct rtw89_dev *rtwdev,
0216 const struct rtw89_sar_cfg_common *sar)
0217 {
0218 enum rtw89_sar_sources src;
0219 int ret = 0;
0220
0221 mutex_lock(&rtwdev->mutex);
0222
0223 src = rtwdev->sar.src;
0224 if (src != RTW89_SAR_SOURCE_NONE && src != RTW89_SAR_SOURCE_COMMON) {
0225 rtw89_warn(rtwdev, "SAR source: %d is in use", src);
0226 ret = -EBUSY;
0227 goto exit;
0228 }
0229
0230 rtw89_sar_set_src(rtwdev, RTW89_SAR_SOURCE_COMMON, cfg_common, sar);
0231 rtw89_chip_set_txpwr(rtwdev);
0232
0233 exit:
0234 mutex_unlock(&rtwdev->mutex);
0235 return ret;
0236 }
0237
0238 static const struct cfg80211_sar_freq_ranges rtw89_common_sar_freq_ranges[] = {
0239 { .start_freq = 2412, .end_freq = 2484, },
0240 { .start_freq = 5180, .end_freq = 5320, },
0241 { .start_freq = 5500, .end_freq = 5720, },
0242 { .start_freq = 5745, .end_freq = 5825, },
0243 { .start_freq = 5955, .end_freq = 6155, },
0244 { .start_freq = 6175, .end_freq = 6415, },
0245 { .start_freq = 6435, .end_freq = 6515, },
0246 { .start_freq = 6535, .end_freq = 6695, },
0247 { .start_freq = 6715, .end_freq = 6875, },
0248 { .start_freq = 6875, .end_freq = 7115, },
0249 };
0250
0251 static_assert(RTW89_SAR_SUBBAND_NR ==
0252 ARRAY_SIZE(rtw89_common_sar_freq_ranges));
0253
0254 const struct cfg80211_sar_capa rtw89_sar_capa = {
0255 .type = NL80211_SAR_TYPE_POWER,
0256 .num_freq_ranges = ARRAY_SIZE(rtw89_common_sar_freq_ranges),
0257 .freq_ranges = rtw89_common_sar_freq_ranges,
0258 };
0259
0260 int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
0261 const struct cfg80211_sar_specs *sar)
0262 {
0263 struct rtw89_dev *rtwdev = hw->priv;
0264 struct rtw89_sar_cfg_common sar_common = {0};
0265 u8 fct;
0266 u32 freq_start;
0267 u32 freq_end;
0268 s32 power;
0269 u32 i, idx;
0270
0271 if (sar->type != NL80211_SAR_TYPE_POWER)
0272 return -EINVAL;
0273
0274 fct = rtw89_sar_handlers[RTW89_SAR_SOURCE_COMMON].txpwr_factor_sar;
0275
0276 for (i = 0; i < sar->num_sub_specs; i++) {
0277 idx = sar->sub_specs[i].freq_range_index;
0278 if (idx >= ARRAY_SIZE(rtw89_common_sar_freq_ranges))
0279 return -EINVAL;
0280
0281 freq_start = rtw89_common_sar_freq_ranges[idx].start_freq;
0282 freq_end = rtw89_common_sar_freq_ranges[idx].end_freq;
0283 power = sar->sub_specs[i].power;
0284
0285 rtw89_debug(rtwdev, RTW89_DBG_SAR,
0286 "On freq %u to %u, set SAR limit %d (unit: 1/%lu dBm)\n",
0287 freq_start, freq_end, power, BIT(fct));
0288
0289 sar_common.set[idx] = true;
0290 sar_common.cfg[idx] = power;
0291 }
0292
0293 return rtw89_apply_sar_common(rtwdev, &sar_common);
0294 }