diff options
| -rw-r--r-- | arch/s390/include/asm/cpu.h | 3 | ||||
| -rw-r--r-- | arch/s390/kernel/process.c | 67 | ||||
| -rw-r--r-- | arch/s390/kernel/smp.c | 25 | ||||
| -rw-r--r-- | arch/s390/kernel/vtime.c | 3 |
4 files changed, 61 insertions, 37 deletions
diff --git a/arch/s390/include/asm/cpu.h b/arch/s390/include/asm/cpu.h index e5a6a9ba3adf..89456df43c4a 100644 --- a/arch/s390/include/asm/cpu.h +++ b/arch/s390/include/asm/cpu.h | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | 14 | ||
| 15 | struct s390_idle_data { | 15 | struct s390_idle_data { |
| 16 | spinlock_t lock; | 16 | spinlock_t lock; |
| 17 | unsigned int in_idle; | ||
| 18 | unsigned long long idle_count; | 17 | unsigned long long idle_count; |
| 19 | unsigned long long idle_enter; | 18 | unsigned long long idle_enter; |
| 20 | unsigned long long idle_time; | 19 | unsigned long long idle_time; |
| @@ -26,7 +25,7 @@ void s390_idle_leave(void); | |||
| 26 | 25 | ||
| 27 | static inline void s390_idle_check(void) | 26 | static inline void s390_idle_check(void) |
| 28 | { | 27 | { |
| 29 | if ((&__get_cpu_var(s390_idle))->in_idle) | 28 | if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL) |
| 30 | s390_idle_leave(); | 29 | s390_idle_leave(); |
| 31 | } | 30 | } |
| 32 | 31 | ||
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 04f8c67a6101..1e06436f07c2 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/utsname.h> | 38 | #include <linux/utsname.h> |
| 39 | #include <linux/tick.h> | 39 | #include <linux/tick.h> |
| 40 | #include <linux/elfcore.h> | 40 | #include <linux/elfcore.h> |
| 41 | #include <linux/kernel_stat.h> | ||
| 41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
| 42 | #include <asm/pgtable.h> | 43 | #include <asm/pgtable.h> |
| 43 | #include <asm/system.h> | 44 | #include <asm/system.h> |
| @@ -79,30 +80,19 @@ DEFINE_PER_CPU(struct s390_idle_data, s390_idle) = { | |||
| 79 | .lock = __SPIN_LOCK_UNLOCKED(s390_idle.lock) | 80 | .lock = __SPIN_LOCK_UNLOCKED(s390_idle.lock) |
| 80 | }; | 81 | }; |
| 81 | 82 | ||
| 82 | static int s390_idle_enter(void) | 83 | void s390_idle_leave(void) |
| 83 | { | 84 | { |
| 84 | struct s390_idle_data *idle; | 85 | struct s390_idle_data *idle; |
| 86 | unsigned long long idle_time; | ||
| 85 | 87 | ||
| 86 | idle = &__get_cpu_var(s390_idle); | 88 | idle = &__get_cpu_var(s390_idle); |
| 89 | idle_time = S390_lowcore.int_clock - idle->idle_enter; | ||
| 87 | spin_lock(&idle->lock); | 90 | spin_lock(&idle->lock); |
| 91 | idle->idle_time += idle_time; | ||
| 92 | idle->idle_enter = 0ULL; | ||
| 88 | idle->idle_count++; | 93 | idle->idle_count++; |
| 89 | idle->in_idle = 1; | ||
| 90 | idle->idle_enter = get_clock(); | ||
| 91 | spin_unlock(&idle->lock); | 94 | spin_unlock(&idle->lock); |
| 92 | vtime_stop_cpu_timer(); | ||
| 93 | return NOTIFY_OK; | ||
| 94 | } | ||
| 95 | |||
| 96 | void s390_idle_leave(void) | ||
| 97 | { | ||
| 98 | struct s390_idle_data *idle; | ||
| 99 | |||
| 100 | vtime_start_cpu_timer(); | 95 | vtime_start_cpu_timer(); |
| 101 | idle = &__get_cpu_var(s390_idle); | ||
| 102 | spin_lock(&idle->lock); | ||
| 103 | idle->idle_time += get_clock() - idle->idle_enter; | ||
| 104 | idle->in_idle = 0; | ||
| 105 | spin_unlock(&idle->lock); | ||
| 106 | } | 96 | } |
| 107 | 97 | ||
| 108 | extern void s390_handle_mcck(void); | 98 | extern void s390_handle_mcck(void); |
| @@ -111,16 +101,16 @@ extern void s390_handle_mcck(void); | |||
| 111 | */ | 101 | */ |
| 112 | static void default_idle(void) | 102 | static void default_idle(void) |
| 113 | { | 103 | { |
| 104 | struct s390_idle_data *idle = &__get_cpu_var(s390_idle); | ||
| 105 | unsigned long addr; | ||
| 106 | psw_t psw; | ||
| 107 | |||
| 114 | /* CPU is going idle. */ | 108 | /* CPU is going idle. */ |
| 115 | local_irq_disable(); | 109 | local_irq_disable(); |
| 116 | if (need_resched()) { | 110 | if (need_resched()) { |
| 117 | local_irq_enable(); | 111 | local_irq_enable(); |
| 118 | return; | 112 | return; |
| 119 | } | 113 | } |
| 120 | if (s390_idle_enter() == NOTIFY_BAD) { | ||
| 121 | local_irq_enable(); | ||
| 122 | return; | ||
| 123 | } | ||
| 124 | #ifdef CONFIG_HOTPLUG_CPU | 114 | #ifdef CONFIG_HOTPLUG_CPU |
| 125 | if (cpu_is_offline(smp_processor_id())) { | 115 | if (cpu_is_offline(smp_processor_id())) { |
| 126 | preempt_enable_no_resched(); | 116 | preempt_enable_no_resched(); |
| @@ -138,9 +128,42 @@ static void default_idle(void) | |||
| 138 | trace_hardirqs_on(); | 128 | trace_hardirqs_on(); |
| 139 | /* Don't trace preempt off for idle. */ | 129 | /* Don't trace preempt off for idle. */ |
| 140 | stop_critical_timings(); | 130 | stop_critical_timings(); |
| 131 | vtime_stop_cpu_timer(); | ||
| 132 | |||
| 133 | /* | ||
| 134 | * The inline assembly is equivalent to | ||
| 135 | * idle->idle_enter = get_clock(); | ||
| 136 | * __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | | ||
| 137 | * PSW_MASK_IO | PSW_MASK_EXT); | ||
| 138 | * The difference is that the inline assembly makes sure that | ||
| 139 | * the stck instruction is right before the lpsw instruction. | ||
| 140 | * This is done to increase the precision. | ||
| 141 | */ | ||
| 142 | |||
| 141 | /* Wait for external, I/O or machine check interrupt. */ | 143 | /* Wait for external, I/O or machine check interrupt. */ |
| 142 | __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | | 144 | psw.mask = psw_kernel_bits|PSW_MASK_WAIT|PSW_MASK_IO|PSW_MASK_EXT; |
| 143 | PSW_MASK_IO | PSW_MASK_EXT); | 145 | #ifndef __s390x__ |
| 146 | asm volatile( | ||
| 147 | " basr %0,0\n" | ||
| 148 | "0: ahi %0,1f-0b\n" | ||
| 149 | " st %0,4(%2)\n" | ||
| 150 | " stck 0(%3)\n" | ||
| 151 | " lpsw 0(%2)\n" | ||
| 152 | "1:" | ||
| 153 | : "=&d" (addr), "=m" (idle->idle_enter) | ||
| 154 | : "a" (&psw), "a" (&idle->idle_enter), "m" (psw) | ||
| 155 | : "memory", "cc"); | ||
| 156 | #else /* __s390x__ */ | ||
| 157 | asm volatile( | ||
| 158 | " larl %0,1f\n" | ||
| 159 | " stg %0,8(%2)\n" | ||
| 160 | " stck 0(%3)\n" | ||
| 161 | " lpswe 0(%2)\n" | ||
| 162 | "1:" | ||
| 163 | : "=&d" (addr), "=m" (idle->idle_enter) | ||
| 164 | : "a" (&psw), "a" (&idle->idle_enter), "m" (psw) | ||
| 165 | : "memory", "cc"); | ||
| 166 | #endif /* __s390x__ */ | ||
| 144 | start_critical_timings(); | 167 | start_critical_timings(); |
| 145 | } | 168 | } |
| 146 | 169 | ||
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 6fc78541dc57..3979a6fc0882 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
| @@ -851,9 +851,11 @@ static ssize_t show_idle_count(struct sys_device *dev, | |||
| 851 | unsigned long long idle_count; | 851 | unsigned long long idle_count; |
| 852 | 852 | ||
| 853 | idle = &per_cpu(s390_idle, dev->id); | 853 | idle = &per_cpu(s390_idle, dev->id); |
| 854 | spin_lock_irq(&idle->lock); | 854 | spin_lock(&idle->lock); |
| 855 | idle_count = idle->idle_count; | 855 | idle_count = idle->idle_count; |
| 856 | spin_unlock_irq(&idle->lock); | 856 | if (idle->idle_enter) |
| 857 | idle_count++; | ||
| 858 | spin_unlock(&idle->lock); | ||
| 857 | return sprintf(buf, "%llu\n", idle_count); | 859 | return sprintf(buf, "%llu\n", idle_count); |
| 858 | } | 860 | } |
| 859 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); | 861 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); |
| @@ -862,18 +864,17 @@ static ssize_t show_idle_time(struct sys_device *dev, | |||
| 862 | struct sysdev_attribute *attr, char *buf) | 864 | struct sysdev_attribute *attr, char *buf) |
| 863 | { | 865 | { |
| 864 | struct s390_idle_data *idle; | 866 | struct s390_idle_data *idle; |
| 865 | unsigned long long new_time; | 867 | unsigned long long now, idle_time, idle_enter; |
| 866 | 868 | ||
| 867 | idle = &per_cpu(s390_idle, dev->id); | 869 | idle = &per_cpu(s390_idle, dev->id); |
| 868 | spin_lock_irq(&idle->lock); | 870 | spin_lock(&idle->lock); |
| 869 | if (idle->in_idle) { | 871 | now = get_clock(); |
| 870 | new_time = get_clock(); | 872 | idle_time = idle->idle_time; |
| 871 | idle->idle_time += new_time - idle->idle_enter; | 873 | idle_enter = idle->idle_enter; |
| 872 | idle->idle_enter = new_time; | 874 | if (idle_enter != 0ULL && idle_enter < now) |
| 873 | } | 875 | idle_time += now - idle_enter; |
| 874 | new_time = idle->idle_time; | 876 | spin_unlock(&idle->lock); |
| 875 | spin_unlock_irq(&idle->lock); | 877 | return sprintf(buf, "%llu\n", idle_time >> 12); |
| 876 | return sprintf(buf, "%llu\n", new_time >> 12); | ||
| 877 | } | 878 | } |
| 878 | static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); | 879 | static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); |
| 879 | 880 | ||
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 1254a4d0d762..25d21fef76ba 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
| @@ -112,6 +112,7 @@ EXPORT_SYMBOL_GPL(account_system_vtime); | |||
| 112 | 112 | ||
| 113 | static inline void set_vtimer(__u64 expires) | 113 | static inline void set_vtimer(__u64 expires) |
| 114 | { | 114 | { |
| 115 | struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); | ||
| 115 | __u64 timer; | 116 | __u64 timer; |
| 116 | 117 | ||
| 117 | asm volatile (" STPT %0\n" /* Store current cpu timer value */ | 118 | asm volatile (" STPT %0\n" /* Store current cpu timer value */ |
| @@ -121,7 +122,7 @@ static inline void set_vtimer(__u64 expires) | |||
| 121 | S390_lowcore.last_update_timer = expires; | 122 | S390_lowcore.last_update_timer = expires; |
| 122 | 123 | ||
| 123 | /* store expire time for this CPU timer */ | 124 | /* store expire time for this CPU timer */ |
| 124 | __get_cpu_var(virt_cpu_timer).to_expire = expires; | 125 | vq->to_expire = expires; |
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | void vtime_start_cpu_timer(void) | 128 | void vtime_start_cpu_timer(void) |
