1
0
Fork 0

s390/zcrypt: add multi domain support

Currently the ap infrastructure only supports one domain at a time.
This feature extends the generic cryptographic device driver to
support multiple cryptographic domains simultaneously.

There are now card and queue devices on the AP bus with independent
card and queue drivers. The new /sys layout is as follows:

/sys/bus/ap
    devices
        <xx>.<yyyy> -> ../../../devices/ap/card<xx>/<xx>.<yyyy>
        ...
        card<xx> -> ../../../devices/ap/card<xx>
        ...
    drivers
        <drv>card
            card<xx> -> ../../../../devices/ap/card<xx>
        <drv>queue
            <xx>.<yyyy> -> ../../../../devices/ap/card<xx>/<xx>.<yyyy>
            ...

/sys/devices/ap
    card<xx>
        <xx>.<yyyy>
            driver -> ../../../../bus/ap/drivers/<zzz>queue
            ...
        driver -> ../../../bus/ap/drivers/<drv>card
        ...

The two digit <xx> field is the card number, the four digit <yyyy>
field is the queue number and <drv> is the name of the device driver,
e.g. "cex4".

For compatability /sys/bus/ap/card<xx> for the old layout has to exist,
including the attributes that used to reside there.

With additional contributions from Harald Freudenberger and
Martin Schwidefsky.

Signed-off-by: Ingo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
hifive-unleashed-5.1
Ingo Tuchscherer 2016-08-25 11:16:03 +02:00 committed by Martin Schwidefsky
parent 34a1516773
commit e28d2af436
17 changed files with 2795 additions and 2017 deletions

View File

@ -2,10 +2,11 @@
# S/390 crypto devices
#
ap-objs := ap_bus.o
ap-objs := ap_bus.o ap_card.o ap_queue.o
obj-$(subst m,y,$(CONFIG_ZCRYPT)) += ap.o
# zcrypt_api.o and zcrypt_msgtype*.o depend on ap.o
zcrypt-objs := zcrypt_api.o zcrypt_msgtype6.o zcrypt_msgtype50.o
zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o
zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o
obj-$(CONFIG_ZCRYPT) += zcrypt.o
# adapter drivers depend on ap.o and zcrypt.o
obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,6 @@
#define _AP_BUS_H_
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/types.h>
#define AP_DEVICES 64 /* Number of AP devices. */
@ -38,14 +37,17 @@
extern int ap_domain_index;
extern spinlock_t ap_list_lock;
extern struct list_head ap_card_list;
/**
* The ap_qid_t identifier of an ap queue. It contains a
* 6 bit device index and a 4 bit queue index (domain).
* 6 bit card index and a 4 bit queue index (domain).
*/
typedef unsigned int ap_qid_t;
#define AP_MKQID(_device, _queue) (((_device) & 63) << 8 | ((_queue) & 255))
#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63)
#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)
/**
@ -55,7 +57,7 @@ typedef unsigned int ap_qid_t;
* @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_conde: Holds the 8 bit response code
* @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
@ -167,7 +169,8 @@ struct ap_driver {
int (*probe)(struct ap_device *);
void (*remove)(struct ap_device *);
int request_timeout; /* request timeout in jiffies */
void (*suspend)(struct ap_device *);
void (*resume)(struct ap_device *);
};
#define to_ap_drv(x) container_of((x), struct ap_driver, driver)
@ -175,39 +178,51 @@ struct ap_driver {
int ap_driver_register(struct ap_driver *, struct module *, char *);
void ap_driver_unregister(struct ap_driver *);
typedef enum ap_wait (ap_func_t)(struct ap_device *ap_dev);
struct ap_device {
struct device device;
struct ap_driver *drv; /* Pointer to AP device driver. */
spinlock_t lock; /* Per device lock. */
struct list_head list; /* private list of all AP devices. */
enum ap_state state; /* State of the AP device. */
ap_qid_t qid; /* AP queue id. */
int queue_depth; /* AP queue depth.*/
int device_type; /* AP device type. */
int raw_hwtype; /* AP raw hardware type. */
unsigned int functions; /* AP device function bitfield. */
struct timer_list timeout; /* Timer for request timeouts. */
int interrupt; /* indicate if interrupts are enabled */
int queue_count; /* # messages currently on AP queue. */
struct list_head pendingq; /* List of message sent to AP queue. */
int pendingq_count; /* # requests on pendingq list. */
struct list_head requestq; /* List of message yet to be sent. */
int requestq_count; /* # requests on requestq list. */
int total_request_count; /* # requests ever for this AP device. */
struct ap_message *reply; /* Per device reply message. */
void *private; /* ap driver private pointer. */
};
#define to_ap_dev(x) container_of((x), struct ap_device, device)
struct ap_card {
struct ap_device ap_dev;
struct list_head list; /* Private list of AP cards. */
struct list_head queues; /* List of assoc. AP queues */
void *private; /* ap driver private pointer. */
int raw_hwtype; /* AP raw hardware type. */
unsigned int functions; /* AP device function bitfield. */
int queue_depth; /* AP queue depth.*/
int id; /* AP card number. */
};
#define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device)
struct ap_queue {
struct ap_device ap_dev;
struct list_head list; /* Private list of AP queues. */
struct ap_card *card; /* Ptr to assoc. AP card. */
spinlock_t lock; /* Per device lock. */
void *private; /* ap driver private pointer. */
ap_qid_t qid; /* AP queue id. */
int interrupt; /* indicate if interrupts are enabled */
int queue_count; /* # messages currently on AP queue. */
enum ap_state state; /* State of the AP device. */
int pendingq_count; /* # requests on pendingq list. */
int requestq_count; /* # requests on requestq list. */
int total_request_count; /* # requests ever for this AP device. */
int request_timeout; /* Request timout in jiffies. */
struct timer_list timeout; /* Timer for request timeouts. */
struct list_head pendingq; /* List of message sent to AP queue. */
struct list_head requestq; /* List of message yet to be sent. */
struct ap_message *reply; /* Per device reply message. */
};
#define to_ap_queue(x) container_of((x), struct ap_queue, ap_dev.device)
typedef enum ap_wait (ap_func_t)(struct ap_queue *queue);
struct ap_message {
struct list_head list; /* Request queueing. */
unsigned long long psmid; /* Message id. */
@ -218,7 +233,7 @@ struct ap_message {
void *private; /* ap driver private pointer. */
unsigned int special:1; /* Used for special commands. */
/* receive is called from tasklet context */
void (*receive)(struct ap_device *, struct ap_message *,
void (*receive)(struct ap_queue *, struct ap_message *,
struct ap_message *);
};
@ -233,10 +248,6 @@ struct ap_config_info {
unsigned char reserved4[16];
} __packed;
#define AP_DEVICE(dt) \
.dev_type=(dt), \
.match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
/**
* ap_init_message() - Initialize ap_message.
* Initialize a message before using. Otherwise this might result in
@ -251,6 +262,12 @@ static inline void ap_init_message(struct ap_message *ap_msg)
ap_msg->receive = NULL;
}
#define for_each_ap_card(_ac) \
list_for_each_entry(_ac, &ap_card_list, list)
#define for_each_ap_queue(_aq, _ac) \
list_for_each_entry(_aq, &(_ac)->queues, list)
/*
* Note: don't use ap_send/ap_recv after using ap_queue_message
* for the first time. Otherwise the ap message queue will get
@ -259,11 +276,26 @@ static inline void ap_init_message(struct ap_message *ap_msg)
int ap_send(ap_qid_t, unsigned long long, void *, size_t);
int ap_recv(ap_qid_t, unsigned long long *, void *, size_t);
void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
void ap_flush_queue(struct ap_device *ap_dev);
enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event);
enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event);
void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg);
void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg);
void ap_flush_queue(struct ap_queue *aq);
void *ap_airq_ptr(void);
void ap_wait(enum ap_wait wait);
void ap_request_timeout(unsigned long data);
void ap_bus_force_rescan(void);
void ap_device_init_reply(struct ap_device *ap_dev, struct ap_message *ap_msg);
void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg);
struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type);
void ap_queue_remove(struct ap_queue *aq);
void ap_queue_suspend(struct ap_device *ap_dev);
void ap_queue_resume(struct ap_device *ap_dev);
struct ap_card *ap_card_create(int id, int queue_depth, int device_type,
unsigned int device_functions);
int ap_module_init(void);
void ap_module_exit(void);

View File

@ -0,0 +1,172 @@
/*
* Copyright IBM Corp. 2016
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*
* Adjunct processor bus, card related code.
*/
#define KMSG_COMPONENT "ap"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/facility.h>
#include "ap_bus.h"
#include "ap_asm.h"
/*
* AP card related attributes.
*/
static ssize_t ap_hwtype_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_card *ac = to_ap_card(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type);
}
static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
static ssize_t ap_raw_hwtype_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_card *ac = to_ap_card(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype);
}
static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL);
static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ap_card *ac = to_ap_card(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth);
}
static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
static ssize_t ap_functions_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_card *ac = to_ap_card(dev);
return snprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions);
}
static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL);
static ssize_t ap_request_count_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ap_card *ac = to_ap_card(dev);
struct ap_queue *aq;
unsigned int req_cnt;
req_cnt = 0;
spin_lock_bh(&ap_list_lock);
for_each_ap_queue(aq, ac)
req_cnt += aq->total_request_count;
spin_unlock_bh(&ap_list_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt);
}
static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
static ssize_t ap_requestq_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_card *ac = to_ap_card(dev);
struct ap_queue *aq;
unsigned int reqq_cnt;
reqq_cnt = 0;
spin_lock_bh(&ap_list_lock);
for_each_ap_queue(aq, ac)
reqq_cnt += aq->requestq_count;
spin_unlock_bh(&ap_list_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt);
}
static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL);
static ssize_t ap_pendingq_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_card *ac = to_ap_card(dev);
struct ap_queue *aq;
unsigned int penq_cnt;
penq_cnt = 0;
spin_lock_bh(&ap_list_lock);
for_each_ap_queue(aq, ac)
penq_cnt += aq->pendingq_count;
spin_unlock_bh(&ap_list_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt);
}
static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL);
static ssize_t ap_modalias_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type);
}
static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
static struct attribute *ap_card_dev_attrs[] = {
&dev_attr_hwtype.attr,
&dev_attr_raw_hwtype.attr,
&dev_attr_depth.attr,
&dev_attr_ap_functions.attr,
&dev_attr_request_count.attr,
&dev_attr_requestq_count.attr,
&dev_attr_pendingq_count.attr,
&dev_attr_modalias.attr,
NULL
};
static struct attribute_group ap_card_dev_attr_group = {
.attrs = ap_card_dev_attrs
};
static const struct attribute_group *ap_card_dev_attr_groups[] = {
&ap_card_dev_attr_group,
NULL
};
struct device_type ap_card_type = {
.name = "ap_card",
.groups = ap_card_dev_attr_groups,
};
static void ap_card_device_release(struct device *dev)
{
kfree(to_ap_card(dev));
}
struct ap_card *ap_card_create(int id, int queue_depth, int device_type,
unsigned int functions)
{
struct ap_card *ac;
ac = kzalloc(sizeof(*ac), GFP_KERNEL);
if (!ac)
return NULL;
INIT_LIST_HEAD(&ac->queues);
ac->ap_dev.device.release = ap_card_device_release;
ac->ap_dev.device.type = &ap_card_type;
ac->ap_dev.device_type = device_type;
/* CEX6 toleration: map to CEX5 */
if (device_type == AP_DEVICE_TYPE_CEX6)
ac->ap_dev.device_type = AP_DEVICE_TYPE_CEX5;
ac->raw_hwtype = device_type;
ac->queue_depth = queue_depth;
ac->functions = functions;
ac->id = id;
return ac;
}

View File

