diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
| -rw-r--r-- | arch/powerpc/sysdev/mpic.c | 59 | 
1 files changed, 55 insertions, 4 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 8e3478c995e..f6299cca781 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -563,6 +563,51 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)  #endif /* CONFIG_MPIC_U3_HT_IRQS */ +#ifdef CONFIG_SMP +static int irq_choose_cpu(unsigned int virt_irq) +{ +	cpumask_t mask = irq_desc[virt_irq].affinity; +	int cpuid; + +	if (cpus_equal(mask, CPU_MASK_ALL)) { +		static int irq_rover; +		static DEFINE_SPINLOCK(irq_rover_lock); +		unsigned long flags; + +		/* Round-robin distribution... */ +	do_round_robin: +		spin_lock_irqsave(&irq_rover_lock, flags); + +		while (!cpu_online(irq_rover)) { +			if (++irq_rover >= NR_CPUS) +				irq_rover = 0; +		} +		cpuid = irq_rover; +		do { +			if (++irq_rover >= NR_CPUS) +				irq_rover = 0; +		} while (!cpu_online(irq_rover)); + +		spin_unlock_irqrestore(&irq_rover_lock, flags); +	} else { +		cpumask_t tmp; + +		cpus_and(tmp, cpu_online_map, mask); + +		if (cpus_empty(tmp)) +			goto do_round_robin; + +		cpuid = first_cpu(tmp); +	} + +	return cpuid; +} +#else +static int irq_choose_cpu(unsigned int virt_irq) +{ +	return hard_smp_processor_id(); +} +#endif  #define mpic_irq_to_hw(virq)	((unsigned int)irq_map[virq].hwirq) @@ -777,12 +822,18 @@ void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)  	struct mpic *mpic = mpic_from_irq(irq);  	unsigned int src = mpic_irq_to_hw(irq); -	cpumask_t tmp; +	if (mpic->flags & MPIC_SINGLE_DEST_CPU) { +		int cpuid = irq_choose_cpu(irq); -	cpus_and(tmp, cpumask, cpu_online_map); +		mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); +	} else { +		cpumask_t tmp; -	mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), -		       mpic_physmask(cpus_addr(tmp)[0]));	 +		cpus_and(tmp, cpumask, cpu_online_map); + +		mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), +			       mpic_physmask(cpus_addr(tmp)[0])); +	}  }  static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)  | 
