Commit f4d37cfb authored by Mao Minkai's avatar Mao Minkai Committed by guzitao
Browse files

sw64: add hardware match support

Sunway inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8Y8CY



--------------------------------

Add hardware match mechanism for SW64.

Signed-off-by: default avatarMao Minkai <maominkai@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent f2156ef3
Loading
Loading
Loading
Loading
+551 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/uaccess.h>

#include <asm/sw64io.h>
#include <asm/debug.h>
#include <asm/csr.h>


char da_match_buf[1024], dv_match_buf[1024], dav_match_buf[1024];
char ia_match_buf[1024], iv_match_buf[1024], ida_match_buf[1024];

unsigned long da_match_cf1, da_match_cf2, da_match_cf3;
unsigned long dv_match_cf1, dv_match_cf2, dv_match_cf3;
unsigned long dav_match_cf1, dav_match_cf2, dav_match_cf3,
	      dav_match_cf4, dav_match_cf5;
unsigned long ia_match_cf1, ia_match_cf2, ia_match_cf3, ia_match_cf4;
unsigned long iv_match_cf1, iv_match_cf2;
unsigned long ida_match_cf1, ida_match_cf2;

static int da_match_show(struct seq_file *m, void *v)
{

	seq_printf(m, "%s", da_match_buf);
	return 0;
}

static int dv_match_show(struct seq_file *m, void *v)
{

	seq_printf(m, "%s", dv_match_buf);
	return 0;
}

static int dav_match_show(struct seq_file *m, void *v)
{

	seq_printf(m, "%s", dav_match_buf);
	return 0;
}

static int ia_match_show(struct seq_file *m, void *v)
{

	seq_printf(m, "%s", ia_match_buf);
	return 0;
}

static int iv_match_show(struct seq_file *m, void *v)
{

	seq_printf(m, "%s", iv_match_buf);
	return 0;
}

static int ida_match_show(struct seq_file *m, void *v)
{

	seq_printf(m, "%s", ida_match_buf);
	return 0;
}

static int da_match_open(struct inode *inode, struct file *file)
{
	return single_open(file, da_match_show, NULL);
}

static int dv_match_open(struct inode *inode, struct file *file)
{
	return single_open(file, dv_match_show, NULL);
}

static int dav_match_open(struct inode *inode, struct file *file)
{
	return single_open(file, dav_match_show, NULL);
}

static int ia_match_open(struct inode *inode, struct file *file)
{
	return single_open(file, ia_match_show, NULL);
}

static int iv_match_open(struct inode *inode, struct file *file)
{
	return single_open(file, iv_match_show, NULL);
}

static int ida_match_open(struct inode *inode, struct file *file)
{
	return single_open(file, ida_match_show, NULL);
}

static void
write_da_match(void *i)
{
	unsigned long dc_ctl;

	write_csr(da_match_cf1, CSR_DA_MATCH);
	write_csr(da_match_cf2, CSR_DA_MASK);
	dc_ctl = read_csr(CSR_DC_CTLP);
	dc_ctl &= ~((0x1UL << 3) | (0x3UL << DA_MATCH_EN_S)
			| (0x1UL << DAV_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S)
			| (0x3UL << DPM_MATCH));
	dc_ctl |= da_match_cf3;
	write_csr(dc_ctl, CSR_DC_CTLP);
}

static void
write_dv_match(void *i)
{
	unsigned long dc_ctl;

	write_csr(dv_match_cf1, CSR_DV_MATCH);
	write_csr(dv_match_cf2, CSR_DV_MASK);
	dc_ctl = read_csr(CSR_DC_CTLP);
	dc_ctl &= ~((0x1UL << DAV_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S)
			| (0x3UL << DPM_MATCH));
	dc_ctl |= ((0x1UL << DV_MATCH_EN_S) | dv_match_cf3);
	write_csr(dc_ctl, CSR_DC_CTLP);
}

