diff options
Diffstat (limited to 'arch/s390/appldata/appldata_base.c')
-rw-r--r-- | arch/s390/appldata/appldata_base.c | 130 |
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 | */ |
85 | static DEFINE_PER_CPU(struct vtimer_list, appldata_timer); | 85 | static struct vtimer_list appldata_timer; |
86 | static atomic_t appldata_expire_count = ATOMIC_INIT(0); | ||
87 | 86 | ||
88 | static DEFINE_SPINLOCK(appldata_timer_lock); | 87 | static DEFINE_SPINLOCK(appldata_timer_lock); |
89 | static int appldata_interval = APPLDATA_CPU_INTERVAL; | 88 | static int appldata_interval = APPLDATA_CPU_INTERVAL; |
@@ -113,10 +112,7 @@ static LIST_HEAD(appldata_ops_list); | |||
113 | */ | 112 | */ |
114 | static void appldata_timer_function(unsigned long data) | 113 | static 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 | */ | ||
175 | static 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 | */ |
193 | static void | 173 | static 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(); | ||
274 | out: | 231 | out: |
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(); | ||
320 | out: | 274 | out: |
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 | ||
568 | static 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 | |||
580 | static 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 | |||
592 | static 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 | |||
611 | static 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 | */ |
620 | static int __init appldata_init(void) | 523 | static 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 | ||