File: /usr/src/linux/arch/s390x/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 unsigned long 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 bits = xchg(&S390_lowcore.ext_call_fast, 0);
163
164 if (test_bit(ec_restart, &bits))
165 do_machine_restart();
166 if (test_bit(ec_halt, &bits))
167 do_machine_halt();
168 if (test_bit(ec_power_off, &bits))
169 do_machine_power_off();
170
171 /*
172 * Handle external call commands with a parameter area
173 */
174 ec = (ec_ext_call *) xchg(&S390_lowcore.ext_call_queue, 0);
175 if (ec == NULL)
176 return; /* no command signals */
177
178 /* Make a fifo out of the lifo */
179 next = ec->next;
180 ec->next = NULL;
181 while (next != NULL) {
182 ec_ext_call *tmp = next->next;
183 next->next = ec;
184 ec = next;
185 next = tmp;
186 }
187
188 /* Execute every sigp command on the queue */
189 while (ec != NULL) {
190 switch (ec->cmd) {
191 case ec_callback_async: {
192 void (*func)(void *info);
193 void *info;
194
195 func = ec->func;
196 info = ec->info;
197 atomic_set(&ec->status,ec_executing);
198 (func)(info);
199 return;
200 }
201 case ec_callback_sync:
202 atomic_set(&ec->status,ec_executing);
203 (ec->func)(ec->info);
204 atomic_set(&ec->status,ec_done);
205 return;
206 default:
207 }
208 ec = ec->next;
209 }
210 }
211
212 /*
213 * Swap in a new request to external call queue
214 */
215 static inline void smp_add_ext_call(ec_ext_call *ec, struct _lowcore *lowcore)
216 {
217 int success;
218
219 while (1) {
220 ec->next = (ec_ext_call*) lowcore->ext_call_queue;
221 __asm__ __volatile__ (
222 " lgr 0,%2\n"
223 " csg 0,%3,%1\n"
224 " ipm %0\n"
225 " srl %0,28\n"
226 : "=d" (success), "+m" (lowcore->ext_call_queue)
227 : "d" (ec->next), "d" (ec)
228 : "cc", "0" );
229 if (success == 0) break;
230 }
231 }
232
233 /*
234 * Send an external call sigp to another cpu and wait for its completion.
235 */
236 sigp_ccode
237 smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait)
238 {
239 sigp_ccode ccode;
240 ec_ext_call ec;
241
242 ec.cmd = wait ? ec_callback_sync:ec_callback_async;
243 atomic_set(&ec.status, ec_pending);
244 ec.func = func;
245 ec.info = info;
246 /* swap in new request to external call queue */
247 smp_add_ext_call(&ec, &get_cpu_lowcore(cpu));
248 /*
249 * We try once to deliver the signal. There are four possible
250 * return codes:
251 * 0) Order code accepted - can't show up on an external call
252 * 1) Status stored - fine, wait for completion.
253 * 2) Busy - there is another signal pending. Thats fine too, because
254 * do_ext_call from the pending signal will execute all signals on
255 * the queue. We wait for completion.
256 * 3) Not operational - something very bad has happened to the cpu.
257 * do not wait for completion.
258 */
259 ccode = signal_processor(cpu, sigp_external_call);
260
261 if (ccode != sigp_not_operational)
262 /* wait for completion, FIXME: possible seed of a deadlock */
263 while (atomic_read(&ec.status) != (wait?ec_done:ec_executing));
264
265 return ccode;
266 }
267
268 /*
269 * Send a callback sigp to every other cpu in the system.
270 */
271 void smp_ext_call_others(void (*func)(void *info), void *info, int wait)
272 {
273 ec_ext_call ec[NR_CPUS];
274 sigp_ccode ccode;
275 int i;
276
277 for (i = 0; i < smp_num_cpus; i++) {
278 if (smp_processor_id() == i)
279 continue;
280 ec[i].cmd = wait ? ec_callback_sync : ec_callback_async;
281 atomic_set(&ec[i].status, ec_pending);
282 ec[i].func = func;
283 ec[i].info = info;
284 smp_add_ext_call(ec+i, &get_cpu_lowcore(i));
285 ccode = signal_processor(i, sigp_external_call);
286 }
287
288 /* wait for completion, FIXME: possible seed of a deadlock */
289 for (i = 0; i < smp_num_cpus; i++) {
290 if (smp_processor_id() == i)
291 continue;
292 while (atomic_read(&ec[i].status) !=
293 (wait ? ec_done:ec_executing));
294 }
295 }
296
297 /*
298 * Send an external call sigp to another cpu and return without waiting
299 * for its completion.
300 */
301 sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
302 {
303 sigp_ccode ccode;
304
305 /*
306 * Set signaling bit in lowcore of target cpu and kick it
307 */
308 set_bit(sig, &(get_cpu_lowcore(cpu).ext_call_fast));
309 ccode = signal_processor(cpu, sigp_external_call);
310 return ccode;
311 }
312
313 /*
314 * Send an external call sigp to every other cpu in the system and
315 * return without waiting for its completion.
316 */
317 void smp_ext_bitcall_others(ec_bit_sig sig)
318 {
319 sigp_ccode ccode;
320 int i;
321
322 for (i = 0; i < smp_num_cpus; i++) {
323 if (smp_processor_id() == i)
324 continue;
325 /*
326 * Set signaling bit in lowcore of target cpu and kick it
327 */
328 set_bit(sig, &(get_cpu_lowcore(i).ext_call_fast));
329 ccode = signal_processor(i, sigp_external_call);
330 }
331 }
332
333 /*
334 * cycles through all the cpus,
335 * returns early if info is not NULL & the processor has something
336 * of intrest to report in the info structure.
337 * it returns the next cpu to check if it returns early.
338 * i.e. it should be used as follows if you wish to receive info.
339 * next_cpu=0;
340 * do
341 * {
342 * info->cpu=next_cpu;
343 * next_cpu=smp_signal_others(order_code,parameter,1,info);
344 * ... check info here
345 * } while(next_cpu<=smp_num_cpus)
346 *
347 * if you are lazy just use it like
348 * smp_signal_others(order_code,parameter,0,1,NULL);
349 */
350 int smp_signal_others(sigp_order_code order_code, u32 parameter,
351 int spin, sigp_info *info)
352 {
353 sigp_ccode ccode;
354 u32 dummy;
355 u16 i;
356
357 if (info)
358 info->intresting = 0;
359 for (i = (info ? info->cpu : 0); i < smp_num_cpus; i++) {
360 if (smp_processor_id() != i) {
361 do {
362 ccode = signal_processor_ps(
363 (info ? &info->status : &dummy),
364 parameter, i, order_code);
365 } while(spin && ccode == sigp_busy);
366 if (info && ccode != sigp_order_code_accepted) {
367 info->intresting = 1;
368 info->cpu = i;
369 info->ccode = ccode;
370 i++;
371 break;
372 }
373 }
374 }
375 return i;
376 }
377
378 /*
379 * this function sends a 'stop' sigp to all other CPUs in the system.
380 * it goes straight through.
381 */
382
383 void smp_send_stop(void)
384 {
385 int i;
386 u32 dummy;
387 unsigned long low_core_addr;
388
389 /* write magic number to zero page (absolute 0) */
390
391 get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
392
393 /* stop all processors */
394
395 smp_signal_others(sigp_stop, 0, 1, NULL);
396
397 /* store status of all processors in their lowcores (real 0) */
398
399 for (i = 0; i < smp_num_cpus; i++) {
400 if (smp_processor_id() != i) {
401 int ccode;
402 low_core_addr = (unsigned long)&get_cpu_lowcore(i);
403 do {
404 ccode = signal_processor_ps(
405 &dummy,
406 low_core_addr,
407 i,
408 sigp_store_status_at_address);
409 } while(ccode == sigp_busy);
410 }
411 }
412 }
413
414 /*
415 * this function sends a 'reschedule' IPI to another CPU.
416 * it goes straight through and wastes no time serializing
417 * anything. Worst case is that we lose a reschedule ...
418 */
419
420 void smp_send_reschedule(int cpu)
421 {
422 smp_ext_bitcall(cpu, ec_schedule);
423 }
424
425 /*
426 * parameter area for the set/clear control bit callbacks
427 */
428 typedef struct
429 {
430 __u16 start_ctl;
431 __u16 end_ctl;
432 __u64 orvals[16];
433 __u64 andvals[16];
434 } ec_creg_mask_parms;
435
436 /*
437 * callback for setting/clearing control bits
438 */
439 void smp_ctl_bit_callback(void *info) {
440 ec_creg_mask_parms *pp;
441 u64 cregs[16];
442 int i;
443
444 pp = (ec_creg_mask_parms *) info;
445 asm volatile (" bras 1,0f\n"
446 " stctg 0,0,0(%0)\n"
447 "0: ex %1,0(1)\n"
448 : : "a" (cregs+pp->start_ctl),
449 "a" ((pp->start_ctl<<4) + pp->end_ctl)
450 : "memory", "1" );
451 for (i = pp->start_ctl; i <= pp->end_ctl; i++)
452 cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
453 asm volatile (" bras 1,0f\n"
454 " lctlg 0,0,0(%0)\n"
455 "0: ex %1,0(1)\n"
456 : : "a" (cregs+pp->start_ctl),
457 "a" ((pp->start_ctl<<4) + pp->end_ctl)
458 : "memory", "1" );
459 }
460
461 /*
462 * Set a bit in a control register of all cpus
463 */
464 void smp_ctl_set_bit(int cr, int bit) {
465 ec_creg_mask_parms parms;
466
467 if (atomic_read(&smp_commenced) != 0) {
468 parms.start_ctl = cr;
469 parms.end_ctl = cr;
470 parms.orvals[cr] = 1 << bit;
471 parms.andvals[cr] = -1L;
472 smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
473 }
474 __ctl_set_bit(cr, bit);
475 }
476
477 /*
478 * Clear a bit in a control register of all cpus
479 */
480 void smp_ctl_clear_bit(int cr, int bit) {
481 ec_creg_mask_parms parms;
482
483 if (atomic_read(&smp_commenced) != 0) {
484 parms.start_ctl = cr;
485 parms.end_ctl = cr;
486 parms.orvals[cr] = 0;
487 parms.andvals[cr] = ~(1L << bit);
488 smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
489 }
490 __ctl_clear_bit(cr, bit);
491 }
492
493 /*
494 * Call a function on all other processors
495 */
496
497 int
498 smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
499 /*
500 * [SUMMARY] Run a function on all other CPUs.
501 * <func> The function to run. This must be fast and non-blocking.
502 * <info> An arbitrary pointer to pass to the function.
503 * <retry> currently unused.
504 * <wait> If true, wait (atomically) until function has completed on other CPUs.
505 * [RETURNS] 0 on success, else a negative status code. Does not return until
506 * remote CPUs are nearly ready to execute <<func>> or are or have executed.
507 *
508 * You must not call this function with disabled interrupts or from a
509 * hardware interrupt handler, you may call it from a bottom half handler.
510 */
511 {
512 if (atomic_read(&smp_commenced) != 0)
513 smp_ext_call_others(func, info, wait);
514 return 0;
515 }
516
517 /*
518 * Lets check how many CPUs we have.
519 */
520
521 void smp_count_cpus(void)
522 {
523 int curr_cpu;
524
525 current->processor = 0;
526 smp_num_cpus = 1;
527 for (curr_cpu = 0;
528 curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
529 if ((__u16) curr_cpu == boot_cpu_addr)
530 continue;
531 __cpu_logical_map[smp_num_cpus] = (__u16) curr_cpu;
532 if (signal_processor(smp_num_cpus, sigp_sense) ==
533 sigp_not_operational)
534 continue;
535 smp_num_cpus++;
536 }
537 printk("Detected %d CPU's\n",(int) smp_num_cpus);
538 printk("Boot cpu address %2X\n", boot_cpu_addr);
539 }
540
541
542 /*
543 * Activate a secondary processor.
544 */
545 extern void init_100hz_timer(void);
546 extern int pfault_init(void);
547
548 int __init start_secondary(void *cpuvoid)
549 {
550 /* Setup the cpu */
551 cpu_init();
552 /* Print info about this processor */
553 print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
554 /* Wait for completion of smp startup */
555 while (!atomic_read(&smp_commenced))
556 /* nothing */ ;
557 /* init per CPU 100 hz timer */
558 init_100hz_timer();
559 #ifdef CONFIG_PFAULT
560 /* Enable pfault pseudo page faults on this cpu. */
561 pfault_init();
562 #endif
563 /* cpu_idle will call schedule for us */
564 return cpu_idle(NULL);
565 }
566
567 /*
568 * The restart interrupt handler jumps to start_secondary directly
569 * without the detour over initialize_secondary. We defined it here
570 * so that the linker doesn't complain.
571 */
572 void __init initialize_secondary(void)
573 {
574 }
575
576 static int __init fork_by_hand(void)
577 {
578 struct pt_regs regs;
579 /* don't care about the psw and regs settings since we'll never
580 reschedule the forked task. */
581 memset(®s,0,sizeof(struct pt_regs));
582 return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0);
583 }
584
585 static void __init do_boot_cpu(int cpu)
586 {
587 struct task_struct *idle;
588 struct _lowcore *cpu_lowcore;
589
590 /* We can't use kernel_thread since we must _avoid_ to reschedule
591 the child. */
592 if (fork_by_hand() < 0)
593 panic("failed fork for CPU %d", cpu);
594
595 /*
596 * We remove it from the pidhash and the runqueue
597 * once we got the process:
598 */
599 idle = init_task.prev_task;
600 if (!idle)
601 panic("No idle process for CPU %d",cpu);
602 idle->processor = cpu;
603 idle->has_cpu = 1; /* we schedule the first task manually */
604
605 del_from_runqueue(idle);
606 unhash_process(idle);
607 init_tasks[cpu] = idle;
608
609 cpu_lowcore=&get_cpu_lowcore(cpu);
610 cpu_lowcore->kernel_stack=idle->thread.ksp;
611 __asm__ __volatile__("stctg 0,15,%0\n\t"
612 "stam 0,15,%1"
613 : "=m" (cpu_lowcore->cregs_save_area[0]),
614 "=m" (cpu_lowcore->access_regs_save_area[0])
615 : : "memory");
616
617 eieio();
618 signal_processor(cpu,sigp_restart);
619 }
620
621 /*
622 * Architecture specific routine called by the kernel just before init is
623 * fired off. This allows the BP to have everything in order [we hope].
624 * At the end of this all the APs will hit the system scheduling and off
625 * we go. Each AP will load the system gdt's and jump through the kernel
626 * init into idle(). At this point the scheduler will one day take over
627 * and give them jobs to do. smp_callin is a standard routine
628 * we use to track CPUs as they power up.
629 */
630
631 void __init smp_commence(void)
632 {
633 /*
634 * Lets the callins below out of their loop.
635 */
636 atomic_set(&smp_commenced,1);
637 }
638
639 /*
640 * Cycle through the processors sending restart sigps to boot each.
641 */
642
643 void __init smp_boot_cpus(void)
644 {
645 struct _lowcore *curr_lowcore;
646 sigp_ccode ccode;
647 int i;
648
649 /* request the 0x1202 external interrupt */
650 if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
651 panic("Couldn't request external interrupt 0x1202");
652 smp_count_cpus();
653 memset(lowcore_ptr,0,sizeof(lowcore_ptr));
654
655 /*
656 * Initialize the logical to physical CPU number mapping
657 * and the per-CPU profiling counter/multiplier
658 */
659
660 for (i = 0; i < NR_CPUS; i++) {
661 prof_counter[i] = 1;
662 prof_old_multiplier[i] = 1;
663 prof_multiplier[i] = 1;
664 }
665
666 print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
667
668 for(i = 0; i < smp_num_cpus; i++)
669 {
670 curr_lowcore = (struct _lowcore *)
671 __get_free_pages(GFP_KERNEL|GFP_DMA, 1);
672 if (curr_lowcore == NULL) {
673 printk("smp_boot_cpus failed to allocate prefix memory\n");
674 break;
675 }
676 lowcore_ptr[i] = curr_lowcore;
677 memcpy(curr_lowcore, &S390_lowcore, sizeof(struct _lowcore));
678 /*
679 * Most of the parameters are set up when the cpu is
680 * started up.
681 */
682 if (smp_processor_id() == i)
683 set_prefix((u32)(u64)curr_lowcore);
684 else {
685 ccode = signal_processor_p((u64)(curr_lowcore),
686 i, sigp_set_prefix);
687 if(ccode) {
688 /* if this gets troublesome I'll have to do
689 * something about it. */
690 printk("ccode %d for cpu %d returned when "
691 "setting prefix in smp_boot_cpus not good.\n",
692 (int) ccode, (int) i);
693 }
694 else
695 do_boot_cpu(i);
696 }
697 }
698 }
699
700 /*
701 * the frequency of the profiling timer can be changed
702 * by writing a multiplier value into /proc/profile.
703 *
704 * usually you want to run this on all CPUs ;)
705 */
706 int setup_profiling_timer(unsigned int multiplier)
707 {
708 return 0;
709 }
710
711 /*
712 * Local timer interrupt handler. It does both profiling and
713 * process statistics/rescheduling.
714 *
715 * We do profiling in every local tick, statistics/rescheduling
716 * happen only every 'profiling multiplier' ticks. The default
717 * multiplier is 1 and it can be changed by writing the new multiplier
718 * value into /proc/profile.
719 */
720
721 void smp_local_timer_interrupt(struct pt_regs * regs)
722 {
723 int user = (user_mode(regs) != 0);
724 int cpu = smp_processor_id();
725
726 /*
727 * The profiling function is SMP safe. (nothing can mess
728 * around with "current", and the profiling counters are
729 * updated with atomic operations). This is especially
730 * useful with a profiling multiplier != 1
731 */
732 if (!user_mode(regs))
733 s390_do_profile(regs->psw.addr);
734
735 if (!--prof_counter[cpu]) {
736 int system = 1-user;
737 struct task_struct * p = current;
738
739 /*
740 * The multiplier may have changed since the last time we got
741 * to this point as a result of the user writing to
742 * /proc/profile. In this case we need to adjust the APIC
743 * timer accordingly.
744 *
745 * Interrupts are already masked off at this point.
746 */
747 prof_counter[cpu] = prof_multiplier[cpu];
748 if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
749 prof_old_multiplier[cpu] = prof_counter[cpu];
750 }
751
752 /*
753 * After doing the above, we need to make like
754 * a normal interrupt - otherwise timer interrupts
755 * ignore the global interrupt lock, which is the
756 * WrongThing (tm) to do.
757 */
758
759 irq_enter(cpu, 0);
760 update_process_times(user);
761 irq_exit(cpu, 0);
762 }
763 }
764
765 EXPORT_SYMBOL(lowcore_ptr);
766 EXPORT_SYMBOL(kernel_flag);
767 EXPORT_SYMBOL(smp_ctl_set_bit);
768 EXPORT_SYMBOL(smp_ctl_clear_bit);
769 EXPORT_SYMBOL(smp_num_cpus);
770