lkml.org 
[lkml]   [2001]   [Sep]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: Patches to enable ia32 NUMA system (32 proc)
    > The only thing I reacted to in these patches is:
    >
    >> diff -urN virgin-2.4.10/init/main.c numa-2.4.10/init/main.c
    >> --- virgin-2.4.10/init/main.c Thu Sep 20 21:02:01 2001
    >> +++ numa-2.4.10/init/main.c Thu Sep 27 11:57:21 2001
    >> @@ -490,9 +490,19 @@
    >>
    >> #else
    >>
    >> +/* Where the IO area was mapped on multiquad, always 0 otherwise */
    >> +void *xquad_portio = NULL;
    > ...
    >
    > This is _definitely_ the wrong place to have magic x86-only code.

    True.

    > Why don't you just move that into the top of smp_boot_cpus()?

    Fixed - new patch below.

    Martin.

    --------------------------------------------------

    diff -urN virgin-2.4.10/Documentation/Configure.help numa-2.4.10/Documentation/Configure.help
    --- virgin-2.4.10/Documentation/Configure.help Sun Sep 23 09:52:38 2001
    +++ numa-2.4.10/Documentation/Configure.help Wed Sep 26 16:04:34 2001
    @@ -119,6 +119,14 @@
    SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ .

    If you don't know what to do here, say N.
    +
    +Multiquad support for NUMA systems
    +CONFIG_MULTIQUAD
    + This option is used for getting Linux to run on a (IBM/Sequent) NUMA
    + multiquad box. This changes the way that processors are bootstrapped,
    + and uses Clustered Logical APIC addressing mode instead of Flat Logical.
    + You will need a new lynxer.elf file to flash your firmware with - send
    + email to Martin.Bligh@us.ibm.com

    APIC and IO-APIC Support on Uniprocessors
    CONFIG_X86_UP_IOAPIC
    diff -urN virgin-2.4.10/arch/i386/boot/compressed/misc.c numa-2.4.10/arch/i386/boot/compressed/misc.c
    --- virgin-2.4.10/arch/i386/boot/compressed/misc.c Tue Sep 11 23:02:02 2001
    +++ numa-2.4.10/arch/i386/boot/compressed/misc.c Wed Sep 26 16:04:34 2001
    @@ -123,6 +123,10 @@
    static int vidport;
    static int lines, cols;

    +#ifdef CONFIG_MULTIQUAD
    +static void *xquad_portio = NULL;
    +#endif
    +
    #include "../../../../lib/inflate.c"

    static void *malloc(int size)
    diff -urN virgin-2.4.10/arch/i386/config.in numa-2.4.10/arch/i386/config.in
    --- virgin-2.4.10/arch/i386/config.in Mon Sep 17 22:52:35 2001
    +++ numa-2.4.10/arch/i386/config.in Wed Sep 26 16:04:34 2001
    @@ -175,6 +175,8 @@
    define_bool CONFIG_X86_IO_APIC y
    define_bool CONFIG_X86_LOCAL_APIC y
    fi
    +else
    + bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
    fi

    if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
    diff -urN virgin-2.4.10/arch/i386/kernel/apic.c numa-2.4.10/arch/i386/kernel/apic.c
    --- virgin-2.4.10/arch/i386/kernel/apic.c Mon Sep 17 23:03:09 2001
    +++ numa-2.4.10/arch/i386/kernel/apic.c Wed Sep 26 16:24:26 2001
    @@ -48,7 +48,7 @@
    return maxlvt;
    }

    -static void clear_local_APIC(void)
    +void clear_local_APIC(void)
    {
    int maxlvt;
    unsigned long v;
    @@ -254,6 +254,14 @@
    {
    unsigned long value, ver, maxlvt;

    + /* Pound the ESR really hard over the head with a big hammer - mbligh */
    + if (esr_disable) {
    + apic_write(APIC_ESR, 0);
    + apic_write(APIC_ESR, 0);
    + apic_write(APIC_ESR, 0);
    + apic_write(APIC_ESR, 0);
    + }
    +
    value = apic_read(APIC_LVR);
    ver = GET_APIC_VERSION(value);

    @@ -262,8 +270,10 @@

    /*
    * Double-check wether this APIC is really registered.
    + * This is meaningless in clustered apic mode, so we skip it.
    */
    - if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
    + if (!clustered_apic_mode &&
    + !test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
    BUG();

    /*
    @@ -272,19 +282,22 @@
    * document number 292116). So here it goes...
    */

    - /*
    - * Put the APIC into flat delivery mode.
    - * Must be "all ones" explicitly for 82489DX.
    - */
    - apic_write_around(APIC_DFR, 0xffffffff);
    + if (!clustered_apic_mode) {
    + /*
    + * In clustered apic mode, the firmware does this for us
    + * Put the APIC into flat delivery mode.
    + * Must be "all ones" explicitly for 82489DX.
    + */
    + apic_write_around(APIC_DFR, 0xffffffff);

    - /*
    - * Set up the logical destination ID.
    - */
    - value = apic_read(APIC_LDR);
    - value &= ~APIC_LDR_MASK;
    - value |= (1<<(smp_processor_id()+24));
    - apic_write_around(APIC_LDR, value);
    + /*
    + * Set up the logical destination ID.
    + */
    + value = apic_read(APIC_LDR);
    + value &= ~APIC_LDR_MASK;
    + value |= (1<<(smp_processor_id()+24));
    + apic_write_around(APIC_LDR, value);
    + }

    /*
    * Set Task Priority to 'accept all'. We never change this
    @@ -367,7 +380,7 @@
    value |= APIC_LVT_LEVEL_TRIGGER;
    apic_write_around(APIC_LVT1, value);

    - if (APIC_INTEGRATED(ver)) { /* !82489DX */
    + if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */
    maxlvt = get_maxlvt();
    if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
    apic_write(APIC_ESR, 0);
    @@ -383,8 +396,18 @@
    apic_write(APIC_ESR, 0);
    value = apic_read(APIC_ESR);
    printk("ESR value after enabling vector: %08lx\n", value);
    - } else
    - printk("No ESR for 82489DX.\n");
    + } else {
    + if (esr_disable)
    + /*
    + * Something untraceble is creating bad interrupts on
    + * secondary quads ... for the moment, just leave the
    + * ESR disabled - we can't do anything useful with the
    + * errors anyway - mbligh
    + */
    + printk("Leaving ESR disabled.\n");
    + else
    + printk("No ESR for 82489DX.\n");
    + }

    if (nmi_watchdog == NMI_LOCAL_APIC)
    setup_apic_nmi_watchdog();
    @@ -598,7 +621,7 @@
    }
    set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability);
    mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
    - boot_cpu_id = 0;
    + boot_cpu_physical_apicid = 0;
    if (nmi_watchdog != NMI_NONE)
    nmi_watchdog = NMI_LOCAL_APIC;

    @@ -636,8 +659,8 @@
    * Fetch the APIC ID of the BSP in case we have a
    * default configuration (or the MP table is broken).
    */
    - if (boot_cpu_id == -1U)
    - boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
    + if (boot_cpu_physical_apicid == -1U)
    + boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));

    #ifdef CONFIG_X86_IO_APIC
    {
    @@ -1077,9 +1100,9 @@
    /*
    * Complain if the BIOS pretends there is one.
    */
    - if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) {
    + if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
    printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
    - boot_cpu_id);
    + boot_cpu_physical_apicid);
    return -1;
    }

    @@ -1088,7 +1111,7 @@
    connect_bsp_APIC();

    phys_cpu_present_map = 1;
    - apic_write_around(APIC_ID, boot_cpu_id);
    + apic_write_around(APIC_ID, boot_cpu_physical_apicid);

    apic_pm_init2();

    diff -urN virgin-2.4.10/arch/i386/kernel/io_apic.c numa-2.4.10/arch/i386/kernel/io_apic.c
    --- virgin-2.4.10/arch/i386/kernel/io_apic.c Mon Sep 17 23:03:09 2001
    +++ numa-2.4.10/arch/i386/kernel/io_apic.c Wed Sep 26 16:04:34 2001
    @@ -44,11 +44,6 @@
    */
    int nr_ioapic_registers[MAX_IO_APICS];

    -#if CONFIG_SMP
    -# define TARGET_CPUS cpu_online_map
    -#else
    -# define TARGET_CPUS 0x01
    -#endif
    /*
    * Rough estimation of how many shared IRQs there are, can
    * be changed anytime.
    @@ -603,7 +598,7 @@
    memset(&entry,0,sizeof(entry));

    entry.delivery_mode = dest_LowestPrio;
    - entry.dest_mode = 1; /* logical delivery */
    + entry.dest_mode = INT_DELIVERY_MODE;
    entry.mask = 0; /* enable IRQ */
    entry.dest.logical.logical_dest = TARGET_CPUS;

    @@ -677,7 +672,7 @@
    * We use logical delivery to get the timer IRQ
    * to the first CPU.
    */
    - entry.dest_mode = 1; /* logical delivery */
    + entry.dest_mode = INT_DELIVERY_MODE;
    entry.mask = 0; /* unmask IRQ now */
    entry.dest.logical.logical_dest = TARGET_CPUS;
    entry.delivery_mode = dest_LowestPrio;
    @@ -1016,6 +1011,9 @@
    unsigned char old_id;
    unsigned long flags;

    + if (clustered_apic_mode)
    + /* We don't have a good way to do this yet - hack */
    + phys_id_present_map = (u_long) 0xf;
    /*
    * Set the IOAPIC ID to the value stored in the MPC table.
    */
    @@ -1053,7 +1051,11 @@
    i);
    phys_id_present_map |= 1 << i;
    mp_ioapics[apic].mpc_apicid = i;
    + } else {
    + printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid);
    + phys_id_present_map |= 1 << mp_ioapics[apic].mpc_apicid;
    }
    +

    /*
    * We need to adjust the IRQ routing table
    diff -urN virgin-2.4.10/arch/i386/kernel/mpparse.c numa-2.4.10/arch/i386/kernel/mpparse.c
    --- virgin-2.4.10/arch/i386/kernel/mpparse.c Mon Sep 17 23:03:09 2001
    +++ numa-2.4.10/arch/i386/kernel/mpparse.c Wed Sep 26 16:04:34 2001
    @@ -54,7 +54,7 @@
    unsigned long mp_lapic_addr;

    /* Processor that is doing the boot up */
    -unsigned int boot_cpu_id = -1U;
    +unsigned int boot_cpu_physical_apicid = -1U;
    /* Internal processor count */
    static unsigned int num_processors;

    @@ -180,8 +180,9 @@

    if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
    Dprintk(" Bootup CPU\n");
    - boot_cpu_id = m->mpc_apicid;
    + boot_cpu_physical_apicid = m->mpc_apicid;
    }
    +
    num_processors++;

    if (m->mpc_apicid > MAX_APICS) {
    @@ -191,7 +192,12 @@
    }
    ver = m->mpc_apicver;

    - phys_cpu_present_map |= 1 << m->mpc_apicid;
    + if (clustered_apic_mode)
    + /* Crude temporary hack. Assumes processors are sequential */
    + phys_cpu_present_map |= 1 << (num_processors-1);
    + else
    + phys_cpu_present_map |= 1 << m->mpc_apicid;
    +
    /*
    * Validate version
    */
    @@ -376,6 +382,10 @@
    break;
    }
    }
    + }
    + if (clustered_apic_mode && nr_ioapics > 2) {
    + /* don't initialise IO apics on secondary quads */
    + nr_ioapics = 2;
    }
    if (!num_processors)
    printk(KERN_ERR "SMP mptable: no processors registered!\n");
    diff -urN virgin-2.4.10/arch/i386/kernel/process.c numa-2.4.10/arch/i386/kernel/process.c
    --- virgin-2.4.10/arch/i386/kernel/process.c Mon Sep 17 22:52:35 2001
    +++ numa-2.4.10/arch/i386/kernel/process.c Wed Sep 26 16:38:53 2001
    @@ -376,7 +376,7 @@
    if ((reboot_cpu == -1) ||
    (reboot_cpu > (NR_CPUS -1)) ||
    !(phys_cpu_present_map & (1<<cpuid)))
    - reboot_cpu = boot_cpu_id;
    + reboot_cpu = boot_cpu_physical_apicid;

    reboot_smp = 0; /* use this as a flag to only go through this once*/
    /* re-run this function on the other CPUs
    diff -urN virgin-2.4.10/arch/i386/kernel/setup.c numa-2.4.10/arch/i386/kernel/setup.c
    --- virgin-2.4.10/arch/i386/kernel/setup.c Mon Sep 17 23:03:09 2001
    +++ numa-2.4.10/arch/i386/kernel/setup.c Wed Sep 26 16:04:34 2001
    @@ -2416,7 +2416,12 @@
    struct cpuinfo_x86 *c = cpu_data;
    int i, n;

    - for (n = 0; n < NR_CPUS; n++, c++) {
    + /*
    + * WARNING - nasty evil hack ... if we print > 8, it overflows the
    + * page buffer and corrupts memory - this needs fixing properly
    + */
    + for (n = 0; n < 8; n++, c++) {
    + /* for (n = 0; n < NR_CPUS; n++, c++) { */
    int fpu_exception;
    #ifdef CONFIG_SMP
    if (!(cpu_online_map & (1<<n)))
    @@ -2479,7 +2484,7 @@
    return p - buffer;
    }

    -static unsigned long cpu_initialized __initdata = 0;
    +unsigned long cpu_initialized __initdata = 0;

    /*
    * cpu_init() initializes state that is per-CPU. Some data is already
    diff -urN virgin-2.4.10/arch/i386/kernel/smp.c numa-2.4.10/arch/i386/kernel/smp.c
    --- virgin-2.4.10/arch/i386/kernel/smp.c Mon Sep 17 23:03:09 2001
    +++ numa-2.4.10/arch/i386/kernel/smp.c Wed Sep 26 16:04:34 2001
    @@ -20,6 +20,7 @@

    #include <asm/mtrr.h>
    #include <asm/pgalloc.h>
    +#include <asm/smpboot.h>

    /*
    * Some notes on x86 processor bugs affecting SMP operation:
    @@ -148,28 +149,12 @@
    apic_write_around(APIC_ICR, cfg);
    }

    -static inline void send_IPI_allbutself(int vector)
    -{
    - /*
    - * if there are no other CPUs in the system then
    - * we get an APIC send error if we try to broadcast.
    - * thus we have to avoid sending IPIs in this case.
    - */
    - if (smp_num_cpus > 1)
    - __send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
    -}
    -
    -static inline void send_IPI_all(int vector)
    -{
    - __send_IPI_shortcut(APIC_DEST_ALLINC, vector);
    -}
    -
    void send_IPI_self(int vector)
    {
    __send_IPI_shortcut(APIC_DEST_SELF, vector);
    }

    -static inline void send_IPI_mask(int mask, int vector)
    +static inline void send_IPI_mask_bitmask(int mask, int vector)
    {
    unsigned long cfg;
    unsigned long flags;
    @@ -177,27 +162,120 @@
    __save_flags(flags);
    __cli();

    +
    /*
    * Wait for idle.
    */
    apic_wait_icr_idle();
    -
    +
    /*
    * prepare target chip field
    */
    cfg = __prepare_ICR2(mask);
    apic_write_around(APIC_ICR2, cfg);
    -
    +
    /*
    * program the ICR
    */
    cfg = __prepare_ICR(0, vector);
    -
    +
    /*
    * Send the IPI. The write to APIC_ICR fires this off.
    */
    apic_write_around(APIC_ICR, cfg);
    +
    __restore_flags(flags);
    +}
    +
    +static inline void send_IPI_mask_sequence(int mask, int vector)
    +{
    + unsigned long cfg, flags;
    + unsigned int query_cpu, query_mask;
    +
    + /*
    + * Hack. The clustered APIC addressing mode doesn't allow us to send
    + * to an arbitrary mask, so I do a unicasts to each CPU instead. This
    + * should be modified to do 1 message per cluster ID - mbligh
    + */
    +
    + __save_flags(flags);
    + __cli();
    +
    + for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
    + query_mask = 1 << query_cpu;
    + if (query_mask & mask) {
    +
    + /*
    + * Wait for idle.
    + */
    + apic_wait_icr_idle();
    +
    + /*
    + * prepare target chip field
    + */
    + cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
    + apic_write_around(APIC_ICR2, cfg);
    +
    + /*
    + * program the ICR
    + */
    + cfg = __prepare_ICR(0, vector);
    +
    + /*
    + * Send the IPI. The write to APIC_ICR fires this off.
    + */
    + apic_write_around(APIC_ICR, cfg);
    + }
    + }
    + __restore_flags(flags);
    +}
    +
    +static inline void send_IPI_mask(int mask, int vector)
    +{
    + if (clustered_apic_mode)
    + send_IPI_mask_sequence(mask, vector);
    + else
    + send_IPI_mask_bitmask(mask, vector);
    +}
    +
    +static inline void send_IPI_allbutself(int vector)
    +{
    + /*
    + * if there are no other CPUs in the system then
    + * we get an APIC send error if we try to broadcast.
    + * thus we have to avoid sending IPIs in this case.
    + */
    + if (!(smp_num_cpus > 1))
    + return;
    +
    + if (clustered_apic_mode) {
    + // Pointless. Use send_IPI_mask to do this instead
    + int cpu;
    +
    + if (smp_num_cpus > 1) {
    + for (cpu = 0; cpu < smp_num_cpus; ++cpu) {
    + if (cpu != smp_processor_id())
    + send_IPI_mask(1 << cpu, vector);
    + }
    + }
    + } else {
    + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
    + return;
    + }
    +}
    +
    +static inline void send_IPI_all(int vector)
    +{
    + if (clustered_apic_mode) {
    + // Pointless. Use send_IPI_mask to do this instead
    + int cpu;
    +
    + for (cpu = 0; cpu < smp_num_cpus; ++cpu) {
    + send_IPI_mask(1 << cpu, vector);
    + }
    + } else {
    + __send_IPI_shortcut(APIC_DEST_ALLINC, vector);
    + }
    }

    /*
    diff -urN virgin-2.4.10/arch/i386/kernel/smpboot.c numa-2.4.10/arch/i386/kernel/smpboot.c
    --- virgin-2.4.10/arch/i386/kernel/smpboot.c Mon Sep 17 23:03:09 2001
    +++ numa-2.4.10/arch/i386/kernel/smpboot.c Fri Sep 28 15:23:32 2001
    @@ -29,6 +29,7 @@
    * Ingo Molnar : various cleanups and rewrites
    * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
    * Maciej W. Rozycki : Bits for genuine 82489DX APICs
    + * Martin J. Bligh : Added support for multi-quad systems
    */

    #include <linux/config.h>
    @@ -44,6 +45,7 @@
    #include <linux/mc146818rtc.h>
    #include <asm/mtrr.h>
    #include <asm/pgalloc.h>
    +#include <asm/smpboot.h>

    /* Set if we find a B stepping CPU */
    static int smp_b_stepping;
    @@ -57,11 +59,6 @@
    /* Bitmask of currently online CPUs */
    unsigned long cpu_online_map;

    -/* which CPU (physical APIC ID) maps to which logical CPU number */
    -volatile int x86_apicid_to_cpu[NR_CPUS];
    -/* which logical CPU number maps to which CPU (physical APIC ID) */
    -volatile int x86_cpu_to_apicid[NR_CPUS];
    -
    static volatile unsigned long cpu_callin_map;
    static volatile unsigned long cpu_callout_map;

    @@ -357,7 +354,8 @@
    * our local APIC. We have to wait for the IPI or we'll
    * lock up on an APIC access.
    */
    - while (!atomic_read(&init_deasserted));
    + if (!clustered_apic_mode)
    + while (!atomic_read(&init_deasserted));

    /*
    * (This works even if the APIC is not enabled.)
    @@ -406,9 +404,15 @@
    */

    Dprintk("CALLIN, before setup_local_APIC().\n");
    + /*
    + * Because we use NMIs rather than the INIT-STARTUP sequence to
    + * bootstrap the CPUs, the APIC may be in a wierd state. Kick it.
    + */
    + if (clustered_apic_mode)
    + clear_local_APIC();
    setup_local_APIC();

    - sti();
    + __sti();

    #ifdef CONFIG_MTRR
    /*
    @@ -458,11 +462,20 @@
    while (!atomic_read(&smp_commenced))
    rep_nop();
    /*
    + * Removing the next 2 printk's causes an undiagnosable BINT error
    + * in multiquad mode. Seems the console lock serialises the procs?
    + * As of 2.4.10, these printk's panic the kernel if I have serial
    + * console enabled. Aarrrgggh. mbligh
    + */
    + if (clustered_apic_mode)
    + printk("Before tlbflush - processor: %d\n", current->processor);
    + /*
    * low-memory mappings have been cleared, flush them from
    * the local TLBs too.
    */
    local_flush_tlb();
    -
    + if (clustered_apic_mode)
    + printk("After tlbflush - processor: %d\n", current->processor);
    return cpu_idle();
    }

    @@ -501,6 +514,61 @@
    return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
    }

    +/* which physical APIC ID maps to which logical CPU number */
    +volatile int physical_apicid_2_cpu[MAX_APICID];
    +/* which logical CPU number maps to which physical APIC ID */
    +volatile int cpu_2_physical_apicid[NR_CPUS];
    +
    +/* which logical APIC ID maps to which logical CPU number */
    +volatile int logical_apicid_2_cpu[MAX_APICID];
    +/* which logical CPU number maps to which logical APIC ID */
    +volatile int cpu_2_logical_apicid[NR_CPUS];
    +
    +static inline void init_cpu_to_apicid(void)
    +/* Initialize all maps between cpu number and apicids */
    +{
    + int apicid, cpu;
    +
    + for (apicid = 0; apicid < MAX_APICID; apicid++) {
    + physical_apicid_2_cpu[apicid] = -1;
    + logical_apicid_2_cpu[apicid] = -1;
    + }
    + for (cpu = 0; cpu < NR_CPUS; cpu++) {
    + cpu_2_physical_apicid[cpu] = -1;
    + cpu_2_logical_apicid[cpu] = -1;
    + }
    +}
    +
    +static inline void map_cpu_to_boot_apicid(int cpu, int apicid)
    +/*
    + * set up a mapping between cpu and apicid. Uses logical apicids for multiquad,
    + * else physical apic ids
    + */
    +{
    + if (clustered_apic_mode) {
    + logical_apicid_2_cpu[apicid] = cpu;
    + cpu_2_logical_apicid[cpu] = apicid;
    + } else {
    + physical_apicid_2_cpu[apicid] = cpu;
    + cpu_2_physical_apicid[cpu] = apicid;
    + }
    +}
    +
    +static inline void unmap_cpu_to_boot_apicid(int cpu, int apicid)
    +/*
    + * undo a mapping between cpu and apicid. Uses logical apicids for multiquad,
    + * else physical apic ids
    + */
    +{
    + if (clustered_apic_mode) {
    + logical_apicid_2_cpu[apicid] = -1;
    + cpu_2_logical_apicid[cpu] = -1;
    + } else {
    + physical_apicid_2_cpu[apicid] = -1;
    + cpu_2_physical_apicid[cpu] = -1;
    + }
    +}
    +
    #if APIC_DEBUG
    static inline void inquire_remote_apic(int apicid)
    {
    @@ -539,89 +607,65 @@
    }
    #endif

    -static void __init do_boot_cpu (int apicid)
    +static int wakeup_secondary_via_NMI(int logical_apicid)
    +/*
    + * Poke the other CPU in the eye to wake it up. Remember that the normal
    + * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
    + * won't ... remember to clear down the APIC, etc later.
    + */
    {
    - struct task_struct *idle;
    - unsigned long send_status, accept_status, boot_status, maxlvt;
    - int timeout, num_starts, j, cpu;
    - unsigned long start_eip;
    -
    - cpu = ++cpucount;
    - /*
    - * We can't use kernel_thread since we must avoid to
    - * reschedule the child.
    - */
    - if (fork_by_hand() < 0)
    - panic("failed fork for CPU %d", cpu);
    -
    - /*
    - * We remove it from the pidhash and the runqueue
    - * once we got the process:
    - */
    - idle = init_task.prev_task;
    - if (!idle)
    - panic("No idle process for CPU %d", cpu);
    + unsigned long send_status = 0, accept_status = 0;
    + int timeout, maxlvt;

    - idle->processor = cpu;
    - x86_cpu_to_apicid[cpu] = apicid;
    - x86_apicid_to_cpu[apicid] = cpu;
    - idle->has_cpu = 1; /* we schedule the first task manually */
    - idle->thread.eip = (unsigned long) start_secondary;
    -
    - del_from_runqueue(idle);
    - unhash_process(idle);
    - init_tasks[cpu] = idle;
    + /* Target chip */
    + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));

    - /* start_eip had better be page-aligned! */
    - start_eip = setup_trampoline();
    + /* Boot on the stack */
    + /* Kick the second */
    + apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);

    - /* So we see what's up */
    - printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
    - stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
    + Dprintk("Waiting for send to finish...\n");
    + timeout = 0;
    + do {
    + Dprintk("+");
    + udelay(100);
    + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
    + } while (send_status && (timeout++ < 1000));

    /*
    - * This grunge runs the startup process for
    - * the targeted processor.
    + * Give the other CPU some time to accept the IPI.
    */
    -
    - atomic_set(&init_deasserted, 0);
    -
    - Dprintk("Setting warm reset code and vector.\n");
    -
    - CMOS_WRITE(0xa, 0xf);
    - local_flush_tlb();
    - Dprintk("1.\n");
    - *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
    - Dprintk("2.\n");
    - *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
    - Dprintk("3.\n");
    -
    + udelay(200);
    /*
    - * Be paranoid about clearing APIC errors.
    + * Due to the Pentium erratum 3AP.
    */
    - if (APIC_INTEGRATED(apic_version[apicid])) {
    + maxlvt = get_maxlvt();
    + if (maxlvt > 3) {
    apic_read_around(APIC_SPIV);
    apic_write(APIC_ESR, 0);
    - apic_read(APIC_ESR);
    }
    + accept_status = (apic_read(APIC_ESR) & 0xEF);
    + Dprintk("NMI sent.\n");

    - /*
    - * Status is now clean
    - */
    - send_status = 0;
    - accept_status = 0;
    - boot_status = 0;
    + if (send_status)
    + printk("APIC never delivered???\n");
    + if (accept_status)
    + printk("APIC delivery error (%lx).\n", accept_status);

    - /*
    - * Starting actual IPI sequence...
    - */
    + return (send_status | accept_status);
    +}
    +
    +static int wakeup_secondary_via_INIT(int phys_apicid, unsigned long start_eip)
    +{
    + unsigned long send_status = 0, accept_status = 0;
    + int maxlvt, timeout, num_starts, j;

    Dprintk("Asserting INIT.\n");

    /*
    * Turn INIT on target chip
    */
    - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
    + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));

    /*
    * Send IPI
    @@ -642,7 +686,7 @@
    Dprintk("Deasserting INIT.\n");

    /* Target chip */
    - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
    + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));

    /* Send IPI */
    apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
    @@ -661,10 +705,9 @@
    * Should we send STARTUP IPIs ?
    *
    * Determine this based on the APIC version.
    - * If we don't have an integrated APIC, don't
    - * send the STARTUP IPIs.
    + * If we don't have an integrated APIC, don't send the STARTUP IPIs.
    */
    - if (APIC_INTEGRATED(apic_version[apicid]))
    + if (APIC_INTEGRATED(apic_version[phys_apicid]))
    num_starts = 2;
    else
    num_starts = 0;
    @@ -688,7 +731,7 @@
    */

    /* Target chip */
    - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
    + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));

    /* Boot on the stack */
    /* Kick the second */
    @@ -732,7 +775,104 @@
    if (accept_status)
    printk("APIC delivery error (%lx).\n", accept_status);

    - if (!send_status && !accept_status) {
    + return (send_status | accept_status);
    +}
    +
    +extern unsigned long cpu_initialized;
    +
    +static void __init do_boot_cpu (int apicid)
    +/*
    + * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
    + * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
    + */
    +{
    + struct task_struct *idle;
    + unsigned long boot_error = 0;
    + int timeout, cpu;
    + unsigned long start_eip;
    + unsigned short nmi_high, nmi_low;
    +
    + cpu = ++cpucount;
    + /*
    + * We can't use kernel_thread since we must avoid to
    + * reschedule the child.
    + */
    + if (fork_by_hand() < 0)
    + panic("failed fork for CPU %d", cpu);
    +
    + /*
    + * We remove it from the pidhash and the runqueue
    + * once we got the process:
    + */
    + idle = init_task.prev_task;
    + if (!idle)
    + panic("No idle process for CPU %d", cpu);
    +
    + idle->processor = cpu;
    +
    + map_cpu_to_boot_apicid(cpu, apicid);
    +
    + idle->has_cpu = 1; /* we schedule the first task manually */
    + idle->thread.eip = (unsigned long) start_secondary;
    +
    + del_from_runqueue(idle);
    + unhash_process(idle);
    + init_tasks[cpu] = idle;
    +
    + /* start_eip had better be page-aligned! */
    + start_eip = setup_trampoline();
    +
    + /* So we see what's up */
    + printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
    + stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
    +
    + /*
    + * This grunge runs the startup process for
    + * the targeted processor.
    + */
    +
    + atomic_set(&init_deasserted, 0);
    +
    + Dprintk("Setting warm reset code and vector.\n");
    +
    + if (clustered_apic_mode) {
    + /* stash the current NMI vector, so we can put things back */
    + nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
    + nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW);
    + }
    +
    + CMOS_WRITE(0xa, 0xf);
    + local_flush_tlb();
    + Dprintk("1.\n");
    + *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
    + Dprintk("2.\n");
    + *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
    + Dprintk("3.\n");
    +
    + /*
    + * Be paranoid about clearing APIC errors.
    + */
    + if (!clustered_apic_mode && APIC_INTEGRATED(apic_version[apicid])) {
    + apic_read_around(APIC_SPIV);
    + apic_write(APIC_ESR, 0);
    + apic_read(APIC_ESR);
    + }
    +
    + /*
    + * Status is now clean
    + */
    + boot_error = 0;
    +
    + /*
    + * Starting actual IPI sequence...
    + */
    +
    + if (clustered_apic_mode)
    + boot_error = wakeup_secondary_via_NMI(apicid);
    + else
    + boot_error = wakeup_secondary_via_INIT(apicid, start_eip);
    +
    + if (!boot_error) {
    /*
    * allow APs to start initializing.
    */
    @@ -756,7 +896,7 @@
    print_cpu_info(&cpu_data[cpu]);
    Dprintk("CPU has booted.\n");
    } else {
    - boot_status = 1;
    + boot_error= 1;
    if (*((volatile unsigned char *)phys_to_virt(8192))
    == 0xA5)
    /* trampoline started but...? */
    @@ -765,18 +905,28 @@
    /* trampoline code not run */
    printk("Not responding.\n");
    #if APIC_DEBUG
    - inquire_remote_apic(apicid);
    + if (!clustered_apic_mode)
    + inquire_remote_apic(apicid);
    #endif
    }
    }
    - if (send_status || accept_status || boot_status) {
    - x86_cpu_to_apicid[cpu] = -1;
    - x86_apicid_to_cpu[apicid] = -1;
    + if (boot_error) {
    + /* Try to put things back the way they were before ... */
    + unmap_cpu_to_boot_apicid(cpu, apicid);
    + clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */
    + clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */
    + clear_bit(cpu, &cpu_online_map); /* was set in smp_callin() */
    cpucount--;
    }

    /* mark "stuck" area as not stuck */
    *((volatile unsigned long *)phys_to_virt(8192)) = 0;
    +
    + if(clustered_apic_mode) {
    + printk("Restoring NMI vector\n");
    + *((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high;
    + *((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low;
    + }
    }

    cycles_t cacheflush_time;
    @@ -826,9 +976,20 @@
    extern int prof_old_multiplier[NR_CPUS];
    extern int prof_counter[NR_CPUS];

    +static int boot_cpu_logical_apicid;
    +/* Where the IO area was mapped on multiquad, always 0 otherwise */
    +void *xquad_portio = NULL;
    +
    void __init smp_boot_cpus(void)
    {
    - int apicid, cpu;
    + int apicid, cpu, bit;
    +
    + if (clustered_apic_mode) {
    + /* remap the 1st quad's 256k range for cross-quad I/O */
    + xquad_portio = ioremap (XQUAD_PORTIO_BASE, XQUAD_PORTIO_LEN);
    + printk("Cross quad port I/O vaddr 0x%08lx, len %08lx\n",
    + (u_long) xquad_portio, (u_long) XQUAD_PORTIO_LEN);
    + }

    #ifdef CONFIG_MTRR
    /* Must be done before other processors booted */
    @@ -839,13 +1000,14 @@
    * and the per-CPU profiling counter/multiplier
    */

    - for (apicid = 0; apicid < NR_CPUS; apicid++) {
    - x86_apicid_to_cpu[apicid] = -1;
    - prof_counter[apicid] = 1;
    - prof_old_multiplier[apicid] = 1;
    - prof_multiplier[apicid] = 1;
    + for (cpu = 0; cpu < NR_CPUS; cpu++) {
    + prof_counter[cpu] = 1;
    + prof_old_multiplier[cpu] = 1;
    + prof_multiplier[cpu] = 1;
    }

    + init_cpu_to_apicid();
    +
    /*
    * Setup boot CPU information
    */
    @@ -857,8 +1019,9 @@
    * We have the boot CPU online for sure.
    */
    set_bit(0, &cpu_online_map);
    - x86_apicid_to_cpu[boot_cpu_id] = 0;
    - x86_cpu_to_apicid[0] = boot_cpu_id;
    + boot_cpu_logical_apicid = logical_smp_processor_id();
    + map_cpu_to_boot_apicid(0, boot_cpu_apicid);
    +
    global_irq_holder = 0;
    current->processor = 0;
    init_idle();
    @@ -884,20 +1047,22 @@
    /*
    * Should not be necessary because the MP table should list the boot
    * CPU too, but we do it for the sake of robustness anyway.
    + * Makes no sense to do this check in clustered apic mode, so skip it
    */
    - if (!test_bit(boot_cpu_id, &phys_cpu_present_map)) {
    + if (!clustered_apic_mode &&
    + !test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map)) {
    printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
    - boot_cpu_id);
    + boot_cpu_physical_apicid);
    phys_cpu_present_map |= (1 << hard_smp_processor_id());
    }

    /*
    * If we couldn't find a local APIC, then get out of here now!
    */
    - if (APIC_INTEGRATED(apic_version[boot_cpu_id]) &&
    + if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) &&
    !test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) {
    printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
    - boot_cpu_id);
    + boot_cpu_physical_apicid);
    printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
    #ifndef CONFIG_VISWS
    io_apic_irqs = 0;
    @@ -926,22 +1091,27 @@
    connect_bsp_APIC();
    setup_local_APIC();

    - if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id)
    + if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid)
    BUG();

    /*
    - * Now scan the CPU present map and fire up the other CPUs.
    + * Scan the CPU present map and fire up the other CPUs via do_boot_cpu
    + *
    + * In clustered apic mode, phys_cpu_present_map is a constructed thus:
    + * bits 0-3 are quad0, 4-7 are quad1, etc. A perverse twist on the
    + * clustered apic ID.
    */
    Dprintk("CPU present map: %lx\n", phys_cpu_present_map);

    - for (apicid = 0; apicid < NR_CPUS; apicid++) {
    + for (bit = 0; bit < NR_CPUS; bit++) {
    + apicid = cpu_present_to_apicid(bit);
    /*
    * Don't even attempt to start the boot CPU!
    */
    - if (apicid == boot_cpu_id)
    + if (apicid == boot_cpu_apicid)
    continue;

    - if (!(phys_cpu_present_map & (1 << apicid)))
    + if (!(phys_cpu_present_map & (1 << bit)))
    continue;
    if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
    continue;
    @@ -951,9 +1121,10 @@
    /*
    * Make sure we unmap all failed CPUs
    */
    - if ((x86_apicid_to_cpu[apicid] == -1) &&
    - (phys_cpu_present_map & (1 << apicid)))
    - printk("phys CPU #%d not responding - cannot use it.\n",apicid);
    + if ((boot_apicid_to_cpu(apicid) == -1) &&
    + (phys_cpu_present_map & (1 << bit)))
    + printk("CPU #%d not responding - cannot use it.\n",
    + apicid);
    }

    /*
    diff -urN virgin-2.4.10/arch/i386/kernel/trampoline.S numa-2.4.10/arch/i386/kernel/trampoline.S
    --- virgin-2.4.10/arch/i386/kernel/trampoline.S Mon Feb 7 19:59:39 2000
    +++ numa-2.4.10/arch/i386/kernel/trampoline.S Wed Sep 26 16:04:34 2001
    @@ -36,7 +36,9 @@

    ENTRY(trampoline_data)
    r_base = .
    -
    +#ifdef CONFIG_MULTIQUAD
    + wbinvd
    +#endif /* CONFIG_MULTIQUAD */
    mov %cs, %ax # Code and data in the same place
    mov %ax, %ds

    diff -urN virgin-2.4.10/include/asm-i386/apic.h numa-2.4.10/include/asm-i386/apic.h
    --- virgin-2.4.10/include/asm-i386/apic.h Sun Sep 23 10:31:02 2001
    +++ numa-2.4.10/include/asm-i386/apic.h Wed Sep 26 16:04:35 2001
    @@ -64,6 +64,7 @@
    }

    extern int get_maxlvt(void);
    +extern void clear_local_APIC(void);
    extern void connect_bsp_APIC (void);
    extern void disconnect_bsp_APIC (void);
    extern void disable_local_APIC (void);
    diff -urN virgin-2.4.10/include/asm-i386/io.h numa-2.4.10/include/asm-i386/io.h
    --- virgin-2.4.10/include/asm-i386/io.h Sun Sep 23 10:31:22 2001
    +++ numa-2.4.10/include/asm-i386/io.h Wed Sep 26 16:04:35 2001
    @@ -36,75 +36,11 @@
    * - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
    */

    -#ifdef SLOW_IO_BY_JUMPING
    -#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
    -#else
    -#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
    -#endif
    -
    -#ifdef REALLY_SLOW_IO
    -#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
    -#else
    -#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
    -#endif
    -
    -/*
    - * Talk about misusing macros..
    - */
    -#define __OUT1(s,x) \
    -static inline void out##s(unsigned x value, unsigned short port) {
    -
    -#define __OUT2(s,s1,s2) \
    -__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
    -
    -#define __OUT(s,s1,x) \
    -__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
    -__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
    -
    -#define __IN1(s) \
    -static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
    -
    -#define __IN2(s,s1,s2) \
    -__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
    -
    -#define __IN(s,s1,i...) \
    -__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
    -__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
    -
    -#define __INS(s) \
    -static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
    -{ __asm__ __volatile__ ("rep ; ins" #s \
    -: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
    -
    -#define __OUTS(s) \
    -static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
    -{ __asm__ __volatile__ ("rep ; outs" #s \
    -: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
    -
    -#define RETURN_TYPE unsigned char
    -__IN(b,"")
    -#undef RETURN_TYPE
    -#define RETURN_TYPE unsigned short
    -__IN(w,"")
    -#undef RETURN_TYPE
    -#define RETURN_TYPE unsigned int
    -__IN(l,"")
    -#undef RETURN_TYPE
    -
    -__OUT(b,"b",char)
    -__OUT(w,"w",short)
    -__OUT(l,,int)
    -
    -__INS(b)
    -__INS(w)
    -__INS(l)
    -
    -__OUTS(b)
    -__OUTS(w)
    -__OUTS(l)
    -
    #define IO_SPACE_LIMIT 0xffff

    +#define XQUAD_PORTIO_BASE 0xfe400000
    +#define XQUAD_PORTIO_LEN 0x40000 /* 256k per quad. Only remapping 1st */
    +
    #ifdef __KERNEL__

    #include <linux/vmalloc.h>
    @@ -260,5 +196,111 @@
    #define dma_cache_wback_inv(_start,_size) do { } while (0)

    #endif /* __KERNEL__ */
    +
    +#ifdef SLOW_IO_BY_JUMPING
    +#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
    +#else
    +#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
    +#endif
    +
    +#ifdef REALLY_SLOW_IO
    +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
    +#else
    +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
    +#endif
    +
    +#ifdef CONFIG_MULTIQUAD
    +extern void *xquad_portio; /* Where the IO area was mapped */
    +#endif /* CONFIG_MULTIQUAD */
    +
    +/*
    + * Talk about misusing macros..
    + */
    +#define __OUT1(s,x) \
    +static inline void out##s(unsigned x value, unsigned short port) {
    +
    +#define __OUT2(s,s1,s2) \
    +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
    +
    +#ifdef CONFIG_MULTIQUAD
    +/* Make the default portio routines operate on quad 0 for now */
    +#define __OUT(s,s1,x) \
    +__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
    +__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
    +__OUTQ0(s,s,x) \
    +__OUTQ0(s,s##_p,x)
    +#else
    +#define __OUT(s,s1,x) \
    +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
    +__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));}
    +#endif /* CONFIG_MULTIQUAD */
    +
    +#ifdef CONFIG_MULTIQUAD
    +#define __OUTQ0(s,ss,x) /* Do the equivalent of the portio op on quad 0 */ \
    +static inline void out##ss(unsigned x value, unsigned short port) { \
    + if (xquad_portio) \
    + write##s(value, (unsigned long) xquad_portio + port); \
    + else /* We're still in early boot, running on quad 0 */ \
    + out##ss##_local(value, port); \
    +}
    +
    +#define __INQ0(s,ss) /* Do the equivalent of the portio op on quad 0 */ \
    +static inline RETURN_TYPE in##ss(unsigned short port) { \
    + if (xquad_portio) \
    + return read##s((unsigned long) xquad_portio + port); \
    + else /* We're still in early boot, running on quad 0 */ \
    + return in##ss##_local(port); \
    +}
    +#endif /* CONFIG_MULTIQUAD */
    +
    +#define __IN1(s) \
    +static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
    +
    +#define __IN2(s,s1,s2) \
    +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
    +
    +#ifdef CONFIG_MULTIQUAD
    +#define __IN(s,s1,i...) \
    +__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
    +__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
    +__INQ0(s,s) \
    +__INQ0(s,s##_p)
    +#else
    +#define __IN(s,s1,i...) \
    +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
    +__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; }
    +#endif /* CONFIG_MULTIQUAD */
    +
    +#define __INS(s) \
    +static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
    +{ __asm__ __volatile__ ("rep ; ins" #s \
    +: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
    +
    +#define __OUTS(s) \
    +static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
    +{ __asm__ __volatile__ ("rep ; outs" #s \
    +: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
    +
    +#define RETURN_TYPE unsigned char
    +__IN(b,"")
    +#undef RETURN_TYPE
    +#define RETURN_TYPE unsigned short
    +__IN(w,"")
    +#undef RETURN_TYPE
    +#define RETURN_TYPE unsigned int
    +__IN(l,"")
    +#undef RETURN_TYPE
    +
    +__OUT(b,"b",char)
    +__OUT(w,"w",short)
    +__OUT(l,,int)
    +
    +__INS(b)
    +__INS(w)
    +__INS(l)
    +
    +__OUTS(b)
    +__OUTS(w)
    +__OUTS(l)

    #endif
    diff -urN virgin-2.4.10/include/asm-i386/mpspec.h numa-2.4.10/include/asm-i386/mpspec.h
    --- virgin-2.4.10/include/asm-i386/mpspec.h Tue Sep 18 11:21:04 2001
    +++ numa-2.4.10/include/asm-i386/mpspec.h Wed Sep 26 16:04:35 2001
    @@ -156,7 +156,7 @@
    * 7 2 CPU MCA+PCI
    */

    -#define MAX_IRQ_SOURCES 128
    +#define MAX_IRQ_SOURCES 256
    #define MAX_MP_BUSSES 32
    enum mp_bustype {
    MP_BUS_ISA = 1,
    @@ -167,7 +167,7 @@
    extern int mp_bus_id_to_type [MAX_MP_BUSSES];
    extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];

    -extern unsigned int boot_cpu_id;
    +extern unsigned int boot_cpu_physical_apicid;
    extern unsigned long phys_cpu_present_map;
    extern int smp_found_config;
    extern void find_smp_config (void);
    diff -urN virgin-2.4.10/include/asm-i386/smp.h numa-2.4.10/include/asm-i386/smp.h
    --- virgin-2.4.10/include/asm-i386/smp.h Sun Sep 23 10:31:02 2001
    +++ numa-2.4.10/include/asm-i386/smp.h Wed Sep 26 16:04:35 2001
    @@ -22,6 +22,18 @@
    #endif
    #endif

    +#if CONFIG_SMP
    +# ifdef CONFIG_MULTIQUAD
    +# define TARGET_CPUS 0xf /* all CPUs in *THIS* quad */
    +# define INT_DELIVERY_MODE 0 /* physical delivery on LOCAL quad */
    +# else
    +# define TARGET_CPUS cpu_online_map
    +# define INT_DELIVERY_MODE 1 /* logical delivery broadcast to all procs */
    +# endif
    +#else
    +# define TARGET_CPUS 0x01
    +#endif
    +
    #ifdef CONFIG_SMP
    #ifndef ASSEMBLY

    @@ -59,8 +71,21 @@
    * Some lowlevel functions might want to know about
    * the real APIC ID <-> CPU # mapping.
    */
    -extern volatile int x86_apicid_to_cpu[NR_CPUS];
    -extern volatile int x86_cpu_to_apicid[NR_CPUS];
    +#define MAX_APICID 256
    +extern volatile int cpu_to_physical_apicid[NR_CPUS];
    +extern volatile int physical_apicid_to_cpu[MAX_APICID];
    +extern volatile int cpu_to_logical_apicid[NR_CPUS];
    +extern volatile int logical_apicid_to_cpu[MAX_APICID];
    +
    +#ifndef clustered_apic_mode
    + #ifdef CONFIG_MULTIQUAD
    + #define clustered_apic_mode (1)
    + #define esr_disable (1)
    + #else /* !CONFIG_MULTIQUAD */
    + #define clustered_apic_mode (0)
    + #define esr_disable (0)
    + #endif /* CONFIG_MULTIQUAD */
    +#endif

    /*
    * General functions that each host system must provide.
    @@ -81,6 +106,12 @@
    {
    /* we don't want to mark this access volatile - bad code generation */
    return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
    +}
    +
    +extern __inline int logical_smp_processor_id(void)
    +{
    + /* we don't want to mark this access volatile - bad code generation */
    + return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
    }

    #endif /* !ASSEMBLY */
    diff -urN virgin-2.4.10/include/asm-i386/smpboot.h numa-2.4.10/include/asm-i386/smpboot.h
    --- virgin-2.4.10/include/asm-i386/smpboot.h Wed Dec 31 16:00:00 1969
    +++ numa-2.4.10/include/asm-i386/smpboot.h Wed Sep 26 16:04:35 2001
    @@ -0,0 +1,62 @@
    +#ifndef __ASM_SMPBOOT_H
    +#define __ASM_SMPBOOT_H
    +
    +#ifndef clustered_apic_mode
    + #ifdef CONFIG_MULTIQUAD
    + #define clustered_apic_mode (1)
    + #else /* !CONFIG_MULTIQUAD */
    + #define clustered_apic_mode (0)
    + #endif /* CONFIG_MULTIQUAD */
    +#endif
    +
    +#ifdef CONFIG_MULTIQUAD
    + #define TRAMPOLINE_LOW phys_to_virt(0x8)
    + #define TRAMPOLINE_HIGH phys_to_virt(0xa)
    +#else /* !CONFIG_MULTIQUAD */
    + #define TRAMPOLINE_LOW phys_to_virt(0x467)
    + #define TRAMPOLINE_HIGH phys_to_virt(0x469)
    +#endif /* CONFIG_MULTIQUAD */
    +
    +#ifdef CONFIG_MULTIQUAD
    + #define boot_cpu_apicid boot_cpu_logical_apicid
    +#else /* !CONFIG_MULTIQUAD */
    + #define boot_cpu_apicid boot_cpu_physical_apicid
    +#endif /* CONFIG_MULTIQUAD */
    +
    +/*
    + * How to map from the cpu_present_map
    + */
    +#ifdef CONFIG_MULTIQUAD
    + #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) )
    +#else /* !CONFIG_MULTIQUAD */
    + #define cpu_present_to_apicid(apicid) (apicid)
    +#endif /* CONFIG_MULTIQUAD */
    +
    +/*
    + * Mappings between logical cpu number and logical / physical apicid
    + * The first four macros are trivial, but it keeps the abstraction consistent
    + */
    +extern volatile int logical_apicid_2_cpu[];
    +extern volatile int cpu_2_logical_apicid[];
    +extern volatile int physical_apicid_2_cpu[];
    +extern volatile int cpu_2_physical_apicid[];
    +
    +#define logical_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid]
    +#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu]
    +#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
    +#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu]
    +#ifdef CONFIG_MULTIQUAD /* use logical IDs to bootstrap */
    +#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid]
    +#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu]
    +#else /* !CONFIG_MULTIQUAD */ /* use physical IDs to bootstrap */
    +#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
    +#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
    +#endif /* CONFIG_MULTIQUAD */
    +
    +
    +#ifdef CONFIG_MULTIQUAD
    +#else /* !CONFIG_MULTIQUAD */
    +#endif /* CONFIG_MULTIQUAD */
    +
    +
    +#endif
    diff -urN virgin-2.4.10/init/main.c numa-2.4.10/init/main.c
    --- virgin-2.4.10/init/main.c Thu Sep 20 21:02:01 2001
    +++ numa-2.4.10/init/main.c Fri Sep 28 15:23:19 2001
    @@ -519,7 +519,7 @@
    /*
    * Activate the first processor.
    */
    -
    +
    asmlinkage void __init start_kernel(void)
    {
    char * command_line;
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 13:03    [W:0.137 / U:29.400 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site