| 1 | |
| 2 | |
| 3 | *
|
| 4 | * Copyright (C) 2000, 2001 Kanoj Sarcar
|
| 5 | * Copyright (C) 2000, 2001 Ralf Baechle
|
| 6 | * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
|
| 7 | * Copyright (C) 2000, 2001, 2003 Broadcom Corporation
|
| 8 |
|
| 9 | #include <linux/cache.h>
|
| 10 | #include <linux/delay.h>
|
| 11 | #include <linux/init.h>
|
| 12 | #include <linux/interrupt.h>
|
| 13 | #include <linux/profile.h>
|
| 14 | #include <linux/smp.h>
|
| 15 | #include <linux/spinlock.h>
|
| 16 | #include <linux/threads.h>
|
| 17 | #include <linux/export.h>
|
| 18 | #include <linux/time.h>
|
| 19 | #include <linux/timex.h>
|
| 20 | #include <linux/sched/mm.h>
|
| 21 | #include <linux/cpumask.h>
|
| 22 | #include <linux/cpu.h>
|
| 23 | #include <linux/rcupdate.h>
|
| 24 | #include <linux/err.h>
|
| 25 | #include <linux/ftrace.h>
|
| 26 | #include <linux/irqdomain.h>
|
| 27 | #include <linux/of.h>
|
| 28 | #include <linux/of_irq.h>
|
| 29 |
|
| 30 | #include <linux/atomic.h>
|
| 31 | #include <asm/cpu.h>
|
| 32 | #include <asm/ginvt.h>
|
| 33 | #include <asm/processor.h>
|
| 34 | #include <asm/idle.h>
|
| 35 | #include <asm/r4k-timer.h>
|
| 36 | #include <asm/mips-cps.h>
|
| 37 | #include <asm/mmu_context.h>
|
| 38 | #include <asm/time.h>
|
| 39 | #include <asm/setup.h>
|
| 40 | #include <asm/maar.h>
|
| 41 |
|
| 42 | int __cpu_number_map[CONFIG_MIPS_NR_CPU_NR_MAP];
|
| 43 | EXPORT_SYMBOL(__cpu_number_map);
|
| 44 |
|
| 45 | int __cpu_logical_map[NR_CPUS];
|
| 46 | EXPORT_SYMBOL(__cpu_logical_map);
|
| 47 |
|
| 48 |
|
| 49 | int smp_num_siblings = 1;
|
| 50 | EXPORT_SYMBOL(smp_num_siblings);
|
| 51 |
|
| 52 |
|
| 53 | cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
|
| 54 | EXPORT_SYMBOL(cpu_sibling_map);
|
| 55 |
|
| 56 |
|
| 57 | cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
|
| 58 | EXPORT_SYMBOL(cpu_core_map);
|
| 59 |
|
| 60 | #ifndef CONFIG_HOTPLUG_PARALLEL
|
| 61 | static DECLARE_COMPLETION(cpu_starting);
|
| 62 | static DECLARE_COMPLETION(cpu_running);
|
| 63 | #endif
|
| 64 |
|
| 65 | |
| 66 | * A logical cpu mask containing only one VPE per core to
|
| 67 | * reduce the number of IPIs on large MT systems.
|
| 68 |
|
| 69 | cpumask_t cpu_foreign_map[NR_CPUS] __read_mostly;
|
| 70 | EXPORT_SYMBOL(cpu_foreign_map);
|
| 71 |
|
| 72 |
|
| 73 | static cpumask_t cpu_sibling_setup_map;
|
| 74 |
|
| 75 |
|
| 76 | static cpumask_t cpu_core_setup_map;
|
| 77 |
|
| 78 | cpumask_t cpu_coherent_mask;
|
| 79 |
|
| 80 | struct cpumask __cpu_primary_thread_mask __read_mostly;
|
| 81 |
|
| 82 | unsigned int smp_max_threads __initdata = UINT_MAX;
|
| 83 |
|
| 84 | static int __init early_nosmt(char *s)
|
| 85 | {
|
| 86 | smp_max_threads = 1;
|
| 87 | return 0;
|
| 88 | }
|
| 89 | early_param("nosmt", early_nosmt);
|
| 90 |
|
| 91 | static int __init early_smt(char *s)
|
| 92 | {
|
| 93 | get_option(&s, &smp_max_threads);
|
| 94 |
|
| 95 | smp_max_threads = clamp_val(smp_max_threads, 1U, UINT_MAX);
|
| 96 | return 0;
|
| 97 | }
|
| 98 | early_param("smt", early_smt);
|
| 99 |
|
| 100 | #ifdef CONFIG_GENERIC_IRQ_IPI
|
| 101 | static struct irq_desc *call_desc;
|
| 102 | static struct irq_desc *sched_desc;
|
| 103 | #endif
|
| 104 |
|
| 105 | static inline void set_cpu_sibling_map(int cpu)
|
| 106 | {
|
| 107 | int i;
|
| 108 |
|
| 109 | cpumask_set_cpu(cpu, &cpu_sibling_setup_map);
|
| 110 |
|
| 111 | if (smp_num_siblings > 1) {
|
| 112 | for_each_cpu(i, &cpu_sibling_setup_map) {
|
| 113 | if (cpus_are_siblings(cpu, i)) {
|
| 114 | cpumask_set_cpu(i, &cpu_sibling_map[cpu]);
|
| 115 | cpumask_set_cpu(cpu, &cpu_sibling_map[i]);
|
| 116 | }
|
| 117 | }
|
| 118 | } else
|
| 119 | cpumask_set_cpu(cpu, &cpu_sibling_map[cpu]);
|
| 120 | }
|
| 121 |
|
| 122 | static inline void set_cpu_core_map(int cpu)
|
| 123 | {
|
| 124 | int i;
|
| 125 |
|
| 126 | cpumask_set_cpu(cpu, &cpu_core_setup_map);
|
| 127 |
|
| 128 | for_each_cpu(i, &cpu_core_setup_map) {
|
| 129 | if (cpu_data[cpu].package == cpu_data[i].package) {
|
| 130 | cpumask_set_cpu(i, &cpu_core_map[cpu]);
|
| 131 | cpumask_set_cpu(cpu, &cpu_core_map[i]);
|
| 132 | }
|
| 133 | }
|
| 134 | }
|
| 135 |
|
| 136 | |
| 137 | * Calculate a new cpu_foreign_map mask whenever a
|
| 138 | * new cpu appears or disappears.
|
| 139 |
|
| 140 | void calculate_cpu_foreign_map(void)
|
| 141 | {
|
| 142 | int i, k, core_present;
|
| 143 | cpumask_t temp_foreign_map;
|
| 144 |
|
| 145 |
|
| 146 | cpumask_clear(&temp_foreign_map);
|
| 147 | for_each_online_cpu(i) {
|
| 148 | core_present = 0;
|
| 149 | for_each_cpu(k, &temp_foreign_map)
|
| 150 | if (cpus_are_siblings(i, k))
|
| 151 | core_present = 1;
|
| 152 | if (!core_present)
|
| 153 | cpumask_set_cpu(i, &temp_foreign_map);
|
| 154 | }
|
| 155 |
|
| 156 | for_each_online_cpu(i)
|
| 157 | cpumask_andnot(&cpu_foreign_map[i],
|
| 158 | &temp_foreign_map, &cpu_sibling_map[i]);
|
| 159 | }
|
| 160 |
|
| 161 | const struct plat_smp_ops *mp_ops;
|
| 162 | EXPORT_SYMBOL(mp_ops);
|
| 163 |
|
| 164 | void register_smp_ops(const struct plat_smp_ops *ops)
|
| 165 | {
|
| 166 | if (mp_ops)
|
| 167 | printk(KERN_WARNING "Overriding previously set SMP ops\n");
|
| 168 |
|
| 169 | mp_ops = ops;
|
| 170 | }
|
| 171 |
|
| 172 | #ifdef CONFIG_GENERIC_IRQ_IPI
|
| 173 | void mips_smp_send_ipi_single(int cpu, unsigned int action)
|
| 174 | {
|
| 175 | mips_smp_send_ipi_mask(cpumask_of(cpu), action);
|
| 176 | }
|
| 177 |
|
| 178 | void mips_smp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
|
| 179 | {
|
| 180 | unsigned long flags;
|
| 181 | unsigned int core;
|
| 182 | int cpu;
|
| 183 |
|
| 184 | local_irq_save(flags);
|
| 185 |
|
| 186 | switch (action) {
|
| 187 | case SMP_CALL_FUNCTION:
|
| 188 | __ipi_send_mask(call_desc, mask);
|
| 189 | break;
|
| 190 |
|
| 191 | case SMP_RESCHEDULE_YOURSELF:
|
| 192 | __ipi_send_mask(sched_desc, mask);
|
| 193 | break;
|
| 194 |
|
| 195 | default:
|
| 196 | BUG();
|
| 197 | }
|
| 198 |
|
| 199 | if (mips_cpc_present()) {
|
| 200 | for_each_cpu(cpu, mask) {
|
| 201 | if (cpus_are_siblings(cpu, smp_processor_id()))
|
| 202 | continue;
|
| 203 |
|
| 204 | core = cpu_core(&cpu_data[cpu]);
|
| 205 |
|
| 206 | while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) {
|
| 207 | mips_cm_lock_other_cpu(cpu, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
|
| 208 | mips_cpc_lock_other(core);
|
| 209 | write_cpc_co_cmd(CPC_Cx_CMD_PWRUP);
|
| 210 | mips_cpc_unlock_other();
|
| 211 | mips_cm_unlock_other();
|
| 212 | }
|
| 213 | }
|
| 214 | }
|
| 215 |
|
| 216 | local_irq_restore(flags);
|
| 217 | }
|
| 218 |
|
| 219 |
|
| 220 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
|
| 221 | {
|
| 222 | scheduler_ipi();
|
| 223 |
|
| 224 | return IRQ_HANDLED;
|
| 225 | }
|
| 226 |
|
| 227 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
|
| 228 | {
|
| 229 | generic_smp_call_function_interrupt();
|
| 230 |
|
| 231 | return IRQ_HANDLED;
|
| 232 | }
|
| 233 |
|
| 234 | static void smp_ipi_init_one(unsigned int virq, const char *name,
|
| 235 | irq_handler_t handler)
|
| 236 | {
|
| 237 | int ret;
|
| 238 |
|
| 239 | irq_set_handler(virq, handle_percpu_irq);
|
| 240 | ret = request_irq(virq, handler, IRQF_PERCPU, name, NULL);
|
| 241 | BUG_ON(ret);
|
| 242 | }
|
| 243 |
|
| 244 | static unsigned int call_virq, sched_virq;
|
| 245 |
|
| 246 | int mips_smp_ipi_allocate(const struct cpumask *mask)
|
| 247 | {
|
| 248 | int virq;
|
| 249 | struct irq_domain *ipidomain;
|
| 250 | struct device_node *node;
|
| 251 |
|
| 252 | node = of_irq_find_parent(of_root);
|
| 253 | ipidomain = irq_find_matching_host(node, DOMAIN_BUS_IPI);
|
| 254 |
|
| 255 | |
| 256 | * Some platforms have half DT setup. So if we found irq node but
|
| 257 | * didn't find an ipidomain, try to search for one that is not in the
|
| 258 | * DT.
|
| 259 |
|
| 260 | if (node && !ipidomain)
|
| 261 | ipidomain = irq_find_matching_host(NULL, DOMAIN_BUS_IPI);
|
| 262 |
|
| 263 | |
| 264 | * There are systems which use IPI IRQ domains, but only have one
|
| 265 | * registered when some runtime condition is met. For example a Malta
|
| 266 | * kernel may include support for GIC & CPU interrupt controller IPI
|
| 267 | * IRQ domains, but if run on a system with no GIC & no MT ASE then
|
| 268 | * neither will be supported or registered.
|
| 269 | *
|
| 270 | * We only have a problem if we're actually using multiple CPUs so fail
|
| 271 | * loudly if that is the case. Otherwise simply return, skipping IPI
|
| 272 | * setup, if we're running with only a single CPU.
|
| 273 |
|
| 274 | if (!ipidomain) {
|
| 275 | BUG_ON(num_present_cpus() > 1);
|
| 276 | return 0;
|
| 277 | }
|
| 278 |
|
| 279 | virq = irq_reserve_ipi(ipidomain, mask);
|
| 280 | BUG_ON(!virq);
|
| 281 | if (!call_virq)
|
| 282 | call_virq = virq;
|
| 283 |
|
| 284 | virq = irq_reserve_ipi(ipidomain, mask);
|
| 285 | BUG_ON(!virq);
|
| 286 | if (!sched_virq)
|
| 287 | sched_virq = virq;
|
| 288 |
|
| 289 | if (irq_domain_is_ipi_per_cpu(ipidomain)) {
|
| 290 | int cpu;
|
| 291 |
|
| 292 | for_each_cpu(cpu, mask) {
|
| 293 | smp_ipi_init_one(call_virq + cpu, "IPI call",
|
| 294 | ipi_call_interrupt);
|
| 295 | smp_ipi_init_one(sched_virq + cpu, "IPI resched",
|
| 296 | ipi_resched_interrupt);
|
| 297 | }
|
| 298 | } else {
|
| 299 | smp_ipi_init_one(call_virq, "IPI call", ipi_call_interrupt);
|
| 300 | smp_ipi_init_one(sched_virq, "IPI resched",
|
| 301 | ipi_resched_interrupt);
|
| 302 | }
|
| 303 |
|
| 304 | return 0;
|
| 305 | }
|
| 306 |
|
| 307 | int mips_smp_ipi_free(const struct cpumask *mask)
|
| 308 | {
|
| 309 | struct irq_domain *ipidomain;
|
| 310 | struct device_node *node;
|
| 311 |
|
| 312 | node = of_irq_find_parent(of_root);
|
| 313 | ipidomain = irq_find_matching_host(node, DOMAIN_BUS_IPI);
|
| 314 |
|
| 315 | |
| 316 | * Some platforms have half DT setup. So if we found irq node but
|
| 317 | * didn't find an ipidomain, try to search for one that is not in the
|
| 318 | * DT.
|
| 319 |
|
| 320 | if (node && !ipidomain)
|
| 321 | ipidomain = irq_find_matching_host(NULL, DOMAIN_BUS_IPI);
|
| 322 |
|
| 323 | BUG_ON(!ipidomain);
|
| 324 |
|
| 325 | if (irq_domain_is_ipi_per_cpu(ipidomain)) {
|
| 326 | int cpu;
|
| 327 |
|
| 328 | for_each_cpu(cpu, mask) {
|
| 329 | free_irq(call_virq + cpu, NULL);
|
| 330 | free_irq(sched_virq + cpu, NULL);
|
| 331 | }
|
| 332 | }
|
| 333 | irq_destroy_ipi(call_virq, mask);
|
| 334 | irq_destroy_ipi(sched_virq, mask);
|
| 335 | return 0;
|
| 336 | }
|
| 337 |
|
| 338 |
|
| 339 | static int __init mips_smp_ipi_init(void)
|
| 340 | {
|
| 341 | if (num_possible_cpus() == 1)
|
| 342 | return 0;
|
| 343 |
|
| 344 | mips_smp_ipi_allocate(cpu_possible_mask);
|
| 345 |
|
| 346 | call_desc = irq_to_desc(call_virq);
|
| 347 | sched_desc = irq_to_desc(sched_virq);
|
| 348 |
|
| 349 | return 0;
|
| 350 | }
|
| 351 | early_initcall(mips_smp_ipi_init);
|
| 352 | #endif
|
| 353 |
|
| 354 | |
| 355 | * First C code run on the secondary CPUs after being started up by
|
| 356 | * the master.
|
| 357 |
|
| 358 | asmlinkage void start_secondary(void)
|
| 359 | {
|
| 360 | unsigned int cpu = raw_smp_processor_id();
|
| 361 |
|
| 362 | cpu_probe();
|
| 363 | per_cpu_trap_init(false);
|
| 364 | rcutree_report_cpu_starting(cpu);
|
| 365 | mips_clockevent_init();
|
| 366 | mp_ops->init_secondary();
|
| 367 | cpu_report();
|
| 368 | maar_init();
|
| 369 |
|
| 370 | |
| 371 | * XXX parity protection should be folded in here when it's converted
|
| 372 | * to an option instead of something based on .cputype
|
| 373 |
|
| 374 |
|
| 375 | #ifdef CONFIG_HOTPLUG_PARALLEL
|
| 376 | cpuhp_ap_sync_alive();
|
| 377 | #endif
|
| 378 | calibrate_delay();
|
| 379 | cpu_data[cpu].udelay_val = loops_per_jiffy;
|
| 380 |
|
| 381 | set_cpu_sibling_map(cpu);
|
| 382 | set_cpu_core_map(cpu);
|
| 383 |
|
| 384 | cpumask_set_cpu(cpu, &cpu_coherent_mask);
|
| 385 | notify_cpu_starting(cpu);
|
| 386 |
|
| 387 | #ifndef CONFIG_HOTPLUG_PARALLEL
|
| 388 |
|
| 389 | complete(&cpu_starting);
|
| 390 | #endif
|
| 391 |
|
| 392 | synchronise_count_slave(cpu);
|
| 393 |
|
| 394 |
|
| 395 | set_cpu_online(cpu, true);
|
| 396 |
|
| 397 | calculate_cpu_foreign_map();
|
| 398 |
|
| 399 | #ifndef CONFIG_HOTPLUG_PARALLEL
|
| 400 | |
| 401 | * Notify boot CPU that we're up & online and it can safely return
|
| 402 | * from __cpu_up
|
| 403 |
|
| 404 | complete(&cpu_running);
|
| 405 | #endif
|
| 406 |
|
| 407 | |
| 408 | * irq will be enabled in ->smp_finish(), enabling it too early
|
| 409 | * is dangerous.
|
| 410 |
|
| 411 | WARN_ON_ONCE(!irqs_disabled());
|
| 412 | mp_ops->smp_finish();
|
| 413 |
|
| 414 | cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
|
| 415 | }
|
| 416 |
|
| 417 | static void stop_this_cpu(void *dummy)
|
| 418 | {
|
| 419 | |
| 420 | * Remove this CPU:
|
| 421 |
|
| 422 |
|
| 423 | set_cpu_online(smp_processor_id(), false);
|
| 424 | calculate_cpu_foreign_map();
|
| 425 | local_irq_disable();
|
| 426 | rcutree_report_cpu_dead();
|
| 427 | while (1);
|
| 428 | }
|
| 429 |
|
| 430 | void smp_send_stop(void)
|
| 431 | {
|
| 432 | smp_call_function(stop_this_cpu, NULL, 0);
|
| 433 | }
|
| 434 |
|
| 435 | void __init smp_cpus_done(unsigned int max_cpus)
|
| 436 | {
|
| 437 | }
|
| 438 |
|
| 439 |
|
| 440 | void __init smp_prepare_cpus(unsigned int max_cpus)
|
| 441 | {
|
| 442 | init_new_context(current, &init_mm);
|
| 443 | current_thread_info()->cpu = 0;
|
| 444 | mp_ops->prepare_cpus(max_cpus);
|
| 445 | set_cpu_sibling_map(0);
|
| 446 | set_cpu_core_map(0);
|
| 447 | calculate_cpu_foreign_map();
|
| 448 | #ifndef CONFIG_HOTPLUG_CPU
|
| 449 | init_cpu_present(cpu_possible_mask);
|
| 450 | #endif
|
| 451 | cpumask_copy(&cpu_coherent_mask, cpu_possible_mask);
|
| 452 | }
|
| 453 |
|
| 454 |
|
| 455 | void __init smp_prepare_boot_cpu(void)
|
| 456 | {
|
| 457 | if (mp_ops->prepare_boot_cpu)
|
| 458 | mp_ops->prepare_boot_cpu();
|
| 459 | set_cpu_possible(0, true);
|
| 460 | set_cpu_online(0, true);
|
| 461 | }
|
| 462 |
|
| 463 | #ifdef CONFIG_HOTPLUG_PARALLEL
|
| 464 | int arch_cpuhp_kick_ap_alive(unsigned int cpu, struct task_struct *tidle)
|
| 465 | {
|
| 466 | return mp_ops->boot_secondary(cpu, tidle);
|
| 467 | }
|
| 468 | #else
|
| 469 | int __cpu_up(unsigned int cpu, struct task_struct *tidle)
|
| 470 | {
|
| 471 | int err;
|
| 472 |
|
| 473 | err = mp_ops->boot_secondary(cpu, tidle);
|
| 474 | if (err)
|
| 475 | return err;
|
| 476 |
|
| 477 |
|
| 478 | if (!wait_for_completion_timeout(&cpu_starting,
|
| 479 | msecs_to_jiffies(1000))) {
|
| 480 | pr_crit("CPU%u: failed to start\n", cpu);
|
| 481 | return -EIO;
|
| 482 | }
|
| 483 |
|
| 484 |
|
| 485 | wait_for_completion(&cpu_running);
|
| 486 | return 0;
|
| 487 | }
|
| 488 | #endif
|
| 489 |
|
| 490 | #ifdef CONFIG_PROFILING
|
| 491 |
|
| 492 | int setup_profiling_timer(unsigned int multiplier)
|
| 493 | {
|
| 494 | return 0;
|
| 495 | }
|
| 496 | #endif
|
| 497 |
|
| 498 | static void flush_tlb_all_ipi(void *info)
|
| 499 | {
|
| 500 | local_flush_tlb_all();
|
| 501 | }
|
| 502 |
|
| 503 | void flush_tlb_all(void)
|
| 504 | {
|
| 505 | if (cpu_has_mmid) {
|
| 506 | htw_stop();
|
| 507 | ginvt_full();
|
| 508 | sync_ginv();
|
| 509 | instruction_hazard();
|
| 510 | htw_start();
|
| 511 | return;
|
| 512 | }
|
| 513 |
|
| 514 | on_each_cpu(flush_tlb_all_ipi, NULL, 1);
|
| 515 | }
|
| 516 |
|
| 517 | static void flush_tlb_mm_ipi(void *mm)
|
| 518 | {
|
| 519 | drop_mmu_context((struct mm_struct *)mm);
|
| 520 | }
|
| 521 |
|
| 522 | |
| 523 | * Special Variant of smp_call_function for use by TLB functions:
|
| 524 | *
|
| 525 | * o No return value
|
| 526 | * o collapses to normal function call on UP kernels
|
| 527 | * o collapses to normal function call on systems with a single shared
|
| 528 | * primary cache.
|
| 529 |
|
| 530 | static inline void smp_on_other_tlbs(void (*func) (void *info), void *info)
|
| 531 | {
|
| 532 | smp_call_function(func, info, 1);
|
| 533 | }
|
| 534 |
|
| 535 | static inline void smp_on_each_tlb(void (*func) (void *info), void *info)
|
| 536 | {
|
| 537 | preempt_disable();
|
| 538 |
|
| 539 | smp_on_other_tlbs(func, info);
|
| 540 | func(info);
|
| 541 |
|
| 542 | preempt_enable();
|
| 543 | }
|
| 544 |
|
| 545 | |
| 546 | * The following tlb flush calls are invoked when old translations are
|
| 547 | * being torn down, or pte attributes are changing. For single threaded
|
| 548 | * address spaces, a new context is obtained on the current cpu, and tlb
|
| 549 | * context on other cpus are invalidated to force a new context allocation
|
| 550 | * at switch_mm time, should the mm ever be used on other cpus. For
|
| 551 | * multithreaded address spaces, inter-CPU interrupts have to be sent.
|
| 552 | * Another case where inter-CPU interrupts are required is when the target
|
| 553 | * mm might be active on another cpu (eg debuggers doing the flushes on
|
| 554 | * behalf of debugees, kswapd stealing pages from another process etc).
|
| 555 | * Kanoj 07/00.
|
| 556 |
|
| 557 |
|
| 558 | void flush_tlb_mm(struct mm_struct *mm)
|
| 559 | {
|
| 560 | if (!mm)
|
| 561 | return;
|
| 562 |
|
| 563 | if (atomic_read(&mm->mm_users) == 0)
|
| 564 | return;
|
| 565 |
|
| 566 | preempt_disable();
|
| 567 |
|
| 568 | if (cpu_has_mmid) {
|
| 569 | |
| 570 | * No need to worry about other CPUs - the ginvt in
|
| 571 | * drop_mmu_context() will be globalized.
|
| 572 |
|
| 573 | } else if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
|
| 574 | smp_on_other_tlbs(flush_tlb_mm_ipi, mm);
|
| 575 | } else {
|
| 576 | unsigned int cpu;
|
| 577 |
|
| 578 | for_each_online_cpu(cpu) {
|
| 579 | if (cpu != smp_processor_id() && cpu_context(cpu, mm))
|
| 580 | set_cpu_context(cpu, mm, 0);
|
| 581 | }
|
| 582 | }
|
| 583 | drop_mmu_context(mm);
|
| 584 |
|
| 585 | preempt_enable();
|
| 586 | }
|
| 587 |
|
| 588 | struct flush_tlb_data {
|
| 589 | struct vm_area_struct *vma;
|
| 590 | unsigned long addr1;
|
| 591 | unsigned long addr2;
|
| 592 | };
|
| 593 |
|
| 594 | static void flush_tlb_range_ipi(void *info)
|
| 595 | {
|
| 596 | struct flush_tlb_data *fd = info;
|
| 597 |
|
| 598 | local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
|
| 599 | }
|
| 600 |
|
| 601 | void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
|
| 602 | {
|
| 603 | struct mm_struct *mm = vma->vm_mm;
|
| 604 | unsigned long addr;
|
| 605 | u32 old_mmid;
|
| 606 |
|
| 607 | preempt_disable();
|
| 608 | if (cpu_has_mmid) {
|
| 609 | htw_stop();
|
| 610 | old_mmid = read_c0_memorymapid();
|
| 611 | write_c0_memorymapid(cpu_asid(0, mm));
|
| 612 | mtc0_tlbw_hazard();
|
| 613 | addr = round_down(start, PAGE_SIZE * 2);
|
| 614 | end = round_up(end, PAGE_SIZE * 2);
|
| 615 | do {
|
| 616 | ginvt_va_mmid(addr);
|
| 617 | sync_ginv();
|
| 618 | addr += PAGE_SIZE * 2;
|
| 619 | } while (addr < end);
|
| 620 | write_c0_memorymapid(old_mmid);
|
| 621 | instruction_hazard();
|
| 622 | htw_start();
|
| 623 | } else if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
|
| 624 | struct flush_tlb_data fd = {
|
| 625 | .vma = vma,
|
| 626 | .addr1 = start,
|
| 627 | .addr2 = end,
|
| 628 | };
|
| 629 |
|
| 630 | smp_on_other_tlbs(flush_tlb_range_ipi, &fd);
|
| 631 | local_flush_tlb_range(vma, start, end);
|
| 632 | } else {
|
| 633 | unsigned int cpu;
|
| 634 | int exec = vma->vm_flags & VM_EXEC;
|
| 635 |
|
| 636 | for_each_online_cpu(cpu) {
|
| 637 | |
| 638 | * flush_cache_range() will only fully flush icache if
|
| 639 | * the VMA is executable, otherwise we must invalidate
|
| 640 | * ASID without it appearing to has_valid_asid() as if
|
| 641 | * mm has been completely unused by that CPU.
|
| 642 |
|
| 643 | if (cpu != smp_processor_id() && cpu_context(cpu, mm))
|
| 644 | set_cpu_context(cpu, mm, !exec);
|
| 645 | }
|
| 646 | local_flush_tlb_range(vma, start, end);
|
| 647 | }
|
| 648 | preempt_enable();
|
| 649 | }
|
| 650 |
|
| 651 | static void flush_tlb_kernel_range_ipi(void *info)
|
| 652 | {
|
| 653 | struct flush_tlb_data *fd = info;
|
| 654 |
|
| 655 | local_flush_tlb_kernel_range(fd->addr1, fd->addr2);
|
| 656 | }
|
| 657 |
|
| 658 | void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
| 659 | {
|
| 660 | struct flush_tlb_data fd = {
|
| 661 | .addr1 = start,
|
| 662 | .addr2 = end,
|
| 663 | };
|
| 664 |
|
| 665 | on_each_cpu(flush_tlb_kernel_range_ipi, &fd, 1);
|
| 666 | }
|
| 667 |
|
| 668 | static void flush_tlb_page_ipi(void *info)
|
| 669 | {
|
| 670 | struct flush_tlb_data *fd = info;
|
| 671 |
|
| 672 | local_flush_tlb_page(fd->vma, fd->addr1);
|
| 673 | }
|
| 674 |
|
| 675 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
|
| 676 | {
|
| 677 | u32 old_mmid;
|
| 678 |
|
| 679 | preempt_disable();
|
| 680 | if (cpu_has_mmid) {
|
| 681 | htw_stop();
|
| 682 | old_mmid = read_c0_memorymapid();
|
| 683 | write_c0_memorymapid(cpu_asid(0, vma->vm_mm));
|
| 684 | mtc0_tlbw_hazard();
|
| 685 | ginvt_va_mmid(page);
|
| 686 | sync_ginv();
|
| 687 | write_c0_memorymapid(old_mmid);
|
| 688 | instruction_hazard();
|
| 689 | htw_start();
|
| 690 | } else if ((atomic_read(&vma->vm_mm->mm_users) != 1) ||
|
| 691 | (current->mm != vma->vm_mm)) {
|
| 692 | struct flush_tlb_data fd = {
|
| 693 | .vma = vma,
|
| 694 | .addr1 = page,
|
| 695 | };
|
| 696 |
|
| 697 | smp_on_other_tlbs(flush_tlb_page_ipi, &fd);
|
| 698 | local_flush_tlb_page(vma, page);
|
| 699 | } else {
|
| 700 | unsigned int cpu;
|
| 701 |
|
| 702 | for_each_online_cpu(cpu) {
|
| 703 | |
| 704 | * flush_cache_page() only does partial flushes, so
|
| 705 | * invalidate ASID without it appearing to
|
| 706 | * has_valid_asid() as if mm has been completely unused
|
| 707 | * by that CPU.
|
| 708 |
|
| 709 | if (cpu != smp_processor_id() && cpu_context(cpu, vma->vm_mm))
|
| 710 | set_cpu_context(cpu, vma->vm_mm, 1);
|
| 711 | }
|
| 712 | local_flush_tlb_page(vma, page);
|
| 713 | }
|
| 714 | preempt_enable();
|
| 715 | }
|
| 716 |
|
| 717 | static void flush_tlb_one_ipi(void *info)
|
| 718 | {
|
| 719 | unsigned long vaddr = (unsigned long) info;
|
| 720 |
|
| 721 | local_flush_tlb_one(vaddr);
|
| 722 | }
|
| 723 |
|
| 724 | void flush_tlb_one(unsigned long vaddr)
|
| 725 | {
|
| 726 | smp_on_each_tlb(flush_tlb_one_ipi, (void *) vaddr);
|
| 727 | }
|
| 728 |
|
| 729 | EXPORT_SYMBOL(flush_tlb_page);
|
| 730 | EXPORT_SYMBOL(flush_tlb_one);
|
| 731 |
|
| 732 | #ifdef CONFIG_HOTPLUG_CORE_SYNC_DEAD
|
| 733 | void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)
|
| 734 | {
|
| 735 | if (mp_ops->cleanup_dead_cpu)
|
| 736 | mp_ops->cleanup_dead_cpu(cpu);
|
| 737 | }
|
| 738 | #endif
|
| 739 |
|
| 740 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
| 741 |
|
| 742 | static void tick_broadcast_callee(void *info)
|
| 743 | {
|
| 744 | tick_receive_broadcast();
|
| 745 | }
|
| 746 |
|
| 747 | static DEFINE_PER_CPU(call_single_data_t, tick_broadcast_csd) =
|
| 748 | CSD_INIT(tick_broadcast_callee, NULL);
|
| 749 |
|
| 750 | void tick_broadcast(const struct cpumask *mask)
|
| 751 | {
|
| 752 | call_single_data_t *csd;
|
| 753 | int cpu;
|
| 754 |
|
| 755 | for_each_cpu(cpu, mask) {
|
| 756 | csd = &per_cpu(tick_broadcast_csd, cpu);
|
| 757 | smp_call_function_single_async(cpu, csd);
|
| 758 | }
|
| 759 | }
|
| 760 |
|
| 761 | #endif
|