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

sw64: modify sys_pfh_ops

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



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

In order to be compatible with new chip which extends each field in
CSR:PFH_CNT, assign a unique id for each field the user may want to
modify, and let the user modify each field individually.

Since this syscall has not been widely used, we will abandon the old
one directly, and assign a new number for this new version.

Only root on host machine is allowed to use this syscall.

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 d23a6be7
Loading
Loading
Loading
Loading
+155 −32
Original line number Diff line number Diff line
@@ -154,53 +154,176 @@ SYSCALL_DEFINE0(sw64_pipe)

#ifdef CONFIG_SUBARCH_C4

struct pfh_val {
	unsigned long pfh_ctl;
	unsigned long pfh_cnt;
};
static void local_set_pfh_ctl(void *info)
{
	unsigned long *kcsr = info;

static void local_set_pfh(void *info)
	sw64_write_csr(*kcsr, CSR_PFH_CTL);
}

static void local_set_pfh_cnt(void *info)
{
	struct pfh_val *kbuf = info;
	unsigned long *kcsr = info;

	if (kbuf->pfh_ctl)
		sw64_write_csr(kbuf->pfh_ctl, CSR_PFH_CTL);
	if (kbuf->pfh_cnt)
		sw64_write_csr(kbuf->pfh_cnt, CSR_PFH_CNT);
	sw64_write_csr(*kcsr, CSR_PFH_CNT);
}

SYSCALL_DEFINE3(pfh_ops, unsigned long, op,
		unsigned long __user *, pfh_ctl_p,
		unsigned long __user *, pfh_cnt_p)
enum pfh_field_id {
	L1_CCNT,
	L1_RCNT,
	L1_MCNT,
	L2_CCNT,
	L2_RCNT,
	L2_MCNT,
	L2_RAMP,
	L3_CCNT,
	L3_RCNT,
	L3_MCNT,
	L3_RAMP,
	L1PFH_EN = 0x10,
	L2PFH_EN,
	L3PFH_EN,
	PFH_FIELD_MAX
};

struct pfh_field {
	unsigned long shift;
	unsigned long mask;
};

struct pfh_field pfh_fields_c4[PFH_FIELD_MAX] = {
	[L1_CCNT] = {0, 0x0f},
	[L1_RCNT] = {4, 0x0f},
	[L1_MCNT] = {8, 0x0f},
	[L2_CCNT] = {12, 0x0f},
	[L2_RCNT] = {16, 0x0f},
	[L2_MCNT] = {20, 0x0f},
	[L2_RAMP] = {24, 0x03},
	[L3_CCNT] = {26, 0x1f},
	[L3_RCNT] = {31, 0x1f},
	[L3_MCNT] = {36, 0x1f},
	[L3_RAMP] = {41, 0x03},
	[L1PFH_EN] = {0, 0x01},
	[L2PFH_EN] = {1, 0x01},
	[L3PFH_EN] = {2, 0x01}
};

struct pfh_field pfh_fields_c4b[PFH_FIELD_MAX] = {
	[L1_CCNT] = {0, 0x3f},
	[L1_RCNT] = {6, 0x3f},
	[L1_MCNT] = {12, 0x3f},
	[L2_CCNT] = {18, 0x3f},
	[L2_RCNT] = {24, 0x3f},
	[L2_MCNT] = {30, 0x3f},
	[L2_RAMP] = {36, 0x03},
	[L3_CCNT] = {38, 0x7f},
	[L3_RCNT] = {45, 0x7f},
	[L3_MCNT] = {52, 0x7f},
	[L3_RAMP] = {59, 0x03},
	[L1PFH_EN] = {0, 0x01},
	[L2PFH_EN] = {1, 0x01},
	[L3PFH_EN] = {2, 0x01}
};

