--- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -1371,6 +1371,186 @@ static const struct file_operations fops .open = simple_open }; +static ssize_t ath11k_write_btcoex(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k_vif *arvif; + struct ath11k *ar = file->private_data; + char buf[256]; + size_t buf_size; + int ret,coex = -1; + enum qca_wlan_priority_type wlan_prio_mask = 0; + int wlan_weight = 0; + + if (!ar) + return -EINVAL; + + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, ubuf, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + ret = sscanf(buf, "%d %u %d" , &coex, &wlan_prio_mask, &wlan_weight); + if (!ret) + return -EINVAL; + + if (wlan_weight == -1) + wlan_weight = 0; + + if(wlan_prio_mask == -1) + wlan_prio_mask =0; + + if(wlan_weight < 0 || wlan_prio_mask < 0) + return -EINVAL; + + if(coex != 1 && coex != -1 && coex) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); + if (!arvif->is_started) { + ret = -EINVAL; + goto exit; + } + + if(coex == 1 && !test_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags)) + set_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags); + + if(coex == -1 && !test_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags)){ + ret = -EINVAL; + goto exit; + } + + if (!coex) + clear_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags); + + ret = ath11k_mac_coex_config(ar, arvif, coex, wlan_prio_mask, wlan_weight); + if (ret) + goto exit; + + ar->coex.wlan_prio_mask = wlan_prio_mask; + ar->coex.wlan_weight = wlan_weight; + ret = count; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static ssize_t ath11k_read_btcoex(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char buf[256]; + int len=0; + + if (!ar) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf) - len, "%d %d %d\n", + test_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags), + ar->coex.wlan_prio_mask, + ar->coex.wlan_weight); + mutex_unlock(&ar->conf_mutex); + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static const struct file_operations fops__btcoex = { + .read = ath11k_read_btcoex, + .write = ath11k_write_btcoex, + .open = simple_open +}; + + +static ssize_t ath11k_write_btcoex_duty_cycle(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k_vif *arvif; + struct ath11k *ar = file->private_data; + struct coex_config_arg coex_config; + char buf[256]; + size_t buf_size; + u32 duty_cycle,wlan_duration; + int ret; + + if (!ar) + return -EINVAL; + + if (!test_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags)) + return -EINVAL; + + if (ar->coex.coex_algo_type != COEX_ALGO_OCS) { + ath11k_err(ar->ab,"duty cycle algo is not enabled"); + return -EINVAL; + } + + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, ubuf, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + ret = sscanf(buf, "%d %d" , &duty_cycle, &wlan_duration); + + if (!ret) + return -EINVAL; + + /*Maximum duty_cycle period allowed is 100 Miliseconds*/ + if (duty_cycle < wlan_duration || !duty_cycle || !wlan_duration || duty_cycle > 100000) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); + if (!arvif->is_started) { + ret = -EINVAL; + goto exit; + } + + coex_config.vdev_id = arvif->vdev_id; + coex_config.config_type = WMI_COEX_CONFIG_AP_TDM; + coex_config.duty_cycle = duty_cycle; + coex_config.wlan_duration = wlan_duration; + + ret = ath11k_send_coex_config_cmd(ar, &coex_config); + if (ret) { + ath11k_warn(ar->ab, + "failed to set coex config vdev_id %d ret %d\n", + coex_config.vdev_id, ret); + goto exit; + } + + ar->coex.duty_cycle = duty_cycle; + ar->coex.wlan_duration = wlan_duration; + ret = count; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; + +} + +static ssize_t ath11k_read_btcoex_duty_cycle(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char buf[256]; + int len =0; + + if (!ar) + return -EINVAL; + + len = scnprintf(buf, sizeof(buf) - len, "%d %d\n", + ar->coex.duty_cycle,ar->coex.wlan_duration); + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + + +static const struct file_operations fops__btcoex_duty_cycle = { + .read = ath11k_read_btcoex_duty_cycle, + .write = ath11k_write_btcoex_duty_cycle, + .open = simple_open +}; + int ath11k_debug_register(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; @@ -1406,6 +1586,12 @@ int ath11k_debug_register(struct ath11k debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_pdev, ar, &fops_pktlog_filter); + debugfs_create_file("btcoex", 0644, + ar->debug.debugfs_pdev, ar, + &fops__btcoex); + debugfs_create_file("btcoex_duty_cycle", 0644, + ar->debug.debugfs_pdev, ar, + &fops__btcoex_duty_cycle); if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) { debugfs_create_file("dfs_simulate_radar", 0200, --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1537,6 +1537,17 @@ static void ath11k_wmi_copy_coex_config( coex_config->bt_txrx_time, coex_config->bt_priority_time, coex_config->pta_algorithm, coex_config->pta_priority); } + + if (coex_config->config_type == WMI_COEX_CONFIG_AP_TDM) { + cmd->duty_cycle = coex_config->duty_cycle; + cmd->wlan_duration = coex_config->wlan_duration; + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI coex config type %u vdev id %d duty_cycle %u wlan_duration %u\n", + coex_config->config_type, + coex_config->vdev_id, + coex_config->duty_cycle, + coex_config->wlan_duration); + } } int ath11k_send_coex_config_cmd(struct ath11k *ar, --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4754,6 +4754,10 @@ struct coex_config_arg { u32 wlan_pkt_weight; u32 bt_pkt_weight; }; + struct { + u32 duty_cycle; + u32 wlan_duration; + }; }; }; @@ -4781,6 +4785,11 @@ struct wmi_coex_config_cmd { u32 wlan_pkt_weight; u32 bt_pkt_weight; } __packed; + + struct { + u32 duty_cycle; + u32 wlan_duration; + } __packed; } __packed; } __packed; --- a/drivers/net/wireless/ath/ath11k/vendor.c +++ b/drivers/net/wireless/ath/ath11k/vendor.c @@ -9,102 +9,10 @@ #include "debug.h" static const struct nla_policy -ath11k_vendor_btcoex_config_policy[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_ENABLE] = { .type = NLA_U8 }, - [QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_WLAN_PRIORITY] = { .type = NLA_NESTED }, -}; - -static const struct nla_policy -ath11k_vendor_wlan_prio_policy[QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_MASK] = { .type = NLA_U8 }, - [QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_WEIGHT] = { .type = NLA_U8 }, -}; - -static const struct nla_policy ath11k_vendor_set_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_CONFIG_GTX] = {.type = NLA_FLAG} }; -static int ath11k_vendor_btcoex_configure(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - struct ieee80211_vif *vif; - struct ath11k_vif *arvif; - struct ath11k *ar; - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_MAX + 1]; - struct nlattr *tb_wlan_prio[QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_MAX + 1]; - struct nlattr *wlan_prio; - enum qca_wlan_priority_type wlan_prio_mask = 0; - int ret, coex = -1, rem_conf; - u8 wlan_weight = 0; - - if (!wdev) - return -EINVAL; - - vif = wdev_to_ieee80211_vif(wdev); - if (!vif) - return -EINVAL; - - arvif = (struct ath11k_vif *)vif->drv_priv; - if (!arvif) - return -EINVAL; - - ar = arvif->ar; - - mutex_lock(&ar->conf_mutex); - - ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_MAX, data, data_len, - ath11k_vendor_btcoex_config_policy, NULL); - if (ret) { - ath11k_warn(ar->ab, "invalid BTCOEX config policy attribute\n"); - goto out; - } - - if (!tb[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_ENABLE] && - !tb[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_WLAN_PRIORITY]) { - ath11k_warn(ar->ab, "invalid BTCOEX config attributes\n"); - ret = -EINVAL; - goto out; - } - - if (tb[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_ENABLE]) { - coex = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_ENABLE]); - ret = ath11k_mac_coex_config(ar, arvif, coex, wlan_prio_mask, wlan_weight); - if (ret) - goto out; - } - if (tb[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_WLAN_PRIORITY]) { - nla_for_each_nested(wlan_prio, - tb[QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_WLAN_PRIORITY], - rem_conf) { - ret = - nla_parse_nested(tb_wlan_prio, QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_MAX, - wlan_prio, ath11k_vendor_wlan_prio_policy, - NULL); - if (ret) - goto out; - wlan_prio_mask = - nla_get_u8(tb_wlan_prio[QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_MASK]); - if (tb_wlan_prio[QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_WEIGHT]) - wlan_weight = - nla_get_u8(tb_wlan_prio[QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_WEIGHT]); - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "BTCOEX enable %u WLAN Priority %u wlan weight %u\n", - coex, wlan_prio_mask, wlan_weight); - - ret = ath11k_mac_coex_config(ar, arvif, coex, wlan_prio_mask, wlan_weight); - if (ret) - goto out; - } - } - -out: - mutex_unlock(&ar->conf_mutex); - return ret; -} - static int ath11k_vendor_set_wifi_config(struct wiphy *wihpy, struct wireless_dev *wdev, const void *data, @@ -153,15 +61,6 @@ exit: static struct wiphy_vendor_command ath11k_vendor_commands[] = { { .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BTCOEX_CONFIG, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = ath11k_vendor_btcoex_configure, - .policy = ath11k_vendor_btcoex_config_policy, - .maxattr = QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_MAX - }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -478,6 +478,10 @@ struct ath11k_coex_info { u32 bt_priority_time_slot; u32 coex_algo_type; u32 pta_priority; + u32 wlan_prio_mask; + u32 wlan_weight; + u32 duty_cycle; + u32 wlan_duration; }; enum ath11k_ap_ps_state { @@ -485,6 +489,12 @@ enum ath11k_ap_ps_state { ATH11K_AP_PS_STATE_ON, }; +enum coex_algo { + COEX_ALGO_UNCONS_FREERUN = 0, + COEX_ALGO_FREERUN, + COEX_ALGO_OCS, +}; + struct ath11k { struct ath11k_base *ab; struct ath11k_pdev *pdev;