static void
write_dav_match(void *i)
{
	unsigned long dc_ctl;

	write_csr(dav_match_cf1, CSR_DA_MATCH);
	write_csr(dav_match_cf2, CSR_DA_MASK);
	write_csr(dav_match_cf3, CSR_DV_MATCH);
	write_csr(dav_match_cf4, CSR_DV_MASK);
	dc_ctl = read_csr(CSR_DC_CTLP);
	dc_ctl &= ~((0x1UL << 3) | (0x3UL << DA_MATCH_EN_S)
			| (0x1UL << DPM_MATCH_EN_S) | (0x3UL << DPM_MATCH));
	dc_ctl |= ((0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S)
			| dav_match_cf5);
	write_csr(dc_ctl, CSR_DC_CTLP);
}

static void
write_ia_match(void *i)
{
	ia_match_cf1 |= (0x1UL << IA_MATCH_EN_S);
	write_csr_imb(ia_match_cf1, CSR_IA_MATCH);
	write_csr_imb(ia_match_cf2, CSR_IA_MASK);
	write_csr(((0x3ffUL << 18) | ia_match_cf3), CSR_IA_VPNMATCH);
	write_csr(((0x3ffUL << 18) | ia_match_cf4), CSR_IA_UPNMATCH);
}

static void
write_iv_match(void *i)
{
	unsigned long ia_match_tmp;

	ia_match_tmp = read_csr(CSR_IA_MATCH);
	ia_match_tmp &= ~(0x1UL << IV_PM_EN_S);
	ia_match_tmp |= ((((iv_match_cf2 >> IV_PM_EN_S) & 0x1) << IV_PM_EN_S)
			| (iv_match_cf2 & 0x3) | (0x1UL << IV_MATCH_EN_S));
	write_csr_imb(iv_match_cf1, CSR_IV_MATCH);
	write_csr_imb(ia_match_tmp, CSR_IA_MATCH);
}

static void
write_ida_match(void *i)
{

	ida_match_cf1 |= (0x1UL << IDA_MATCH_EN_S);
	write_csr(ida_match_cf1, CSR_IDA_MATCH);
	write_csr(ida_match_cf2, CSR_IDA_MASK);
}

static ssize_t da_match_set(struct file *file, const char __user *user_buf,
			size_t len, loff_t *ppos)
{
	size_t size;
	char tmp[400];
	char *p;
	int i, m;
	const char *sep = " ";
	char tmp1[400];
	int err;
	char *ret = NULL;

	size = min(sizeof(da_match_buf) - 1, len);
	if (copy_from_user(da_match_buf, user_buf, size))
		return -EFAULT;

	da_match_buf[size] = '\0';
	strcpy(tmp, da_match_buf);
	p = tmp;

	for (i = 0 ; i < 4; i++) {
		m = i*100;
		ret = strsep(&p, sep);
		if (ret != NULL)
			strcpy(&tmp1[m], ret);

	}
	tmp1[400] = '\0';

	err = kstrtoul(&tmp1[0], 0, &da_match_cf1);
	if (err)
		return err;

	err = kstrtoul(&tmp1[100], 0, &da_match_cf2);
	if (err)
		return err;

	err = kstrtoul(&tmp1[200], 0, &da_match_cf3);
	if (err)
		return err;

	if (on_each_cpu(write_da_match, NULL, 1))
		pr_crit("%s: timed out\n", __func__);

	return len;
}

static ssize_t dv_match_set(struct file *file, const char __user *user_buf,
			size_t len, loff_t *ppos)
{
	size_t size;
	char tmp[400];
	char *p;
	int i, m;
	const char *sep = " ";
	char tmp1[400];
	int err;
	char *ret = NULL;

	size = min(sizeof(dv_match_buf) - 1, len);
	if (copy_from_user(dv_match_buf, user_buf, size))
		return -EFAULT;

	dv_match_buf[size] = '\0';
	strcpy(tmp, dv_match_buf);
	p = tmp;

	for (i = 0 ; i < 4; i++) {
		m = i*100;
		ret = strsep(&p, sep);
		if (ret != NULL)
			strcpy(&tmp1[m], ret);

	}
	tmp1[400] = '\0';

	err = kstrtoul(&tmp1[0], 0, &dv_match_cf1);
	if (err)
		return err;

	err = kstrtoul(&tmp1[100], 0, &dv_match_cf2);
	if (err)
		return err;

	err = kstrtoul(&tmp1[200], 0, &dv_match_cf3);
	if (err)
		return err;

	if (on_each_cpu(write_dv_match, NULL, 1))
		pr_crit("%s: timed out\n", __func__);

	return len;
}

