Commit 2d72eaf0 authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Heiko Carstens

s390/ap: implement SE AP bind, unbind and associate

Implementation of the new functions for SE AP support:
bind, unbind and associate. There are two new sysfs
attributes for this:

/sys/devices/ap/cardxx/xx.yyyy/se_bind
/sys/devices/ap/cardxx/xx.yyyy/se_associate

Writing a 1 into the se_bind attribute triggers the
SE AP bind for this AP queue, writing a 0 into does
an unbind - that's a reset (RAPQ) with the F bit enabled.

The se_associate attribute needs an integer value in
range 0...2^16-1 written in. This is the index into a
secrets table feed into the ultravisor. For more details
please see the Architecture documents.

These both new ap queue attributes are only visible
inside a SE guest with SB (Secure Binding) available.
Signed-off-by: default avatarHarald Freudenberger <freude@linux.ibm.com>
Reviewed-by: default avatarHolger Dengler <dengler@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent 263c8454
......@@ -43,10 +43,11 @@ 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 : 3;
unsigned int async : 1;
unsigned int irq_enabled : 1;
unsigned int response_code : 8;
unsigned int _pad2 : 16;
unsigned int : 16;
};
/*
......@@ -114,6 +115,14 @@ struct ap_tapq_gr2 {
};
};
/*
* Convenience defines to be used with the bs field from struct ap_tapq_gr2
*/
#define AP_BS_Q_USABLE 0
#define AP_BS_Q_USABLE_NO_SECURE_KEY 1
#define AP_BS_Q_AVAIL_FOR_BINDING 2
#define AP_BS_Q_UNUSABLE 3
/**
* ap_tapq(): Test adjunct processor queue.
* @qid: The AP queue number
......
......@@ -39,22 +39,32 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
return (*ptr & (0x80000000u >> nr)) != 0;
}
#define AP_RESPONSE_NORMAL 0x00
#define AP_RESPONSE_Q_NOT_AVAIL 0x01
#define AP_RESPONSE_RESET_IN_PROGRESS 0x02
#define AP_RESPONSE_DECONFIGURED 0x03
#define AP_RESPONSE_CHECKSTOPPED 0x04
#define AP_RESPONSE_BUSY 0x05
#define AP_RESPONSE_INVALID_ADDRESS 0x06
#define AP_RESPONSE_OTHERWISE_CHANGED 0x07
#define AP_RESPONSE_INVALID_GISA 0x08
#define AP_RESPONSE_Q_FULL 0x10
#define AP_RESPONSE_NO_PENDING_REPLY 0x10
#define AP_RESPONSE_INDEX_TOO_BIG 0x11
#define AP_RESPONSE_NO_FIRST_PART 0x13
#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
#define AP_RESPONSE_REQ_FAC_NOT_INST 0x16
#define AP_RESPONSE_INVALID_DOMAIN 0x42
#define AP_RESPONSE_NORMAL 0x00
#define AP_RESPONSE_Q_NOT_AVAIL 0x01
#define AP_RESPONSE_RESET_IN_PROGRESS 0x02
#define AP_RESPONSE_DECONFIGURED 0x03
#define AP_RESPONSE_CHECKSTOPPED 0x04
#define AP_RESPONSE_BUSY 0x05
#define AP_RESPONSE_INVALID_ADDRESS 0x06
#define AP_RESPONSE_OTHERWISE_CHANGED 0x07
#define AP_RESPONSE_INVALID_GISA 0x08
#define AP_RESPONSE_Q_BOUND_TO_ANOTHER 0x09
#define AP_RESPONSE_STATE_CHANGE_IN_PROGRESS 0x0A
#define AP_RESPONSE_Q_NOT_BOUND 0x0B
#define AP_RESPONSE_Q_FULL 0x10
#define AP_RESPONSE_NO_PENDING_REPLY 0x10
#define AP_RESPONSE_INDEX_TOO_BIG 0x11
#define AP_RESPONSE_NO_FIRST_PART 0x13
#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
#define AP_RESPONSE_REQ_FAC_NOT_INST 0x16
#define AP_RESPONSE_Q_BIND_ERROR 0x30
#define AP_RESPONSE_Q_NOT_AVAIL_FOR_ASSOC 0x31
#define AP_RESPONSE_Q_NOT_EMPTY 0x32
#define AP_RESPONSE_BIND_LIMIT_EXCEEDED 0x33
#define AP_RESPONSE_INVALID_ASSOC_SECRET 0x34
#define AP_RESPONSE_ASSOC_SECRET_NOT_UNIQUE 0x35
#define AP_RESPONSE_ASSOC_FAILED 0x36
#define AP_RESPONSE_INVALID_DOMAIN 0x42
/*
* Known device types
......@@ -92,6 +102,7 @@ enum ap_sm_state {
AP_SM_STATE_IDLE,
AP_SM_STATE_WORKING,
AP_SM_STATE_QUEUE_FULL,
AP_SM_STATE_ASSOC_WAIT,
NR_AP_SM_STATES
};
......@@ -189,6 +200,7 @@ struct ap_card {
};
#define TAPQ_CARD_FUNC_CMP_MASK 0xFFFF0000
#define ASSOC_IDX_INVALID 0x10000
#define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device)
......@@ -202,6 +214,7 @@ struct ap_queue {
bool chkstop; /* checkstop state */
ap_qid_t qid; /* AP queue id. */
bool interrupt; /* indicate if interrupts are enabled */
unsigned int assoc_idx; /* SE association index */
int queue_count; /* # messages currently on AP queue. */
int pendingq_count; /* # requests on pendingq list. */
int requestq_count; /* # requests on requestq list. */
......@@ -212,6 +225,7 @@ struct ap_queue {
struct list_head requestq; /* List of message yet to be sent. */
struct ap_message *reply; /* Per device reply message. */
enum ap_sm_state sm_state; /* ap queue state machine state */
int rapq_fbit; /* fbit arg for next rapq invocation */
int last_err_rc; /* last error state response code */
};
......
......@@ -18,6 +18,21 @@
static void __ap_flush_queue(struct ap_queue *aq);
/*
* some AP queue helper functions
*/
static inline bool ap_q_supports_bind(struct ap_queue *aq)
{
return ap_test_bit(&aq->card->functions, AP_FUNC_EP11) ||
ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL);
}
static inline bool ap_q_supports_assoc(struct ap_queue *aq)
{
return ap_test_bit(&aq->card->functions, AP_FUNC_EP11);
}
/**
* ap_queue_enable_irq(): Enable interrupt support on this AP queue.
* @aq: The AP queue
......@@ -322,12 +337,13 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq)
{
struct ap_queue_status status;
status = ap_rapq(aq->qid, 0);
status = ap_rapq(aq->qid, aq->rapq_fbit);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
case AP_RESPONSE_RESET_IN_PROGRESS:
aq->sm_state = AP_SM_STATE_RESET_WAIT;
aq->interrupt = false;
aq->rapq_fbit = 0;
return AP_SM_WAIT_LOW_TIMEOUT;
default:
aq->dev_state = AP_DEV_STATE_ERROR;
......@@ -423,6 +439,59 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq)
}
}
/**
* ap_sm_assoc_wait(): Test queue for completion of a pending
* association request.
* @aq: pointer to the AP queue
*/
static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq)
{
struct ap_queue_status status;
struct ap_tapq_gr2 info;
status = ap_test_queue(aq->qid, 1, &info);
/* handle asynchronous error on this queue */
if (status.async && status.response_code) {
aq->dev_state = AP_DEV_STATE_ERROR;
aq->last_err_rc = status.response_code;
AP_DBF_WARN("%s asynch RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n",
__func__, status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return AP_SM_WAIT_NONE;
}
if (status.response_code > AP_RESPONSE_BUSY) {
aq->dev_state = AP_DEV_STATE_ERROR;
aq->last_err_rc = status.response_code;
AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n",
__func__, status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return AP_SM_WAIT_NONE;
}
/* check bs bits */
switch (info.bs) {
case AP_BS_Q_USABLE:
/* association is through */
aq->sm_state = AP_SM_STATE_IDLE;
AP_DBF_DBG("%s queue 0x%02x.%04x associated with %u\n",
__func__, 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:
/* association still pending */
return AP_SM_WAIT_LOW_TIMEOUT;
default:
/* reset from 'outside' happened or no idea at all */
aq->assoc_idx = ASSOC_IDX_INVALID;
aq->dev_state = AP_DEV_STATE_ERROR;
aq->last_err_rc = status.response_code;
AP_DBF_WARN("%s bs 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n",
__func__, info.bs,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return AP_SM_WAIT_NONE;
}
}
/*
* AP state machine jump table
*/
......@@ -451,6 +520,10 @@ static ap_func_t *ap_jumptable[NR_AP_SM_STATES][NR_AP_SM_EVENTS] = {
[AP_SM_EVENT_POLL] = ap_sm_read,
[AP_SM_EVENT_TIMEOUT] = ap_sm_reset,
},
[AP_SM_STATE_ASSOC_WAIT] = {
[AP_SM_EVENT_POLL] = ap_sm_assoc_wait,
[AP_SM_EVENT_TIMEOUT] = ap_sm_reset,
},
};
enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event)
......@@ -696,6 +769,9 @@ static ssize_t states_show(struct device *dev,
case AP_SM_STATE_QUEUE_FULL:
rc += sysfs_emit_at(buf, rc, " [FULL]\n");
break;
case AP_SM_STATE_ASSOC_WAIT:
rc += sysfs_emit_at(buf, rc, " [ASSOC_WAIT]\n");
break;
default:
rc += sysfs_emit_at(buf, rc, " [UNKNOWN]\n");
}
......@@ -780,6 +856,186 @@ static struct device_type ap_queue_type = {
.groups = ap_queue_dev_attr_groups,
};
static ssize_t se_bind_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_queue *aq = to_ap_queue(dev);
struct ap_queue_status status;
struct ap_tapq_gr2 info;
if (!ap_q_supports_bind(aq))
return sysfs_emit(buf, "-\n");
status = ap_test_queue(aq->qid, 1, &info);
if (status.response_code > AP_RESPONSE_BUSY) {
AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
__func__, status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return -EIO;
}
switch (info.bs) {
case AP_BS_Q_USABLE:
case AP_BS_Q_USABLE_NO_SECURE_KEY:
return sysfs_emit(buf, "bound\n");
default:
return sysfs_emit(buf, "unbound\n");
}
}
static ssize_t se_bind_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ap_queue *aq = to_ap_queue(dev);
struct ap_queue_status status;
bool value;
int rc;
if (!ap_q_supports_bind(aq))
return -EINVAL;
/* only 0 (unbind) and 1 (bind) allowed */
rc = kstrtobool(buf, &value);
if (rc)
return rc;
if (value) {
/* bind, do BAPQ */
spin_lock_bh(&aq->lock);
if (aq->sm_state < AP_SM_STATE_IDLE) {
spin_unlock_bh(&aq->lock);
return -EBUSY;
}
status = ap_bapq(aq->qid);
spin_unlock_bh(&aq->lock);
if (status.response_code) {
AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n",
__func__, status.response_code,
AP_QID_CARD(aq->qid),
AP_QID_QUEUE(aq->qid));
return -EIO;
}
} else {
/* unbind, set F bit arg and trigger RAPQ */
spin_lock_bh(&aq->lock);
__ap_flush_queue(aq);
aq->rapq_fbit = 1;
aq->assoc_idx = ASSOC_IDX_INVALID;
aq->sm_state = AP_SM_STATE_RESET_START;
ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL));
spin_unlock_bh(&aq->lock);
}
return count;
}
static DEVICE_ATTR_RW(se_bind);
static ssize_t se_associate_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_queue *aq = to_ap_queue(dev);
struct ap_queue_status status;
struct ap_tapq_gr2 info;
if (!ap_q_supports_assoc(aq))
return sysfs_emit(buf, "-\n");
status = ap_test_queue(aq->qid, 1, &info);
if (status.response_code > AP_RESPONSE_BUSY) {
AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
__func__, status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return -EIO;
}
switch (info.bs) {
case AP_BS_Q_USABLE:
if (aq->assoc_idx == ASSOC_IDX_INVALID) {
AP_DBF_WARN("%s AP_BS_Q_USABLE but invalid assoc_idx\n", __func__);
return -EIO;
}
return sysfs_emit(buf, "associated %u\n", aq->assoc_idx);
case AP_BS_Q_USABLE_NO_SECURE_KEY:
if (aq->assoc_idx != ASSOC_IDX_INVALID)
return sysfs_emit(buf, "association pending\n");
fallthrough;
default:
return sysfs_emit(buf, "unassociated\n");
}
}
static ssize_t se_associate_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ap_queue *aq = to_ap_queue(dev);
struct ap_queue_status status;
unsigned int value;
int rc;
if (!ap_q_supports_assoc(aq))
return -EINVAL;
/* association index needs to be >= 0 */
rc = kstrtouint(buf, 0, &value);
if (rc)
return rc;
if (value >= ASSOC_IDX_INVALID)
return -EINVAL;
spin_lock_bh(&aq->lock);
/* sm should be in idle state */
if (aq->sm_state != AP_SM_STATE_IDLE) {
spin_unlock_bh(&aq->lock);
return -EBUSY;
}
/* already associated or association pending ? */
if (aq->assoc_idx != ASSOC_IDX_INVALID) {
spin_unlock_bh(&aq->lock);
return -EINVAL;
}
/* trigger the asynchronous association request */
status = ap_aapq(aq->qid, value);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
case AP_RESPONSE_STATE_CHANGE_IN_PROGRESS:
aq->sm_state = AP_SM_STATE_ASSOC_WAIT;
aq->assoc_idx = value;
ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL));
spin_unlock_bh(&aq->lock);
break;
default:
spin_unlock_bh(&aq->lock);
AP_DBF_WARN("%s RC 0x%02x on aapq(0x%02x.%04x)\n",
__func__, status.response_code,
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
return -EIO;
}
return count;
}
static DEVICE_ATTR_RW(se_associate);
static struct attribute *ap_queue_dev_sb_attrs[] = {
&dev_attr_se_bind.attr,
&dev_attr_se_associate.attr,
NULL
};
static struct attribute_group ap_queue_dev_sb_attr_group = {
.attrs = ap_queue_dev_sb_attrs
};
static const struct attribute_group *ap_queue_dev_sb_attr_groups[] = {
&ap_queue_dev_sb_attr_group,
NULL
};
static void ap_queue_device_release(struct device *dev)
{
struct ap_queue *aq = to_ap_queue(dev);
......@@ -801,6 +1057,9 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)
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.groups = ap_queue_dev_sb_attr_groups;
aq->qid = qid;
aq->interrupt = false;
spin_lock_init(&aq->lock);
......@@ -947,6 +1206,7 @@ void ap_queue_init_state(struct ap_queue *aq)
aq->dev_state = AP_DEV_STATE_OPERATING;
aq->sm_state = AP_SM_STATE_RESET_START;
aq->last_err_rc = 0;
aq->assoc_idx = ASSOC_IDX_INVALID;
ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL));
spin_unlock_bh(&aq->lock);
}
......
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