Root/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c

1/*
2 * arch/ubicom32/kernel/smp.c
3 * SMP implementation for Ubicom32 processors.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
7 * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
8 * Copyright (C) 2001,2004 Grant Grundler <grundler@parisc-linux.org>
9 *
10 * This file is part of the Ubicom32 Linux Kernel Port.
11 *
12 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
13 * it and/or modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
18 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
20 * the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with the Ubicom32 Linux Kernel Port. If not,
24 * see <http://www.gnu.org/licenses/>.
25 *
26 * Ubicom32 implementation derived from (with many thanks):
27 * arch/m68knommu
28 * arch/blackfin
29 * arch/parisc
30 */
31
32#include <linux/types.h>
33#include <linux/spinlock.h>
34#include <linux/slab.h>
35
36#include <linux/kernel.h>
37#include <linux/bootmem.h>
38#include <linux/module.h>
39#include <linux/sched.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/smp.h>
43#include <linux/kernel_stat.h>
44#include <linux/mm.h>
45#include <linux/err.h>
46#include <linux/delay.h>
47#include <linux/bitops.h>
48#include <linux/cpu.h>
49#include <linux/profile.h>
50#include <linux/delay.h>
51#include <linux/io.h>
52#include <linux/ptrace.h>
53#include <linux/unistd.h>
54#include <linux/irq.h>
55
56#include <asm/system.h>
57#include <asm/atomic.h>
58#include <asm/current.h>
59#include <asm/tlbflush.h>
60#include <asm/timex.h>
61#include <asm/cpu.h>
62#include <asm/irq.h>
63#include <asm/processor.h>
64#include <asm/thread.h>
65#include <asm/sections.h>
66#include <asm/ip5000.h>
67
68/*
69 * Mask the debug printout for IPI because they are too verbose
70 * for regular debugging.
71 */
72
73// #define DEBUG_SMP 1
74#if !defined(DEBUG_SMP)
75#define smp_debug(lvl, ...)
76#else
77static unsigned int smp_debug_lvl = 50;
78#define smp_debug(lvl, printargs...) \
79    if (lvl >= smp_debug_lvl) { \
80            printk(printargs); \
81    }
82#endif
83
84#if !defined(DEBUG_SMP)
85#define DEBUG_ASSERT(cond)
86#else
87#define DEBUG_ASSERT(cond) \
88    if (!(cond)) { \
89        THREAD_STALL; \
90    }
91#endif
92
93/*
94 * List of IPI Commands (more than one can be set at a time).
95 */
96enum ipi_message_type {
97    IPI_NOP,
98    IPI_RESCHEDULE,
99    IPI_CALL_FUNC,
100    IPI_CALL_FUNC_SINGLE,
101    IPI_CPU_STOP,
102    IPI_CPU_TIMER,
103};
104
105/*
106 * We maintain a hardware thread oriented view of online threads
107 * and those involved or needing IPI.
108 */
109static volatile unsigned long smp_online_threads = 0;
110static volatile unsigned long smp_needs_ipi = 0;
111static volatile unsigned long smp_inside_ipi = 0;
112static unsigned long smp_irq_affinity[NR_IRQS];
113
114/*
115 * What do we need to track on a per cpu/thread basis?
116 */
117DEFINE_PER_CPU(struct cpuinfo_ubicom32, cpu_data);
118
119/*
120 * Each thread cpuinfo IPI information is guarded by a lock
121 * that is kept local to this file.
122 */
123DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED;
124
125/*
126 * The IPI(s) are based on a software IRQ through the LDSR.
127 */
128unsigned int smp_ipi_irq;
129
130/*
131 * Define a spinlock so that only one cpu is able to modify the
132 * smp_needs_ipi and to set/clear the IRQ at a time.
133 */
134DEFINE_SPINLOCK(smp_ipi_lock);
135
136/*
137 * smp_halt_processor()
138 * Halt this hardware thread.
139 */
140static void smp_halt_processor(void)
141{
142    int cpuid = thread_get_self();
143    cpu_clear(smp_processor_id(), cpu_online_map);
144    local_irq_disable();
145    printk(KERN_EMERG "cpu[%d] has halted. It is not OK to turn off power \
146        until all cpu's are off.\n", cpuid);
147    for (;;) {
148        thread_suspend();
149    }
150}
151
152/*
153 * ipi_interrupt()
154 * Handle an Interprocessor Interrupt.
155 */
156static irqreturn_t ipi_interrupt(int irq, void *dev_id)
157{
158    int cpuid = smp_processor_id();
159    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
160    unsigned long ops;
161
162    /*
163     * Count this now; we may make a call that never returns.
164     */
165    p->ipi_count++;
166
167    /*
168     * We are about to process all ops. If another cpu has stated
169     * that we need an IPI, we will have already processed it. By
170     * clearing our smp_needs_ipi, and processing all ops,
171     * we reduce the number of IPI interrupts. However, this introduces
172     * the possibility that smp_needs_ipi will be clear and the soft irq
173     * will have gone off; so we need to make the get_affinity() path
174     * tolerant of spurious interrupts.
175     */
176    spin_lock(&smp_ipi_lock);
177    smp_needs_ipi &= ~(1 << p->tid);
178    spin_unlock(&smp_ipi_lock);
179
180    for (;;) {
181        /*
182         * Read the set of IPI commands we should handle.
183         */
184        spinlock_t *lock = &per_cpu(ipi_lock, cpuid);
185        spin_lock(lock);
186        ops = p->ipi_pending;
187        p->ipi_pending = 0;
188        spin_unlock(lock);
189
190        /*
191         * If we have no IPI commands to execute, break out.
192         */
193        if (!ops) {
194            break;
195        }
196
197        /*
198         * Execute the set of commands in the ops word, one command
199         * at a time in no particular order. Strip of each command
200         * as we execute it.
201         */
202        while (ops) {
203            unsigned long which = ffz(~ops);
204            ops &= ~(1 << which);
205
206            BUG_ON(!irqs_disabled());
207            switch (which) {
208            case IPI_NOP:
209                smp_debug(100, KERN_INFO "cpu[%d]: "
210                      "IPI_NOP\n", cpuid);
211                break;
212
213            case IPI_RESCHEDULE:
214                /*
215                 * Reschedule callback. Everything to be
216                 * done is done by the interrupt return path.
217                 */
218                smp_debug(200, KERN_INFO "cpu[%d]: "
219                      "IPI_RESCHEDULE\n", cpuid);
220                break;
221
222            case IPI_CALL_FUNC:
223                smp_debug(100, KERN_INFO "cpu[%d]: "
224                      "IPI_CALL_FUNC\n", cpuid);
225                generic_smp_call_function_interrupt();
226                break;
227
228            case IPI_CALL_FUNC_SINGLE:
229                smp_debug(100, KERN_INFO "cpu[%d]: "
230                      "IPI_CALL_FUNC_SINGLE\n", cpuid);
231                generic_smp_call_function_single_interrupt();
232                break;
233
234            case IPI_CPU_STOP:
235                smp_debug(100, KERN_INFO "cpu[%d]: "
236                      "IPI_CPU_STOP\n", cpuid);
237                smp_halt_processor();
238                break;
239
240#if !defined(CONFIG_LOCAL_TIMERS)
241            case IPI_CPU_TIMER:
242                smp_debug(100, KERN_INFO "cpu[%d]: "
243                      "IPI_CPU_TIMER\n", cpuid);
244#if defined(CONFIG_GENERIC_CLOCKEVENTS)
245                local_timer_interrupt();
246#else
247                update_process_times(user_mode(get_irq_regs()));
248                profile_tick(CPU_PROFILING);
249#endif
250#endif
251                break;
252
253            default:
254                printk(KERN_CRIT "cpu[%d]: "
255                      "Unknown IPI: %lu\n", cpuid, which);
256
257                return IRQ_NONE;
258            }
259
260            /*
261             * Let in any pending interrupts
262             */
263            BUG_ON(!irqs_disabled());
264            local_irq_enable();
265            local_irq_disable();
266        }
267    }
268    return IRQ_HANDLED;
269}
270
271/*
272 * ipi_send()
273 * Send an Interprocessor Interrupt.
274 */
275static void ipi_send(int cpu, enum ipi_message_type op)
276{
277    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu);
278    spinlock_t *lock = &per_cpu(ipi_lock, cpu);
279    unsigned long flags;
280
281    /*
282     * We protect the setting of the ipi_pending field and ensure
283     * that the ipi delivery mechanism and interrupt are atomically
284     * handled.
285     */
286    spin_lock_irqsave(lock, flags);
287    p->ipi_pending |= 1 << op;
288    spin_unlock_irqrestore(lock, flags);
289
290    spin_lock_irqsave(&smp_ipi_lock, flags);
291    smp_needs_ipi |= (1 << p->tid);
292    ubicom32_set_interrupt(smp_ipi_irq);
293    spin_unlock_irqrestore(&smp_ipi_lock, flags);
294    smp_debug(100, KERN_INFO "cpu[%d]: send: %d\n", cpu, op);
295}
296
297/*
298 * ipi_send_mask
299 * Send an IPI to each cpu in mask.
300 */
301static inline void ipi_send_mask(unsigned int op, const struct cpumask mask)
302{
303    int cpu;
304    for_each_cpu_mask(cpu, mask) {
305        ipi_send(cpu, op);
306    }
307}
308
309/*
310 * ipi_send_allbutself()
311 * Send an IPI to all threads but ourselves.
312 */
313static inline void ipi_send_allbutself(unsigned int op)
314{
315    int self = smp_processor_id();
316    struct cpumask result;
317    cpumask_copy(&result, &cpu_online_map);
318    cpu_clear(self, result);
319    ipi_send_mask(op, result);
320}
321
322/*
323 * smp_enable_vector()
324 */
325static void smp_enable_vector(unsigned int irq)
326{
327    ubicom32_clear_interrupt(smp_ipi_irq);
328    ldsr_enable_vector(irq);
329}
330
331/*
332 * smp_disable_vector()
333 * Disable the interrupt by clearing the appropriate bit in the
334 * LDSR Mask Register.
335 */
336static void smp_disable_vector(unsigned int irq)
337{
338    ldsr_disable_vector(irq);
339}
340
341/*
342 * smp_mask_vector()
343 */
344static void smp_mask_vector(unsigned int irq)
345{
346    ldsr_mask_vector(irq);
347}
348
349/*
350 * smp_unmask_vector()
351 */
352static void smp_unmask_vector(unsigned int irq)
353{
354    ldsr_unmask_vector(irq);
355}
356
357/*
358 * smp_end_vector()
359 * Called once an interrupt is completed (reset the LDSR mask).
360 */
361static void smp_end_vector(unsigned int irq)
362{
363    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, smp_processor_id());
364    spin_lock(&smp_ipi_lock);
365    smp_inside_ipi &= ~(1 << p->tid);
366    if (smp_inside_ipi) {
367        spin_unlock(&smp_ipi_lock);
368        return;
369    }
370    spin_unlock(&smp_ipi_lock);
371    ldsr_unmask_vector(irq);
372    smp_debug(100, KERN_INFO "cpu[%d]: unamesk vector\n", smp_processor_id());
373}
374
375/*
376 * Special hanlder functions for SMP.
377 */
378static struct irq_chip ubicom32_smp_chip = {
379    .name = "UbicoIPI",
380    .startup = NULL,
381    .shutdown = NULL,
382    .enable = smp_enable_vector,
383    .disable = smp_disable_vector,
384    .ack = NULL,
385    .mask = smp_mask_vector,
386    .unmask = smp_unmask_vector,
387    .end = smp_end_vector,
388};
389
390/*
391 * smp_reset_ipi()
392 * None of these cpu(s) got their IPI, turn it back on.
393 *
394 * Note: This is called by the LDSR which is not a full
395 * Linux cpu. Thus you must use the raw form of locks
396 * because lock debugging will not work on the partial
397 * cpu nature of the LDSR.
398 */
399void smp_reset_ipi(unsigned long mask)
400{
401    __raw_spin_lock(&smp_ipi_lock.raw_lock);
402    smp_needs_ipi |= mask;
403    smp_inside_ipi &= ~mask;
404    ubicom32_set_interrupt(smp_ipi_irq);
405    __raw_spin_unlock(&smp_ipi_lock.raw_lock);
406    smp_debug(100, KERN_INFO "smp: reset IPIs for: 0x%x\n", mask);
407}
408
409/*
410 * smp_get_affinity()
411 * Choose the thread affinity for this interrupt.
412 *
413 * Note: This is called by the LDSR which is not a full
414 * Linux cpu. Thus you must use the raw form of locks
415 * because lock debugging will not work on the partial
416 * cpu nature of the LDSR.
417 */
418unsigned long smp_get_affinity(unsigned int irq, int *all)
419{
420    unsigned long mask = 0;
421
422    /*
423     * Most IRQ(s) are delivered in a round robin fashion.
424     */
425    if (irq != smp_ipi_irq) {
426        unsigned long result = smp_irq_affinity[irq] & smp_online_threads;
427        DEBUG_ASSERT(result);
428        *all = 0;
429        return result;
430    }
431
432    /*
433     * This is an IPI request. Return all cpu(s) scheduled for an IPI.
434     * We also track those cpu(s) that are going to be "receiving" IPI this
435     * round. When all CPU(s) have called smp_end_vector(),
436     * we will unmask the IPI interrupt.
437     */
438    __raw_spin_lock(&smp_ipi_lock.raw_lock);
439    ubicom32_clear_interrupt(smp_ipi_irq);
440    if (smp_needs_ipi) {
441        mask = smp_needs_ipi;
442        smp_inside_ipi |= smp_needs_ipi;
443        smp_needs_ipi = 0;
444    }
445    __raw_spin_unlock(&smp_ipi_lock.raw_lock);
446    *all = 1;
447    return mask;
448}
449
450/*
451 * smp_set_affinity()
452 * Set the affinity for this irq but store the value in tid(s).
453 */
454void smp_set_affinity(unsigned int irq, const struct cpumask *dest)
455{
456    int cpuid;
457    unsigned long *paffinity = &smp_irq_affinity[irq];
458
459    /*
460     * If none specified, all cpus are allowed.
461     */
462    if (cpus_empty(*dest)) {
463        *paffinity = 0xffffffff;
464        return;
465    }
466
467    /*
468     * Make sure to clear the old value before setting up the
469     * list.
470     */
471    *paffinity = 0;
472    for_each_cpu_mask(cpuid, *dest) {
473        struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
474        *paffinity |= (1 << p->tid);
475    }
476}
477
478/*
479 * smp_send_stop()
480 * Send a stop request to all CPU but this one.
481 */
482void smp_send_stop(void)
483{
484    ipi_send_allbutself(IPI_CPU_STOP);
485}
486
487/*
488 * smp_send_timer_all()
489 * Send all cpu(s) but this one, a request to update times.
490 */
491void smp_send_timer_all(void)
492{
493    ipi_send_allbutself(IPI_CPU_TIMER);
494}
495
496/*
497 * smp_timer_broadcast()
498 * Use an IPI to broadcast a timer message
499 */
500void smp_timer_broadcast(const struct cpumask *mask)
501{
502    ipi_send_mask(IPI_CPU_TIMER, *mask);
503}
504
505/*
506 * smp_send_reschedule()
507 * Send a reschedule request to the specified cpu.
508 */
509void smp_send_reschedule(int cpu)
510{
511    ipi_send(cpu, IPI_RESCHEDULE);
512}
513
514/*
515 * arch_send_call_function_ipi()
516 * Cause each cpu in the mask to call the generic function handler.
517 */
518void arch_send_call_function_ipi_mask(const struct cpumask *mask)
519{
520    int cpu;
521    for_each_cpu_mask(cpu, *mask) {
522        ipi_send(cpu, IPI_CALL_FUNC);
523    }
524}
525
526/*
527 * arch_send_call_function_single_ipi()
528 * Cause the specified cpu to call the generic function handler.
529 */
530void arch_send_call_function_single_ipi(int cpu)
531{
532    ipi_send(cpu, IPI_CALL_FUNC_SINGLE);
533}
534
535/*
536 * setup_profiling_timer()
537 * Dummy function created to keep Oprofile happy in the SMP case.
538 */
539int setup_profiling_timer(unsigned int multiplier)
540{
541    return 0;
542}
543
544/*
545 * smp_mainline_start()
546 * Start a slave thread executing a mainline Linux context.
547 */
548static void __init smp_mainline_start(void *arg)
549{
550    int cpuid = smp_processor_id();
551    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
552
553    BUG_ON(p->tid != thread_get_self());
554
555    /*
556     * Well, support 2.4 linux scheme as well.
557     */
558    if (cpu_test_and_set(cpuid, cpu_online_map)) {
559        printk(KERN_CRIT "cpu[%d]: already initialized!\n", cpuid);
560        smp_halt_processor();
561        return;
562    }
563
564    /*
565     * Initialise the idle task for this CPU
566     */
567    atomic_inc(&init_mm.mm_count);
568    current->active_mm = &init_mm;
569    if (current->mm) {
570        printk(KERN_CRIT "cpu[%d]: idle task already has memory "
571               "management\n", cpuid);
572        smp_halt_processor();
573        return;
574    }
575
576    /*
577     * TODO: X86 does this prior to calling notify, try to understand why?
578     */
579    preempt_disable();
580
581#if defined(CONFIG_GENERIC_CLOCKEVENTS)
582    /*
583     * Setup a local timer event so that this cpu will get timer interrupts
584     */
585    if (local_timer_setup(cpuid) == -1) {
586        printk(KERN_CRIT "cpu[%d]: timer alloc failed\n", cpuid);
587        smp_halt_processor();
588        return;
589    }
590#endif
591
592    /*
593     * Notify those interested that we are up and alive. This must
594     * be done before interrupts are enabled. It must also be completed
595     * before the bootstrap cpu returns from __cpu_up() (see comment
596     * above cpu_set() of the cpu_online_map).
597     */
598    notify_cpu_starting(cpuid);
599
600    /*
601     * Indicate that this thread is now online and present. Setting
602     * cpu_online_map has the side effect of allowing the bootstrap
603     * cpu to continue along; so anything that MUST be done prior to the
604     * bootstrap cpu returning from __cpu_up() needs to go above here.
605     */
606    cpu_set(cpuid, cpu_online_map);
607    cpu_set(cpuid, cpu_present_map);
608
609    /*
610     * Maintain a thread mapping in addition to the cpu mapping.
611     */
612    smp_online_threads |= (1 << p->tid);
613
614    /*
615     * Enable interrupts for this thread.
616     */
617    local_irq_enable();
618
619    /*
620     * Enter the idle loop and wait for a timer to schedule some work.
621     */
622    printk(KERN_INFO "cpu[%d]: entering cpu_idle()\n", cpuid);
623    cpu_idle();
624
625    /* Not Reached */
626}
627
628/*
629 * smp_cpus_done()
630 * Called once the kernel_init() has brought up all cpu(s).
631 */
632void smp_cpus_done(unsigned int cpu_max)
633{
634    /* Do Nothing */
635}
636
637/*
638 * __cpu_up()
639 * Called to startup a sepcific cpu.
640 */
641int __cpuinit __cpu_up(unsigned int cpu)
642{
643    struct task_struct *idle;
644    unsigned int *stack;
645    long timeout;
646    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu);
647
648    /*
649     * Create an idle task for this CPU.
650     */
651    idle = fork_idle(cpu);
652    if (IS_ERR(idle)) {
653        panic("cpu[%d]: fork failed\n", cpu);
654        return -ENOSYS;
655    }
656    task_thread_info(idle)->cpu = cpu;
657
658    /*
659     * Setup the sw_ksp[] to point to this new task.
660     */
661    sw_ksp[p->tid] = (unsigned int)idle->stack;
662    stack = (unsigned int *)(sw_ksp[p->tid] + PAGE_SIZE - 8);
663
664    /*
665     * Cause the specified thread to execute our smp_mainline_start
666     * function as a TYPE_NORMAL thread.
667     */
668    printk(KERN_INFO "cpu[%d]: launching mainline Linux thread\n", cpu);
669    if (thread_start(p->tid, smp_mainline_start, (void *)NULL, stack,
670             THREAD_TYPE_NORMAL) == -1) {
671        printk(KERN_WARNING "cpu[%d]: failed thread_start\n", cpu);
672        return -ENOSYS;
673    }
674
675    /*
676     * Wait for the thread to start up. The thread will set
677     * the online bit when it is running. Our caller execpts the
678     * cpu to be online if we return 0.
679     */
680    for (timeout = 0; timeout < 10000; timeout++) {
681        if (cpu_online(cpu)) {
682            break;
683        }
684
685        udelay(100);
686        barrier();
687        continue;
688    }
689
690    if (!cpu_online(cpu)) {
691        printk(KERN_CRIT "cpu[%d]: failed to live after %ld us\n",
692               cpu, timeout * 100);
693        return -ENOSYS;
694    }
695
696    printk(KERN_INFO "cpu[%d]: came alive after %ld us\n",
697           cpu, timeout * 100);
698    return 0;
699}
700
701/*
702 * Data used by setup_irq for the IPI.
703 */
704static struct irqaction ipi_irq = {
705    .name = "ipi",
706    .flags = IRQF_DISABLED | IRQF_PERCPU,
707    .handler = ipi_interrupt,
708};
709
710/*
711 * smp_prepare_cpus()
712 * Mark threads that are available to Linux as possible cpus(s).
713 */
714void __init smp_prepare_cpus(unsigned int max_cpus)
715{
716    int i;
717
718    /*
719     * We will need a software IRQ to send IPI(s). We will use
720     * a single software IRQ for all IPI(s).
721     */
722    if (irq_soft_alloc(&smp_ipi_irq) < 0) {
723        panic("no software IRQ is available\n");
724        return;
725    }
726
727    /*
728     * For the IPI interrupt, we want to use our own chip definition.
729     * This allows us to define what happens in SMP IPI without affecting
730     * the performance of the other interrupts.
731     *
732     * Next, Register the IPI interrupt function against the soft IRQ.
733     */
734    set_irq_chip(smp_ipi_irq, &ubicom32_smp_chip);
735    setup_irq(smp_ipi_irq, &ipi_irq);
736
737    /*
738     * We use the device tree node to determine how many
739     * free cpus we will have (up to NR_CPUS) and we indicate
740     * that those cpus are present.
741     *
742     * We need to do this very early in the SMP case
743     * because the Linux init code uses the cpu_present_map.
744     */
745    for_each_possible_cpu(i) {
746        thread_t tid;
747        struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, i);
748
749        /*
750         * Skip the bootstrap cpu
751         */
752        if (i == 0) {
753            continue;
754        }
755
756        /*
757         * If we have a free thread left in the mask,
758         * indicate that the cpu is present.
759         */
760        tid = thread_alloc();
761        if (tid == (thread_t)-1) {
762            break;
763        }
764
765        /*
766         * Save the hardware thread id for this cpu.
767         */
768        p->tid = tid;
769        cpu_set(i, cpu_present_map);
770        printk(KERN_INFO "cpu[%d]: added to cpu_present_map - tid: %d\n", i, tid);
771    }
772}
773
774/*
775 * smp_prepare_boot_cpu()
776 * Copy the per_cpu data into the appropriate spot for the bootstrap cpu.
777 *
778 * The code in boot_cpu_init() has already set the boot cpu's
779 * state in the possible, present, and online maps.
780 */
781void __devinit smp_prepare_boot_cpu(void)
782{
783    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0);
784
785    smp_online_threads |= (1 << p->tid);
786    printk(KERN_INFO "cpu[%d]: bootstrap CPU online - tid: %ld\n",
787            current_thread_info()->cpu, p->tid);
788}
789
790/*
791 * smp_setup_processor_id()
792 * Set the current_thread_info() structure cpu value.
793 *
794 * We set the value to the true hardware thread value that we are running on.
795 * NOTE: this function overrides the weak alias function in main.c
796 */
797void __init smp_setup_processor_id(void)
798{
799    struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0);
800    int i;
801    for_each_cpu_mask(i, CPU_MASK_ALL)
802        set_cpu_possible(i, true);
803
804    current_thread_info()->cpu = 0;
805    p->tid = thread_get_self();
806}
807

Archive Download this file



interactive