Blob Blame History Raw
From: Harald Freudenberger <freude@linux.vnet.ibm.com>
Subject: s390/zcrypt: externalize AP queue interrupt control
Patch-mainline: v4.14-rc1
Git-commit: 46fde9a9d204e322cf4fda391c30213633dcc17f
References: FATE#324118, LTC#158322

Summary:     s390/zcrypt: AP bus kernel API for KVM
Description: s390 zcrypt AP bus code modifications needed for
             KVM to be able to virtualize the AP bus
             functionallity.

Upstream-Description:

             s390/zcrypt: externalize AP queue interrupt control

             KVM has a need to control the interrupts on real and virtualized
             AP queue devices. This fix provides a new function to control
             the interrupt facilities of an AP queue device.

             Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
             Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>


Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
---
 arch/s390/include/asm/ap.h     |   36 ++++++++++++++++++++++++++++++++++++
 drivers/s390/crypto/ap_asm.h   |    9 ++++++---
 drivers/s390/crypto/ap_queue.c |   24 +++++++++++++++++++++++-
 3 files changed, 65 insertions(+), 4 deletions(-)

--- a/arch/s390/include/asm/ap.h
+++ b/arch/s390/include/asm/ap.h
@@ -87,4 +87,40 @@ struct ap_config_info {
  */
 int ap_query_configuration(struct ap_config_info *info);
 
+/*
+ * struct ap_qirq_ctrl - convenient struct for easy invocation
+ * of the ap_queue_irq_ctrl() function. This struct is passed
+ * as GR1 parameter to the PQAP(AQIC) instruction. For details
+ * please see the AR documentation.
+ */
+struct ap_qirq_ctrl {
+	unsigned int _res1 : 8;
+	unsigned int zone  : 8;  /* zone info */
+	unsigned int ir    : 1;  /* ir flag: enable (1) or disable (0) irq */
+	unsigned int _res2 : 4;
+	unsigned int gisc  : 3;  /* guest isc field */
+	unsigned int _res3 : 6;
+	unsigned int gf    : 2;  /* gisa format */
+	unsigned int _res4 : 1;
+	unsigned int gisa  : 27; /* gisa origin */
+	unsigned int _res5 : 1;
+	unsigned int isc   : 3;  /* irq sub class */
+};
+
+/**
+ * ap_queue_irq_ctrl(): Control interruption on a AP queue.
+ * @qid: The AP queue number
+ * @qirqctrl: struct ap_qirq_ctrl, see above
+ * @ind: The notification indicator byte
+ *
+ * Returns AP queue status.
+ *
+ * Control interruption on the given AP queue.
+ * Just a simple wrapper function for the low level PQAP(AQIC)
+ * instruction available for other kernel modules.
+ */
+struct ap_queue_status ap_queue_irq_ctrl(ap_qid_t qid,
+					 struct ap_qirq_ctrl qirqctrl,
+					 void *ind);
+
 #endif /* _ASM_S390_AP_H_ */
--- a/drivers/s390/crypto/ap_asm.h
+++ b/drivers/s390/crypto/ap_asm.h
@@ -69,16 +69,19 @@ static inline struct ap_queue_status ap_
 }
 
 /**
- * ap_aqic(): Enable interruption for a specific AP.
+ * ap_aqic(): Control interruption for a specific AP.
  * @qid: The AP queue number
+ * @qirqctrl: struct ap_qirq_ctrl (64 bit value)
  * @ind: The notification indicator byte
  *
  * Returns AP queue status.
  */
-static inline struct ap_queue_status ap_aqic(ap_qid_t qid, void *ind)
+static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
+					     struct ap_qirq_ctrl qirqctrl,
+					     void *ind)
 {
 	register unsigned long reg0 asm ("0") = qid | (3UL << 24);
-	register unsigned long reg1_in asm ("1") = (8UL << 44) | AP_ISC;
+	register struct ap_qirq_ctrl reg1_in asm ("1") = qirqctrl;
 	register struct ap_queue_status reg1_out asm ("1");
 	register void *reg2 asm ("2") = ind;
 
--- a/drivers/s390/crypto/ap_queue.c
+++ b/drivers/s390/crypto/ap_queue.c
@@ -16,6 +16,25 @@
 #include "ap_asm.h"
 
 /**
+ * ap_queue_irq_ctrl(): Control interruption on a AP queue.
+ * @qirqctrl: struct ap_qirq_ctrl (64 bit value)
+ * @ind: The notification indicator byte
+ *
+ * Returns AP queue status.
+ *
+ * Control interruption on the given AP queue.
+ * Just a simple wrapper function for the low level PQAP(AQIC)
+ * instruction available for other kernel modules.
+ */
+struct ap_queue_status ap_queue_irq_ctrl(ap_qid_t qid,
+					 struct ap_qirq_ctrl qirqctrl,
+					 void *ind)
+{
+	return ap_aqic(qid, qirqctrl, ind);
+}
+EXPORT_SYMBOL(ap_queue_irq_ctrl);
+
+/**
  * ap_queue_enable_interruption(): Enable interruption on an AP queue.
  * @qid: The AP queue number
  * @ind: the notification indicator byte
@@ -27,8 +46,11 @@
 static int ap_queue_enable_interruption(struct ap_queue *aq, void *ind)
 {
 	struct ap_queue_status status;
+	struct ap_qirq_ctrl qirqctrl = { 0 };
 
-	status = ap_aqic(aq->qid, ind);
+	qirqctrl.ir = 1;
+	qirqctrl.isc = AP_ISC;
+	status = ap_aqic(aq->qid, qirqctrl, ind);
 	switch (status.response_code) {
 	case AP_RESPONSE_NORMAL:
 	case AP_RESPONSE_OTHERWISE_CHANGED: