mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-20 10:51:27 +00:00
549 lines
17 KiB
Diff
549 lines
17 KiB
Diff
From 40ea68f9c184368f1d6ca18283040368b4304f30 Mon Sep 17 00:00:00 2001
|
|
From: Nagarajan Maran <quic_nmaran@quicinc.com>
|
|
Date: Mon, 7 Nov 2022 18:26:49 +0530
|
|
Subject: [PATCH] ath12: Add vendor command support for SAWF
|
|
|
|
Add vendor command support for SAWF configure/reconfigure,
|
|
disable and view the service classes.
|
|
|
|
Signed-off-by: Nagarajan Maran <quic_nmaran@quicinc.com>
|
|
Signed-off-by: Karthikeyan Kathirvel <quic_kathirve@quicinc.com>
|
|
---
|
|
drivers/net/wireless/ath/ath12k/Makefile | 3 +-
|
|
drivers/net/wireless/ath/ath12k/vendor.c | 121 +++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath12k/vendor.h | 46 +++++++++
|
|
3 files changed, 169 insertions(+), 1 deletion(-)
|
|
create mode 100644 drivers/net/wireless/ath/ath12k/vendor.c
|
|
create mode 100644 drivers/net/wireless/ath/ath12k/vendor.h
|
|
|
|
--- a/drivers/net/wireless/ath/ath12k/Makefile
|
|
+++ b/drivers/net/wireless/ath/ath12k/Makefile
|
|
@@ -21,7 +21,8 @@ ath12k-y += core.o \
|
|
mhi.o \
|
|
pci.o \
|
|
dp_mon.o \
|
|
- sawf.o
|
|
+ sawf.o \
|
|
+ vendor.o
|
|
|
|
ath12k-$(CPTCFG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
|
|
ath12k-$(CPTCFG_NL80211_TESTMODE) += testmode.o
|
|
--- /dev/null
|
|
+++ b/drivers/net/wireless/ath/ath12k/vendor.c
|
|
@@ -0,0 +1,275 @@
|
|
+// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
+/*
|
|
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
|
|
+ */
|
|
+#include <net/netlink.h>
|
|
+#include <net/mac80211.h>
|
|
+#include "core.h"
|
|
+#include "debug.h"
|
|
+#include "mac.h"
|
|
+
|
|
+static const struct nla_policy
|
|
+ath12k_vendor_sawf_config_policy[QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX + 1] = {
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SERVICE_CLASSES] = {.type = NLA_NESTED},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID] = {.type = NLA_U8},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME] = {.type = NLA_STRING},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_TID] = {.type = NLA_U32},
|
|
+ [QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS] = {.type = NLA_U32},
|
|
+};
|
|
+
|
|
+static void ath12k_set_default_values(struct ath12k_sawf_svc_params *param)
|
|
+{
|
|
+ param->min_throughput_rate = SAWF_SVC_PARAM_DEFAULT_MIN_THRUPUT;
|
|
+ param->max_throughput_rate = SAWF_SVC_PARAM_DEFAULT_MAX_THRUPUT;
|
|
+ param->burst_size = SAWF_SVC_PARAM_DEFAULT_BURST_SIZE;
|
|
+ param->service_interval = SAWF_SVC_PARAM_DEFAULT_SVC_INTERVAL;
|
|
+ param->delay_bound = SAWF_SVC_PARAM_DEFAULT_DELAY_BOUND;
|
|
+ param->msdu_ttl = SAWF_SVC_PARAM_DEFAULT_TIME_TO_LIVE;
|
|
+ param->priority = SAWF_SVC_PARAM_DEFAULT_PRIORITY;
|
|
+ param->tid = SAWF_SVC_PARAM_DEFAULT_TID;
|
|
+ param->msdu_rate_loss = SAWF_SVC_PARAM_DEFAULT_MSDU_LOSS_RATE;
|
|
+}
|
|
+
|
|
+static int ath12k_vendor_set_sawf_config(struct wiphy *wiphy,
|
|
+ struct wireless_dev *wdev,
|
|
+ const void *data,
|
|
+ int data_len)
|
|
+{
|
|
+ struct nlattr *tb[QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX + 1];
|
|
+ struct ath12k_sawf_svc_params sawf_param;
|
|
+ char *app_name = NULL;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!ath12k_sawf_enable)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ memset(&sawf_param, 0, sizeof(struct ath12k_sawf_svc_params));
|
|
+
|
|
+ ret = nla_parse(tb, QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX, data, data_len,
|
|
+ ath12k_vendor_sawf_config_policy, NULL);
|
|
+ if (ret) {
|
|
+ ath12k_err(NULL, "Invalid attributes with SAWF configure command\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID] &&
|
|
+ tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME]) {
|
|
+ sawf_param.svc_id = nla_get_u8(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID]);
|
|
+ app_name = nla_data(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME]);
|
|
+ memcpy(sawf_param.app_name, app_name, ATH12K_MAX_APP_NAME);
|
|
+ } else {
|
|
+ ath12k_err(NULL, "Mandatory attributes not available\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ath12k_set_default_values(&sawf_param);
|
|
+
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP])
|
|
+ sawf_param.min_throughput_rate = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP])
|
|
+ sawf_param.max_throughput_rate = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE])
|
|
+ sawf_param.burst_size = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL])
|
|
+ sawf_param.service_interval = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND])
|
|
+ sawf_param.delay_bound = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL])
|
|
+ sawf_param.msdu_ttl = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO])
|
|
+ sawf_param.priority = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_TID])
|
|
+ sawf_param.tid = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_TID]);
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS])
|
|
+ sawf_param.msdu_rate_loss = nla_get_u32(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS]);
|
|
+
|
|
+ ret = ath12k_create_send_svc_params(&sawf_param);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ath12k_vendor_disable_sawf_config(struct wiphy *wihpy,
|
|
+ struct wireless_dev *wdev,
|
|
+ const void *data,
|
|
+ int data_len)
|
|
+{
|
|
+ struct nlattr *tb[QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX + 1];
|
|
+ u8 svc_id = 0;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!ath12k_sawf_enable)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ ret = nla_parse(tb, QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX, data, data_len,
|
|
+ ath12k_vendor_sawf_config_policy, NULL);
|
|
+ if (ret) {
|
|
+ ath12k_err(NULL, "Invalid attribute with SAWF disable command\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID]) {
|
|
+ svc_id = nla_get_u8(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID]);
|
|
+ } else {
|
|
+ ath12k_err(NULL, "Mandatory attribute not available\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = ath12k_sawf_disable_config(svc_id);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ath12k_vendor_view_sawf_config(struct wiphy *wihpy,
|
|
+ struct wireless_dev *wdev,
|
|
+ struct sk_buff *msg,
|
|
+ const void *data,
|
|
+ int data_len,
|
|
+ unsigned long *storage)
|
|
+{
|
|
+ struct nlattr *tb[QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX + 1];
|
|
+ struct ath12k_sawf_ctx *sawf_ctx;
|
|
+ struct ath12k_sawf_svc_params *svc_class;
|
|
+ struct nlattr *sawf_svc_classes, *sawf_svc_class;
|
|
+ int ret = 0, i, j = 0;
|
|
+ int tailroom = 0, nest_start_length = 0, nest_end_length = 0, nested_range = 0;
|
|
+ u8 svc_id = 0;
|
|
+
|
|
+ if (!ath12k_sawf_enable)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ ret = nla_parse(tb, QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX, data, data_len,
|
|
+ ath12k_vendor_sawf_config_policy, NULL);
|
|
+
|
|
+ if (ret) {
|
|
+ ath12k_warn(NULL, "Invalid attribute with SAWF view command \n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID]) {
|
|
+ svc_id = nla_get_u8(tb[QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID]);
|
|
+ if (!ath12k_svc_id_valid(svc_id)) {
|
|
+ ath12k_err(NULL, "Invalid Service ID: %u\n", svc_id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (!ath12k_svc_id_configured(svc_id))
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* return 0 to end the dump */
|
|
+ if (storage && (*storage == ATH12K_SAWF_SVC_CLASS_MAX))
|
|
+ return 0;
|
|
+
|
|
+ sawf_ctx = ath12k_get_sawf_context();
|
|
+
|
|
+ if (!sawf_ctx) {
|
|
+ ath12k_err(NULL, "SAWF context not available\n");
|
|
+ return -ENODATA;
|
|
+ }
|
|
+
|
|
+ sawf_svc_classes = nla_nest_start(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SERVICE_CLASSES);
|
|
+
|
|
+ if (!sawf_svc_classes)
|
|
+ return -ENOBUFS;
|
|
+
|
|
+ tailroom = skb_tailroom(msg);
|
|
+ spin_lock_bh(&sawf_ctx->sawf_svc_lock);
|
|
+ for (i = (svc_id) ? (svc_id - 1) : (*storage);
|
|
+ i < ATH12K_SAWF_SVC_CLASS_MAX && tailroom > nested_range;
|
|
+ i += (svc_id) ? (ATH12K_SAWF_SVC_CLASS_MAX) : (1)) {
|
|
+ if (!sawf_ctx->svc_classes[i].configured)
|
|
+ continue;
|
|
+
|
|
+ svc_class = &sawf_ctx->svc_classes[i];
|
|
+ nest_start_length = msg->len;
|
|
+ sawf_svc_class = nla_nest_start(msg, j);
|
|
+ if (nla_put_u8(msg, QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID,
|
|
+ svc_class->svc_id) ||
|
|
+ nla_put(msg, QCN_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME,
|
|
+ sizeof(svc_class->app_name),
|
|
+ svc_class->app_name) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP,
|
|
+ svc_class->min_throughput_rate) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP,
|
|
+ svc_class->max_throughput_rate) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE,
|
|
+ svc_class->burst_size) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL,
|
|
+ svc_class->service_interval) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND,
|
|
+ svc_class->delay_bound) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL,
|
|
+ svc_class->msdu_ttl) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO,
|
|
+ svc_class->priority) ||
|
|
+ nla_put_u32(msg, QCN_WLAN_VENDOR_ATTR_SAWF_SVC_TID,
|
|
+ svc_class->tid) ||
|
|
+ nla_put_u32(msg,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS,
|
|
+ svc_class->msdu_rate_loss))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ nest_end_length = nla_nest_end(msg, sawf_svc_class);
|
|
+ nested_range = nest_end_length - nest_start_length;
|
|
+ tailroom -= nested_range;
|
|
+ j++;
|
|
+ }
|
|
+ spin_unlock_bh(&sawf_ctx->sawf_svc_lock);
|
|
+ nla_nest_end(msg, sawf_svc_classes);
|
|
+
|
|
+ *storage = (svc_id) ? (ATH12K_SAWF_SVC_CLASS_MAX) : (i);
|
|
+
|
|
+ if (!j)
|
|
+ return 0;
|
|
+
|
|
+ return msg->len;
|
|
+
|
|
+nla_put_failure:
|
|
+ spin_unlock_bh(&sawf_ctx->sawf_svc_lock);
|
|
+ return -ENOBUFS;
|
|
+}
|
|
+
|
|
+static struct wiphy_vendor_command ath12k_vendor_commands[] = {
|
|
+ {
|
|
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
|
|
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SVC_CREATE,
|
|
+ .doit = ath12k_vendor_set_sawf_config,
|
|
+ .policy = ath12k_vendor_sawf_config_policy,
|
|
+ .maxattr = QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX,
|
|
+ },
|
|
+ {
|
|
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
|
|
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SVC_DISABLE,
|
|
+ .doit = ath12k_vendor_disable_sawf_config,
|
|
+ .policy = ath12k_vendor_sawf_config_policy,
|
|
+ .maxattr = QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX,
|
|
+ },
|
|
+ {
|
|
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
|
|
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SVC_VIEW,
|
|
+ .dumpit = ath12k_vendor_view_sawf_config,
|
|
+ .policy = ath12k_vendor_sawf_config_policy,
|
|
+ .maxattr = QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX,
|
|
+ },
|
|
+};
|
|
+
|
|
+int ath12k_vendor_register(struct ath12k_hw *ah)
|
|
+{
|
|
+ ah->hw->wiphy->vendor_commands = ath12k_vendor_commands;
|
|
+ ah->hw->wiphy->n_vendor_commands = ARRAY_SIZE(ath12k_vendor_commands);
|
|
+ return 0;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/drivers/net/wireless/ath/ath12k/vendor.h
|
|
@@ -0,0 +1,40 @@
|
|
+// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
+/*
|
|
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
|
|
+ */
|
|
+#ifndef ATH12K_VENDOR_H
|
|
+#define ATH12K_VENDOR_H
|
|
+
|
|
+#define QCA_NL80211_VENDOR_ID 0x001374
|
|
+
|
|
+enum qca_nl80211_vendor_subcmds {
|
|
+ /* Wi-Fi configuration subcommand */
|
|
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
|
|
+
|
|
+ QCA_NL80211_VENDOR_SUBCMD_SVC_CREATE = 204,
|
|
+ QCA_NL80211_VENDOR_SUBCMD_SVC_DISABLE = 205,
|
|
+ QCA_NL80211_VENDOR_SUBCMD_SVC_VIEW = 206,
|
|
+};
|
|
+
|
|
+enum qca_wlan_vendor_sawf_attr_config {
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SERVICE_CLASSES = 1,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_ID,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_TID,
|
|
+ QCN_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS,
|
|
+
|
|
+ /* keep last */
|
|
+ QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_AFTER_LAST,
|
|
+ QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX =
|
|
+ QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_AFTER_LAST - 1,
|
|
+};
|
|
+
|
|
+int ath12k_vendor_register(struct ath12k_hw *ah);
|
|
+#endif /* QCA_VENDOR_H */
|
|
--- a/drivers/net/wireless/ath/ath12k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath12k/core.h
|
|
@@ -27,6 +27,7 @@
|
|
#include "spectral.h"
|
|
#include "pktlog.h"
|
|
#include "sawf.h"
|
|
+#include "vendor.h"
|
|
|
|
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
|
|
|
--- a/drivers/net/wireless/ath/ath12k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/mac.c
|
|
@@ -15021,6 +15021,8 @@ static int ath12k_mac_hw_register(struct
|
|
ah->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
|
|
ah->hw->wiphy->reg_notifier = ath12k_reg_notifier;
|
|
|
|
+ ath12k_vendor_register(ah);
|
|
+
|
|
if (!test_bit(ATH12K_FLAG_RAW_MODE, &ag->dev_flags)) {
|
|
hw->netdev_features = NETIF_F_HW_CSUM;
|
|
ieee80211_hw_set(hw, SW_CRYPTO_CONTROL);
|
|
--- a/drivers/net/wireless/ath/ath12k/sawf.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/sawf.c
|
|
@@ -242,3 +242,145 @@ bool ath12k_disable_svc_class(u8 svc_id)
|
|
|
|
return true;
|
|
}
|
|
+
|
|
+/* When fimware crash occurs/simulated with firmware recovery
|
|
+ * enabled, the service class records in the driver will be sent
|
|
+ * to the crashed chip for configuring in the firmware.
|
|
+ */
|
|
+int ath12k_sawf_reconfigure_on_crash(struct ath12k_base *ab)
|
|
+{
|
|
+ struct ath12k_sawf_svc_params svc_class = {};
|
|
+ struct ath12k *ar;
|
|
+ int i;
|
|
+
|
|
+ if (!ath12k_sawf_enable)
|
|
+ return 0;
|
|
+
|
|
+ if (!sawf_ctx)
|
|
+ return -ENODATA;
|
|
+
|
|
+ ar = ab->pdevs[0].ar;
|
|
+ if (!ar) {
|
|
+ ath12k_err(NULL, "Radio not initialized\n");
|
|
+ return -ENODATA;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ATH12K_SAWF_SVC_CLASS_MAX; i++) {
|
|
+ if (!sawf_ctx->svc_classes[i].configured)
|
|
+ continue;
|
|
+ svc_class = sawf_ctx->svc_classes[i];
|
|
+ ath12k_wmi_svc_config_send(ar, &svc_class);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* TID which is an optional parameter, when not given during
|
|
+ * service class configuration, is calulated based on the
|
|
+ * other service class parameters.
|
|
+ */
|
|
+static u32 ath12k_sawf_tid_calc(struct ath12k_sawf_svc_params *cmd)
|
|
+{
|
|
+ u32 delay_bound_present, time_to_live_present, svc_interval_present, tid;
|
|
+
|
|
+ delay_bound_present =
|
|
+ cmd->delay_bound != SAWF_SVC_PARAM_DEFAULT_DELAY_BOUND;
|
|
+ time_to_live_present =
|
|
+ cmd->msdu_ttl != SAWF_SVC_PARAM_DEFAULT_TIME_TO_LIVE;
|
|
+ svc_interval_present =
|
|
+ cmd->service_interval != SAWF_SVC_PARAM_DEFAULT_SVC_INTERVAL;
|
|
+
|
|
+ tid = 0; /* default */
|
|
+ if (delay_bound_present) {
|
|
+ if (cmd->delay_bound < DELAY_BOUND_ULTRA_LOW) {
|
|
+ tid = 7;
|
|
+ } else if (cmd->delay_bound < DELAY_BOUND_LOW) {
|
|
+ tid = 6;
|
|
+ } else if (cmd->delay_bound < DELAY_BOUND_MID) {
|
|
+ tid = 4;
|
|
+ if (time_to_live_present &&
|
|
+ (cmd->msdu_ttl < TIME_TO_LIVE_MID))
|
|
+ tid = 5;
|
|
+ } else if (cmd->delay_bound < DELAY_BOUND_HIGH) {
|
|
+ tid = 4;
|
|
+ if (svc_interval_present) {
|
|
+ if (cmd->service_interval < SVC_INTERVAL_ULTRA_LOW)
|
|
+ tid = 7;
|
|
+ else if (cmd->service_interval < SVC_INTERVAL_LOW)
|
|
+ tid = 6;
|
|
+ }
|
|
+ }
|
|
+ } else if (svc_interval_present) {
|
|
+ if (cmd->service_interval < SVC_INTERVAL_ULTRA_LOW)
|
|
+ tid = 7;
|
|
+ else if (cmd->service_interval < SVC_INTERVAL_LOW)
|
|
+ tid = 6;
|
|
+ } else if (time_to_live_present) {
|
|
+ if (cmd->msdu_ttl < TIME_TO_LIVE_ULTRA_LOW)
|
|
+ tid = 7;
|
|
+ else if (cmd->msdu_ttl < TIME_TO_LIVE_LOW)
|
|
+ tid = 6;
|
|
+ }
|
|
+ return tid;
|
|
+}
|
|
+
|
|
+int ath12k_create_send_svc_params(struct ath12k_sawf_svc_params *param)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!ath12k_svc_id_valid(param->svc_id)) {
|
|
+ ath12k_warn(NULL, "svc_id: %u is invalid, Service ID range: %d - %d\n",
|
|
+ param->svc_id, ATH12K_SAWF_SVC_CLASS_MIN,
|
|
+ ATH12K_SAWF_SVC_CLASS_MAX);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (ath12k_svc_id_configured(param->svc_id)) {
|
|
+ if (ath12k_get_tid(param->svc_id) != param->tid) {
|
|
+ ath12k_err(NULL, "Updating service class failed for TID ID:%u",
|
|
+ param->tid);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (param->tid == SAWF_SVC_PARAM_DEFAULT_TID)
|
|
+ param->tid = ath12k_sawf_tid_calc(param);
|
|
+
|
|
+ if (!ath12k_validate_sawf_param(param)) {
|
|
+ ath12k_err(NULL, "Service class parameters validation failed\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = ath12k_send_sawf_configs_soc(param);
|
|
+ if (ret) {
|
|
+ ath12k_err(NULL, "service class configuration failed\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ param->configured = true;
|
|
+ ath12k_update_svc_class(param);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int ath12k_sawf_disable_config(u8 svc_id)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if (!ath12k_svc_id_valid(svc_id)) {
|
|
+ ath12k_err(NULL, "svc_id: %u is invalid\n", svc_id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (!ath12k_svc_id_configured(svc_id)) {
|
|
+ ath12k_err(NULL, "svc_id: %u is not configured\n", svc_id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = ath12k_sawf_send_disable_soc(svc_id);
|
|
+ if (ret) {
|
|
+ ath12k_err(NULL, "svc_id: %u disabling failed\n", svc_id);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ath12k_disable_svc_class(svc_id);
|
|
+ return ret;
|
|
+}
|
|
--- a/drivers/net/wireless/ath/ath12k/sawf.h
|
|
+++ b/drivers/net/wireless/ath/ath12k/sawf.h
|
|
@@ -82,6 +82,16 @@ enum SAWF_SVC_PARAM_DEFAULTS {
|
|
SAWF_SVC_PARAM_DEFAULT_MSDU_LOSS_RATE = 0,
|
|
};
|
|
|
|
+#define DELAY_BOUND_ULTRA_LOW 10
|
|
+#define DELAY_BOUND_LOW 100
|
|
+#define DELAY_BOUND_MID 200
|
|
+#define DELAY_BOUND_HIGH 300
|
|
+#define SVC_INTERVAL_ULTRA_LOW 20
|
|
+#define SVC_INTERVAL_LOW 50
|
|
+#define TIME_TO_LIVE_ULTRA_LOW 20
|
|
+#define TIME_TO_LIVE_LOW 200
|
|
+#define TIME_TO_LIVE_MID 250
|
|
+
|
|
/**
|
|
* struct ath12k_sawf_svc_params - Service Class Parameters
|
|
* @svc_id: Service ID
|
|
@@ -134,5 +144,7 @@ bool ath12k_svc_id_valid(u8 svc_id);
|
|
void ath12k_update_svc_class(struct ath12k_sawf_svc_params *sawf_params);
|
|
bool ath12k_disable_svc_class(u8 svc_id);
|
|
int ath12k_get_tid(u8 svc_id);
|
|
-
|
|
+int ath12k_sawf_reconfigure_on_crash(struct ath12k_base *ab);
|
|
+int ath12k_create_send_svc_params(struct ath12k_sawf_svc_params *param);
|
|
+int ath12k_sawf_disable_config(u8 svc_id);
|
|
#endif /* ATH11K_SAWF_H */
|