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

Commit 5217192b authored by Paul E. McKenney's avatar Paul E. McKenney
Browse files

Merge remote-tracking branch 'tip/smp/hotplug' into next.2012.09.25b

The conflicts between kernel/rcutree.h and kernel/rcutree_plugin.h
were due to adjacent insertions and deletions, which were resolved
by simply accepting the changes on both branches.
parents bda4ec9f bff4a394
Loading
Loading
Loading
Loading
+89 −161
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
 */

#include <linux/slab.h>
#include <linux/smpboot.h>

#include "ehca_classes.h"
#include "ehca_irq.h"
@@ -652,7 +653,7 @@ void ehca_tasklet_eq(unsigned long data)
	ehca_process_eq((struct ehca_shca*)data, 1);
}

static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
static int find_next_online_cpu(struct ehca_comp_pool *pool)
{
	int cpu;
	unsigned long flags;
@@ -662,17 +663,20 @@ static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
		ehca_dmp(cpu_online_mask, cpumask_size(), "");

	spin_lock_irqsave(&pool->last_cpu_lock, flags);
	do {
		cpu = cpumask_next(pool->last_cpu, cpu_online_mask);
		if (cpu >= nr_cpu_ids)
			cpu = cpumask_first(cpu_online_mask);
		pool->last_cpu = cpu;
	} while (!per_cpu_ptr(pool->cpu_comp_tasks, cpu)->active);
	spin_unlock_irqrestore(&pool->last_cpu_lock, flags);

	return cpu;
}

static void __queue_comp_task(struct ehca_cq *__cq,
			      struct ehca_cpu_comp_task *cct)
			      struct ehca_cpu_comp_task *cct,
			      struct task_struct *thread)
{
	unsigned long flags;

@@ -683,7 +687,7 @@ static void __queue_comp_task(struct ehca_cq *__cq,
		__cq->nr_callbacks++;
		list_add_tail(&__cq->entry, &cct->cq_list);
		cct->cq_jobs++;
		wake_up(&cct->wait_queue);
		wake_up_process(thread);
	} else
		__cq->nr_callbacks++;

@@ -695,6 +699,7 @@ static void queue_comp_task(struct ehca_cq *__cq)
{
	int cpu_id;
	struct ehca_cpu_comp_task *cct;
	struct task_struct *thread;
	int cq_jobs;
	unsigned long flags;

@@ -702,7 +707,8 @@ static void queue_comp_task(struct ehca_cq *__cq)
	BUG_ON(!cpu_online(cpu_id));

	cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
	BUG_ON(!cct);
	thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id);
	BUG_ON(!cct || !thread);

	spin_lock_irqsave(&cct->task_lock, flags);
	cq_jobs = cct->cq_jobs;
@@ -710,28 +716,25 @@ static void queue_comp_task(struct ehca_cq *__cq)
	if (cq_jobs > 0) {
		cpu_id = find_next_online_cpu(pool);
		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
		BUG_ON(!cct);
		thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id);
		BUG_ON(!cct || !thread);
	}

	__queue_comp_task(__cq, cct);
	__queue_comp_task(__cq, cct, thread);
}

static void run_comp_task(struct ehca_cpu_comp_task *cct)
{
	struct ehca_cq *cq;
	unsigned long flags;

	spin_lock_irqsave(&cct->task_lock, flags);

	while (!list_empty(&cct->cq_list)) {
		cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
		spin_unlock_irqrestore(&cct->task_lock, flags);
		spin_unlock_irq(&cct->task_lock);

		comp_event_callback(cq);
		if (atomic_dec_and_test(&cq->nr_events))
			wake_up(&cq->wait_completion);

		spin_lock_irqsave(&cct->task_lock, flags);
		spin_lock_irq(&cct->task_lock);
		spin_lock(&cq->task_lock);
		cq->nr_callbacks--;
		if (!cq->nr_callbacks) {
@@ -740,159 +743,76 @@ static void run_comp_task(struct ehca_cpu_comp_task *cct)
		}
		spin_unlock(&cq->task_lock);
	}

	spin_unlock_irqrestore(&cct->task_lock, flags);
}