@ -0,0 +1,700 @@
/*
* Copyright IBM Corp. 2016
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*
* Adjunct processor bus, queue related code.
*/
#define KMSG_COMPONENT "ap"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/facility.h>
#include "ap_bus.h"
#include "ap_asm.h"
/**
* ap_queue_enable_interruption(): Enable interruption on an AP queue.
* @qid: The AP queue number
* @ind: the notification indicator byte
*
* Enables interruption on AP queue via ap_aqic(). Based on the return
* value it waits a while and tests the AP queue if interrupts
* have been switched on using ap_test_queue().
*/
static int ap_queue_enable_interruption(struct ap_queue *aq, void *ind)
{
struct ap_queue_status status;
status = ap_aqic(aq->qid, ind);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
case AP_RESPONSE_OTHERWISE_CHANGED:
return 0;
case AP_RESPONSE_Q_NOT_AVAIL:
case AP_RESPONSE_DECONFIGURED:
case AP_RESPONSE_CHECKSTOPPED:
case AP_RESPONSE_INVALID_ADDRESS:
pr_err("Registering adapter interrupts for AP device %02x.%04x failed\n",
AP_QID_CARD(aq->qid),
AP_QID_QUEUE(aq->qid));
return -EOPNOTSUPP;
case AP_RESPONSE_RESET_IN_PROGRESS:
case AP_RESPONSE_BUSY:
default:
return -EBUSY;
}
}
/**
* __ap_send(): Send message to adjunct processor queue.
* @qid: The AP queue number
* @psmid: The program supplied message identifier
* @msg: The message text
* @length: The message length
* @special: Special Bit
*
* Returns AP queue status structure.
* Condition code 1 on NQAP can't happen because the L bit is 1.
* Condition code 2 on NQAP also means the send is incomplete,
* because a segment boundary was reached. The NQAP is repeated.
*/
static inline struct ap_queue_status
__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
unsigned int special)
{
if (special == 1)
qid |= 0x400000UL;
return ap_nqap(qid, psmid, msg, length);
}
int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
{
struct ap_queue_status status;
status = __ap_send(qid, psmid, msg, length, 0);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
return 0;
case AP_RESPONSE_Q_FULL:
case AP_RESPONSE_RESET_IN_PROGRESS:
return -EBUSY;
case AP_RESPONSE_REQ_FAC_NOT_INST:
return -EINVAL;
default: /* Device is gone. */
return -ENODEV;
}
}
EXPORT_SYMBOL(ap_send);
int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
{
struct ap_queue_status status;
if (msg == NULL)
return -EINVAL;
status = ap_dqap(qid, psmid, msg, length);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
return 0;
case AP_RESPONSE_NO_PENDING_REPLY:
if (status.queue_empty)
return -ENOENT;
return -EBUSY;
case AP_RESPONSE_RESET_IN_PROGRESS:
return -EBUSY;
default:
return -ENODEV;
}
}
EXPORT_SYMBOL(ap_recv);
/* State machine definitions and helpers */
static enum ap_wait ap_sm_nop(struct ap_queue *aq)
{
return AP_WAIT_NONE;
}
/**
* ap_sm_recv(): Receive pending reply messages from an AP queue but do
* not change the state of the device.
* @aq: pointer to the AP queue
*
* Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
*/
static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
status = ap_dqap(aq->qid, &aq->reply->psmid,
aq->reply->message, aq->reply->length);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
aq->queue_count--;
if (aq->queue_count > 0)
mod_timer(&aq->timeout,
jiffies + aq->request_timeout);
list_for_each_entry(ap_msg, &aq->pendingq, list) {
if (ap_msg->psmid != aq->reply->psmid)
continue;
list_del_init(&ap_msg->list);
aq->pendingq_count--;
ap_msg->receive(aq, ap_msg, aq->reply);
break;
}
case AP_RESPONSE_NO_PENDING_REPLY:
if (!status.queue_empty || aq->queue_count <= 0)
break;
/* The card shouldn't forget requests but who knows. */
aq->queue_count = 0;
list_splice_init(&aq->pendingq, &aq->requestq);
aq->requestq_count += aq->pendingq_count;
aq->pendingq_count = 0;
break;
default:
break;
}
return status;
}
/**
* ap_sm_read(): Receive pending reply messages from an AP queue.
* @aq: pointer to the AP queue
*
* Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
*/
static enum ap_wait ap_sm_read(struct ap_queue *aq)
{
struct ap_queue_status status;
if (!aq->reply)
return AP_WAIT_NONE;
status = ap_sm_recv(aq);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
if (aq->queue_count > 0) {
aq->state = AP_STATE_WORKING;
return AP_WAIT_AGAIN;
}
aq->state = AP_STATE_IDLE;
return AP_WAIT_NONE;
case AP_RESPONSE_NO_PENDING_REPLY:
if (aq->queue_count > 0)
return AP_WAIT_INTERRUPT;
aq->state = AP_STATE_IDLE;
return AP_WAIT_NONE;
default:
aq->state = AP_STATE_BORKED;
return AP_WAIT_NONE;
}
}
/**
* ap_sm_suspend_read(): Receive pending reply messages from an AP queue
* without changing the device state in between. In suspend mode we don't
* allow sending new requests, therefore just fetch pending replies.
* @aq: pointer to the AP queue
*
* Returns AP_WAIT_NONE or AP_WAIT_AGAIN
*/
static enum ap_wait ap_sm_suspend_read(struct ap_queue *aq)
{
struct ap_queue_status status;
if (!aq->reply)
return AP_WAIT_NONE;
status = ap_sm_recv(aq);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
if (aq->queue_count > 0)
return AP_WAIT_AGAIN;
/* fall through */
default:
return AP_WAIT_NONE;
}
}
/**
* ap_sm_write(): Send messages from the request queue to an AP queue.
* @aq: pointer to the AP queue
*
* Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
*/
static enum ap_wait ap_sm_write(struct ap_queue *aq)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
if (aq->requestq_count <= 0)
return AP_WAIT_NONE;
/* Start the next request on the queue. */
ap_msg = list_entry(aq->requestq.next, struct ap_message, list);
status = __ap_send(aq->qid, ap_msg->psmid,
ap_msg->message, ap_msg->length, ap_msg->special);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
aq->queue_count++;
if (aq->queue_count == 1)
mod_timer(&aq->timeout, jiffies + aq->request_timeout);
list_move_tail(&ap_msg->list, &aq->pendingq);
aq->requestq_count--;
aq->pendingq_count++;
if (aq->queue_count < aq->card->queue_depth) {
aq->state = AP_STATE_WORKING;
return AP_WAIT_AGAIN;
}
/* fall through */
case AP_RESPONSE_Q_FULL:
aq->state = AP_STATE_QUEUE_FULL;
return AP_WAIT_INTERRUPT;
case AP_RESPONSE_RESET_IN_PROGRESS:
aq->state = AP_STATE_RESET_WAIT;
return AP_WAIT_TIMEOUT;
case AP_RESPONSE_MESSAGE_TOO_BIG:
case AP_RESPONSE_REQ_FAC_NOT_INST:
list_del_init(&ap_msg->list);
aq->requestq_count--;
ap_msg->rc = -EINVAL;
ap_msg->receive(aq, ap_msg, NULL);
return AP_WAIT_AGAIN;
default:
aq->state = AP_STATE_BORKED;
return AP_WAIT_NONE;
}
}
/**
* ap_sm_read_write(): Send and receive messages to/from an AP queue.
* @aq: pointer to the AP queue
*
* Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
*/
static enum ap_wait ap_sm_read_write(struct ap_queue *aq)
{
return min(ap_sm_read(aq), ap_sm_write(aq));
}
/**
* ap_sm_reset(): Reset an AP queue.
* @qid: The AP queue number
*
* Submit the Reset command to an AP queue.
*/
static enum ap_wait ap_sm_reset(struct ap_queue *aq)
{
struct ap_queue_status status;
status = ap_rapq(aq->qid);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
case AP_RESPONSE_RESET_IN_PROGRESS:
aq->state = AP_STATE_RESET_WAIT;
aq->interrupt = AP_INTR_DISABLED;
return AP_WAIT_TIMEOUT;
case AP_RESPONSE_BUSY:
return AP_WAIT_TIMEOUT;
case AP_RESPONSE_Q_NOT_AVAIL:
case AP_RESPONSE_DECONFIGURED:
case AP_RESPONSE_CHECKSTOPPED:
default:
aq->state = AP_STATE_BORKED;
return AP_WAIT_NONE;
}
}
/**
* ap_sm_reset_wait(): Test queue for completion of the reset operation
* @aq: pointer to the AP queue
*
* Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0.
*/
static enum ap_wait ap_sm_reset_wait(struct ap_queue *aq)
{
struct ap_queue_status status;
void *lsi_ptr;
if (aq->queue_count > 0 && aq->reply)
/* Try to read a completed message and get the status */
status = ap_sm_recv(aq);
else
/* Get the status with TAPQ */
status = ap_tapq(aq->qid, NULL);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
lsi_ptr = ap_airq_ptr();
if (lsi_ptr && ap_queue_enable_interruption(aq, lsi_ptr) == 0)
aq->state = AP_STATE_SETIRQ_WAIT;
else
aq->state = (aq->queue_count > 0) ?
AP_STATE_WORKING : AP_STATE_IDLE;
return AP_WAIT_AGAIN;
case AP_RESPONSE_BUSY:
case AP_RESPONSE_RESET_IN_PROGRESS:
return AP_WAIT_TIMEOUT;
case AP_RESPONSE_Q_NOT_AVAIL:
case AP_RESPONSE_DECONFIGURED:
case AP_RESPONSE_CHECKSTOPPED:
default:
aq->state = AP_STATE_BORKED;
return AP_WAIT_NONE;
}
}
/**
* ap_sm_setirq_wait(): Test queue for completion of the irq enablement
* @aq: pointer to the AP queue
*
* Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0.
*/
static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq)
{
struct ap_queue_status status;
if (aq->queue_count > 0 && aq->reply)
/* Try to read a completed message and get the status */
status = ap_sm_recv(aq);
else
/* Get the status with TAPQ */
status = ap_tapq(aq->qid, NULL);
if (status.int_enabled == 1) {
/* Irqs are now enabled */
aq->interrupt = AP_INTR_ENABLED;
aq->state = (aq->queue_count > 0) ?
AP_STATE_WORKING : AP_STATE_IDLE;
}
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
if (aq->queue_count > 0)
return AP_WAIT_AGAIN;
/* fallthrough */
case AP_RESPONSE_NO_PENDING_REPLY:
return AP_WAIT_TIMEOUT;
default:
aq->state = AP_STATE_BORKED;
return AP_WAIT_NONE;
}
}
/*
* AP state machine jump table
*/
static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = {
[AP_STATE_RESET_START] = {
[AP_EVENT_POLL] = ap_sm_reset,
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
[AP_STATE_RESET_WAIT] = {
[AP_EVENT_POLL] = ap_sm_reset_wait,
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
[AP_STATE_SETIRQ_WAIT] = {
[AP_EVENT_POLL] = ap_sm_setirq_wait,
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
[AP_STATE_IDLE] = {
[AP_EVENT_POLL] = ap_sm_write,
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
[AP_STATE_WORKING] = {
[AP_EVENT_POLL] = ap_sm_read_write,
[AP_EVENT_TIMEOUT] = ap_sm_reset,
},
[AP_STATE_QUEUE_FULL] = {
[AP_EVENT_POLL] = ap_sm_read,
[AP_EVENT_TIMEOUT] = ap_sm_reset,
},
[AP_STATE_SUSPEND_WAIT] = {
[AP_EVENT_POLL] = ap_sm_suspend_read,
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
[AP_STATE_BORKED] = {
[AP_EVENT_POLL] = ap_sm_nop,
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
};
enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event)
{
return ap_jumptable[aq->state][event](aq);
}
enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event)
{
enum ap_wait wait;
while ((wait = ap_sm_event(aq, event)) == AP_WAIT_AGAIN)
;
return wait;
}
/*
* Power management for queue devices
*/
void ap_queue_suspend(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
/* Poll on the device until all requests are finished. */
spin_lock_bh(&aq->lock);
aq->state = AP_STATE_SUSPEND_WAIT;
while (ap_sm_event(aq, AP_EVENT_POLL) != AP_WAIT_NONE)
;
aq->state = AP_STATE_BORKED;
spin_unlock_bh(&aq->lock);
}
EXPORT_SYMBOL(ap_queue_suspend);
void ap_queue_resume(struct ap_device *ap_dev)
{
}
EXPORT_SYMBOL(ap_queue_resume);
/*
* AP queue related attributes.
*/
static ssize_t ap_request_count_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ap_queue *aq = to_ap_queue(dev);
unsigned int req_cnt;
spin_lock_bh(&aq->lock);
req_cnt = aq->total_request_count;
spin_unlock_bh(&aq->lock);
return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt);
}
static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
static ssize_t ap_requestq_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_queue *aq = to_ap_queue(dev);
unsigned int reqq_cnt = 0;
spin_lock_bh(&aq->lock);
reqq_cnt = aq->requestq_count;
spin_unlock_bh(&aq->lock);
return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt);
}
static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL);
static ssize_t ap_pendingq_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_queue *aq = to_ap_queue(dev);
unsigned int penq_cnt = 0;
spin_lock_bh(&aq->lock);
penq_cnt = aq->pendingq_count;
spin_unlock_bh(&aq->lock);
return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt);
}
static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL);
static ssize_t ap_reset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_queue *aq = to_ap_queue(dev);
int rc = 0;
spin_lock_bh(&aq->lock);
switch (aq->state) {
case AP_STATE_RESET_START:
case AP_STATE_RESET_WAIT:
rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n");
break;
case AP_STATE_WORKING:
case AP_STATE_QUEUE_FULL:
rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n");
break;
default:
rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n");
}
spin_unlock_bh(&aq->lock);
return rc;
}
static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL);
static ssize_t ap_interrupt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_queue *aq = to_ap_queue(dev);
int rc = 0;
spin_lock_bh(&aq->lock);
if (aq->state == AP_STATE_SETIRQ_WAIT)
rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n");
else if (aq->interrupt == AP_INTR_ENABLED)
rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n");
else
rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n");
spin_unlock_bh(&aq->lock);
return rc;
}
static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL);
static struct attribute *ap_queue_dev_attrs[] = {
&dev_attr_request_count.attr,
&dev_attr_requestq_count.attr,
&dev_attr_pendingq_count.attr,
&dev_attr_reset.attr,
&dev_attr_interrupt.attr,
NULL
};
static struct attribute_group ap_queue_dev_attr_group = {
.attrs = ap_queue_dev_attrs
};
static const struct attribute_group *ap_queue_dev_attr_groups[] = {
&ap_queue_dev_attr_group,
NULL
};
struct device_type ap_queue_type = {
.name = "ap_queue",
.groups = ap_queue_dev_attr_groups,
};
static void ap_queue_device_release(struct device *dev)
{
kfree(to_ap_queue(dev));
}
struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)
{
struct ap_queue *aq;
aq = kzalloc(sizeof(*aq), GFP_KERNEL);
if (!aq)
return NULL;
aq->ap_dev.device.release = ap_queue_device_release;
aq->ap_dev.device.type = &ap_queue_type;
aq->ap_dev.device_type = device_type;
/* CEX6 toleration: map to CEX5 */
if (device_type == AP_DEVICE_TYPE_CEX6)
aq->ap_dev.device_type = AP_DEVICE_TYPE_CEX5;
aq->qid = qid;
aq->state = AP_STATE_RESET_START;
aq->interrupt = AP_INTR_DISABLED;
spin_lock_init(&aq->lock);
INIT_LIST_HEAD(&aq->pendingq);
INIT_LIST_HEAD(&aq->requestq);
setup_timer(&aq->timeout, ap_request_timeout, (unsigned long) aq);
return aq;
}
void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *reply)
{
aq->reply = reply;
spin_lock_bh(&aq->lock);
ap_wait(ap_sm_event(aq, AP_EVENT_POLL));
spin_unlock_bh(&aq->lock);
}
EXPORT_SYMBOL(ap_queue_init_reply);
/**
* ap_queue_message(): Queue a request to an AP device.
* @aq: The AP device to queue the message to
* @ap_msg: The message that is to be added
*/
void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg)
{
/* For asynchronous message handling a valid receive-callback
* is required.
*/
BUG_ON(!ap_msg->receive);
spin_lock_bh(&aq->lock);
/* Queue the message. */
list_add_tail(&ap_msg->list, &aq->requestq);
aq->requestq_count++;
aq->total_request_count++;
/* Send/receive as many request from the queue as possible. */
ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL));
spin_unlock_bh(&aq->lock);
}
EXPORT_SYMBOL(ap_queue_message);
/**
* ap_cancel_message(): Cancel a crypto request.
* @aq: The AP device that has the message queued
* @ap_msg: The message that is to be removed
*
* Cancel a crypto request. This is done by removing the request
* from the device pending or request queue. Note that the
* request stays on the AP queue. When it finishes the message
* reply will be discarded because the psmid can't be found.
*/
void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg)
{
struct ap_message *tmp;
spin_lock_bh(&aq->lock);
if (!list_empty(&ap_msg->list)) {
list_for_each_entry(tmp, &aq->pendingq, list)
if (tmp->psmid == ap_msg->psmid) {
aq->pendingq_count--;
goto found;
}
aq->requestq_count--;
found:
list_del_init(&ap_msg->list);
}
spin_unlock_bh(&aq->lock);
}
EXPORT_SYMBOL(ap_cancel_message);
/**
* __ap_flush_queue(): Flush requests.
* @aq: Pointer to the AP queue
*
* Flush all requests from the request/pending queue of an AP device.
*/
static void __ap_flush_queue(struct ap_queue *aq)
{
struct ap_message *ap_msg, *next;
list_for_each_entry_safe(ap_msg, next, &aq->pendingq, list) {
list_del_init(&ap_msg->list);
aq->pendingq_count--;
ap_msg->rc = -EAGAIN;
ap_msg->receive(aq, ap_msg, NULL);
}
list_for_each_entry_safe(ap_msg, next, &aq->requestq, list) {
list_del_init(&ap_msg->list);
aq->requestq_count--;
ap_msg->rc = -EAGAIN;
ap_msg->receive(aq, ap_msg, NULL);
}
}
void ap_flush_queue(struct ap_queue *aq)
{
spin_lock_bh(&aq->lock);
__ap_flush_queue(aq);
spin_unlock_bh(&aq->lock);
}
EXPORT_SYMBOL(ap_flush_queue);
void ap_queue_remove(struct ap_queue *aq)
{
ap_flush_queue(aq);
del_timer_sync(&aq->timeout);
}
EXPORT_SYMBOL(ap_queue_remove);

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@ struct ica_z90_status {
* Identifier for Crypto Request Performance Index
*/
enum crypto_ops {
MEX_1K = 0,
MEX_1K,
MEX_2K,
MEX_4K,
CRT_1K,
@ -99,43 +99,56 @@ enum crypto_ops {
NUM_OPS
};
struct zcrypt_device;
struct zcrypt_queue;
struct zcrypt_ops {
long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
long (*rsa_modexpo_crt)(struct zcrypt_device *,
long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *);
long (*rsa_modexpo_crt)(struct zcrypt_queue *,
struct ica_rsa_modexpo_crt *);
long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *,
long (*send_cprb)(struct zcrypt_queue *, struct ica_xcRB *,
struct ap_message *);
long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *,
long (*send_ep11_cprb)(struct zcrypt_queue *, struct ep11_urb *,
struct ap_message *);
long (*rng)(struct zcrypt_device *, char *, struct ap_message *);
long (*rng)(struct zcrypt_queue *, char *, struct ap_message *);
struct list_head list; /* zcrypt ops list. */
struct module *owner;
int variant;
char name[128];
};
struct zcrypt_device {
struct zcrypt_card {
struct list_head list; /* Device list. */
spinlock_t lock; /* Per device lock. */
struct list_head zqueues; /* List of zcrypt queues */
struct kref refcount; /* device refcounting */
struct ap_device *ap_dev; /* The "real" ap device. */
struct zcrypt_ops *ops; /* Crypto operations. */
struct ap_card *card; /* The "real" ap card device. */
int online; /* User online/offline */
int user_space_type; /* User space device id. */
char *type_string; /* User space device name. */
int min_mod_size; /* Min number of bits. */
int max_mod_size; /* Max number of bits. */
int short_crt; /* Card has crt length restriction. */
int max_exp_bit_length;
int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */
int load; /* Utilization of the crypto device */
atomic_t load; /* Utilization of the crypto device */
int request_count; /* # current requests. */
debug_info_t *dbf_area; /* debugging */
};
struct zcrypt_queue {
struct list_head list; /* Device list. */
struct kref refcount; /* device refcounting */
struct zcrypt_card *zcard;
struct zcrypt_ops *ops; /* Crypto operations. */
struct ap_queue *queue; /* The "real" ap queue device. */
int online; /* User online/offline */
atomic_t load; /* Utilization of the crypto device */
int request_count; /* # current requests. */
struct ap_message reply; /* Per-device reply structure. */
int max_exp_bit_length;
debug_info_t *dbf_area; /* debugging */
};
@ -143,12 +156,43 @@ struct zcrypt_device {
/* transport layer rescanning */
extern atomic_t zcrypt_rescan_req;
struct zcrypt_device *zcrypt_device_alloc(size_t);
void zcrypt_device_free(struct zcrypt_device *);
void zcrypt_device_get(struct zcrypt_device *);
int zcrypt_device_put(struct zcrypt_device *);
int zcrypt_device_register(struct zcrypt_device *);
void zcrypt_device_unregister(struct zcrypt_device *);
extern spinlock_t zcrypt_list_lock;
extern int zcrypt_device_count;
extern struct list_head zcrypt_card_list;
extern debug_info_t *zcrypt_dbf_common;
extern debug_info_t *zcrypt_dbf_devices;
extern debug_info_t *zcrypt_dbf_cards;
#define for_each_zcrypt_card(_zc) \
list_for_each_entry(_zc, &zcrypt_card_list, list)
#define for_each_zcrypt_queue(_zq, _zc) \
list_for_each_entry(_zq, &(_zc)->zqueues, list)
struct zcrypt_card *zcrypt_card_alloc(void);
void zcrypt_card_free(struct zcrypt_card *);
void zcrypt_card_get(struct zcrypt_card *);
int zcrypt_card_put(struct zcrypt_card *);
int zcrypt_card_register(struct zcrypt_card *);
void zcrypt_card_unregister(struct zcrypt_card *);
struct zcrypt_card *zcrypt_card_get_best(unsigned int *,
unsigned int, unsigned int);
void zcrypt_card_put_best(struct zcrypt_card *, unsigned int);
struct zcrypt_queue *zcrypt_queue_alloc(size_t);
void zcrypt_queue_free(struct zcrypt_queue *);
void zcrypt_queue_get(struct zcrypt_queue *);
int zcrypt_queue_put(struct zcrypt_queue *);
int zcrypt_queue_register(struct zcrypt_queue *);
void zcrypt_queue_unregister(struct zcrypt_queue *);
void zcrypt_queue_force_online(struct zcrypt_queue *, int);
struct zcrypt_queue *zcrypt_queue_get_best(unsigned int, unsigned int);
void zcrypt_queue_put_best(struct zcrypt_queue *, unsigned int);
int zcrypt_rng_device_add(void);
void zcrypt_rng_device_remove(void);
void zcrypt_msgtype_register(struct zcrypt_ops *);
void zcrypt_msgtype_unregister(struct zcrypt_ops *);
struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int);

View File

@ -0,0 +1,181 @@
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
* Cornelia Huck <cornelia.huck@de.ibm.com>
*
* Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
* Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/compat.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <linux/uaccess.h>
#include <linux/hw_random.h>
#include <linux/debugfs.h>
#include <asm/debug.h>
#include "zcrypt_debug.h"
#include "zcrypt_api.h"
#include "zcrypt_msgtype6.h"
#include "zcrypt_msgtype50.h"
/*
* Device attributes common for all crypto card devices.
*/
static ssize_t zcrypt_card_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct zcrypt_card *zc = to_ap_card(dev)->private;
return snprintf(buf, PAGE_SIZE, "%s\n", zc->type_string);
}
static DEVICE_ATTR(type, 0444, zcrypt_card_type_show, NULL);
static ssize_t zcrypt_card_online_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct zcrypt_card *zc = to_ap_card(dev)->private;
return snprintf(buf, PAGE_SIZE, "%d\n", zc->online);
}
static ssize_t zcrypt_card_online_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct zcrypt_card *zc = to_ap_card(dev)->private;
struct zcrypt_queue *zq;
int online, id;
if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
return -EINVAL;
zc->online = online;
id = zc->card->id;
ZCRYPT_DBF_DEV(DBF_INFO, zc, "card%02xo%dman", id, online);
spin_lock(&zcrypt_list_lock);
list_for_each_entry(zq, &zc->zqueues, list)
zcrypt_queue_force_online(zq, online);
spin_unlock(&zcrypt_list_lock);
return count;
}
static DEVICE_ATTR(online, 0644, zcrypt_card_online_show,
zcrypt_card_online_store);
static struct attribute *zcrypt_card_attrs[] = {
&dev_attr_type.attr,
&dev_attr_online.attr,
NULL,
};
static struct attribute_group zcrypt_card_attr_group = {
.attrs = zcrypt_card_attrs,
};
struct zcrypt_card *zcrypt_card_alloc(void)
{
struct zcrypt_card *zc;
zc = kzalloc(sizeof(struct zcrypt_card), GFP_KERNEL);
if (!zc)
return NULL;
INIT_LIST_HEAD(&zc->list);
INIT_LIST_HEAD(&zc->zqueues);
zc->dbf_area = zcrypt_dbf_cards;
kref_init(&zc->refcount);
return zc;
}
EXPORT_SYMBOL(zcrypt_card_alloc);
void zcrypt_card_free(struct zcrypt_card *zc)
{
kfree(zc);
}
EXPORT_SYMBOL(zcrypt_card_free);
static void zcrypt_card_release(struct kref *kref)
{
struct zcrypt_card *zdev =
container_of(kref, struct zcrypt_card, refcount);
zcrypt_card_free(zdev);
}
void zcrypt_card_get(struct zcrypt_card *zc)
{
kref_get(&zc->refcount);
}
EXPORT_SYMBOL(zcrypt_card_get);
int zcrypt_card_put(struct zcrypt_card *zc)
{
return kref_put(&zc->refcount, zcrypt_card_release);
}
EXPORT_SYMBOL(zcrypt_card_put);
/**
* zcrypt_card_register() - Register a crypto card device.
* @zc: Pointer to a crypto card device
*
* Register a crypto card device. Returns 0 if successful.
*/
int zcrypt_card_register(struct zcrypt_card *zc)
{
int rc;
rc = sysfs_create_group(&zc->card->ap_dev.device.kobj,
&zcrypt_card_attr_group);
if (rc)
return rc;
spin_lock(&zcrypt_list_lock);
list_add_tail(&zc->list, &zcrypt_card_list);
spin_unlock(&zcrypt_list_lock);
zc->online = 1;
return rc;
}
EXPORT_SYMBOL(zcrypt_card_register);
/**
* zcrypt_card_unregister(): Unregister a crypto card device.
* @zc: Pointer to crypto card device
*
* Unregister a crypto card device.
*/
void zcrypt_card_unregister(struct zcrypt_card *zc)
{
spin_lock(&zcrypt_list_lock);
list_del_init(&zc->list);
spin_unlock(&zcrypt_list_lock);
sysfs_remove_group(&zc->card->ap_dev.device.kobj,
&zcrypt_card_attr_group);
}
EXPORT_SYMBOL(zcrypt_card_unregister);

