diff options
Diffstat (limited to 'arch/s390/kernel/vtime.c')
-rw-r--r-- | arch/s390/kernel/vtime.c | 83 |
1 files changed, 51 insertions, 32 deletions
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index ecf0304e61c1..c87f59bd8246 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -134,6 +134,8 @@ void vtime_start_cpu(void) | |||
134 | /* Account time spent with enabled wait psw loaded as idle time. */ | 134 | /* Account time spent with enabled wait psw loaded as idle time. */ |
135 | idle_time = S390_lowcore.int_clock - idle->idle_enter; | 135 | idle_time = S390_lowcore.int_clock - idle->idle_enter; |
136 | account_idle_time(idle_time); | 136 | account_idle_time(idle_time); |
137 | S390_lowcore.steal_timer += | ||
138 | idle->idle_enter - S390_lowcore.last_update_clock; | ||
137 | S390_lowcore.last_update_clock = S390_lowcore.int_clock; | 139 | S390_lowcore.last_update_clock = S390_lowcore.int_clock; |
138 | 140 | ||
139 | /* Account system time spent going idle. */ | 141 | /* Account system time spent going idle. */ |
@@ -238,6 +240,22 @@ void vtime_stop_cpu(void) | |||
238 | } | 240 | } |
239 | } | 241 | } |
240 | 242 | ||
243 | cputime64_t s390_get_idle_time(int cpu) | ||
244 | { | ||
245 | struct s390_idle_data *idle; | ||
246 | unsigned long long now, idle_time, idle_enter; | ||
247 | |||
248 | idle = &per_cpu(s390_idle, cpu); | ||
249 | spin_lock(&idle->lock); | ||
250 | now = get_clock(); | ||
251 | idle_time = 0; | ||
252 | idle_enter = idle->idle_enter; | ||
253 | if (idle_enter != 0ULL && idle_enter < now) | ||
254 | idle_time = now - idle_enter; | ||
255 | spin_unlock(&idle->lock); | ||
256 | return idle_time; | ||
257 | } | ||
258 | |||
241 | /* | 259 | /* |
242 | * Sorted add to a list. List is linear searched until first bigger | 260 | * Sorted add to a list. List is linear searched until first bigger |
243 | * element is found. | 261 | * element is found. |
@@ -425,17 +443,7 @@ void add_virt_timer_periodic(void *new) | |||
425 | } | 443 | } |
426 | EXPORT_SYMBOL(add_virt_timer_periodic); | 444 | EXPORT_SYMBOL(add_virt_timer_periodic); |
427 | 445 | ||
428 | /* | 446 | 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 | { | 447 | { |
440 | struct vtimer_queue *vq; | 448 | struct vtimer_queue *vq; |
441 | unsigned long flags; | 449 | unsigned long flags; |
@@ -444,39 +452,35 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) | |||
444 | BUG_ON(!timer->function); | 452 | BUG_ON(!timer->function); |
445 | BUG_ON(!expires || expires > VTIMER_MAX_SLICE); | 453 | BUG_ON(!expires || expires > VTIMER_MAX_SLICE); |
446 | 454 | ||
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)) | 455 | if (timer->expires == expires && vtimer_pending(timer)) |
453 | return 1; | 456 | return 1; |
454 | 457 | ||
455 | cpu = get_cpu(); | 458 | cpu = get_cpu(); |
456 | vq = &per_cpu(virt_cpu_timer, cpu); | 459 | vq = &per_cpu(virt_cpu_timer, cpu); |
457 | 460 | ||
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 */ | 461 | /* disable interrupts before test if timer is pending */ |
462 | spin_lock_irqsave(&vq->lock, flags); | 462 | spin_lock_irqsave(&vq->lock, flags); |
463 | 463 | ||
464 | /* if timer isn't pending add it on the current CPU */ | 464 | /* if timer isn't pending add it on the current CPU */ |
465 | if (!vtimer_pending(timer)) { | 465 | if (!vtimer_pending(timer)) { |
466 | spin_unlock_irqrestore(&vq->lock, flags); | 466 | spin_unlock_irqrestore(&vq->lock, flags); |
467 | /* we do not activate an interval timer with mod_virt_timer */ | 467 | |
468 | timer->interval = 0; | 468 | if (periodic) |
469 | timer->interval = expires; | ||
470 | else | ||
471 | timer->interval = 0; | ||
469 | timer->expires = expires; | 472 | timer->expires = expires; |
470 | timer->cpu = cpu; | 473 | timer->cpu = cpu; |
471 | internal_add_vtimer(timer); | 474 | internal_add_vtimer(timer); |
472 | return 0; | 475 | return 0; |
473 | } | 476 | } |
474 | 477 | ||
478 | /* check if we run on the right CPU */ | ||
479 | BUG_ON(timer->cpu != cpu); | ||
480 | |||
475 | list_del_init(&timer->entry); | 481 | list_del_init(&timer->entry); |
476 | timer->expires = expires; | 482 | timer->expires = expires; |
477 | 483 | if (periodic) | |
478 | /* also change the interval if we have an interval timer */ | ||
479 | if (timer->interval) | ||
480 | timer->interval = expires; | 484 | timer->interval = expires; |
481 | 485 | ||
482 | /* the timer can't expire anymore so we can release the lock */ | 486 | /* the timer can't expire anymore so we can release the lock */ |
@@ -484,9 +488,32 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) | |||
484 | internal_add_vtimer(timer); | 488 | internal_add_vtimer(timer); |
485 | return 1; | 489 | return 1; |
486 | } | 490 | } |
491 | |||
492 | /* | ||
493 | * If we change a pending timer the function must be called on the CPU | ||
494 | * where the timer is running on. | ||
495 | * | ||
496 | * returns whether it has modified a pending timer (1) or not (0) | ||
497 | */ | ||
498 | int mod_virt_timer(struct vtimer_list *timer, __u64 expires) | ||
499 | { | ||
500 | return __mod_vtimer(timer, expires, 0); | ||
501 | } | ||
487 | EXPORT_SYMBOL(mod_virt_timer); | 502 | EXPORT_SYMBOL(mod_virt_timer); |
488 | 503 | ||
489 | /* | 504 | /* |
505 | * If we change a pending timer the function must be called on the CPU | ||
506 | * where the timer is running on. | ||
507 | * | ||
508 | * returns whether it has modified a pending timer (1) or not (0) | ||
509 | */ | ||
510 | int mod_virt_timer_periodic(struct vtimer_list *timer, __u64 expires) | ||
511 | { | ||
512 | return __mod_vtimer(timer, expires, 1); | ||
513 | } | ||
514 | EXPORT_SYMBOL(mod_virt_timer_periodic); | ||
515 | |||
516 | /* | ||
490 | * delete a virtual timer | 517 | * delete a virtual timer |
491 | * | 518 | * |
492 | * returns whether the deleted timer was pending (1) or not (0) | 519 | * returns whether the deleted timer was pending (1) or not (0) |
@@ -516,16 +543,8 @@ EXPORT_SYMBOL(del_virt_timer); | |||
516 | */ | 543 | */ |
517 | void init_cpu_vtimer(void) | 544 | void init_cpu_vtimer(void) |
518 | { | 545 | { |
519 | struct thread_info *ti = current_thread_info(); | ||
520 | struct vtimer_queue *vq; | 546 | struct vtimer_queue *vq; |
521 | 547 | ||
522 | S390_lowcore.user_timer = ti->user_timer; | ||
523 | S390_lowcore.system_timer = ti->system_timer; | ||
524 | |||
525 | /* kick the virtual timer */ | ||
526 | asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); | ||
527 | asm volatile ("STPT %0" : "=m" (S390_lowcore.last_update_timer)); | ||
528 | |||
529 | /* initialize per cpu vtimer structure */ | 548 | /* initialize per cpu vtimer structure */ |
530 | vq = &__get_cpu_var(virt_cpu_timer); | 549 | vq = &__get_cpu_var(virt_cpu_timer); |
531 | INIT_LIST_HEAD(&vq->list); | 550 | INIT_LIST_HEAD(&vq->list); |