Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions drivers/net/wireless/ath/ath12k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -4505,6 +4505,166 @@ static void ath12k_wmi_vdev_params_up(struct ath12k *ar,
arvif->vdev_id, ret);
}

static int ath12k_mac_config_obss_pd(struct ath12k_link_vif *arvif,
const struct ieee80211_he_obss_pd *he_obss_pd)
{
struct ath12k_wmi_obss_pd_arg obss_pd_arg = {};
u32 srg_bitmap[2], non_srg_bitmap[2];
struct ath12k *ar = arvif->ar;
u32 param_id, pdev_id;
u32 param_val;
int ret;

if (ar->ab->hw_params->single_pdev_only)
pdev_id = ath12k_mac_get_target_pdev_id_from_vif(arvif);
else
pdev_id = ar->pdev->pdev_id;

/* Set and enable SRG/non-SRG OBSS PD threshold */
param_id = WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD;
if (ar->monitor_started || !he_obss_pd->enable) {
ret = ath12k_wmi_pdev_set_param(ar, param_id, 0, pdev_id);
if (ret)
ath12k_warn(ar->ab,
"failed to set OBSS PD threshold for pdev %u: %d\n",
pdev_id, ret);
return ret;
}

/*
* This service flag indicates firmware support for SRG/SRP-based
* spatial reuse. It also specifies whether OBSS PD threshold values
* should be interpreted as dB (offset) or dBm (absolute) units.
*/
obss_pd_arg.srp_support = test_bit(WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT,
ar->ab->wmi_ab.svc_map);

if (!(he_obss_pd->sr_ctrl &
IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED)) {
if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
obss_pd_arg.non_srg_th = ATH12K_OBSS_PD_MAX_THRESHOLD +
he_obss_pd->non_srg_max_offset;
else
obss_pd_arg.non_srg_th = ATH12K_OBSS_PD_NON_SRG_MAX_THRESHOLD;

if (!obss_pd_arg.srp_support)
obss_pd_arg.non_srg_th -= ATH12K_DEFAULT_NOISE_FLOOR;

obss_pd_arg.non_srg_enabled = true;
}

if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) {
obss_pd_arg.srg_th = ATH12K_OBSS_PD_MAX_THRESHOLD +
he_obss_pd->max_offset;
obss_pd_arg.srg_enabled = true;
}

ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"pdev %u OBSS PD sr_ctrl 0x%x srg_th %d dBm non_srg_th %d dBm\n",
pdev_id, he_obss_pd->sr_ctrl,
obss_pd_arg.srg_th, obss_pd_arg.non_srg_th);

param_val = ath12k_wmi_build_obss_pd(&obss_pd_arg);
ret = ath12k_wmi_pdev_set_param(ar, param_id, param_val, pdev_id);
if (ret) {
ath12k_warn(ar->ab,
"failed to set OBSS PD threshold for pdev %u: %d\n",
pdev_id, ret);
return ret;
}

/* Enable OBSS PD for all access category */
param_id = WMI_PDEV_PARAM_SET_CMD_OBSS_PD_PER_AC;
param_val = 0xf;
ret = ath12k_wmi_pdev_set_param(ar, param_id, param_val, pdev_id);
if (ret) {
ath12k_warn(ar->ab,
"failed to set OBSS PD per ac for pdev %u: %d\n",
pdev_id, ret);
return ret;
}

/* Set SR prohibit */
param_id = WMI_PDEV_PARAM_ENABLE_SR_PROHIBIT;
param_val = !!(he_obss_pd->sr_ctrl &
IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED);
ret = ath12k_wmi_pdev_set_param(ar, param_id, param_val, pdev_id);
if (ret) {
ath12k_warn(ar->ab, "failed to set SR prohibit for pdev %u: %d\n",
pdev_id, ret);
return ret;
}

if (!obss_pd_arg.srp_support)
return 0;

memcpy(srg_bitmap, he_obss_pd->bss_color_bitmap, sizeof(srg_bitmap));
/* Set SRG BSS color bitmap */
ret = ath12k_wmi_pdev_set_srg_bss_color_bitmap(ar, pdev_id, srg_bitmap);
if (ret) {
ath12k_warn(ar->ab,
"failed to set SRG bss color bitmap for pdev %u: %d\n",
pdev_id, ret);
return ret;
}

