ia64/xen-unstable

changeset 2915:a049a5fcefc4

bitkeeper revision 1.1159.1.392 (418f90efoPSUCiX94PZ6xsvTCedrgQ)

Support compile with CONFIG_SMP.
author cl349@freefall.cl.cam.ac.uk
date Mon Nov 08 15:29:51 2004 +0000 (2004-11-08)
parents 2a69594a92dc
children fe5933507ca5
files .rootkeys linux-2.6.9-xen-sparse/arch/xen/i386/Kconfig linux-2.6.9-xen-sparse/arch/xen/i386/kernel/Makefile linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/common.c linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c linux-2.6.9-xen-sparse/arch/xen/i386/kernel/time.c linux-2.6.9-xen-sparse/arch/xen/kernel/Makefile linux-2.6.9-xen-sparse/arch/xen/kernel/smp.c linux-2.6.9-xen-sparse/drivers/xen/console/console.c linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/msr.h
line diff
     1.1 --- a/.rootkeys	Mon Nov 08 13:44:07 2004 +0000
     1.2 +++ b/.rootkeys	Mon Nov 08 15:29:51 2004 +0000
     1.3 @@ -148,6 +148,8 @@ 4107adf1cNtsuOxOB4T6paAoY2R2PA linux-2.6
     1.4  40f56238a8iOVDEoostsbun_sy2i4g linux-2.6.9-xen-sparse/arch/xen/i386/kernel/process.c
     1.5  40f56238YQIJoYG2ehDGEcdTgLmGbg linux-2.6.9-xen-sparse/arch/xen/i386/kernel/setup.c
     1.6  40f56238nWMQg7CKbyTy0KJNvCzbtg linux-2.6.9-xen-sparse/arch/xen/i386/kernel/signal.c
     1.7 +41811cac4lkCB-fHir6CcxuEJ2pGsQ linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c
     1.8 +41811ca9mbGpqBrZVrUGEiv8CTV3ng linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c
     1.9  40f56238UL9uv78ODDzMwLL9yryeFw linux-2.6.9-xen-sparse/arch/xen/i386/kernel/sysenter.c
    1.10  40f56238qVGkpO_ycnQA8k03kQzAgA linux-2.6.9-xen-sparse/arch/xen/i386/kernel/time.c
    1.11  40f56238NzTgeO63RGoxHrW5NQeO3Q linux-2.6.9-xen-sparse/arch/xen/i386/kernel/timers/Makefile
    1.12 @@ -175,6 +177,7 @@ 4110f478aeQWllIN7J4kouAHiAqrPw linux-2.6
    1.13  412dfae9eA3_6e6bCGUtg1mj8b56fQ linux-2.6.9-xen-sparse/arch/xen/kernel/gnttab.c
    1.14  40f562392LBhwmOxVPsYdkYXMxI_ZQ linux-2.6.9-xen-sparse/arch/xen/kernel/reboot.c
    1.15  414c113396tK1HTVeUalm3u-1DF16g linux-2.6.9-xen-sparse/arch/xen/kernel/skbuff.c
    1.16 +418f90e4lGdeJK9rmbOB1kN-IKSjsQ linux-2.6.9-xen-sparse/arch/xen/kernel/smp.c
    1.17  3f68905c5eiA-lBMQSvXLMWS1ikDEA linux-2.6.9-xen-sparse/arch/xen/kernel/xen_proc.c
    1.18  41261688yS8eAyy-7kzG4KBs0xbYCA linux-2.6.9-xen-sparse/drivers/Makefile
    1.19  4108f5c1WfTIrs0HZFeV39sttekCTw linux-2.6.9-xen-sparse/drivers/char/mem.c
    1.20 @@ -216,6 +219,7 @@ 40f5623aJVXQwpJMOLE99XgvGsfQ8Q linux-2.6
    1.21  40f5623aKXkBBxgpLx2NcvkncQ1Yyw linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
    1.22  40f5623aDMCsWOFO0jktZ4e8sjwvEg linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_post.h
    1.23  40f5623arsFXkGdPvIqvFi3yFXGR0Q linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_pre.h
    1.24 +41811f07Iri9hrvs97t-baxmhOwWDQ linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h
    1.25  4120f807GCO0uqsLqdZj9csxR1Wthw linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mmu_context.h
    1.26  40f5623aFTyFTR-vdiA-KaGxk5JOKQ linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/msr.h
    1.27  40f5623adgjZq9nAgCt0IXdWl7udSA linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/page.h
     2.1 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/Kconfig	Mon Nov 08 13:44:07 2004 +0000
     2.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/Kconfig	Mon Nov 08 15:29:51 2004 +0000
     2.3 @@ -322,36 +322,33 @@ config HPET_EMULATE_RTC
     2.4  	def_bool HPET_TIMER && RTC=y
     2.5  
     2.6  config SMP
     2.7 -	bool
     2.8 -	default n
     2.9 -#config SMP
    2.10 -#	bool "Symmetric multi-processing support"
    2.11 -#	---help---
    2.12 -#	  This enables support for systems with more than one CPU. If you have
    2.13 -#	  a system with only one CPU, like most personal computers, say N. If
    2.14 -#	  you have a system with more than one CPU, say Y.
    2.15 -#
    2.16 -#	  If you say N here, the kernel will run on single and multiprocessor
    2.17 -#	  machines, but will use only one CPU of a multiprocessor machine. If
    2.18 -#	  you say Y here, the kernel will run on many, but not all,
    2.19 -#	  singleprocessor machines. On a singleprocessor machine, the kernel
    2.20 -#	  will run faster if you say N here.
    2.21 -#
    2.22 -#	  Note that if you say Y here and choose architecture "586" or
    2.23 -#	  "Pentium" under "Processor family", the kernel will not work on 486
    2.24 -#	  architectures. Similarly, multiprocessor kernels for the "PPro"
    2.25 -#	  architecture may not work on all Pentium based boards.
    2.26 -#
    2.27 -#	  People using multiprocessor machines who say Y here should also say
    2.28 -#	  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
    2.29 -#	  Management" code will be disabled if you say Y here.
    2.30 -#
    2.31 -#	  See also the <file:Documentation/smp.txt>,
    2.32 -#	  <file:Documentation/i386/IO-APIC.txt>,
    2.33 -#	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
    2.34 -#	  <http://www.tldp.org/docs.html#howto>.
    2.35 -#
    2.36 -#	  If you don't know what to do here, say N.
    2.37 +	bool "Symmetric multi-processing support"
    2.38 +	---help---
    2.39 +	  This enables support for systems with more than one CPU. If you have
    2.40 +	  a system with only one CPU, like most personal computers, say N. If
    2.41 +	  you have a system with more than one CPU, say Y.
    2.42 +
    2.43 +	  If you say N here, the kernel will run on single and multiprocessor
    2.44 +	  machines, but will use only one CPU of a multiprocessor machine. If
    2.45 +	  you say Y here, the kernel will run on many, but not all,
    2.46 +	  singleprocessor machines. On a singleprocessor machine, the kernel
    2.47 +	  will run faster if you say N here.
    2.48 +
    2.49 +	  Note that if you say Y here and choose architecture "586" or
    2.50 +	  "Pentium" under "Processor family", the kernel will not work on 486
    2.51 +	  architectures. Similarly, multiprocessor kernels for the "PPro"
    2.52 +	  architecture may not work on all Pentium based boards.
    2.53 +
    2.54 +	  People using multiprocessor machines who say Y here should also say
    2.55 +	  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
    2.56 +	  Management" code will be disabled if you say Y here.
    2.57 +
    2.58 +	  See also the <file:Documentation/smp.txt>,
    2.59 +	  <file:Documentation/i386/IO-APIC.txt>,
    2.60 +	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
    2.61 +	  <http://www.tldp.org/docs.html#howto>.
    2.62 +
    2.63 +	  If you don't know what to do here, say N.
    2.64  
    2.65  config NR_CPUS
    2.66  	int "Maximum number of CPUs (2-255)"
    2.67 @@ -632,6 +629,11 @@ config REGPARM
    2.68  	-mregparm=3 is used.
    2.69  
    2.70  
    2.71 +config X86_LOCAL_APIC
    2.72 +	bool
    2.73 +	depends on (X86_VISWS || SMP) && !X86_VOYAGER
    2.74 +	default n
    2.75 +
    2.76  if XEN_PHYSDEV_ACCESS
    2.77  
    2.78  menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
    2.79 @@ -641,11 +643,6 @@ config X86_VISWS_APIC
    2.80  	depends on X86_VISWS
    2.81  	default y
    2.82  
    2.83 -config X86_LOCAL_APIC
    2.84 -	bool
    2.85 -	depends on (X86_VISWS || SMP) && !X86_VOYAGER
    2.86 -	default y
    2.87 -
    2.88  config X86_IO_APIC
    2.89  	bool
    2.90  	depends on SMP && !(X86_VISWS || X86_VOYAGER)
    2.91 @@ -908,10 +905,10 @@ config X86_SMP
    2.92  	depends on SMP && !X86_VOYAGER
    2.93  	default y
    2.94  
    2.95 -config X86_HT
    2.96 -	bool
    2.97 -	depends on SMP && !(X86_VISWS || X86_VOYAGER)
    2.98 -	default y
    2.99 +#config X86_HT
   2.100 +#	bool
   2.101 +#	depends on SMP && !(X86_VISWS || X86_VOYAGER)
   2.102 +#	default y
   2.103  
   2.104  config X86_BIOS_REBOOT
   2.105  	bool
     3.1 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/Makefile	Mon Nov 08 13:44:07 2004 +0000
     3.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/Makefile	Mon Nov 08 15:29:51 2004 +0000
     3.3 @@ -26,10 +26,11 @@ c-obj-$(CONFIG_X86_MSR)		+= msr.o
     3.4  c-obj-$(CONFIG_X86_CPUID)	+= cpuid.o
     3.5  c-obj-$(CONFIG_MICROCODE)	+= microcode.o
     3.6  c-obj-$(CONFIG_APM)		+= apm.o
     3.7 -c-obj-$(CONFIG_X86_SMP)		+= smp.o smpboot.o
     3.8 -c-obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline.o
     3.9 +obj-$(CONFIG_X86_SMP)		+= smp.o smpboot.o
    3.10 +#obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline.o
    3.11  c-obj-$(CONFIG_X86_MPPARSE)	+= mpparse.o
    3.12 -c-obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o nmi.o
    3.13 +#obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o
    3.14 +c-obj-$(CONFIG_X86_LOCAL_APIC)	+= nmi.o
    3.15  c-obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
    3.16  c-obj-$(CONFIG_X86_NUMAQ)	+= numaq.o
    3.17  c-obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
     4.1 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/common.c	Mon Nov 08 13:44:07 2004 +0000
     4.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/common.c	Mon Nov 08 15:29:51 2004 +0000
     4.3 @@ -604,3 +604,9 @@ void __init cpu_init (void)
     4.4  	current->used_math = 0;
     4.5  	mxcsr_feature_mask_init();
     4.6  }
     4.7 +
     4.8 +
     4.9 +int get_smp_processor_id(void)
    4.10 +{
    4.11 +	return smp_processor_id();
    4.12 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c	Mon Nov 08 15:29:51 2004 +0000
     5.3 @@ -0,0 +1,646 @@
     5.4 +/*
     5.5 + *	Intel SMP support routines.
     5.6 + *
     5.7 + *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
     5.8 + *	(c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
     5.9 + *
    5.10 + *	This code is released under the GNU General Public License version 2 or
    5.11 + *	later.
    5.12 + */
    5.13 +
    5.14 +#include <linux/init.h>
    5.15 +
    5.16 +#include <linux/mm.h>
    5.17 +#include <linux/irq.h>
    5.18 +#include <linux/delay.h>
    5.19 +#include <linux/spinlock.h>
    5.20 +#include <linux/smp_lock.h>
    5.21 +#include <linux/kernel_stat.h>
    5.22 +#include <linux/mc146818rtc.h>
    5.23 +#include <linux/cache.h>
    5.24 +#include <linux/interrupt.h>
    5.25 +
    5.26 +#include <asm/mtrr.h>
    5.27 +#include <asm/tlbflush.h>
    5.28 +#if 0
    5.29 +#include <mach_apic.h>
    5.30 +#endif
    5.31 +
    5.32 +/*
    5.33 + *	Some notes on x86 processor bugs affecting SMP operation:
    5.34 + *
    5.35 + *	Pentium, Pentium Pro, II, III (and all CPUs) have bugs.
    5.36 + *	The Linux implications for SMP are handled as follows:
    5.37 + *
    5.38 + *	Pentium III / [Xeon]
    5.39 + *		None of the E1AP-E3AP errata are visible to the user.
    5.40 + *
    5.41 + *	E1AP.	see PII A1AP
    5.42 + *	E2AP.	see PII A2AP
    5.43 + *	E3AP.	see PII A3AP
    5.44 + *
    5.45 + *	Pentium II / [Xeon]
    5.46 + *		None of the A1AP-A3AP errata are visible to the user.
    5.47 + *
    5.48 + *	A1AP.	see PPro 1AP
    5.49 + *	A2AP.	see PPro 2AP
    5.50 + *	A3AP.	see PPro 7AP
    5.51 + *
    5.52 + *	Pentium Pro
    5.53 + *		None of 1AP-9AP errata are visible to the normal user,
    5.54 + *	except occasional delivery of 'spurious interrupt' as trap #15.
    5.55 + *	This is very rare and a non-problem.
    5.56 + *
    5.57 + *	1AP.	Linux maps APIC as non-cacheable
    5.58 + *	2AP.	worked around in hardware
    5.59 + *	3AP.	fixed in C0 and above steppings microcode update.
    5.60 + *		Linux does not use excessive STARTUP_IPIs.
    5.61 + *	4AP.	worked around in hardware
    5.62 + *	5AP.	symmetric IO mode (normal Linux operation) not affected.
    5.63 + *		'noapic' mode has vector 0xf filled out properly.
    5.64 + *	6AP.	'noapic' mode might be affected - fixed in later steppings
    5.65 + *	7AP.	We do not assume writes to the LVT deassering IRQs
    5.66 + *	8AP.	We do not enable low power mode (deep sleep) during MP bootup
    5.67 + *	9AP.	We do not use mixed mode
    5.68 + *
    5.69 + *	Pentium
    5.70 + *		There is a marginal case where REP MOVS on 100MHz SMP
    5.71 + *	machines with B stepping processors can fail. XXX should provide
    5.72 + *	an L1cache=Writethrough or L1cache=off option.
    5.73 + *
    5.74 + *		B stepping CPUs may hang. There are hardware work arounds
    5.75 + *	for this. We warn about it in case your board doesn't have the work
    5.76 + *	arounds. Basically thats so I can tell anyone with a B stepping
    5.77 + *	CPU and SMP problems "tough".
    5.78 + *
    5.79 + *	Specific items [From Pentium Processor Specification Update]
    5.80 + *
    5.81 + *	1AP.	Linux doesn't use remote read
    5.82 + *	2AP.	Linux doesn't trust APIC errors
    5.83 + *	3AP.	We work around this
    5.84 + *	4AP.	Linux never generated 3 interrupts of the same priority
    5.85 + *		to cause a lost local interrupt.
    5.86 + *	5AP.	Remote read is never used
    5.87 + *	6AP.	not affected - worked around in hardware
    5.88 + *	7AP.	not affected - worked around in hardware
    5.89 + *	8AP.	worked around in hardware - we get explicit CS errors if not
    5.90 + *	9AP.	only 'noapic' mode affected. Might generate spurious
    5.91 + *		interrupts, we log only the first one and count the
    5.92 + *		rest silently.
    5.93 + *	10AP.	not affected - worked around in hardware
    5.94 + *	11AP.	Linux reads the APIC between writes to avoid this, as per
    5.95 + *		the documentation. Make sure you preserve this as it affects
    5.96 + *		the C stepping chips too.
    5.97 + *	12AP.	not affected - worked around in hardware
    5.98 + *	13AP.	not affected - worked around in hardware
    5.99 + *	14AP.	we always deassert INIT during bootup
   5.100 + *	15AP.	not affected - worked around in hardware
   5.101 + *	16AP.	not affected - worked around in hardware
   5.102 + *	17AP.	not affected - worked around in hardware
   5.103 + *	18AP.	not affected - worked around in hardware
   5.104 + *	19AP.	not affected - worked around in BIOS
   5.105 + *
   5.106 + *	If this sounds worrying believe me these bugs are either ___RARE___,
   5.107 + *	or are signal timing bugs worked around in hardware and there's
   5.108 + *	about nothing of note with C stepping upwards.
   5.109 + */
   5.110 +
   5.111 +DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0, };
   5.112 +
   5.113 +/*
   5.114 + * the following functions deal with sending IPIs between CPUs.
   5.115 + *
   5.116 + * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
   5.117 + */
   5.118 +
   5.119 +static inline int __prepare_ICR (unsigned int shortcut, int vector)
   5.120 +{
   5.121 +	return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
   5.122 +}
   5.123 +
   5.124 +static inline int __prepare_ICR2 (unsigned int mask)
   5.125 +{
   5.126 +	return SET_APIC_DEST_FIELD(mask);
   5.127 +}
   5.128 +
   5.129 +void __send_IPI_shortcut(unsigned int shortcut, int vector)
   5.130 +{
   5.131 +#if 1
   5.132 +	printk("__send_IPI_shortcut\n");
   5.133 +#else
   5.134 +	/*
   5.135 +	 * Subtle. In the case of the 'never do double writes' workaround
   5.136 +	 * we have to lock out interrupts to be safe.  As we don't care
   5.137 +	 * of the value read we use an atomic rmw access to avoid costly
   5.138 +	 * cli/sti.  Otherwise we use an even cheaper single atomic write
   5.139 +	 * to the APIC.
   5.140 +	 */
   5.141 +	unsigned int cfg;
   5.142 +
   5.143 +	/*
   5.144 +	 * Wait for idle.
   5.145 +	 */
   5.146 +	apic_wait_icr_idle();
   5.147 +
   5.148 +	/*
   5.149 +	 * No need to touch the target chip field
   5.150 +	 */
   5.151 +	cfg = __prepare_ICR(shortcut, vector);
   5.152 +
   5.153 +	/*
   5.154 +	 * Send the IPI. The write to APIC_ICR fires this off.
   5.155 +	 */
   5.156 +	apic_write_around(APIC_ICR, cfg);
   5.157 +#endif
   5.158 +}
   5.159 +
   5.160 +void fastcall send_IPI_self(int vector)
   5.161 +{
   5.162 +	__send_IPI_shortcut(APIC_DEST_SELF, vector);
   5.163 +}
   5.164 +
   5.165 +/*
   5.166 + * This is only used on smaller machines.
   5.167 + */
   5.168 +void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
   5.169 +{
   5.170 +#if 1
   5.171 +	printk("send_IPI_mask_bitmask\n");
   5.172 +#else
   5.173 +	unsigned long mask = cpus_addr(cpumask)[0];
   5.174 +	unsigned long cfg;
   5.175 +	unsigned long flags;
   5.176 +
   5.177 +	local_irq_save(flags);
   5.178 +		
   5.179 +	/*
   5.180 +	 * Wait for idle.
   5.181 +	 */
   5.182 +	apic_wait_icr_idle();
   5.183 +		
   5.184 +	/*
   5.185 +	 * prepare target chip field
   5.186 +	 */
   5.187 +	cfg = __prepare_ICR2(mask);
   5.188 +	apic_write_around(APIC_ICR2, cfg);
   5.189 +		
   5.190 +	/*
   5.191 +	 * program the ICR 
   5.192 +	 */
   5.193 +	cfg = __prepare_ICR(0, vector);
   5.194 +			
   5.195 +	/*
   5.196 +	 * Send the IPI. The write to APIC_ICR fires this off.
   5.197 +	 */
   5.198 +	apic_write_around(APIC_ICR, cfg);
   5.199 +
   5.200 +	local_irq_restore(flags);
   5.201 +#endif
   5.202 +}
   5.203 +
   5.204 +inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
   5.205 +{
   5.206 +#if 1
   5.207 +	printk("send_IPI_mask_sequence\n");
   5.208 +#else
   5.209 +	unsigned long cfg, flags;
   5.210 +	unsigned int query_cpu;
   5.211 +
   5.212 +	/*
   5.213 +	 * Hack. The clustered APIC addressing mode doesn't allow us to send 
   5.214 +	 * to an arbitrary mask, so I do a unicasts to each CPU instead. This 
   5.215 +	 * should be modified to do 1 message per cluster ID - mbligh
   5.216 +	 */ 
   5.217 +
   5.218 +	local_irq_save(flags);
   5.219 +
   5.220 +	for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
   5.221 +		if (cpu_isset(query_cpu, mask)) {
   5.222 +		
   5.223 +			/*
   5.224 +			 * Wait for idle.
   5.225 +			 */
   5.226 +			apic_wait_icr_idle();
   5.227 +		
   5.228 +			/*
   5.229 +			 * prepare target chip field
   5.230 +			 */
   5.231 +			cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
   5.232 +			apic_write_around(APIC_ICR2, cfg);
   5.233 +		
   5.234 +			/*
   5.235 +			 * program the ICR 
   5.236 +			 */
   5.237 +			cfg = __prepare_ICR(0, vector);
   5.238 +			
   5.239 +			/*
   5.240 +			 * Send the IPI. The write to APIC_ICR fires this off.
   5.241 +			 */
   5.242 +			apic_write_around(APIC_ICR, cfg);
   5.243 +		}
   5.244 +	}
   5.245 +	local_irq_restore(flags);
   5.246 +#endif
   5.247 +}
   5.248 +
   5.249 +#include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */
   5.250 +
   5.251 +/*
   5.252 + *	Smarter SMP flushing macros. 
   5.253 + *		c/o Linus Torvalds.
   5.254 + *
   5.255 + *	These mean you can really definitely utterly forget about
   5.256 + *	writing to user space from interrupts. (Its not allowed anyway).
   5.257 + *
   5.258 + *	Optimizations Manfred Spraul <manfred@colorfullife.com>
   5.259 + */
   5.260 +
   5.261 +static cpumask_t flush_cpumask;
   5.262 +static struct mm_struct * flush_mm;
   5.263 +static unsigned long flush_va;
   5.264 +static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED;
   5.265 +#define FLUSH_ALL	0xffffffff
   5.266 +
   5.267 +/*
   5.268 + * We cannot call mmdrop() because we are in interrupt context, 
   5.269 + * instead update mm->cpu_vm_mask.
   5.270 + *
   5.271 + * We need to reload %cr3 since the page tables may be going
   5.272 + * away from under us..
   5.273 + */
   5.274 +static inline void leave_mm (unsigned long cpu)
   5.275 +{
   5.276 +	if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
   5.277 +		BUG();
   5.278 +	cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask);
   5.279 +	load_cr3(swapper_pg_dir);
   5.280 +}
   5.281 +
   5.282 +/*
   5.283 + *
   5.284 + * The flush IPI assumes that a thread switch happens in this order:
   5.285 + * [cpu0: the cpu that switches]
   5.286 + * 1) switch_mm() either 1a) or 1b)
   5.287 + * 1a) thread switch to a different mm
   5.288 + * 1a1) cpu_clear(cpu, old_mm->cpu_vm_mask);
   5.289 + * 	Stop ipi delivery for the old mm. This is not synchronized with
   5.290 + * 	the other cpus, but smp_invalidate_interrupt ignore flush ipis
   5.291 + * 	for the wrong mm, and in the worst case we perform a superflous
   5.292 + * 	tlb flush.
   5.293 + * 1a2) set cpu_tlbstate to TLBSTATE_OK
   5.294 + * 	Now the smp_invalidate_interrupt won't call leave_mm if cpu0
   5.295 + *	was in lazy tlb mode.
   5.296 + * 1a3) update cpu_tlbstate[].active_mm
   5.297 + * 	Now cpu0 accepts tlb flushes for the new mm.
   5.298 + * 1a4) cpu_set(cpu, new_mm->cpu_vm_mask);
   5.299 + * 	Now the other cpus will send tlb flush ipis.
   5.300 + * 1a4) change cr3.
   5.301 + * 1b) thread switch without mm change
   5.302 + *	cpu_tlbstate[].active_mm is correct, cpu0 already handles
   5.303 + *	flush ipis.
   5.304 + * 1b1) set cpu_tlbstate to TLBSTATE_OK
   5.305 + * 1b2) test_and_set the cpu bit in cpu_vm_mask.
   5.306 + * 	Atomically set the bit [other cpus will start sending flush ipis],
   5.307 + * 	and test the bit.
   5.308 + * 1b3) if the bit was 0: leave_mm was called, flush the tlb.
   5.309 + * 2) switch %%esp, ie current
   5.310 + *
   5.311 + * The interrupt must handle 2 special cases:
   5.312 + * - cr3 is changed before %%esp, ie. it cannot use current->{active_,}mm.
   5.313 + * - the cpu performs speculative tlb reads, i.e. even if the cpu only
   5.314 + *   runs in kernel space, the cpu could load tlb entries for user space
   5.315 + *   pages.
   5.316 + *
   5.317 + * The good news is that cpu_tlbstate is local to each cpu, no
   5.318 + * write/read ordering problems.
   5.319 + */
   5.320 +
   5.321 +/*
   5.322 + * TLB flush IPI:
   5.323 + *
   5.324 + * 1) Flush the tlb entries if the cpu uses the mm that's being flushed.
   5.325 + * 2) Leave the mm if we are in the lazy tlb mode.
   5.326 + */
   5.327 +
   5.328 +asmlinkage void smp_invalidate_interrupt (void)
   5.329 +{
   5.330 +	unsigned long cpu;
   5.331 +
   5.332 +	cpu = get_cpu();
   5.333 +
   5.334 +	if (!cpu_isset(cpu, flush_cpumask))
   5.335 +		goto out;
   5.336 +		/* 
   5.337 +		 * This was a BUG() but until someone can quote me the
   5.338 +		 * line from the intel manual that guarantees an IPI to
   5.339 +		 * multiple CPUs is retried _only_ on the erroring CPUs
   5.340 +		 * its staying as a return
   5.341 +		 *
   5.342 +		 * BUG();
   5.343 +		 */
   5.344 +		 
   5.345 +	if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) {
   5.346 +		if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) {
   5.347 +			if (flush_va == FLUSH_ALL)
   5.348 +				local_flush_tlb();
   5.349 +			else
   5.350 +				__flush_tlb_one(flush_va);
   5.351 +		} else
   5.352 +			leave_mm(cpu);
   5.353 +	}
   5.354 +#if 1
   5.355 +	printk("smp_invalidate_interrupt ack_APIC_irq\n");
   5.356 +#else
   5.357 +	ack_APIC_irq();
   5.358 +#endif
   5.359 +	smp_mb__before_clear_bit();
   5.360 +	cpu_clear(cpu, flush_cpumask);
   5.361 +	smp_mb__after_clear_bit();
   5.362 +out:
   5.363 +	put_cpu_no_resched();
   5.364 +}
   5.365 +
   5.366 +static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
   5.367 +						unsigned long va)
   5.368 +{
   5.369 +	cpumask_t tmp;
   5.370 +	/*
   5.371 +	 * A couple of (to be removed) sanity checks:
   5.372 +	 *
   5.373 +	 * - we do not send IPIs to not-yet booted CPUs.
   5.374 +	 * - current CPU must not be in mask
   5.375 +	 * - mask must exist :)
   5.376 +	 */
   5.377 +	BUG_ON(cpus_empty(cpumask));
   5.378 +
   5.379 +	cpus_and(tmp, cpumask, cpu_online_map);
   5.380 +	BUG_ON(!cpus_equal(cpumask, tmp));
   5.381 +	BUG_ON(cpu_isset(smp_processor_id(), cpumask));
   5.382 +	BUG_ON(!mm);
   5.383 +
   5.384 +	/*
   5.385 +	 * i'm not happy about this global shared spinlock in the
   5.386 +	 * MM hot path, but we'll see how contended it is.
   5.387 +	 * Temporarily this turns IRQs off, so that lockups are
   5.388 +	 * detected by the NMI watchdog.
   5.389 +	 */
   5.390 +	spin_lock(&tlbstate_lock);
   5.391 +	
   5.392 +	flush_mm = mm;
   5.393 +	flush_va = va;
   5.394 +#if NR_CPUS <= BITS_PER_LONG
   5.395 +	atomic_set_mask(cpumask, &flush_cpumask);
   5.396 +#else
   5.397 +	{
   5.398 +		int k;
   5.399 +		unsigned long *flush_mask = (unsigned long *)&flush_cpumask;
   5.400 +		unsigned long *cpu_mask = (unsigned long *)&cpumask;
   5.401 +		for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k)
   5.402 +			atomic_set_mask(cpu_mask[k], &flush_mask[k]);
   5.403 +	}
   5.404 +#endif
   5.405 +	/*
   5.406 +	 * We have to send the IPI only to
   5.407 +	 * CPUs affected.
   5.408 +	 */
   5.409 +	send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
   5.410 +
   5.411 +	while (!cpus_empty(flush_cpumask))
   5.412 +		/* nothing. lockup detection does not belong here */
   5.413 +		mb();
   5.414 +
   5.415 +	flush_mm = NULL;
   5.416 +	flush_va = 0;
   5.417 +	spin_unlock(&tlbstate_lock);
   5.418 +}
   5.419 +	
   5.420 +void flush_tlb_current_task(void)
   5.421 +{
   5.422 +	struct mm_struct *mm = current->mm;
   5.423 +	cpumask_t cpu_mask;
   5.424 +
   5.425 +	preempt_disable();
   5.426 +	cpu_mask = mm->cpu_vm_mask;
   5.427 +	cpu_clear(smp_processor_id(), cpu_mask);
   5.428 +
   5.429 +	local_flush_tlb();
   5.430 +	if (!cpus_empty(cpu_mask))
   5.431 +		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
   5.432 +	preempt_enable();
   5.433 +}
   5.434 +
   5.435 +void flush_tlb_mm (struct mm_struct * mm)
   5.436 +{
   5.437 +	cpumask_t cpu_mask;
   5.438 +
   5.439 +	preempt_disable();
   5.440 +	cpu_mask = mm->cpu_vm_mask;
   5.441 +	cpu_clear(smp_processor_id(), cpu_mask);
   5.442 +
   5.443 +	if (current->active_mm == mm) {
   5.444 +		if (current->mm)
   5.445 +			local_flush_tlb();
   5.446 +		else
   5.447 +			leave_mm(smp_processor_id());
   5.448 +	}
   5.449 +	if (!cpus_empty(cpu_mask))
   5.450 +		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
   5.451 +
   5.452 +	preempt_enable();
   5.453 +}
   5.454 +
   5.455 +void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
   5.456 +{
   5.457 +	struct mm_struct *mm = vma->vm_mm;
   5.458 +	cpumask_t cpu_mask;
   5.459 +
   5.460 +	preempt_disable();
   5.461 +	cpu_mask = mm->cpu_vm_mask;
   5.462 +	cpu_clear(smp_processor_id(), cpu_mask);
   5.463 +
   5.464 +	if (current->active_mm == mm) {
   5.465 +		if(current->mm)
   5.466 +			__flush_tlb_one(va);
   5.467 +		 else
   5.468 +		 	leave_mm(smp_processor_id());
   5.469 +	}
   5.470 +
   5.471 +	if (!cpus_empty(cpu_mask))
   5.472 +		flush_tlb_others(cpu_mask, mm, va);
   5.473 +
   5.474 +	preempt_enable();
   5.475 +}
   5.476 +
   5.477 +static void do_flush_tlb_all(void* info)
   5.478 +{
   5.479 +	unsigned long cpu = smp_processor_id();
   5.480 +
   5.481 +	__flush_tlb_all();
   5.482 +	if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY)
   5.483 +		leave_mm(cpu);
   5.484 +}
   5.485 +
   5.486 +void flush_tlb_all(void)
   5.487 +{
   5.488 +	on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
   5.489 +}
   5.490 +
   5.491 +/*
   5.492 + * this function sends a 'reschedule' IPI to another CPU.
   5.493 + * it goes straight through and wastes no time serializing
   5.494 + * anything. Worst case is that we lose a reschedule ...
   5.495 + */
   5.496 +void smp_send_reschedule(int cpu)
   5.497 +{
   5.498 +	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
   5.499 +}
   5.500 +
   5.501 +/*
   5.502 + * Structure and data for smp_call_function(). This is designed to minimise
   5.503 + * static memory requirements. It also looks cleaner.
   5.504 + */
   5.505 +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
   5.506 +
   5.507 +struct call_data_struct {
   5.508 +	void (*func) (void *info);
   5.509 +	void *info;
   5.510 +	atomic_t started;
   5.511 +	atomic_t finished;
   5.512 +	int wait;
   5.513 +};
   5.514 +
   5.515 +static struct call_data_struct * call_data;
   5.516 +
   5.517 +/*
   5.518 + * this function sends a 'generic call function' IPI to all other CPUs
   5.519 + * in the system.
   5.520 + */
   5.521 +
   5.522 +int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
   5.523 +			int wait)
   5.524 +/*
   5.525 + * [SUMMARY] Run a function on all other CPUs.
   5.526 + * <func> The function to run. This must be fast and non-blocking.
   5.527 + * <info> An arbitrary pointer to pass to the function.
   5.528 + * <nonatomic> currently unused.
   5.529 + * <wait> If true, wait (atomically) until function has completed on other CPUs.
   5.530 + * [RETURNS] 0 on success, else a negative status code. Does not return until
   5.531 + * remote CPUs are nearly ready to execute <<func>> or are or have executed.
   5.532 + *
   5.533 + * You must not call this function with disabled interrupts or from a
   5.534 + * hardware interrupt handler or from a bottom half handler.
   5.535 + */
   5.536 +{
   5.537 +	struct call_data_struct data;
   5.538 +	int cpus = num_online_cpus()-1;
   5.539 +
   5.540 +	if (!cpus)
   5.541 +		return 0;
   5.542 +
   5.543 +	/* Can deadlock when called with interrupts disabled */
   5.544 +	WARN_ON(irqs_disabled());
   5.545 +
   5.546 +	data.func = func;
   5.547 +	data.info = info;
   5.548 +	atomic_set(&data.started, 0);
   5.549 +	data.wait = wait;
   5.550 +	if (wait)
   5.551 +		atomic_set(&data.finished, 0);
   5.552 +
   5.553 +	spin_lock(&call_lock);
   5.554 +	call_data = &data;
   5.555 +	mb();
   5.556 +	
   5.557 +	/* Send a message to all other CPUs and wait for them to respond */
   5.558 +	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
   5.559 +
   5.560 +	/* Wait for response */
   5.561 +	while (atomic_read(&data.started) != cpus)
   5.562 +		barrier();
   5.563 +
   5.564 +	if (wait)
   5.565 +		while (atomic_read(&data.finished) != cpus)
   5.566 +			barrier();
   5.567 +	spin_unlock(&call_lock);
   5.568 +
   5.569 +	return 0;
   5.570 +}
   5.571 +
   5.572 +static void stop_this_cpu (void * dummy)
   5.573 +{
   5.574 +	/*
   5.575 +	 * Remove this CPU:
   5.576 +	 */
   5.577 +	cpu_clear(smp_processor_id(), cpu_online_map);
   5.578 +	local_irq_disable();
   5.579 +#if 1
   5.580 +	printk("stop_this_cpu disable_local_APIC\n");
   5.581 +#else
   5.582 +	disable_local_APIC();
   5.583 +#endif
   5.584 +	if (cpu_data[smp_processor_id()].hlt_works_ok)
   5.585 +		for(;;) __asm__("hlt");
   5.586 +	for (;;);
   5.587 +}
   5.588 +
   5.589 +/*
   5.590 + * this function calls the 'stop' function on all other CPUs in the system.
   5.591 + */
   5.592 +
   5.593 +void smp_send_stop(void)
   5.594 +{
   5.595 +	smp_call_function(stop_this_cpu, NULL, 1, 0);
   5.596 +
   5.597 +	local_irq_disable();
   5.598 +#if 1
   5.599 +	printk("smp_send_stop disable_local_APIC\n");
   5.600 +#else
   5.601 +	disable_local_APIC();
   5.602 +#endif
   5.603 +	local_irq_enable();
   5.604 +}
   5.605 +
   5.606 +/*
   5.607 + * Reschedule call back. Nothing to do,
   5.608 + * all the work is done automatically when
   5.609 + * we return from the interrupt.
   5.610 + */
   5.611 +asmlinkage void smp_reschedule_interrupt(void)
   5.612 +{
   5.613 +#if 1
   5.614 +	printk("smp_reschedule_interrupt: ack_APIC_irq\n");
   5.615 +#else
   5.616 +	ack_APIC_irq();
   5.617 +#endif
   5.618 +}
   5.619 +
   5.620 +asmlinkage void smp_call_function_interrupt(void)
   5.621 +{
   5.622 +	void (*func) (void *info) = call_data->func;
   5.623 +	void *info = call_data->info;
   5.624 +	int wait = call_data->wait;
   5.625 +
   5.626 +#if 1
   5.627 +	printk("smp_call_function_interrupt: ack_APIC_irq\n");
   5.628 +#else
   5.629 +	ack_APIC_irq();
   5.630 +#endif
   5.631 +	/*
   5.632 +	 * Notify initiating CPU that I've grabbed the data and am
   5.633 +	 * about to execute the function
   5.634 +	 */
   5.635 +	mb();
   5.636 +	atomic_inc(&call_data->started);
   5.637 +	/*
   5.638 +	 * At this point the info structure may be out of scope unless wait==1
   5.639 +	 */
   5.640 +	irq_enter();
   5.641 +	(*func)(info);
   5.642 +	irq_exit();
   5.643 +
   5.644 +	if (wait) {
   5.645 +		mb();
   5.646 +		atomic_inc(&call_data->finished);
   5.647 +	}
   5.648 +}
   5.649 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c	Mon Nov 08 15:29:51 2004 +0000
     6.3 @@ -0,0 +1,1209 @@
     6.4 +/*
     6.5 + *	x86 SMP booting functions
     6.6 + *
     6.7 + *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
     6.8 + *	(c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
     6.9 + *
    6.10 + *	Much of the core SMP work is based on previous work by Thomas Radke, to
    6.11 + *	whom a great many thanks are extended.
    6.12 + *
    6.13 + *	Thanks to Intel for making available several different Pentium,
    6.14 + *	Pentium Pro and Pentium-II/Xeon MP machines.
    6.15 + *	Original development of Linux SMP code supported by Caldera.
    6.16 + *
    6.17 + *	This code is released under the GNU General Public License version 2 or
    6.18 + *	later.
    6.19 + *
    6.20 + *	Fixes
    6.21 + *		Felix Koop	:	NR_CPUS used properly
    6.22 + *		Jose Renau	:	Handle single CPU case.
    6.23 + *		Alan Cox	:	By repeated request 8) - Total BogoMIPS report.
    6.24 + *		Greg Wright	:	Fix for kernel stacks panic.
    6.25 + *		Erich Boleyn	:	MP v1.4 and additional changes.
    6.26 + *	Matthias Sattler	:	Changes for 2.1 kernel map.
    6.27 + *	Michel Lespinasse	:	Changes for 2.1 kernel map.
    6.28 + *	Michael Chastain	:	Change trampoline.S to gnu as.
    6.29 + *		Alan Cox	:	Dumb bug: 'B' step PPro's are fine
    6.30 + *		Ingo Molnar	:	Added APIC timers, based on code
    6.31 + *					from Jose Renau
    6.32 + *		Ingo Molnar	:	various cleanups and rewrites
    6.33 + *		Tigran Aivazian	:	fixed "0.00 in /proc/uptime on SMP" bug.
    6.34 + *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs
    6.35 + *		Martin J. Bligh	: 	Added support for multi-quad systems
    6.36 + *		Dave Jones	:	Report invalid combinations of Athlon CPUs.
    6.37 +*		Rusty Russell	:	Hacked into shape for new "hotplug" boot process. */
    6.38 +
    6.39 +#include <linux/module.h>
    6.40 +#include <linux/config.h>
    6.41 +#include <linux/init.h>
    6.42 +#include <linux/kernel.h>
    6.43 +
    6.44 +#include <linux/mm.h>
    6.45 +#include <linux/sched.h>
    6.46 +#include <linux/kernel_stat.h>
    6.47 +#include <linux/smp_lock.h>
    6.48 +#include <linux/irq.h>
    6.49 +#include <linux/bootmem.h>
    6.50 +
    6.51 +#include <linux/delay.h>
    6.52 +#include <linux/mc146818rtc.h>
    6.53 +#include <asm/tlbflush.h>
    6.54 +#include <asm/desc.h>
    6.55 +#include <asm/arch_hooks.h>
    6.56 +
    6.57 +#if 0
    6.58 +#include <mach_apic.h>
    6.59 +#endif
    6.60 +#include <mach_wakecpu.h>
    6.61 +#include <smpboot_hooks.h>
    6.62 +
    6.63 +#if 0
    6.64 +/* Set if we find a B stepping CPU */
    6.65 +static int __initdata smp_b_stepping;
    6.66 +#endif
    6.67 +
    6.68 +/* Number of siblings per CPU package */
    6.69 +int smp_num_siblings = 1;
    6.70 +int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
    6.71 +
    6.72 +/* bitmap of online cpus */
    6.73 +cpumask_t cpu_online_map;
    6.74 +
    6.75 +static cpumask_t cpu_callin_map;
    6.76 +cpumask_t cpu_callout_map;
    6.77 +static cpumask_t smp_commenced_mask;
    6.78 +
    6.79 +/* Per CPU bogomips and other parameters */
    6.80 +struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
    6.81 +
    6.82 +u8 x86_cpu_to_apicid[NR_CPUS] =
    6.83 +			{ [0 ... NR_CPUS-1] = 0xff };
    6.84 +EXPORT_SYMBOL(x86_cpu_to_apicid);
    6.85 +
    6.86 +/* Set when the idlers are all forked */
    6.87 +int smp_threads_ready;
    6.88 +
    6.89 +#if 0
    6.90 +/*
    6.91 + * Trampoline 80x86 program as an array.
    6.92 + */
    6.93 +
    6.94 +extern unsigned char trampoline_data [];
    6.95 +extern unsigned char trampoline_end  [];
    6.96 +static unsigned char *trampoline_base;
    6.97 +static int trampoline_exec;
    6.98 +
    6.99 +/*
   6.100 + * Currently trivial. Write the real->protected mode
   6.101 + * bootstrap into the page concerned. The caller
   6.102 + * has made sure it's suitably aligned.
   6.103 + */
   6.104 +
   6.105 +static unsigned long __init setup_trampoline(void)
   6.106 +{
   6.107 +	memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
   6.108 +	return virt_to_phys(trampoline_base);
   6.109 +}
   6.110 +#endif
   6.111 +
   6.112 +/*
   6.113 + * We are called very early to get the low memory for the
   6.114 + * SMP bootup trampoline page.
   6.115 + */
   6.116 +void __init smp_alloc_memory(void)
   6.117 +{
   6.118 +#if 1
   6.119 +	printk("smp_alloc_memory\n");
   6.120 +#else
   6.121 +	trampoline_base = (void *) alloc_bootmem_low_pages(PAGE_SIZE);
   6.122 +	/*
   6.123 +	 * Has to be in very low memory so we can execute
   6.124 +	 * real-mode AP code.
   6.125 +	 */
   6.126 +	if (__pa(trampoline_base) >= 0x9F000)
   6.127 +		BUG();
   6.128 +	/*
   6.129 +	 * Make the SMP trampoline executable:
   6.130 +	 */
   6.131 +	trampoline_exec = set_kernel_exec((unsigned long)trampoline_base, 1);
   6.132 +#endif
   6.133 +}
   6.134 +
   6.135 +/*
   6.136 + * The bootstrap kernel entry code has set these up. Save them for
   6.137 + * a given CPU
   6.138 + */
   6.139 +
   6.140 +#if 0
   6.141 +static void __init smp_store_cpu_info(int id)
   6.142 +{
   6.143 +	struct cpuinfo_x86 *c = cpu_data + id;
   6.144 +
   6.145 +	*c = boot_cpu_data;
   6.146 +	if (id!=0)
   6.147 +		identify_cpu(c);
   6.148 +	/*
   6.149 +	 * Mask B, Pentium, but not Pentium MMX
   6.150 +	 */
   6.151 +	if (c->x86_vendor == X86_VENDOR_INTEL &&
   6.152 +	    c->x86 == 5 &&
   6.153 +	    c->x86_mask >= 1 && c->x86_mask <= 4 &&
   6.154 +	    c->x86_model <= 3)
   6.155 +		/*
   6.156 +		 * Remember we have B step Pentia with bugs
   6.157 +		 */
   6.158 +		smp_b_stepping = 1;
   6.159 +
   6.160 +	/*
   6.161 +	 * Certain Athlons might work (for various values of 'work') in SMP
   6.162 +	 * but they are not certified as MP capable.
   6.163 +	 */
   6.164 +	if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
   6.165 +
   6.166 +		/* Athlon 660/661 is valid. */	
   6.167 +		if ((c->x86_model==6) && ((c->x86_mask==0) || (c->x86_mask==1)))
   6.168 +			goto valid_k7;
   6.169 +
   6.170 +		/* Duron 670 is valid */
   6.171 +		if ((c->x86_model==7) && (c->x86_mask==0))
   6.172 +			goto valid_k7;
   6.173 +
   6.174 +		/*
   6.175 +		 * Athlon 662, Duron 671, and Athlon >model 7 have capability bit.
   6.176 +		 * It's worth noting that the A5 stepping (662) of some Athlon XP's
   6.177 +		 * have the MP bit set.
   6.178 +		 * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for more.
   6.179 +		 */
   6.180 +		if (((c->x86_model==6) && (c->x86_mask>=2)) ||
   6.181 +		    ((c->x86_model==7) && (c->x86_mask>=1)) ||
   6.182 +		     (c->x86_model> 7))
   6.183 +			if (cpu_has_mp)
   6.184 +				goto valid_k7;
   6.185 +
   6.186 +		/* If we get here, it's not a certified SMP capable AMD system. */
   6.187 +		tainted |= TAINT_UNSAFE_SMP;
   6.188 +	}
   6.189 +
   6.190 +valid_k7:
   6.191 +	;
   6.192 +}
   6.193 +#endif
   6.194 +
   6.195 +#if 0
   6.196 +/*
   6.197 + * TSC synchronization.
   6.198 + *
   6.199 + * We first check whether all CPUs have their TSC's synchronized,
   6.200 + * then we print a warning if not, and always resync.
   6.201 + */
   6.202 +
   6.203 +static atomic_t tsc_start_flag = ATOMIC_INIT(0);
   6.204 +static atomic_t tsc_count_start = ATOMIC_INIT(0);
   6.205 +static atomic_t tsc_count_stop = ATOMIC_INIT(0);
   6.206 +static unsigned long long tsc_values[NR_CPUS];
   6.207 +
   6.208 +#define NR_LOOPS 5
   6.209 +
   6.210 +static void __init synchronize_tsc_bp (void)
   6.211 +{
   6.212 +	int i;
   6.213 +	unsigned long long t0;
   6.214 +	unsigned long long sum, avg;
   6.215 +	long long delta;
   6.216 +	unsigned long one_usec;
   6.217 +	int buggy = 0;
   6.218 +
   6.219 +	printk(KERN_INFO "checking TSC synchronization across %u CPUs: ", num_booting_cpus());
   6.220 +
   6.221 +	/* convert from kcyc/sec to cyc/usec */
   6.222 +	one_usec = cpu_khz / 1000;
   6.223 +
   6.224 +	atomic_set(&tsc_start_flag, 1);
   6.225 +	wmb();
   6.226 +
   6.227 +	/*
   6.228 +	 * We loop a few times to get a primed instruction cache,
   6.229 +	 * then the last pass is more or less synchronized and
   6.230 +	 * the BP and APs set their cycle counters to zero all at
   6.231 +	 * once. This reduces the chance of having random offsets
   6.232 +	 * between the processors, and guarantees that the maximum
   6.233 +	 * delay between the cycle counters is never bigger than
   6.234 +	 * the latency of information-passing (cachelines) between
   6.235 +	 * two CPUs.
   6.236 +	 */
   6.237 +	for (i = 0; i < NR_LOOPS; i++) {
   6.238 +		/*
   6.239 +		 * all APs synchronize but they loop on '== num_cpus'
   6.240 +		 */
   6.241 +		while (atomic_read(&tsc_count_start) != num_booting_cpus()-1)
   6.242 +			mb();
   6.243 +		atomic_set(&tsc_count_stop, 0);
   6.244 +		wmb();
   6.245 +		/*
   6.246 +		 * this lets the APs save their current TSC:
   6.247 +		 */
   6.248 +		atomic_inc(&tsc_count_start);
   6.249 +
   6.250 +		rdtscll(tsc_values[smp_processor_id()]);
   6.251 +		/*
   6.252 +		 * We clear the TSC in the last loop:
   6.253 +		 */
   6.254 +		if (i == NR_LOOPS-1)
   6.255 +			write_tsc(0, 0);
   6.256 +
   6.257 +		/*
   6.258 +		 * Wait for all APs to leave the synchronization point:
   6.259 +		 */
   6.260 +		while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1)
   6.261 +			mb();
   6.262 +		atomic_set(&tsc_count_start, 0);
   6.263 +		wmb();
   6.264 +		atomic_inc(&tsc_count_stop);
   6.265 +	}
   6.266 +
   6.267 +	sum = 0;
   6.268 +	for (i = 0; i < NR_CPUS; i++) {
   6.269 +		if (cpu_isset(i, cpu_callout_map)) {
   6.270 +			t0 = tsc_values[i];
   6.271 +			sum += t0;
   6.272 +		}
   6.273 +	}
   6.274 +	avg = sum;
   6.275 +	do_div(avg, num_booting_cpus());
   6.276 +
   6.277 +	sum = 0;
   6.278 +	for (i = 0; i < NR_CPUS; i++) {
   6.279 +		if (!cpu_isset(i, cpu_callout_map))
   6.280 +			continue;
   6.281 +		delta = tsc_values[i] - avg;
   6.282 +		if (delta < 0)
   6.283 +			delta = -delta;
   6.284 +		/*
   6.285 +		 * We report bigger than 2 microseconds clock differences.
   6.286 +		 */
   6.287 +		if (delta > 2*one_usec) {
   6.288 +			long realdelta;
   6.289 +			if (!buggy) {
   6.290 +				buggy = 1;
   6.291 +				printk("\n");
   6.292 +			}
   6.293 +			realdelta = delta;
   6.294 +			do_div(realdelta, one_usec);
   6.295 +			if (tsc_values[i] < avg)
   6.296 +				realdelta = -realdelta;
   6.297 +
   6.298 +			printk(KERN_INFO "CPU#%d had %ld usecs TSC skew, fixed it up.\n", i, realdelta);
   6.299 +		}
   6.300 +
   6.301 +		sum += delta;
   6.302 +	}
   6.303 +	if (!buggy)
   6.304 +		printk("passed.\n");
   6.305 +}
   6.306 +
   6.307 +static void __init synchronize_tsc_ap (void)
   6.308 +{
   6.309 +	int i;
   6.310 +
   6.311 +	/*
   6.312 +	 * Not every cpu is online at the time
   6.313 +	 * this gets called, so we first wait for the BP to
   6.314 +	 * finish SMP initialization:
   6.315 +	 */
   6.316 +	while (!atomic_read(&tsc_start_flag)) mb();
   6.317 +
   6.318 +	for (i = 0; i < NR_LOOPS; i++) {
   6.319 +		atomic_inc(&tsc_count_start);
   6.320 +		while (atomic_read(&tsc_count_start) != num_booting_cpus())
   6.321 +			mb();
   6.322 +
   6.323 +		rdtscll(tsc_values[smp_processor_id()]);
   6.324 +		if (i == NR_LOOPS-1)
   6.325 +			write_tsc(0, 0);
   6.326 +
   6.327 +		atomic_inc(&tsc_count_stop);
   6.328 +		while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
   6.329 +	}
   6.330 +}
   6.331 +#undef NR_LOOPS
   6.332 +
   6.333 +extern void calibrate_delay(void);
   6.334 +
   6.335 +static atomic_t init_deasserted;
   6.336 +#endif
   6.337 +
   6.338 +void __init smp_callin(void)
   6.339 +{
   6.340 +#if 1
   6.341 +	printk("smp_callin\n");
   6.342 +#else
   6.343 +	int cpuid, phys_id;
   6.344 +	unsigned long timeout;
   6.345 +
   6.346 +	/*
   6.347 +	 * If waken up by an INIT in an 82489DX configuration
   6.348 +	 * we may get here before an INIT-deassert IPI reaches
   6.349 +	 * our local APIC.  We have to wait for the IPI or we'll
   6.350 +	 * lock up on an APIC access.
   6.351 +	 */
   6.352 +	wait_for_init_deassert(&init_deasserted);
   6.353 +
   6.354 +	/*
   6.355 +	 * (This works even if the APIC is not enabled.)
   6.356 +	 */
   6.357 +	phys_id = GET_APIC_ID(apic_read(APIC_ID));
   6.358 +	cpuid = smp_processor_id();
   6.359 +	if (cpu_isset(cpuid, cpu_callin_map)) {
   6.360 +		printk("huh, phys CPU#%d, CPU#%d already present??\n",
   6.361 +					phys_id, cpuid);
   6.362 +		BUG();
   6.363 +	}
   6.364 +	Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
   6.365 +
   6.366 +	/*
   6.367 +	 * STARTUP IPIs are fragile beasts as they might sometimes
   6.368 +	 * trigger some glue motherboard logic. Complete APIC bus
   6.369 +	 * silence for 1 second, this overestimates the time the
   6.370 +	 * boot CPU is spending to send the up to 2 STARTUP IPIs
   6.371 +	 * by a factor of two. This should be enough.
   6.372 +	 */
   6.373 +
   6.374 +	/*
   6.375 +	 * Waiting 2s total for startup (udelay is not yet working)
   6.376 +	 */
   6.377 +	timeout = jiffies + 2*HZ;
   6.378 +	while (time_before(jiffies, timeout)) {
   6.379 +		/*
   6.380 +		 * Has the boot CPU finished it's STARTUP sequence?
   6.381 +		 */
   6.382 +		if (cpu_isset(cpuid, cpu_callout_map))
   6.383 +			break;
   6.384 +		rep_nop();
   6.385 +	}
   6.386 +
   6.387 +	if (!time_before(jiffies, timeout)) {
   6.388 +		printk("BUG: CPU%d started up but did not get a callout!\n",
   6.389 +			cpuid);
   6.390 +		BUG();
   6.391 +	}
   6.392 +
   6.393 +	/*
   6.394 +	 * the boot CPU has finished the init stage and is spinning
   6.395 +	 * on callin_map until we finish. We are free to set up this
   6.396 +	 * CPU, first the APIC. (this is probably redundant on most
   6.397 +	 * boards)
   6.398 +	 */
   6.399 +
   6.400 +	Dprintk("CALLIN, before setup_local_APIC().\n");
   6.401 +	smp_callin_clear_local_apic();
   6.402 +	setup_local_APIC();
   6.403 +	map_cpu_to_logical_apicid();
   6.404 +
   6.405 +	local_irq_enable();
   6.406 +
   6.407 +	/*
   6.408 +	 * Get our bogomips.
   6.409 +	 */
   6.410 +	calibrate_delay();
   6.411 +	Dprintk("Stack at about %p\n",&cpuid);
   6.412 +
   6.413 +	/*
   6.414 +	 * Save our processor parameters
   6.415 +	 */
   6.416 + 	smp_store_cpu_info(cpuid);
   6.417 +
   6.418 +	disable_APIC_timer();
   6.419 +	local_irq_disable();
   6.420 +	/*
   6.421 +	 * Allow the master to continue.
   6.422 +	 */
   6.423 +	cpu_set(cpuid, cpu_callin_map);
   6.424 +
   6.425 +	/*
   6.426 +	 *      Synchronize the TSC with the BP
   6.427 +	 */
   6.428 +	if (cpu_has_tsc && cpu_khz)
   6.429 +		synchronize_tsc_ap();
   6.430 +#endif
   6.431 +}
   6.432 +
   6.433 +int cpucount;
   6.434 +
   6.435 +extern int cpu_idle(void);
   6.436 +
   6.437 +/*
   6.438 + * Activate a secondary processor.
   6.439 + */
   6.440 +int __init start_secondary(void *unused)
   6.441 +{
   6.442 +#if 1
   6.443 +	printk("start_secondary\n");
   6.444 +	return cpu_idle();
   6.445 +#else
   6.446 +	/*
   6.447 +	 * Dont put anything before smp_callin(), SMP
   6.448 +	 * booting is too fragile that we want to limit the
   6.449 +	 * things done here to the most necessary things.
   6.450 +	 */
   6.451 +	cpu_init();
   6.452 +	smp_callin();
   6.453 +	while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
   6.454 +		rep_nop();
   6.455 +	setup_secondary_APIC_clock();
   6.456 +	if (nmi_watchdog == NMI_IO_APIC) {
   6.457 +		disable_8259A_irq(0);
   6.458 +		enable_NMI_through_LVT0(NULL);
   6.459 +		enable_8259A_irq(0);
   6.460 +	}
   6.461 +	enable_APIC_timer();
   6.462 +	/*
   6.463 +	 * low-memory mappings have been cleared, flush them from
   6.464 +	 * the local TLBs too.
   6.465 +	 */
   6.466 +	local_flush_tlb();
   6.467 +	cpu_set(smp_processor_id(), cpu_online_map);
   6.468 +	wmb();
   6.469 +	return cpu_idle();
   6.470 +#endif
   6.471 +}
   6.472 +
   6.473 +/*
   6.474 + * Everything has been set up for the secondary
   6.475 + * CPUs - they just need to reload everything
   6.476 + * from the task structure
   6.477 + * This function must not return.
   6.478 + */
   6.479 +void __init initialize_secondary(void)
   6.480 +{
   6.481 +	/*
   6.482 +	 * We don't actually need to load the full TSS,
   6.483 +	 * basically just the stack pointer and the eip.
   6.484 +	 */
   6.485 +
   6.486 +	asm volatile(
   6.487 +		"movl %0,%%esp\n\t"
   6.488 +		"jmp *%1"
   6.489 +		:
   6.490 +		:"r" (current->thread.esp),"r" (current->thread.eip));
   6.491 +}
   6.492 +
   6.493 +extern struct {
   6.494 +	void * esp;
   6.495 +	unsigned short ss;
   6.496 +} stack_start;
   6.497 +
   6.498 +#ifdef CONFIG_NUMA
   6.499 +
   6.500 +/* which logical CPUs are on which nodes */
   6.501 +cpumask_t node_2_cpu_mask[MAX_NUMNODES] =
   6.502 +				{ [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
   6.503 +/* which node each logical CPU is on */
   6.504 +int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 };
   6.505 +EXPORT_SYMBOL(cpu_2_node);
   6.506 +
   6.507 +/* set up a mapping between cpu and node. */
   6.508 +static inline void map_cpu_to_node(int cpu, int node)
   6.509 +{
   6.510 +	printk("Mapping cpu %d to node %d\n", cpu, node);
   6.511 +	cpu_set(cpu, node_2_cpu_mask[node]);
   6.512 +	cpu_2_node[cpu] = node;
   6.513 +}
   6.514 +
   6.515 +/* undo a mapping between cpu and node. */
   6.516 +static inline void unmap_cpu_to_node(int cpu)
   6.517 +{
   6.518 +	int node;
   6.519 +
   6.520 +	printk("Unmapping cpu %d from all nodes\n", cpu);
   6.521 +	for (node = 0; node < MAX_NUMNODES; node ++)
   6.522 +		cpu_clear(cpu, node_2_cpu_mask[node]);
   6.523 +	cpu_2_node[cpu] = 0;
   6.524 +}
   6.525 +#else /* !CONFIG_NUMA */
   6.526 +
   6.527 +#define map_cpu_to_node(cpu, node)	({})
   6.528 +#define unmap_cpu_to_node(cpu)	({})
   6.529 +
   6.530 +#endif /* CONFIG_NUMA */
   6.531 +
   6.532 +u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
   6.533 +
   6.534 +void map_cpu_to_logical_apicid(void)
   6.535 +{
   6.536 +#if 1
   6.537 +	printk("map_cpu_to_logical_apicid\n");
   6.538 +#else
   6.539 +	int cpu = smp_processor_id();
   6.540 +	int apicid = logical_smp_processor_id();
   6.541 +
   6.542 +	cpu_2_logical_apicid[cpu] = apicid;
   6.543 +	map_cpu_to_node(cpu, apicid_to_node(apicid));
   6.544 +#endif
   6.545 +}
   6.546 +
   6.547 +void unmap_cpu_to_logical_apicid(int cpu)
   6.548 +{
   6.549 +	cpu_2_logical_apicid[cpu] = BAD_APICID;
   6.550 +	unmap_cpu_to_node(cpu);
   6.551 +}
   6.552 +
   6.553 +#if APIC_DEBUG
   6.554 +static inline void __inquire_remote_apic(int apicid)
   6.555 +{
   6.556 +	int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
   6.557 +	char *names[] = { "ID", "VERSION", "SPIV" };
   6.558 +	int timeout, status;
   6.559 +
   6.560 +	printk("Inquiring remote APIC #%d...\n", apicid);
   6.561 +
   6.562 +	for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) {
   6.563 +		printk("... APIC #%d %s: ", apicid, names[i]);
   6.564 +
   6.565 +		/*
   6.566 +		 * Wait for idle.
   6.567 +		 */
   6.568 +		apic_wait_icr_idle();
   6.569 +
   6.570 +		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
   6.571 +		apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
   6.572 +
   6.573 +		timeout = 0;
   6.574 +		do {
   6.575 +			udelay(100);
   6.576 +			status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
   6.577 +		} while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
   6.578 +
   6.579 +		switch (status) {
   6.580 +		case APIC_ICR_RR_VALID:
   6.581 +			status = apic_read(APIC_RRR);
   6.582 +			printk("%08x\n", status);
   6.583 +			break;
   6.584 +		default:
   6.585 +			printk("failed\n");
   6.586 +		}
   6.587 +	}
   6.588 +}
   6.589 +#endif
   6.590 +
   6.591 +#if 0
   6.592 +#ifdef WAKE_SECONDARY_VIA_NMI
   6.593 +/* 
   6.594 + * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
   6.595 + * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
   6.596 + * won't ... remember to clear down the APIC, etc later.
   6.597 + */
   6.598 +static int __init
   6.599 +wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
   6.600 +{
   6.601 +	unsigned long send_status = 0, accept_status = 0;
   6.602 +	int timeout, maxlvt;
   6.603 +
   6.604 +	/* Target chip */
   6.605 +	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
   6.606 +
   6.607 +	/* Boot on the stack */
   6.608 +	/* Kick the second */
   6.609 +	apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
   6.610 +
   6.611 +	Dprintk("Waiting for send to finish...\n");
   6.612 +	timeout = 0;
   6.613 +	do {
   6.614 +		Dprintk("+");
   6.615 +		udelay(100);
   6.616 +		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
   6.617 +	} while (send_status && (timeout++ < 1000));
   6.618 +
   6.619 +	/*
   6.620 +	 * Give the other CPU some time to accept the IPI.
   6.621 +	 */
   6.622 +	udelay(200);
   6.623 +	/*
   6.624 +	 * Due to the Pentium erratum 3AP.
   6.625 +	 */
   6.626 +	maxlvt = get_maxlvt();
   6.627 +	if (maxlvt > 3) {
   6.628 +		apic_read_around(APIC_SPIV);
   6.629 +		apic_write(APIC_ESR, 0);
   6.630 +	}
   6.631 +	accept_status = (apic_read(APIC_ESR) & 0xEF);
   6.632 +	Dprintk("NMI sent.\n");
   6.633 +
   6.634 +	if (send_status)
   6.635 +		printk("APIC never delivered???\n");
   6.636 +	if (accept_status)
   6.637 +		printk("APIC delivery error (%lx).\n", accept_status);
   6.638 +
   6.639 +	return (send_status | accept_status);
   6.640 +}
   6.641 +#endif	/* WAKE_SECONDARY_VIA_NMI */
   6.642 +
   6.643 +#ifdef WAKE_SECONDARY_VIA_INIT
   6.644 +static int __init
   6.645 +wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
   6.646 +{
   6.647 +#if 1
   6.648 +	printk("wakeup_secondary_cpu\n");
   6.649 +	return 0;
   6.650 +#else
   6.651 +	unsigned long send_status = 0, accept_status = 0;
   6.652 +	int maxlvt, timeout, num_starts, j;
   6.653 +
   6.654 +	/*
   6.655 +	 * Be paranoid about clearing APIC errors.
   6.656 +	 */
   6.657 +	if (APIC_INTEGRATED(apic_version[phys_apicid])) {
   6.658 +		apic_read_around(APIC_SPIV);
   6.659 +		apic_write(APIC_ESR, 0);
   6.660 +		apic_read(APIC_ESR);
   6.661 +	}
   6.662 +
   6.663 +	Dprintk("Asserting INIT.\n");
   6.664 +
   6.665 +	/*
   6.666 +	 * Turn INIT on target chip
   6.667 +	 */
   6.668 +	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
   6.669 +
   6.670 +	/*
   6.671 +	 * Send IPI
   6.672 +	 */
   6.673 +	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
   6.674 +				| APIC_DM_INIT);
   6.675 +
   6.676 +	Dprintk("Waiting for send to finish...\n");
   6.677 +	timeout = 0;
   6.678 +	do {
   6.679 +		Dprintk("+");
   6.680 +		udelay(100);
   6.681 +		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
   6.682 +	} while (send_status && (timeout++ < 1000));
   6.683 +
   6.684 +	mdelay(10);
   6.685 +
   6.686 +	Dprintk("Deasserting INIT.\n");
   6.687 +
   6.688 +	/* Target chip */
   6.689 +	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
   6.690 +
   6.691 +	/* Send IPI */
   6.692 +	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
   6.693 +
   6.694 +	Dprintk("Waiting for send to finish...\n");
   6.695 +	timeout = 0;
   6.696 +	do {
   6.697 +		Dprintk("+");
   6.698 +		udelay(100);
   6.699 +		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
   6.700 +	} while (send_status && (timeout++ < 1000));
   6.701 +
   6.702 +	atomic_set(&init_deasserted, 1);
   6.703 +
   6.704 +	/*
   6.705 +	 * Should we send STARTUP IPIs ?
   6.706 +	 *
   6.707 +	 * Determine this based on the APIC version.
   6.708 +	 * If we don't have an integrated APIC, don't send the STARTUP IPIs.
   6.709 +	 */
   6.710 +	if (APIC_INTEGRATED(apic_version[phys_apicid]))
   6.711 +		num_starts = 2;
   6.712 +	else
   6.713 +		num_starts = 0;
   6.714 +
   6.715 +	/*
   6.716 +	 * Run STARTUP IPI loop.
   6.717 +	 */
   6.718 +	Dprintk("#startup loops: %d.\n", num_starts);
   6.719 +
   6.720 +	maxlvt = get_maxlvt();
   6.721 +
   6.722 +	for (j = 1; j <= num_starts; j++) {
   6.723 +		Dprintk("Sending STARTUP #%d.\n",j);
   6.724 +		apic_read_around(APIC_SPIV);
   6.725 +		apic_write(APIC_ESR, 0);
   6.726 +		apic_read(APIC_ESR);
   6.727 +		Dprintk("After apic_write.\n");
   6.728 +
   6.729 +		/*
   6.730 +		 * STARTUP IPI
   6.731 +		 */
   6.732 +
   6.733 +		/* Target chip */
   6.734 +		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
   6.735 +
   6.736 +		/* Boot on the stack */
   6.737 +		/* Kick the second */
   6.738 +		apic_write_around(APIC_ICR, APIC_DM_STARTUP
   6.739 +					| (start_eip >> 12));
   6.740 +
   6.741 +		/*
   6.742 +		 * Give the other CPU some time to accept the IPI.
   6.743 +		 */
   6.744 +		udelay(300);
   6.745 +
   6.746 +		Dprintk("Startup point 1.\n");
   6.747 +
   6.748 +		Dprintk("Waiting for send to finish...\n");
   6.749 +		timeout = 0;
   6.750 +		do {
   6.751 +			Dprintk("+");
   6.752 +			udelay(100);
   6.753 +			send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
   6.754 +		} while (send_status && (timeout++ < 1000));
   6.755 +
   6.756 +		/*
   6.757 +		 * Give the other CPU some time to accept the IPI.
   6.758 +		 */
   6.759 +		udelay(200);
   6.760 +		/*
   6.761 +		 * Due to the Pentium erratum 3AP.
   6.762 +		 */
   6.763 +		if (maxlvt > 3) {
   6.764 +			apic_read_around(APIC_SPIV);
   6.765 +			apic_write(APIC_ESR, 0);
   6.766 +		}
   6.767 +		accept_status = (apic_read(APIC_ESR) & 0xEF);
   6.768 +		if (send_status || accept_status)
   6.769 +			break;
   6.770 +	}
   6.771 +	Dprintk("After Startup.\n");
   6.772 +
   6.773 +	if (send_status)
   6.774 +		printk("APIC never delivered???\n");
   6.775 +	if (accept_status)
   6.776 +		printk("APIC delivery error (%lx).\n", accept_status);
   6.777 +
   6.778 +	return (send_status | accept_status);
   6.779 +#endif
   6.780 +}
   6.781 +#endif	/* WAKE_SECONDARY_VIA_INIT */
   6.782 +#endif
   6.783 +
   6.784 +extern cpumask_t cpu_initialized;
   6.785 +
   6.786 +#if 0
   6.787 +static int __init do_boot_cpu(int apicid)
   6.788 +/*
   6.789 + * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
   6.790 + * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
   6.791 + * Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu.
   6.792 + */
   6.793 +{
   6.794 +	struct task_struct *idle;
   6.795 +	unsigned long boot_error;
   6.796 +	int timeout, cpu;
   6.797 +	unsigned long start_eip;
   6.798 +	unsigned short nmi_high = 0, nmi_low = 0;
   6.799 +
   6.800 +	cpu = ++cpucount;
   6.801 +	/*
   6.802 +	 * We can't use kernel_thread since we must avoid to
   6.803 +	 * reschedule the child.
   6.804 +	 */
   6.805 +	idle = fork_idle(cpu);
   6.806 +	if (IS_ERR(idle))
   6.807 +		panic("failed fork for CPU %d", cpu);
   6.808 +	idle->thread.eip = (unsigned long) start_secondary;
   6.809 +	/* start_eip had better be page-aligned! */
   6.810 +	start_eip = setup_trampoline();
   6.811 +
   6.812 +	/* So we see what's up   */
   6.813 +	printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
   6.814 +	/* Stack for startup_32 can be just as for start_secondary onwards */
   6.815 +	stack_start.esp = (void *) idle->thread.esp;
   6.816 +
   6.817 +	irq_ctx_init(cpu);
   6.818 +
   6.819 +	/*
   6.820 +	 * This grunge runs the startup process for
   6.821 +	 * the targeted processor.
   6.822 +	 */
   6.823 +
   6.824 +	atomic_set(&init_deasserted, 0);
   6.825 +
   6.826 +	Dprintk("Setting warm reset code and vector.\n");
   6.827 +
   6.828 +	store_NMI_vector(&nmi_high, &nmi_low);
   6.829 +
   6.830 +	smpboot_setup_warm_reset_vector(start_eip);
   6.831 +
   6.832 +	/*
   6.833 +	 * Starting actual IPI sequence...
   6.834 +	 */
   6.835 +	boot_error = wakeup_secondary_cpu(apicid, start_eip);
   6.836 +
   6.837 +	if (!boot_error) {
   6.838 +		/*
   6.839 +		 * allow APs to start initializing.
   6.840 +		 */
   6.841 +		Dprintk("Before Callout %d.\n", cpu);
   6.842 +		cpu_set(cpu, cpu_callout_map);
   6.843 +		Dprintk("After Callout %d.\n", cpu);
   6.844 +
   6.845 +		/*
   6.846 +		 * Wait 5s total for a response
   6.847 +		 */
   6.848 +		for (timeout = 0; timeout < 50000; timeout++) {
   6.849 +			if (cpu_isset(cpu, cpu_callin_map))
   6.850 +				break;	/* It has booted */
   6.851 +			udelay(100);
   6.852 +		}
   6.853 +
   6.854 +		if (cpu_isset(cpu, cpu_callin_map)) {
   6.855 +			/* number CPUs logically, starting from 1 (BSP is 0) */
   6.856 +			Dprintk("OK.\n");
   6.857 +			printk("CPU%d: ", cpu);
   6.858 +			print_cpu_info(&cpu_data[cpu]);
   6.859 +			Dprintk("CPU has booted.\n");
   6.860 +		} else {
   6.861 +			boot_error= 1;
   6.862 +			if (*((volatile unsigned char *)trampoline_base)
   6.863 +					== 0xA5)
   6.864 +				/* trampoline started but...? */
   6.865 +				printk("Stuck ??\n");
   6.866 +			else
   6.867 +				/* trampoline code not run */
   6.868 +				printk("Not responding.\n");
   6.869 +			inquire_remote_apic(apicid);
   6.870 +		}
   6.871 +	}
   6.872 +	x86_cpu_to_apicid[cpu] = apicid;
   6.873 +	if (boot_error) {
   6.874 +		/* Try to put things back the way they were before ... */
   6.875 +		unmap_cpu_to_logical_apicid(cpu);
   6.876 +		cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
   6.877 +		cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
   6.878 +		cpucount--;
   6.879 +	}
   6.880 +
   6.881 +	/* mark "stuck" area as not stuck */
   6.882 +	*((volatile unsigned long *)trampoline_base) = 0;
   6.883 +
   6.884 +	return boot_error;
   6.885 +}
   6.886 +
   6.887 +cycles_t cacheflush_time;
   6.888 +#endif
   6.889 +unsigned long cache_decay_ticks;
   6.890 +#if 0
   6.891 +
   6.892 +static void smp_tune_scheduling (void)
   6.893 +{
   6.894 +	unsigned long cachesize;       /* kB   */
   6.895 +	unsigned long bandwidth = 350; /* MB/s */
   6.896 +	/*
   6.897 +	 * Rough estimation for SMP scheduling, this is the number of
   6.898 +	 * cycles it takes for a fully memory-limited process to flush
   6.899 +	 * the SMP-local cache.
   6.900 +	 *
   6.901 +	 * (For a P5 this pretty much means we will choose another idle
   6.902 +	 *  CPU almost always at wakeup time (this is due to the small
   6.903 +	 *  L1 cache), on PIIs it's around 50-100 usecs, depending on
   6.904 +	 *  the cache size)
   6.905 +	 */
   6.906 +
   6.907 +	if (!cpu_khz) {
   6.908 +		/*
   6.909 +		 * this basically disables processor-affinity
   6.910 +		 * scheduling on SMP without a TSC.
   6.911 +		 */
   6.912 +		cacheflush_time = 0;
   6.913 +		return;
   6.914 +	} else {
   6.915 +		cachesize = boot_cpu_data.x86_cache_size;
   6.916 +		if (cachesize == -1) {
   6.917 +			cachesize = 16; /* Pentiums, 2x8kB cache */
   6.918 +			bandwidth = 100;
   6.919 +		}
   6.920 +
   6.921 +		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
   6.922 +	}
   6.923 +
   6.924 +	cache_decay_ticks = (long)cacheflush_time/cpu_khz + 1;
   6.925 +
   6.926 +	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
   6.927 +		(long)cacheflush_time/(cpu_khz/1000),
   6.928 +		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
   6.929 +	printk("task migration cache decay timeout: %ld msecs.\n",
   6.930 +		cache_decay_ticks);
   6.931 +}
   6.932 +
   6.933 +/*
   6.934 + * Cycle through the processors sending APIC IPIs to boot each.
   6.935 + */
   6.936 +
   6.937 +static int boot_cpu_logical_apicid;
   6.938 +#endif
   6.939 +/* Where the IO area was mapped on multiquad, always 0 otherwise */
   6.940 +void *xquad_portio;
   6.941 +
   6.942 +cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
   6.943 +
   6.944 +static void __init smp_boot_cpus(unsigned int max_cpus)
   6.945 +{
   6.946 +#if 1
   6.947 +	printk("smp_boot_cpus %d\n", max_cpus);
   6.948 +#else
   6.949 +	int apicid, cpu, bit, kicked;
   6.950 +	unsigned long bogosum = 0;
   6.951 +
   6.952 +	/*
   6.953 +	 * Setup boot CPU information
   6.954 +	 */
   6.955 +	smp_store_cpu_info(0); /* Final full version of the data */
   6.956 +	printk("CPU%d: ", 0);
   6.957 +	print_cpu_info(&cpu_data[0]);
   6.958 +
   6.959 +	boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
   6.960 +	boot_cpu_logical_apicid = logical_smp_processor_id();
   6.961 +	x86_cpu_to_apicid[0] = boot_cpu_physical_apicid;
   6.962 +
   6.963 +	current_thread_info()->cpu = 0;
   6.964 +	smp_tune_scheduling();
   6.965 +	cpus_clear(cpu_sibling_map[0]);
   6.966 +	cpu_set(0, cpu_sibling_map[0]);
   6.967 +
   6.968 +	/*
   6.969 +	 * If we couldn't find an SMP configuration at boot time,
   6.970 +	 * get out of here now!
   6.971 +	 */
   6.972 +	if (!smp_found_config && !acpi_lapic) {
   6.973 +		printk(KERN_NOTICE "SMP motherboard not detected.\n");
   6.974 +		smpboot_clear_io_apic_irqs();
   6.975 +		phys_cpu_present_map = physid_mask_of_physid(0);
   6.976 +		if (APIC_init_uniprocessor())
   6.977 +			printk(KERN_NOTICE "Local APIC not detected."
   6.978 +					   " Using dummy APIC emulation.\n");
   6.979 +		map_cpu_to_logical_apicid();
   6.980 +		return;
   6.981 +	}
   6.982 +
   6.983 +	/*
   6.984 +	 * Should not be necessary because the MP table should list the boot
   6.985 +	 * CPU too, but we do it for the sake of robustness anyway.
   6.986 +	 * Makes no sense to do this check in clustered apic mode, so skip it
   6.987 +	 */
   6.988 +	if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
   6.989 +		printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
   6.990 +				boot_cpu_physical_apicid);
   6.991 +		physid_set(hard_smp_processor_id(), phys_cpu_present_map);
   6.992 +	}
   6.993 +
   6.994 +	/*
   6.995 +	 * If we couldn't find a local APIC, then get out of here now!
   6.996 +	 */
   6.997 +	if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) {
   6.998 +		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
   6.999 +			boot_cpu_physical_apicid);
  6.1000 +		printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
  6.1001 +		smpboot_clear_io_apic_irqs();
  6.1002 +		phys_cpu_present_map = physid_mask_of_physid(0);
  6.1003 +		return;
  6.1004 +	}
  6.1005 +
  6.1006 +	verify_local_APIC();
  6.1007 +
  6.1008 +	/*
  6.1009 +	 * If SMP should be disabled, then really disable it!
  6.1010 +	 */
  6.1011 +	if (!max_cpus) {
  6.1012 +		smp_found_config = 0;
  6.1013 +		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
  6.1014 +		smpboot_clear_io_apic_irqs();
  6.1015 +		phys_cpu_present_map = physid_mask_of_physid(0);
  6.1016 +		return;
  6.1017 +	}
  6.1018 +
  6.1019 +	connect_bsp_APIC();
  6.1020 +	setup_local_APIC();
  6.1021 +	map_cpu_to_logical_apicid();
  6.1022 +
  6.1023 +
  6.1024 +	setup_portio_remap();
  6.1025 +
  6.1026 +	/*
  6.1027 +	 * Scan the CPU present map and fire up the other CPUs via do_boot_cpu
  6.1028 +	 *
  6.1029 +	 * In clustered apic mode, phys_cpu_present_map is a constructed thus:
  6.1030 +	 * bits 0-3 are quad0, 4-7 are quad1, etc. A perverse twist on the 
  6.1031 +	 * clustered apic ID.
  6.1032 +	 */
  6.1033 +	Dprintk("CPU present map: %lx\n", physids_coerce(phys_cpu_present_map));
  6.1034 +
  6.1035 +	kicked = 1;
  6.1036 +	for (bit = 0; kicked < NR_CPUS && bit < MAX_APICS; bit++) {
  6.1037 +		apicid = cpu_present_to_apicid(bit);
  6.1038 +		/*
  6.1039 +		 * Don't even attempt to start the boot CPU!
  6.1040 +		 */
  6.1041 +		if ((apicid == boot_cpu_apicid) || (apicid == BAD_APICID))
  6.1042 +			continue;
  6.1043 +
  6.1044 +		if (!check_apicid_present(bit))
  6.1045 +			continue;
  6.1046 +		if (max_cpus <= cpucount+1)
  6.1047 +			continue;
  6.1048 +
  6.1049 +		if (do_boot_cpu(apicid))
  6.1050 +			printk("CPU #%d not responding - cannot use it.\n",
  6.1051 +								apicid);
  6.1052 +		else
  6.1053 +			++kicked;
  6.1054 +	}
  6.1055 +
  6.1056 +	/*
  6.1057 +	 * Cleanup possible dangling ends...
  6.1058 +	 */
  6.1059 +	smpboot_restore_warm_reset_vector();
  6.1060 +
  6.1061 +	/*
  6.1062 +	 * Allow the user to impress friends.
  6.1063 +	 */
  6.1064 +	Dprintk("Before bogomips.\n");
  6.1065 +	for (cpu = 0; cpu < NR_CPUS; cpu++)
  6.1066 +		if (cpu_isset(cpu, cpu_callout_map))
  6.1067 +			bogosum += cpu_data[cpu].loops_per_jiffy;
  6.1068 +	printk(KERN_INFO
  6.1069 +		"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
  6.1070 +		cpucount+1,
  6.1071 +		bogosum/(500000/HZ),
  6.1072 +		(bogosum/(5000/HZ))%100);
  6.1073 +	
  6.1074 +	Dprintk("Before bogocount - setting activated=1.\n");
  6.1075 +
  6.1076 +	if (smp_b_stepping)
  6.1077 +		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
  6.1078 +
  6.1079 +	/*
  6.1080 +	 * Don't taint if we are running SMP kernel on a single non-MP
  6.1081 +	 * approved Athlon
  6.1082 +	 */
  6.1083 +	if (tainted & TAINT_UNSAFE_SMP) {
  6.1084 +		if (cpucount)
  6.1085 +			printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n");
  6.1086 +		else
  6.1087 +			tainted &= ~TAINT_UNSAFE_SMP;
  6.1088 +	}
  6.1089 +
  6.1090 +	Dprintk("Boot done.\n");
  6.1091 +
  6.1092 +	/*
  6.1093 +	 * construct cpu_sibling_map[], so that we can tell sibling CPUs
  6.1094 +	 * efficiently.
  6.1095 +	 */
  6.1096 +	for (cpu = 0; cpu < NR_CPUS; cpu++)
  6.1097 +		cpus_clear(cpu_sibling_map[cpu]);
  6.1098 +
  6.1099 +	for (cpu = 0; cpu < NR_CPUS; cpu++) {
  6.1100 +		int siblings = 0;
  6.1101 +		int i;
  6.1102 +		if (!cpu_isset(cpu, cpu_callout_map))
  6.1103 +			continue;
  6.1104 +
  6.1105 +		if (smp_num_siblings > 1) {
  6.1106 +			for (i = 0; i < NR_CPUS; i++) {
  6.1107 +				if (!cpu_isset(i, cpu_callout_map))
  6.1108 +					continue;
  6.1109 +				if (phys_proc_id[cpu] == phys_proc_id[i]) {
  6.1110 +					siblings++;
  6.1111 +					cpu_set(i, cpu_sibling_map[cpu]);
  6.1112 +				}
  6.1113 +			}
  6.1114 +		} else {
  6.1115 +			siblings++;
  6.1116 +			cpu_set(cpu, cpu_sibling_map[cpu]);
  6.1117 +		}
  6.1118 +
  6.1119 +		if (siblings != smp_num_siblings)
  6.1120 +			printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
  6.1121 +	}
  6.1122 +
  6.1123 +	if (nmi_watchdog == NMI_LOCAL_APIC)
  6.1124 +		check_nmi_watchdog();
  6.1125 +
  6.1126 +	smpboot_setup_io_apic();
  6.1127 +
  6.1128 +	setup_boot_APIC_clock();
  6.1129 +
  6.1130 +	/*
  6.1131 +	 * Synchronize the TSC with the AP
  6.1132 +	 */
  6.1133 +	if (cpu_has_tsc && cpucount && cpu_khz)
  6.1134 +		synchronize_tsc_bp();
  6.1135 +#endif
  6.1136 +}
  6.1137 +
  6.1138 +/* These are wrappers to interface to the new boot process.  Someone
  6.1139 +   who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
  6.1140 +void __init smp_prepare_cpus(unsigned int max_cpus)
  6.1141 +{
  6.1142 +	smp_boot_cpus(max_cpus);
  6.1143 +}
  6.1144 +
  6.1145 +void __devinit smp_prepare_boot_cpu(void)
  6.1146 +{
  6.1147 +	cpu_set(smp_processor_id(), cpu_online_map);
  6.1148 +	cpu_set(smp_processor_id(), cpu_callout_map);
  6.1149 +}
  6.1150 +
  6.1151 +int __devinit __cpu_up(unsigned int cpu)
  6.1152 +{
  6.1153 +	/* This only works at boot for x86.  See "rewrite" above. */
  6.1154 +	if (cpu_isset(cpu, smp_commenced_mask)) {
  6.1155 +		local_irq_enable();
  6.1156 +		return -ENOSYS;
  6.1157 +	}
  6.1158 +
  6.1159 +	/* In case one didn't come up */
  6.1160 +	if (!cpu_isset(cpu, cpu_callin_map)) {
  6.1161 +		local_irq_enable();
  6.1162 +		return -EIO;
  6.1163 +	}
  6.1164 +
  6.1165 +	local_irq_enable();
  6.1166 +	/* Unleash the CPU! */
  6.1167 +	cpu_set(cpu, smp_commenced_mask);
  6.1168 +	while (!cpu_isset(cpu, cpu_online_map))
  6.1169 +		mb();
  6.1170 +	return 0;
  6.1171 +}
  6.1172 +
  6.1173 +void __init smp_cpus_done(unsigned int max_cpus)
  6.1174 +{
  6.1175 +#if 1
  6.1176 +	printk("smp_cpus_done %d\n", max_cpus);
  6.1177 +#else
  6.1178 +#ifdef CONFIG_X86_IO_APIC
  6.1179 +	setup_ioapic_dest();
  6.1180 +#endif
  6.1181 +	zap_low_mappings();
  6.1182 +	/*
  6.1183 +	 * Disable executability of the SMP trampoline:
  6.1184 +	 */
  6.1185 +	set_kernel_exec((unsigned long)trampoline_base, trampoline_exec);
  6.1186 +#endif
  6.1187 +}
  6.1188 +
  6.1189 +void __init smp_intr_init(void)
  6.1190 +{
  6.1191 +#if 1
  6.1192 +	printk("smp_intr_init\n");
  6.1193 +#else
  6.1194 +	/*
  6.1195 +	 * IRQ0 must be given a fixed assignment and initialized,
  6.1196 +	 * because it's used before the IO-APIC is set up.
  6.1197 +	 */
  6.1198 +	set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
  6.1199 +
  6.1200 +	/*
  6.1201 +	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
  6.1202 +	 * IPI, driven by wakeup.
  6.1203 +	 */
  6.1204 +	set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
  6.1205 +
  6.1206 +	/* IPI for invalidation */
  6.1207 +	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
  6.1208 +
  6.1209 +	/* IPI for generic function call */
  6.1210 +	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
  6.1211 +#endif
  6.1212 +}
     7.1 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/time.c	Mon Nov 08 13:44:07 2004 +0000
     7.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/time.c	Mon Nov 08 15:29:51 2004 +0000
     7.3 @@ -401,6 +401,11 @@ static inline void do_timer_interrupt(in
     7.4  		delta -= NS_PER_TICK;
     7.5  		processed_system_time += NS_PER_TICK;
     7.6  		do_timer(regs);
     7.7 +#ifdef CONFIG_SMP
     7.8 +		if (regs)	/* XXXsmp this needs to be done on every cpu
     7.9 +				 * - every tick - maybe  */
    7.10 +		    update_process_times(user_mode(regs));
    7.11 +#endif
    7.12  		if (regs)
    7.13  		    profile_tick(CPU_PROFILING, regs);
    7.14  	}
     8.1 --- a/linux-2.6.9-xen-sparse/arch/xen/kernel/Makefile	Mon Nov 08 13:44:07 2004 +0000
     8.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/kernel/Makefile	Mon Nov 08 15:29:51 2004 +0000
     8.3 @@ -10,4 +10,4 @@ XENARCH	:= $(subst ",,$(CONFIG_XENARCH))
     8.4  extra-y += vmlinux.lds
     8.5  
     8.6  obj-y	:= ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o empty.o \
     8.7 -           gnttab.o skbuff.o
     8.8 +           gnttab.o skbuff.o smp.o
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/kernel/smp.c	Mon Nov 08 15:29:51 2004 +0000
     9.3 @@ -0,0 +1,19 @@
     9.4 +/* Copyright (C) 2004, Christian Limpach */
     9.5 +
     9.6 +#include <linux/init.h>
     9.7 +#include <linux/kernel.h>
     9.8 +#include <linux/threads.h>
     9.9 +
    9.10 +unsigned int __initdata maxcpus = NR_CPUS;
    9.11 +
    9.12 +
    9.13 +/*
    9.14 + * the frequency of the profiling timer can be changed
    9.15 + * by writing a multiplier value into /proc/profile.
    9.16 + */
    9.17 +int setup_profiling_timer(unsigned int multiplier)
    9.18 +{
    9.19 +	printk("setup_profiling_timer\n");
    9.20 +
    9.21 +	return 0;
    9.22 +}
    10.1 --- a/linux-2.6.9-xen-sparse/drivers/xen/console/console.c	Mon Nov 08 13:44:07 2004 +0000
    10.2 +++ b/linux-2.6.9-xen-sparse/drivers/xen/console/console.c	Mon Nov 08 15:29:51 2004 +0000
    10.3 @@ -238,7 +238,7 @@ void xencons_force_flush(void)
    10.4       * We use dangerous control-interface functions that require a quiescent
    10.5       * system and no interrupts. Try to ensure this with a global cli().
    10.6       */
    10.7 -    cli();
    10.8 +    local_irq_disable();	/* XXXsmp */
    10.9  
   10.10      /* Spin until console data is flushed through to the domain controller. */
   10.11      while ( (wc != wp) && !ctrl_if_transmitter_empty() )
    11.1 --- a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h	Mon Nov 08 13:44:07 2004 +0000
    11.2 +++ b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h	Mon Nov 08 15:29:51 2004 +0000
    11.3 @@ -77,7 +77,6 @@
    11.4   * the usable vector space is 0x20-0xff (224 vectors)
    11.5   */
    11.6  
    11.7 -#if 0
    11.8  /*
    11.9   * The maximum number of vectors supported by i386 processors
   11.10   * is limited to 256. For processors other than i386, NR_VECTORS
   11.11 @@ -85,6 +84,7 @@
   11.12   */
   11.13  #define NR_VECTORS 256
   11.14  
   11.15 +#if 0
   11.16  #ifdef CONFIG_PCI_USE_VECTOR
   11.17  #define NR_IRQS FIRST_SYSTEM_VECTOR
   11.18  #define NR_IRQ_VECTORS NR_IRQS
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h	Mon Nov 08 15:29:51 2004 +0000
    12.3 @@ -0,0 +1,56 @@
    12.4 +/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws
    12.5 + * which needs to alter them. */
    12.6 +
    12.7 +static inline void smpboot_clear_io_apic_irqs(void)
    12.8 +{
    12.9 +#if 1
   12.10 +	printk("smpboot_clear_io_apic_irqs\n");
   12.11 +#else
   12.12 +	io_apic_irqs = 0;
   12.13 +#endif
   12.14 +}
   12.15 +
   12.16 +static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
   12.17 +{
   12.18 +#if 1
   12.19 +	printk("smpboot_setup_warm_reset_vector\n");
   12.20 +#else
   12.21 +	CMOS_WRITE(0xa, 0xf);
   12.22 +	local_flush_tlb();
   12.23 +	Dprintk("1.\n");
   12.24 +	*((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
   12.25 +	Dprintk("2.\n");
   12.26 +	*((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
   12.27 +	Dprintk("3.\n");
   12.28 +#endif
   12.29 +}
   12.30 +
   12.31 +static inline void smpboot_restore_warm_reset_vector(void)
   12.32 +{
   12.33 +	/*
   12.34 +	 * Install writable page 0 entry to set BIOS data area.
   12.35 +	 */
   12.36 +	local_flush_tlb();
   12.37 +
   12.38 +	/*
   12.39 +	 * Paranoid:  Set warm reset code and vector here back
   12.40 +	 * to default values.
   12.41 +	 */
   12.42 +	CMOS_WRITE(0, 0xf);
   12.43 +
   12.44 +	*((volatile long *) phys_to_virt(0x467)) = 0;
   12.45 +}
   12.46 +
   12.47 +static inline void smpboot_setup_io_apic(void)
   12.48 +{
   12.49 +#if 1
   12.50 +	printk("smpboot_setup_io_apic\n");
   12.51 +#else
   12.52 +	/*
   12.53 +	 * Here we can be sure that there is an IO-APIC in the system. Let's
   12.54 +	 * go and set it up:
   12.55 +	 */
   12.56 +	if (!skip_ioapic_setup && nr_ioapics)
   12.57 +		setup_IO_APIC();
   12.58 +#endif
   12.59 +}
    13.1 --- a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/msr.h	Mon Nov 08 13:44:07 2004 +0000
    13.2 +++ b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/msr.h	Mon Nov 08 15:29:51 2004 +0000
    13.3 @@ -1,7 +1,6 @@
    13.4  #ifndef __ASM_MSR_H
    13.5  #define __ASM_MSR_H
    13.6  
    13.7 -#include <linux/smp.h>
    13.8  #include <asm-xen/hypervisor.h>
    13.9  
   13.10  /*
   13.11 @@ -10,12 +9,14 @@
   13.12   * pointer indirection), this allows gcc to optimize better
   13.13   */
   13.14  
   13.15 +extern int get_smp_processor_id(void);
   13.16 +
   13.17  #define rdmsr(_msr,_val1,_val2) do { \
   13.18  	dom0_op_t op; \
   13.19  	op.cmd = DOM0_MSR; \
   13.20  	op.u.msr.write = 0; \
   13.21  	op.u.msr.msr = (_msr); \
   13.22 -	op.u.msr.cpu_mask = (1 << smp_processor_id()); \
   13.23 +	op.u.msr.cpu_mask = (1 << get_smp_processor_id()); \
   13.24  	HYPERVISOR_dom0_op(&op); \
   13.25  	(_val1) = op.u.msr.out1; \
   13.26  	(_val2) = op.u.msr.out2; \
   13.27 @@ -25,7 +26,7 @@
   13.28  	dom0_op_t op; \
   13.29  	op.cmd = DOM0_MSR; \
   13.30  	op.u.msr.write = 1; \
   13.31 -	op.u.msr.cpu_mask = (1 << smp_processor_id()); \
   13.32 +	op.u.msr.cpu_mask = (1 << get_smp_processor_id()); \
   13.33  	op.u.msr.msr = (_msr); \
   13.34  	op.u.msr.in1 = (_val1); \
   13.35  	op.u.msr.in2 = (_val2); \