diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:58 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:47 -0400 |
commit | ecdcc0234b27472b561378ac59e2beeea06ec6ff (patch) | |
tree | daeb20bb76d2f0d9283c538319a4f2d6a4341310 /arch/s390/kernel/time.c | |
parent | 6c210482ae4a9a5bb9377ad250feaacec3faa3cd (diff) |
[S390] Switch etr from tasklet to workqueue.
The clock synchronization of the ETR code requires an smp_call_function
to synchronize all cpus. Calling smp_call_function from a tasklet is
illegal. Replace the tasklet with a job on the global workqueue.
ETR work is rare and can be postponed to a be done by a kernel thread.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/time.c')
-rw-r--r-- | arch/s390/kernel/time.c | 34 |
1 files changed, 17 insertions, 17 deletions
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index e1ad464b6f20..711dae8da7ad 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -280,7 +280,6 @@ static void clock_comparator_interrupt(__u16 code) | |||
280 | } | 280 | } |
281 | 281 | ||
282 | static void etr_reset(void); | 282 | static void etr_reset(void); |
283 | static void etr_init(void); | ||
284 | static void etr_ext_handler(__u16); | 283 | static void etr_ext_handler(__u16); |
285 | 284 | ||
286 | /* | 285 | /* |
@@ -355,7 +354,6 @@ void __init time_init(void) | |||
355 | #ifdef CONFIG_VIRT_TIMER | 354 | #ifdef CONFIG_VIRT_TIMER |
356 | vtime_init(); | 355 | vtime_init(); |
357 | #endif | 356 | #endif |
358 | etr_init(); | ||
359 | } | 357 | } |
360 | 358 | ||
361 | /* | 359 | /* |
@@ -426,11 +424,11 @@ static struct etr_aib etr_port1; | |||
426 | static int etr_port1_uptodate; | 424 | static int etr_port1_uptodate; |
427 | static unsigned long etr_events; | 425 | static unsigned long etr_events; |
428 | static struct timer_list etr_timer; | 426 | static struct timer_list etr_timer; |
429 | static struct tasklet_struct etr_tasklet; | ||
430 | static DEFINE_PER_CPU(atomic_t, etr_sync_word); | 427 | static DEFINE_PER_CPU(atomic_t, etr_sync_word); |
431 | 428 | ||
432 | static void etr_timeout(unsigned long dummy); | 429 | static void etr_timeout(unsigned long dummy); |
433 | static void etr_tasklet_fn(unsigned long dummy); | 430 | static void etr_work_fn(struct work_struct *work); |
431 | static DECLARE_WORK(etr_work, etr_work_fn); | ||
434 | 432 | ||
435 | /* | 433 | /* |
436 | * The etr get_clock function. It will write the current clock value | 434 | * The etr get_clock function. It will write the current clock value |
@@ -507,29 +505,31 @@ static void etr_reset(void) | |||
507 | } | 505 | } |
508 | } | 506 | } |
509 | 507 | ||
510 | static void etr_init(void) | 508 | static int __init etr_init(void) |
511 | { | 509 | { |
512 | struct etr_aib aib; | 510 | struct etr_aib aib; |
513 | 511 | ||
514 | if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) | 512 | if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) |
515 | return; | 513 | return 0; |
516 | /* Check if this machine has the steai instruction. */ | 514 | /* Check if this machine has the steai instruction. */ |
517 | if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) | 515 | if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) |
518 | set_bit(ETR_FLAG_STEAI, &etr_flags); | 516 | set_bit(ETR_FLAG_STEAI, &etr_flags); |
519 | setup_timer(&etr_timer, etr_timeout, 0UL); | 517 | setup_timer(&etr_timer, etr_timeout, 0UL); |
520 | tasklet_init(&etr_tasklet, etr_tasklet_fn, 0); | ||
521 | if (!etr_port0_online && !etr_port1_online) | 518 | if (!etr_port0_online && !etr_port1_online) |
522 | set_bit(ETR_FLAG_EACCES, &etr_flags); | 519 | set_bit(ETR_FLAG_EACCES, &etr_flags); |
523 | if (etr_port0_online) { | 520 | if (etr_port0_online) { |
524 | set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); | 521 | set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); |
525 | tasklet_hi_schedule(&etr_tasklet); | 522 | schedule_work(&etr_work); |
526 | } | 523 | } |
527 | if (etr_port1_online) { | 524 | if (etr_port1_online) { |
528 | set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); | 525 | set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); |
529 | tasklet_hi_schedule(&etr_tasklet); | 526 | schedule_work(&etr_work); |
530 | } | 527 | } |
528 | return 0; | ||
531 | } | 529 | } |
532 | 530 | ||
531 | arch_initcall(etr_init); | ||
532 | |||
533 | /* | 533 | /* |
534 | * Two sorts of ETR machine checks. The architecture reads: | 534 | * Two sorts of ETR machine checks. The architecture reads: |
535 | * "When a machine-check niterruption occurs and if a switch-to-local or | 535 | * "When a machine-check niterruption occurs and if a switch-to-local or |
@@ -549,7 +549,7 @@ void etr_switch_to_local(void) | |||
549 | return; | 549 | return; |
550 | etr_disable_sync_clock(NULL); | 550 | etr_disable_sync_clock(NULL); |
551 | set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); | 551 | set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); |
552 | tasklet_hi_schedule(&etr_tasklet); | 552 | schedule_work(&etr_work); |
553 | } | 553 | } |
554 | 554 | ||
555 | /* | 555 | /* |
@@ -564,7 +564,7 @@ void etr_sync_check(void) | |||
564 | return; | 564 | return; |
565 | etr_disable_sync_clock(NULL); | 565 | etr_disable_sync_clock(NULL); |
566 | set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); | 566 | set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); |
567 | tasklet_hi_schedule(&etr_tasklet); | 567 | schedule_work(&etr_work); |
568 | } | 568 | } |
569 | 569 | ||
570 | /* | 570 | /* |
@@ -591,13 +591,13 @@ static void etr_ext_handler(__u16 code) | |||
591 | * Both ports are not up-to-date now. | 591 | * Both ports are not up-to-date now. |
592 | */ | 592 | */ |
593 | set_bit(ETR_EVENT_PORT_ALERT, &etr_events); | 593 | set_bit(ETR_EVENT_PORT_ALERT, &etr_events); |
594 | tasklet_hi_schedule(&etr_tasklet); | 594 | schedule_work(&etr_work); |
595 | } | 595 | } |
596 | 596 | ||
597 | static void etr_timeout(unsigned long dummy) | 597 | static void etr_timeout(unsigned long dummy) |
598 | { | 598 | { |
599 | set_bit(ETR_EVENT_UPDATE, &etr_events); | 599 | set_bit(ETR_EVENT_UPDATE, &etr_events); |
600 | tasklet_hi_schedule(&etr_tasklet); | 600 | schedule_work(&etr_work); |
601 | } | 601 | } |
602 | 602 | ||
603 | /* | 603 | /* |
@@ -927,7 +927,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, | |||
927 | if (!eacr.e0 && !eacr.e1) | 927 | if (!eacr.e0 && !eacr.e1) |
928 | return eacr; | 928 | return eacr; |
929 | 929 | ||
930 | /* Update port0 or port1 with aib stored in etr_tasklet_fn. */ | 930 | /* Update port0 or port1 with aib stored in etr_work_fn. */ |
931 | if (aib->esw.q == 0) { | 931 | if (aib->esw.q == 0) { |
932 | /* Information for port 0 stored. */ | 932 | /* Information for port 0 stored. */ |
933 | if (eacr.p0 && !etr_port0_uptodate) { | 933 | if (eacr.p0 && !etr_port0_uptodate) { |
@@ -1007,7 +1007,7 @@ static void etr_update_eacr(struct etr_eacr eacr) | |||
1007 | * particular this is the only function that calls etr_update_eacr(), | 1007 | * particular this is the only function that calls etr_update_eacr(), |
1008 | * it "controls" the etr control register. | 1008 | * it "controls" the etr control register. |
1009 | */ | 1009 | */ |
1010 | static void etr_tasklet_fn(unsigned long dummy) | 1010 | static void etr_work_fn(struct work_struct *work) |
1011 | { | 1011 | { |
1012 | unsigned long long now; | 1012 | unsigned long long now; |
1013 | struct etr_eacr eacr; | 1013 | struct etr_eacr eacr; |
@@ -1220,13 +1220,13 @@ static ssize_t etr_online_store(struct sys_device *dev, | |||
1220 | return count; /* Nothing to do. */ | 1220 | return count; /* Nothing to do. */ |
1221 | etr_port0_online = value; | 1221 | etr_port0_online = value; |
1222 | set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); | 1222 | set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); |
1223 | tasklet_hi_schedule(&etr_tasklet); | 1223 | schedule_work(&etr_work); |
1224 | } else { | 1224 | } else { |
1225 | if (etr_port1_online == value) | 1225 | if (etr_port1_online == value) |
1226 | return count; /* Nothing to do. */ | 1226 | return count; /* Nothing to do. */ |
1227 | etr_port1_online = value; | 1227 | etr_port1_online = value; |
1228 | set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); | 1228 | set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); |
1229 | tasklet_hi_schedule(&etr_tasklet); | 1229 | schedule_work(&etr_work); |
1230 | } | 1230 | } |
1231 | return count; | 1231 | return count; |
1232 | } | 1232 | } |