Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca9fc75a authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky
Browse files

[S390] convert s390 to generic IPI infrastructure



Since etr/stp don't need the old smp_call_function semantics anymore
we can convert s390 to the generic IPI infrastructure.

Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 0b3016b7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ mainmenu "Linux Kernel Configuration"

config S390
	def_bool y
	select USE_GENERIC_SMP_HELPERS if SMP
	select HAVE_OPROFILE
	select HAVE_KPROBES
	select HAVE_KRETPROBES
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ typedef enum
{
	ec_schedule=0,
	ec_call_function,
	ec_call_function_single,
	ec_bit_last
} ec_bit_sig;

+3 −2
Original line number Diff line number Diff line
@@ -91,8 +91,9 @@ extern int __cpu_up (unsigned int cpu);
extern struct mutex smp_cpu_state_mutex;
extern int smp_cpu_polarization[];

extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
	void *info, int wait);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi(cpumask_t mask);

#endif

#ifndef CONFIG_SMP
+19 −156
Original line number Diff line number Diff line
@@ -77,159 +77,6 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices);

static void smp_ext_bitcall(int, ec_bit_sig);

/*
 * Structure and data for __smp_call_function_map(). This is designed to
 * minimise static memory requirements. It also looks cleaner.
 */
static DEFINE_SPINLOCK(call_lock);

struct call_data_struct {
	void (*func) (void *info);
	void *info;
	cpumask_t started;
	cpumask_t finished;
	int wait;
};

static struct call_data_struct *call_data;

/*
 * 'Call function' interrupt callback
 */
static void do_call_function(void)
{
	void (*func) (void *info) = call_data->func;
	void *info = call_data->info;
	int wait = call_data->wait;

	cpu_set(smp_processor_id(), call_data->started);
	(*func)(info);
	if (wait)
		cpu_set(smp_processor_id(), call_data->finished);;
}

static void __smp_call_function_map(void (*func) (void *info), void *info,
				    int wait, cpumask_t map)
{
	struct call_data_struct data;
	int cpu, local = 0;

	/*
	 * Can deadlock when interrupts are disabled or if in wrong context.
	 */
	WARN_ON(irqs_disabled() || in_irq());

	/*
	 * Check for local function call. We have to have the same call order
	 * as in on_each_cpu() because of machine_restart_smp().
	 */
	if (cpu_isset(smp_processor_id(), map)) {
		local = 1;
		cpu_clear(smp_processor_id(), map);
	}

	cpus_and(map, map, cpu_online_map);
	if (cpus_empty(map))
		goto out;

	data.func = func;
	data.info = info;
	data.started = CPU_MASK_NONE;
	data.wait = wait;
	if (wait)
		data.finished = CPU_MASK_NONE;

	call_data = &data;

	for_each_cpu_mask(cpu, map)
		smp_ext_bitcall(cpu, ec_call_function);

	/* Wait for response */
	while (!cpus_equal(map, data.started))
		cpu_relax();
	if (wait)
		while (!cpus_equal(map, data.finished))
			cpu_relax();
out:
	if (local) {
		local_irq_disable();
		func(info);
		local_irq_enable();
	}
}

/*
 * smp_call_function:
 * @func: the function to run; this must be fast and non-blocking
 * @info: an arbitrary pointer to pass to the function
 * @wait: if true, wait (atomically) until function has completed on other CPUs
 *
 * Run a function on all other CPUs.
 *
 * You must not call this function with disabled interrupts, from a
 * hardware interrupt handler or from a bottom half.
 */
int smp_call_function(void (*func) (void *info), void *info, int wait)
{
	cpumask_t map;

	spin_lock(&call_lock);
	map = cpu_online_map;
	cpu_clear(smp_processor_id(), map);
	__smp_call_function_map(func, info, wait, map);
	spin_unlock(&call_lock);
	return 0;
}
EXPORT_SYMBOL(smp_call_function);

/*
 * smp_call_function_single:
 * @cpu: the CPU where func should run
 * @func: the function to run; this must be fast and non-blocking
 * @info: an arbitrary pointer to pass to the function
 * @wait: if true, wait (atomically) until function has completed on other CPUs
 *
 * Run a function on one processor.
 *
 * You must not call this function with disabled interrupts, from a
 * hardware interrupt handler or from a bottom half.
 */
int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
			     int wait)
{
	spin_lock(&call_lock);
	__smp_call_function_map(func, info, wait, cpumask_of_cpu(cpu));
	spin_unlock(&call_lock);
	return 0;
}
EXPORT_SYMBOL(smp_call_function_single);

/**
 * smp_call_function_mask(): Run a function on a set of other CPUs.
 * @mask: The set of cpus to run on.  Must not include the current cpu.
 * @func: The function to run. This must be fast and non-blocking.
 * @info: An arbitrary pointer to pass to the function.
 * @wait: If true, wait (atomically) until function has completed on other CPUs.
 *
 * Returns 0 on success, else a negative status code.
 *
 * If @wait is true, then returns once @func has returned; otherwise
 * it returns just before the target cpu calls @func.
 *
 * You must not call this function with disabled interrupts or from a
 * hardware interrupt handler or from a bottom half handler.
 */
int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
			   int wait)
{
	spin_lock(&call_lock);
	cpu_clear(smp_processor_id(), mask);
	__smp_call_function_map(func, info, wait, mask);
	spin_unlock(&call_lock);
	return 0;
}
EXPORT_SYMBOL(smp_call_function_mask);

void smp_send_stop(void)
{
	int cpu, rc;
@@ -271,7 +118,10 @@ static void do_ext_call_interrupt(__u16 code)
	bits = xchg(&S390_lowcore.ext_call_fast, 0);

	if (test_bit(ec_call_function, &bits))
		do_call_function();
		generic_smp_call_function_interrupt();

	if (test_bit(ec_call_function_single, &bits))
		generic_smp_call_function_single_interrupt();
}

/*
@@ -288,6 +138,19 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig)
		udelay(10);
}

void arch_send_call_function_ipi(cpumask_t mask)
{
	int cpu;

	for_each_cpu_mask(cpu, mask)
		smp_ext_bitcall(cpu, ec_call_function);
}

void arch_send_call_function_single_ipi(int cpu)
{
	smp_ext_bitcall(cpu, ec_call_function_single);
}

#ifndef CONFIG_64BIT
/*
 * this function sends a 'purge tlb' signal to another CPU.
@@ -588,9 +451,9 @@ int __cpuinit start_secondary(void *cpuvoid)
	/* call cpu notifiers */
	notify_cpu_starting(smp_processor_id());
	/* Mark this cpu as online */
	spin_lock(&call_lock);
	ipi_call_lock();
	cpu_set(smp_processor_id(), cpu_online_map);
	spin_unlock(&call_lock);
	ipi_call_unlock();
	/* Switch on interrupts */
	local_irq_enable();
	/* Print info about this processor */