/* Enable BSS colors for SRG */
ret = ath12k_wmi_pdev_srg_obss_color_enable_bitmap(ar, pdev_id, srg_bitmap);
if (ret) {
ath12k_warn(ar->ab,
"failed to enable SRG bss color bitmap pdev %u: %d\n",
pdev_id, ret);
return ret;
}

memcpy(srg_bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(srg_bitmap));
/* Set SRG partial bssid bitmap */
ret = ath12k_wmi_pdev_set_srg_partial_bssid_bitmap(ar, pdev_id, srg_bitmap);
if (ret) {
ath12k_warn(ar->ab,
"failed to set SRG partial bssid bitmap for pdev %u: %d\n",
pdev_id, ret);
return ret;
}

/* Enable partial bssid mask for SRG */
ret = ath12k_wmi_pdev_srg_obss_bssid_enable_bitmap(ar, pdev_id, srg_bitmap);
if (ret) {
ath12k_warn(ar->ab,
"failed to enable SRG bssid bitmap pdev %u: %d\n",
pdev_id, ret);
return ret;
}

/*
* No explicit non-SRG bitmap from mac80211; enable all colors/bssids
* as non-SRG candidates. Actual SRG members are filtered by SRG bitmaps.
*/
memset(non_srg_bitmap, 0xff, sizeof(non_srg_bitmap));

/* Enable BSS colors for non-SRG */
ret = ath12k_wmi_pdev_non_srg_obss_color_enable_bitmap(ar, pdev_id,
non_srg_bitmap);
if (ret) {
ath12k_warn(ar->ab,
"failed to enable non SRG color bitmap pdev %u: %d\n",
pdev_id, ret);
return ret;
}

/* Enable partial bssid mask for non-SRG */
ret = ath12k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(ar, pdev_id,
non_srg_bitmap);
if (ret) {
ath12k_warn(ar->ab,
"failed to enable non SRG bssid bitmap pdev %u: %d\n",
pdev_id, ret);
return ret;
}

return 0;
}

static void ath12k_mac_bss_info_changed(struct ath12k *ar,
struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *info,
Expand Down Expand Up @@ -4796,9 +4956,13 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
ath12k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
}

if (changed & BSS_CHANGED_HE_OBSS_PD)
ath12k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id,
&info->he_obss_pd);
if (changed & BSS_CHANGED_HE_OBSS_PD) {
if (vif->type == NL80211_IFTYPE_AP)
ath12k_mac_config_obss_pd(arvif, &info->he_obss_pd);
else
ath12k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id,
&info->he_obss_pd);
}

if (changed & BSS_CHANGED_HE_BSS_COLOR) {
if (vif->type == NL80211_IFTYPE_AP) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/ath/ath12k/mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ struct ath12k_reg_tpc_power_info {
struct ath12k_chan_power_info chan_power_info[ATH12K_NUM_PWR_LEVELS];
};

#define ATH12K_OBSS_PD_MAX_THRESHOLD -82
#define ATH12K_OBSS_PD_NON_SRG_MAX_THRESHOLD -62

extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;

#define ATH12K_SCAN_11D_INTERVAL 600000
Expand Down
142 changes: 142 additions & 0 deletions drivers/net/wireless/ath/ath12k/wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ struct wmi_tlv_mgmt_rx_parse {
bool frame_buf_done;
};

struct wmi_pdev_set_obss_bitmap_arg {
u32 tlv_tag;
u32 pdev_id;
u32 cmd_id;
const u32 *bitmap;
const char *label;
};

static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
[WMI_TAG_ARRAY_BYTE] = { .min_len = 0 },
[WMI_TAG_ARRAY_UINT32] = { .min_len = 0 },
Expand Down Expand Up @@ -3560,6 +3568,140 @@ ath12k_wmi_send_obss_spr_cmd(struct ath12k *ar, u32 vdev_id,
return ret;
}

u32 ath12k_wmi_build_obss_pd(const struct ath12k_wmi_obss_pd_arg *arg)
{
u32 param_val = 0;

param_val |= u32_encode_bits((u8)arg->srg_th, GENMASK(15, 8));
param_val |= u32_encode_bits((u8)arg->non_srg_th, GENMASK(7, 0));

if (arg->srp_support)
param_val |= ATH12K_OBSS_PD_THRESHOLD_IN_DBM;

if (arg->srg_enabled && arg->srp_support)
param_val |= ATH12K_OBSS_PD_SRG_EN;

if (arg->non_srg_enabled)
param_val |= ATH12K_OBSS_PD_NON_SRG_EN;

return param_val;
}

static int ath12k_wmi_pdev_set_obss_bitmap(struct ath12k *ar,
const struct wmi_pdev_set_obss_bitmap_arg *arg)
{
struct wmi_pdev_obss_pd_bitmap_cmd *cmd;
struct ath12k_wmi_pdev *wmi = ar->wmi;
const int len = sizeof(*cmd);
struct sk_buff *skb;
int ret;

skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb)
return -ENOMEM;

cmd = (struct wmi_pdev_obss_pd_bitmap_cmd *)skb->data;
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(arg->tlv_tag, len);
cmd->pdev_id = cpu_to_le32(arg->pdev_id);
memcpy(cmd->bitmap, arg->bitmap, sizeof(cmd->bitmap));

ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
"wmi set pdev %u %s %08x %08x\n",
arg->pdev_id, arg->label, arg->bitmap[0], arg->bitmap[1]);

