blob: e425e6879a1cf4d307240c37b866ffc754945c23 [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/device.h>
#include "firmware.h"
#include "hpdma.h"
#include "internal.h"
#include "mcu.h"
#include "netsys.h"
#include "trm.h"
#include "tunnel.h"
#include "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 ssize_t mtk_tops_fw_info_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
enum tops_role_type rtype;
struct tm tm = {0};
const char *value;
const char *prop;
int len = 0;
u32 nattr;
u32 i;
for (rtype = TOPS_ROLE_TYPE_MGMT; rtype < __TOPS_ROLE_TYPE_MAX; rtype++) {
mtk_tops_fw_get_built_date(rtype, &tm);
len += snprintf(buf + len, PAGE_SIZE - len,
"%s FW information:\n", tops_role_name[rtype]);
len += snprintf(buf + len, PAGE_SIZE - len,
"Git revision:\t%llx\n",
mtk_tops_fw_get_git_commit_id(rtype));
len += snprintf(buf + len, PAGE_SIZE - len,
"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);
len += snprintf(buf + len, PAGE_SIZE - len,
"%s:\t%s\n", prop, value);
}
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
}
return len;
}
static int mtk_tops_ctrl_fetch_port(const char *buf, int *ofs, u16 *port)
{
int nchar = 0;
int ret;
u16 p = 0;
ret = sscanf(buf + *ofs, "%hu %n", &p, &nchar);
if (ret != 1)
return -EPERM;
*port = htons(p);
*ofs += nchar;
return nchar;
}
static int mtk_tops_ctrl_fetch_ip(const char *buf, int *ofs, u32 *ip)
{
int nchar = 0;
int ret = 0;
u8 tmp[4];
ret = sscanf(buf + *ofs, "%hhu.%hhu.%hhu.%hhu %n",
&tmp[3], &tmp[2], &tmp[1], &tmp[0], &nchar);
if (ret != 4)
return -EPERM;
*ip = tmp[0] | tmp[1] << 8 | tmp[2] << 16 | tmp[3] << 24;
*ofs += nchar;
return nchar;
}
static int mtk_tops_ctrl_fetch_mac(const char *buf, int *ofs, u8 *mac)
{
int nchar = 0;
int ret = 0;
ret = sscanf(buf + *ofs, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %n",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], &nchar);
if (ret != 6)
return -EPERM;
*ofs += nchar;
return 0;
}
static int mtk_tops_ctrl_add_tnl(const char *buf)
{
struct tops_tnl_params tnl_params = {0};
struct tops_tnl_info *tnl_info;
struct tops_tnl_type *tnl_type;
char tnl_type_name[21] = {0};
int ofs = 0;
int ret = 0;
ret = sscanf(buf, "%20s %n", tnl_type_name, &ofs);
if (ret != 1)
return -EPERM;
tnl_type = mtk_tops_tnl_type_get_by_name(tnl_type_name);
if (unlikely(!tnl_type || !tnl_type->tnl_debug_param_setup))
return -ENODEV;
ret = mtk_tops_ctrl_fetch_mac(buf, &ofs, tnl_params.daddr);
if (ret < 0)
return ret;
ret = mtk_tops_ctrl_fetch_mac(buf, &ofs, tnl_params.saddr);
if (ret < 0)
return ret;
ret = mtk_tops_ctrl_fetch_ip(buf, &ofs, &tnl_params.dip);
if (ret < 0)
return ret;
ret = mtk_tops_ctrl_fetch_ip(buf, &ofs, &tnl_params.sip);
if (ret < 0)
return ret;
ret = mtk_tops_ctrl_fetch_port(buf, &ofs, &tnl_params.dport);
if (ret < 0)
return ret;
ret = mtk_tops_ctrl_fetch_port(buf, &ofs, &tnl_params.sport);
if (ret < 0)
return ret;
ret = tnl_type->tnl_debug_param_setup(buf, &ofs, &tnl_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->tops_entry;
tnl_info = mtk_tops_tnl_info_alloc();
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 mtk_tops_tnl_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
char cmd[21] = {0};
int nchar = 0;
int ret = 0;
ret = sscanf(buf, "%20s %n", cmd, &nchar);
if (ret != 1)
return -EPERM;
if (!strcmp(cmd, "NEW_TNL")) {
ret = mtk_tops_ctrl_add_tnl(buf + nchar);
if (ret)
return ret;
}
return count;
}
static int mtk_tops_trm_fetch_setting(const char *buf,
int *ofs,
char *name,
u32 *offset,
u32 *size,
u8 *enable)
{
int nchar = 0;
int ret = 0;
ret = sscanf(buf + *ofs, "%31s %x %x %hhx %n",
name, offset, size, enable, &nchar);
if (ret != 4)
return -EPERM;
*ofs += nchar;
return nchar;
}
static ssize_t mtk_tops_trm_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
char name[TRM_CONFIG_NAME_MAX_LEN] = { 0 };
char cmd[21] = { 0 };
int nchar = 0;
int ret = 0;
u32 offset;
u8 enable;
u32 size;
ret = sscanf(buf, "%20s %n", cmd, &nchar);
if (ret != 1)
return -EPERM;
if (!strcmp(cmd, "trm_dump")) {
ret = mtk_trm_dump(TRM_RSN_NULL);
if (ret)
return ret;
} else if (!strcmp(cmd, "trm_cfg_setup")) {
ret = mtk_tops_trm_fetch_setting(buf, &nchar,
name, &offset, &size, &enable);
if (ret < 0)
return ret;
ret = mtk_trm_cfg_setup(name, offset, size, enable);
if (ret)
return ret;
}
return count;
}
static ssize_t mtk_tops_wdt_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
char cmd[21] = {0};
u32 core = 0;
u32 i;
int ret;
ret = sscanf(buf, "%20s %x", cmd, &core);
if (ret != 2)
return -EPERM;
core &= CORE_TOPS_MASK;
if (!strcmp(cmd, "WDT_TO")) {
for (i = 0; i < CORE_TOPS_NUM; i++) {
if (core & 0x1)
mtk_tops_wdt_trigger_timeout(i);
core >>= 1;
}
} else {
return -EINVAL;
}
return count;
}
static DEVICE_ATTR_RO(mtk_tops_fw_info);
static DEVICE_ATTR_WO(mtk_tops_tnl);
static DEVICE_ATTR_WO(mtk_tops_trm);
static DEVICE_ATTR_WO(mtk_tops_wdt);
static struct attribute *mtk_tops_attributes[] = {
&dev_attr_mtk_tops_fw_info.attr,
&dev_attr_mtk_tops_tnl.attr,
&dev_attr_mtk_tops_trm.attr,
&dev_attr_mtk_tops_wdt.attr,
NULL,
};
static const struct attribute_group mtk_tops_attr_group = {
.name = "mtk_tops",
.attrs = mtk_tops_attributes,
};
int mtk_tops_ctrl_init(struct platform_device *pdev)
{
int ret = 0;
ret = sysfs_create_group(&pdev->dev.kobj, &mtk_tops_attr_group);
if (ret) {
TOPS_ERR("create sysfs failed\n");
return ret;
}
return ret;
}
void mtk_tops_ctrl_deinit(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &mtk_tops_attr_group);
}