static int comp_task(void *__cct)
static void comp_task_park(unsigned int cpu)
{
	struct ehca_cpu_comp_task *cct = __cct;
	int cql_empty;
	DECLARE_WAITQUEUE(wait, current);

	set_current_state(TASK_INTERRUPTIBLE);
	while (!kthread_should_stop()) {
		add_wait_queue(&cct->wait_queue, &wait);

		spin_lock_irq(&cct->task_lock);
		cql_empty = list_empty(&cct->cq_list);
		spin_unlock_irq(&cct->task_lock);
		if (cql_empty)
			schedule();
		else
			__set_current_state(TASK_RUNNING);

		remove_wait_queue(&cct->wait_queue, &wait);
	struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
	struct ehca_cpu_comp_task *target;
	struct task_struct *thread;
	struct ehca_cq *cq, *tmp;
	LIST_HEAD(list);

	spin_lock_irq(&cct->task_lock);
		cql_empty = list_empty(&cct->cq_list);
	cct->cq_jobs = 0;
	cct->active = 0;
	list_splice_init(&cct->cq_list, &list);
	spin_unlock_irq(&cct->task_lock);
		if (!cql_empty)
			run_comp_task(__cct);

		set_current_state(TASK_INTERRUPTIBLE);
	cpu = find_next_online_cpu(pool);
	target = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
	thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu);
	spin_lock_irq(&target->task_lock);
	list_for_each_entry_safe(cq, tmp, &list, entry) {
		list_del(&cq->entry);
		__queue_comp_task(cq, target, thread);
	}
	__set_current_state(TASK_RUNNING);

	return 0;
	spin_unlock_irq(&target->task_lock);
}

static struct task_struct *create_comp_task(struct ehca_comp_pool *pool,
					    int cpu)
static void comp_task_stop(unsigned int cpu, bool online)
{
	struct ehca_cpu_comp_task *cct;

	cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
	spin_lock_init(&cct->task_lock);
	INIT_LIST_HEAD(&cct->cq_list);
	init_waitqueue_head(&cct->wait_queue);
	cct->task = kthread_create_on_node(comp_task, cct, cpu_to_node(cpu),
					   "ehca_comp/%d", cpu);

	return cct->task;
}

static void destroy_comp_task(struct ehca_comp_pool *pool,
			      int cpu)
{
	struct ehca_cpu_comp_task *cct;
	struct task_struct *task;
	unsigned long flags_cct;

	cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);

	spin_lock_irqsave(&cct->task_lock, flags_cct);
	struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);

	task = cct->task;
	cct->task = NULL;
	spin_lock_irq(&cct->task_lock);
	cct->cq_jobs = 0;

	spin_unlock_irqrestore(&cct->task_lock, flags_cct);

	if (task)
		kthread_stop(task);
	cct->active = 0;
	WARN_ON(!list_empty(&cct->cq_list));
	spin_unlock_irq(&cct->task_lock);
}

static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
static int comp_task_should_run(unsigned int cpu)
{
	struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
	LIST_HEAD(list);
	struct ehca_cq *cq;
	unsigned long flags_cct;

	spin_lock_irqsave(&cct->task_lock, flags_cct);

	list_splice_init(&cct->cq_list, &list);

	while (!list_empty(&list)) {
		cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);

		list_del(&cq->entry);
		__queue_comp_task(cq, this_cpu_ptr(pool->cpu_comp_tasks));
	}

	spin_unlock_irqrestore(&cct->task_lock, flags_cct);

	return cct->cq_jobs;
}

static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
					unsigned long action,
					void *hcpu)
