File: /usr/src/linux/arch/s390/kernel/smp.c
1 /*
2 * arch/s390/kernel/smp.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * based on other smp stuff by
10 * (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
11 * (c) 1998 Ingo Molnar
12 *
13 * We work with logical cpu numbering everywhere we can. The only
14 * functions using the real cpu address (got from STAP) are the sigp
15 * functions. For all other functions we use the identity mapping.
16 * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is
17 * used e.g. to find the idle task belonging to a logical cpu. Every array
18 * in the kernel is sorted by the logical cpu number and not by the physical
19 * one which is causing all the confusion with __cpu_logical_map and
20 * cpu_number_map in other architectures.
21 */
22
23 #include <linux/module.h>
24 #include <linux/init.h>
25
26 #include <linux/mm.h>
27 #include <linux/spinlock.h>
28 #include <linux/kernel_stat.h>
29 #include <linux/smp_lock.h>
30
31 #include <linux/delay.h>
32
33 #include <asm/sigp.h>
34 #include <asm/pgalloc.h>
35 #include <asm/irq.h>
36 #include <asm/s390_ext.h>
37 #include <asm/cpcmd.h>
38
39 /* prototypes */
40 extern int cpu_idle(void * unused);
41
42 extern __u16 boot_cpu_addr;
43 extern volatile int __cpu_logical_map[];
44
45 /*
46 * An array with a pointer the lowcore of every CPU.
47 */
48 static int max_cpus = NR_CPUS; /* Setup configured maximum number of CPUs to activate */
49 int smp_num_cpus;
50 struct _lowcore *lowcore_ptr[NR_CPUS];
51 unsigned int prof_multiplier[NR_CPUS];
52 unsigned int prof_old_multiplier[NR_CPUS];
53 unsigned int prof_counter[NR_CPUS];
54 cycles_t cacheflush_time=0;
55 int smp_threads_ready=0; /* Set when the idlers are all forked. */
56 static atomic_t smp_commenced = ATOMIC_INIT(0);
57
58 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
59
60 /*
61 * Setup routine for controlling SMP activation
62 *
63 * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
64 * activation entirely (the MPS table probe still happens, though).
65 *
66 * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
67 * greater than 0, limits the maximum number of CPUs activated in
68 * SMP mode to <NUM>.
69 */
70
71 static int __init nosmp(char *str)
72 {
73 max_cpus = 0;
74 return 1;
75 }
76
77 __setup("nosmp", nosmp);
78
79 static int __init maxcpus(char *str)
80 {
81 get_option(&str, &max_cpus);
82 return 1;
83 }
84
85 __setup("maxcpus=", maxcpus);
86
87 /*
88 * Reboot, halt and power_off routines for SMP.
89 */
90 extern char vmhalt_cmd[];
91 extern char vmpoff_cmd[];
92
93 extern void reipl(unsigned long devno);
94
95 void do_machine_restart(void)
96 {
97 smp_send_stop();
98 reipl(S390_lowcore.ipl_device);
99 }
100
101 void machine_restart(char * __unused)
102 {
103 if (smp_processor_id() != 0) {
104 smp_ext_bitcall(0, ec_restart);
105 for (;;);
106 } else
107 do_machine_restart();
108 }
109
110 void do_machine_halt(void)
111 {
112 smp_send_stop();
113 if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
114 cpcmd(vmhalt_cmd, NULL, 0);
115 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
116 }
117
118 void machine_halt(void)
119 {
120 if (smp_processor_id() != 0) {
121 smp_ext_bitcall(0, ec_halt);
122 for (;;);
123 } else
124 do_machine_halt();
125 }
126
127 void do_machine_power_off(void)
128 {
129 smp_send_stop();
130 if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
131 cpcmd(vmpoff_cmd, NULL, 0);
132 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
133 }
134
135 void machine_power_off(void)
136 {
137 if (smp_processor_id() != 0) {
138 smp_ext_bitcall(0, ec_power_off);
139 for (;;);
140 } else
141 do_machine_power_off();
142 }
143
144 /*
145 * This is the main routine where commands issued by other
146 * cpus are handled.
147 */
148
149 void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
150 {
151 ec_ext_call *ec, *next;
152 int bits;
153
154 /*
155 * handle bit signal external calls
156 *
157 * For the ec_schedule signal we have to do nothing. All the work
158 * is done automatically when we return from the interrupt.
159 * For the ec_restart, ec_halt and ec_power_off we call the
160 * appropriate routine.
161 */
162 do {
163 bits = atomic_read(&S390_lowcore.ext_call_fast);
164 } while (atomic_compare_and_swap(bits,0,&S390_lowcore.ext_call_fast));
165
166 if (test_bit(ec_restart, &bits))
167 do_machine_restart();
168 if (test_bit(ec_halt, &bits))
169 do_machine_halt();
170 if (test_bit(ec_power_off, &bits))
171 do_machine_power_off();
172 if (test_bit(ec_ptlb, &bits))
173 local_flush_tlb();
174
175 /*
176 * Handle external call commands with a parameter area
177 */
178 do {
179 ec = (ec_ext_call *) atomic_read(&S390_lowcore.ext_call_queue);
180 } while (atomic_compare_and_swap((int) ec, 0,
181 &S390_lowcore.ext_call_queue));
182 if (ec == NULL)
183 return; /* no command signals */
184
185 /* Make a fifo out of the lifo */
186 next = ec->next;
187 ec->next = NULL;
188 while (next != NULL) {
189 ec_ext_call *tmp = next->next;
190 next->next = ec;
191 ec = next;
192 next = tmp;
193 }
194
195 /* Execute every sigp command on the queue */
196 while (ec != NULL) {
197 switch (ec->cmd) {
198 case ec_callback_async: {
199 void (*func)(void *info);
200 void *info;
201
202 func = ec->func;
203 info = ec->info;
204 atomic_set(&ec->status,ec_executing);
205 (func)(info);
206 return;
207 }
208 case ec_callback_sync:
209 atomic_set(&ec->status,ec_executing);
210 (ec->func)(ec->info);
211 atomic_set(&ec->status,ec_done);
212 return;
213 default:
214 }
215 ec = ec->next;
216 }
217 }
218
219 /*
220 * Send a callback sigp to another cpu.
221 */
222 sigp_ccode
223 smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait)
224 {
225 struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
226 sigp_ccode ccode;
227 ec_ext_call ec;
228
229 ec.cmd = wait ? ec_callback_sync : ec_callback_async;
230 atomic_set(&ec.status, ec_pending);
231 ec.func = func;
232 ec.info = info;
233 do {
234 ec.next = (ec_ext_call*) atomic_read(&lowcore->ext_call_queue);
235 } while (atomic_compare_and_swap((int) ec.next, (int)(&ec),
236 &lowcore->ext_call_queue));
237 /*
238 * We try once to deliver the signal. There are four possible
239 * return codes:
240 * 0) Order code accepted - can't show up on an external call
241 * 1) Status stored - fine, wait for completion.
242 * 2) Busy - there is another signal pending. Thats fine too, because
243 * do_ext_call from the pending signal will execute all signals on
244 * the queue. We wait for completion.
245 * 3) Not operational - something very bad has happened to the cpu.
246 * do not wait for completion.
247 */
248 ccode = signal_processor(cpu, sigp_external_call);
249
250 if (ccode != sigp_not_operational)
251 /* wait for completion, FIXME: possible seed of a deadlock */
252 while (atomic_read(&ec.status) != (wait?ec_done:ec_executing));
253
254 return ccode;
255 }
256
257 /*
258 * Send a callback sigp to every other cpu in the system.
259 */
260 void smp_ext_call_others(void (*func)(void *info), void *info, int wait)
261 {
262 struct _lowcore *lowcore;
263 ec_ext_call ec[NR_CPUS];
264 sigp_ccode ccode;
265 int i;
266
267 for (i = 0; i < smp_num_cpus; i++) {
268 if (smp_processor_id() == i)
269 continue;
270 lowcore = &get_cpu_lowcore(i);
271 ec[i].cmd = wait ? ec_callback_sync : ec_callback_async;
272 atomic_set(&ec[i].status, ec_pending);
273 ec[i].func = func;
274 ec[i].info = info;
275 do {
276 ec[i].next = (ec_ext_call *)
277 atomic_read(&lowcore->ext_call_queue);
278 } while (atomic_compare_and_swap((int) ec[i].next, (int)(ec+i),
279 &lowcore->ext_call_queue));
280 ccode = signal_processor(i, sigp_external_call);
281 }
282
283 /* wait for completion, FIXME: possible seed of a deadlock */
284 for (i = 0; i < smp_num_cpus; i++) {
285 if (smp_processor_id() == i)
286 continue;
287 while (atomic_read(&ec[i].status) !=
288 (wait ? ec_done:ec_executing));
289 }
290 }
291
292 /*
293 * Send an external call sigp to another cpu and return without waiting
294 * for its completion.
295 */
296 sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
297 {
298 struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
299 sigp_ccode ccode;
300
301 /*
302 * Set signaling bit in lowcore of target cpu and kick it
303 */
304 atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
305 ccode = signal_processor(cpu, sigp_external_call);
306 return ccode;
307 }
308
309 /*
310 * Send an external call sigp to every other cpu in the system and
311 * return without waiting for its completion.
312 */
313 void smp_ext_bitcall_others(ec_bit_sig sig)
314 {
315 struct _lowcore *lowcore;
316 sigp_ccode ccode;
317 int i;
318
319 for (i = 0; i < smp_num_cpus; i++) {
320 if (smp_processor_id() == i)
321 continue;
322 lowcore = &get_cpu_lowcore(i);
323 /*
324 * Set signaling bit in lowcore of target cpu and kick it
325 */
326 atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
327 ccode = signal_processor(i, sigp_external_call);
328 }
329 }
330
331 /*
332 * cycles through all the cpus,
333 * returns early if info is not NULL & the processor has something
334 * of intrest to report in the info structure.
335 * it returns the next cpu to check if it returns early.
336 * i.e. it should be used as follows if you wish to receive info.
337 * next_cpu=0;
338 * do
339 * {
340 * info->cpu=next_cpu;
341 * next_cpu=smp_signal_others(order_code,parameter,1,info);
342 * ... check info here
343 * } while(next_cpu<=smp_num_cpus)
344 *
345 * if you are lazy just use it like
346 * smp_signal_others(order_code,parameter,0,1,NULL);
347 */
348 int smp_signal_others(sigp_order_code order_code, u32 parameter,
349 int spin, sigp_info *info)
350 {
351 sigp_ccode ccode;
352 u32 dummy;
353 u16 i;
354
355 if (info)
356 info->intresting = 0;
357 for (i = (info ? info->cpu : 0); i < smp_num_cpus; i++) {
358 if (smp_processor_id() != i) {
359 do {
360 ccode = signal_processor_ps(
361 (info ? &info->status : &dummy),
362 parameter, i, order_code);
363 } while(spin && ccode == sigp_busy);
364 if (info && ccode != sigp_order_code_accepted) {
365 info->intresting = 1;
366 info->cpu = i;
367 info->ccode = ccode;
368 i++;
369 break;
370 }
371 }
372 }
373 return i;
374 }
375
376 /*
377 * this function sends a 'stop' sigp to all other CPUs in the system.
378 * it goes straight through.
379 */
380
381 void smp_send_stop(void)
382 {
383 int i;
384 u32 dummy;
385 unsigned long low_core_addr;
386
387 /* write magic number to zero page (absolute 0) */
388
389 get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
390
391 /* stop all processors */
392
393 smp_signal_others(sigp_stop, 0, 1, NULL);
394
395 /* store status of all processors in their lowcores (real 0) */
396
397 for (i = 0; i < smp_num_cpus; i++) {
398 if (smp_processor_id() != i) {
399 int ccode;
400 low_core_addr = (unsigned long)&get_cpu_lowcore(i);
401 do {
402 ccode = signal_processor_ps(
403 &dummy,
404 low_core_addr,
405 i,
406 sigp_store_status_at_address);
407 } while(ccode == sigp_busy);
408 }
409 }
410 }
411
412 /*
413 * this function sends a 'purge tlb' signal to another CPU.
414 */
415 void smp_ptlb_callback(void *info)
416 {
417 local_flush_tlb();
418 }
419
420 void smp_ptlb_all(void)
421 {
422 smp_ext_call_others(smp_ptlb_callback, NULL, 1);
423 local_flush_tlb();
424 }
425
426 /*
427 * this function sends a 'reschedule' IPI to another CPU.
428 * it goes straight through and wastes no time serializing
429 * anything. Worst case is that we lose a reschedule ...
430 */
431
432 void smp_send_reschedule(int cpu)
433 {
434 smp_ext_bitcall(cpu, ec_schedule);
435 }
436
437 /*
438 * parameter area for the set/clear control bit callbacks
439 */
440 typedef struct
441 {
442 __u16 start_ctl;
443 __u16 end_ctl;
444 __u32 orvals[16];
445 __u32 andvals[16];
446 } ec_creg_mask_parms;
447
448 /*
449 * callback for setting/clearing control bits
450 */
451 void smp_ctl_bit_callback(void *info) {
452 ec_creg_mask_parms *pp;
453 u32 cregs[16];
454 int i;
455
456 pp = (ec_creg_mask_parms *) info;
457 asm volatile (" bras 1,0f\n"
458 " stctl 0,0,0(%0)\n"
459 "0: ex %1,0(1)\n"
460 : : "a" (cregs+pp->start_ctl),
461 "a" ((pp->start_ctl<<4) + pp->end_ctl)
462 : "memory", "1" );
463 for (i = pp->start_ctl; i <= pp->end_ctl; i++)
464 cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
465 asm volatile (" bras 1,0f\n"
466 " lctl 0,0,0(%0)\n"
467 "0: ex %1,0(1)\n"
468 : : "a" (cregs+pp->start_ctl),
469 "a" ((pp->start_ctl<<4) + pp->end_ctl)
470 : "memory", "1" );
471 return;
472 }
473
474 /*
475 * Set a bit in a control register of all cpus
476 */
477 void smp_ctl_set_bit(int cr, int bit) {
478 ec_creg_mask_parms parms;
479
480 if (atomic_read(&smp_commenced) != 0) {
481 parms.start_ctl = cr;
482 parms.end_ctl = cr;
483 parms.orvals[cr] = 1 << bit;
484 parms.andvals[cr] = 0xFFFFFFFF;
485 smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
486 }
487 __ctl_set_bit(cr, bit);
488 }
489
490 /*
491 * Clear a bit in a control register of all cpus
492 */
493 void smp_ctl_clear_bit(int cr, int bit) {
494 ec_creg_mask_parms parms;
495
496 if (atomic_read(&smp_commenced) != 0) {
497 parms.start_ctl = cr;
498 parms.end_ctl = cr;
499 parms.orvals[cr] = 0x00000000;
500 parms.andvals[cr] = ~(1 << bit);
501 smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
502 }
503 __ctl_clear_bit(cr, bit);
504 }
505
506 /*
507 * Call a function on all other processors
508 */
509
510 int
511 smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
512 /*
513 * [SUMMARY] Run a function on all other CPUs.
514 * <func> The function to run. This must be fast and non-blocking.
515 * <info> An arbitrary pointer to pass to the function.
516 * <retry> currently unused.
517 * <wait> If true, wait (atomically) until function has completed on other CPUs.
518 * [RETURNS] 0 on success, else a negative status code. Does not return until
519 * remote CPUs are nearly ready to execute <<func>> or are or have executed.
520 *
521 * You must not call this function with disabled interrupts or from a
522 * hardware interrupt handler, you may call it from a bottom half handler.
523 */
524 {
525 if (atomic_read(&smp_commenced) != 0)
526 smp_ext_call_others(func, info, wait);
527 return 0;
528 }
529
530 /*
531 * Lets check how many CPUs we have.
532 */
533
534 void smp_count_cpus(void)
535 {
536 int curr_cpu;
537
538 current->processor = 0;
539 smp_num_cpus = 1;
540 for (curr_cpu = 0;
541 curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
542 if ((__u16) curr_cpu == boot_cpu_addr)
543 continue;
544 __cpu_logical_map[smp_num_cpus] = (__u16) curr_cpu;
545 if (signal_processor(smp_num_cpus, sigp_sense) ==
546 sigp_not_operational)
547 continue;
548 smp_num_cpus++;
549 }
550 printk("Detected %d CPU's\n",(int) smp_num_cpus);
551 printk("Boot cpu address %2X\n", boot_cpu_addr);
552 }
553
554
555 /*
556 * Activate a secondary processor.
557 */
558 extern void init_100hz_timer(void);
559 extern int pfault_token(void);
560
561 int __init start_secondary(void *cpuvoid)
562 {
563 /* Setup the cpu */
564 cpu_init();
565 /* Print info about this processor */
566 print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
567 /* Wait for completion of smp startup */
568 while (!atomic_read(&smp_commenced))
569 /* nothing */ ;
570 /* init per CPU 100 hz timer */
571 init_100hz_timer();
572 #ifdef CONFIG_PFAULT
573 /* Enable pfault pseudo page faults on this cpu. */
574 pfault_init();
575 #endif
576 /* cpu_idle will call schedule for us */
577 return cpu_idle(NULL);
578 }
579
580 /*
581 * The restart interrupt handler jumps to start_secondary directly
582 * without the detour over initialize_secondary. We defined it here
583 * so that the linker doesn't complain.
584 */
585 void __init initialize_secondary(void)
586 {
587 }
588
589 static int __init fork_by_hand(void)
590 {
591 struct pt_regs regs;
592 /* don't care about the psw and regs settings since we'll never
593 reschedule the forked task. */
594 memset(®s,0,sizeof(struct pt_regs));
595 return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0);
596 }
597
598 static void __init do_boot_cpu(int cpu)
599 {
600 struct task_struct *idle;
601 struct _lowcore *cpu_lowcore;
602
603 /* We can't use kernel_thread since we must _avoid_ to reschedule
604 the child. */
605 if (fork_by_hand() < 0)
606 panic("failed fork for CPU %d", cpu);
607
608 /*
609 * We remove it from the pidhash and the runqueue
610 * once we got the process:
611 */
612 idle = init_task.prev_task;
613 if (!idle)
614 panic("No idle process for CPU %d",cpu);
615 idle->processor = cpu;
616 idle->has_cpu = 1; /* we schedule the first task manually */
617
618 del_from_runqueue(idle);
619 unhash_process(idle);
620 init_tasks[cpu] = idle;
621
622 cpu_lowcore=&get_cpu_lowcore(cpu);
623 cpu_lowcore->kernel_stack=idle->thread.ksp;
624 __asm__ __volatile__("stctl 0,15,%0\n\t"
625 "stam 0,15,%1"
626 : "=m" (cpu_lowcore->cregs_save_area[0]),
627 "=m" (cpu_lowcore->access_regs_save_area[0])
628 : : "memory");
629
630 eieio();
631 signal_processor(cpu,sigp_restart);
632 }
633
634 /*
635 * Architecture specific routine called by the kernel just before init is
636 * fired off. This allows the BP to have everything in order [we hope].
637 * At the end of this all the APs will hit the system scheduling and off
638 * we go. Each AP will load the system gdt's and jump through the kernel
639 * init into idle(). At this point the scheduler will one day take over
640 * and give them jobs to do. smp_callin is a standard routine
641 * we use to track CPUs as they power up.
642 */
643
644 void __init smp_commence(void)
645 {
646 /*
647 * Lets the callins below out of their loop.
648 */
649 atomic_set(&smp_commenced,1);
650 }
651
652 /*
653 * Cycle through the processors sending APIC IPIs to boot each.
654 */
655
656 void __init smp_boot_cpus(void)
657 {
658 struct _lowcore *curr_lowcore;
659 sigp_ccode ccode;
660 int i;
661
662 /* request the 0x1202 external interrupt */
663 if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
664 panic("Couldn't request external interrupt 0x1202");
665 smp_count_cpus();
666 memset(lowcore_ptr,0,sizeof(lowcore_ptr));
667
668 /*
669 * Initialize the logical to physical CPU number mapping
670 * and the per-CPU profiling counter/multiplier
671 */
672
673 for (i = 0; i < NR_CPUS; i++) {
674 prof_counter[i] = 1;
675 prof_old_multiplier[i] = 1;
676 prof_multiplier[i] = 1;
677 }
678
679 print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
680
681 for(i = 0; i < smp_num_cpus; i++)
682 {
683 curr_lowcore = (struct _lowcore *)
684 __get_free_page(GFP_KERNEL|GFP_DMA);
685 if (curr_lowcore == NULL) {
686 printk("smp_boot_cpus failed to allocate prefix memory\n");
687 break;
688 }
689 lowcore_ptr[i] = curr_lowcore;
690 memcpy(curr_lowcore, &S390_lowcore, sizeof(struct _lowcore));
691 /*
692 * Most of the parameters are set up when the cpu is
693 * started up.
694 */
695 if (smp_processor_id() == i)
696 set_prefix((u32) curr_lowcore);
697 else {
698 ccode = signal_processor_p((u32)(curr_lowcore),
699 i, sigp_set_prefix);
700 if(ccode) {
701 /* if this gets troublesome I'll have to do
702 * something about it. */
703 printk("ccode %d for cpu %d returned when "
704 "setting prefix in smp_boot_cpus not good.\n",
705 (int) ccode, (int) i);
706 }
707 else
708 do_boot_cpu(i);
709 }
710 }
711 }
712
713 /*
714 * the frequency of the profiling timer can be changed
715 * by writing a multiplier value into /proc/profile.
716 *
717 * usually you want to run this on all CPUs ;)
718 */
719 int setup_profiling_timer(unsigned int multiplier)
720 {
721 return 0;
722 }
723
724 /*
725 * Local timer interrupt handler. It does both profiling and
726 * process statistics/rescheduling.
727 *
728 * We do profiling in every local tick, statistics/rescheduling
729 * happen only every 'profiling multiplier' ticks. The default
730 * multiplier is 1 and it can be changed by writing the new multiplier
731 * value into /proc/profile.
732 */
733
734 void smp_local_timer_interrupt(struct pt_regs * regs)
735 {
736 int user = (user_mode(regs) != 0);
737 int cpu = smp_processor_id();
738
739 /*
740 * The profiling function is SMP safe. (nothing can mess
741 * around with "current", and the profiling counters are
742 * updated with atomic operations). This is especially
743 * useful with a profiling multiplier != 1
744 */
745 if (!user_mode(regs))
746 s390_do_profile(regs->psw.addr);
747
748 if (!--prof_counter[cpu]) {
749 int system = 1-user;
750 struct task_struct * p = current;
751
752 /*
753 * The multiplier may have changed since the last time we got
754 * to this point as a result of the user writing to
755 * /proc/profile. In this case we need to adjust the APIC
756 * timer accordingly.
757 *
758 * Interrupts are already masked off at this point.
759 */
760 prof_counter[cpu] = prof_multiplier[cpu];
761 if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
762 /* FIXME setup_APIC_timer(calibration_result/prof_counter[cpu]
763 ); */
764 prof_old_multiplier[cpu] = prof_counter[cpu];
765 }
766
767 /*
768 * After doing the above, we need to make like
769 * a normal interrupt - otherwise timer interrupts
770 * ignore the global interrupt lock, which is the
771 * WrongThing (tm) to do.
772 */
773
774 irq_enter(cpu, 0);
775 update_process_times(user);
776 irq_exit(cpu, 0);
777 }
778 }
779
780 EXPORT_SYMBOL(lowcore_ptr);
781 EXPORT_SYMBOL(kernel_flag);
782 EXPORT_SYMBOL(smp_ctl_set_bit);
783 EXPORT_SYMBOL(smp_ctl_clear_bit);
784 EXPORT_SYMBOL(smp_num_cpus);
785