1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/init.h>
3 #include <linux/export.h>
4 #include <linux/debugfs.h>
5 #include <linux/kstrtox.h>
6 #include <asm/loongarch.h>
7 
8 struct dentry *arch_debugfs_dir;
9 EXPORT_SYMBOL(arch_debugfs_dir);
10 
11 static int sfb_state, tso_state;
12 
set_sfb_state(void * info)13 static void set_sfb_state(void *info)
14 {
15 	int val = *(int *)info << CSR_STFILL_SHIFT;
16 
17 	csr_xchg32(val, CSR_STFILL, LOONGARCH_CSR_IMPCTL1);
18 }
19 
sfb_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)20 static ssize_t sfb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
21 {
22 	int s, state;
23 	char str[32];
24 
25 	state = (csr_read32(LOONGARCH_CSR_IMPCTL1) & CSR_STFILL) >> CSR_STFILL_SHIFT;
26 
27 	s = snprintf(str, sizeof(str), "Boot State: %x\nCurrent State: %x\n", sfb_state, state);
28 
29 	if (*ppos >= s)
30 		return 0;
31 
32 	s -= *ppos;
33 	s = min_t(u32, s, count);
34 
35 	if (copy_to_user(buf, &str[*ppos], s))
36 		return -EFAULT;
37 
38 	*ppos += s;
39 
40 	return s;
41 }
42 
sfb_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)43 static ssize_t sfb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
44 {
45 	int state;
46 
47 	if (kstrtoint_from_user(buf, count, 10, &state))
48 		return -EFAULT;
49 
50 	switch (state) {
51 	case 0: case 1:
52 		on_each_cpu(set_sfb_state, &state, 1);
53 		break;
54 	default:
55 		return -EINVAL;
56 	}
57 
58 	return count;
59 }
60 
61 static const struct file_operations sfb_fops = {
62 	.read = sfb_read,
63 	.write = sfb_write,
64 	.open = simple_open,
65 	.llseek = default_llseek
66 };
67 
68 #define LDSTORDER_NLD_NST        0x0 /* 000 = No Load No Store */
69 #define LDSTORDER_ALD_NST        0x1 /* 001 = All Load No Store */
70 #define LDSTORDER_SLD_NST        0x3 /* 011 = Same Load No Store */
71 #define LDSTORDER_NLD_AST        0x4 /* 100 = No Load All Store */
72 #define LDSTORDER_ALD_AST        0x5 /* 101 = All Load All Store */
73 #define LDSTORDER_SLD_AST        0x7 /* 111 = Same Load All Store */
74 
75 static char *tso_hints[] = {
76 	"No Load No Store",
77 	"All Load No Store",
78 	"Invalid Config",
79 	"Same Load No Store",
80 	"No Load All Store",
81 	"All Load All Store",
82 	"Invalid Config",
83 	"Same Load All Store"
84 };
85 
set_tso_state(void * info)86 static void set_tso_state(void *info)
87 {
88 	int val = *(int *)info << CSR_LDSTORDER_SHIFT;
89 
90 	csr_xchg32(val, CSR_LDSTORDER_MASK, LOONGARCH_CSR_IMPCTL1);
91 }
92 
tso_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)93 static ssize_t tso_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
94 {
95 	int s, state;
96 	char str[240];
97 
98 	state = (csr_read32(LOONGARCH_CSR_IMPCTL1) & CSR_LDSTORDER_MASK) >> CSR_LDSTORDER_SHIFT;
99 
100 	s = snprintf(str, sizeof(str), "Boot State: %d (%s)\n"
101 			               "Current State: %d (%s)\n\n"
102 				       "Available States:\n"
103 				       "0 (%s)\t" "1 (%s)\t" "3 (%s)\n"
104 				       "4 (%s)\t" "5 (%s)\t" "7 (%s)\n",
105 				       tso_state, tso_hints[tso_state], state, tso_hints[state],
106 				       tso_hints[0], tso_hints[1], tso_hints[3], tso_hints[4], tso_hints[5], tso_hints[7]);
107 
108 	if (*ppos >= s)
109 		return 0;
110 
111 	s -= *ppos;
112 	s = min_t(u32, s, count);
113 
114 	if (copy_to_user(buf, &str[*ppos], s))
115 		return -EFAULT;
116 
117 	*ppos += s;
118 
119 	return s;
120 }
121 
tso_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)122 static ssize_t tso_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
123 {
124 	int state;
125 
126 	if (kstrtoint_from_user(buf, count, 10, &state))
127 		return -EFAULT;
128 
129 	switch (state) {
130 	case 0: case 1: case 3:
131 	case 4: case 5: case 7:
132 		on_each_cpu(set_tso_state, &state, 1);
133 		break;
134 	default:
135 		return -EINVAL;
136 	}
137 
138 	return count;
139 }
140 
141 static const struct file_operations tso_fops = {
142 	.read = tso_read,
143 	.write = tso_write,
144 	.open = simple_open,
145 	.llseek = default_llseek
146 };
147 
arch_kdebugfs_init(void)148 static int __init arch_kdebugfs_init(void)
149 {
150 	unsigned int config = read_cpucfg(LOONGARCH_CPUCFG3);
151 
152 	arch_debugfs_dir = debugfs_create_dir("loongarch", NULL);
153 
154 	if (config & CPUCFG3_SFB) {
155 		debugfs_create_file("sfb_state", S_IRUGO | S_IWUSR,
156 			    arch_debugfs_dir, &sfb_state, &sfb_fops);
157 		sfb_state = (csr_read32(LOONGARCH_CSR_IMPCTL1) & CSR_STFILL) >> CSR_STFILL_SHIFT;
158 	}
159 
160 	if (config & (CPUCFG3_ALDORDER_CAP | CPUCFG3_ASTORDER_CAP)) {
161 		debugfs_create_file("tso_state", S_IRUGO | S_IWUSR,
162 			    arch_debugfs_dir, &tso_state, &tso_fops);
163 		tso_state = (csr_read32(LOONGARCH_CSR_IMPCTL1) & CSR_LDSTORDER_MASK) >> CSR_LDSTORDER_SHIFT;
164 	}
165 
166 	return 0;
167 }
168 postcore_initcall(arch_kdebugfs_init);
169