Commit e7fc5146 authored by Tony Krowiak's avatar Tony Krowiak Committed by Martin Schwidefsky

s390/zcrypt: externalize test AP queue

Under certain specified conditions, the Test AP Queue (TAPQ)
subfunction of the Process Adjunct Processor Queue (PQAP) instruction
will be intercepted by a guest VM. The guest VM must have a means for
executing the intercepted instruction.

The vfio_ap driver will provide an interface to execute the
PQAP(TAPQ) instruction subfunction on behalf of a guest VM.
The code for executing the AP instructions currently resides in the
AP bus. This patch refactors the AP bus code to externalize access
to the PQAP(TAPQ) instruction subfunction to make it available to
the vfio_ap driver.
Signed-off-by: default avatarTony Krowiak <akrowiak@linux.vnet.ibm.com>
Signed-off-by: default avatarHarald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 2fc4876e
/*
* Adjunct processor (AP) interfaces
*
* Copyright IBM Corp. 2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
* as published by the Free Software Foundation.
*
* Author(s): Tony Krowiak <akrowia@linux.vnet.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Harald Freudenberger <freude@de.ibm.com>
*/
#ifndef _ASM_S390_AP_H_
#define _ASM_S390_AP_H_
/**
* The ap_qid_t identifier of an ap queue.
* If the AP facilities test (APFT) facility is available,
* card and queue index are 8 bit values, otherwise
* card index is 6 bit and queue index a 4 bit value.
*/
typedef unsigned int ap_qid_t;
#define AP_MKQID(_card, _queue) (((_card) & 63) << 8 | ((_queue) & 255))
#define AP_QID_CARD(_qid) (((_qid) >> 8) & 63)
#define AP_QID_QUEUE(_qid) ((_qid) & 255)
/**
* struct ap_queue_status - Holds the AP queue status.
* @queue_empty: Shows if queue is empty
* @replies_waiting: Waiting replies
* @queue_full: Is 1 if the queue is full
* @irq_enabled: Shows if interrupts are enabled for the AP
* @response_code: Holds the 8 bit response code
*
* The ap queue status word is returned by all three AP functions
* (PQAP, NQAP and DQAP). There's a set of flags in the first
* byte, followed by a 1 byte response code.
*/
struct ap_queue_status {
unsigned int queue_empty : 1;
unsigned int replies_waiting : 1;
unsigned int queue_full : 1;
unsigned int _pad1 : 4;
unsigned int irq_enabled : 1;
unsigned int response_code : 8;
unsigned int _pad2 : 16;
};
/**
* ap_test_queue(): Test adjunct processor queue.
* @qid: The AP queue number
* @tbit: Test facilities bit
* @info: Pointer to queue descriptor
*
* Returns AP queue status structure.
*/
struct ap_queue_status ap_test_queue(ap_qid_t qid,
int tbit,
unsigned long *info);
#endif /* _ASM_S390_AP_H_ */
...@@ -165,20 +165,34 @@ static int ap_configuration_available(void) ...@@ -165,20 +165,34 @@ static int ap_configuration_available(void)
return test_facility(12); return test_facility(12);
} }
/**
* ap_apft_available(): Test if AP facilities test (APFT)
* facility is available.
*
* Returns 1 if APFT is is available.
*/
static int ap_apft_available(void)
{
return test_facility(15);
}
/** /**
* ap_test_queue(): Test adjunct processor queue. * ap_test_queue(): Test adjunct processor queue.
* @qid: The AP queue number * @qid: The AP queue number
* @tbit: Test facilities bit
* @info: Pointer to queue descriptor * @info: Pointer to queue descriptor
* *
* Returns AP queue status structure. * Returns AP queue status structure.
*/ */
static inline struct ap_queue_status struct ap_queue_status ap_test_queue(ap_qid_t qid,
ap_test_queue(ap_qid_t qid, unsigned long *info) int tbit,
unsigned long *info)
{ {
if (test_facility(15)) if (tbit)
qid |= 1UL << 23; /* set APFT T bit*/ qid |= 1UL << 23; /* set T bit*/
return ap_tapq(qid, info); return ap_tapq(qid, info);
} }
EXPORT_SYMBOL(ap_test_queue);
static inline int ap_query_configuration(void) static inline int ap_query_configuration(void)
{ {
...@@ -261,7 +275,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, ...@@ -261,7 +275,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type,
if (!ap_test_config_card_id(AP_QID_CARD(qid))) if (!ap_test_config_card_id(AP_QID_CARD(qid)))
return -ENODEV; return -ENODEV;
status = ap_test_queue(qid, &info); status = ap_test_queue(qid, ap_apft_available(), &info);
switch (status.response_code) { switch (status.response_code) {
case AP_RESPONSE_NORMAL: case AP_RESPONSE_NORMAL:
*queue_depth = (int)(info & 0xff); *queue_depth = (int)(info & 0xff);
...@@ -940,7 +954,9 @@ static int ap_select_domain(void) ...@@ -940,7 +954,9 @@ static int ap_select_domain(void)
for (j = 0; j < AP_DEVICES; j++) { for (j = 0; j < AP_DEVICES; j++) {
if (!ap_test_config_card_id(j)) if (!ap_test_config_card_id(j))
continue; continue;
status = ap_test_queue(AP_MKQID(j, i), NULL); status = ap_test_queue(AP_MKQID(j, i),
ap_apft_available(),
NULL);
if (status.response_code != AP_RESPONSE_NORMAL) if (status.response_code != AP_RESPONSE_NORMAL)
continue; continue;
count++; count++;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/ap.h>
#define AP_DEVICES 64 /* Number of AP devices. */ #define AP_DEVICES 64 /* Number of AP devices. */
#define AP_DOMAINS 256 /* Number of AP domains. */ #define AP_DOMAINS 256 /* Number of AP domains. */
...@@ -40,41 +41,6 @@ extern int ap_domain_index; ...@@ -40,41 +41,6 @@ extern int ap_domain_index;
extern spinlock_t ap_list_lock; extern spinlock_t ap_list_lock;
extern struct list_head ap_card_list; extern struct list_head ap_card_list;
/**
* The ap_qid_t identifier of an ap queue. It contains a
* 6 bit card index and a 4 bit queue index (domain).
*/
typedef unsigned int ap_qid_t;
#define AP_MKQID(_card, _queue) (((_card) & 63) << 8 | ((_queue) & 255))
#define AP_QID_CARD(_qid) (((_qid) >> 8) & 63)
#define AP_QID_QUEUE(_qid) ((_qid) & 255)
/**
* structy ap_queue_status - Holds the AP queue status.
* @queue_empty: Shows if queue is empty
* @replies_waiting: Waiting replies
* @queue_full: Is 1 if the queue is full
* @pad: A 4 bit pad
* @int_enabled: Shows if interrupts are enabled for the AP
* @response_code: Holds the 8 bit response code
* @pad2: A 16 bit pad
*
* The ap queue status word is returned by all three AP functions
* (PQAP, NQAP and DQAP). There's a set of flags in the first
* byte, followed by a 1 byte response code.
*/
struct ap_queue_status {
unsigned int queue_empty : 1;
unsigned int replies_waiting : 1;
unsigned int queue_full : 1;
unsigned int pad1 : 4;
unsigned int int_enabled : 1;
unsigned int response_code : 8;
unsigned int pad2 : 16;
} __packed;
static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
{ {
return (*ptr & (0x80000000u >> nr)) != 0; return (*ptr & (0x80000000u >> nr)) != 0;
......
...@@ -362,7 +362,7 @@ static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq) ...@@ -362,7 +362,7 @@ static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq)
/* Get the status with TAPQ */ /* Get the status with TAPQ */
status = ap_tapq(aq->qid, NULL); status = ap_tapq(aq->qid, NULL);
if (status.int_enabled == 1) { if (status.irq_enabled == 1) {
/* Irqs are now enabled */ /* Irqs are now enabled */
aq->interrupt = AP_INTR_ENABLED; aq->interrupt = AP_INTR_ENABLED;
aq->state = (aq->queue_count > 0) ? aq->state = (aq->queue_count > 0) ?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment