linux/arch/mips/kernel/smp.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or
   3 * modify it under the terms of the GNU General Public License
   4 * as published by the Free Software Foundation; either version 2
   5 * of the License, or (at your option) any later version.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 *
  12 * You should have received a copy of the GNU General Public License
  13 * along with this program; if not, write to the Free Software
  14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  15 *
  16 * Copyright (C) 2000, 2001 Kanoj Sarcar
  17 * Copyright (C) 2000, 2001 Ralf Baechle
  18 * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
  19 * Copyright (C) 2000, 2001, 2003 Broadcom Corporation
  20 */
  21#include <linux/cache.h>
  22#include <linux/delay.h>
  23#include <linux/init.h>
  24#include <linux/interrupt.h>
  25#include <linux/smp.h>
  26#include <linux/spinlock.h>
  27#include <linux/threads.h>
  28#include <linux/module.h>
  29#include <linux/time.h>
  30#include <linux/timex.h>
  31#include <linux/sched.h>
  32#include <linux/cpumask.h>
  33#include <linux/cpu.h>
  34#include <linux/err.h>
  35#include <linux/ftrace.h>
  36
  37#include <linux/atomic.h>
  38#include <asm/cpu.h>
  39#include <asm/processor.h>
  40#include <asm/idle.h>
  41#include <asm/r4k-timer.h>
  42#include <asm/mmu_context.h>
  43#include <asm/time.h>
  44#include <asm/setup.h>
  45#include <asm/maar.h>
  46
  47cpumask_t cpu_callin_map;               /* Bitmask of started secondaries */
  48
  49int __cpu_number_map[NR_CPUS];          /* Map physical to logical */
  50EXPORT_SYMBOL(__cpu_number_map);
  51
  52int __cpu_logical_map[NR_CPUS];         /* Map logical to physical */
  53EXPORT_SYMBOL(__cpu_logical_map);
  54
  55/* Number of TCs (or siblings in Intel speak) per CPU core */
  56int smp_num_siblings = 1;
  57EXPORT_SYMBOL(smp_num_siblings);
  58
  59/* representing the TCs (or siblings in Intel speak) of each logical CPU */
  60cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
  61EXPORT_SYMBOL(cpu_sibling_map);
  62
  63/* representing the core map of multi-core chips of each logical CPU */
  64cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
  65EXPORT_SYMBOL(cpu_core_map);
  66
  67/*
  68 * A logcal cpu mask containing only one VPE per core to
  69 * reduce the number of IPIs on large MT systems.
  70 */
  71cpumask_t cpu_foreign_map __read_mostly;
  72EXPORT_SYMBOL(cpu_foreign_map);
  73
  74/* representing cpus for which sibling maps can be computed */
  75static cpumask_t cpu_sibling_setup_map;
  76
  77/* representing cpus for which core maps can be computed */
  78static cpumask_t cpu_core_setup_map;
  79
  80cpumask_t cpu_coherent_mask;
  81
  82static inline void set_cpu_sibling_map(int cpu)
  83{
  84        int i;
  85
  86        cpumask_set_cpu(cpu, &cpu_sibling_setup_map);
  87
  88        if (smp_num_siblings > 1) {
  89                for_each_cpu(i, &cpu_sibling_setup_map) {
  90                        if (cpu_data[cpu].package == cpu_data[i].package &&
  91                                    cpu_data[cpu].core == cpu_data[i].core) {
  92                                cpumask_set_cpu(i, &cpu_sibling_map[cpu]);
  93                                cpumask_set_cpu(cpu, &cpu_sibling_map[i]);
  94                        }
  95                }
  96        } else
  97                cpumask_set_cpu(cpu, &cpu_sibling_map[cpu]);
  98}
  99
 100static inline void set_cpu_core_map(int cpu)
 101{
 102        int i;
 103
 104        cpumask_set_cpu(cpu, &cpu_core_setup_map);
 105
 106        for_each_cpu(i, &cpu_core_setup_map) {
 107                if (cpu_data[cpu].package == cpu_data[i].package) {
 108                        cpumask_set_cpu(i, &cpu_core_map[cpu]);
 109                        cpumask_set_cpu(cpu, &cpu_core_map[i]);
 110                }
 111        }
 112}
 113
 114/*
 115 * Calculate a new cpu_foreign_map mask whenever a
 116 * new cpu appears or disappears.
 117 */
 118static inline void calculate_cpu_foreign_map(void)
 119{
 120        int i, k, core_present;
 121        cpumask_t temp_foreign_map;
 122
 123        /* Re-calculate the mask */
 124        for_each_online_cpu(i) {
 125                core_present = 0;
 126                for_each_cpu(k, &temp_foreign_map)
 127                        if (cpu_data[i].package == cpu_data[k].package &&
 128                            cpu_data[i].core == cpu_data[k].core)
 129                                core_present = 1;
 130                if (!core_present)
 131                        cpumask_set_cpu(i, &temp_foreign_map);
 132        }
 133
 134        cpumask_copy(&cpu_foreign_map, &temp_foreign_map);
 135}
 136
 137struct plat_smp_ops *mp_ops;
 138EXPORT_SYMBOL(mp_ops);
 139
 140void register_smp_ops(struct plat_smp_ops *ops)
 141{
 142        if (mp_ops)
 143                printk(KERN_WARNING "Overriding previously set SMP ops\n");
 144
 145        mp_ops = ops;
 146}
 147
 148/*
 149 * First C code run on the secondary CPUs after being started up by
 150 * the master.
 151 */
 152asmlinkage void start_secondary(void)
 153{
 154        unsigned int cpu;
 155
 156        cpu_probe();
 157        per_cpu_trap_init(false);
 158        mips_clockevent_init();
 159        mp_ops->init_secondary();
 160        cpu_report();
 161        maar_init();
 162
 163        /*
 164         * XXX parity protection should be folded in here when it's converted
 165         * to an option instead of something based on .cputype
 166         */
 167
 168        calibrate_delay();
 169        preempt_disable();
 170        cpu = smp_processor_id();
 171        cpu_data[cpu].udelay_val = loops_per_jiffy;
 172
 173        cpumask_set_cpu(cpu, &cpu_coherent_mask);
 174        notify_cpu_starting(cpu);
 175
 176        set_cpu_online(cpu, true);
 177
 178        set_cpu_sibling_map(cpu);
 179        set_cpu_core_map(cpu);
 180
 181        calculate_cpu_foreign_map();
 182
 183        cpumask_set_cpu(cpu, &cpu_callin_map);
 184
 185        synchronise_count_slave(cpu);
 186
 187        /*
 188         * irq will be enabled in ->smp_finish(), enabling it too early
 189         * is dangerous.
 190         */
 191        WARN_ON_ONCE(!irqs_disabled());
 192        mp_ops->smp_finish();
 193
 194        cpu_startup_entry(CPUHP_ONLINE);
 195}
 196
 197static void stop_this_cpu(void *dummy)
 198{
 199        /*
 200         * Remove this CPU. Be a bit slow here and
 201         * set the bits for every online CPU so we don't miss
 202         * any IPI whilst taking this VPE down.
 203         */
 204
 205        cpumask_copy(&cpu_foreign_map, cpu_online_mask);
 206
 207        /* Make it visible to every other CPU */
 208        smp_mb();
 209
 210        set_cpu_online(smp_processor_id(), false);
 211        calculate_cpu_foreign_map();
 212        local_irq_disable();
 213        while (1);
 214}
 215
 216void smp_send_stop(void)
 217{
 218        smp_call_function(stop_this_cpu, NULL, 0);
 219}
 220
 221void __init smp_cpus_done(unsigned int max_cpus)
 222{
 223}
 224
 225/* called from main before smp_init() */
 226void __init smp_prepare_cpus(unsigned int max_cpus)
 227{
 228        init_new_context(current, &init_mm);
 229        current_thread_info()->cpu = 0;
 230        mp_ops->prepare_cpus(max_cpus);
 231        set_cpu_sibling_map(0);
 232        set_cpu_core_map(0);
 233        calculate_cpu_foreign_map();
 234#ifndef CONFIG_HOTPLUG_CPU
 235        init_cpu_present(cpu_possible_mask);
 236#endif
 237        cpumask_copy(&cpu_coherent_mask, cpu_possible_mask);
 238}
 239
 240/* preload SMP state for boot cpu */
 241void smp_prepare_boot_cpu(void)
 242{
 243        set_cpu_possible(0, true);
 244        set_cpu_online(0, true);
 245        cpumask_set_cpu(0, &cpu_callin_map);
 246}
 247
 248int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 249{
 250        mp_ops->boot_secondary(cpu, tidle);
 251
 252        /*
 253         * Trust is futile.  We should really have timeouts ...
 254         */
 255        while (!cpumask_test_cpu(cpu, &cpu_callin_map)) {
 256                udelay(100);
 257                schedule();
 258        }
 259
 260        synchronise_count_master(cpu);
 261        return 0;
 262}
 263
 264/* Not really SMP stuff ... */
 265int setup_profiling_timer(unsigned int multiplier)
 266{
 267        return 0;
 268}
 269
 270static void flush_tlb_all_ipi(void *info)
 271{
 272        local_flush_tlb_all();
 273}
 274
 275void flush_tlb_all(void)
 276{
 277        on_each_cpu(flush_tlb_all_ipi, NULL, 1);
 278}
 279
 280static void flush_tlb_mm_ipi(void *mm)
 281{
 282        local_flush_tlb_mm((struct mm_struct *)mm);
 283}
 284
 285/*
 286 * Special Variant of smp_call_function for use by TLB functions:
 287 *
 288 *  o No return value
 289 *  o collapses to normal function call on UP kernels
 290 *  o collapses to normal function call on systems with a single shared
 291 *    primary cache.
 292 */
 293static inline void smp_on_other_tlbs(void (*func) (void *info), void *info)
 294{
 295        smp_call_function(func, info, 1);
 296}
 297
 298static inline void smp_on_each_tlb(void (*func) (void *info), void *info)
 299{
 300        preempt_disable();
 301
 302        smp_on_other_tlbs(func, info);
 303        func(info);
 304
 305        preempt_enable();
 306}
 307
 308/*
 309 * The following tlb flush calls are invoked when old translations are
 310 * being torn down, or pte attributes are changing. For single threaded
 311 * address spaces, a new context is obtained on the current cpu, and tlb
 312 * context on other cpus are invalidated to force a new context allocation
 313 * at switch_mm time, should the mm ever be used on other cpus. For
 314 * multithreaded address spaces, intercpu interrupts have to be sent.
 315 * Another case where intercpu interrupts are required is when the target
 316 * mm might be active on another cpu (eg debuggers doing the flushes on
 317 * behalf of debugees, kswapd stealing pages from another process etc).
 318 * Kanoj 07/00.
 319 */
 320
 321void flush_tlb_mm(struct mm_struct *mm)
 322{
 323        preempt_disable();
 324
 325        if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
 326                smp_on_other_tlbs(flush_tlb_mm_ipi, mm);
 327        } else {
 328                unsigned int cpu;
 329
 330                for_each_online_cpu(cpu) {
 331                        if (cpu != smp_processor_id() && cpu_context(cpu, mm))
 332                                cpu_context(cpu, mm) = 0;
 333                }
 334        }
 335        local_flush_tlb_mm(mm);
 336
 337        preempt_enable();
 338}
 339
 340struct flush_tlb_data {
 341        struct vm_area_struct *vma;
 342        unsigned long addr1;
 343        unsigned long addr2;
 344};
 345
 346static void flush_tlb_range_ipi(void *info)
 347{
 348        struct flush_tlb_data *fd = info;
 349
 350        local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
 351}
 352
 353void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 354{
 355        struct mm_struct *mm = vma->vm_mm;
 356
 357        preempt_disable();
 358        if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
 359                struct flush_tlb_data fd = {
 360                        .vma = vma,
 361                        .addr1 = start,
 362                        .addr2 = end,
 363                };
 364
 365                smp_on_other_tlbs(flush_tlb_range_ipi, &fd);
 366        } else {
 367                unsigned int cpu;
 368
 369                for_each_online_cpu(cpu) {
 370                        if (cpu != smp_processor_id() && cpu_context(cpu, mm))
 371                                cpu_context(cpu, mm) = 0;
 372                }
 373        }
 374        local_flush_tlb_range(vma, start, end);
 375        preempt_enable();
 376}
 377
 378static void flush_tlb_kernel_range_ipi(void *info)
 379{
 380        struct flush_tlb_data *fd = info;
 381
 382        local_flush_tlb_kernel_range(fd->addr1, fd->addr2);
 383}
 384
 385void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 386{
 387        struct flush_tlb_data fd = {
 388                .addr1 = start,
 389                .addr2 = end,
 390        };
 391
 392        on_each_cpu(flush_tlb_kernel_range_ipi, &fd, 1);
 393}
 394
 395static void flush_tlb_page_ipi(void *info)
 396{
 397        struct flush_tlb_data *fd = info;
 398
 399        local_flush_tlb_page(fd->vma, fd->addr1);
 400}
 401
 402void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 403{
 404        preempt_disable();
 405        if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) {
 406                struct flush_tlb_data fd = {
 407                        .vma = vma,
 408                        .addr1 = page,
 409                };
 410
 411                smp_on_other_tlbs(flush_tlb_page_ipi, &fd);
 412        } else {
 413                unsigned int cpu;
 414
 415                for_each_online_cpu(cpu) {
 416                        if (cpu != smp_processor_id() && cpu_context(cpu, vma->vm_mm))
 417                                cpu_context(cpu, vma->vm_mm) = 0;
 418                }
 419        }
 420        local_flush_tlb_page(vma, page);
 421        preempt_enable();
 422}
 423
 424static void flush_tlb_one_ipi(void *info)
 425{
 426        unsigned long vaddr = (unsigned long) info;
 427
 428        local_flush_tlb_one(vaddr);
 429}
 430
 431void flush_tlb_one(unsigned long vaddr)
 432{
 433        smp_on_each_tlb(flush_tlb_one_ipi, (void *) vaddr);
 434}
 435
 436EXPORT_SYMBOL(flush_tlb_page);
 437EXPORT_SYMBOL(flush_tlb_one);
 438
 439#if defined(CONFIG_KEXEC)
 440void (*dump_ipi_function_ptr)(void *) = NULL;
 441void dump_send_ipi(void (*dump_ipi_callback)(void *))
 442{
 443        int i;
 444        int cpu = smp_processor_id();
 445
 446        dump_ipi_function_ptr = dump_ipi_callback;
 447        smp_mb();
 448        for_each_online_cpu(i)
 449                if (i != cpu)
 450                        mp_ops->send_ipi_single(i, SMP_DUMP);
 451
 452}
 453EXPORT_SYMBOL(dump_send_ipi);
 454#endif
 455
 456#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 457
 458static DEFINE_PER_CPU(atomic_t, tick_broadcast_count);
 459static DEFINE_PER_CPU(struct call_single_data, tick_broadcast_csd);
 460
 461void tick_broadcast(const struct cpumask *mask)
 462{
 463        atomic_t *count;
 464        struct call_single_data *csd;
 465        int cpu;
 466
 467        for_each_cpu(cpu, mask) {
 468                count = &per_cpu(tick_broadcast_count, cpu);
 469                csd = &per_cpu(tick_broadcast_csd, cpu);
 470
 471                if (atomic_inc_return(count) == 1)
 472                        smp_call_function_single_async(cpu, csd);
 473        }
 474}
 475
 476static void tick_broadcast_callee(void *info)
 477{
 478        int cpu = smp_processor_id();
 479        tick_receive_broadcast();
 480        atomic_set(&per_cpu(tick_broadcast_count, cpu), 0);
 481}
 482
 483static int __init tick_broadcast_init(void)
 484{
 485        struct call_single_data *csd;
 486        int cpu;
 487
 488        for (cpu = 0; cpu < NR_CPUS; cpu++) {
 489                csd = &per_cpu(tick_broadcast_csd, cpu);
 490                csd->func = tick_broadcast_callee;
 491        }
 492
 493        return 0;
 494}
 495early_initcall(tick_broadcast_init);
 496
 497#endif /* CONFIG_GENERIC_CLOCKEVENTS_BROADCAST */
 498