static void comp_task(unsigned int cpu)
{
	unsigned int cpu = (unsigned long)hcpu;
	struct ehca_cpu_comp_task *cct;
	struct ehca_cpu_comp_task *cct = this_cpu_ptr(pool->cpu_comp_tasks);
	int cql_empty;

	switch (action) {
	case CPU_UP_PREPARE:
	case CPU_UP_PREPARE_FROZEN:
		ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
		if (!create_comp_task(pool, cpu)) {
			ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
			return notifier_from_errno(-ENOMEM);
		}
		break;
	case CPU_UP_CANCELED:
	case CPU_UP_CANCELED_FROZEN:
		ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
		kthread_bind(cct->task, cpumask_any(cpu_online_mask));
		destroy_comp_task(pool, cpu);
		break;
	case CPU_ONLINE:
	case CPU_ONLINE_FROZEN:
		ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
		kthread_bind(cct->task, cpu);
		wake_up_process(cct->task);
		break;
	case CPU_DOWN_PREPARE:
	case CPU_DOWN_PREPARE_FROZEN:
		ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
		break;
	case CPU_DOWN_FAILED:
	case CPU_DOWN_FAILED_FROZEN:
		ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
		break;
	case CPU_DEAD:
	case CPU_DEAD_FROZEN:
		ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
		destroy_comp_task(pool, cpu);
		take_over_work(pool, cpu);
		break;
	spin_lock_irq(&cct->task_lock);
	cql_empty = list_empty(&cct->cq_list);
	if (!cql_empty) {
		__set_current_state(TASK_RUNNING);
		run_comp_task(cct);
	}

	return NOTIFY_OK;
	spin_unlock_irq(&cct->task_lock);
}

static struct notifier_block comp_pool_callback_nb __cpuinitdata = {
	.notifier_call	= comp_pool_callback,
	.priority	= 0,
static struct smp_hotplug_thread comp_pool_threads = {
	.thread_should_run	= comp_task_should_run,
	.thread_fn		= comp_task,
	.thread_comm		= "ehca_comp/%u",
	.cleanup		= comp_task_stop,
	.park			= comp_task_park,
};

int ehca_create_comp_pool(void)
{
	int cpu;
	struct task_struct *task;
	int cpu, ret = -ENOMEM;

	if (!ehca_scaling_code)
		return 0;
@@ -905,38 +825,46 @@ int ehca_create_comp_pool(void)
	pool->last_cpu = cpumask_any(cpu_online_mask);

	pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task);
	if (pool->cpu_comp_tasks == NULL) {
		kfree(pool);
		return -EINVAL;
	}
	if (!pool->cpu_comp_tasks)
		goto out_pool;

	for_each_online_cpu(cpu) {
		task = create_comp_task(pool, cpu);
		if (task) {
			kthread_bind(task, cpu);
			wake_up_process(task);
		}
	pool->cpu_comp_threads = alloc_percpu(struct task_struct *);
	if (!pool->cpu_comp_threads)
		goto out_tasks;

	for_each_present_cpu(cpu) {
		struct ehca_cpu_comp_task *cct;

		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
		spin_lock_init(&cct->task_lock);
		INIT_LIST_HEAD(&cct->cq_list);
	}

	register_hotcpu_notifier(&comp_pool_callback_nb);
	comp_pool_threads.store = pool->cpu_comp_threads;
	ret = smpboot_register_percpu_thread(&comp_pool_threads);
	if (ret)
		goto out_threads;

	printk(KERN_INFO "eHCA scaling code enabled\n");
	pr_info("eHCA scaling code enabled\n");
	return ret;

	return 0;
out_threads:
	free_percpu(pool->cpu_comp_threads);
out_tasks:
	free_percpu(pool->cpu_comp_tasks);
out_pool:
	kfree(pool);
	return ret;
}

void ehca_destroy_comp_pool(void)
{
	int i;

	if (!ehca_scaling_code)
		return;

	unregister_hotcpu_notifier(&comp_pool_callback_nb);

	for_each_online_cpu(i)
		destroy_comp_task(pool, i);
	smpboot_unregister_percpu_thread(&comp_pool_threads);

	free_percpu(pool->cpu_comp_threads);
	free_percpu(pool->cpu_comp_tasks);
	kfree(pool);
}
+3 −3
Original line number Diff line number Diff line
@@ -58,15 +58,15 @@ void ehca_tasklet_eq(unsigned long data);
void ehca_process_eq(struct ehca_shca *shca, int is_irq);

struct ehca_cpu_comp_task {
	wait_queue_head_t wait_queue;
	struct list_head cq_list;
	struct task_struct *task;
	spinlock_t task_lock;
	int cq_jobs;
	int active;
};

struct ehca_comp_pool {
	struct ehca_cpu_comp_task *cpu_comp_tasks;
	struct ehca_cpu_comp_task __percpu *cpu_comp_tasks;
	struct task_struct * __percpu *cpu_comp_threads;
	int last_cpu;
	spinlock_t last_cpu_lock;
};
+10 −1
Original line number Diff line number Diff line
@@ -14,6 +14,11 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
	kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)


struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
					  void *data,
					  unsigned int cpu,
					  const char *namefmt);

