diff options
| -rw-r--r-- | arch/s390/include/asm/cputime.h | 2 | ||||
| -rw-r--r-- | arch/s390/kernel/smp.c | 28 | ||||
| -rw-r--r-- | arch/s390/kernel/vtime.c | 22 |
3 files changed, 35 insertions, 17 deletions
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index ec917d42ee6d..7a3817a656df 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h | |||
| @@ -178,7 +178,7 @@ cputime64_to_clock_t(cputime64_t cputime) | |||
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | struct s390_idle_data { | 180 | struct s390_idle_data { |
| 181 | spinlock_t lock; | 181 | unsigned int sequence; |
| 182 | unsigned long long idle_count; | 182 | unsigned long long idle_count; |
| 183 | unsigned long long idle_enter; | 183 | unsigned long long idle_enter; |
| 184 | unsigned long long idle_time; | 184 | unsigned long long idle_time; |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index fd8e3111a4e8..2270730f5354 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
| @@ -856,13 +856,20 @@ static ssize_t show_idle_count(struct sys_device *dev, | |||
| 856 | { | 856 | { |
| 857 | struct s390_idle_data *idle; | 857 | struct s390_idle_data *idle; |
| 858 | unsigned long long idle_count; | 858 | unsigned long long idle_count; |
| 859 | unsigned int sequence; | ||
| 859 | 860 | ||
| 860 | idle = &per_cpu(s390_idle, dev->id); | 861 | idle = &per_cpu(s390_idle, dev->id); |
| 861 | spin_lock(&idle->lock); | 862 | repeat: |
| 863 | sequence = idle->sequence; | ||
| 864 | smp_rmb(); | ||
| 865 | if (sequence & 1) | ||
| 866 | goto repeat; | ||
| 862 | idle_count = idle->idle_count; | 867 | idle_count = idle->idle_count; |
| 863 | if (idle->idle_enter) | 868 | if (idle->idle_enter) |
| 864 | idle_count++; | 869 | idle_count++; |
| 865 | spin_unlock(&idle->lock); | 870 | smp_rmb(); |
| 871 | if (idle->sequence != sequence) | ||
| 872 | goto repeat; | ||
| 866 | return sprintf(buf, "%llu\n", idle_count); | 873 | return sprintf(buf, "%llu\n", idle_count); |
| 867 | } | 874 | } |
| 868 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); | 875 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); |
| @@ -872,15 +879,22 @@ static ssize_t show_idle_time(struct sys_device *dev, | |||
| 872 | { | 879 | { |
| 873 | struct s390_idle_data *idle; | 880 | struct s390_idle_data *idle; |
| 874 | unsigned long long now, idle_time, idle_enter; | 881 | unsigned long long now, idle_time, idle_enter; |
| 882 | unsigned int sequence; | ||
| 875 | 883 | ||
| 876 | idle = &per_cpu(s390_idle, dev->id); | 884 | idle = &per_cpu(s390_idle, dev->id); |
| 877 | spin_lock(&idle->lock); | ||
| 878 | now = get_clock(); | 885 | now = get_clock(); |
| 886 | repeat: | ||
| 887 | sequence = idle->sequence; | ||
| 888 | smp_rmb(); | ||
| 889 | if (sequence & 1) | ||
| 890 | goto repeat; | ||
| 879 | idle_time = idle->idle_time; | 891 | idle_time = idle->idle_time; |
| 880 | idle_enter = idle->idle_enter; | 892 | idle_enter = idle->idle_enter; |
| 881 | if (idle_enter != 0ULL && idle_enter < now) | 893 | if (idle_enter != 0ULL && idle_enter < now) |
| 882 | idle_time += now - idle_enter; | 894 | idle_time += now - idle_enter; |
| 883 | spin_unlock(&idle->lock); | 895 | smp_rmb(); |
| 896 | if (idle->sequence != sequence) | ||
| 897 | goto repeat; | ||
| 884 | return sprintf(buf, "%llu\n", idle_time >> 12); | 898 | return sprintf(buf, "%llu\n", idle_time >> 12); |
| 885 | } | 899 | } |
| 886 | static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); | 900 | static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); |
| @@ -908,11 +922,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, | |||
| 908 | case CPU_ONLINE: | 922 | case CPU_ONLINE: |
| 909 | case CPU_ONLINE_FROZEN: | 923 | case CPU_ONLINE_FROZEN: |
| 910 | idle = &per_cpu(s390_idle, cpu); | 924 | idle = &per_cpu(s390_idle, cpu); |
| 911 | spin_lock_irq(&idle->lock); | 925 | memset(idle, 0, sizeof(struct s390_idle_data)); |
| 912 | idle->idle_enter = 0; | ||
| 913 | idle->idle_time = 0; | ||
| 914 | idle->idle_count = 0; | ||
| 915 | spin_unlock_irq(&idle->lock); | ||
| 916 | if (sysfs_create_group(&s->kobj, &cpu_online_attr_group)) | 926 | if (sysfs_create_group(&s->kobj, &cpu_online_attr_group)) |
| 917 | return NOTIFY_BAD; | 927 | return NOTIFY_BAD; |
| 918 | break; | 928 | break; |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index ade17e771f05..c41bb0d416e1 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
| @@ -27,9 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); | 28 | static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); |
| 29 | 29 | ||
| 30 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle) = { | 30 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle); |
| 31 | .lock = __SPIN_LOCK_UNLOCKED(s390_idle.lock) | ||
| 32 | }; | ||
| 33 | 31 | ||
| 34 | static inline __u64 get_vtimer(void) | 32 | static inline __u64 get_vtimer(void) |
| 35 | { | 33 | { |
| @@ -151,11 +149,13 @@ void vtime_start_cpu(void) | |||
| 151 | vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; | 149 | vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; |
| 152 | } | 150 | } |
| 153 | 151 | ||
| 154 | spin_lock(&idle->lock); | 152 | idle->sequence++; |
| 153 | smp_wmb(); | ||
| 155 | idle->idle_time += idle_time; | 154 | idle->idle_time += idle_time; |
| 156 | idle->idle_enter = 0ULL; | 155 | idle->idle_enter = 0ULL; |
| 157 | idle->idle_count++; | 156 | idle->idle_count++; |
| 158 | spin_unlock(&idle->lock); | 157 | smp_wmb(); |
| 158 | idle->sequence++; | ||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | void vtime_stop_cpu(void) | 161 | void vtime_stop_cpu(void) |
| @@ -242,15 +242,23 @@ cputime64_t s390_get_idle_time(int cpu) | |||
| 242 | { | 242 | { |
| 243 | struct s390_idle_data *idle; | 243 | struct s390_idle_data *idle; |
| 244 | unsigned long long now, idle_time, idle_enter; | 244 | unsigned long long now, idle_time, idle_enter; |
| 245 | unsigned int sequence; | ||
| 245 | 246 | ||
| 246 | idle = &per_cpu(s390_idle, cpu); | 247 | idle = &per_cpu(s390_idle, cpu); |
| 247 | spin_lock(&idle->lock); | 248 | |
| 248 | now = get_clock(); | 249 | now = get_clock(); |
| 250 | repeat: | ||
| 251 | sequence = idle->sequence; | ||
| 252 | smp_rmb(); | ||
| 253 | if (sequence & 1) | ||
| 254 | goto repeat; | ||
| 249 | idle_time = 0; | 255 | idle_time = 0; |
| 250 | idle_enter = idle->idle_enter; | 256 | idle_enter = idle->idle_enter; |
| 251 | if (idle_enter != 0ULL && idle_enter < now) | 257 | if (idle_enter != 0ULL && idle_enter < now) |
| 252 | idle_time = now - idle_enter; | 258 | idle_time = now - idle_enter; |
| 253 | spin_unlock(&idle->lock); | 259 | smp_rmb(); |
| 260 | if (idle->sequence != sequence) | ||
| 261 | goto repeat; | ||
| 254 | return idle_time; | 262 | return idle_time; |
| 255 | } | 263 | } |
| 256 | 264 | ||
