~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/riscv/mm/cacheflush.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2017 SiFive
  4  */
  5 
  6 #include <linux/acpi.h>
  7 #include <linux/of.h>
  8 #include <linux/prctl.h>
  9 #include <asm/acpi.h>
 10 #include <asm/cacheflush.h>
 11 
 12 #ifdef CONFIG_SMP
 13 
 14 #include <asm/sbi.h>
 15 
 16 static void ipi_remote_fence_i(void *info)
 17 {
 18         return local_flush_icache_all();
 19 }
 20 
 21 void flush_icache_all(void)
 22 {
 23         local_flush_icache_all();
 24 
 25         if (num_online_cpus() < 2)
 26                 return;
 27         else if (riscv_use_sbi_for_rfence())
 28                 sbi_remote_fence_i(NULL);
 29         else
 30                 on_each_cpu(ipi_remote_fence_i, NULL, 1);
 31 }
 32 EXPORT_SYMBOL(flush_icache_all);
 33 
 34 /*
 35  * Performs an icache flush for the given MM context.  RISC-V has no direct
 36  * mechanism for instruction cache shoot downs, so instead we send an IPI that
 37  * informs the remote harts they need to flush their local instruction caches.
 38  * To avoid pathologically slow behavior in a common case (a bunch of
 39  * single-hart processes on a many-hart machine, ie 'make -j') we avoid the
 40  * IPIs for harts that are not currently executing a MM context and instead
 41  * schedule a deferred local instruction cache flush to be performed before
 42  * execution resumes on each hart.
 43  */
 44 void flush_icache_mm(struct mm_struct *mm, bool local)
 45 {
 46         unsigned int cpu;
 47         cpumask_t others, *mask;
 48 
 49         preempt_disable();
 50 
 51         /* Mark every hart's icache as needing a flush for this MM. */
 52         mask = &mm->context.icache_stale_mask;
 53         cpumask_setall(mask);
 54         /* Flush this hart's I$ now, and mark it as flushed. */
 55         cpu = smp_processor_id();
 56         cpumask_clear_cpu(cpu, mask);
 57         local_flush_icache_all();
 58 
 59         /*
 60          * Flush the I$ of other harts concurrently executing, and mark them as
 61          * flushed.
 62          */
 63         cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu));
 64         local |= cpumask_empty(&others);
 65         if (mm == current->active_mm && local) {
 66                 /*
 67                  * It's assumed that at least one strongly ordered operation is
 68                  * performed on this hart between setting a hart's cpumask bit
 69                  * and scheduling this MM context on that hart.  Sending an SBI
 70                  * remote message will do this, but in the case where no
 71                  * messages are sent we still need to order this hart's writes
 72                  * with flush_icache_deferred().
 73                  */
 74                 smp_mb();
 75         } else if (riscv_use_sbi_for_rfence()) {
 76                 sbi_remote_fence_i(&others);
 77         } else {
 78                 on_each_cpu_mask(&others, ipi_remote_fence_i, NULL, 1);
 79         }
 80 
 81         preempt_enable();
 82 }
 83 
 84 #endif /* CONFIG_SMP */
 85 
 86 #ifdef CONFIG_MMU
 87 void flush_icache_pte(struct mm_struct *mm, pte_t pte)
 88 {
 89         struct folio *folio = page_folio(pte_page(pte));
 90 
 91         if (!test_bit(PG_dcache_clean, &folio->flags)) {
 92                 flush_icache_mm(mm, false);
 93                 set_bit(PG_dcache_clean, &folio->flags);
 94         }
 95 }
 96 #endif /* CONFIG_MMU */
 97 
 98 unsigned int riscv_cbom_block_size;
 99 EXPORT_SYMBOL_GPL(riscv_cbom_block_size);
