aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/kernel/process.c16
-rw-r--r--arch/s390/kernel/smp.c63
-rw-r--r--include/asm-s390/cpu.h25
3 files changed, 101 insertions, 3 deletions
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 70c57378f426..cc7c4ba0774d 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -44,6 +44,7 @@
44#include <asm/processor.h> 44#include <asm/processor.h>
45#include <asm/irq.h> 45#include <asm/irq.h>
46#include <asm/timer.h> 46#include <asm/timer.h>
47#include <asm/cpu.h>
47 48
48asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); 49asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
49 50
@@ -91,6 +92,14 @@ EXPORT_SYMBOL(unregister_idle_notifier);
91 92
92void do_monitor_call(struct pt_regs *regs, long interruption_code) 93void do_monitor_call(struct pt_regs *regs, long interruption_code)
93{ 94{
95 struct s390_idle_data *idle;
96
97 idle = &__get_cpu_var(s390_idle);
98 spin_lock(&idle->lock);
99 idle->idle_time += get_clock() - idle->idle_enter;
100 idle->in_idle = 0;
101 spin_unlock(&idle->lock);
102
94 /* disable monitor call class 0 */ 103 /* disable monitor call class 0 */
95 __ctl_clear_bit(8, 15); 104 __ctl_clear_bit(8, 15);
96 105
@@ -105,6 +114,7 @@ extern void s390_handle_mcck(void);
105static void default_idle(void) 114static void default_idle(void)
106{ 115{
107 int cpu, rc; 116 int cpu, rc;
117 struct s390_idle_data *idle;
108 118
109 /* CPU is going idle. */ 119 /* CPU is going idle. */
110 cpu = smp_processor_id(); 120 cpu = smp_processor_id();
@@ -142,6 +152,12 @@ static void default_idle(void)
142 return; 152 return;
143 } 153 }
144 154
155 idle = &__get_cpu_var(s390_idle);
156 spin_lock(&idle->lock);
157 idle->idle_count++;
158 idle->in_idle = 1;
159 idle->idle_enter = get_clock();
160 spin_unlock(&idle->lock);
145 trace_hardirqs_on(); 161 trace_hardirqs_on();
146 /* Wait for external, I/O or machine check interrupt. */ 162 /* Wait for external, I/O or machine check interrupt. */
147 __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | 163 __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 35edbef1d222..ba3fff06fad1 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -42,6 +42,7 @@
42#include <asm/tlbflush.h> 42#include <asm/tlbflush.h>
43#include <asm/timer.h> 43#include <asm/timer.h>
44#include <asm/lowcore.h> 44#include <asm/lowcore.h>
45#include <asm/cpu.h>
45 46
46/* 47/*
47 * An array with a pointer the lowcore of every CPU. 48 * An array with a pointer the lowcore of every CPU.
@@ -494,6 +495,8 @@ int __cpuinit start_secondary(void *cpuvoid)
494 return 0; 495 return 0;
495} 496}
496 497
498DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
499
497static void __init smp_create_idle(unsigned int cpu) 500static void __init smp_create_idle(unsigned int cpu)
498{ 501{
499 struct task_struct *p; 502 struct task_struct *p;
@@ -506,6 +509,7 @@ static void __init smp_create_idle(unsigned int cpu)
506 if (IS_ERR(p)) 509 if (IS_ERR(p))
507 panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); 510 panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
508 current_set[cpu] = p; 511 current_set[cpu] = p;
512 spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock);
509} 513}
510 514
511static int cpu_stopped(int cpu) 515static int cpu_stopped(int cpu)
@@ -724,6 +728,7 @@ void __init smp_prepare_boot_cpu(void)
724 cpu_set(0, cpu_online_map); 728 cpu_set(0, cpu_online_map);
725 S390_lowcore.percpu_offset = __per_cpu_offset[0]; 729 S390_lowcore.percpu_offset = __per_cpu_offset[0];
726 current_set[0] = current; 730 current_set[0] = current;
731 spin_lock_init(&(&__get_cpu_var(s390_idle))->lock);
727} 732}
728 733
729void __init smp_cpus_done(unsigned int max_cpus) 734void __init smp_cpus_done(unsigned int max_cpus)
@@ -756,22 +761,71 @@ static ssize_t show_capability(struct sys_device *dev, char *buf)
756} 761}
757static SYSDEV_ATTR(capability, 0444, show_capability, NULL); 762static SYSDEV_ATTR(capability, 0444, show_capability, NULL);
758 763
764static ssize_t show_idle_count(struct sys_device *dev, char *buf)
765{
766 struct s390_idle_data *idle;
767 unsigned long long idle_count;
768
769 idle = &per_cpu(s390_idle, dev->id);
770 spin_lock_irq(&idle->lock);
771 idle_count = idle->idle_count;
772 spin_unlock_irq(&idle->lock);
773 return sprintf(buf, "%llu\n", idle_count);
774}
775static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL);
776
777static ssize_t show_idle_time(struct sys_device *dev, char *buf)
778{
779 struct s390_idle_data *idle;
780 unsigned long long new_time;
781
782 idle = &per_cpu(s390_idle, dev->id);
783 spin_lock_irq(&idle->lock);
784 if (idle->in_idle) {
785 new_time = get_clock();
786 idle->idle_time += new_time - idle->idle_enter;
787 idle->idle_enter = new_time;
788 }
789 new_time = idle->idle_time;
790 spin_unlock_irq(&idle->lock);
791 return sprintf(buf, "%llu us\n", new_time >> 12);
792}
793static SYSDEV_ATTR(idle_time, 0444, show_idle_time, NULL);
794
795static struct attribute *cpu_attrs[] = {
796 &attr_capability.attr,
797 &attr_idle_count.attr,
798 &attr_idle_time.attr,
799 NULL,
800};
801
802static struct attribute_group cpu_attr_group = {
803 .attrs = cpu_attrs,
804};
805
759static int __cpuinit smp_cpu_notify(struct notifier_block *self, 806static int __cpuinit smp_cpu_notify(struct notifier_block *self,
760 unsigned long action, void *hcpu) 807 unsigned long action, void *hcpu)
761{ 808{
762 unsigned int cpu = (unsigned int)(long)hcpu; 809 unsigned int cpu = (unsigned int)(long)hcpu;
763 struct cpu *c = &per_cpu(cpu_devices, cpu); 810 struct cpu *c = &per_cpu(cpu_devices, cpu);
764 struct sys_device *s = &c->sysdev; 811 struct sys_device *s = &c->sysdev;
812 struct s390_idle_data *idle;
765 813
766 switch (action) { 814 switch (action) {
767 case CPU_ONLINE: 815 case CPU_ONLINE:
768 case CPU_ONLINE_FROZEN: 816 case CPU_ONLINE_FROZEN:
769 if (sysdev_create_file(s, &attr_capability)) 817 idle = &per_cpu(s390_idle, cpu);
818 spin_lock_irq(&idle->lock);
819 idle->idle_enter = 0;
820 idle->idle_time = 0;
821 idle->idle_count = 0;
822 spin_unlock_irq(&idle->lock);
823 if (sysfs_create_group(&s->kobj, &cpu_attr_group))
770 return NOTIFY_BAD; 824 return NOTIFY_BAD;
771 break; 825 break;
772 case CPU_DEAD: 826 case CPU_DEAD:
773 case CPU_DEAD_FROZEN: 827 case CPU_DEAD_FROZEN:
774 sysdev_remove_file(s, &attr_capability); 828 sysfs_remove_group(&s->kobj, &cpu_attr_group);
775 break; 829 break;
776 } 830 }
777 return NOTIFY_OK; 831 return NOTIFY_OK;
@@ -784,6 +838,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = {
784static int __init topology_init(void) 838static int __init topology_init(void)
785{ 839{
786 int cpu; 840 int cpu;
841 int rc;
787 842
788 register_cpu_notifier(&smp_cpu_nb); 843 register_cpu_notifier(&smp_cpu_nb);
789 844
@@ -796,7 +851,9 @@ static int __init topology_init(void)
796 if (!cpu_online(cpu)) 851 if (!cpu_online(cpu))
797 continue; 852 continue;
798 s = &c->sysdev; 853 s = &c->sysdev;
799 sysdev_create_file(s, &attr_capability); 854 rc = sysfs_create_group(&s->kobj, &cpu_attr_group);
855 if (rc)
856 return rc;
800 } 857 }
801 return 0; 858 return 0;
802} 859}
diff --git a/include/asm-s390/cpu.h b/include/asm-s390/cpu.h
new file mode 100644
index 000000000000..352dde194f3c
--- /dev/null
+++ b/include/asm-s390/cpu.h
@@ -0,0 +1,25 @@
1/*
2 * include/asm-s390/cpu.h
3 *
4 * Copyright IBM Corp. 2007
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6 */
7
8#ifndef _ASM_S390_CPU_H_
9#define _ASM_S390_CPU_H_
10
11#include <linux/types.h>
12#include <linux/percpu.h>
13#include <linux/spinlock.h>
14
15struct s390_idle_data {
16 spinlock_t lock;
17 unsigned int in_idle;
18 unsigned long long idle_count;
19 unsigned long long idle_enter;
20 unsigned long long idle_time;
21};
22
23DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
24
25#endif /* _ASM_S390_CPU_H_ */