summaryrefslogtreecommitdiff
path: root/drivers/s390/crypto/ap_queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto/ap_queue.c')
-rw-r--r--drivers/s390/crypto/ap_queue.c126
1 files changed, 104 insertions, 22 deletions
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
index 1f647ffd6f4d..4a32c1e19a1e 100644
--- a/drivers/s390/crypto/ap_queue.c
+++ b/drivers/s390/crypto/ap_queue.c
@@ -6,22 +6,33 @@
* Adjunct processor bus, queue related code.
*/
-#define KMSG_COMPONENT "ap"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#define pr_fmt(fmt) "ap: " fmt
+#include <linux/export.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/facility.h>
+#define CREATE_TRACE_POINTS
+#include <asm/trace/ap.h>
+
#include "ap_bus.h"
#include "ap_debug.h"
+EXPORT_TRACEPOINT_SYMBOL(s390_ap_nqap);
+EXPORT_TRACEPOINT_SYMBOL(s390_ap_dqap);
+
static void __ap_flush_queue(struct ap_queue *aq);
/*
* some AP queue helper functions
*/
+static inline bool ap_q_supported_in_se(struct ap_queue *aq)
+{
+ return aq->card->hwinfo.ep11 || aq->card->hwinfo.accel;
+}
+
static inline bool ap_q_supports_bind(struct ap_queue *aq)
{
return aq->card->hwinfo.ep11 || aq->card->hwinfo.accel;
@@ -92,9 +103,17 @@ static inline struct ap_queue_status
__ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen,
int special)
{
+ struct ap_queue_status status;
+
if (special)
qid |= 0x400000UL;
- return ap_nqap(qid, psmid, msg, msglen);
+
+ status = ap_nqap(qid, psmid, msg, msglen);
+
+ trace_s390_ap_nqap(AP_QID_CARD(qid), AP_QID_QUEUE(qid),
+ status.value, psmid);
+
+ return status;
}
/* State machine definitions and helpers */
@@ -134,6 +153,9 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
parts++;
} while (status.response_code == 0xFF && resgr0 != 0);
+ trace_s390_ap_dqap(AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid),
+ status.value, aq->reply->psmid);
+
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
print_hex_dump_debug("aprpl: ", DUMP_PREFIX_ADDRESS, 16, 1,
@@ -171,8 +193,8 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
aq->queue_count = 0;
list_splice_init(&aq->pendingq, &aq->requestq);
aq->requestq_count += aq->pendingq_count;
- pr_debug("%s queue 0x%02x.%04x rescheduled %d reqs (new req %d)\n",
- __func__, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid),
+ pr_debug("queue 0x%02x.%04x rescheduled %d reqs (new req %d)\n",
+ AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid),
aq->pendingq_count, aq->requestq_count);
aq->pendingq_count = 0;
break;
@@ -453,8 +475,8 @@ static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq)
case AP_BS_Q_USABLE:
/* association is through */
aq->sm_state = AP_SM_STATE_IDLE;
- pr_debug("%s queue 0x%02x.%04x associated with %u\n",
- __func__, AP_QID_CARD(aq->qid),
+ pr_debug("queue 0x%02x.%04x associated with %u\n",
+ AP_QID_CARD(aq->qid),
AP_QID_QUEUE(aq->qid), aq->assoc_idx);
return AP_SM_WAIT_NONE;
case AP_BS_Q_USABLE_NO_SECURE_KEY:
@@ -697,8 +719,8 @@ static ssize_t ap_functions_show(struct device *dev,
status = ap_test_queue(aq->qid, 1, &hwinfo);
if (status.response_code > AP_RESPONSE_BUSY) {
- pr_debug("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
- __func__, status.response_code,
+ pr_debug("RC 0x%02x on tapq(0x%02x.%04x)\n",
+ status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return -EIO;
}
@@ -708,6 +730,58 @@ static ssize_t ap_functions_show(struct device *dev,
static DEVICE_ATTR_RO(ap_functions);
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ap_queue *aq = to_ap_queue(dev);
+ struct ap_device *ap_dev = &aq->ap_dev;
+ int rc;
+
+ device_lock(dev);
+ if (ap_dev->driver_override)
+ rc = sysfs_emit(buf, "%s\n", ap_dev->driver_override);
+ else
+ rc = sysfs_emit(buf, "\n");
+ device_unlock(dev);
+
+ return rc;
+}
+
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ap_queue *aq = to_ap_queue(dev);
+ struct ap_device *ap_dev = &aq->ap_dev;
+ int rc = -EINVAL;
+ bool old_value;
+
+ if (mutex_lock_interruptible(&ap_attr_mutex))
+ return -ERESTARTSYS;
+
+ /* Do not allow driver override if apmask/aqmask is in use */
+ if (ap_apmask_aqmask_in_use)
+ goto out;
+
+ old_value = ap_dev->driver_override ? true : false;
+ rc = driver_set_override(dev, &ap_dev->driver_override, buf, count);
+ if (rc)
+ goto out;
+ if (old_value && !ap_dev->driver_override)
+ --ap_driver_override_ctr;
+ else if (!old_value && ap_dev->driver_override)
+ ++ap_driver_override_ctr;
+
+ rc = count;
+
+out:
+ mutex_unlock(&ap_attr_mutex);
+ return rc;
+}
+
+static DEVICE_ATTR_RW(driver_override);
+
#ifdef CONFIG_AP_DEBUG
static ssize_t states_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -820,6 +894,7 @@ static struct attribute *ap_queue_dev_attrs[] = {
&dev_attr_config.attr,
&dev_attr_chkstop.attr,
&dev_attr_ap_functions.attr,
+ &dev_attr_driver_override.attr,
#ifdef CONFIG_AP_DEBUG
&dev_attr_states.attr,
&dev_attr_last_err_rc.attr,
@@ -853,8 +928,8 @@ static ssize_t se_bind_show(struct device *dev,
status = ap_test_queue(aq->qid, 1, &hwinfo);
if (status.response_code > AP_RESPONSE_BUSY) {
- pr_debug("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
- __func__, status.response_code,
+ pr_debug("RC 0x%02x on tapq(0x%02x.%04x)\n",
+ status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return -EIO;
}
@@ -981,8 +1056,8 @@ static ssize_t se_associate_show(struct device *dev,
status = ap_test_queue(aq->qid, 1, &hwinfo);
if (status.response_code > AP_RESPONSE_BUSY) {
- pr_debug("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
- __func__, status.response_code,
+ pr_debug("RC 0x%02x on tapq(0x%02x.%04x)\n",
+ status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return -EIO;
}
@@ -1104,18 +1179,19 @@ static void ap_queue_device_release(struct device *dev)
kfree(aq);
}
-struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)
+struct ap_queue *ap_queue_create(ap_qid_t qid, struct ap_card *ac)
{
struct ap_queue *aq;
aq = kzalloc(sizeof(*aq), GFP_KERNEL);
if (!aq)
return NULL;
+ aq->card = ac;
aq->ap_dev.device.release = ap_queue_device_release;
aq->ap_dev.device.type = &ap_queue_type;
- aq->ap_dev.device_type = device_type;
- // add optional SE secure binding attributes group
- if (ap_sb_available() && is_prot_virt_guest())
+ aq->ap_dev.device_type = ac->ap_dev.device_type;
+ /* in SE environment add bind/associate attributes group */
+ if (ap_is_se_guest() && ap_q_supported_in_se(aq))
aq->ap_dev.device.groups = ap_queue_dev_sb_attr_groups;
aq->qid = qid;
spin_lock_init(&aq->lock);
@@ -1196,10 +1272,16 @@ bool ap_queue_usable(struct ap_queue *aq)
}
/* SE guest's queues additionally need to be bound */
- if (ap_q_needs_bind(aq) &&
- !(aq->se_bstate == AP_BS_Q_USABLE ||
- aq->se_bstate == AP_BS_Q_USABLE_NO_SECURE_KEY))
- rc = false;
+ if (ap_is_se_guest()) {
+ if (!ap_q_supported_in_se(aq)) {
+ rc = false;
+ goto unlock_and_out;
+ }
+ if (ap_q_needs_bind(aq) &&
+ !(aq->se_bstate == AP_BS_Q_USABLE ||
+ aq->se_bstate == AP_BS_Q_USABLE_NO_SECURE_KEY))
+ rc = false;
+ }
unlock_and_out:
spin_unlock_bh(&aq->lock);
@@ -1277,7 +1359,7 @@ void ap_queue_prepare_remove(struct ap_queue *aq)
/* move queue device state to SHUTDOWN in progress */
aq->dev_state = AP_DEV_STATE_SHUTDOWN;
spin_unlock_bh(&aq->lock);
- del_timer_sync(&aq->timeout);
+ timer_delete_sync(&aq->timeout);
}
void ap_queue_remove(struct ap_queue *aq)