/**
 * kthread_run - create and wake a thread.
 * @threadfn: the function to run until signal_pending(current).
@@ -34,9 +39,13 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),

void kthread_bind(struct task_struct *k, unsigned int cpu);
int kthread_stop(struct task_struct *k);
int kthread_should_stop(void);
bool kthread_should_stop(void);
bool kthread_should_park(void);
bool kthread_freezable_should_stop(bool *was_frozen);
void *kthread_data(struct task_struct *k);
int kthread_park(struct task_struct *k);
void kthread_unpark(struct task_struct *k);
void kthread_parkme(void);

int kthreadd(void *unused);
extern struct task_struct *kthreadd_task;
+43 −0
Original line number Diff line number Diff line
#ifndef _LINUX_SMPBOOT_H
#define _LINUX_SMPBOOT_H

#include <linux/types.h>

struct task_struct;
/* Cookie handed to the thread_fn*/
struct smpboot_thread_data;

/**
 * struct smp_hotplug_thread - CPU hotplug related thread descriptor
 * @store:		Pointer to per cpu storage for the task pointers
 * @list:		List head for core management
 * @thread_should_run:	Check whether the thread should run or not. Called with
 *			preemption disabled.
 * @thread_fn:		The associated thread function
 * @setup:		Optional setup function, called when the thread gets
 *			operational the first time
 * @cleanup:		Optional cleanup function, called when the thread
 *			should stop (module exit)
 * @park:		Optional park function, called when the thread is
 *			parked (cpu offline)
 * @unpark:		Optional unpark function, called when the thread is
 *			unparked (cpu online)
 * @thread_comm:	The base name of the thread
 */
struct smp_hotplug_thread {
	struct task_struct __percpu	**store;
	struct list_head		list;
	int				(*thread_should_run)(unsigned int cpu);
	void				(*thread_fn)(unsigned int cpu);
	void				(*setup)(unsigned int cpu);
	void				(*cleanup)(unsigned int cpu, bool online);
	void				(*park)(unsigned int cpu);
	void				(*unpark)(unsigned int cpu);
	const char			*thread_comm;
};

int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread);
void smpboot_unregister_percpu_thread(struct smp_hotplug_thread *plug_thread);
int smpboot_thread_schedule(void);

#endif
+1 −2
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o printk.o \
	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
	    notifier.o ksysfs.o cred.o \
	    async.o range.o groups.o lglock.o
	    async.o range.o groups.o lglock.o smpboot.o

ifdef CONFIG_FUNCTION_TRACER
# Do not trace debug files and internal ftrace files
@@ -46,7 +46,6 @@ obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SMP) += smpboot.o
ifneq ($(CONFIG_SMP),y)
obj-y += up.o
endif
Loading