diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-07-14 06:14:45 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-16 07:05:07 -0400 |
commit | bd0e11ff221d929b2b711ce3e5712e097e9dd1d8 (patch) | |
tree | b4b7a44d336029908245396f40c7832c1898d91b /arch/sparc64/kernel | |
parent | 8b99cfb8cc51adae7f5294c8962a026c63100959 (diff) |
[SPARC64]: Process dr-cpu events in a kthread instead of workqueue.
This will be necessary to handle unconfigure requests
properly.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r-- | arch/sparc64/kernel/ds.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c index 0cb96dc399b7..d412cf876ab4 100644 --- a/arch/sparc64/kernel/ds.c +++ b/arch/sparc64/kernel/ds.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/mutex.h> | 14 | #include <linux/mutex.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/kthread.h> |
16 | #include <linux/cpu.h> | 16 | #include <linux/cpu.h> |
17 | 17 | ||
18 | #include <asm/ldc.h> | 18 | #include <asm/ldc.h> |
@@ -395,6 +395,7 @@ struct dr_cpu_resp_entry { | |||
395 | * ds_lock, and processed by dr_cpu_process() in order. | 395 | * ds_lock, and processed by dr_cpu_process() in order. |
396 | */ | 396 | */ |
397 | static LIST_HEAD(dr_cpu_work_list); | 397 | static LIST_HEAD(dr_cpu_work_list); |
398 | static DECLARE_WAIT_QUEUE_HEAD(dr_cpu_wait); | ||
398 | 399 | ||
399 | struct dr_cpu_queue_entry { | 400 | struct dr_cpu_queue_entry { |
400 | struct list_head list; | 401 | struct list_head list; |
@@ -533,10 +534,13 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num, | |||
533 | 534 | ||
534 | printk(KERN_INFO PFX "Starting cpu %d...\n", cpu); | 535 | printk(KERN_INFO PFX "Starting cpu %d...\n", cpu); |
535 | err = cpu_up(cpu); | 536 | err = cpu_up(cpu); |
536 | if (err) | 537 | if (err) { |
538 | printk(KERN_INFO PFX "CPU startup failed err=%d\n", | ||
539 | err); | ||
537 | dr_cpu_mark(resp, cpu, ncpus, | 540 | dr_cpu_mark(resp, cpu, ncpus, |
538 | DR_CPU_RES_FAILURE, | 541 | DR_CPU_RES_FAILURE, |
539 | DR_CPU_STAT_UNCONFIGURED); | 542 | DR_CPU_STAT_UNCONFIGURED); |
543 | } | ||
540 | } | 544 | } |
541 | 545 | ||
542 | spin_lock_irqsave(&ds_lock, flags); | 546 | spin_lock_irqsave(&ds_lock, flags); |
@@ -569,18 +573,16 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num, | |||
569 | return -EOPNOTSUPP; | 573 | return -EOPNOTSUPP; |
570 | } | 574 | } |
571 | 575 | ||
572 | static void dr_cpu_process(struct work_struct *work) | 576 | static void process_dr_cpu_list(struct ds_cap_state *cp) |
573 | { | 577 | { |
574 | struct dr_cpu_queue_entry *qp, *tmp; | 578 | struct dr_cpu_queue_entry *qp, *tmp; |
575 | struct ds_cap_state *cp; | ||
576 | unsigned long flags; | 579 | unsigned long flags; |
577 | LIST_HEAD(todo); | 580 | LIST_HEAD(todo); |
578 | cpumask_t mask; | 581 | cpumask_t mask; |
579 | 582 | ||
580 | cp = find_cap_by_string("dr-cpu"); | ||
581 | |||
582 | spin_lock_irqsave(&ds_lock, flags); | 583 | spin_lock_irqsave(&ds_lock, flags); |
583 | list_splice(&dr_cpu_work_list, &todo); | 584 | list_splice(&dr_cpu_work_list, &todo); |
585 | INIT_LIST_HEAD(&dr_cpu_work_list); | ||
584 | spin_unlock_irqrestore(&ds_lock, flags); | 586 | spin_unlock_irqrestore(&ds_lock, flags); |
585 | 587 | ||
586 | list_for_each_entry_safe(qp, tmp, &todo, list) { | 588 | list_for_each_entry_safe(qp, tmp, &todo, list) { |
@@ -627,7 +629,27 @@ next: | |||
627 | } | 629 | } |
628 | } | 630 | } |
629 | 631 | ||
630 | static DECLARE_WORK(dr_cpu_work, dr_cpu_process); | 632 | static int dr_cpu_thread(void *__unused) |
633 | { | ||
634 | struct ds_cap_state *cp; | ||
635 | DEFINE_WAIT(wait); | ||
636 | |||
637 | cp = find_cap_by_string("dr-cpu"); | ||
638 | |||
639 | while (1) { | ||
640 | prepare_to_wait(&dr_cpu_wait, &wait, TASK_INTERRUPTIBLE); | ||
641 | if (list_empty(&dr_cpu_work_list)) | ||
642 | schedule(); | ||
643 | finish_wait(&dr_cpu_wait, &wait); | ||
644 | |||
645 | if (kthread_should_stop()) | ||
646 | break; | ||
647 | |||
648 | process_dr_cpu_list(cp); | ||
649 | } | ||
650 | |||
651 | return 0; | ||
652 | } | ||
631 | 653 | ||
632 | static void dr_cpu_data(struct ldc_channel *lp, | 654 | static void dr_cpu_data(struct ldc_channel *lp, |
633 | struct ds_cap_state *dp, | 655 | struct ds_cap_state *dp, |
@@ -648,7 +670,7 @@ static void dr_cpu_data(struct ldc_channel *lp, | |||
648 | } else { | 670 | } else { |
649 | memcpy(&qp->req, buf, len); | 671 | memcpy(&qp->req, buf, len); |
650 | list_add_tail(&qp->list, &dr_cpu_work_list); | 672 | list_add_tail(&qp->list, &dr_cpu_work_list); |
651 | schedule_work(&dr_cpu_work); | 673 | wake_up(&dr_cpu_wait); |
652 | } | 674 | } |
653 | } | 675 | } |
654 | #endif | 676 | #endif |
@@ -1095,6 +1117,10 @@ static int __init ds_init(void) | |||
1095 | for (i = 0; i < ARRAY_SIZE(ds_states); i++) | 1117 | for (i = 0; i < ARRAY_SIZE(ds_states); i++) |
1096 | ds_states[i].handle = ((u64)i << 32); | 1118 | ds_states[i].handle = ((u64)i << 32); |
1097 | 1119 | ||
1120 | #ifdef CONFIG_HOTPLUG_CPU | ||
1121 | kthread_run(dr_cpu_thread, NULL, "kdrcpud"); | ||
1122 | #endif | ||
1123 | |||
1098 | return vio_register_driver(&ds_driver); | 1124 | return vio_register_driver(&ds_driver); |
1099 | } | 1125 | } |
1100 | 1126 | ||