ret = ath12k_wmi_cmd_send(wmi, skb, arg->cmd_id);
if (ret) {
ath12k_warn(ar->ab, "failed to send %s: %d\n", arg->label, ret);
dev_kfree_skb(skb);
}

return ret;
}

int ath12k_wmi_pdev_set_srg_bss_color_bitmap(struct ath12k *ar,
u32 pdev_id, const u32 *bitmap)
{
struct wmi_pdev_set_obss_bitmap_arg arg = {
.tlv_tag = WMI_TAG_PDEV_SRG_BSS_COLOR_BITMAP_CMD,
.pdev_id = pdev_id,
.cmd_id = WMI_PDEV_SET_SRG_BSS_COLOR_BITMAP_CMDID,
.bitmap = bitmap,
.label = "SRG bss color bitmap",
};

return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
}

int ath12k_wmi_pdev_set_srg_partial_bssid_bitmap(struct ath12k *ar,
u32 pdev_id, const u32 *bitmap)
{
struct wmi_pdev_set_obss_bitmap_arg arg = {
.tlv_tag = WMI_TAG_PDEV_SRG_PARTIAL_BSSID_BITMAP_CMD,
.pdev_id = pdev_id,
.cmd_id = WMI_PDEV_SET_SRG_PARTIAL_BSSID_BITMAP_CMDID,
.bitmap = bitmap,
.label = "SRG partial bssid bitmap",
};

return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
}

int ath12k_wmi_pdev_srg_obss_color_enable_bitmap(struct ath12k *ar,
u32 pdev_id, const u32 *bitmap)
{
struct wmi_pdev_set_obss_bitmap_arg arg = {
.tlv_tag = WMI_TAG_PDEV_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
.pdev_id = pdev_id,
.cmd_id = WMI_PDEV_SET_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
.bitmap = bitmap,
.label = "SRG obss color enable bitmap",
};

return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
}

int ath12k_wmi_pdev_srg_obss_bssid_enable_bitmap(struct ath12k *ar,
u32 pdev_id, const u32 *bitmap)
{
struct wmi_pdev_set_obss_bitmap_arg arg = {
.tlv_tag = WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
.pdev_id = pdev_id,
.cmd_id = WMI_PDEV_SET_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
.bitmap = bitmap,
.label = "SRG obss bssid enable bitmap",
};

return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
}

int ath12k_wmi_pdev_non_srg_obss_color_enable_bitmap(struct ath12k *ar,
u32 pdev_id, const u32 *bitmap)
{
struct wmi_pdev_set_obss_bitmap_arg arg = {
.tlv_tag = WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
.pdev_id = pdev_id,
.cmd_id = WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
.bitmap = bitmap,
.label = "non SRG obss color enable bitmap",
};

return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
}

int ath12k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(struct ath12k *ar,
u32 pdev_id, const u32 *bitmap)
{
struct wmi_pdev_set_obss_bitmap_arg arg = {
.tlv_tag = WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
.pdev_id = pdev_id,
.cmd_id = WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
.bitmap = bitmap,
.label = "non SRG obss bssid enable bitmap",
};

return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
}

int ath12k_wmi_obss_color_cfg_cmd(struct ath12k *ar, u32 vdev_id,
u8 bss_color, u32 period,
bool enable)
Expand Down
Loading