diff options
Diffstat (limited to 'arch/x86/kernel/apic/x2apic_cluster.c')
| -rw-r--r-- | arch/x86/kernel/apic/x2apic_cluster.c | 82 | 
1 files changed, 54 insertions, 28 deletions
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index ff35cff0e1a..c88baa4ff0e 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -81,7 +81,7 @@ static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)  }  static void - x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector) +x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)  {  	__x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);  } @@ -96,36 +96,37 @@ static void x2apic_send_IPI_all(int vector)  	__x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);  } -static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask) +static int +x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask, +			      const struct cpumask *andmask, +			      unsigned int *apicid)  { -	/* -	 * We're using fixed IRQ delivery, can only return one logical APIC ID. -	 * May as well be the first. -	 */ -	int cpu = cpumask_first(cpumask); +	u32 dest = 0; +	u16 cluster; +	int i; -	if ((unsigned)cpu < nr_cpu_ids) -		return per_cpu(x86_cpu_to_logical_apicid, cpu); -	else -		return BAD_APICID; -} +	for_each_cpu_and(i, cpumask, andmask) { +		if (!cpumask_test_cpu(i, cpu_online_mask)) +			continue; +		dest = per_cpu(x86_cpu_to_logical_apicid, i); +		cluster = x2apic_cluster(i); +		break; +	} -static unsigned int -x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask, -			      const struct cpumask *andmask) -{ -	int cpu; +	if (!dest) +		return -EINVAL; -	/* -	 * We're using fixed IRQ delivery, can only return one logical APIC ID. -	 * May as well be the first. -	 */ -	for_each_cpu_and(cpu, cpumask, andmask) { -		if (cpumask_test_cpu(cpu, cpu_online_mask)) -			break; +	for_each_cpu_and(i, cpumask, andmask) { +		if (!cpumask_test_cpu(i, cpu_online_mask)) +			continue; +		if (cluster != x2apic_cluster(i)) +			continue; +		dest |= per_cpu(x86_cpu_to_logical_apicid, i);  	} -	return per_cpu(x86_cpu_to_logical_apicid, cpu); +	*apicid = dest; + +	return 0;  }  static void init_x2apic_ldr(void) @@ -208,6 +209,32 @@ static int x2apic_cluster_probe(void)  		return 0;  } +static const struct cpumask *x2apic_cluster_target_cpus(void) +{ +	return cpu_all_mask; +} + +/* + * Each x2apic cluster is an allocation domain. + */ +static void cluster_vector_allocation_domain(int cpu, struct cpumask *retmask, +					     const struct cpumask *mask) +{ +	/* +	 * To minimize vector pressure, default case of boot, device bringup +	 * etc will use a single cpu for the interrupt destination. +	 * +	 * On explicit migration requests coming from irqbalance etc, +	 * interrupts will be routed to the x2apic cluster (cluster-id +	 * derived from the first cpu in the mask) members specified +	 * in the mask. +	 */ +	if (mask == x2apic_cluster_target_cpus()) +		cpumask_copy(retmask, cpumask_of(cpu)); +	else +		cpumask_and(retmask, mask, per_cpu(cpus_in_cluster, cpu)); +} +  static struct apic apic_x2apic_cluster = {  	.name				= "cluster x2apic", @@ -219,13 +246,13 @@ static struct apic apic_x2apic_cluster = {  	.irq_delivery_mode		= dest_LowestPrio,  	.irq_dest_mode			= 1, /* logical */ -	.target_cpus			= x2apic_target_cpus, +	.target_cpus			= x2apic_cluster_target_cpus,  	.disable_esr			= 0,  	.dest_logical			= APIC_DEST_LOGICAL,  	.check_apicid_used		= NULL,  	.check_apicid_present		= NULL, -	.vector_allocation_domain	= x2apic_vector_allocation_domain, +	.vector_allocation_domain	= cluster_vector_allocation_domain,  	.init_apic_ldr			= init_x2apic_ldr,  	.ioapic_phys_id_map		= NULL, @@ -243,7 +270,6 @@ static struct apic apic_x2apic_cluster = {  	.set_apic_id			= x2apic_set_apic_id,  	.apic_id_mask			= 0xFFFFFFFFu, -	.cpu_mask_to_apicid		= x2apic_cpu_mask_to_apicid,  	.cpu_mask_to_apicid_and		= x2apic_cpu_mask_to_apicid_and,  	.send_IPI_mask			= x2apic_send_IPI_mask,  |