|
5 | 5 |
|
6 | 6 | #include <linux/acpi.h> |
7 | 7 | #include <linux/of.h> |
| 8 | +#include <linux/prctl.h> |
8 | 9 | #include <asm/acpi.h> |
9 | 10 | #include <asm/cacheflush.h> |
10 | 11 |
|
@@ -152,3 +153,115 @@ void __init riscv_init_cbo_blocksizes(void) |
152 | 153 | if (cboz_block_size) |
153 | 154 | riscv_cboz_block_size = cboz_block_size; |
154 | 155 | } |
| 156 | + |
| 157 | +#ifdef CONFIG_SMP |
| 158 | +static void set_icache_stale_mask(void) |
| 159 | +{ |
| 160 | + cpumask_t *mask; |
| 161 | + bool stale_cpu; |
| 162 | + |
| 163 | + /* |
| 164 | + * Mark every other hart's icache as needing a flush for |
| 165 | + * this MM. Maintain the previous value of the current |
| 166 | + * cpu to handle the case when this function is called |
| 167 | + * concurrently on different harts. |
| 168 | + */ |
| 169 | + mask = ¤t->mm->context.icache_stale_mask; |
| 170 | + stale_cpu = cpumask_test_cpu(smp_processor_id(), mask); |
| 171 | + |
| 172 | + cpumask_setall(mask); |
| 173 | + assign_bit(cpumask_check(smp_processor_id()), cpumask_bits(mask), stale_cpu); |
| 174 | +} |
| 175 | +#endif |
| 176 | + |
| 177 | +/** |
| 178 | + * riscv_set_icache_flush_ctx() - Enable/disable icache flushing instructions in |
| 179 | + * userspace. |
| 180 | + * @ctx: Set the type of icache flushing instructions permitted/prohibited in |
| 181 | + * userspace. Supported values described below. |
| 182 | + * |
| 183 | + * Supported values for ctx: |
| 184 | + * |
| 185 | + * * %PR_RISCV_CTX_SW_FENCEI_ON: Allow fence.i in user space. |
| 186 | + * |
| 187 | + * * %PR_RISCV_CTX_SW_FENCEI_OFF: Disallow fence.i in user space. All threads in |
| 188 | + * a process will be affected when ``scope == PR_RISCV_SCOPE_PER_PROCESS``. |
| 189 | + * Therefore, caution must be taken; use this flag only when you can guarantee |
| 190 | + * that no thread in the process will emit fence.i from this point onward. |
| 191 | + * |
| 192 | + * @scope: Set scope of where icache flushing instructions are allowed to be |
| 193 | + * emitted. Supported values described below. |
| 194 | + * |
| 195 | + * Supported values for scope: |
| 196 | + * |
| 197 | + * * %PR_RISCV_SCOPE_PER_PROCESS: Ensure the icache of any thread in this process |
| 198 | + * is coherent with instruction storage upon |
| 199 | + * migration. |
| 200 | + * |
| 201 | + * * %PR_RISCV_SCOPE_PER_THREAD: Ensure the icache of the current thread is |
| 202 | + * coherent with instruction storage upon |
| 203 | + * migration. |
| 204 | + * |
| 205 | + * When ``scope == PR_RISCV_SCOPE_PER_PROCESS``, all threads in the process are |
| 206 | + * permitted to emit icache flushing instructions. Whenever any thread in the |
| 207 | + * process is migrated, the corresponding hart's icache will be guaranteed to be |
| 208 | + * consistent with instruction storage. This does not enforce any guarantees |
| 209 | + * outside of migration. If a thread modifies an instruction that another thread |
| 210 | + * may attempt to execute, the other thread must still emit an icache flushing |
| 211 | + * instruction before attempting to execute the potentially modified |
| 212 | + * instruction. This must be performed by the user-space program. |
| 213 | + * |
| 214 | + * In per-thread context (eg. ``scope == PR_RISCV_SCOPE_PER_THREAD``) only the |
| 215 | + * thread calling this function is permitted to emit icache flushing |
| 216 | + * instructions. When the thread is migrated, the corresponding hart's icache |
| 217 | + * will be guaranteed to be consistent with instruction storage. |
| 218 | + * |
| 219 | + * On kernels configured without SMP, this function is a nop as migrations |
| 220 | + * across harts will not occur. |
| 221 | + */ |
| 222 | +int riscv_set_icache_flush_ctx(unsigned long ctx, unsigned long scope) |
| 223 | +{ |
| 224 | +#ifdef CONFIG_SMP |
| 225 | + switch (ctx) { |
| 226 | + case PR_RISCV_CTX_SW_FENCEI_ON: |
| 227 | + switch (scope) { |
| 228 | + case PR_RISCV_SCOPE_PER_PROCESS: |
| 229 | + current->mm->context.force_icache_flush = true; |
| 230 | + break; |
| 231 | + case PR_RISCV_SCOPE_PER_THREAD: |
| 232 | + current->thread.force_icache_flush = true; |
| 233 | + break; |
| 234 | + default: |
| 235 | + return -EINVAL; |
| 236 | + } |
| 237 | + break; |
| 238 | + case PR_RISCV_CTX_SW_FENCEI_OFF: |
| 239 | + switch (scope) { |
| 240 | + case PR_RISCV_SCOPE_PER_PROCESS: |
| 241 | + current->mm->context.force_icache_flush = false; |
| 242 | + |
| 243 | + set_icache_stale_mask(); |
| 244 | + break; |
| 245 | + case PR_RISCV_SCOPE_PER_THREAD: |
| 246 | + current->thread.force_icache_flush = false; |
| 247 | + |
| 248 | + set_icache_stale_mask(); |
| 249 | + break; |
| 250 | + default: |
| 251 | + return -EINVAL; |
| 252 | + } |
| 253 | + break; |
| 254 | + default: |
| 255 | + return -EINVAL; |
| 256 | + } |
| 257 | + return 0; |
| 258 | +#else |
| 259 | + switch (ctx) { |
| 260 | + case PR_RISCV_CTX_SW_FENCEI_ON: |
| 261 | + case PR_RISCV_CTX_SW_FENCEI_OFF: |
| 262 | + return 0; |
| 263 | + default: |
| 264 | + return -EINVAL; |
| 265 | + } |
| 266 | +#endif |
| 267 | +} |
0 commit comments