View File

@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/atomic.h>
#include <asm/uaccess.h>
#include <linux/mod_devicetable.h>
#include "ap_bus.h"
#include "zcrypt_api.h"
@ -54,108 +55,195 @@
#define CEX2A_CLEANUP_TIME (15*HZ)
#define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME
static struct ap_device_id zcrypt_cex2a_ids[] = {
{ AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
{ AP_DEVICE(AP_DEVICE_TYPE_CEX3A) },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids);
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \
"Copyright IBM Corp. 2001, 2012");
MODULE_LICENSE("GPL");
static int zcrypt_cex2a_probe(struct ap_device *ap_dev);
static void zcrypt_cex2a_remove(struct ap_device *ap_dev);
static struct ap_driver zcrypt_cex2a_driver = {
.probe = zcrypt_cex2a_probe,
.remove = zcrypt_cex2a_remove,
.ids = zcrypt_cex2a_ids,
.request_timeout = CEX2A_CLEANUP_TIME,
static struct ap_device_id zcrypt_cex2a_card_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX2A,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3A,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_card_ids);
static struct ap_device_id zcrypt_cex2a_queue_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX2A,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3A,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_queue_ids);
/**
* Probe function for CEX2A cards. It always accepts the AP device
* since the bus_match already checked the hardware type.
* Probe function for CEX2A card devices. It always accepts the AP device
* since the bus_match already checked the card type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev = NULL;
int CEX2A_SPEED_IDX[] = { 800, 1000, 2000, 900, 1200, 2400, 0};
int CEX3A_SPEED_IDX[] = { 400, 500, 1000, 450, 550, 1200, 0};
/*
* Normalized speed ratings per crypto adapter
* MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
*/
static const int CEX2A_SPEED_IDX[] = {
800, 1000, 2000, 900, 1200, 2400, 0, 0};
static const int CEX3A_SPEED_IDX[] = {
400, 500, 1000, 450, 550, 1200, 0, 0};
struct ap_card *ac = to_ap_card(&ap_dev->device);
struct zcrypt_card *zc;
int rc = 0;
switch (ap_dev->device_type) {
case AP_DEVICE_TYPE_CEX2A:
zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
if (!zdev)
return -ENOMEM;
zdev->user_space_type = ZCRYPT_CEX2A;
zdev->type_string = "CEX2A";
zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
zdev->short_crt = 1;
memcpy(zdev->speed_rating, CEX2A_SPEED_IDX,
zc = zcrypt_card_alloc();
if (!zc)
return -ENOMEM;
zc->card = ac;
ac->private = zc;
if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) {
zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
memcpy(zc->speed_rating, CEX2A_SPEED_IDX,
sizeof(CEX2A_SPEED_IDX));
zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
break;
case AP_DEVICE_TYPE_CEX3A:
zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE);
if (!zdev)
return -ENOMEM;
zdev->user_space_type = ZCRYPT_CEX3A;
zdev->type_string = "CEX3A";
zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) {
zdev->max_mod_size = CEX3A_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
zc->type_string = "CEX2A";
zc->user_space_type = ZCRYPT_CEX2A;
} else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX3A) {
zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) {
zc->max_mod_size = CEX3A_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
}
zdev->short_crt = 1;
memcpy(zdev->speed_rating, CEX3A_SPEED_IDX,
memcpy(zc->speed_rating, CEX3A_SPEED_IDX,
sizeof(CEX3A_SPEED_IDX));
break;
}
if (!zdev)
zc->type_string = "CEX3A";
zc->user_space_type = ZCRYPT_CEX3A;
} else {
zcrypt_card_free(zc);
return -ENODEV;
zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
zdev->ap_dev = ap_dev;
zdev->online = 1;
zdev->load = zdev->speed_rating[0];
ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc) {
ap_dev->private = NULL;
zcrypt_device_free(zdev);
}
zc->online = 1;
rc = zcrypt_card_register(zc);
if (rc) {
ac->private = NULL;
zcrypt_card_free(zc);
}
return rc;
}
/**
* This is called to remove the extended CEX2A driver information
* if an AP device is removed.
* This is called to remove the CEX2A card driver information
* if an AP card device is removed.
*/
static void zcrypt_cex2a_remove(struct ap_device *ap_dev)
static void zcrypt_cex2a_card_remove(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev = ap_dev->private;
struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
zcrypt_device_unregister(zdev);
if (zc)
zcrypt_card_unregister(zc);
}
static struct ap_driver zcrypt_cex2a_card_driver = {
.probe = zcrypt_cex2a_card_probe,
.remove = zcrypt_cex2a_card_remove,
.ids = zcrypt_cex2a_card_ids,
};
/**
* Probe function for CEX2A queue devices. It always accepts the AP device
* since the bus_match already checked the queue type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq = NULL;
int rc;
switch (ap_dev->device_type) {
case AP_DEVICE_TYPE_CEX2A:
zq = zcrypt_queue_alloc(CEX2A_MAX_RESPONSE_SIZE);
if (!zq)
return -ENOMEM;
break;
case AP_DEVICE_TYPE_CEX3A:
zq = zcrypt_queue_alloc(CEX3A_MAX_RESPONSE_SIZE);
if (!zq)
return -ENOMEM;
break;
}
if (!zq)
return -ENODEV;
zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
zq->queue = aq;
zq->online = 1;
atomic_set(&zq->load, 0);
ap_queue_init_reply(aq, &zq->reply);
aq->request_timeout = CEX2A_CLEANUP_TIME,
aq->private = zq;
rc = zcrypt_queue_register(zq);
if (rc) {
aq->private = NULL;
zcrypt_queue_free(zq);
}
return rc;
}
/**
* This is called to remove the CEX2A queue driver information
* if an AP queue device is removed.
*/
static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq = aq->private;
ap_queue_remove(aq);
if (zq)
zcrypt_queue_unregister(zq);
}
static struct ap_driver zcrypt_cex2a_queue_driver = {
.probe = zcrypt_cex2a_queue_probe,
.remove = zcrypt_cex2a_queue_remove,
.suspend = ap_queue_suspend,
.resume = ap_queue_resume,
.ids = zcrypt_cex2a_queue_ids,
};
int __init zcrypt_cex2a_init(void)
{
return ap_driver_register(&zcrypt_cex2a_driver, THIS_MODULE, "cex2a");
int rc;
rc = ap_driver_register(&zcrypt_cex2a_card_driver,
THIS_MODULE, "cex2acard");
if (rc)
return rc;
rc = ap_driver_register(&zcrypt_cex2a_queue_driver,
THIS_MODULE, "cex2aqueue");
if (rc)
ap_driver_unregister(&zcrypt_cex2a_card_driver);
return rc;
}
void __exit zcrypt_cex2a_exit(void)
{
ap_driver_unregister(&zcrypt_cex2a_driver);
ap_driver_unregister(&zcrypt_cex2a_queue_driver);
ap_driver_unregister(&zcrypt_cex2a_card_driver);
}
module_init(zcrypt_cex2a_init);

