debuggers.hg

changeset 21987:2f4a89ad2528

x86: Reorder CPUs at boot time to reflect system topology.

This is an attempt to impose some sensible coherent ordering on the
cpu namespace, where previously there was none (we were at the mercy
of BIOS ordering, which varies wildly across systems).

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Aug 09 18:28:04 2010 +0100 (2010-08-09)
parents e7afe98afd43
children f45026ec8db5
files xen/arch/x86/setup.c
line diff
     1.1 --- a/xen/arch/x86/setup.c	Mon Aug 09 16:46:42 2010 +0100
     1.2 +++ b/xen/arch/x86/setup.c	Mon Aug 09 18:28:04 2010 +0100
     1.3 @@ -206,6 +206,58 @@ void __devinit srat_detect_node(int cpu)
     1.4  }
     1.5  
     1.6  /*
     1.7 + * Sort CPUs by <node,package,core,thread> tuple. Fortunately this hierarchy is
     1.8 + * reflected in the structure of modern APIC identifiers, so we sort based on
     1.9 + * those. This is slightly complicated by the fact that the BSP must remain
    1.10 + * CPU 0. Hence we do a variation on longest-prefix matching to do the best we
    1.11 + * can while keeping CPU 0 static.
    1.12 + */
    1.13 +static void __init normalise_cpu_order(void)
    1.14 +{
    1.15 +    unsigned int i, j, min_cpu;
    1.16 +    uint32_t apicid, diff, min_diff;
    1.17 +
    1.18 +    for_each_present_cpu ( i )
    1.19 +    {
    1.20 +        apicid = x86_cpu_to_apicid[i];
    1.21 +        min_diff = min_cpu = ~0u;
    1.22 +
    1.23 +        /*
    1.24 +         * Find remaining CPU with longest-prefix match on APIC ID.
    1.25 +         * Among identical longest-prefix matches, pick the smallest APIC ID.
    1.26 +         */
    1.27 +        for ( j = next_cpu(i, cpu_present_map);
    1.28 +              j < NR_CPUS;
    1.29 +              j = next_cpu(j, cpu_present_map) )
    1.30 +        {
    1.31 +            diff = x86_cpu_to_apicid[j] ^ apicid;
    1.32 +            while ( diff & (diff-1) )
    1.33 +                diff &= diff-1;
    1.34 +            if ( (diff < min_diff) ||
    1.35 +                 ((diff == min_diff) &&
    1.36 +                  (x86_cpu_to_apicid[j] < x86_cpu_to_apicid[min_cpu])) )
    1.37 +            {
    1.38 +                min_diff = diff;
    1.39 +                min_cpu = j;
    1.40 +            }
    1.41 +        }
    1.42 +
    1.43 +        /* If no match then there must be no CPUs remaining to consider. */
    1.44 +        if ( min_cpu >= NR_CPUS )
    1.45 +        {
    1.46 +            BUG_ON(next_cpu(i, cpu_present_map) < NR_CPUS);
    1.47 +            break;
    1.48 +        }
    1.49 +
    1.50 +        /* Switch the best-matching CPU with the next CPU in logical order. */
    1.51 +        j = next_cpu(i, cpu_present_map);
    1.52 +        apicid = x86_cpu_to_apicid[min_cpu];
    1.53 +        x86_cpu_to_apicid[min_cpu] = x86_cpu_to_apicid[j];
    1.54 +        x86_cpu_to_apicid[j] = apicid;
    1.55 +    }
    1.56 +}
    1.57 +
    1.58 +/*
    1.59   * Ensure a given physical memory range is present in the bootstrap mappings.
    1.60   * Use superpage mappings to ensure that pagetable memory needn't be allocated.
    1.61   */
    1.62 @@ -952,8 +1004,6 @@ void __init __start_xen(unsigned long mb
    1.63  
    1.64      acpi_boot_init();
    1.65  
    1.66 -    init_cpu_to_node();
    1.67 -
    1.68      if ( smp_found_config )
    1.69          get_smp_config();
    1.70  
    1.71 @@ -964,6 +1014,10 @@ void __init __start_xen(unsigned long mb
    1.72  
    1.73      init_apic_mappings();
    1.74  
    1.75 +    normalise_cpu_order();
    1.76 +
    1.77 +    init_cpu_to_node();
    1.78 +
    1.79      if ( x2apic_is_available() )
    1.80          enable_x2apic();
    1.81