aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/appldata
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2012-07-20 05:15:08 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-07-20 05:15:08 -0400
commit27f6b416626a240e1b46f646d2e0c5266f4eac95 (patch)
tree4549855d7996ce9d18e1586e2f0bfb5fa5835718 /arch/s390/appldata
parent921486b92bcb1b82ab6668dcbb36d05604966351 (diff)
s390/vtimer: rework virtual timer interface
The current virtual timer interface is inherently per-cpu and hard to use. The sole user of the interface is appldata which uses it to execute a function after a specific amount of cputime has been used over all cpus. Rework the virtual timer interface to hook into the cputime accounting. This makes the interface independent from the CPU timer interrupts, and makes the virtual timers global as opposed to per-cpu. Overall the code is greatly simplified. The downside is that the accuracy is not as good as the original implementation, but it is still good enough for appldata. Reviewed-by: Jan Glauber <jang@linux.vnet.ibm.com> Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/appldata')
-rw-r--r--arch/s390/appldata/appldata_base.c130
1 files changed, 14 insertions, 116 deletions
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index fadefce09962..bae0f402bf2a 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -27,7 +27,7 @@
27#include <linux/suspend.h> 27#include <linux/suspend.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <asm/appldata.h> 29#include <asm/appldata.h>
30#include <asm/timer.h> 30#include <asm/vtimer.h>
31#include <asm/uaccess.h> 31#include <asm/uaccess.h>
32#include <asm/io.h> 32#include <asm/io.h>
33#include <asm/smp.h> 33#include <asm/smp.h>
@@ -82,8 +82,7 @@ static struct ctl_table appldata_dir_table[] = {
82/* 82/*
83 * Timer 83 * Timer
84 */ 84 */
85static DEFINE_PER_CPU(struct vtimer_list, appldata_timer); 85static struct vtimer_list appldata_timer;
86static atomic_t appldata_expire_count = ATOMIC_INIT(0);
87 86
88static DEFINE_SPINLOCK(appldata_timer_lock); 87static DEFINE_SPINLOCK(appldata_timer_lock);
89static int appldata_interval = APPLDATA_CPU_INTERVAL; 88static int appldata_interval = APPLDATA_CPU_INTERVAL;
@@ -113,10 +112,7 @@ static LIST_HEAD(appldata_ops_list);
113 */ 112 */
114static void appldata_timer_function(unsigned long data) 113static void appldata_timer_function(unsigned long data)
115{ 114{
116 if (atomic_dec_and_test(&appldata_expire_count)) { 115 queue_work(appldata_wq, (struct work_struct *) data);
117 atomic_set(&appldata_expire_count, num_online_cpus());
118 queue_work(appldata_wq, (struct work_struct *) data);
119 }
120} 116}
121 117
122/* 118/*
@@ -129,7 +125,6 @@ static void appldata_work_fn(struct work_struct *work)
129 struct list_head *lh; 125 struct list_head *lh;
130 struct appldata_ops *ops; 126 struct appldata_ops *ops;
131 127
132 get_online_cpus();
133 mutex_lock(&appldata_ops_mutex); 128 mutex_lock(&appldata_ops_mutex);
134 list_for_each(lh, &appldata_ops_list) { 129 list_for_each(lh, &appldata_ops_list) {
135 ops = list_entry(lh, struct appldata_ops, list); 130 ops = list_entry(lh, struct appldata_ops, list);
@@ -138,7 +133,6 @@ static void appldata_work_fn(struct work_struct *work)
138 } 133 }
139 } 134 }
140 mutex_unlock(&appldata_ops_mutex); 135 mutex_unlock(&appldata_ops_mutex);
141 put_online_cpus();
142} 136}
143 137
144/* 138/*
@@ -166,20 +160,6 @@ int appldata_diag(char record_nr, u16 function, unsigned long buffer,
166 160
167/****************************** /proc stuff **********************************/ 161/****************************** /proc stuff **********************************/
168 162
169/*
170 * appldata_mod_vtimer_wrap()
171 *
172 * wrapper function for mod_virt_timer(), because smp_call_function_single()
173 * accepts only one parameter.
174 */
175static void __appldata_mod_vtimer_wrap(void *p) {
176 struct {
177 struct vtimer_list *timer;
178 u64 expires;
179 } *args = p;
180 mod_virt_timer_periodic(args->timer, args->expires);
181}
182
183#define APPLDATA_ADD_TIMER 0 163#define APPLDATA_ADD_TIMER 0
184#define APPLDATA_DEL_TIMER 1 164#define APPLDATA_DEL_TIMER 1
185#define APPLDATA_MOD_TIMER 2 165#define APPLDATA_MOD_TIMER 2
@@ -190,49 +170,28 @@ static void __appldata_mod_vtimer_wrap(void *p) {
190 * Add, delete or modify virtual timers on all online cpus. 170 * Add, delete or modify virtual timers on all online cpus.
191 * The caller needs to get the appldata_timer_lock spinlock. 171 * The caller needs to get the appldata_timer_lock spinlock.
192 */ 172 */
193static void 173static void __appldata_vtimer_setup(int cmd)
194__appldata_vtimer_setup(int cmd)
195{ 174{
196 u64 per_cpu_interval; 175 u64 timer_interval = (u64) appldata_interval * 1000 * TOD_MICRO;
197 int i;
198 176
199 switch (cmd) { 177 switch (cmd) {
200 case APPLDATA_ADD_TIMER: 178 case APPLDATA_ADD_TIMER:
201 if (appldata_timer_active) 179 if (appldata_timer_active)
202 break; 180 break;
203 per_cpu_interval = (u64) (appldata_interval*1000 / 181 appldata_timer.expires = timer_interval;
204 num_online_cpus()) * TOD_MICRO; 182 add_virt_timer_periodic(&appldata_timer);
205 for_each_online_cpu(i) {
206 per_cpu(appldata_timer, i).expires = per_cpu_interval;
207 smp_call_function_single(i, add_virt_timer_periodic,
208 &per_cpu(appldata_timer, i),
209 1);
210 }
211 appldata_timer_active = 1; 183 appldata_timer_active = 1;
212 break; 184 break;
213 case APPLDATA_DEL_TIMER: 185 case APPLDATA_DEL_TIMER:
214 for_each_online_cpu(i) 186 del_virt_timer(&appldata_timer);
215 del_virt_timer(&per_cpu(appldata_timer, i));
216 if (!appldata_timer_active) 187 if (!appldata_timer_active)
217 break; 188 break;
218 appldata_timer_active = 0; 189 appldata_timer_active = 0;
219 atomic_set(&appldata_expire_count, num_online_cpus());
220 break; 190 break;
221 case APPLDATA_MOD_TIMER: 191 case APPLDATA_MOD_TIMER:
222 per_cpu_interval = (u64) (appldata_interval*1000 /
223 num_online_cpus()) * TOD_MICRO;
224 if (!appldata_timer_active) 192 if (!appldata_timer_active)
225 break; 193 break;
226 for_each_online_cpu(i) { 194 mod_virt_timer_periodic(&appldata_timer, timer_interval);
227 struct {
228 struct vtimer_list *timer;
229 u64 expires;
230 } args;
231 args.timer = &per_cpu(appldata_timer, i);
232 args.expires = per_cpu_interval;
233 smp_call_function_single(i, __appldata_mod_vtimer_wrap,
234 &args, 1);
235 }
236 } 195 }
237} 196}
238 197
@@ -263,14 +222,12 @@ appldata_timer_handler(ctl_table *ctl, int write,
263 len = *lenp; 222 len = *lenp;
264 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) 223 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
265 return -EFAULT; 224 return -EFAULT;
266 get_online_cpus();
267 spin_lock(&appldata_timer_lock); 225 spin_lock(&appldata_timer_lock);
268 if (buf[0] == '1') 226 if (buf[0] == '1')
269 __appldata_vtimer_setup(APPLDATA_ADD_TIMER); 227 __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
270 else if (buf[0] == '0') 228 else if (buf[0] == '0')
271 __appldata_vtimer_setup(APPLDATA_DEL_TIMER); 229 __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
272 spin_unlock(&appldata_timer_lock); 230 spin_unlock(&appldata_timer_lock);
273 put_online_cpus();
274out: 231out:
275 *lenp = len; 232 *lenp = len;
276 *ppos += len; 233 *ppos += len;
@@ -303,20 +260,17 @@ appldata_interval_handler(ctl_table *ctl, int write,
303 goto out; 260 goto out;
304 } 261 }
305 len = *lenp; 262 len = *lenp;
306 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) { 263 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
307 return -EFAULT; 264 return -EFAULT;
308 }
309 interval = 0; 265 interval = 0;
310 sscanf(buf, "%i", &interval); 266 sscanf(buf, "%i", &interval);
311 if (interval <= 0) 267 if (interval <= 0)
312 return -EINVAL; 268 return -EINVAL;
313 269
314 get_online_cpus();
315 spin_lock(&appldata_timer_lock); 270 spin_lock(&appldata_timer_lock);
316 appldata_interval = interval; 271 appldata_interval = interval;
317 __appldata_vtimer_setup(APPLDATA_MOD_TIMER); 272 __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
318 spin_unlock(&appldata_timer_lock); 273 spin_unlock(&appldata_timer_lock);
319 put_online_cpus();
320out: 274out:
321 *lenp = len; 275 *lenp = len;
322 *ppos += len; 276 *ppos += len;
@@ -483,14 +437,12 @@ static int appldata_freeze(struct device *dev)
483 int rc; 437 int rc;
484 struct list_head *lh; 438 struct list_head *lh;
485 439
486 get_online_cpus();
487 spin_lock(&appldata_timer_lock); 440 spin_lock(&appldata_timer_lock);
488 if (appldata_timer_active) { 441 if (appldata_timer_active) {
489 __appldata_vtimer_setup(APPLDATA_DEL_TIMER); 442 __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
490 appldata_timer_suspended = 1; 443 appldata_timer_suspended = 1;
491 } 444 }
492 spin_unlock(&appldata_timer_lock); 445 spin_unlock(&appldata_timer_lock);
493 put_online_cpus();
494 446
495 mutex_lock(&appldata_ops_mutex); 447 mutex_lock(&appldata_ops_mutex);
496 list_for_each(lh, &appldata_ops_list) { 448 list_for_each(lh, &appldata_ops_list) {
@@ -514,14 +466,12 @@ static int appldata_restore(struct device *dev)
514 int rc; 466 int rc;
515 struct list_head *lh; 467 struct list_head *lh;
516 468
517 get_online_cpus();
518 spin_lock(&appldata_timer_lock); 469 spin_lock(&appldata_timer_lock);
519 if (appldata_timer_suspended) { 470 if (appldata_timer_suspended) {
520 __appldata_vtimer_setup(APPLDATA_ADD_TIMER); 471 __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
521 appldata_timer_suspended = 0; 472 appldata_timer_suspended = 0;
522 } 473 }
523 spin_unlock(&appldata_timer_lock); 474 spin_unlock(&appldata_timer_lock);
524 put_online_cpus();
525 475
526 mutex_lock(&appldata_ops_mutex); 476 mutex_lock(&appldata_ops_mutex);
527 list_for_each(lh, &appldata_ops_list) { 477 list_for_each(lh, &appldata_ops_list) {
@@ -565,53 +515,6 @@ static struct platform_driver appldata_pdrv = {
565 515
566/******************************* init / exit *********************************/ 516/******************************* init / exit *********************************/
567 517
568static void __cpuinit appldata_online_cpu(int cpu)
569{
570 init_virt_timer(&per_cpu(appldata_timer, cpu));
571 per_cpu(appldata_timer, cpu).function = appldata_timer_function;
572 per_cpu(appldata_timer, cpu).data = (unsigned long)
573 &appldata_work;
574 atomic_inc(&appldata_expire_count);
575 spin_lock(&appldata_timer_lock);
576 __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
577 spin_unlock(&appldata_timer_lock);
578}
579
580static void __cpuinit appldata_offline_cpu(int cpu)
581{
582 del_virt_timer(&per_cpu(appldata_timer, cpu));
583 if (atomic_dec_and_test(&appldata_expire_count)) {
584 atomic_set(&appldata_expire_count, num_online_cpus());
585 queue_work(appldata_wq, &appldata_work);
586 }
587 spin_lock(&appldata_timer_lock);
588 __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
589 spin_unlock(&appldata_timer_lock);
590}
591
592static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
593 unsigned long action,
594 void *hcpu)
595{
596 switch (action) {
597 case CPU_ONLINE:
598 case CPU_ONLINE_FROZEN:
599 appldata_online_cpu((long) hcpu);
600 break;
601 case CPU_DEAD:
602 case CPU_DEAD_FROZEN:
603 appldata_offline_cpu((long) hcpu);
604 break;
605 default:
606 break;
607 }
608 return NOTIFY_OK;
609}
610
611static struct notifier_block __cpuinitdata appldata_nb = {
612 .notifier_call = appldata_cpu_notify,
613};
614
615/* 518/*
616 * appldata_init() 519 * appldata_init()
617 * 520 *
@@ -619,7 +522,10 @@ static struct notifier_block __cpuinitdata appldata_nb = {
619 */ 522 */
620static int __init appldata_init(void) 523static int __init appldata_init(void)
621{ 524{
622 int i, rc; 525 int rc;
526
527 appldata_timer.function = appldata_timer_function;
528 appldata_timer.data = (unsigned long) &appldata_work;
623 529
624 rc = platform_driver_register(&appldata_pdrv); 530 rc = platform_driver_register(&appldata_pdrv);
625 if (rc) 531 if (rc)
@@ -637,14 +543,6 @@ static int __init appldata_init(void)
637 goto out_device; 543 goto out_device;
638 } 544 }
639 545
640 get_online_cpus();
641 for_each_online_cpu(i)
642 appldata_online_cpu(i);
643 put_online_cpus();
644
645 /* Register cpu hotplug notifier */
646 register_hotcpu_notifier(&appldata_nb);
647
648 appldata_sysctl_header = register_sysctl_table(appldata_dir_table); 546 appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
649 return 0; 547 return 0;
650 548