View File

@ -9,6 +9,7 @@
#include <linux/err.h>
#include <linux/atomic.h>
#include <linux/uaccess.h>
#include <linux/mod_devicetable.h>
#include "ap_bus.h"
#include "zcrypt_api.h"
@ -34,160 +35,246 @@
*/
#define CEX4_CLEANUP_TIME (900*HZ)
static struct ap_device_id zcrypt_cex4_ids[] = {
{ AP_DEVICE(AP_DEVICE_TYPE_CEX4) },
{ AP_DEVICE(AP_DEVICE_TYPE_CEX5) },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_cex4_ids);
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \
"Copyright IBM Corp. 2012");
MODULE_LICENSE("GPL");
static int zcrypt_cex4_probe(struct ap_device *ap_dev);
static void zcrypt_cex4_remove(struct ap_device *ap_dev);
static struct ap_driver zcrypt_cex4_driver = {
.probe = zcrypt_cex4_probe,
.remove = zcrypt_cex4_remove,
.ids = zcrypt_cex4_ids,
.request_timeout = CEX4_CLEANUP_TIME,
static struct ap_device_id zcrypt_cex4_card_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX4,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX5,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_cex4_card_ids);
static struct ap_device_id zcrypt_cex4_queue_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX4,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX5,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids);
/**
* Probe function for CEX4 cards. It always accepts the AP device
* Probe function for CEX4 card device. It always accepts the AP device
* since the bus_match already checked the hardware type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex4_probe(struct ap_device *ap_dev)
static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev = NULL;
/*
* Normalized speed ratings per crypto adapter
* MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
*/
int CEX4A_SPEED_IDX[] = { 5, 6, 59, 20, 115, 581, 0, 0};
int CEX5A_SPEED_IDX[] = { 3, 3, 6, 8, 32, 218, 0, 0};
int CEX4C_SPEED_IDX[] = { 24, 25, 82, 41, 138, 1111, 79, 8};
int CEX5C_SPEED_IDX[] = { 10, 14, 23, 17, 45, 242, 63, 4};
int CEX4P_SPEED_IDX[] = {142, 198, 1852, 203, 331, 1563, 0, 8};
int CEX5P_SPEED_IDX[] = { 49, 67, 131, 52, 85, 287, 0, 4};
static const int CEX4A_SPEED_IDX[] = {
5, 6, 59, 20, 115, 581, 0, 0};
static const int CEX5A_SPEED_IDX[] = {
3, 3, 6, 8, 32, 218, 0, 0};
static const int CEX4C_SPEED_IDX[] = {
24, 25, 82, 41, 138, 1111, 79, 8};
static const int CEX5C_SPEED_IDX[] = {
10, 14, 23, 17, 45, 242, 63, 4};
static const int CEX4P_SPEED_IDX[] = {
142, 198, 1852, 203, 331, 1563, 0, 8};
static const int CEX5P_SPEED_IDX[] = {
49, 67, 131, 52, 85, 287, 0, 4};
struct ap_card *ac = to_ap_card(&ap_dev->device);
struct zcrypt_card *zc;
int rc = 0;
switch (ap_dev->device_type) {
case AP_DEVICE_TYPE_CEX4:
case AP_DEVICE_TYPE_CEX5:
if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) {
zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE);
if (!zdev)
return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4A";
memcpy(zdev->speed_rating, CEX4A_SPEED_IDX,
sizeof(CEX4A_SPEED_IDX));
} else {
zdev->type_string = "CEX5A";
memcpy(zdev->speed_rating, CEX5A_SPEED_IDX,
sizeof(CEX5A_SPEED_IDX));
}
zdev->user_space_type = ZCRYPT_CEX3A;
zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) {
zdev->max_mod_size =
CEX4A_MAX_MOD_SIZE_4K;
zdev->max_exp_bit_length =
CEX4A_MAX_MOD_SIZE_4K;
} else {
zdev->max_mod_size =
CEX4A_MAX_MOD_SIZE_2K;
zdev->max_exp_bit_length =
CEX4A_MAX_MOD_SIZE_2K;
}
zdev->short_crt = 1;
zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME,
MSGTYPE50_VARIANT_DEFAULT);
} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) {
zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
if (!zdev)
return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4C";
memcpy(zdev->speed_rating, CEX4C_SPEED_IDX,
sizeof(CEX4C_SPEED_IDX));
} else {
zdev->type_string = "CEX5C";
memcpy(zdev->speed_rating, CEX5C_SPEED_IDX,
sizeof(CEX5C_SPEED_IDX));
}
zdev->user_space_type = ZCRYPT_CEX3C;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
zdev->short_crt = 0;
zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_DEFAULT);
} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) {
zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
if (!zdev)
return -ENOMEM;
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
zdev->type_string = "CEX4P";
memcpy(zdev->speed_rating, CEX4P_SPEED_IDX,
sizeof(CEX4P_SPEED_IDX));
} else {
zdev->type_string = "CEX5P";
memcpy(zdev->speed_rating, CEX5P_SPEED_IDX,
sizeof(CEX5P_SPEED_IDX));
}
zdev->user_space_type = ZCRYPT_CEX4;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
zdev->short_crt = 0;
zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_EP11);
zc = zcrypt_card_alloc();
if (!zc)
return -ENOMEM;
zc->card = ac;
ac->private = zc;
if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) {
if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
zc->type_string = "CEX4A";
zc->user_space_type = ZCRYPT_CEX4;
memcpy(zc->speed_rating, CEX4A_SPEED_IDX,
sizeof(CEX4A_SPEED_IDX));
} else {
zc->type_string = "CEX5A";
zc->user_space_type = ZCRYPT_CEX5;
memcpy(zc->speed_rating, CEX5A_SPEED_IDX,
sizeof(CEX5A_SPEED_IDX));
}
break;
}
if (!zdev)
zc->min_mod_size = CEX4A_MIN_MOD_SIZE;
if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) {
zc->max_mod_size = CEX4A_MAX_MOD_SIZE_4K;
zc->max_exp_bit_length =
CEX4A_MAX_MOD_SIZE_4K;
} else {
zc->max_mod_size = CEX4A_MAX_MOD_SIZE_2K;
zc->max_exp_bit_length =
CEX4A_MAX_MOD_SIZE_2K;
}
} else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) {
if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
zc->type_string = "CEX4C";
/* wrong user space type, must be CEX4
* just keep it for cca compatibility
*/
zc->user_space_type = ZCRYPT_CEX3C;
memcpy(zc->speed_rating, CEX4C_SPEED_IDX,
sizeof(CEX4C_SPEED_IDX));
} else {
zc->type_string = "CEX5C";
/* wrong user space type, must be CEX5
* just keep it for cca compatibility
*/
zc->user_space_type = ZCRYPT_CEX3C;
memcpy(zc->speed_rating, CEX5C_SPEED_IDX,
sizeof(CEX5C_SPEED_IDX));
}
zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
zc->max_mod_size = CEX4C_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
} else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) {
if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
zc->type_string = "CEX4P";
zc->user_space_type = ZCRYPT_CEX4;
memcpy(zc->speed_rating, CEX4P_SPEED_IDX,
sizeof(CEX4P_SPEED_IDX));
} else {
zc->type_string = "CEX5P";
zc->user_space_type = ZCRYPT_CEX5;
memcpy(zc->speed_rating, CEX5P_SPEED_IDX,
sizeof(CEX5P_SPEED_IDX));
}
zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
zc->max_mod_size = CEX4C_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
} else {
zcrypt_card_free(zc);
return -ENODEV;
zdev->ap_dev = ap_dev;
zdev->online = 1;
zdev->load = zdev->speed_rating[0];
ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc) {
ap_dev->private = NULL;
zcrypt_device_free(zdev);
}
zc->online = 1;
rc = zcrypt_card_register(zc);
if (rc) {
ac->private = NULL;
zcrypt_card_free(zc);
}
return rc;
}
/**
* This is called to remove the extended CEX4 driver information
* if an AP device is removed.
* This is called to remove the CEX4 card driver information
* if an AP card device is removed.
*/
static void zcrypt_cex4_remove(struct ap_device *ap_dev)
static void zcrypt_cex4_card_remove(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev = ap_dev->private;
struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
if (zdev) {
zcrypt_device_unregister(zdev);
}
if (zc)
zcrypt_card_unregister(zc);
}
static struct ap_driver zcrypt_cex4_card_driver = {
.probe = zcrypt_cex4_card_probe,
.remove = zcrypt_cex4_card_remove,
.ids = zcrypt_cex4_card_ids,
};
/**
* Probe function for CEX4 queue device. It always accepts the AP device
* since the bus_match already checked the hardware type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq;
int rc;
if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) {
zq = zcrypt_queue_alloc(CEX4A_MAX_MESSAGE_SIZE);
if (!zq)
return -ENOMEM;
zq->ops = zcrypt_msgtype(MSGTYPE50_NAME,
MSGTYPE50_VARIANT_DEFAULT);
} else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) {
zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
if (!zq)
return -ENOMEM;
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_DEFAULT);
} else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) {
zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
if (!zq)
return -ENOMEM;
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_EP11);
} else {
return -ENODEV;
}
zq->queue = aq;
zq->online = 1;
atomic_set(&zq->load, 0);
ap_queue_init_reply(aq, &zq->reply);
aq->request_timeout = CEX4_CLEANUP_TIME,
aq->private = zq;
rc = zcrypt_queue_register(zq);
if (rc) {
aq->private = NULL;
zcrypt_queue_free(zq);
}
return rc;
}
/**
* This is called to remove the CEX4 queue driver information
* if an AP queue device is removed.
*/
static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq = aq->private;
ap_queue_remove(aq);
if (zq)
zcrypt_queue_unregister(zq);
}
static struct ap_driver zcrypt_cex4_queue_driver = {
.probe = zcrypt_cex4_queue_probe,
.remove = zcrypt_cex4_queue_remove,
.suspend = ap_queue_suspend,
.resume = ap_queue_resume,
.ids = zcrypt_cex4_queue_ids,
};
int __init zcrypt_cex4_init(void)
{
return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4");
int rc;
rc = ap_driver_register(&zcrypt_cex4_card_driver,
THIS_MODULE, "cex4card");
if (rc)
return rc;
rc = ap_driver_register(&zcrypt_cex4_queue_driver,
THIS_MODULE, "cex4queue");
if (rc)
ap_driver_unregister(&zcrypt_cex4_card_driver);
return rc;
}
void __exit zcrypt_cex4_exit(void)
{
ap_driver_unregister(&zcrypt_cex4_driver);
ap_driver_unregister(&zcrypt_cex4_queue_driver);
ap_driver_unregister(&zcrypt_cex4_card_driver);
}
module_init(zcrypt_cex4_init);

View File

@ -87,7 +87,7 @@ struct error_hdr {
#define REP88_ERROR_OPERAND 0x84 /* CEX2A */
#define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */
static inline int convert_error(struct zcrypt_device *zdev,
static inline int convert_error(struct zcrypt_queue *zq,
struct ap_message *reply)
{
struct error_hdr *ehdr = reply->message;
@ -110,11 +110,13 @@ static inline int convert_error(struct zcrypt_device *zdev,
* and then repeat the request.
*/
atomic_set(&zcrypt_rescan_req, 1);
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), zq->online,
ehdr->reply_code);
return -EAGAIN;
case REP82_ERROR_TRANSPORT_FAIL:
@ -122,19 +124,23 @@ static inline int convert_error(struct zcrypt_device *zdev,
// REP88_ERROR_MODULE_FAILURE // '10' CEX2A
/* If a card fails disable it and repeat the request. */
atomic_set(&zcrypt_rescan_req, 1);
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), zq->online,
ehdr->reply_code);
return -EAGAIN;
default:
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), zq->online,
ehdr->reply_code);
return -EAGAIN; /* repeat the request on a different device. */
}

View File

@ -53,9 +53,6 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
"Copyright IBM Corp. 2001, 2012");
MODULE_LICENSE("GPL");
static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
struct ap_message *);
/**
* The type 50 message family is associated with a CEX2A card.
*
@ -208,13 +205,13 @@ unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode)
/**
* Convert a ICAMEX message to a type50 MEX message.
*
* @zdev: crypto device pointer
* @zreq: crypto request pointer
* @zq: crypto queue pointer
* @ap_msg: crypto request pointer
* @mex: pointer to user input data
*
* Returns 0 on success or -EFAULT.
*/
static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq,
struct ap_message *ap_msg,
struct ica_rsa_modexpo *mex)
{
@ -266,13 +263,13 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
/**
* Convert a ICACRT message to a type50 CRT message.
*
* @zdev: crypto device pointer
* @zreq: crypto request pointer
* @zq: crypto queue pointer
* @ap_msg: crypto request pointer
* @crt: pointer to user input data
*
* Returns 0 on success or -EFAULT.
*/
static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq,
struct ap_message *ap_msg,
struct ica_rsa_modexpo_crt *crt)
{
@ -315,7 +312,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
u = crb2->u + sizeof(crb2->u) - short_len;
inp = crb2->message + sizeof(crb2->message) - mod_len;
} else if ((mod_len <= 512) && /* up to 4096 bit key size */
(zdev->max_mod_size == CEX3A_MAX_MOD_SIZE)) { /* >= CEX3A */
(zq->zcard->max_mod_size == CEX3A_MAX_MOD_SIZE)) {
struct type50_crb3_msg *crb3 = ap_msg->message;
memset(crb3, 0, sizeof(*crb3));
ap_msg->length = sizeof(*crb3);
@ -349,14 +346,14 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
/**
* Copy results from a type 80 reply message back to user space.
*
* @zdev: crypto device pointer
* @zq: crypto device pointer
* @reply: reply AP message.
* @data: pointer to user output data
* @length: size of user output data
*
* Returns 0 on success or -EFAULT.
*/
static int convert_type80(struct zcrypt_device *zdev,
static int convert_type80(struct zcrypt_queue *zq,
struct ap_message *reply,
char __user *outputdata,
unsigned int outputdatalength)
@ -366,16 +363,18 @@ static int convert_type80(struct zcrypt_device *zdev,
if (t80h->len < sizeof(*t80h) + outputdatalength) {
/* The result is too short, the CEX2A card may not do that.. */
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
AP_QID_DEVICE(zdev->ap_dev->qid),
zdev->online, t80h->code);
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online, t80h->code);
return -EAGAIN; /* repeat the request on a different device. */
}
if (zdev->user_space_type == ZCRYPT_CEX2A)
if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
else
BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
@ -385,7 +384,7 @@ static int convert_type80(struct zcrypt_device *zdev,
return 0;
}
static int convert_response(struct zcrypt_device *zdev,
static int convert_response(struct zcrypt_queue *zq,
struct ap_message *reply,
char __user *outputdata,
unsigned int outputdatalength)
@ -394,16 +393,19 @@ static int convert_response(struct zcrypt_device *zdev,
switch (((unsigned char *) reply->message)[1]) {
case TYPE82_RSP_CODE:
case TYPE88_RSP_CODE:
return convert_error(zdev, reply);
return convert_error(zq, reply);
case TYPE80_RSP_CODE:
return convert_type80(zdev, reply,
return convert_type80(zq, reply,
outputdata, outputdatalength);
default: /* Unknown response type, this should NEVER EVER happen */
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online);
return -EAGAIN; /* repeat the request on a different device. */
}
}
@ -412,11 +414,11 @@ static int convert_response(struct zcrypt_device *zdev,
* This function is called from the AP bus code after a crypto request
* "msg" has finished with the reply message "reply".
* It is called from tasklet context.
* @ap_dev: pointer to the AP device
* @aq: pointer to the AP device
* @msg: pointer to the AP message
* @reply: pointer to the AP reply message
*/
static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
static void zcrypt_cex2a_receive(struct ap_queue *aq,
struct ap_message *msg,
struct ap_message *reply)
{
@ -432,7 +434,7 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
goto out; /* ap_msg->rc indicates the error */
t80h = reply->message;
if (t80h->type == TYPE80_RSP_CODE) {
if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A)
if (aq->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A)
length = min_t(int,
CEX2A_MAX_RESPONSE_SIZE, t80h->len);
else
@ -450,11 +452,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
/**
* The request distributor calls this function if it picked the CEX2A
* device to handle a modexpo request.
* @zdev: pointer to zcrypt_device structure that identifies the
* @zq: pointer to zcrypt_queue structure that identifies the
* CEX2A device to the request distributor
* @mex: pointer to the modexpo request buffer
*/
static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
struct ica_rsa_modexpo *mex)
{
struct ap_message ap_msg;
@ -462,7 +464,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
int rc;
ap_init_message(&ap_msg);
if (zdev->user_space_type == ZCRYPT_CEX2A)
if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE,
GFP_KERNEL);
else
@ -474,20 +476,20 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &work;
rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex);
rc = ICAMEX_msg_to_type50MEX_msg(zq, &ap_msg, mex);
if (rc)
goto out_free;
init_completion(&work);
ap_queue_message(zdev->ap_dev, &ap_msg);
ap_queue_message(zq->queue, &ap_msg);
rc = wait_for_completion_interruptible(&work);
if (rc == 0) {
rc = ap_msg.rc;
if (rc == 0)
rc = convert_response(zdev, &ap_msg, mex->outputdata,
rc = convert_response(zq, &ap_msg, mex->outputdata,
mex->outputdatalength);
} else
/* Signal pending. */
ap_cancel_message(zdev->ap_dev, &ap_msg);
ap_cancel_message(zq->queue, &ap_msg);
out_free:
kfree(ap_msg.message);
return rc;
@ -496,11 +498,11 @@ out_free:
/**
* The request distributor calls this function if it picked the CEX2A
* device to handle a modexpo_crt request.
* @zdev: pointer to zcrypt_device structure that identifies the
* @zq: pointer to zcrypt_queue structure that identifies the
* CEX2A device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
*/
static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
struct ica_rsa_modexpo_crt *crt)
{
struct ap_message ap_msg;
@ -508,7 +510,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
int rc;
ap_init_message(&ap_msg);
if (zdev->user_space_type == ZCRYPT_CEX2A)
if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE,
GFP_KERNEL);
else
@ -520,20 +522,20 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &work;
rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt);
rc = ICACRT_msg_to_type50CRT_msg(zq, &ap_msg, crt);
if (rc)
goto out_free;
init_completion(&work);
ap_queue_message(zdev->ap_dev, &ap_msg);
ap_queue_message(zq->queue, &ap_msg);
rc = wait_for_completion_interruptible(&work);
if (rc == 0) {
rc = ap_msg.rc;
if (rc == 0)
rc = convert_response(zdev, &ap_msg, crt->outputdata,
rc = convert_response(zq, &ap_msg, crt->outputdata,
crt->outputdatalength);
} else
/* Signal pending. */
ap_cancel_message(zdev->ap_dev, &ap_msg);
ap_cancel_message(zq->queue, &ap_msg);
out_free:
kfree(ap_msg.message);
return rc;

View File

@ -60,9 +60,6 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
"Copyright IBM Corp. 2001, 2012");
MODULE_LICENSE("GPL");
static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *,
struct ap_message *);
/**
* CPRB
* Note that all shorts, ints and longs are little-endian.
@ -258,13 +255,13 @@ int speed_idx_ep11(int req_type)
/**
* Convert a ICAMEX message to a type6 MEX message.
*
* @zdev: crypto device pointer
* @zq: crypto device pointer
* @ap_msg: pointer to AP message
* @mex: pointer to user input data
*
* Returns 0 on success or -EFAULT.
*/
static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq,
struct ap_message *ap_msg,
struct ica_rsa_modexpo *mex)
{
@ -279,11 +276,6 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
.ulen = 10,
.only_rule = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '}
};
static struct function_and_rules_block static_pke_fnr_MCL2 = {
.function_code = {'P', 'K'},
.ulen = 10,
.only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
};
struct {
struct type6_hdr hdr;
struct CPRBX cprbx;
@ -310,11 +302,10 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->cprbx = static_cprbx;
msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
static_pke_fnr_MCL2 : static_pke_fnr;
msg->fr = static_pke_fnr;
msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
@ -325,13 +316,13 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
/**
* Convert a ICACRT message to a type6 CRT message.
*
* @zdev: crypto device pointer
* @zq: crypto device pointer
* @ap_msg: pointer to AP message
* @crt: pointer to user input data
*
* Returns 0 on success or -EFAULT.
*/
static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq,
struct ap_message *ap_msg,
struct ica_rsa_modexpo_crt *crt)
{
@ -347,11 +338,6 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
.only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
};
static struct function_and_rules_block static_pkd_fnr_MCL2 = {
.function_code = {'P', 'D'},
.ulen = 10,
.only_rule = {'P', 'K', 'C', 'S', '-', '1', '.', '2'}
};
struct {
struct type6_hdr hdr;
struct CPRBX cprbx;
@ -378,12 +364,11 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->cprbx = static_cprbx;
msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
size - sizeof(msg->hdr) - sizeof(msg->cprbx);
msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
static_pkd_fnr_MCL2 : static_pkd_fnr;
msg->fr = static_pkd_fnr;
ap_msg->length = size;
return 0;
@ -392,7 +377,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
/**
* Convert a XCRB message to a type6 CPRB message.
*
* @zdev: crypto device pointer
* @zq: crypto device pointer
* @ap_msg: pointer to AP message
* @xcRB: pointer to user input data
*
@ -405,7 +390,8 @@ struct type86_fmt2_msg {
static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
struct ica_xcRB *xcRB,
unsigned int *fcode)
unsigned int *fcode,
unsigned short **dom)
{
static struct type6_hdr static_type6_hdrX = {
.type = 0x06,
@ -486,6 +472,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
sizeof(msg->hdr.function_code));
*fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1];
*dom = (unsigned short *)&msg->cprbx.domain;
if (memcmp(function_code, "US", 2) == 0)
ap_msg->special = 1;
@ -497,6 +484,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
copy_from_user(req_data, xcRB->request_data_address,
xcRB->request_data_length))
return -EFAULT;
return 0;
}
@ -504,6 +492,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
struct ep11_urb *xcRB,
unsigned int *fcode)
{
unsigned int lfmt;
static struct type6_hdr static_type6_ep11_hdr = {
.type = 0x06,
.rqid = {0x00, 0x01},
@ -556,14 +545,30 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
return -EFAULT;
}
*fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF);
if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
switch (msg->pld_lenfmt & 0x03) {
case 1:
lfmt = 2;
break;
case 2:
lfmt = 3;
break;
default:
return -EINVAL;
}
} else {
lfmt = 1; /* length format #1 */
}
payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
*fcode = payload_hdr->func_val & 0xFFFF;
return 0;
}
/**
* Copy results from a type 86 ICA reply message back to user space.
*
* @zdev: crypto device pointer
* @zq: crypto device pointer
* @reply: reply AP message.
* @data: pointer to user output data
* @length: size of user output data
@ -585,7 +590,7 @@ struct type86_ep11_reply {
struct ep11_cprb cprbx;
} __packed;
static int convert_type86_ica(struct zcrypt_device *zdev,
static int convert_type86_ica(struct zcrypt_queue *zq,
struct ap_message *reply,
char __user *outputdata,
unsigned int outputdatalength)
@ -640,18 +645,22 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
if (service_rc == 8 && service_rs == 770)
return -EINVAL;
if (service_rc == 8 && service_rs == 783) {
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
zq->zcard->min_mod_size =
PCIXCC_MIN_MOD_SIZE_OLD;
return -EAGAIN;
}
if (service_rc == 12 && service_rs == 769)
return -EINVAL;
if (service_rc == 8 && service_rs == 72)
return -EINVAL;
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online,
msg->hdr.reply_code);
return -EAGAIN; /* repeat the request on a different device. */
}
@ -688,13 +697,13 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
/**
* Copy results from a type 86 XCRB reply message back to user space.
*
* @zdev: crypto device pointer
* @zq: crypto device pointer
* @reply: reply AP message.
* @xcRB: pointer to XCRB
*
* Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
*/
static int convert_type86_xcrb(struct zcrypt_device *zdev,
static int convert_type86_xcrb(struct zcrypt_queue *zq,
struct ap_message *reply,
struct ica_xcRB *xcRB)
{
@ -719,13 +728,13 @@ static int convert_type86_xcrb(struct zcrypt_device *zdev,
/**
* Copy results from a type 86 EP11 XCRB reply message back to user space.
*
* @zdev: crypto device pointer
* @zq: crypto device pointer
* @reply: reply AP message.
* @xcRB: pointer to EP11 user request block
*
* Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
*/
static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev,
static int convert_type86_ep11_xcrb(struct zcrypt_queue *zq,
struct ap_message *reply,
struct ep11_urb *xcRB)
{
@ -743,7 +752,7 @@ static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev,
return 0;
}
static int convert_type86_rng(struct zcrypt_device *zdev,
static int convert_type86_rng(struct zcrypt_queue *zq,
struct ap_message *reply,
char *buffer)
{
@ -760,7 +769,7 @@ static int convert_type86_rng(struct zcrypt_device *zdev,
return msg->fmt2.count2;
}
static int convert_response_ica(struct zcrypt_device *zdev,
static int convert_response_ica(struct zcrypt_queue *zq,
struct ap_message *reply,
char __user *outputdata,
unsigned int outputdatalength)
@ -771,35 +780,38 @@ static int convert_response_ica(struct zcrypt_device *zdev,
switch (((unsigned char *) reply->message)[1]) {
case TYPE82_RSP_CODE:
case TYPE88_RSP_CODE:
return convert_error(zdev, reply);
return convert_error(zq, reply);
case TYPE86_RSP_CODE:
if (msg->cprbx.ccp_rtcode &&
(msg->cprbx.ccp_rscode == 0x14f) &&
(outputdatalength > 256)) {
if (zdev->max_exp_bit_length <= 17) {
zdev->max_exp_bit_length = 17;
if (zq->zcard->max_exp_bit_length <= 17) {
zq->zcard->max_exp_bit_length = 17;
return -EAGAIN;
} else
return -EINVAL;
}
if (msg->hdr.reply_code)
return convert_error(zdev, reply);
return convert_error(zq, reply);
if (msg->cprbx.cprb_ver_id == 0x02)
return convert_type86_ica(zdev, reply,
return convert_type86_ica(zq, reply,
outputdata, outputdatalength);
/* Fall through, no break, incorrect cprb version is an unknown
* response */
default: /* Unknown response type, this should NEVER EVER happen */
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online);
return -EAGAIN; /* repeat the request on a different device. */
}
}
static int convert_response_xcrb(struct zcrypt_device *zdev,
static int convert_response_xcrb(struct zcrypt_queue *zq,
struct ap_message *reply,
struct ica_xcRB *xcRB)
{
@ -810,28 +822,31 @@ static int convert_response_xcrb(struct zcrypt_device *zdev,
case TYPE82_RSP_CODE:
case TYPE88_RSP_CODE:
xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
return convert_error(zdev, reply);
return convert_error(zq, reply);
case TYPE86_RSP_CODE:
if (msg->hdr.reply_code) {
memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
return convert_error(zdev, reply);
return convert_error(zq, reply);
}
if (msg->cprbx.cprb_ver_id == 0x02)
return convert_type86_xcrb(zdev, reply, xcRB);
return convert_type86_xcrb(zq, reply, xcRB);
/* Fall through, no break, incorrect cprb version is an unknown
* response */
default: /* Unknown response type, this should NEVER EVER happen */
xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online);
return -EAGAIN; /* repeat the request on a different device. */
}
}
static int convert_response_ep11_xcrb(struct zcrypt_device *zdev,
static int convert_response_ep11_xcrb(struct zcrypt_queue *zq,
struct ap_message *reply, struct ep11_urb *xcRB)
{
struct type86_ep11_reply *msg = reply->message;
@ -840,24 +855,27 @@ static int convert_response_ep11_xcrb(struct zcrypt_device *zdev,
switch (((unsigned char *)reply->message)[1]) {
case TYPE82_RSP_CODE:
case TYPE87_RSP_CODE:
return convert_error(zdev, reply);
return convert_error(zq, reply);
case TYPE86_RSP_CODE:
if (msg->hdr.reply_code)
return convert_error(zdev, reply);
return convert_error(zq, reply);
if (msg->cprbx.cprb_ver_id == 0x04)
return convert_type86_ep11_xcrb(zdev, reply, xcRB);
return convert_type86_ep11_xcrb(zq, reply, xcRB);
/* Fall through, no break, incorrect cprb version is an unknown resp.*/
default: /* Unknown response type, this should NEVER EVER happen */
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online);
return -EAGAIN; /* repeat the request on a different device. */
}
}
static int convert_response_rng(struct zcrypt_device *zdev,
static int convert_response_rng(struct zcrypt_queue *zq,
struct ap_message *reply,
char *data)
{
@ -871,15 +889,18 @@ static int convert_response_rng(struct zcrypt_device *zdev,
if (msg->hdr.reply_code)
return -EINVAL;
if (msg->cprbx.cprb_ver_id == 0x02)
return convert_type86_rng(zdev, reply, data);
return convert_type86_rng(zq, reply, data);
/* Fall through, no break, incorrect cprb version is an unknown
* response */
default: /* Unknown response type, this should NEVER EVER happen */
zdev->online = 0;
pr_err("Cryptographic device %x failed and was set offline\n",
AP_QID_DEVICE(zdev->ap_dev->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid));
ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online);
return -EAGAIN; /* repeat the request on a different device. */
}
}
@ -888,11 +909,11 @@ static int convert_response_rng(struct zcrypt_device *zdev,
* This function is called from the AP bus code after a crypto request
* "msg" has finished with the reply message "reply".
* It is called from tasklet context.
* @ap_dev: pointer to the AP device
* @aq: pointer to the AP queue
* @msg: pointer to the AP message
* @reply: pointer to the AP reply message
*/
static void zcrypt_msgtype6_receive(struct ap_device *ap_dev,
static void zcrypt_msgtype6_receive(struct ap_queue *aq,
struct ap_message *msg,
struct ap_message *reply)
{
@ -937,11 +958,11 @@ out:
* This function is called from the AP bus code after a crypto request
* "msg" has finished with the reply message "reply".
* It is called from tasklet context.
* @ap_dev: pointer to the AP device
* @aq: pointer to the AP queue
* @msg: pointer to the AP message
* @reply: pointer to the AP reply message
*/
static void zcrypt_msgtype6_receive_ep11(struct ap_device *ap_dev,
static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
struct ap_message *msg,
struct ap_message *reply)
{
@ -981,11 +1002,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to handle a modexpo request.
* @zdev: pointer to zcrypt_device structure that identifies the
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* @mex: pointer to the modexpo request buffer
*/
static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev,
static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
struct ica_rsa_modexpo *mex)
{
struct ap_message ap_msg;
@ -1002,21 +1023,21 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev,
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &resp_type;
rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
rc = ICAMEX_msg_to_type6MEX_msgX(zq, &ap_msg, mex);
if (rc)
goto out_free;
init_completion(&resp_type.work);
ap_queue_message(zdev->ap_dev, &ap_msg);
ap_queue_message(zq->queue, &ap_msg);
rc = wait_for_completion_interruptible(&resp_type.work);
if (rc == 0) {
rc = ap_msg.rc;
if (rc == 0)
rc = convert_response_ica(zdev, &ap_msg,
rc = convert_response_ica(zq, &ap_msg,
mex->outputdata,
mex->outputdatalength);
} else
/* Signal pending. */
ap_cancel_message(zdev->ap_dev, &ap_msg);
ap_cancel_message(zq->queue, &ap_msg);
out_free:
free_page((unsigned long) ap_msg.message);
return rc;
@ -1025,11 +1046,11 @@ out_free:
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to handle a modexpo_crt request.
* @zdev: pointer to zcrypt_device structure that identifies the
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
*/
static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
struct ica_rsa_modexpo_crt *crt)
{
struct ap_message ap_msg;
@ -1046,21 +1067,22 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg.private = &resp_type;
rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
rc = ICACRT_msg_to_type6CRT_msgX(zq, &ap_msg, crt);
if (rc)
goto out_free;
init_completion(&resp_type.work);
ap_queue_message(zdev->ap_dev, &ap_msg);
ap_queue_message(zq->queue, &ap_msg);
rc = wait_for_completion_interruptible(&resp_type.work);
if (rc == 0) {
rc = ap_msg.rc;
if (rc == 0)
rc = convert_response_ica(zdev, &ap_msg,
rc = convert_response_ica(zq, &ap_msg,
crt->outputdata,
crt->outputdatalength);
} else
} else {
/* Signal pending. */
ap_cancel_message(zdev->ap_dev, &ap_msg);
ap_cancel_message(zq->queue, &ap_msg);
}
out_free:
free_page((unsigned long) ap_msg.message);
return rc;
@ -1068,7 +1090,7 @@ out_free:
unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
struct ap_message *ap_msg,
int *func_code)
unsigned int *func_code, unsigned short **dom)
{
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_XCRB,
@ -1088,7 +1110,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
return -ENOMEM;
}
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code);
rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom);
if (rc) {
kzfree(ap_msg->message);
kzfree(ap_msg->private);
@ -1099,11 +1121,11 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to handle a send_cprb request.
* @zdev: pointer to zcrypt_device structure that identifies the
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* @xcRB: pointer to the send_cprb request buffer
*/
static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq,
struct ica_xcRB *xcRB,
struct ap_message *ap_msg)
{
@ -1111,15 +1133,15 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
struct response_type *rtype = (struct response_type *)(ap_msg->private);
init_completion(&rtype->work);
ap_queue_message(zdev->ap_dev, ap_msg);
ap_queue_message(zq->queue, ap_msg);
rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
rc = convert_response_xcrb(zdev, ap_msg, xcRB);
rc = convert_response_xcrb(zq, ap_msg, xcRB);
} else
/* Signal pending. */
ap_cancel_message(zdev->ap_dev, ap_msg);
ap_cancel_message(zq->queue, ap_msg);
kzfree(ap_msg->message);
kzfree(ap_msg->private);
@ -1128,7 +1150,7 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
struct ap_message *ap_msg,
int *func_code)
unsigned int *func_code)
{
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_EP11,
@ -1159,11 +1181,11 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
/**
* The request distributor calls this function if it picked the CEX4P
* device to handle a send_ep11_cprb request.
* @zdev: pointer to zcrypt_device structure that identifies the
* @zq: pointer to zcrypt_queue structure that identifies the
* CEX4P device to the request distributor
* @xcRB: pointer to the ep11 user request block
*/
static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_queue *zq,
struct ep11_urb *xcrb,
struct ap_message *ap_msg)
{
@ -1196,7 +1218,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
*/
if (!((msg->cprbx.flags & 0x80) == 0x80)) {
msg->cprbx.target_id = (unsigned int)
AP_QID_QUEUE(zdev->ap_dev->qid);
AP_QID_QUEUE(zq->queue->qid);
if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
switch (msg->pld_lenfmt & 0x03) {
@ -1214,26 +1236,27 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
}
payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
payload_hdr->dom_val = (unsigned int)
AP_QID_QUEUE(zdev->ap_dev->qid);
AP_QID_QUEUE(zq->queue->qid);
}
init_completion(&rtype->work);
ap_queue_message(zdev->ap_dev, ap_msg);
ap_queue_message(zq->queue, ap_msg);
rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb);
rc = convert_response_ep11_xcrb(zq, ap_msg, xcrb);
} else
/* Signal pending. */
ap_cancel_message(zdev->ap_dev, ap_msg);
ap_cancel_message(zq->queue, ap_msg);
kzfree(ap_msg->message);
kzfree(ap_msg->private);
return rc;
}
unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
unsigned int *domain)
{
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_XCRB,
@ -1253,7 +1276,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
}
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain);
*func_code = HWRNG;
return 0;
@ -1262,11 +1285,11 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to generate random data.
* @zdev: pointer to zcrypt_device structure that identifies the
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* @buffer: pointer to a memory page to return random data
*/
static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
char *buffer, struct ap_message *ap_msg)
{
struct {
@ -1281,18 +1304,18 @@ static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
struct response_type *rtype = (struct response_type *)(ap_msg->private);
int rc;
msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
init_completion(&rtype->work);
ap_queue_message(zdev->ap_dev, ap_msg);
ap_queue_message(zq->queue, ap_msg);
rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
rc = convert_response_rng(zdev, ap_msg, buffer);
rc = convert_response_rng(zq, ap_msg, buffer);
} else
/* Signal pending. */
ap_cancel_message(zdev->ap_dev, ap_msg);
ap_cancel_message(zq->queue, ap_msg);
kzfree(ap_msg->message);
kzfree(ap_msg->private);

View File

@ -116,9 +116,11 @@ struct type86_fmt2_ext {
unsigned int offset4; /* 0x00000000 */
} __packed;
unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, int *);
unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, int *);
unsigned int get_rng_fc(struct ap_message *, int *);
unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *,
unsigned int *, unsigned short **);
unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *,
unsigned int *);
unsigned int get_rng_fc(struct ap_message *, int *, unsigned int *);
#define LOW 10
#define MEDIUM 100
@ -134,7 +136,8 @@ int speed_idx_ep11(int);
* @ap_msg: pointer to AP message
*/
static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg,
unsigned int random_number_length)
unsigned int random_number_length,
unsigned int *domain)
{
struct {
struct type6_hdr hdr;
@ -172,6 +175,7 @@ static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg,
msg->verb_length = 0x02;
msg->key_length = 0x02;
ap_msg->length = sizeof(*msg);
*domain = (unsigned short)msg->cprbx.domain;
}
void zcrypt_msgtype6_init(void);

View File

@ -32,6 +32,7 @@
#include <linux/slab.h>
#include <linux/atomic.h>
#include <asm/uaccess.h>
#include <linux/mod_devicetable.h>
#include "ap_bus.h"
#include "zcrypt_api.h"
@ -62,142 +63,34 @@ struct response_type {
#define PCIXCC_RESPONSE_TYPE_ICA 0
#define PCIXCC_RESPONSE_TYPE_XCRB 1
static struct ap_device_id zcrypt_pcixcc_ids[] = {
{ AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
{ AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
{ AP_DEVICE(AP_DEVICE_TYPE_CEX3C) },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \
"Copyright IBM Corp. 2001, 2012");
MODULE_LICENSE("GPL");
static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
static struct ap_driver zcrypt_pcixcc_driver = {
.probe = zcrypt_pcixcc_probe,
.remove = zcrypt_pcixcc_remove,
.ids = zcrypt_pcixcc_ids,
.request_timeout = PCIXCC_CLEANUP_TIME,
static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_PCIXCC,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ /* end of list */ },
};
/**
* Micro-code detection function. Its sends a message to a pcixcc card
* to find out the microcode level.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
{
static unsigned char msg[] = {
0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
0xF1,0x3D,0x93,0x53
};
unsigned long long psmid;
struct CPRBX *cprbx;
char *reply;
int rc, i;
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids);
reply = (void *) get_zeroed_page(GFP_KERNEL);
if (!reply)
return -ENOMEM;
static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_PCIXCC,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ /* end of list */ },
};
rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
if (rc)
goto out_free;
/* Wait for the test message to complete. */
for (i = 0; i < 6; i++) {
msleep(300);
rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
if (rc == 0 && psmid == 0x0102030405060708ULL)
break;
}
if (i >= 6) {
/* Got no answer. */
rc = -ENODEV;
goto out_free;
}
cprbx = (struct CPRBX *) (reply + 48);
if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
rc = ZCRYPT_PCIXCC_MCL2;
else
rc = ZCRYPT_PCIXCC_MCL3;
out_free:
free_page((unsigned long) reply);
return rc;
}
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids);
/**
* Large random number detection function. Its sends a message to a pcixcc
@ -206,10 +99,11 @@ out_free:
*
* Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
*/
static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq)
{
struct ap_message ap_msg;
unsigned long long psmid;
unsigned int domain;
struct {
struct type86_hdr hdr;
struct type86_fmt2_ext fmt2;
@ -231,12 +125,12 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
if (!ap_msg.message)
return -ENOMEM;
rng_type6CPRB_msgX(&ap_msg, 4);
rng_type6CPRB_msgX(&ap_msg, 4, &domain);
msg = ap_msg.message;
msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
msg->cprbx.domain = AP_QID_QUEUE(aq->qid);
rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message,
rc = ap_send(aq->qid, 0x0102030405060708ULL, ap_msg.message,
ap_msg.length);
if (rc)
goto out_free;
@ -244,7 +138,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
/* Wait for the test message to complete. */
for (i = 0; i < 2 * HZ; i++) {
msleep(1000 / HZ);
rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096);
rc = ap_recv(aq->qid, &psmid, ap_msg.message, 4096);
if (rc == 0 && psmid == 0x0102030405060708ULL)
break;
}
@ -266,120 +160,168 @@ out_free:
}
/**
* Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
* since the bus_match already checked the hardware type. The PCIXCC
* cards come in two flavours: micro code level 2 and micro code level 3.
* This is checked by sending a test message to the device.
* @ap_dev: pointer to the AP device.
* Probe function for PCIXCC/CEX2C card devices. It always accepts the
* AP device since the bus_match already checked the hardware type. The
* PCIXCC cards come in two flavours: micro code level 2 and micro code
* level 3. This is checked by sending a test message to the device.
* @ap_dev: pointer to the AP card device.
*/
static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev;
/*
* Normalized speed ratings per crypto adapter
* MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
*/
int PCIXCC_MCL2_SPEED_IDX[] = {10, 10, 10, 10, 10, 10, 10, 10};
int PCIXCC_MCL3_SPEED_IDX[] = { 8, 8, 8, 8, 8, 8, 8, 8};
int CEX2C_SPEED_IDX[] = {1000, 1400, 2400, 1100, 1500, 2600, 100, 12};
int CEX3C_SPEED_IDX[] = { 500, 700, 1400, 550, 800, 1500, 80, 10};
static const int CEX2C_SPEED_IDX[] = {
1000, 1400, 2400, 1100, 1500, 2600, 100, 12};
static const int CEX3C_SPEED_IDX[] = {
500, 700, 1400, 550, 800, 1500, 80, 10};
struct ap_card *ac = to_ap_card(&ap_dev->device);
struct zcrypt_card *zc;
int rc = 0;
zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
if (!zdev)
zc = zcrypt_card_alloc();
if (!zc)
return -ENOMEM;
zdev->ap_dev = ap_dev;
zdev->online = 1;
switch (ap_dev->device_type) {
case AP_DEVICE_TYPE_PCIXCC:
rc = zcrypt_pcixcc_mcl(ap_dev);
if (rc < 0) {
zcrypt_device_free(zdev);
return rc;
}
zdev->user_space_type = rc;
if (rc == ZCRYPT_PCIXCC_MCL2) {
zdev->type_string = "PCIXCC_MCL2";
memcpy(zdev->speed_rating, PCIXCC_MCL2_SPEED_IDX,
sizeof(PCIXCC_MCL2_SPEED_IDX));
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
} else {
zdev->type_string = "PCIXCC_MCL3";
memcpy(zdev->speed_rating, PCIXCC_MCL3_SPEED_IDX,
sizeof(PCIXCC_MCL3_SPEED_IDX));
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
}
break;
zc->card = ac;
ac->private = zc;
switch (ac->ap_dev.device_type) {
case AP_DEVICE_TYPE_CEX2C:
zdev->user_space_type = ZCRYPT_CEX2C;
zdev->type_string = "CEX2C";
memcpy(zdev->speed_rating, CEX2C_SPEED_IDX,
zc->user_space_type = ZCRYPT_CEX2C;
zc->type_string = "CEX2C";
memcpy(zc->speed_rating, CEX2C_SPEED_IDX,
sizeof(CEX2C_SPEED_IDX));
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
zc->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zc->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
break;
case AP_DEVICE_TYPE_CEX3C:
zdev->user_space_type = ZCRYPT_CEX3C;
zdev->type_string = "CEX3C";
memcpy(zdev->speed_rating, CEX3C_SPEED_IDX,
zc->user_space_type = ZCRYPT_CEX3C;
zc->type_string = "CEX3C";
memcpy(zc->speed_rating, CEX3C_SPEED_IDX,
sizeof(CEX3C_SPEED_IDX));
zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
zc->min_mod_size = CEX3C_MIN_MOD_SIZE;
zc->max_mod_size = CEX3C_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
break;
default:
goto out_free;
zcrypt_card_free(zc);
return -ENODEV;
}
zdev->load = zdev->speed_rating[0];
zc->online = 1;
rc = zcrypt_pcixcc_rng_supported(ap_dev);
if (rc < 0) {
zcrypt_device_free(zdev);
return rc;
rc = zcrypt_card_register(zc);
if (rc) {
ac->private = NULL;
zcrypt_card_free(zc);
}
if (rc)
zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_DEFAULT);
else
zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_NORNG);
ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc)
goto out_free;
return 0;
out_free:
ap_dev->private = NULL;
zcrypt_device_free(zdev);
return rc;
}
/**
* This is called to remove the extended PCIXCC/CEX2C driver information
* if an AP device is removed.
* This is called to remove the PCIXCC/CEX2C card driver information
* if an AP card device is removed.
*/
static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
{
struct zcrypt_device *zdev = ap_dev->private;
struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
zcrypt_device_unregister(zdev);
if (zc)
zcrypt_card_unregister(zc);
}
static struct ap_driver zcrypt_pcixcc_card_driver = {
.probe = zcrypt_pcixcc_card_probe,
.remove = zcrypt_pcixcc_card_remove,
.ids = zcrypt_pcixcc_card_ids,
};
/**
* Probe function for PCIXCC/CEX2C queue devices. It always accepts the
* AP device since the bus_match already checked the hardware type. The
* PCIXCC cards come in two flavours: micro code level 2 and micro code
* level 3. This is checked by sending a test message to the device.
* @ap_dev: pointer to the AP card device.
*/
static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq;
int rc;
zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
if (!zq)
return -ENOMEM;
zq->queue = aq;
zq->online = 1;
atomic_set(&zq->load, 0);
rc = zcrypt_pcixcc_rng_supported(aq);
if (rc < 0) {
zcrypt_queue_free(zq);
return rc;
}
if (rc)
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_DEFAULT);
else
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_NORNG);
ap_queue_init_reply(aq, &zq->reply);
aq->request_timeout = PCIXCC_CLEANUP_TIME,
aq->private = zq;
rc = zcrypt_queue_register(zq);
if (rc) {
aq->private = NULL;
zcrypt_queue_free(zq);
}
return rc;
}
/**
* This is called to remove the PCIXCC/CEX2C queue driver information
* if an AP queue device is removed.
*/
static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq = aq->private;
ap_queue_remove(aq);
if (zq)
zcrypt_queue_unregister(zq);
}
static struct ap_driver zcrypt_pcixcc_queue_driver = {
.probe = zcrypt_pcixcc_queue_probe,
.remove = zcrypt_pcixcc_queue_remove,
.suspend = ap_queue_suspend,
.resume = ap_queue_resume,
.ids = zcrypt_pcixcc_queue_ids,
};
int __init zcrypt_pcixcc_init(void)
{
return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
int rc;
rc = ap_driver_register(&zcrypt_pcixcc_card_driver,
THIS_MODULE, "pcixcccard");
if (rc)
return rc;
rc = ap_driver_register(&zcrypt_pcixcc_queue_driver,
THIS_MODULE, "pcixccqueue");
if (rc)
ap_driver_unregister(&zcrypt_pcixcc_card_driver);
return rc;
}
void zcrypt_pcixcc_exit(void)
{
ap_driver_unregister(&zcrypt_pcixcc_driver);
ap_driver_unregister(&zcrypt_pcixcc_queue_driver);
ap_driver_unregister(&zcrypt_pcixcc_card_driver);
}
module_init(zcrypt_pcixcc_init);

