--- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -622,6 +622,8 @@ struct ath11k { enum ath11k_ap_ps_state ap_ps_state; bool monitor_vdev_created; + bool rate_mask_params_valid; + u32 rate_mask_params[4]; }; struct ath11k_band_cap { --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -1361,6 +1361,57 @@ static const struct file_operations fops .open = simple_open }; +static ssize_t ath11k_write_rate_mask(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + struct ath11k_vif *arvif = NULL; + u32 params[4]; + u8 buf[128] = {0}; + int ret, vdev_count= 0; + + mutex_lock(&ar->conf_mutex); + list_for_each_entry(arvif, &ar->arvifs, list) + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) + vdev_count++; + + if (vdev_count){ + ath11k_warn(ar->ab, "can't set rate mask if any ap vdev up\n"); + ret = -EINVAL; + goto exit; + } + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); + if (ret < 0) + goto exit; + + buf[ret] = '\0'; + ret = sscanf(buf, "%x %x %x %x", + ¶ms[0], ¶ms[1], ¶ms[2], ¶ms[3]); + if (ret != 4) { + ret = -EINVAL; + goto exit; + } + + if (!params[0] && !params[1] && !params[2] && !params[3]) + ar->rate_mask_params_valid = false; + else { + memcpy(ar->rate_mask_params, params, sizeof(params)); + ar->rate_mask_params_valid = true; + } + + ret = count; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_rate_mask = { + .write = ath11k_write_rate_mask, + .open = simple_open, +}; + static ssize_t ath11k_write_simulate_radar(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -1595,6 +1646,9 @@ int ath11k_debug_register(struct ath11k debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_pdev, ar, &fops_pktlog_filter); + debugfs_create_file("rate_mask", 0644, + ar->debug.debugfs_pdev, ar, + &fops_rate_mask); debugfs_create_file("btcoex", 0644, ar->debug.debugfs_pdev, ar, &fops__btcoex); --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1141,6 +1141,15 @@ static void ath11k_control_beaconing(str return; } + if (ar->rate_mask_params_valid && arvif->vdev_type == WMI_VDEV_TYPE_AP) { + ret = ath11k_wmi_vdev_set_ratemask(ar, arvif->vdev_id, ar->rate_mask_params); + if (ret) { + ath11k_warn(ar->ab, "failed to send rate mask cmd\n"); + return; + } + ar->rate_mask_params_valid = false; + } + arvif->tx_seq_no = 0x1000; arvif->aid = 0; --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -911,6 +911,40 @@ int ath11k_wmi_vdev_start(struct ath11k return ret; } +int ath11k_wmi_vdev_set_ratemask(struct ath11k *ar, u32 vdev_id, u32 *params) +{ + struct wmi_vdev_config_ratemask_cmd *cmd; + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if(!skb) + return -ENOMEM; + + cmd = (struct wmi_vdev_config_ratemask_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_CONFIG_RATEMASK) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = vdev_id; + cmd->type = params[0]; + cmd->mask_l = params[1]; + cmd->mask_h = params[2]; + cmd->mask_l2 = params[3]; + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_RATEMASK_CMDID); + if (ret) { + ath11k_warn(ar->ab, "failed to send vdev ratemask cmd\n"); + dev_kfree_skb(skb); + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "ratemask vdev %d type %d mskl 0x%x, mskh 0x%x mskl2 0x%x\n", + vdev_id, params[0], params[1], params[2], params[3]); + + return ret; +} + int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid) { struct ath11k_pdev_wmi *wmi = ar->wmi; --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2498,6 +2498,15 @@ struct wmi_vdev_delete_cmd { u32 vdev_id; } __packed; +struct wmi_vdev_config_ratemask_cmd { + u32 tlv_header; + u32 vdev_id; + u32 type; + u32 mask_l; + u32 mask_h; + u32 mask_l2; +} __packed; + struct wmi_vdev_up_cmd { u32 tlv_header; u32 vdev_id; @@ -5372,6 +5381,7 @@ int ath11k_wmi_send_obss_spr_cmd(struct int ath11k_send_coex_config_cmd(struct ath11k *ar, struct coex_config_arg *coex_config); int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u8 pdev_id, u32 value); +int ath11k_wmi_vdev_set_ratemask(struct ath11k *ar, u32 vdev_id, u32 *rate_mask_params); int ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id, u8 bss_color, u32 period, bool enable);