1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/module.h>
26#include <linux/acpi.h>
27#include <linux/bootmem.h>
28#include <linux/cpu.h>
29#include <linux/delay.h>
30#include <linux/init.h>
31#include <linux/interrupt.h>
32#include <linux/irq.h>
33#include <linux/kernel.h>
34#include <linux/kernel_stat.h>
35#include <linux/mm.h>
36#include <linux/notifier.h>
37#include <linux/smp.h>
38#include <linux/spinlock.h>
39#include <linux/efi.h>
40#include <linux/percpu.h>
41#include <linux/bitops.h>
42
43#include <asm/atomic.h>
44#include <asm/cache.h>
45#include <asm/current.h>
46#include <asm/delay.h>
47#include <asm/ia32.h>
48#include <asm/io.h>
49#include <asm/irq.h>
50#include <asm/machvec.h>
51#include <asm/mca.h>
52#include <asm/page.h>
53#include <asm/paravirt.h>
54#include <asm/pgalloc.h>
55#include <asm/pgtable.h>
56#include <asm/processor.h>
57#include <asm/ptrace.h>
58#include <asm/sal.h>
59#include <asm/system.h>
60#include <asm/tlbflush.h>
61#include <asm/unistd.h>
62#include <asm/sn/arch.h>
63
64#define SMP_DEBUG 0
65
66#if SMP_DEBUG
67#define Dprintk(x...) printk(x)
68#else
69#define Dprintk(x...)
70#endif
71
72#ifdef CONFIG_HOTPLUG_CPU
73#ifdef CONFIG_PERMIT_BSP_REMOVE
74#define bsp_remove_ok 1
75#else
76#define bsp_remove_ok 0
77#endif
78
79
80
81
82
83
84struct task_struct *idle_thread_array[NR_CPUS];
85
86
87
88
89struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS];
90
91
92
93
94
95struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0];
96
97#define set_brendez_area(x) (sal_state_for_booting_cpu = &sal_boot_rendez_state[(x)]);
98
99#define get_idle_for_cpu(x) (idle_thread_array[(x)])
100#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p))
101
102#else
103
104#define get_idle_for_cpu(x) (NULL)
105#define set_idle_for_cpu(x,p)
106#define set_brendez_area(x)
107#endif
108
109
110
111
112
113#define MASTER (0)
114#define SLAVE (SMP_CACHE_BYTES/8)
115
116#define NUM_ROUNDS 64
117#define NUM_ITERS 5
118
119static DEFINE_SPINLOCK(itc_sync_lock);
120static volatile unsigned long go[SLAVE + 1];
121
122#define DEBUG_ITC_SYNC 0
123
124extern void start_ap (void);
125extern unsigned long ia64_iobase;
126
127struct task_struct *task_for_booting_cpu;
128
129
130
131
132DEFINE_PER_CPU(int, cpu_state);
133
134cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
135EXPORT_SYMBOL(cpu_core_map);
136DEFINE_PER_CPU_SHARED_ALIGNED(cpumask_t, cpu_sibling_map);
137EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
138
139int smp_num_siblings = 1;
140
141
142volatile int ia64_cpu_to_sapicid[NR_CPUS];
143EXPORT_SYMBOL(ia64_cpu_to_sapicid);
144
145static volatile cpumask_t cpu_callin_map;
146
147struct smp_boot_data smp_boot_data __initdata;
148
149unsigned long ap_wakeup_vector = -1;
150
151char __initdata no_int_routing;
152
153unsigned char smp_int_redirect;
154
155#ifdef CONFIG_FORCE_CPEI_RETARGET
156#define CPEI_OVERRIDE_DEFAULT (1)
157#else
158#define CPEI_OVERRIDE_DEFAULT (0)
159#endif
160
161unsigned int force_cpei_retarget = CPEI_OVERRIDE_DEFAULT;
162
163static int __init
164cmdl_force_cpei(char *str)
165{
166 int value=0;
167
168 get_option (&str, &value);
169 force_cpei_retarget = value;
170
171 return 1;
172}
173
174__setup("force_cpei=", cmdl_force_cpei);
175
176static int __init
177nointroute (char *str)
178{
179 no_int_routing = 1;
180 printk ("no_int_routing on\n");
181 return 1;
182}
183
184__setup("nointroute", nointroute);
185
186static void fix_b0_for_bsp(void)
187{
188#ifdef CONFIG_HOTPLUG_CPU
189 int cpuid;
190 static int fix_bsp_b0 = 1;
191
192 cpuid = smp_processor_id();
193
194
195
196
197 if (!(fix_bsp_b0 && cpuid))
198 return;
199
200 sal_boot_rendez_state[0].br[0] = sal_boot_rendez_state[cpuid].br[0];
201 printk ("Fixed BSP b0 value from CPU %d\n", cpuid);
202
203 fix_bsp_b0 = 0;
204#endif
205}
206
207void
208sync_master (void *arg)
209{
210 unsigned long flags, i;
211
212 go[MASTER] = 0;
213
214 local_irq_save(flags);
215 {
216 for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) {
217 while (!go[MASTER])
218 cpu_relax();
219 go[MASTER] = 0;
220 go[SLAVE] = ia64_get_itc();
221 }
222 }
223 local_irq_restore(flags);
224}
225
226
227
228
229
230
231static inline long
232get_delta (long *rt, long *master)
233{
234 unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0;
235 unsigned long tcenter, t0, t1, tm;
236 long i;
237
238 for (i = 0; i < NUM_ITERS; ++i) {
239 t0 = ia64_get_itc();
240 go[MASTER] = 1;
241 while (!(tm = go[SLAVE]))
242 cpu_relax();
243 go[SLAVE] = 0;
244 t1 = ia64_get_itc();
245
246 if (t1 - t0 < best_t1 - best_t0)
247 best_t0 = t0, best_t1 = t1, best_tm = tm;
248 }
249
250 *rt = best_t1 - best_t0;
251 *master = best_tm - best_t0;
252
253
254 tcenter = (best_t0/2 + best_t1/2);
255 if (best_t0 % 2 + best_t1 % 2 == 2)
256 ++tcenter;
257 return tcenter - best_tm;
258}
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292void
293ia64_sync_itc (unsigned int master)
294{
295 long i, delta, adj, adjust_latency = 0, done = 0;
296 unsigned long flags, rt, master_time_stamp, bound;
297#if DEBUG_ITC_SYNC
298 struct {
299 long rt;
300 long master;
301 long diff;
302 long lat;
303 } t[NUM_ROUNDS];
304#endif
305
306
307
308
309
310
311
312 BUG_ON((ia64_get_itv() & (1 << 16)) == 0);
313
314 go[MASTER] = 1;
315
316 if (smp_call_function_single(master, sync_master, NULL, 0) < 0) {
317 printk(KERN_ERR "sync_itc: failed to get attention of CPU %u!\n", master);
318 return;
319 }
320
321 while (go[MASTER])
322 cpu_relax();
323
324 spin_lock_irqsave(&itc_sync_lock, flags);
325 {
326 for (i = 0; i < NUM_ROUNDS; ++i) {
327 delta = get_delta(&rt, &master_time_stamp);
328 if (delta == 0) {
329 done = 1;
330 bound = rt;
331 }
332
333 if (!done) {
334 if (i > 0) {
335 adjust_latency += -delta;
336 adj = -delta + adjust_latency/4;
337 } else
338 adj = -delta;
339
340 ia64_set_itc(ia64_get_itc() + adj);
341 }
342#if DEBUG_ITC_SYNC
343 t[i].rt = rt;
344 t[i].master = master_time_stamp;
345 t[i].diff = delta;
346 t[i].lat = adjust_latency/4;
347#endif
348 }
349 }
350 spin_unlock_irqrestore(&itc_sync_lock, flags);
351
352#if DEBUG_ITC_SYNC
353 for (i = 0; i < NUM_ROUNDS; ++i)
354 printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",
355 t[i].rt, t[i].master, t[i].diff, t[i].lat);
356#endif
357
358 printk(KERN_INFO "CPU %d: synchronized ITC with CPU %u (last diff %ld cycles, "
359 "maxerr %lu cycles)\n", smp_processor_id(), master, delta, rt);
360}
361
362
363
364
365static inline void __devinit
366smp_setup_percpu_timer (void)
367{
368}
369
370static void __cpuinit
371smp_callin (void)
372{
373 int cpuid, phys_id, itc_master;
374 struct cpuinfo_ia64 *last_cpuinfo, *this_cpuinfo;
375 extern void ia64_init_itm(void);
376 extern volatile int time_keeper_id;
377
378#ifdef CONFIG_PERFMON
379 extern void pfm_init_percpu(void);
380#endif
381
382 cpuid = smp_processor_id();
383 phys_id = hard_smp_processor_id();
384 itc_master = time_keeper_id;
385
386 if (cpu_online(cpuid)) {
387 printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n",
388 phys_id, cpuid);
389 BUG();
390 }
391
392 fix_b0_for_bsp();
393
394 ipi_call_lock_irq();
395 spin_lock(&vector_lock);
396
397 __setup_vector_irq(cpuid);
398 notify_cpu_starting(cpuid);
399 cpu_set(cpuid, cpu_online_map);
400 per_cpu(cpu_state, cpuid) = CPU_ONLINE;
401 spin_unlock(&vector_lock);
402 ipi_call_unlock_irq();
403
404 smp_setup_percpu_timer();
405
406 ia64_mca_cmc_vector_setup();
407
408#ifdef CONFIG_PERFMON
409 pfm_init_percpu();
410#endif
411
412 local_irq_enable();
413
414 if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
415
416
417
418
419
420
421 Dprintk("Going to syncup ITC with ITC Master.\n");
422 ia64_sync_itc(itc_master);
423 }
424
425
426
427
428 ia64_init_itm();
429
430
431
432
433
434 last_cpuinfo = cpu_data(cpuid - 1);
435 this_cpuinfo = local_cpu_data;
436 if (last_cpuinfo->itc_freq != this_cpuinfo->itc_freq ||
437 last_cpuinfo->proc_freq != this_cpuinfo->proc_freq ||
438 last_cpuinfo->features != this_cpuinfo->features ||
439 last_cpuinfo->revision != this_cpuinfo->revision ||
440 last_cpuinfo->family != this_cpuinfo->family ||
441 last_cpuinfo->archrev != this_cpuinfo->archrev ||
442 last_cpuinfo->model != this_cpuinfo->model)
443 calibrate_delay();
444 local_cpu_data->loops_per_jiffy = loops_per_jiffy;
445
446#ifdef CONFIG_IA32_SUPPORT
447 ia32_gdt_init();
448#endif
449
450
451
452
453 cpu_set(cpuid, cpu_callin_map);
454 Dprintk("Stack on CPU %d at about %p\n",cpuid, &cpuid);
455}
456
457
458
459
460
461int __cpuinit
462start_secondary (void *unused)
463{
464
465 ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase));
466#ifndef CONFIG_PRINTK_TIME
467 Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
468#endif
469 efi_map_pal_code();
470 cpu_init();
471 preempt_disable();
472 smp_callin();
473
474 cpu_idle();
475 return 0;
476}
477
478struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
479{
480 return NULL;
481}
482
483struct create_idle {
484 struct work_struct work;
485 struct task_struct *idle;
486 struct completion done;
487 int cpu;
488};
489
490void __cpuinit
491do_fork_idle(struct work_struct *work)
492{
493 struct create_idle *c_idle =
494 container_of(work, struct create_idle, work);
495
496 c_idle->idle = fork_idle(c_idle->cpu);
497 complete(&c_idle->done);
498}
499
500static int __cpuinit
501do_boot_cpu (int sapicid, int cpu)
502{
503 int timeout;
504 struct create_idle c_idle = {
505 .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle),
506 .cpu = cpu,
507 .done = COMPLETION_INITIALIZER(c_idle.done),
508 };
509
510 c_idle.idle = get_idle_for_cpu(cpu);
511 if (c_idle.idle) {
512 init_idle(c_idle.idle, cpu);
513 goto do_rest;
514 }
515
516
517
518
519 if (!keventd_up() || current_is_keventd())
520 c_idle.work.func(&c_idle.work);
521 else {
522 schedule_work(&c_idle.work);
523 wait_for_completion(&c_idle.done);
524 }
525
526 if (IS_ERR(c_idle.idle))
527 panic("failed fork for CPU %d", cpu);
528
529 set_idle_for_cpu(cpu, c_idle.idle);
530
531do_rest:
532 task_for_booting_cpu = c_idle.idle;
533
534 Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
535
536 set_brendez_area(cpu);
537 platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
538
539
540
541
542 Dprintk("Waiting on callin_map ...");
543 for (timeout = 0; timeout < 100000; timeout++) {
544 if (cpu_isset(cpu, cpu_callin_map))
545 break;
546 udelay(100);
547 }
548 Dprintk("\n");
549
550 if (!cpu_isset(cpu, cpu_callin_map)) {
551 printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid);
552 ia64_cpu_to_sapicid[cpu] = -1;
553 cpu_clear(cpu, cpu_online_map);
554 return -EINVAL;
555 }
556 return 0;
557}
558
559static int __init
560decay (char *str)
561{
562 int ticks;
563 get_option (&str, &ticks);
564 return 1;
565}
566
567__setup("decay=", decay);
568
569
570
571
572void __init
573smp_build_cpu_map (void)
574{
575 int sapicid, cpu, i;
576 int boot_cpu_id = hard_smp_processor_id();
577
578 for (cpu = 0; cpu < NR_CPUS; cpu++) {
579 ia64_cpu_to_sapicid[cpu] = -1;
580 }
581
582 ia64_cpu_to_sapicid[0] = boot_cpu_id;
583 cpus_clear(cpu_present_map);
584 set_cpu_present(0, true);
585 set_cpu_possible(0, true);
586 for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
587 sapicid = smp_boot_data.cpu_phys_id[i];
588 if (sapicid == boot_cpu_id)
589 continue;
590 set_cpu_present(cpu, true);
591 set_cpu_possible(cpu, true);
592 ia64_cpu_to_sapicid[cpu] = sapicid;
593 cpu++;
594 }
595}
596
597
598
599
600void __init
601smp_prepare_cpus (unsigned int max_cpus)
602{
603 int boot_cpu_id = hard_smp_processor_id();
604
605
606
607
608
609 smp_setup_percpu_timer();
610
611
612
613
614 cpu_set(0, cpu_online_map);
615 cpu_set(0, cpu_callin_map);
616
617 local_cpu_data->loops_per_jiffy = loops_per_jiffy;
618 ia64_cpu_to_sapicid[0] = boot_cpu_id;
619
620 printk(KERN_INFO "Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id);
621
622 current_thread_info()->cpu = 0;
623
624
625
626
627 if (!max_cpus) {
628 printk(KERN_INFO "SMP mode deactivated.\n");
629 init_cpu_online(cpumask_of(0));
630 init_cpu_present(cpumask_of(0));
631 init_cpu_possible(cpumask_of(0));
632 return;
633 }
634}
635
636void __devinit smp_prepare_boot_cpu(void)
637{
638 cpu_set(smp_processor_id(), cpu_online_map);
639 cpu_set(smp_processor_id(), cpu_callin_map);
640 per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
641 paravirt_post_smp_prepare_boot_cpu();
642}
643
644#ifdef CONFIG_HOTPLUG_CPU
645static inline void
646clear_cpu_sibling_map(int cpu)
647{
648 int i;
649
650 for_each_cpu_mask(i, per_cpu(cpu_sibling_map, cpu))
651 cpu_clear(cpu, per_cpu(cpu_sibling_map, i));
652 for_each_cpu_mask(i, cpu_core_map[cpu])
653 cpu_clear(cpu, cpu_core_map[i]);
654
655 per_cpu(cpu_sibling_map, cpu) = cpu_core_map[cpu] = CPU_MASK_NONE;
656}
657
658static void
659remove_siblinginfo(int cpu)
660{
661 int last = 0;
662
663 if (cpu_data(cpu)->threads_per_core == 1 &&
664 cpu_data(cpu)->cores_per_socket == 1) {
665 cpu_clear(cpu, cpu_core_map[cpu]);
666 cpu_clear(cpu, per_cpu(cpu_sibling_map, cpu));
667 return;
668 }
669
670 last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0);
671
672
673 clear_cpu_sibling_map(cpu);
674}
675
676extern void fixup_irqs(void);
677
678int migrate_platform_irqs(unsigned int cpu)
679{
680 int new_cpei_cpu;
681 struct irq_desc *desc = NULL;
682 const struct cpumask *mask;
683 int retval = 0;
684
685
686
687
688 if (cpe_vector > 0 && is_cpu_cpei_target(cpu)) {
689 printk ("CPU (%d) is CPEI Target\n", cpu);
690 if (can_cpei_retarget()) {
691
692
693
694 new_cpei_cpu = any_online_cpu(cpu_online_map);
695 mask = cpumask_of(new_cpei_cpu);
696 set_cpei_target_cpu(new_cpei_cpu);
697 desc = irq_desc + ia64_cpe_irq;
698
699
700
701
702
703 if (desc) {
704 desc->chip->disable(ia64_cpe_irq);
705 desc->chip->set_affinity(ia64_cpe_irq, mask);
706 desc->chip->enable(ia64_cpe_irq);
707 printk ("Re-targetting CPEI to cpu %d\n", new_cpei_cpu);
708 }
709 }
710 if (!desc) {
711 printk ("Unable to retarget CPEI, offline cpu [%d] failed\n", cpu);
712 retval = -EBUSY;
713 }
714 }
715 return retval;
716}
717
718
719int __cpu_disable(void)
720{
721 int cpu = smp_processor_id();
722
723
724
725
726 if (cpu == 0 && !bsp_remove_ok) {
727 printk ("Your platform does not support removal of BSP\n");
728 return (-EBUSY);
729 }
730
731 if (ia64_platform_is("sn2")) {
732 if (!sn_cpu_disable_allowed(cpu))
733 return -EBUSY;
734 }
735
736 cpu_clear(cpu, cpu_online_map);
737
738 if (migrate_platform_irqs(cpu)) {
739 cpu_set(cpu, cpu_online_map);
740 return -EBUSY;
741 }
742
743 remove_siblinginfo(cpu);
744 fixup_irqs();
745 local_flush_tlb_all();
746 cpu_clear(cpu, cpu_callin_map);
747 return 0;
748}
749
750void __cpu_die(unsigned int cpu)
751{
752 unsigned int i;
753
754 for (i = 0; i < 100; i++) {
755
756 if (per_cpu(cpu_state, cpu) == CPU_DEAD)
757 {
758 printk ("CPU %d is now offline\n", cpu);
759 return;
760 }
761 msleep(100);
762 }
763 printk(KERN_ERR "CPU %u didn't die...\n", cpu);
764}
765#endif
766
767void
768smp_cpus_done (unsigned int dummy)
769{
770 int cpu;
771 unsigned long bogosum = 0;
772
773
774
775
776
777 for_each_online_cpu(cpu) {
778 bogosum += cpu_data(cpu)->loops_per_jiffy;
779 }
780
781 printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
782 (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
783}
784
785static inline void __devinit
786set_cpu_sibling_map(int cpu)
787{
788 int i;
789
790 for_each_online_cpu(i) {
791 if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) {
792 cpu_set(i, cpu_core_map[cpu]);
793 cpu_set(cpu, cpu_core_map[i]);
794 if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) {
795 cpu_set(i, per_cpu(cpu_sibling_map, cpu));
796 cpu_set(cpu, per_cpu(cpu_sibling_map, i));
797 }
798 }
799 }
800}
801
802int __cpuinit
803__cpu_up (unsigned int cpu)
804{
805 int ret;
806 int sapicid;
807
808 sapicid = ia64_cpu_to_sapicid[cpu];
809 if (sapicid == -1)
810 return -EINVAL;
811
812
813
814
815
816 if (cpu_isset(cpu, cpu_callin_map))
817 return -EINVAL;
818
819 per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
820
821 ret = do_boot_cpu(sapicid, cpu);
822 if (ret < 0)
823 return ret;
824
825 if (cpu_data(cpu)->threads_per_core == 1 &&
826 cpu_data(cpu)->cores_per_socket == 1) {
827 cpu_set(cpu, per_cpu(cpu_sibling_map, cpu));
828 cpu_set(cpu, cpu_core_map[cpu]);
829 return 0;
830 }
831
832 set_cpu_sibling_map(cpu);
833
834 return 0;
835}
836
837
838
839
840
841
842
843void __init
844init_smp_config(void)
845{
846 struct fptr {
847 unsigned long fp;
848 unsigned long gp;
849 } *ap_startup;
850 long sal_ret;
851
852
853 ap_startup = (struct fptr *) start_ap;
854 sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
855 ia64_tpa(ap_startup->fp), ia64_tpa(ap_startup->gp), 0, 0, 0, 0);
856 if (sal_ret < 0)
857 printk(KERN_ERR "SMP: Can't set SAL AP Boot Rendezvous: %s\n",
858 ia64_sal_strerror(sal_ret));
859}
860
861
862
863
864
865void __devinit
866identify_siblings(struct cpuinfo_ia64 *c)
867{
868 long status;
869 u16 pltid;
870 pal_logical_to_physical_t info;
871
872 status = ia64_pal_logical_to_phys(-1, &info);
873 if (status != PAL_STATUS_SUCCESS) {
874 if (status != PAL_STATUS_UNIMPLEMENTED) {
875 printk(KERN_ERR
876 "ia64_pal_logical_to_phys failed with %ld\n",
877 status);
878 return;
879 }
880
881 info.overview_ppid = 0;
882 info.overview_cpp = 1;
883 info.overview_tpc = 1;
884 }
885
886 status = ia64_sal_physical_id_info(&pltid);
887 if (status != PAL_STATUS_SUCCESS) {
888 if (status != PAL_STATUS_UNIMPLEMENTED)
889 printk(KERN_ERR
890 "ia64_sal_pltid failed with %ld\n",
891 status);
892 return;
893 }
894
895 c->socket_id = (pltid << 8) | info.overview_ppid;
896
897 if (info.overview_cpp == 1 && info.overview_tpc == 1)
898 return;
899
900 c->cores_per_socket = info.overview_cpp;
901 c->threads_per_core = info.overview_tpc;
902 c->num_log = info.overview_num_log;
903
904 c->core_id = info.log1_cid;
905 c->thread_id = info.log1_tid;
906}
907
908
909
910
911
912
913
914int is_multithreading_enabled(void)
915{
916 int i, j;
917
918 for_each_present_cpu(i) {
919 for_each_present_cpu(j) {
920 if (j == i)
921 continue;
922 if ((cpu_data(j)->socket_id == cpu_data(i)->socket_id)) {
923 if (cpu_data(j)->core_id == cpu_data(i)->core_id)
924 return 1;
925 }
926 }
927 }
928 return 0;
929}
930EXPORT_SYMBOL_GPL(is_multithreading_enabled);
931