View File

@ -0,0 +1,221 @@
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
* Cornelia Huck <cornelia.huck@de.ibm.com>
*
* Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
* Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/compat.h>
#include <linux/slab.h>
#include <linux/atomic.h>
#include <linux/uaccess.h>
#include <linux/hw_random.h>
#include <linux/debugfs.h>
#include <asm/debug.h>
#include "zcrypt_debug.h"
#include "zcrypt_api.h"
#include "zcrypt_msgtype6.h"
#include "zcrypt_msgtype50.h"
/*
* Device attributes common for all crypto queue devices.
*/
static ssize_t zcrypt_queue_online_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct zcrypt_queue *zq = to_ap_queue(dev)->private;
return snprintf(buf, PAGE_SIZE, "%d\n", zq->online);
}
static ssize_t zcrypt_queue_online_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct zcrypt_queue *zq = to_ap_queue(dev)->private;
struct zcrypt_card *zc = zq->zcard;
int online;
if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
return -EINVAL;
if (online && !zc->online)
return -EINVAL;
zq->online = online;
ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dman",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid), online);
if (!online)
ap_flush_queue(zq->queue);
return count;
}
static DEVICE_ATTR(online, 0644, zcrypt_queue_online_show,
zcrypt_queue_online_store);
static struct attribute *zcrypt_queue_attrs[] = {
&dev_attr_online.attr,
NULL,
};
static struct attribute_group zcrypt_queue_attr_group = {
.attrs = zcrypt_queue_attrs,
};
void zcrypt_queue_force_online(struct zcrypt_queue *zq, int online)
{
zq->online = online;
if (!online)
ap_flush_queue(zq->queue);
}
struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size)
{
struct zcrypt_queue *zq;
zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL);
if (!zq)
return NULL;
zq->reply.message = kmalloc(max_response_size, GFP_KERNEL);
if (!zq->reply.message)
goto out_free;
zq->reply.length = max_response_size;
INIT_LIST_HEAD(&zq->list);
zq->dbf_area = zcrypt_dbf_devices;
kref_init(&zq->refcount);
return zq;
out_free:
kfree(zq);
return NULL;
}
EXPORT_SYMBOL(zcrypt_queue_alloc);
void zcrypt_queue_free(struct zcrypt_queue *zq)
{
kfree(zq->reply.message);
kfree(zq);
}
EXPORT_SYMBOL(zcrypt_queue_free);
static void zcrypt_queue_release(struct kref *kref)
{
struct zcrypt_queue *zq =
container_of(kref, struct zcrypt_queue, refcount);
zcrypt_queue_free(zq);
}
void zcrypt_queue_get(struct zcrypt_queue *zq)
{
kref_get(&zq->refcount);
}
EXPORT_SYMBOL(zcrypt_queue_get);
int zcrypt_queue_put(struct zcrypt_queue *zq)
{
return kref_put(&zq->refcount, zcrypt_queue_release);
}
EXPORT_SYMBOL(zcrypt_queue_put);
/**
* zcrypt_queue_register() - Register a crypto queue device.
* @zq: Pointer to a crypto queue device
*
* Register a crypto queue device. Returns 0 if successful.
*/
int zcrypt_queue_register(struct zcrypt_queue *zq)
{
struct zcrypt_card *zc;
int rc;
spin_lock(&zcrypt_list_lock);
zc = zq->queue->card->private;
zcrypt_card_get(zc);
zq->zcard = zc;
zq->online = 1; /* New devices are online by default. */
ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dreg",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
zq->online);
list_add_tail(&zq->list, &zc->zqueues);
zcrypt_device_count++;
spin_unlock(&zcrypt_list_lock);
rc = sysfs_create_group(&zq->queue->ap_dev.device.kobj,
&zcrypt_queue_attr_group);
if (rc)
goto out;
get_device(&zq->queue->ap_dev.device);
if (zq->ops->rng) {
rc = zcrypt_rng_device_add();
if (rc)
goto out_unregister;
}
return 0;
out_unregister:
sysfs_remove_group(&zq->queue->ap_dev.device.kobj,
&zcrypt_queue_attr_group);
put_device(&zq->queue->ap_dev.device);
out:
spin_lock(&zcrypt_list_lock);
list_del_init(&zq->list);
spin_unlock(&zcrypt_list_lock);
zcrypt_card_put(zc);
return rc;
}
EXPORT_SYMBOL(zcrypt_queue_register);
/**
* zcrypt_queue_unregister(): Unregister a crypto queue device.
* @zq: Pointer to crypto queue device
*
* Unregister a crypto queue device.
*/
void zcrypt_queue_unregister(struct zcrypt_queue *zq)
{
struct zcrypt_card *zc;
zc = zq->zcard;
spin_lock(&zcrypt_list_lock);
list_del_init(&zq->list);
zcrypt_device_count--;
spin_unlock(&zcrypt_list_lock);
zcrypt_card_put(zc);
if (zq->ops->rng)
zcrypt_rng_device_remove();
sysfs_remove_group(&zq->queue->ap_dev.device.kobj,
&zcrypt_queue_attr_group);
put_device(&zq->queue->ap_dev.device);
zcrypt_queue_put(zq);
}
EXPORT_SYMBOL(zcrypt_queue_unregister);

View File

@ -175,7 +175,8 @@ struct ap_device_id {
kernel_ulong_t driver_info;
};
#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01
#define AP_DEVICE_ID_MATCH_CARD_TYPE 0x01
#define AP_DEVICE_ID_MATCH_QUEUE_TYPE 0x02
/* s390 css bus devices (subchannels) */
struct css_device_id {