diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2009-04-14 09:36:20 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-04-14 09:37:23 -0400 |
commit | b6ecfa9273e27b5c7ba04655eb44f78bf4db5b64 (patch) | |
tree | 559f0b436efd410625d8a7a502ca3a1503e3a1a2 /arch/s390 | |
parent | 0436230148c55e3afbe5c57775a1fb44ba4834ac (diff) |
[S390] extend virtual timer interface by mod_virt_timer_periodic
In case mod_virt_timer is used to add a non pending timer the timer
is always added as a one-shot timer. If mod_virt_timer is used for
periodic timers they may therfore be degraded to one-shot timers.
Add mod_virt_timer_periodic to the interface to allow safe re-programming
of the interval value.
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/timer.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 57 |
2 files changed, 34 insertions, 24 deletions
diff --git a/arch/s390/include/asm/timer.h b/arch/s390/include/asm/timer.h index e4bcab739c19..814243cafdfe 100644 --- a/arch/s390/include/asm/timer.h +++ b/arch/s390/include/asm/timer.h | |||
@@ -41,6 +41,7 @@ extern void init_virt_timer(struct vtimer_list *timer); | |||
41 | extern void add_virt_timer(void *new); | 41 | extern void add_virt_timer(void *new); |
42 | extern void add_virt_timer_periodic(void *new); | 42 | extern void add_virt_timer_periodic(void *new); |
43 | extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires); | 43 | extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires); |
44 | extern int mod_virt_timer_periodic(struct vtimer_list *timer, __u64 expires); | ||
44 | extern int del_virt_timer(struct vtimer_list *timer); | 45 | extern int del_virt_timer(struct vtimer_list *timer); |
45 | 46 | ||
46 | extern void init_cpu_vtimer(void); | 47 | extern void init_cpu_vtimer(void); |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index ecf0304e61c1..694b44374a2b 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -425,17 +425,7 @@ void add_virt_timer_periodic(void *new) | |||
425 | } | 425 | } |
426 | EXPORT_SYMBOL(add_virt_timer_periodic); | 426 | EXPORT_SYMBOL(add_virt_timer_periodic); |
427 | 427 | ||
428 | /* | 428 | int __mod_vtimer(struct vtimer_list *timer, __u64 expires, int periodic) |
429 | * If we change a pending timer the function must be called on the CPU | ||
430 | * where the timer is running on, e.g. by smp_call_function_single() | ||
431 | * | ||
432 | * The original mod_timer adds the timer if it is not pending. For | ||
433 | * compatibility we do the same. The timer will be added on the current | ||
434 | * CPU as a oneshot timer. | ||
435 | * | ||
436 | * returns whether it has modified a pending timer (1) or not (0) | ||
437 | */ | ||
438 | int mod_virt_timer(struct vtimer_list *timer, __u64 expires) | ||
439 | { | 429 | { |
440 | struct vtimer_queue *vq; | 430 | struct vtimer_queue *vq; |
441 | unsigned long flags; | 431 | unsigned long flags; |
@@ -444,39 +434,35 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) | |||
444 | BUG_ON(!timer->function); | 434 | BUG_ON(!timer->function); |
445 | BUG_ON(!expires || expires > VTIMER_MAX_SLICE); | 435 | BUG_ON(!expires || expires > VTIMER_MAX_SLICE); |
446 | 436 | ||
447 | /* | ||
448 | * This is a common optimization triggered by the | ||
449 | * networking code - if the timer is re-modified | ||
450 | * to be the same thing then just return: | ||
451 | */ | ||
452 | if (timer->expires == expires && vtimer_pending(timer)) | 437 | if (timer->expires == expires && vtimer_pending(timer)) |
453 | return 1; | 438 | return 1; |
454 | 439 | ||
455 | cpu = get_cpu(); | 440 | cpu = get_cpu(); |
456 | vq = &per_cpu(virt_cpu_timer, cpu); | 441 | vq = &per_cpu(virt_cpu_timer, cpu); |
457 | 442 | ||
458 | /* check if we run on the right CPU */ | ||
459 | BUG_ON(timer->cpu != cpu); | ||
460 | |||
461 | /* disable interrupts before test if timer is pending */ | 443 | /* disable interrupts before test if timer is pending */ |
462 | spin_lock_irqsave(&vq->lock, flags); | 444 | spin_lock_irqsave(&vq->lock, flags); |
463 | 445 | ||
464 | /* if timer isn't pending add it on the current CPU */ | 446 | /* if timer isn't pending add it on the current CPU */ |
465 | if (!vtimer_pending(timer)) { | 447 | if (!vtimer_pending(timer)) { |
466 | spin_unlock_irqrestore(&vq->lock, flags); | 448 | spin_unlock_irqrestore(&vq->lock, flags); |
467 | /* we do not activate an interval timer with mod_virt_timer */ | 449 | |
468 | timer->interval = 0; | 450 | if (periodic) |
451 | timer->interval = expires; | ||
452 | else | ||
453 | timer->interval = 0; | ||
469 | timer->expires = expires; | 454 | timer->expires = expires; |
470 | timer->cpu = cpu; | 455 | timer->cpu = cpu; |
471 | internal_add_vtimer(timer); | 456 | internal_add_vtimer(timer); |
472 | return 0; | 457 | return 0; |
473 | } | 458 | } |
474 | 459 | ||
460 | /* check if we run on the right CPU */ | ||
461 | BUG_ON(timer->cpu != cpu); | ||
462 | |||
475 | list_del_init(&timer->entry); | 463 | list_del_init(&timer->entry); |
476 | timer->expires = expires; | 464 | timer->expires = expires; |
477 | 465 | if (periodic) | |
478 | /* also change the interval if we have an interval timer */ | ||
479 | if (timer->interval) | ||
480 | timer->interval = expires; | 466 | timer->interval = expires; |
481 | 467 | ||
482 | /* the timer can't expire anymore so we can release the lock */ | 468 | /* the timer can't expire anymore so we can release the lock */ |
@@ -484,9 +470,32 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) | |||
484 | internal_add_vtimer(timer); | 470 | internal_add_vtimer(timer); |
485 | return 1; | 471 | return 1; |
486 | } | 472 | } |
473 | |||
474 | /* | ||
475 | * If we change a pending timer the function must be called on the CPU | ||
476 | * where the timer is running on. | ||
477 | * | ||
478 | * returns whether it has modified a pending timer (1) or not (0) | ||
479 | */ | ||
480 | int mod_virt_timer(struct vtimer_list *timer, __u64 expires) | ||
481 | { | ||
482 | return __mod_vtimer(timer, expires, 0); | ||
483 | } | ||
487 | EXPORT_SYMBOL(mod_virt_timer); | 484 | EXPORT_SYMBOL(mod_virt_timer); |
488 | 485 | ||
489 | /* | 486 | /* |
487 | * If we change a pending timer the function must be called on the CPU | ||
488 | * where the timer is running on. | ||
489 | * | ||
490 | * returns whether it has modified a pending timer (1) or not (0) | ||
491 | */ | ||
492 | int mod_virt_timer_periodic(struct vtimer_list *timer, __u64 expires) | ||
493 | { | ||
494 | return __mod_vtimer(timer, expires, 1); | ||
495 | } | ||
496 | EXPORT_SYMBOL(mod_virt_timer_periodic); | ||
497 | |||
498 | /* | ||
490 | * delete a virtual timer | 499 | * delete a virtual timer |
491 | * | 500 | * |
492 | * returns whether the deleted timer was pending (1) or not (0) | 501 | * returns whether the deleted timer was pending (1) or not (0) |