aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFelix Beck <felix.beck@de.ibm.com>2008-12-25 07:38:41 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-12-25 07:38:57 -0500
commitcb17a6364a29b4dfe5bbb00696032fb63d780157 (patch)
tree9bd2d71b6bc80188f3ff1eac9deeacad96b8124f /drivers
parent320c04c068c62b71fe9ea55e06e4968b4edc9e48 (diff)
[S390] zcrypt: Use of Thin Interrupts
When the machine supports AP adapter interrupts polling will be switched off at module initialization and the driver will work in interrupt mode. Signed-off-by: Felix Beck <felix.beck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/crypto/ap_bus.c174
-rw-r--r--drivers/s390/crypto/ap_bus.h6
2 files changed, 176 insertions, 4 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index e3fe6838293a..2335be5f9bf7 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -5,6 +5,7 @@
5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6 * Martin Schwidefsky <schwidefsky@de.ibm.com> 6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Ralph Wuerthner <rwuerthn@de.ibm.com> 7 * Ralph Wuerthner <rwuerthn@de.ibm.com>
8 * Felix Beck <felix.beck@de.ibm.com>
8 * 9 *
9 * Adjunct processor bus. 10 * Adjunct processor bus.
10 * 11 *
@@ -34,6 +35,10 @@
34#include <linux/mutex.h> 35#include <linux/mutex.h>
35#include <asm/s390_rdev.h> 36#include <asm/s390_rdev.h>
36#include <asm/reset.h> 37#include <asm/reset.h>
38#include <asm/airq.h>
39#include <asm/atomic.h>
40#include <asm/system.h>
41#include <asm/isc.h>
37#include <linux/hrtimer.h> 42#include <linux/hrtimer.h>
38#include <linux/ktime.h> 43#include <linux/ktime.h>
39 44
@@ -46,6 +51,7 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *);
46static int ap_poll_thread_start(void); 51static int ap_poll_thread_start(void);
47static void ap_poll_thread_stop(void); 52static void ap_poll_thread_stop(void);
48static void ap_request_timeout(unsigned long); 53static void ap_request_timeout(unsigned long);
54static inline void ap_schedule_poll_timer(void);
49 55
50/* 56/*
51 * Module description. 57 * Module description.
@@ -80,19 +86,29 @@ static int ap_config_time = AP_CONFIG_TIME;
80static DECLARE_WORK(ap_config_work, ap_scan_bus); 86static DECLARE_WORK(ap_config_work, ap_scan_bus);
81 87
82/* 88/*
83 * Tasklet & timer for AP request polling. 89 * Tasklet & timer for AP request polling and interrupts
84 */ 90 */
85static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0); 91static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0);
86static atomic_t ap_poll_requests = ATOMIC_INIT(0); 92static atomic_t ap_poll_requests = ATOMIC_INIT(0);
87static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); 93static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
88static struct task_struct *ap_poll_kthread = NULL; 94static struct task_struct *ap_poll_kthread = NULL;
89static DEFINE_MUTEX(ap_poll_thread_mutex); 95static DEFINE_MUTEX(ap_poll_thread_mutex);
96static void *ap_interrupt_indicator;
90static struct hrtimer ap_poll_timer; 97static struct hrtimer ap_poll_timer;
91/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. 98/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds.
92 * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ 99 * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
93static unsigned long long poll_timeout = 250000; 100static unsigned long long poll_timeout = 250000;
94 101
95/** 102/**
103 * ap_using_interrupts() - Returns non-zero if interrupt support is
104 * available.
105 */
106static inline int ap_using_interrupts(void)
107{
108 return ap_interrupt_indicator != NULL;
109}
110
111/**
96 * ap_intructions_available() - Test if AP instructions are available. 112 * ap_intructions_available() - Test if AP instructions are available.
97 * 113 *
98 * Returns 0 if the AP instructions are installed. 114 * Returns 0 if the AP instructions are installed.
@@ -113,6 +129,23 @@ static inline int ap_instructions_available(void)
113} 129}
114 130
115/** 131/**
132 * ap_interrupts_available(): Test if AP interrupts are available.
133 *
134 * Returns 1 if AP interrupts are available.
135 */
136static int ap_interrupts_available(void)
137{
138 unsigned long long facility_bits[2];
139
140 if (stfle(facility_bits, 2) <= 1)
141 return 0;
142 if (!(facility_bits[0] & (1ULL << 61)) ||
143 !(facility_bits[1] & (1ULL << 62)))
144 return 0;
145 return 1;
146}
147
148/**
116 * ap_test_queue(): Test adjunct processor queue. 149 * ap_test_queue(): Test adjunct processor queue.
117 * @qid: The AP queue number 150 * @qid: The AP queue number
118 * @queue_depth: Pointer to queue depth value 151 * @queue_depth: Pointer to queue depth value
@@ -152,6 +185,80 @@ static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid)
152 return reg1; 185 return reg1;
153} 186}
154 187
188#ifdef CONFIG_64BIT
189/**
190 * ap_queue_interruption_control(): Enable interruption for a specific AP.
191 * @qid: The AP queue number
192 * @ind: The notification indicator byte
193 *
194 * Returns AP queue status.
195 */
196static inline struct ap_queue_status
197ap_queue_interruption_control(ap_qid_t qid, void *ind)
198{
199 register unsigned long reg0 asm ("0") = qid | 0x03000000UL;
200 register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC;
201 register struct ap_queue_status reg1_out asm ("1");
202 register void *reg2 asm ("2") = ind;
203 asm volatile(
204 ".long 0xb2af0000" /* PQAP(RAPQ) */
205 : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2)
206 :
207 : "cc" );
208 return reg1_out;
209}
210#endif
211
212/**
213 * ap_queue_enable_interruption(): Enable interruption on an AP.
214 * @qid: The AP queue number
215 * @ind: the notification indicator byte
216 *
217 * Enables interruption on AP queue via ap_queue_interruption_control(). Based
218 * on the return value it waits a while and tests the AP queue if interrupts
219 * have been switched on using ap_test_queue().
220 */
221static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
222{
223#ifdef CONFIG_64BIT
224 struct ap_queue_status status;
225 int t_depth, t_device_type, rc, i;
226
227 rc = -EBUSY;
228 status = ap_queue_interruption_control(qid, ind);
229
230 for (i = 0; i < AP_MAX_RESET; i++) {
231 switch (status.response_code) {
232 case AP_RESPONSE_NORMAL:
233 if (status.int_enabled)
234 return 0;
235 break;
236 case AP_RESPONSE_RESET_IN_PROGRESS:
237 case AP_RESPONSE_BUSY:
238 break;
239 case AP_RESPONSE_Q_NOT_AVAIL:
240 case AP_RESPONSE_DECONFIGURED:
241 case AP_RESPONSE_CHECKSTOPPED:
242 case AP_RESPONSE_INVALID_ADDRESS:
243 return -ENODEV;
244 case AP_RESPONSE_OTHERWISE_CHANGED:
245 if (status.int_enabled)
246 return 0;
247 break;
248 default:
249 break;
250 }
251 if (i < AP_MAX_RESET - 1) {
252 udelay(5);
253 status = ap_test_queue(qid, &t_depth, &t_device_type);
254 }
255 }
256 return rc;
257#else
258 return -EINVAL;
259#endif
260}
261
155/** 262/**
156 * __ap_send(): Send message to adjunct processor queue. 263 * __ap_send(): Send message to adjunct processor queue.
157 * @qid: The AP queue number 264 * @qid: The AP queue number
@@ -295,6 +402,11 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type)
295 case AP_RESPONSE_CHECKSTOPPED: 402 case AP_RESPONSE_CHECKSTOPPED:
296 rc = -ENODEV; 403 rc = -ENODEV;
297 break; 404 break;
405 case AP_RESPONSE_INVALID_ADDRESS:
406 rc = -ENODEV;
407 break;
408 case AP_RESPONSE_OTHERWISE_CHANGED:
409 break;
298 case AP_RESPONSE_BUSY: 410 case AP_RESPONSE_BUSY:
299 break; 411 break;
300 default: 412 default:
@@ -345,6 +457,15 @@ static int ap_init_queue(ap_qid_t qid)
345 status = ap_test_queue(qid, &dummy, &dummy); 457 status = ap_test_queue(qid, &dummy, &dummy);
346 } 458 }
347 } 459 }
460 if (rc == 0 && ap_using_interrupts()) {
461 rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator);
462 /* If interruption mode is supported by the machine,
463 * but an AP can not be enabled for interruption then
464 * the AP will be discarded. */
465 if (rc)
466 pr_err("Registering adapter interrupts for "
467 "AP %d failed\n", AP_QID_DEVICE(qid));
468 }
348 return rc; 469 return rc;
349} 470}
350 471
@@ -599,6 +720,14 @@ static ssize_t ap_config_time_show(struct bus_type *bus, char *buf)
599 return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); 720 return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
600} 721}
601 722
723static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)
724{
725 return snprintf(buf, PAGE_SIZE, "%d\n",
726 ap_using_interrupts() ? 1 : 0);
727}
728
729static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL);
730
602static ssize_t ap_config_time_store(struct bus_type *bus, 731static ssize_t ap_config_time_store(struct bus_type *bus,
603 const char *buf, size_t count) 732 const char *buf, size_t count)
604{ 733{
@@ -653,7 +782,8 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
653 ktime_t hr_time; 782 ktime_t hr_time;
654 783
655 /* 120 seconds = maximum poll interval */ 784 /* 120 seconds = maximum poll interval */
656 if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000) 785 if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 ||
786 time > 120000000000ULL)
657 return -EINVAL; 787 return -EINVAL;
658 poll_timeout = time; 788 poll_timeout = time;
659 hr_time = ktime_set(0, poll_timeout); 789 hr_time = ktime_set(0, poll_timeout);
@@ -672,6 +802,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
672 &bus_attr_ap_domain, 802 &bus_attr_ap_domain,
673 &bus_attr_config_time, 803 &bus_attr_config_time,
674 &bus_attr_poll_thread, 804 &bus_attr_poll_thread,
805 &bus_attr_ap_interrupts,
675 &bus_attr_poll_timeout, 806 &bus_attr_poll_timeout,
676 NULL, 807 NULL,
677}; 808};
@@ -814,6 +945,11 @@ out:
814 return rc; 945 return rc;
815} 946}
816 947
948static void ap_interrupt_handler(void *unused1, void *unused2)
949{
950 tasklet_schedule(&ap_tasklet);
951}
952
817/** 953/**
818 * __ap_scan_bus(): Scan the AP bus. 954 * __ap_scan_bus(): Scan the AP bus.
819 * @dev: Pointer to device 955 * @dev: Pointer to device
@@ -928,6 +1064,8 @@ ap_config_timeout(unsigned long ptr)
928 */ 1064 */
929static inline void ap_schedule_poll_timer(void) 1065static inline void ap_schedule_poll_timer(void)
930{ 1066{
1067 if (ap_using_interrupts())
1068 return;
931 if (hrtimer_is_queued(&ap_poll_timer)) 1069 if (hrtimer_is_queued(&ap_poll_timer))
932 return; 1070 return;
933 hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout), 1071 hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout),
@@ -1207,6 +1345,12 @@ static void ap_poll_all(unsigned long dummy)
1207 unsigned long flags; 1345 unsigned long flags;
1208 struct ap_device *ap_dev; 1346 struct ap_device *ap_dev;
1209 1347
1348 /* Reset the indicator if interrupts are used. Thus new interrupts can
1349 * be received. Doing it in the beginning of the tasklet is therefor
1350 * important that no requests on any AP get lost.
1351 */
1352 if (ap_using_interrupts())
1353 xchg((u8 *)ap_interrupt_indicator, 0);
1210 do { 1354 do {
1211 flags = 0; 1355 flags = 0;
1212 spin_lock(&ap_device_lock); 1356 spin_lock(&ap_device_lock);
@@ -1268,6 +1412,8 @@ static int ap_poll_thread_start(void)
1268{ 1412{
1269 int rc; 1413 int rc;
1270 1414
1415 if (ap_using_interrupts())
1416 return 0;
1271 mutex_lock(&ap_poll_thread_mutex); 1417 mutex_lock(&ap_poll_thread_mutex);
1272 if (!ap_poll_kthread) { 1418 if (!ap_poll_kthread) {
1273 ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); 1419 ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");
@@ -1301,8 +1447,12 @@ static void ap_request_timeout(unsigned long data)
1301{ 1447{
1302 struct ap_device *ap_dev = (struct ap_device *) data; 1448 struct ap_device *ap_dev = (struct ap_device *) data;
1303 1449
1304 if (ap_dev->reset == AP_RESET_ARMED) 1450 if (ap_dev->reset == AP_RESET_ARMED) {
1305 ap_dev->reset = AP_RESET_DO; 1451 ap_dev->reset = AP_RESET_DO;
1452
1453 if (ap_using_interrupts())
1454 tasklet_schedule(&ap_tasklet);
1455 }
1306} 1456}
1307 1457
1308static void ap_reset_domain(void) 1458static void ap_reset_domain(void)
@@ -1345,6 +1495,16 @@ int __init ap_module_init(void)
1345 printk(KERN_WARNING "AP instructions not installed.\n"); 1495 printk(KERN_WARNING "AP instructions not installed.\n");
1346 return -ENODEV; 1496 return -ENODEV;
1347 } 1497 }
1498 if (ap_interrupts_available()) {
1499 isc_register(AP_ISC);
1500 ap_interrupt_indicator = s390_register_adapter_interrupt(
1501 &ap_interrupt_handler, NULL, AP_ISC);
1502 if (IS_ERR(ap_interrupt_indicator)) {
1503 ap_interrupt_indicator = NULL;
1504 isc_unregister(AP_ISC);
1505 }
1506 }
1507
1348 register_reset_call(&ap_reset_call); 1508 register_reset_call(&ap_reset_call);
1349 1509
1350 /* Create /sys/bus/ap. */ 1510 /* Create /sys/bus/ap. */
@@ -1408,6 +1568,10 @@ out_bus:
1408 bus_unregister(&ap_bus_type); 1568 bus_unregister(&ap_bus_type);
1409out: 1569out:
1410 unregister_reset_call(&ap_reset_call); 1570 unregister_reset_call(&ap_reset_call);
1571 if (ap_using_interrupts()) {
1572 s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
1573 isc_unregister(AP_ISC);
1574 }
1411 return rc; 1575 return rc;
1412} 1576}
1413 1577
@@ -1443,6 +1607,10 @@ void ap_module_exit(void)
1443 bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); 1607 bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
1444 bus_unregister(&ap_bus_type); 1608 bus_unregister(&ap_bus_type);
1445 unregister_reset_call(&ap_reset_call); 1609 unregister_reset_call(&ap_reset_call);
1610 if (ap_using_interrupts()) {
1611 s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
1612 isc_unregister(AP_ISC);
1613 }
1446} 1614}
1447 1615
1448#ifndef CONFIG_ZCRYPT_MONOLITHIC 1616#ifndef CONFIG_ZCRYPT_MONOLITHIC
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 446378b308fc..a35362241805 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -5,6 +5,7 @@
5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6 * Martin Schwidefsky <schwidefsky@de.ibm.com> 6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Ralph Wuerthner <rwuerthn@de.ibm.com> 7 * Ralph Wuerthner <rwuerthn@de.ibm.com>
8 * Felix Beck <felix.beck@de.ibm.com>
8 * 9 *
9 * Adjunct processor bus header file. 10 * Adjunct processor bus header file.
10 * 11 *
@@ -67,7 +68,8 @@ struct ap_queue_status {
67 unsigned int queue_empty : 1; 68 unsigned int queue_empty : 1;
68 unsigned int replies_waiting : 1; 69 unsigned int replies_waiting : 1;
69 unsigned int queue_full : 1; 70 unsigned int queue_full : 1;
70 unsigned int pad1 : 5; 71 unsigned int pad1 : 4;
72 unsigned int int_enabled : 1;
71 unsigned int response_code : 8; 73 unsigned int response_code : 8;
72 unsigned int pad2 : 16; 74 unsigned int pad2 : 16;
73}; 75};
@@ -78,6 +80,8 @@ struct ap_queue_status {
78#define AP_RESPONSE_DECONFIGURED 0x03 80#define AP_RESPONSE_DECONFIGURED 0x03
79#define AP_RESPONSE_CHECKSTOPPED 0x04 81#define AP_RESPONSE_CHECKSTOPPED 0x04
80#define AP_RESPONSE_BUSY 0x05 82#define AP_RESPONSE_BUSY 0x05
83#define AP_RESPONSE_INVALID_ADDRESS 0x06
84#define AP_RESPONSE_OTHERWISE_CHANGED 0x07
81#define AP_RESPONSE_Q_FULL 0x10 85#define AP_RESPONSE_Q_FULL 0x10
82#define AP_RESPONSE_NO_PENDING_REPLY 0x10 86#define AP_RESPONSE_NO_PENDING_REPLY 0x10
83#define AP_RESPONSE_INDEX_TOO_BIG 0x11 87#define AP_RESPONSE_INDEX_TOO_BIG 0x11