|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 2/2] x86/x2apic: properly implement cluster mode
On 08/11/2012 15:03, "Jan Beulich" <JBeulich@xxxxxxxx> wrote:
> So far, cluster mode was just an alternative implementation of
> physical mode: Allowing only single CPU interrupt targets, and sending
> IPIs to each target CPU separately. Take advantage of what cluster
> mode really can do in that regard.
What does it allow? Multicast within certain constraints? I know it's not
part of our coding style, but some comments would be nice. ;)
-- Keir
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
>
> --- a/xen/arch/x86/genapic/x2apic.c
> +++ b/xen/arch/x86/genapic/x2apic.c
> @@ -19,6 +19,7 @@
>
> #include <xen/config.h>
> #include <xen/init.h>
> +#include <xen/cpu.h>
> #include <xen/cpumask.h>
> #include <asm/apicdef.h>
> #include <asm/genapic.h>
> @@ -33,6 +34,14 @@ static bool_t __initdata x2apic_phys; /*
> boolean_param("x2apic_phys", x2apic_phys);
>
> static DEFINE_PER_CPU_READ_MOSTLY(u32, cpu_2_logical_apicid);
> +static DEFINE_PER_CPU_READ_MOSTLY(cpumask_t *, cluster_cpus);
> +static cpumask_t *cluster_cpus_spare;
> +static DEFINE_PER_CPU(cpumask_var_t, scratch_mask);
> +
> +static inline u32 x2apic_cluster(unsigned int cpu)
> +{
> + return per_cpu(cpu_2_logical_apicid, cpu) >> 16;
> +}
>
> static void init_apic_ldr_x2apic_phys(void)
> {
> @@ -40,20 +49,53 @@ static void init_apic_ldr_x2apic_phys(vo
>
> static void init_apic_ldr_x2apic_cluster(void)
> {
> - this_cpu(cpu_2_logical_apicid) = apic_read(APIC_LDR);
> + unsigned int cpu, this_cpu = smp_processor_id();
> +
> + per_cpu(cpu_2_logical_apicid, this_cpu) = apic_read(APIC_LDR);
> +
> + if ( per_cpu(cluster_cpus, this_cpu) )
> + {
> + ASSERT(cpumask_test_cpu(this_cpu, per_cpu(cluster_cpus, this_cpu)));
> + return;
> + }
> +
> + per_cpu(cluster_cpus, this_cpu) = cluster_cpus_spare;
> + for_each_online_cpu ( cpu )
> + {
> + if (this_cpu == cpu || x2apic_cluster(this_cpu) !=
> x2apic_cluster(cpu))
> + continue;
> + per_cpu(cluster_cpus, this_cpu) = per_cpu(cluster_cpus, cpu);
> + break;
> + }
> + if ( per_cpu(cluster_cpus, this_cpu) == cluster_cpus_spare )
> + cluster_cpus_spare = NULL;
> +
> + cpumask_set_cpu(this_cpu, per_cpu(cluster_cpus, this_cpu));
> }
>
> static void __init clustered_apic_check_x2apic(void)
> {
> }
>
> +static const cpumask_t *vector_allocation_cpumask_x2apic_cluster(int cpu)
> +{
> + return per_cpu(cluster_cpus, cpu);
> +}
> +
> static unsigned int cpu_mask_to_apicid_x2apic_cluster(const cpumask_t
> *cpumask)
> {
> - return per_cpu(cpu_2_logical_apicid, cpumask_first(cpumask));
> + unsigned int cpu = cpumask_first(cpumask);
> + unsigned int dest = per_cpu(cpu_2_logical_apicid, cpu);
> + const cpumask_t *cluster_cpus = per_cpu(cluster_cpus, cpu);
> +
> + for_each_cpu ( cpu, cluster_cpus )
> + if ( cpumask_test_cpu(cpu, cpumask) )
> + dest |= per_cpu(cpu_2_logical_apicid, cpu);
> +
> + return dest;
> }
>
> -static void __send_IPI_mask_x2apic(
> - const cpumask_t *cpumask, int vector, unsigned int dest_mode)
> +static void send_IPI_mask_x2apic_phys(const cpumask_t *cpumask, int vector)
> {
> unsigned int cpu;
> unsigned long flags;
> @@ -77,23 +119,48 @@ static void __send_IPI_mask_x2apic(
> {
> if ( !cpu_online(cpu) || (cpu == smp_processor_id()) )
> continue;
> - msr_content = (dest_mode == APIC_DEST_PHYSICAL)
> - ? cpu_physical_id(cpu) : per_cpu(cpu_2_logical_apicid, cpu);
> - msr_content = (msr_content << 32) | APIC_DM_FIXED | dest_mode |
> vector;
> + msr_content = cpu_physical_id(cpu);
> + msr_content = (msr_content << 32) | APIC_DM_FIXED |
> + APIC_DEST_PHYSICAL | vector;
> apic_wrmsr(APIC_ICR, msr_content);
> }
>
> local_irq_restore(flags);
> }
>
> -static void send_IPI_mask_x2apic_phys(const cpumask_t *cpumask, int vector)
> -{
> - __send_IPI_mask_x2apic(cpumask, vector, APIC_DEST_PHYSICAL);
> -}
> -
> static void send_IPI_mask_x2apic_cluster(const cpumask_t *cpumask, int
> vector)
> {
> - __send_IPI_mask_x2apic(cpumask, vector, APIC_DEST_LOGICAL);
> + unsigned int cpu = smp_processor_id();
> + cpumask_t *ipimask = per_cpu(scratch_mask, cpu);
> + const cpumask_t *cluster_cpus;
> + unsigned long flags;
> +
> + mb(); /* See above for an explanation. */
> +
> + local_irq_save(flags);
> +
> + cpumask_andnot(ipimask, &cpu_online_map, cpumask_of(cpu));
> +
> + for ( cpumask_and(ipimask, cpumask, ipimask); !cpumask_empty(ipimask);
> + cpumask_andnot(ipimask, ipimask, cluster_cpus) )
> + {
> + uint64_t msr_content = 0;
> +
> + cluster_cpus = per_cpu(cluster_cpus, cpumask_first(ipimask));
> + for_each_cpu ( cpu, cluster_cpus )
> + {
> + if ( !cpumask_test_cpu(cpu, ipimask) )
> + continue;
> + msr_content |= per_cpu(cpu_2_logical_apicid, cpu);
> + }
> +
> + BUG_ON(!msr_content);
> + msr_content = (msr_content << 32) | APIC_DM_FIXED |
> + APIC_DEST_LOGICAL | vector;
> + apic_wrmsr(APIC_ICR, msr_content);
> + }
> +
> + local_irq_restore(flags);
> }
>
> static const struct genapic apic_x2apic_phys = {
> @@ -116,15 +183,60 @@ static const struct genapic apic_x2apic_
> .init_apic_ldr = init_apic_ldr_x2apic_cluster,
> .clustered_apic_check = clustered_apic_check_x2apic,
> .target_cpus = target_cpus_all,
> - .vector_allocation_cpumask = vector_allocation_cpumask_phys,
> + .vector_allocation_cpumask = vector_allocation_cpumask_x2apic_cluster,
> .cpu_mask_to_apicid = cpu_mask_to_apicid_x2apic_cluster,
> .send_IPI_mask = send_IPI_mask_x2apic_cluster,
> .send_IPI_self = send_IPI_self_x2apic
> };
>
> +static int update_clusterinfo(
> + struct notifier_block *nfb, unsigned long action, void *hcpu)
> +{
> + unsigned int cpu = (unsigned long)hcpu;
> + int err = 0;
> +
> + switch (action) {
> + case CPU_UP_PREPARE:
> + per_cpu(cpu_2_logical_apicid, cpu) = BAD_APICID;
> + if ( !cluster_cpus_spare )
> + cluster_cpus_spare = xzalloc(cpumask_t);
> + if ( !cluster_cpus_spare ||
> + !alloc_cpumask_var(&per_cpu(scratch_mask, cpu)) )
> + err = -ENOMEM;
> + break;
> + case CPU_UP_CANCELED:
> + case CPU_DEAD:
> + if ( per_cpu(cluster_cpus, cpu) )
> + {
> + cpumask_clear_cpu(cpu, per_cpu(cluster_cpus, cpu));
> + if ( cpumask_empty(per_cpu(cluster_cpus, cpu)) )
> + xfree(per_cpu(cluster_cpus, cpu));
> + }
> + free_cpumask_var(per_cpu(scratch_mask, cpu));
> + break;
> + }
> +
> + return !err ? NOTIFY_DONE : notifier_from_errno(err);
> +}
> +
> +static struct notifier_block x2apic_cpu_nfb = {
> + .notifier_call = update_clusterinfo
> +};
> +
> const struct genapic *__init apic_x2apic_probe(void)
> {
> - return x2apic_phys ? &apic_x2apic_phys : &apic_x2apic_cluster;
> + if ( x2apic_phys )
> + return &apic_x2apic_phys;
> +
> + if ( !this_cpu(cluster_cpus) )
> + {
> + update_clusterinfo(NULL, CPU_UP_PREPARE,
> + (void *)(long)smp_processor_id());
> + init_apic_ldr_x2apic_cluster();
> + register_cpu_notifier(&x2apic_cpu_nfb);
> + }
> +
> + return &apic_x2apic_cluster;
> }
>
> void __init check_x2apic_preenabled(void)
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxx
> http://lists.xen.org/xen-devel
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |