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