this is against vanilla 2.2.2, these are mainly SMP fixes that were too
risky for 2.2.2:

 - hopefully nailed down the real cause of 'unexpected interrupts'.
   Unfortunately this impacts all other boxes in a nontrivial way too, so
   please test this patch so i can see wether this really works ...

 - TSC calibration patch added. This again is a patch that fixes a few
   but impacts all SMP boxes.

 - new 'forcecpus=' boot config option. Those with no or quirky MP config
   can now 'fall back' to a safe (albeit IO-APIC-less) mode.

-- mingo

--- linux/init/main.c.orig      Wed Feb 24 09:12:40 1999
+++ linux/init/main.c   Wed Feb 24 09:28:35 1999
@@ -89,6 +89,7 @@
 #endif
 
 extern void smp_setup(char *str, int *ints);
+extern void smp_force_setup(char *str, int *ints);
 #ifdef __i386__
 extern void ioapic_pirq_setup(char *str, int *ints);
 extern void ioapic_setup(char *str, int *ints);
@@ -542,6 +543,7 @@
 #ifdef __SMP__
        { "nosmp", smp_setup },
        { "maxcpus=", smp_setup },
+       { "forcecpus=", smp_force_setup },
 #ifdef CONFIG_X86_IO_APIC
        { "noapic", ioapic_setup },
        { "pirq=", ioapic_pirq_setup },
--- linux/arch/i386/kernel/smp.c.orig   Wed Feb 24 09:02:44 1999
+++ linux/arch/i386/kernel/smp.c        Wed Feb 24 09:28:57 1999
@@ -97,6 +97,7 @@
 static int smp_b_stepping = 0;                         /* Set if we find a B stepping 
CPU                      */
 
 static int max_cpus = -1;                              /* Setup configured maximum 
number of CPUs to activate  */
+static int forced_cpus = 0;                            /* Setup configured number of 
+CPUs to activate, even if no SMP config is found */
 int smp_found_config=0;                                        /* Have we found an 
SMP box                             */
 
 unsigned long cpu_present_map = 0;                     /* Bitmask of physically 
existing CPUs                          */
@@ -176,6 +177,38 @@
                max_cpus = 0;
 }
 
+void __init smp_force_setup(char *str, int *ints)
+{
+       int i;
+
+       if (ints && ints[0] > 0)
+               forced_cpus = ints[1];
+       else {
+               forced_cpus = 0;
+               return;
+       }
+       if (forced_cpus > NR_CPUS) {
+               printk("warning: can force only %d CPUs\n", NR_CPUS);
+               forced_cpus = NR_CPUS;
+       }
+       /*
+        * forced config takes precedence.
+        */
+       smp_found_config = 1;
+
+       cpu_present_map = (1<<forced_cpus)-1;
+       for (i = 0; i < forced_cpus; i++) {
+               apic_version[i] = 0x10; /* integrated APIC */
+       }
+       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+       /*
+        * it doesnt make much sense to try the IOAPIC without
+        * some MP config help ...
+        */
+       skip_ioapic_setup = 1;
+}
+
 void ack_APIC_irq(void)
 {
        /* Clear the IPI */
@@ -634,6 +667,11 @@
  */
 void __init init_smp_config (void)
 {
+       /*
+        * We might have forced a default configuration
+        */
+       if (smp_found_config)
+               return;
 #ifndef CONFIG_VISWS
        init_intel_smp();
 #else
@@ -793,6 +831,179 @@
        return memory_start;
 }
 
+#ifdef CONFIG_X86_TSC
+/*
+ * TSC synchronization.
+ *
+ * We first check wether all CPUs have their TSC's synchronized,
+ * then we print a warning if not, and always resync.
+ */
+
+static atomic_t tsc_start_flag = ATOMIC_INIT(0);
+static atomic_t tsc_count_start = ATOMIC_INIT(0);
+static atomic_t tsc_count_stop = ATOMIC_INIT(0);
+static unsigned long long tsc_values[NR_CPUS] = { 0, };
+
+#define NR_LOOPS 5
+
+extern unsigned long fast_gettimeoffset_quotient;
+
+/*
+ * accurate 64-bit division, expanded to 32-bit divisions. Not terribly
+ * optimized but we need it at boot time only anyway.
+ *
+ * result == a / b
+ *        == (a1 + a2*(2^32)) / b
+ *        == a1/b + a2*(2^32/b)
+ *        == a1/b + a2*((2^32-1)/b) + a2/b + (a2*((2^32-1) % b))/b
+ *                    ^---- (this multiplication can overflow)
+ */
+
+unsigned long long div64 (unsigned long long a, unsigned long long b)
+{
+       unsigned int a1, a2, b0;
+       unsigned long long res;
+
+       if (b > 0x00000000ffffffffULL)
+               return 0;
+       if (!b)
+               panic("huh?\n");
+
+       b0 = (unsigned int) b;
+       a1 = ((unsigned int*)&a)[0];
+       a2 = ((unsigned int*)&a)[1];
+
+       res = a1/b0 +
+               (unsigned long long)a2 * (unsigned long long)(0xffffffff/b0) +
+               a2 / b0 +
+               (a2 * (0xffffffff % b0)) / b0;
+
+        return res;
+}
+
+
+static void __init synchronize_tsc_bp (void)
+{
+       int i;
+       unsigned long long t0;
+       unsigned long long sum, avg;
+       long long delta;
+       unsigned long one_usec;
+       int buggy = 0;
+
+       printk("checking TSC synchronization across CPUs: ");
+
+       one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2);
+       
+       atomic_set(&tsc_start_flag, 1);
+       wmb();
+
+       /*
+        * We loop a few times to get a primed instruction cache,
+        * then the last pass is more or less synchronized and
+        * the BP and APs set their cycle counters to zero all at
+        * once. This reduces the chance of having random offsets
+        * between the processors, and guarantees that the maximum
+        * delay between the cycle counters is never bigger than
+        * the latency of information-passing (cachelines) between
+        * two CPUs.
+        */
+       for (i = 0; i < NR_LOOPS; i++) {
+               /*
+                * all APs synchronize but they loop on '== num_cpus'
+                */
+               while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb();
+               atomic_set(&tsc_count_stop, 0);
+               wmb();
+               /*
+                * this lets the APs save their current TSC:
+                */
+               atomic_inc(&tsc_count_start);
+
+               READ_TSC(tsc_values[smp_processor_id()]);
+               /*
+                * We clear the TSC in the last loop:
+                */
+               if (i == NR_LOOPS-1)
+                       CLEAR_TSC;
+
+               /*
+                * Wait for all APs to leave the synchronization point:
+                */
+               while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb();
+               atomic_set(&tsc_count_start, 0);
+               wmb();
+               atomic_inc(&tsc_count_stop);
+       }
+
+       sum = 0;
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!(cpu_online_map & (1 << i)))
+                       continue;
+
+               t0 = tsc_values[i];
+               sum += t0;
+       }
+       avg = div64(sum, smp_num_cpus);
+
+       sum = 0;
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!(cpu_online_map & (1 << i)))
+                       continue;
+
+               delta = tsc_values[i] - avg;
+               if (delta < 0)
+                       delta = -delta;
+               /*
+                * We report bigger than 2 microseconds clock differences.
+                */
+               if (delta > 2*one_usec) {
+                       long realdelta;
+                       if (!buggy) {
+                               buggy = 1;
+                               printk("\n");
+                       }
+                       realdelta = div64(delta, one_usec);
+                       if (tsc_values[i] < avg)
+                               realdelta = -realdelta;
+               
+                       printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs 
+TSC skew! FIXED.\n",
+                               i, realdelta);
+               }
+                               
+               sum += delta;
+       }
+       if (!buggy)
+               printk("passed.\n");
+}
+
+static void __init synchronize_tsc_ap (void)
+{
+       int i;
+
+       /*
+        * smp_num_cpus is not necessarily known at the time
+        * this gets called, so we first wait for the BP to
+        * finish SMP initialization:
+        */
+       while (!atomic_read(&tsc_start_flag)) mb();
+
+       for (i = 0; i < NR_LOOPS; i++) {
+               atomic_inc(&tsc_count_start);
+               while (atomic_read(&tsc_count_start) != smp_num_cpus) mb();
+
+               READ_TSC(tsc_values[smp_processor_id()]);
+               if (i == NR_LOOPS-1)
+                       CLEAR_TSC;
+
+               atomic_inc(&tsc_count_stop);
+               while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb();
+       }
+}
+#undef NR_LOOPS
+
+#endif
+
 extern void calibrate_delay(void);
 
 void __init smp_callin(void)