100 
101 unsigned int riscv_cboz_block_size;
102 EXPORT_SYMBOL_GPL(riscv_cboz_block_size);
103 
104 static void __init cbo_get_block_size(struct device_node *node,
105                                       const char *name, u32 *block_size,
106                                       unsigned long *first_hartid)
107 {
108         unsigned long hartid;
109         u32 val;
110 
111         if (riscv_of_processor_hartid(node, &hartid))
112                 return;
113 
114         if (of_property_read_u32(node, name, &val))
115                 return;
116 
117         if (!*block_size) {
118                 *block_size = val;
119                 *first_hartid = hartid;
120         } else if (*block_size != val) {
121                 pr_warn("%s mismatched between harts %lu and %lu\n",
122                         name, *first_hartid, hartid);
123         }
124 }
125 
126 void __init riscv_init_cbo_blocksizes(void)
127 {
128         unsigned long cbom_hartid, cboz_hartid;
129         u32 cbom_block_size = 0, cboz_block_size = 0;
130         struct device_node *node;
131         struct acpi_table_header *rhct;
132         acpi_status status;
133 
134         if (acpi_disabled) {
135                 for_each_of_cpu_node(node) {
136                         /* set block-size for cbom and/or cboz extension if available */
137                         cbo_get_block_size(node, "riscv,cbom-block-size",
138                                            &cbom_block_size, &cbom_hartid);
139                         cbo_get_block_size(node, "riscv,cboz-block-size",
140                                            &cboz_block_size, &cboz_hartid);
141                 }
142         } else {
143                 status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct);
144                 if (ACPI_FAILURE(status))
145                         return;
146 
147                 acpi_get_cbo_block_size(rhct, &cbom_block_size, &cboz_block_size, NULL);
148                 acpi_put_table((struct acpi_table_header *)rhct);
149         }
150 
151         if (cbom_block_size)
152                 riscv_cbom_block_size = cbom_block_size;
153 
154         if (cboz_block_size)
155                 riscv_cboz_block_size = cboz_block_size;
156 }
157 
158 #ifdef CONFIG_SMP
159 static void set_icache_stale_mask(void)
160 {
161         int cpu = get_cpu();
162         cpumask_t *mask;
163         bool stale_cpu;
164 
165         /*
166          * Mark every other hart's icache as needing a flush for
167          * this MM. Maintain the previous value of the current
168          * cpu to handle the case when this function is called
169          * concurrently on different harts.
170          */
171         mask = &current->mm->context.icache_stale_mask;
172         stale_cpu = cpumask_test_cpu(cpu, mask);
173 
174         cpumask_setall(mask);
175         cpumask_assign_cpu(cpu, mask, stale_cpu);
176         put_cpu();
177 }
178 #endif
179 
180 /**
181  * riscv_set_icache_flush_ctx() - Enable/disable icache flushing instructions in
182  * userspace.
183  * @ctx: Set the type of icache flushing instructions permitted/prohibited in
184  *       userspace. Supported values described below.
185  *
186  * Supported values for ctx:
187  *
188  * * %PR_RISCV_CTX_SW_FENCEI_ON: Allow fence.i in user space.
189  *
190  * * %PR_RISCV_CTX_SW_FENCEI_OFF: Disallow fence.i in user space. All threads in
191  *   a process will be affected when ``scope == PR_RISCV_SCOPE_PER_PROCESS``.
192  *   Therefore, caution must be taken; use this flag only when you can guarantee
193  *   that no thread in the process will emit fence.i from this point onward.
194  *
195  * @scope: Set scope of where icache flushing instructions are allowed to be
196  *         emitted. Supported values described below.
197  *
198  * Supported values for scope:
199  *
200  * * %PR_RISCV_SCOPE_PER_PROCESS: Ensure the icache of any thread in this process
201  *                               is coherent with instruction storage upon
202  *                               migration.
203  *
204  * * %PR_RISCV_SCOPE_PER_THREAD: Ensure the icache of the current thread is
205  *                              coherent with instruction storage upon
206  *                              migration.
207  *
208  * When ``scope == PR_RISCV_SCOPE_PER_PROCESS``, all threads in the process are
209  * permitted to emit icache flushing instructions. Whenever any thread in the
210  * process is migrated, the corresponding hart's icache will be guaranteed to be
211  * consistent with instruction storage. This does not enforce any guarantees
212  * outside of migration. If a thread modifies an instruction that another thread
213  * may attempt to execute, the other thread must still emit an icache flushing
214  * instruction before attempting to execute the potentially modified
215  * instruction. This must be performed by the user-space program.
216  *
217  * In per-thread context (eg. ``scope == PR_RISCV_SCOPE_PER_THREAD``) only the
218  * thread calling this function is permitted to emit icache flushing
219  * instructions. When the thread is migrated, the corresponding hart's icache
220  * will be guaranteed to be consistent with instruction storage.
221  *
222  * On kernels configured without SMP, this function is a nop as migrations
223  * across harts will not occur.
224  */
225 int riscv_set_icache_flush_ctx(unsigned long ctx, unsigned long scope)
226 {
227 #ifdef CONFIG_SMP
228         switch (ctx) {
229         case PR_RISCV_CTX_SW_FENCEI_ON:
230                 switch (scope) {
231                 case PR_RISCV_SCOPE_PER_PROCESS:
232                         current->mm->context.force_icache_flush = true;
233                         break;
234                 case PR_RISCV_SCOPE_PER_THREAD:
235                         current->thread.force_icache_flush = true;
236                         break;
237                 default:
238                         return -EINVAL;
239                 }
240                 break;
241         case PR_RISCV_CTX_SW_FENCEI_OFF:
242                 switch (scope) {
243                 case PR_RISCV_SCOPE_PER_PROCESS:
244                         set_icache_stale_mask();
245                         current->mm->context.force_icache_flush = false;
246                         break;
247                 case PR_RISCV_SCOPE_PER_THREAD:
248                         set_icache_stale_mask();
249                         current->thread.force_icache_flush = false;
250                         break;
251                 default:
252                         return -EINVAL;
253                 }
254                 break;
255         default:
256                 return -EINVAL;
257         }
258         return 0;
259 #else
260         switch (ctx) {
261         case PR_RISCV_CTX_SW_FENCEI_ON:
262         case PR_RISCV_CTX_SW_FENCEI_OFF:
263                 return 0;
264         default:
265                 return -EINVAL;
266         }
267 #endif
268 }
269 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php