/*
 * id:
 *	0x00: PFH_CNT: L1_CCNT
 *	0x01: PFH_CNT: L1_RCNT
 *	0x02: PFH_CNT: L1_MCNT
 *	0x03: PFH_CNT: L2_CCNT
 *	0x04: PFH_CNT: L2_RCNT
 *	0x05: PFH_CNT: L2_MCNT
 *	0x06: PFH_CNT: L2_RAMP
 *	0x07: PFH_CNT: L3_CCNT
 *	0x08: PFH_CNT: L3_RCNT
 *	0x09: PFH_CNT: L3_MCNT
 *	0x0a: PFH_CNT: L3_RAMP
 *	0x10: PFH_CTL: L1PFH_EN
 *	0x11: PFH_CTL: L2PFH_EN
 *	0x12: PFH_CTL: L3PFH_EN
 * op:	0 for get, 1 for set
 */
SYSCALL_DEFINE3(pfh_ops, unsigned long, id, unsigned long, op,
		unsigned long __user *, buf)
{
	struct pfh_val kbuf = {0, 0};
	unsigned long kcsr = 0;
	unsigned long kbuf = 0;
	unsigned long field_shift;
	unsigned long field_mask;
	unsigned long csr_idx;
	long error = 0;
	struct pfh_field *pfh_fields_arr;

	if (!capable(CAP_SYS_ADMIN))
	if (!is_in_host())
		return -EPERM;

	if (op) {	// op != 0, set
		if (pfh_ctl_p)
			error |= get_user(kbuf.pfh_ctl, pfh_ctl_p);
		if (pfh_cnt_p)
			error |= get_user(kbuf.pfh_cnt, pfh_cnt_p);
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

		if (!error && (kbuf.pfh_ctl || kbuf.pfh_cnt)) {
			smp_call_function(local_set_pfh, &kbuf, 1);
			local_set_pfh(&kbuf);
	switch (id & 0xf0) {
	case 0x00:
		csr_idx = CSR_PFH_CNT;
		break;
	case 0x10:
		csr_idx = CSR_PFH_CTL;
		break;
	default:
		error = -EINVAL;
		goto out;
	}
	} else {	// op == 0, get
		if (pfh_ctl_p) {
			kbuf.pfh_ctl = sw64_read_csr(CSR_PFH_CTL);
			error |= put_user(kbuf.pfh_ctl, pfh_ctl_p);

	if (!is_junzhang_v3())
		pfh_fields_arr = pfh_fields_c4;
	else
		pfh_fields_arr = pfh_fields_c4b;

	field_shift = pfh_fields_arr[id].shift;
	field_mask = pfh_fields_arr[id].mask << field_shift;

	switch (csr_idx) {
	case CSR_PFH_CTL:
		kcsr = sw64_read_csr(CSR_PFH_CTL);
		break;
	case CSR_PFH_CNT:
		kcsr = sw64_read_csr(CSR_PFH_CNT);
		break;
	default:
		/* should never reach here */
		BUG();
	}

		if (pfh_cnt_p) {
			kbuf.pfh_cnt = sw64_read_csr(CSR_PFH_CNT);
			error |= put_user(kbuf.pfh_cnt, pfh_cnt_p);
	switch (op) {
	case 0:		// get
		kbuf = (kcsr & field_mask) >> field_shift;
		error = put_user(kbuf, buf);
		goto out;
	case 1:		// set
		error = get_user(kbuf, buf);
		if (error)
			goto out;
		kcsr = (kcsr & (~field_mask)) |
			((kbuf << field_shift) & field_mask);
		break;
	default:
		error = -EINVAL;
		goto out;
	}

	switch (csr_idx) {
	case CSR_PFH_CTL:
		smp_call_function(local_set_pfh_ctl, &kcsr, 1);
		local_set_pfh_ctl(&kcsr);
		break;
	case CSR_PFH_CNT:
		smp_call_function(local_set_pfh_cnt, &kcsr, 1);
		local_set_pfh_cnt(&kcsr);
		break;
	default:
		/* should never reach here */
		BUG();
	}

out:
	return error;
}

+2 −2
Original line number Diff line number Diff line
@@ -116,8 +116,8 @@
106	common	listen				sys_listen
#107 is unused
#108 is unused
#109 is unused
110	common	pfh_ops				sys_pfh_ops
109	common	pfh_ops				sys_pfh_ops
110	common	old_pfh_ops			sys_ni_syscall
111	common	sigsuspend			sys_sigsuspend
#112 is unused
113	common	recvmsg				sys_recvmsg