diff options
author | Felix Beck <felix.beck@de.ibm.com> | 2008-07-14 03:59:08 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:13 -0400 |
commit | fe1372306149d8c8a68d43765e7caea2377003b6 (patch) | |
tree | 4ac98196a8efb5df9583623100406b9c34ee19f9 /drivers/s390 | |
parent | ad211790c040fae3459e9c4c8cbd681ae126d2b8 (diff) |
[S390] ap: Use high-resolution timer for polling
The ap poll mechanism is converted to use a high-resolution timer for
polling. This allows more specific polling. With this a new sysfs
attribute is introduced to specify the polling rate in nanoseconds.
Signed-off-by: Felix Beck <felix.beck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 63 |
1 files changed, 53 insertions, 10 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index a1ab3e3efd11..62b6b55230d0 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -34,13 +34,15 @@ | |||
34 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
35 | #include <asm/s390_rdev.h> | 35 | #include <asm/s390_rdev.h> |
36 | #include <asm/reset.h> | 36 | #include <asm/reset.h> |
37 | #include <linux/hrtimer.h> | ||
38 | #include <linux/ktime.h> | ||
37 | 39 | ||
38 | #include "ap_bus.h" | 40 | #include "ap_bus.h" |
39 | 41 | ||
40 | /* Some prototypes. */ | 42 | /* Some prototypes. */ |
41 | static void ap_scan_bus(struct work_struct *); | 43 | static void ap_scan_bus(struct work_struct *); |
42 | static void ap_poll_all(unsigned long); | 44 | static void ap_poll_all(unsigned long); |
43 | static void ap_poll_timeout(unsigned long); | 45 | static enum hrtimer_restart ap_poll_timeout(struct hrtimer *); |
44 | static int ap_poll_thread_start(void); | 46 | static int ap_poll_thread_start(void); |
45 | static void ap_poll_thread_stop(void); | 47 | static void ap_poll_thread_stop(void); |
46 | static void ap_request_timeout(unsigned long); | 48 | static void ap_request_timeout(unsigned long); |
@@ -80,12 +82,15 @@ static DECLARE_WORK(ap_config_work, ap_scan_bus); | |||
80 | /* | 82 | /* |
81 | * Tasklet & timer for AP request polling. | 83 | * Tasklet & timer for AP request polling. |
82 | */ | 84 | */ |
83 | static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0); | ||
84 | static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0); | 85 | static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0); |
85 | static atomic_t ap_poll_requests = ATOMIC_INIT(0); | 86 | static atomic_t ap_poll_requests = ATOMIC_INIT(0); |
86 | static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); | 87 | static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); |
87 | static struct task_struct *ap_poll_kthread = NULL; | 88 | static struct task_struct *ap_poll_kthread = NULL; |
88 | static DEFINE_MUTEX(ap_poll_thread_mutex); | 89 | static DEFINE_MUTEX(ap_poll_thread_mutex); |
90 | static struct hrtimer ap_poll_timer; | ||
91 | /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. | ||
92 | * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ | ||
93 | static unsigned long long poll_timeout = 250000; | ||
89 | 94 | ||
90 | /** | 95 | /** |
91 | * ap_intructions_available() - Test if AP instructions are available. | 96 | * ap_intructions_available() - Test if AP instructions are available. |
@@ -636,11 +641,39 @@ static ssize_t ap_poll_thread_store(struct bus_type *bus, | |||
636 | 641 | ||
637 | static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store); | 642 | static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store); |
638 | 643 | ||
644 | static ssize_t poll_timeout_show(struct bus_type *bus, char *buf) | ||
645 | { | ||
646 | return snprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout); | ||
647 | } | ||
648 | |||
649 | static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, | ||
650 | size_t count) | ||
651 | { | ||
652 | unsigned long long time; | ||
653 | ktime_t hr_time; | ||
654 | |||
655 | /* 120 seconds = maximum poll interval */ | ||
656 | if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000) | ||
657 | return -EINVAL; | ||
658 | poll_timeout = time; | ||
659 | hr_time = ktime_set(0, poll_timeout); | ||
660 | |||
661 | if (!hrtimer_is_queued(&ap_poll_timer) || | ||
662 | !hrtimer_forward(&ap_poll_timer, ap_poll_timer.expires, hr_time)) { | ||
663 | ap_poll_timer.expires = hr_time; | ||
664 | hrtimer_start(&ap_poll_timer, hr_time, HRTIMER_MODE_ABS); | ||
665 | } | ||
666 | return count; | ||
667 | } | ||
668 | |||
669 | static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); | ||
670 | |||
639 | static struct bus_attribute *const ap_bus_attrs[] = { | 671 | static struct bus_attribute *const ap_bus_attrs[] = { |
640 | &bus_attr_ap_domain, | 672 | &bus_attr_ap_domain, |
641 | &bus_attr_config_time, | 673 | &bus_attr_config_time, |
642 | &bus_attr_poll_thread, | 674 | &bus_attr_poll_thread, |
643 | NULL | 675 | &bus_attr_poll_timeout, |
676 | NULL, | ||
644 | }; | 677 | }; |
645 | 678 | ||
646 | /** | 679 | /** |
@@ -895,9 +928,10 @@ ap_config_timeout(unsigned long ptr) | |||
895 | */ | 928 | */ |
896 | static inline void ap_schedule_poll_timer(void) | 929 | static inline void ap_schedule_poll_timer(void) |
897 | { | 930 | { |
898 | if (timer_pending(&ap_poll_timer)) | 931 | if (hrtimer_is_queued(&ap_poll_timer)) |
899 | return; | 932 | return; |
900 | mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME); | 933 | hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout), |
934 | HRTIMER_MODE_ABS); | ||
901 | } | 935 | } |
902 | 936 | ||
903 | /** | 937 | /** |
@@ -1115,13 +1149,14 @@ EXPORT_SYMBOL(ap_cancel_message); | |||
1115 | 1149 | ||
1116 | /** | 1150 | /** |
1117 | * ap_poll_timeout(): AP receive polling for finished AP requests. | 1151 | * ap_poll_timeout(): AP receive polling for finished AP requests. |
1118 | * @unused: Unused variable. | 1152 | * @unused: Unused pointer. |
1119 | * | 1153 | * |
1120 | * Schedules the AP tasklet. | 1154 | * Schedules the AP tasklet using a high resolution timer. |
1121 | */ | 1155 | */ |
1122 | static void ap_poll_timeout(unsigned long unused) | 1156 | static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) |
1123 | { | 1157 | { |
1124 | tasklet_schedule(&ap_tasklet); | 1158 | tasklet_schedule(&ap_tasklet); |
1159 | return HRTIMER_NORESTART; | ||
1125 | } | 1160 | } |
1126 | 1161 | ||
1127 | /** | 1162 | /** |
@@ -1344,6 +1379,14 @@ int __init ap_module_init(void) | |||
1344 | ap_config_timer.expires = jiffies + ap_config_time * HZ; | 1379 | ap_config_timer.expires = jiffies + ap_config_time * HZ; |
1345 | add_timer(&ap_config_timer); | 1380 | add_timer(&ap_config_timer); |
1346 | 1381 | ||
1382 | /* Setup the high resultion poll timer. | ||
1383 | * If we are running under z/VM adjust polling to z/VM polling rate. | ||
1384 | */ | ||
1385 | if (MACHINE_IS_VM) | ||
1386 | poll_timeout = 1500000; | ||
1387 | hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
1388 | ap_poll_timer.function = ap_poll_timeout; | ||
1389 | |||
1347 | /* Start the low priority AP bus poll thread. */ | 1390 | /* Start the low priority AP bus poll thread. */ |
1348 | if (ap_thread_flag) { | 1391 | if (ap_thread_flag) { |
1349 | rc = ap_poll_thread_start(); | 1392 | rc = ap_poll_thread_start(); |
@@ -1355,7 +1398,7 @@ int __init ap_module_init(void) | |||
1355 | 1398 | ||
1356 | out_work: | 1399 | out_work: |
1357 | del_timer_sync(&ap_config_timer); | 1400 | del_timer_sync(&ap_config_timer); |
1358 | del_timer_sync(&ap_poll_timer); | 1401 | hrtimer_cancel(&ap_poll_timer); |
1359 | destroy_workqueue(ap_work_queue); | 1402 | destroy_workqueue(ap_work_queue); |
1360 | out_root: | 1403 | out_root: |
1361 | s390_root_dev_unregister(ap_root_device); | 1404 | s390_root_dev_unregister(ap_root_device); |
@@ -1386,7 +1429,7 @@ void ap_module_exit(void) | |||
1386 | ap_reset_domain(); | 1429 | ap_reset_domain(); |
1387 | ap_poll_thread_stop(); | 1430 | ap_poll_thread_stop(); |
1388 | del_timer_sync(&ap_config_timer); | 1431 | del_timer_sync(&ap_config_timer); |
1389 | del_timer_sync(&ap_poll_timer); | 1432 | hrtimer_cancel(&ap_poll_timer); |
1390 | destroy_workqueue(ap_work_queue); | 1433 | destroy_workqueue(ap_work_queue); |
1391 | tasklet_kill(&ap_tasklet); | 1434 | tasklet_kill(&ap_tasklet); |
1392 | s390_root_dev_unregister(ap_root_device); | 1435 | s390_root_dev_unregister(ap_root_device); |