diff options
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 1294876bf7b4..20836eff88c5 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -102,6 +102,7 @@ static atomic_t ap_poll_requests = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread = NULL; static DEFINE_MUTEX(ap_poll_thread_mutex); +static DEFINE_SPINLOCK(ap_poll_timer_lock); static void *ap_interrupt_indicator; static struct hrtimer ap_poll_timer; /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. @@ -282,6 +283,7 @@ static int ap_queue_enable_interruption(ap_qid_t qid, void *ind) * @psmid: The program supplied message identifier * @msg: The message text * @length: The message length + * @special: Special Bit * * Returns AP queue status structure. * Condition code 1 on NQAP can't happen because the L bit is 1. @@ -289,7 +291,8 @@ static int ap_queue_enable_interruption(ap_qid_t qid, void *ind) * because a segment boundary was reached. The NQAP is repeated. */ static inline struct ap_queue_status -__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) +__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, + unsigned int special) { typedef struct { char _[length]; } msgblock; register unsigned long reg0 asm ("0") = qid | 0x40000000UL; @@ -299,6 +302,9 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); register unsigned long reg5 asm ("5") = (unsigned int) psmid; + if (special == 1) + reg0 |= 0x400000UL; + asm volatile ( "0: .long 0xb2ad0042\n" /* DQAP */ " brc 2,0b" @@ -312,13 +318,15 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) { struct ap_queue_status status; - status = __ap_send(qid, psmid, msg, length); + status = __ap_send(qid, psmid, msg, length, 0); switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; case AP_RESPONSE_Q_FULL: case AP_RESPONSE_RESET_IN_PROGRESS: return -EBUSY; + case AP_RESPONSE_REQ_FAC_NOT_INST: + return -EINVAL; default: /* Device is gone. */ return -ENODEV; } @@ -1008,7 +1016,7 @@ static int ap_probe_device_type(struct ap_device *ap_dev) } status = __ap_send(ap_dev->qid, 0x0102030405060708ULL, - msg, sizeof(msg)); + msg, sizeof(msg), 0); if (status.response_code != AP_RESPONSE_NORMAL) { rc = -ENODEV; goto out_free; @@ -1163,16 +1171,19 @@ ap_config_timeout(unsigned long ptr) static inline void ap_schedule_poll_timer(void) { ktime_t hr_time; + + spin_lock_bh(&ap_poll_timer_lock); if (ap_using_interrupts() || ap_suspend_flag) - return; + goto out; if (hrtimer_is_queued(&ap_poll_timer)) - return; + goto out; if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) { hr_time = ktime_set(0, poll_timeout); hrtimer_forward_now(&ap_poll_timer, hr_time); hrtimer_restart(&ap_poll_timer); } - return; +out: + spin_unlock_bh(&ap_poll_timer_lock); } /** @@ -1243,7 +1254,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) /* Start the next request on the queue. */ ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list); status = __ap_send(ap_dev->qid, ap_msg->psmid, - ap_msg->message, ap_msg->length); + ap_msg->message, ap_msg->length, ap_msg->special); switch (status.response_code) { case AP_RESPONSE_NORMAL: atomic_inc(&ap_poll_requests); @@ -1261,6 +1272,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) *flags |= 2; break; case AP_RESPONSE_MESSAGE_TOO_BIG: + case AP_RESPONSE_REQ_FAC_NOT_INST: return -EINVAL; default: return -ENODEV; @@ -1302,7 +1314,8 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms if (list_empty(&ap_dev->requestq) && ap_dev->queue_count < ap_dev->queue_depth) { status = __ap_send(ap_dev->qid, ap_msg->psmid, - ap_msg->message, ap_msg->length); + ap_msg->message, ap_msg->length, + ap_msg->special); switch (status.response_code) { case AP_RESPONSE_NORMAL: list_add_tail(&ap_msg->list, &ap_dev->pendingq); @@ -1317,6 +1330,7 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms ap_dev->requestq_count++; ap_dev->total_request_count++; return -EBUSY; + case AP_RESPONSE_REQ_FAC_NOT_INST: case AP_RESPONSE_MESSAGE_TOO_BIG: ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL)); return -EINVAL; @@ -1658,6 +1672,7 @@ int __init ap_module_init(void) */ if (MACHINE_IS_VM) poll_timeout = 1500000; + spin_lock_init(&ap_poll_timer_lock); hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ap_poll_timer.function = ap_poll_timeout; |