Commit 652f69ed authored by Baochen Qiang's avatar Baochen Qiang Committed by Kalle Valo

ath11k: Add support for SAR

Add ath11k_mac_op_set_bios_sar_specs() to ath11k_ops, this function is called
when user space application calls NL80211_CMD_SET_SAR_SPECS. ath11k also
registers SAR type and frequency ranges to wiphy so user space can query SAR
capabilities.

This feature is currently enabled for WCN6855.

Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-02431-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1
Signed-off-by: default avatarBaochen Qiang <quic_bqiang@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220401120948.1312956-3-quic_bqiang@quicinc.com
parent e2e23a79
......@@ -101,6 +101,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.current_cc_support = false,
.dbr_debug_support = true,
.global_reset = false,
.bios_sar_capa = NULL,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
......@@ -167,6 +168,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.current_cc_support = false,
.dbr_debug_support = true,
.global_reset = false,
.bios_sar_capa = NULL,
},
{
.name = "qca6390 hw2.0",
......@@ -232,6 +234,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.current_cc_support = true,
.dbr_debug_support = false,
.global_reset = true,
.bios_sar_capa = NULL,
},
{
.name = "qcn9074 hw1.0",
......@@ -297,6 +300,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.current_cc_support = false,
.dbr_debug_support = true,
.global_reset = false,
.bios_sar_capa = NULL,
},
{
.name = "wcn6855 hw2.0",
......@@ -362,6 +366,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.current_cc_support = true,
.dbr_debug_support = false,
.global_reset = true,
.bios_sar_capa = &ath11k_hw_sar_capa_wcn6855,
},
{
.name = "wcn6855 hw2.1",
......@@ -426,6 +431,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.current_cc_support = true,
.dbr_debug_support = false,
.global_reset = true,
.bios_sar_capa = &ath11k_hw_sar_capa_wcn6855,
},
};
......
......@@ -2154,3 +2154,23 @@ const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = {
const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390 = {
.rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM,
};
static const struct cfg80211_sar_freq_ranges ath11k_hw_sar_freq_ranges_wcn6855[] = {
{.start_freq = 2402, .end_freq = 2482 }, /* 2G ch1~ch13 */
{.start_freq = 5150, .end_freq = 5250 }, /* 5G UNII-1 ch32~ch48 */
{.start_freq = 5250, .end_freq = 5725 }, /* 5G UNII-2 ch50~ch144 */
{.start_freq = 5725, .end_freq = 5810 }, /* 5G UNII-3 ch149~ch161 */
{.start_freq = 5815, .end_freq = 5895 }, /* 5G UNII-4 ch163~ch177 */
{.start_freq = 5925, .end_freq = 6165 }, /* 6G UNII-5 Ch1, Ch2 ~ Ch41 */
{.start_freq = 6165, .end_freq = 6425 }, /* 6G UNII-5 ch45~ch93 */
{.start_freq = 6425, .end_freq = 6525 }, /* 6G UNII-6 ch97~ch113 */
{.start_freq = 6525, .end_freq = 6705 }, /* 6G UNII-7 ch117~ch149 */
{.start_freq = 6705, .end_freq = 6875 }, /* 6G UNII-7 ch153~ch185 */
{.start_freq = 6875, .end_freq = 7125 }, /* 6G UNII-8 ch189~ch233 */
};
const struct cfg80211_sar_capa ath11k_hw_sar_capa_wcn6855 = {
.type = NL80211_SAR_TYPE_POWER,
.num_freq_ranges = (ARRAY_SIZE(ath11k_hw_sar_freq_ranges_wcn6855)),
.freq_ranges = ath11k_hw_sar_freq_ranges_wcn6855,
};
......@@ -195,6 +195,7 @@ struct ath11k_hw_params {
bool current_cc_support;
bool dbr_debug_support;
bool global_reset;
const struct cfg80211_sar_capa *bios_sar_capa;
};
struct ath11k_hw_ops {
......@@ -380,4 +381,5 @@ static inline const char *ath11k_bd_ie_type_str(enum ath11k_bd_ie_type type)
return "unknown";
}
extern const struct cfg80211_sar_capa ath11k_hw_sar_capa_wcn6855;
#endif
......@@ -8273,6 +8273,68 @@ static void ath11k_mac_op_set_rekey_data(struct ieee80211_hw *hw,
mutex_unlock(&ar->conf_mutex);
}
static int ath11k_mac_op_set_bios_sar_specs(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar)
{
struct ath11k *ar = hw->priv;
const struct cfg80211_sar_sub_specs *sspec = sar->sub_specs;
int ret, index;
u8 *sar_tbl;
u32 i;
mutex_lock(&ar->conf_mutex);
if (!test_bit(WMI_TLV_SERVICE_BIOS_SAR_SUPPORT, ar->ab->wmi_ab.svc_map) ||
!ar->ab->hw_params.bios_sar_capa) {
ret = -EOPNOTSUPP;
goto exit;
}
if (!sar || sar->type != NL80211_SAR_TYPE_POWER ||
sar->num_sub_specs == 0) {
ret = -EINVAL;
goto exit;
}
ret = ath11k_wmi_pdev_set_bios_geo_table_param(ar);
if (ret) {
ath11k_warn(ar->ab, "failed to set geo table: %d\n", ret);
goto exit;
}
sar_tbl = kzalloc(BIOS_SAR_TABLE_LEN, GFP_KERNEL);
if (!sar_tbl) {
ret = -ENOMEM;
goto exit;
}
for (i = 0; i < sar->num_sub_specs; i++) {
if (sspec->freq_range_index >= (BIOS_SAR_TABLE_LEN >> 1)) {
ath11k_warn(ar->ab, "Ignore bad frequency index %u, max allowed %u\n",
sspec->freq_range_index, BIOS_SAR_TABLE_LEN >> 1);
continue;
}
/* chain0 and chain1 share same power setting */
sar_tbl[sspec->freq_range_index] = sspec->power;
index = sspec->freq_range_index + (BIOS_SAR_TABLE_LEN >> 1);
sar_tbl[index] = sspec->power;
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "sar tbl[%d] = %d\n",
sspec->freq_range_index, sar_tbl[sspec->freq_range_index]);
sspec++;
}
ret = ath11k_wmi_pdev_set_bios_sar_table_param(ar, sar_tbl);
if (ret)
ath11k_warn(ar->ab, "failed to set sar power: %d", ret);
kfree(sar_tbl);
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct ieee80211_ops ath11k_ops = {
.tx = ath11k_mac_op_tx,
.start = ath11k_mac_op_start,
......@@ -8324,6 +8386,7 @@ static const struct ieee80211_ops ath11k_ops = {
.ipv6_addr_change = ath11k_mac_op_ipv6_changed,
#endif
.set_sar_specs = ath11k_mac_op_set_bios_sar_specs,
};
static void ath11k_mac_update_ch_list(struct ath11k *ar,
......@@ -8746,6 +8809,10 @@ static int __ath11k_mac_register(struct ath11k *ar)
ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);
}
if (test_bit(WMI_TLV_SERVICE_BIOS_SAR_SUPPORT, ar->ab->wmi_ab.svc_map) &&
ab->hw_params.bios_sar_capa)
ar->hw->wiphy->sar_capa = ab->hw_params.bios_sar_capa;
ret = ieee80211_register_hw(ar->hw);
if (ret) {
ath11k_err(ar->ab, "ieee80211 registration failed: %d\n", ret);
......
......@@ -8883,3 +8883,73 @@ int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar,
arvif->vdev_id);
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID);
}
int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_val)
{ struct ath11k_pdev_wmi *wmi = ar->wmi;
struct wmi_pdev_set_sar_table_cmd *cmd;
struct wmi_tlv *tlv;
struct sk_buff *skb;
u8 *buf_ptr;
u32 len, sar_len_aligned, rsvd_len_aligned;
sar_len_aligned = roundup(BIOS_SAR_TABLE_LEN, sizeof(u32));
rsvd_len_aligned = roundup(BIOS_SAR_RSVD1_LEN, sizeof(u32));
len = sizeof(*cmd) +
TLV_HDR_SIZE + sar_len_aligned +
TLV_HDR_SIZE + rsvd_len_aligned;
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb)
return -ENOMEM;
cmd = (struct wmi_pdev_set_sar_table_cmd *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->pdev_id = ar->pdev->pdev_id;
cmd->sar_len = BIOS_SAR_TABLE_LEN;
cmd->rsvd_len = BIOS_SAR_RSVD1_LEN;
buf_ptr = skb->data + sizeof(*cmd);
tlv = (struct wmi_tlv *)buf_ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
FIELD_PREP(WMI_TLV_LEN, sar_len_aligned);
buf_ptr += TLV_HDR_SIZE;
memcpy(buf_ptr, sar_val, BIOS_SAR_TABLE_LEN);
buf_ptr += sar_len_aligned;
tlv = (struct wmi_tlv *)buf_ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
FIELD_PREP(WMI_TLV_LEN, rsvd_len_aligned);
return ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
}
int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar)
{
struct ath11k_pdev_wmi *wmi = ar->wmi;
struct wmi_pdev_set_geo_table_cmd *cmd;
struct wmi_tlv *tlv;
struct sk_buff *skb;
u8 *buf_ptr;
u32 len, rsvd_len_aligned;
rsvd_len_aligned = roundup(BIOS_SAR_RSVD2_LEN, sizeof(u32));
len = sizeof(*cmd) + TLV_HDR_SIZE + rsvd_len_aligned;
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb)
return -ENOMEM;
cmd = (struct wmi_pdev_set_geo_table_cmd *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->pdev_id = ar->pdev->pdev_id;
cmd->rsvd_len = BIOS_SAR_RSVD2_LEN;
buf_ptr = skb->data + sizeof(*cmd);
tlv = (struct wmi_tlv *)buf_ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
FIELD_PREP(WMI_TLV_LEN, rsvd_len_aligned);
return ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
}
......@@ -285,6 +285,11 @@ enum wmi_tlv_cmd_id {
WMI_PDEV_SET_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
WMI_PDEV_GET_TPC_STATS_CMDID,
WMI_PDEV_ENABLE_DURATION_BASED_TX_MODE_SELECTION_CMDID,
WMI_PDEV_GET_DPD_STATUS_CMDID,
WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID,
WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID,
WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
WMI_VDEV_DELETE_CMDID,
WMI_VDEV_START_REQUEST_CMDID,
......@@ -1859,6 +1864,8 @@ enum wmi_tlv_tag {
WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8,
WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD,
WMI_TAG_MAX
};
......@@ -2087,6 +2094,7 @@ enum wmi_tlv_service {
/* The second 128 bits */
WMI_MAX_EXT_SERVICE = 256,
WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326,
/* The third 128 bits */
WMI_MAX_EXT2_SERVICE = 384
......@@ -5882,6 +5890,23 @@ struct wmi_gtk_rekey_offload_cmd {
u8 replay_ctr[GTK_REPLAY_COUNTER_BYTES];
} __packed;
#define BIOS_SAR_TABLE_LEN (22)
#define BIOS_SAR_RSVD1_LEN (6)
#define BIOS_SAR_RSVD2_LEN (18)
struct wmi_pdev_set_sar_table_cmd {
u32 tlv_header;
u32 pdev_id;
u32 sar_len;
u32 rsvd_len;
} __packed;
struct wmi_pdev_set_geo_table_cmd {
u32 tlv_header;
u32 pdev_id;
u32 rsvd_len;
} __packed;
int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
u32 cmd_id);
struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len);
......@@ -6060,5 +6085,7 @@ int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar,
struct ath11k_vif *arvif, bool enable);
int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar,
struct ath11k_vif *arvif);
int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_val);
int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment