[PATCH 2/2] x86_64 irq: make affinity work for genapic_flat mode
From: Yinghai Lu
Date: Mon Mar 05 2007 - 23:18:26 EST
please check the patch
YH
[PATCH 2/2] x86_64 irq: make affinity works for genapic_flat mode
For AMD dual socket system with two IO Hypertransort chain on differenct cpu.
We still can use apic_flat mode instead of apic_physflat mode, and like to
CPUs on second socket to handle irq for device on its chain. When apic_flat
mode is used, the domain will be the same (all CPUS). We need to check the old
affinity in addition to domain, otherwise we can not set affinity from 0x0f to
0x0c, or from 0xff to 0xf0. Also need to make sure vector is changed when we
set affinity from 0x03 to 0x0c or 0x0f to 0xf0.
Signed-off-by: Yinghai Lu <yinghai.lu@xxxxxxx>
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 0a91368..b2ea29a 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -673,8 +673,31 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
if (old_vector) {
cpumask_t tmp;
cpus_and(tmp, cfg->domain, mask);
- if (!cpus_empty(tmp))
- return 0;
+
+ /* only exact same mask can return directly */
+ for_each_cpu_mask(cpu, mask) {
+ cpumask_t domain;
+
+ domain = vector_allocation_domain(cpu);
+ if (cpus_equal(domain, cfg->domain)) {
+#ifdef CONFIG_SMP
+ /* we don't need lock for desc here
+ for apic_flat can not be used with CONFIG_HOTPLUG_CPU
+ others only have one cpu set in domain or affinity
+ */
+ int equal;
+ struct irq_desc *desc;
+ desc = irq_desc + irq;
+ equal = cpus_equal(tmp, desc->affinity);
+ if (equal) {
+ return 0;
+ }
+#else
+ return 0;
+#endif
+ }
+
+ }
}
for_each_cpu_mask(cpu, mask) {
@@ -683,7 +706,6 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
int vector, offset;
domain = vector_allocation_domain(cpu);
- cpus_and(new_mask, domain, cpu_online_map);
vector = current_vector;
offset = current_offset;
@@ -698,9 +720,17 @@ next:
continue;
if (vector == IA32_SYSCALL_VECTOR)
goto next;
+
+ cpus_and(new_mask, domain, cpu_online_map);
for_each_cpu_mask(new_cpu, new_mask)
if (per_cpu(vector_irq, new_cpu)[vector] != -1)
goto next;
+
+ /* Make sure vector is changed when domain is not changed */
+ if (unlikely(vector == old_vector))
+ if (cpus_equal(domain, cfg->domain))
+ goto next;
+
/* Found one! */
current_vector = vector;
current_offset = offset;
@@ -715,6 +745,8 @@ next:
return 0;
}
return -ENOSPC;
+
+
}
static int assign_irq_vector(int irq, cpumask_t mask)