diff options
Diffstat (limited to 'arch/arm/kernel/smp.c')
| -rw-r--r-- | arch/arm/kernel/smp.c | 51 | 
1 files changed, 46 insertions, 5 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 72024ea8a3a..7c4fada440f 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -25,6 +25,7 @@  #include <linux/clockchips.h>  #include <linux/completion.h>  #include <linux/cpufreq.h> +#include <linux/irq_work.h>  #include <linux/atomic.h>  #include <asm/smp.h> @@ -66,6 +67,8 @@ enum ipi_msg_type {  	IPI_CALL_FUNC,  	IPI_CALL_FUNC_SINGLE,  	IPI_CPU_STOP, +	IPI_IRQ_WORK, +	IPI_COMPLETION,  };  static DECLARE_COMPLETION(cpu_running); @@ -80,7 +83,7 @@ void __init smp_set_ops(struct smp_operations *ops)  static unsigned long get_arch_pgd(pgd_t *pgd)  { -	phys_addr_t pgdir = virt_to_phys(pgd); +	phys_addr_t pgdir = virt_to_idmap(pgd);  	BUG_ON(pgdir & ARCH_PGD_MASK);  	return pgdir >> ARCH_PGD_SHIFT;  } @@ -102,8 +105,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)  	secondary_data.pgdir = get_arch_pgd(idmap_pgd);  	secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);  #endif -	__cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data)); -	outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1)); +	sync_cache_w(&secondary_data);  	/*  	 * Now bring the CPU into our world. @@ -291,6 +293,9 @@ void __ref cpu_die(void)  	if (smp_ops.cpu_die)  		smp_ops.cpu_die(cpu); +	pr_warn("CPU%u: smp_ops.cpu_die() returned, trying to resuscitate\n", +		cpu); +  	/*  	 * Do not return to the idle loop - jump back to the secondary  	 * cpu initialisation.  There's some initialisation which needs @@ -448,6 +453,14 @@ void arch_send_call_function_single_ipi(int cpu)  	smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);  } +#ifdef CONFIG_IRQ_WORK +void arch_irq_work_raise(void) +{ +	if (is_smp()) +		smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); +} +#endif +  static const char *ipi_types[NR_IPI] = {  #define S(x,s)	[x] = s  	S(IPI_WAKEUP, "CPU wakeup interrupts"), @@ -456,6 +469,8 @@ static const char *ipi_types[NR_IPI] = {  	S(IPI_CALL_FUNC, "Function call interrupts"),  	S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),  	S(IPI_CPU_STOP, "CPU stop interrupts"), +	S(IPI_IRQ_WORK, "IRQ work interrupts"), +	S(IPI_COMPLETION, "completion interrupts"),  };  void show_ipi_list(struct seq_file *p, int prec) @@ -515,6 +530,19 @@ static void ipi_cpu_stop(unsigned int cpu)  		cpu_relax();  } +static DEFINE_PER_CPU(struct completion *, cpu_completion); + +int register_ipi_completion(struct completion *completion, int cpu) +{ +	per_cpu(cpu_completion, cpu) = completion; +	return IPI_COMPLETION; +} + +static void ipi_complete(unsigned int cpu) +{ +	complete(per_cpu(cpu_completion, cpu)); +} +  /*   * Main handler for inter-processor interrupts   */ @@ -565,6 +593,20 @@ void handle_IPI(int ipinr, struct pt_regs *regs)  		irq_exit();  		break; +#ifdef CONFIG_IRQ_WORK +	case IPI_IRQ_WORK: +		irq_enter(); +		irq_work_run(); +		irq_exit(); +		break; +#endif + +	case IPI_COMPLETION: +		irq_enter(); +		ipi_complete(cpu); +		irq_exit(); +		break; +  	default:  		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",  		       cpu, ipinr); @@ -632,8 +674,7 @@ static int cpufreq_callback(struct notifier_block *nb,  	}  	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) || -	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || -	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { +	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {  		loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,  						global_l_p_j_ref_freq,  						freq->new);  | 