@@ -870,6 +1081,13 @@
         *      Allow the master to continue.
         */
        set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+
+#ifdef CONFIG_X86_TSC
+       /*
+        *      Synchronize the TSC with the BP
+        */
+       synchronize_tsc_ap ();
+#endif
 }
 
 int cpucount = 0;
@@ -1391,8 +1609,15 @@
 #endif
 
 smp_done:
-}
 
+#ifdef CONFIG_X86_TSC
+       /*
+        * Synchronize the TSC with the AP
+        */
+       if (cpucount)
+               synchronize_tsc_bp();
+#endif
+}
 
 /*
  * the following functions deal with sending IPIs between CPUs.
--- linux/arch/i386/kernel/time.c.orig  Wed Feb 24 09:26:19 1999
+++ linux/arch/i386/kernel/time.c       Wed Feb 24 09:27:22 1999
@@ -86,7 +86,7 @@
  * Equal to 2^32 * (1 / (clocks per usec) ).
  * Initialized in time_init.
  */
-static unsigned long fast_gettimeoffset_quotient=0;
+unsigned long fast_gettimeoffset_quotient=0;
 
 extern rwlock_t xtime_lock;
 
--- linux/arch/i386/kernel/io_apic.c.orig       Wed Feb 24 09:02:44 1999
+++ linux/arch/i386/kernel/io_apic.c    Wed Feb 24 09:35:51 1999
@@ -591,9 +591,15 @@
                memset(&entry,0,sizeof(entry));
 
                entry.delivery_mode = dest_LowestPrio;
+#if 1
+               entry.dest_mode = 0;                    /* physical delivery */
+               entry.mask = 0;                         /* enable IRQ */
+               entry.dest.physical.physical_dest = 0;  /* but no route */
+#else
                entry.dest_mode = 1;                    /* logical delivery */
                entry.mask = 0;                         /* enable IRQ */
                entry.dest.logical.logical_dest = 0;    /* but no route */
+#endif
 
                idx = find_irq_entry(pin,mp_INT);
                if (idx == -1) {

-
Linux SMP list: FIRST see FAQ at http://www.irisa.fr/prive/mentre/smp-faq/
To Unsubscribe: send "unsubscribe linux-smp" to [EMAIL PROTECTED]

Reply via email to