static ssize_t dav_match_set(struct file *file, const char __user *user_buf,
			size_t len, loff_t *ppos)
{
	size_t size;
	char tmp[500];
	char *p;
	int i, m;
	const char *sep = " ";
	char tmp1[500];
	int err;
	char *ret = NULL;

	size = min(sizeof(dav_match_buf) - 1, len);
	if (copy_from_user(dav_match_buf, user_buf, size))
		return -EFAULT;

	dav_match_buf[size] = '\0';
	strcpy(tmp, dav_match_buf);
	p = tmp;

	for (i = 0 ; i < 5; i++) {
		m = i*100;
		ret = strsep(&p, sep);
		if (ret != NULL)
			strcpy(&tmp1[m], ret);

	}
	tmp1[500] = '\0';

	err = kstrtoul(&tmp1[0], 0, &dav_match_cf1);
	if (err)
		return err;

	err = kstrtoul(&tmp1[100], 0, &dav_match_cf2);
	if (err)
		return err;

	err = kstrtoul(&tmp1[200], 0, &dav_match_cf3);
	if (err)
		return err;

	err = kstrtoul(&tmp1[300], 0, &dav_match_cf4);
	if (err)
		return err;

	err = kstrtoul(&tmp1[400], 0, &dav_match_cf5);
	if (err)
		return err;


	if (on_each_cpu(write_dav_match, NULL, 1))
		pr_crit("%s: timed out\n", __func__);
	return len;
}

static ssize_t ia_match_set(struct file *file, const char __user *user_buf,
			size_t len, loff_t *ppos)
{
	size_t size;
	char tmp[400];
	char *p;
	int i, m;
	const char *sep = " ";
	char tmp1[400];
	int err;
	char *ret = NULL;

	size = min(sizeof(ia_match_buf) - 1, len);
	if (copy_from_user(ia_match_buf, user_buf, size))
		return -EFAULT;

	ia_match_buf[size] = '\0';
	strcpy(tmp, ia_match_buf);
	p = tmp;

	for (i = 0 ; i < 4; i++) {
		m = i*100;
		ret = strsep(&p, sep);
		if (ret != NULL)
			strcpy(&tmp1[m], ret);

	}
	tmp1[400] = '\0';

	err = kstrtoul(&tmp1[0], 0, &ia_match_cf1);
	if (err)
		return err;

	err = kstrtoul(&tmp1[100], 0, &ia_match_cf2);
	if (err)
		return err;

	err = kstrtoul(&tmp1[200], 0, &ia_match_cf3);
	if (err)
		return err;

	err = kstrtoul(&tmp1[300], 0, &ia_match_cf4);
	if (err)
		return err;

	if (on_each_cpu(write_ia_match, NULL, 1))
		pr_crit("%s: timed out\n", __func__);
	return len;
}

static ssize_t iv_match_set(struct file *file, const char __user *user_buf,
			size_t len, loff_t *ppos)
{
	size_t size;
	char tmp[400];
	char *p;
	int i, m;
	const char *sep = " ";
	char tmp1[400];
	int err;
	char *ret = NULL;

	size = min(sizeof(ia_match_buf) - 1, len);
	if (copy_from_user(ia_match_buf, user_buf, size))
		return -EFAULT;

	ia_match_buf[size] = '\0';
	strcpy(tmp, ia_match_buf);
	p = tmp;

	for (i = 0 ; i < 4; i++) {
		m = i*100;
		ret = strsep(&p, sep);
		if (ret != NULL)
			strcpy(&tmp1[m], ret);

	}
	tmp1[400] = '\0';

	err = kstrtoul(&tmp1[0], 0, &iv_match_cf1);
	if (err)
		return err;

	err = kstrtoul(&tmp1[100], 0, &iv_match_cf2);
	if (err)
		return err;

	if (on_each_cpu(write_iv_match, NULL, 1))
		pr_crit("%s: timed out\n", __func__);
	return len;
}


