summaryrefslogtreecommitdiff
path: root/arch/s390
diff options
context:
space:
mode:
authorHarald Freudenberger <freude@linux.ibm.com>2021-06-30 16:10:56 +0200
committerVasily Gorbik <gor@linux.ibm.com>2021-07-08 15:37:27 +0200
commit1f0d22defd59f603d63ba51483eeb8d72726ce8b (patch)
tree2d5596036c3cdb260d56cc3b7902490f72ba25a2 /arch/s390
parentbd39654a2282c1a51c044575a6bc00d641d5dfd1 (diff)
s390/ap: Rework ap_dqap to deal with messages greater than recv buffer
Rework of the ap_dqap() inline function with the dqap inline assembler invocation and the caller code in ap_queue.c to be able to handle replies which exceed the receive buffer size. ap_dqap() now provides two additional parameters to handle together with the caller the case where a reply in the firmware queue entry exceeds the given message buffer size. It depends on the caller how to exactly handle this. The behavior implemented now by ap_sm_recv() in ap_queue.c is to simple purge this entry from the firmware queue and let the caller 'receive' a -EMSGSIZE for the request without delivering any reply data - not even a truncated reply message. However, the reworked ap_dqap() could now get invoked in a way that the message is received in multiple parts and the caller assembles the parts into one reply message. Signed-off-by: Harald Freudenberger <freude@linux.ibm.com> Suggested-by: Juergen Christ <jchrist@linux.ibm.com> Reviewed-by: Juergen Christ <jchrist@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/ap.h48
1 files changed, 41 insertions, 7 deletions
diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h
index 837d1699b109..5e77a81ab36a 100644
--- a/arch/s390/include/asm/ap.h
+++ b/arch/s390/include/asm/ap.h
@@ -325,6 +325,8 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
* @psmid: Pointer to program supplied message identifier
* @msg: The message text
* @length: The message length
+ * @reslength: Resitual length on return
+ * @resgr0: input: gr0 value (only used if != 0), output: resitual gr0 content
*
* Returns AP queue status structure.
* Condition code 1 on DQAP means the receive has taken place
@@ -336,12 +338,25 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
* Note that gpr2 is used by the DQAP instruction to keep track of
* any 'residual' length, in case the instruction gets interrupted.
* Hence it gets zeroed before the instruction.
+ * If the message does not fit into the buffer, this function will
+ * return with a truncated message and the reply in the firmware queue
+ * is not removed. This is indicated to the caller with an
+ * ap_queue_status response_code value of all bits on (0xFF) and (if
+ * the reslength ptr is given) the remaining length is stored in
+ * *reslength and (if the resgr0 ptr is given) the updated gr0 value
+ * for further processing of this msg entry is stored in *resgr0. The
+ * caller needs to detect this situation and should invoke ap_dqap
+ * with a valid resgr0 ptr and a value in there != 0 to indicate that
+ * *resgr0 is to be used instead of qid to further process this entry.
*/
static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
unsigned long long *psmid,
- void *msg, size_t length)
+ void *msg, size_t length,
+ size_t *reslength,
+ unsigned long *resgr0)
{
- register unsigned long reg0 asm("0") = qid | 0x80000000UL;
+ register unsigned long reg0 asm("0") =
+ resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;
register struct ap_queue_status reg1 asm ("1");
register unsigned long reg2 asm("2") = 0UL;
register unsigned long reg4 asm("4") = (unsigned long) msg;
@@ -349,14 +364,33 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
register unsigned long reg6 asm("6") = 0UL;
register unsigned long reg7 asm("7") = 0UL;
-
asm volatile(
- "0: .long 0xb2ae0064\n" /* DQAP */
- " brc 6,0b\n"
+ "0: ltgr %[bl],%[bl]\n" /* if avail. buf len is 0 then */
+ " jz 2f\n" /* go out of this asm block */
+ "1: .long 0xb2ae0064\n" /* DQAP */
+ " brc 6,0b\n" /* if partially do again */
+ "2:\n"
: "+d" (reg0), "=d" (reg1), "+d" (reg2),
- "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7)
+ "+d" (reg4), [bl] "+d" (reg5), "+d" (reg6), "+d" (reg7)
: : "cc", "memory");
- *psmid = (((unsigned long long) reg6) << 32) + reg7;
+
+ if (reslength)
+ *reslength = reg2;
+ if (reg2 != 0 && reg5 == 0) {
+ /*
+ * Partially complete, status in gr1 is not set.
+ * Signal the caller that this dqap is only partially received
+ * with a special status response code 0xFF and *resgr0 updated
+ */
+ reg1.response_code = 0xFF;
+ if (resgr0)
+ *resgr0 = reg0;
+ } else {
+ *psmid = (((unsigned long long) reg6) << 32) + reg7;
+ if (resgr0)
+ *resgr0 = 0;
+ }
+
return reg1;
}