blob: d2c40cfbf86e3aa9903fb6470cc24c2b62fa8476 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Mediatek Inc. All Rights Reserved.
*
* Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
*/
#include <linux/debugfs.h>
#include <linux/inet.h>
#include <linux/uaccess.h>
#include "tops/debugfs.h"
#include "tops/firmware.h"
#include "tops/internal.h"
#include "tops/mcu.h"
#include "tops/trm.h"
#include "tops/tunnel.h"
#include "tops/wdt.h"
static const char *tops_role_name[__TOPS_ROLE_TYPE_MAX] = {
[TOPS_ROLE_TYPE_MGMT] = "tops-mgmt",
[TOPS_ROLE_TYPE_CLUSTER] = "tops-offload",
};
static struct dentry *tops_fw_debugfs_root;
static int tops_fw_info_show(struct seq_file *s, void *private)
{
enum tops_role_type rtype;
struct tm tm = {0};
const char *value;
const char *prop;
u32 nattr;
u32 i;
for (rtype = TOPS_ROLE_TYPE_MGMT; rtype < __TOPS_ROLE_TYPE_MAX; rtype++) {
mtk_tops_fw_get_built_date(rtype, &tm);
seq_printf(s, "%s FW information:\n", tops_role_name[rtype]);
seq_printf(s, "Git revision:\t%llx\n",
mtk_tops_fw_get_git_commit_id(rtype));
seq_printf(s, "Build date:\t%04ld/%02d/%02d %02d:%02d:%02d\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
nattr = mtk_tops_fw_attr_get_num(rtype);
for (i = 0; i < nattr; i++) {
prop = mtk_tops_fw_attr_get_property(rtype, i);
if (!prop)
continue;
value = mtk_tops_fw_attr_get_value(rtype, prop);
seq_printf(s, "%s:\t%s\n", prop, value);
}
seq_puts(s, "\n");
}
return 0;
}
static int tops_tnl_show(struct seq_file *s, void *private)
{
struct tops_tnl_info *tnl_info;
struct tops_tnl_params *tnl_params;
u32 i;
for (i = 0; i < CONFIG_TOPS_TNL_NUM; i++) {
tnl_info = mtk_tops_tnl_info_get_by_idx(i);
if (IS_ERR(tnl_info))
/* tunnel not enabled */
continue;
tnl_params = &tnl_info->tnl_params;
if (!tnl_info->tnl_type || !tnl_info->tnl_type->tnl_param_dump)
continue;
seq_printf(s, "Tunnel Index: %02u\n", i);
mtk_tops_mac_param_dump(s, &tnl_params->params);
mtk_tops_network_param_dump(s, &tnl_params->params);
mtk_tops_transport_param_dump(s, &tnl_params->params);
tnl_info->tnl_type->tnl_param_dump(s, &tnl_params->params);
seq_printf(s, "\tTOPS Entry: %02u CLS Entry: %02u CDRT: %02u Flag: 0x%x\n",
tnl_params->tops_entry_proto,
tnl_params->cls_entry,
tnl_params->cdrt,
tnl_params->flag);
}
return 0;
}
static int tops_tnl_open(struct inode *inode, struct file *file)
{
return single_open(file, tops_tnl_show, file->private_data);
}
static int tops_tnl_add_new_tnl(const char *buf)
{
struct tops_tnl_params tnl_params;
struct tops_params *params;
struct tops_tnl_info *tnl_info;
struct tops_tnl_type *tnl_type;
char proto[DEBUG_PROTO_LEN];
int ofs = 0;
int ret = 0;
memset(&tnl_params, 0, sizeof(struct tops_tnl_params));
memset(proto, 0, sizeof(proto));
params = &tnl_params.params;
ret = mtk_tops_debug_param_setup(buf, &ofs, params);
if (ret)
return ret;
ret = mtk_tops_debug_param_proto_peek(buf, ofs, proto);
if (ret < 0)
return ret;
ofs += ret;
tnl_type = mtk_tops_tnl_type_get_by_name(proto);
if (!tnl_type || !tnl_type->tnl_debug_param_setup)
return -ENODEV;
ret = tnl_type->tnl_debug_param_setup(buf, &ofs, params);
if (ret < 0)
return ret;
tnl_params.flag |= TNL_DECAP_ENABLE;
tnl_params.flag |= TNL_ENCAP_ENABLE;
tnl_params.tops_entry_proto = tnl_type->tnl_proto_type;
tnl_info = mtk_tops_tnl_info_alloc(tnl_type);
if (IS_ERR(tnl_info))
return -ENOMEM;
tnl_info->flag |= TNL_INFO_DEBUG;
memcpy(&tnl_info->cache, &tnl_params, sizeof(struct tops_tnl_params));
mtk_tops_tnl_info_hash(tnl_info);
mtk_tops_tnl_info_submit(tnl_info);
return 0;
}
static ssize_t tops_tnl_write(struct file *file, const char __user *buffer,
size_t count, loff_t *data)
{
char cmd[21] = {0};
char buf[512];
int nchar = 0;
int ret = 0;
if (count > sizeof(buf))
return -ENOMEM;
if (copy_from_user(buf, buffer, count))
return -EFAULT;
buf[count] = '\0';
ret = sscanf(buf, "%20s %n", cmd, &nchar);
if (ret != 1)
return -EPERM;
if (!strcmp(cmd, "NEW_TNL")) {
ret = tops_tnl_add_new_tnl(buf + nchar);
if (ret)
return ret;
} else {
return -EINVAL;
}
return count;
}
DEFINE_SHOW_ATTRIBUTE(tops_fw_info);
static const struct file_operations tops_tnl_fops = {
.open = tops_tnl_open,
.read = seq_read,
.write = tops_tnl_write,
.llseek = seq_lseek,
.release = single_release,
};
int mtk_tops_debugfs_init(struct platform_device *pdev)
{
tops_fw_debugfs_root = debugfs_create_dir("fw", tops_debugfs_root);
debugfs_create_file("firmware_info", 0400, tops_fw_debugfs_root, NULL,
&tops_fw_info_fops);
debugfs_create_file("tunnel", 0444, tops_fw_debugfs_root, NULL,
&tops_tnl_fops);
return 0;
}
void mtk_tops_debugfs_deinit(struct platform_device *pdev)
{
debugfs_remove_recursive(tops_fw_debugfs_root);
}