static ssize_t ida_match_set(struct file *file, const char __user *user_buf,
			size_t len, loff_t *ppos)
{
	size_t size;
	char tmp[400];
	char *p;
	int i, m;
	const char *sep = " ";
	char tmp1[400];
	int err;
	char *ret = NULL;

	size = min(sizeof(ida_match_buf) - 1, len);
	if (copy_from_user(ida_match_buf, user_buf, size))
		return -EFAULT;

	ida_match_buf[size] = '\0';
	strcpy(tmp, ida_match_buf);
	p = tmp;

	for (i = 0 ; i < 4; i++) {
		m = i*100;
		ret = strsep(&p, sep);
		if (ret != NULL)
			strcpy(&tmp1[m], ret);
	}
	tmp1[400] = '\0';

	err = kstrtoul(&tmp1[0], 0, &ida_match_cf1);
	if (err)
		return err;

	err = kstrtoul(&tmp1[100], 0, &ida_match_cf2);
	if (err)
		return err;

	if (on_each_cpu(write_ida_match, NULL, 1))
		pr_crit("%s: timed out\n", __func__);

	return len;
}

static const struct file_operations set_da_match_fops = {
	.open		= da_match_open,
	.read		= seq_read,
	.write		= da_match_set,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static const struct file_operations set_dv_match_fops = {
	.open		= dv_match_open,
	.read		= seq_read,
	.write		= dv_match_set,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static const struct file_operations set_dav_match_fops = {
	.open		= dav_match_open,
	.read		= seq_read,
	.write		= dav_match_set,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static const struct file_operations set_ia_match_fops = {
	.open		= ia_match_open,
	.read		= seq_read,
	.write		= ia_match_set,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static const struct file_operations set_iv_match_fops = {
	.open		= iv_match_open,
	.read		= seq_read,
	.write		= iv_match_set,
	.llseek		= seq_lseek,
	.release	= single_release,
};


static const struct file_operations set_ida_match_fops = {
	.open		= ida_match_open,
	.read		= seq_read,
	.write		= ida_match_set,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static int __init match_debugfs_init(void)
{
	struct dentry *match_entry;

	if (!sw64_debugfs_dir)
		return -ENODEV;

	match_entry = debugfs_create_file("da_match", 0600,
					sw64_debugfs_dir, NULL,
					&set_da_match_fops);
	if (!match_entry)
		return -ENOMEM;

	match_entry = debugfs_create_file("dv_match", 0600,
					sw64_debugfs_dir, NULL,
					&set_dv_match_fops);
	if (!match_entry)
		return -ENOMEM;

	match_entry = debugfs_create_file("dav_match", 0600,
					sw64_debugfs_dir, NULL,
					&set_dav_match_fops);
	if (!match_entry)
		return -ENOMEM;

	match_entry = debugfs_create_file("ia_match", 0600,
					sw64_debugfs_dir, NULL,
					&set_ia_match_fops);
	if (!match_entry)
		return -ENOMEM;

	match_entry = debugfs_create_file("iv_match", 0600,
					sw64_debugfs_dir, NULL,
					&set_iv_match_fops);
	if (!match_entry)
		return -ENOMEM;

	match_entry = debugfs_create_file("ida_match", 0600,
					sw64_debugfs_dir, NULL,
					&set_ida_match_fops);
	if (!match_entry)
		return -ENOMEM;

	return 0;
}
late_initcall(match_debugfs_init);