blob: 28998592b46313acc4fdbe74666d659254afba94 [file] [log] [blame]
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
*/
#ifdef CONFIG_ATH11K_NSS_SUPPORT
#include <net/mac80211.h>
#include "dp_rx.h"
#include "nss.h"
#include "debug.h"
#include "debug_nss.h"
extern struct dentry *debugfs_debug_infra;
static unsigned int
debug_nss_fill_mpp_dump(struct ath11k_vif *arvif, char *buf, ssize_t size)
{
struct arvif_nss *nss = &arvif->nss;
struct ath11k *ar = arvif->ar;
struct ath11k_nss_mpp_entry *entry, *tmp;
LIST_HEAD(local_entry);
unsigned int len = 0;
int i;
len += scnprintf(buf + len, size - len, "\nProxy path table\n");
len += scnprintf(buf + len, size - len, "dest_mac_addr\t\tmesh_dest_mac\t\tflags\n");
spin_lock_bh(&ar->nss.dump_lock);
list_splice_tail(&nss->mpp_dump, &local_entry);
spin_unlock_bh(&ar->nss.dump_lock);
list_for_each_entry_safe(entry, tmp, &local_entry, list) {
for (i = 0; i < entry->num_entries; i++)
len += scnprintf(buf + len, size - len, "%pM\t%pM\t0x%x\n",
entry->mpp[i].dest_mac_addr,
entry->mpp[i].mesh_dest_mac, entry->mpp[i].flags);
kfree(entry);
}
return len;
}
static int ath11k_nss_dump_mpp_open(struct inode *inode, struct file *file)
{
struct ath11k_vif *arvif = inode->i_private;
struct ath11k *ar = arvif->ar;
unsigned long time_left;
struct ath11k_nss_dbg_priv_data *priv_data;
int ret;
ssize_t size = 100;
char *buf;
reinit_completion(&arvif->nss.dump_mpp_complete);
priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
if (!priv_data)
return -ENOMEM;
mutex_lock(&ar->conf_mutex);
priv_data->arvif = arvif;
ret = ath11k_nss_dump_mpp_request(arvif);
if (ret) {
ath11k_warn(ar->ab, "failed to send dump mpp command %d\n", ret);
goto err_unlock;
}
time_left = wait_for_completion_timeout(&arvif->nss.dump_mpp_complete,
ATH11K_NSS_MPATH_DUMP_TIMEOUT);
if (time_left == 0) {
ret = -ETIMEDOUT;
goto err_unlock;
}
mutex_unlock(&ar->conf_mutex);
size += (arvif->nss.mpp_dump_num_entries * 200 + 10 * 100);
buf = kmalloc(size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
priv_data->buf = buf;
priv_data->len= debug_nss_fill_mpp_dump(arvif, buf, size);
file->private_data = priv_data;
return 0;
err_unlock:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static int ath11k_nss_dump_mpp_release(struct inode *inode, struct file *file)
{
struct ath11k_nss_dbg_priv_data *priv_data = file->private_data;
kfree(priv_data->buf);
kfree(priv_data);
return 0;
}
static ssize_t ath11k_nss_dump_mpp_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_nss_dbg_priv_data *priv_data = file->private_data;
struct ath11k_vif *arvif = priv_data->arvif;
char *buf = priv_data->buf;
struct ath11k *ar = arvif->ar;
int ret;
mutex_lock(&ar->conf_mutex);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, priv_data->len);
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_nss_dump_mpp_table = {
.open = ath11k_nss_dump_mpp_open,
.read = ath11k_nss_dump_mpp_read,
.release = ath11k_nss_dump_mpp_release,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static unsigned int
debug_nss_fill_mpath_dump(struct ath11k_vif *arvif, char *buf, ssize_t size)
{
struct arvif_nss *nss = &arvif->nss;
struct ath11k *ar = arvif->ar;
struct ath11k_nss_mpath_entry *entry, *tmp;
LIST_HEAD(local_entry);
unsigned int len = 0;
u64 expiry_time;
int i;
len += scnprintf(buf + len, size - len, "\nmpath table\n");
len += scnprintf(buf + len, size - len, "dest_mac_addr\t\tnext_hop_mac\t\tmetric\t"
"expiry_time\thop_count\tflags\tlink_vap_id\n");
spin_lock_bh(&ar->nss.dump_lock);
list_splice_tail(&nss->mpath_dump, &local_entry);
spin_unlock_bh(&ar->nss.dump_lock);
list_for_each_entry_safe(entry, tmp, &local_entry, list) {
for (i = 0; i < entry->num_entries; i++) {
memcpy(&expiry_time, entry->mpath[i].expiry_time, sizeof(u64));
len += scnprintf(buf + len, size - len, "%pM\t%pM\t%u\t%llu\t\t\t%d\t0x%x\t%d\n",
entry->mpath[i].dest_mac_addr,
entry->mpath[i].next_hop_mac_addr, entry->mpath[i].metric,
expiry_time, entry->mpath[i].hop_count,
entry->mpath[i].flags, entry->mpath[i].link_vap_id);
}
kfree(entry);
}
return len;
}
static int ath11k_nss_dump_mpath_open(struct inode *inode, struct file *file)
{
struct ath11k_vif *arvif = inode->i_private;
struct ath11k *ar = arvif->ar;
unsigned long time_left;
struct ath11k_nss_dbg_priv_data *priv_data;
ssize_t size = 200;
char *buf;
int ret;
reinit_completion(&arvif->nss.dump_mpath_complete);
priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
if (!priv_data)
return -ENOMEM;
mutex_lock(&ar->conf_mutex);
priv_data->arvif = arvif;
ret = ath11k_nss_dump_mpath_request(arvif);
if (ret) {
ath11k_warn(ar->ab, "failed to send dump mpath command %d\n", ret);
goto err_unlock;
}
time_left = wait_for_completion_timeout(&arvif->nss.dump_mpath_complete,
ATH11K_NSS_MPATH_DUMP_TIMEOUT);
if (time_left == 0) {
ret = -ETIMEDOUT;
goto err_unlock;
}
mutex_unlock(&ar->conf_mutex);
size += (arvif->nss.mpath_dump_num_entries * 200 + 10 * 100);
buf = kmalloc(size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
priv_data->buf = buf;
priv_data->len = debug_nss_fill_mpath_dump(arvif, buf, size);
file->private_data = priv_data;
return 0;
err_unlock:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static int ath11k_nss_dump_mpath_release(struct inode *inode, struct file *file)
{
struct ath11k_nss_dbg_priv_data *priv_data = file->private_data;
kfree(priv_data->buf);
kfree(priv_data);
return 0;
}
static ssize_t ath11k_nss_dump_mpath_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_nss_dbg_priv_data *priv_data = file->private_data;
struct ath11k_vif *arvif = priv_data->arvif;
char *buf = priv_data->buf;
struct ath11k *ar = arvif->ar;
int ret;
mutex_lock(&ar->conf_mutex);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, priv_data->len);
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_nss_dump_mpath_table = {
.open = ath11k_nss_dump_mpath_open,
.read = ath11k_nss_dump_mpath_read,
.release = ath11k_nss_dump_mpath_release,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_mesh_obj_stats_sync_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ath11k *ar = arvif->ar;
unsigned int size = sizeof(struct nss_wifi_mesh_stats_sync_msg);
unsigned int len = 0;
struct nss_wifi_vdev_stats_sync_msg *stats;
struct nss_wifi_mesh_path_stats *mpstats;
struct nss_wifi_mesh_proxy_path_stats *mppstats;
char *buf;
size = sizeof(struct nss_wifi_mesh_stats_sync_msg) +
((sizeof(struct nss_wifi_mesh_stats_sync_msg) / 4) * 20);
buf = kzalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->nss.dump_lock);
stats = &arvif->nss.mesh_stats;
mpstats = &arvif->nss.mesh_stats.mesh_path_stats;
mppstats = &arvif->nss.mesh_stats.mesh_proxy_path_stats;
len += scnprintf(buf + len, size - len, "\nMesh path stats\n\n");
len += scnprintf(buf + len, size - len, "path alloc failures %d\n",
mpstats->alloc_failures);
len += scnprintf(buf + len, size - len, "max radio count errors %d\n",
mpstats->error_max_radio_count);
len += scnprintf(buf + len, size - len, "invalid interface errors %d\n",
mpstats->invalid_interface_failures);
len += scnprintf(buf + len, size - len, "mpath add success %d\n",
mpstats->add_success);
len += scnprintf(buf + len, size - len, "mpath table full errors %d\n",
mpstats->table_full_errors);
len += scnprintf(buf + len, size - len, "mpath insert errors %d\n",
mpstats->insert_failures);
len += scnprintf(buf + len, size - len, "mpath not found errors %d\n",
mpstats->not_found);
len += scnprintf(buf + len, size - len, "mpath del success %d\n",
mpstats->delete_success);
len += scnprintf(buf + len, size - len, "mpath update success %d\n",
mpstats->update_success);
len += scnprintf(buf + len, size - len, "\nMesh proxy path stats\n\n");
len += scnprintf(buf + len, size - len, "path alloc failures %d\n",
mppstats->alloc_failures);
len += scnprintf(buf + len, size - len, "mpp entry already exists errors %d\n",
mppstats->entry_exist_failures);
len += scnprintf(buf + len, size - len, "mpp add success %d\n",
mppstats->add_success);
len += scnprintf(buf + len, size - len, "mpp table full errors %d\n",
mppstats->table_full_errors);
len += scnprintf(buf + len, size - len, "mpp insert errors %d\n",
mppstats->insert_failures);
len += scnprintf(buf + len, size - len, "mpp not found errors %d\n",
mppstats->not_found);
len += scnprintf(buf + len, size - len, "mpp del success %d\n",
mppstats->delete_success);
len += scnprintf(buf + len, size - len, "mpp update success %d\n",
mppstats->update_success);
len += scnprintf(buf + len, size - len, "mpp lookup success %d\n",
mppstats->lookup_success);
len += scnprintf(buf + len, size - len, "mpp unhashed errors %d\n",
mppstats->unhashed_errors);
len += scnprintf(buf + len, size - len, "mpp delete failures %d\n",
mppstats->delete_failures);
len += scnprintf(buf + len, size - len, "dropped %d\n",
stats->dropped);
len += scnprintf(buf + len, size - len, "tx_enqueue_cnt %d\n",
stats->tx_enqueue_cnt);
len += scnprintf(buf + len, size - len, "tx_enq_fail_cnt %d\n",
stats->tx_enqueue_fail_cnt);
len += scnprintf(buf + len, size - len, "tx_enqueue_bytes %d\n",
stats->tx_enqueue_bytes);
len += scnprintf(buf + len, size - len, "rx_enqueue_cnt %d\n",
stats->rx_enqueue_cnt);
len += scnprintf(buf + len, size - len, "rx_enq_fail_cnt %d\n",
stats->rx_enqueue_fail_cnt);
len += scnprintf(buf + len, size - len, "rx_except_enqueue_cnt %d\n",
stats->rx_except_enqueue_cnt);
len += scnprintf(buf + len, size - len, "rx_enq_fail_cnt %d\n",
stats->rx_except_enqueue_fail_cnt);
len += scnprintf(buf + len, size - len, "rx_enqueue_bytes %d\n",
stats->rx_enqueue_bytes);
len += scnprintf(buf + len, size - len, "tx_rcvd %d\n",
stats->tx_rcvd);
len += scnprintf(buf + len, size - len, "tx_rcvd_bytes %d\n",
stats->tx_rcvd_bytes);
spin_unlock_bh(&ar->nss.dump_lock);
mutex_unlock(&ar->conf_mutex);
kfree(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_nss_mesh_obj_stats_sync = {
.open = simple_open,
.read = ath11k_nss_mesh_obj_stats_sync_read,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_mpath_add(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ieee80211_mesh_path_offld path = {0};
u8 buf[128] = {0};
int ret;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%u %hhu %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %hhu %hhu",
&path.metric,
&path.hop_count,
&path.mesh_da[0],
&path.mesh_da[1],
&path.mesh_da[2],
&path.mesh_da[3],
&path.mesh_da[4],
&path.mesh_da[5],
&path.next_hop[0],
&path.next_hop[1],
&path.next_hop[2],
&path.next_hop[3],
&path.next_hop[4],
&path.next_hop[5],
&path.block_mesh_fwd,
&path.metadata_type);
path.flags |= IEEE80211_MESH_PATH_ACTIVE | IEEE80211_MESH_PATH_RESOLVED;
if (ret != 16)
return -EINVAL;
/* Configure the mpath */
ret = ath11k_nss_mesh_config_path(arvif->ar, arvif,
IEEE80211_MESH_PATH_OFFLD_CMD_ADD_MPATH,
&path);
if(ret) {
ath11k_warn(arvif->ar->ab, "failed to configure mpath ret %d\n", ret);
return -EINVAL;
}
return ret ? ret : count;
}
static const struct file_operations fops_nss_mpath_add = {
.open = simple_open,
.write = ath11k_nss_mpath_add,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_mpp_add(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ieee80211_mesh_path_offld path = {0};
u8 buf[128] = {0};
int ret;
if (!arvif->ar->ab->nss.debug_mode) {
ret = -EPERM;
return ret;
}
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&path.da[0],
&path.da[1],
&path.da[2],
&path.da[3],
&path.da[4],
&path.da[5],
&path.mesh_da[0],
&path.mesh_da[1],
&path.mesh_da[2],
&path.mesh_da[3],
&path.mesh_da[4],
&path.mesh_da[5]);
path.flags |= IEEE80211_MESH_PATH_ACTIVE | IEEE80211_MESH_PATH_RESOLVED;
if (ret != 12)
return -EINVAL;
/* Configure the mpp */
ret = ath11k_nss_mesh_config_path(arvif->ar, arvif,
IEEE80211_MESH_PATH_OFFLD_CMD_ADD_MPP,
&path);
if(ret) {
ath11k_warn(arvif->ar->ab, "failed to configure mpp ret %d\n", ret);
return -EINVAL;
}
return ret ? ret : count;
}
static const struct file_operations fops_nss_mpp_add = {
.open = simple_open,
.write = ath11k_nss_mpp_add,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_mpath_update(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ieee80211_mesh_path_offld path = {0};
u8 buf[128] = {0};
int ret;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%u %hhu %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %hhu %lu %hhu %hhu",
&path.metric,
&path.hop_count,
&path.mesh_da[0],
&path.mesh_da[1],
&path.mesh_da[2],
&path.mesh_da[3],
&path.mesh_da[4],
&path.mesh_da[5],
&path.next_hop[0],
&path.next_hop[1],
&path.next_hop[2],
&path.next_hop[3],
&path.next_hop[4],
&path.next_hop[5],
&path.mesh_gate,
&path.exp_time,
&path.block_mesh_fwd,
&path.metadata_type);
path.flags |= IEEE80211_MESH_PATH_ACTIVE | IEEE80211_MESH_PATH_RESOLVED;
if (ret != 18)
return -EINVAL;
/* Configure the mpath */
ret = ath11k_nss_mesh_config_path(arvif->ar, arvif,
IEEE80211_MESH_PATH_OFFLD_CMD_UPDATE_MPATH,
&path);
if(ret) {
ath11k_warn(arvif->ar->ab, "failed to configure mpath ret %d\n", ret);
return -EINVAL;
}
return ret ? ret : count;
}
static const struct file_operations fops_nss_mpath_update = {
.open = simple_open,
.write = ath11k_nss_mpath_update,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_mpp_update(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ieee80211_mesh_path_offld path = {0};
u8 buf[128] = {0};
int ret;
if (!arvif->ar->ab->nss.debug_mode) {
ret = -EPERM;
return ret;
}
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&path.da[0],
&path.da[1],
&path.da[2],
&path.da[3],
&path.da[4],
&path.da[5],
&path.mesh_da[0],
&path.mesh_da[1],
&path.mesh_da[2],
&path.mesh_da[3],
&path.mesh_da[4],
&path.mesh_da[5]);
path.flags |= IEEE80211_MESH_PATH_ACTIVE | IEEE80211_MESH_PATH_RESOLVED;
if (ret != 12)
return -EINVAL;
/* Configure the mpp */
ret = ath11k_nss_mesh_config_path(arvif->ar, arvif,
IEEE80211_MESH_PATH_OFFLD_CMD_UPDATE_MPP,
&path);
if(ret) {
ath11k_warn(arvif->ar->ab, "failed to configure mpp ret %d\n", ret);
return -EINVAL;
}
return ret ? ret : count;
}
static const struct file_operations fops_nss_mpp_update = {
.open = simple_open,
.write = ath11k_nss_mpp_update,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_mpath_delete(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ieee80211_mesh_path_offld path = {0};
u8 buf[128] = {0};
int ret;
if (!arvif->ar->ab->nss.debug_mode) {
ret = -EPERM;
return ret;
}
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&path.mesh_da[0],
&path.mesh_da[1],
&path.mesh_da[2],
&path.mesh_da[3],
&path.mesh_da[4],
&path.mesh_da[5]);
path.flags |= IEEE80211_MESH_PATH_DELETED;
if (ret != 6)
return -EINVAL;
/* Configure the mpath */
ret = ath11k_nss_mesh_config_path(arvif->ar, arvif,
IEEE80211_MESH_PATH_OFFLD_CMD_DELETE_MPATH,
&path);
if(ret) {
ath11k_warn(arvif->ar->ab, "failed to configure mpath ret %d\n", ret);
return -EINVAL;
}
return ret ? ret : count;
}
static const struct file_operations fops_nss_mpath_del = {
.open = simple_open,
.write = ath11k_nss_mpath_delete,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_mpp_delete(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ieee80211_mesh_path_offld path = {0};
u8 buf[128] = {0};
int ret;
if (!arvif->ar->ab->nss.debug_mode) {
ret = -EPERM;
return ret;
}
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&path.da[0],
&path.da[1],
&path.da[2],
&path.da[3],
&path.da[4],
&path.da[5],
&path.mesh_da[0],
&path.mesh_da[1],
&path.mesh_da[2],
&path.mesh_da[3],
&path.mesh_da[4],
&path.mesh_da[5]);
path.flags |= IEEE80211_MESH_PATH_DELETED;
if (ret != 12)
return -EINVAL;
/* Configure the mpp */
ret = ath11k_nss_mesh_config_path(arvif->ar, arvif,
IEEE80211_MESH_PATH_OFFLD_CMD_DELETE_MPP,
&path);
if(ret) {
ath11k_warn(arvif->ar->ab, "failed to configure mpp ret %d\n", ret);
return -EINVAL;
}
return ret ? ret : count;
}
static const struct file_operations fops_nss_mpp_del = {
.open = simple_open,
.write = ath11k_nss_mpp_delete,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_assoc_link(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
u8 buf[128] = {0};
int ret;
u32 assoc_link = 0;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%u", &assoc_link);
if (ret != 1)
return -EINVAL;
arvif->ar->ab->nss.debug_mode = true;
arvif->vif->driver_flags |= IEEE80211_VIF_NSS_OFFLOAD_DEBUG_MODE;
ret = ath11k_nss_assoc_link_arvif_to_ifnum(arvif, assoc_link);
return ret ? ret : count;
}
static const struct file_operations fops_nss_assoc_link = {
.open = simple_open,
.write = ath11k_nss_assoc_link,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_links(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
char buf[512] = {0};
struct arvif_nss *nss;
int len = 0;
list_for_each_entry(nss, &mesh_vaps, list)
len += scnprintf(buf + len, sizeof(buf) - len, "link id %d\n",
nss->if_num);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_nss_links = {
.open = simple_open,
.read = ath11k_nss_links,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_vap_link_id(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct arvif_nss *nss = &arvif->nss;
char buf[512] = {0};
int len = 0;
len = scnprintf(buf, sizeof(buf) - len, "link id %d\n",
nss->if_num);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_nss_vap_link_id = {
.open = simple_open,
.read = ath11k_nss_vap_link_id,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_read_mpp_mode(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
char buf[512] = {0};
int len = 0;
len = scnprintf(buf, sizeof(buf) - len, "%s\n",mpp_mode ?
"Host Assisted Learning" : "NSS Independent Learning");
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath11k_nss_write_mpp_mode(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
u8 buf[128] = {0};
int ret;
u32 mppath_mode = 0;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%u", &mppath_mode);
if (ret != 1)
return -EINVAL;
mpp_mode = mppath_mode;
ret = 0;
return ret ? ret : count;
}
static const struct file_operations fops_nss_mpp_mode = {
.open = simple_open,
.write = ath11k_nss_write_mpp_mode,
.read = ath11k_nss_read_mpp_mode,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_write_excep_flags(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
u8 buf[128] = {0};
int ret;
struct nss_wifi_mesh_exception_flag_msg msg;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %hhu",
&msg.dest_mac_addr[0],
&msg.dest_mac_addr[1],
&msg.dest_mac_addr[2],
&msg.dest_mac_addr[3],
&msg.dest_mac_addr[4],
&msg.dest_mac_addr[5],
&msg.exception);
if (ret != 7)
return -EINVAL;
ret = ath11k_nss_mesh_exception_flags(arvif, &msg);
return ret ? ret : count;
}
static const struct file_operations fops_nss_excep_flags = {
.open = simple_open,
.write = ath11k_nss_write_excep_flags,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_write_metadata_type(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
struct ath11k *ar = arvif->ar;
u8 buf[128] = {0};
int ret;
u8 pkt_type;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%hhu", &pkt_type);
mutex_lock(&ar->conf_mutex);
arvif->nss.metadata_type = pkt_type ? NSS_WIFI_MESH_PRE_HEADER_80211 : NSS_WIFI_MESH_PRE_HEADER_NONE;
mutex_unlock(&ar->conf_mutex);
if (ret != 1)
return -EINVAL;
ret = 0;
return ret ? ret : count;
}
static const struct file_operations fops_nss_metadata_type = {
.open = simple_open,
.write = ath11k_nss_write_metadata_type,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_nss_write_exc_rate_limit(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_vif *arvif = file->private_data;
u8 buf[128] = {0};
int ret;
struct nss_wifi_mesh_rate_limit_config nss_exc_cfg;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
if (ret < 0)
return ret;
buf[ret] = '\0';
ret = sscanf(buf, "%u %u %u",
&nss_exc_cfg.exception_num,
&nss_exc_cfg.enable,
&nss_exc_cfg.rate_limit);
if (ret != 3)
return -EINVAL;
ret = ath11k_nss_exc_rate_config(arvif, &nss_exc_cfg);
return ret ? ret : count;
}
static const struct file_operations fops_nss_exc_rate_limit = {
.open = simple_open,
.write = ath11k_nss_write_exc_rate_limit,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
void ath11k_debugfs_nss_mesh_vap_create(struct ath11k_vif *arvif)
{
struct dentry *debugfs_nss_mesh_dir, *debugfs_dbg_infra;
debugfs_nss_mesh_dir = debugfs_create_dir("nss_mesh", arvif->vif->debugfs_dir);
debugfs_dbg_infra = debugfs_create_dir("dbg_infra", debugfs_nss_mesh_dir);
debugfs_create_file("mesh_obj_nss_stats_sync", 0600,
debugfs_nss_mesh_dir, arvif,
&fops_nss_mesh_obj_stats_sync);
debugfs_create_file("dump_nss_mpath_table", 0600,
debugfs_nss_mesh_dir, arvif,
&fops_nss_dump_mpath_table);
debugfs_create_file("dump_nss_mpp_table", 0600,
debugfs_nss_mesh_dir, arvif,
&fops_nss_dump_mpp_table);
debugfs_create_file("mpath_add", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_mpath_add);
debugfs_create_file("mpath_update", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_mpath_update);
debugfs_create_file("mpath_del", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_mpath_del);
debugfs_create_file("mpp_add", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_mpp_add);
debugfs_create_file("mpp_update", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_mpp_update);
debugfs_create_file("mpp_del", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_mpp_del);
debugfs_create_file("assoc_link", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_assoc_link);
debugfs_create_file("vap_linkid", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_vap_link_id);
debugfs_create_file("excep_flags", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_excep_flags);
debugfs_create_file("metadata_type", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_metadata_type);
debugfs_create_file("exc_rate_limit", 0200,
debugfs_dbg_infra, arvif,
&fops_nss_exc_rate_limit);
}
void ath11k_debugfs_nss_soc_create(struct ath11k_base *ab)
{
if (debugfs_debug_infra)
return;
debugfs_debug_infra = debugfs_create_dir("dbg_infra", debugfs_ath11k);
debugfs_create_file("links", 0200,
debugfs_debug_infra, ab,
&fops_nss_links);
debugfs_create_file("mpp_mode", 0600,
debugfs_debug_infra, ab,
&fops_nss_mpp_mode);
}
#endif