Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dabecb29 authored by Holger Dengler's avatar Holger Dengler Committed by Martin Schwidefsky
Browse files

s390/zcryt: Handle AP configuration changes



Detect external AP bus configuration changes and request
an AP device rescan.

Signed-off-by: default avatarHolger Dengler <hd@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 745e967a
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -950,6 +950,20 @@ void ap_driver_unregister(struct ap_driver *ap_drv)
}
EXPORT_SYMBOL(ap_driver_unregister);

void ap_bus_force_rescan(void)
{
	/* Delete the AP bus rescan timer. */
	del_timer(&ap_config_timer);

	/* processing a synchonuous bus rescan */
	ap_scan_bus(NULL);

	/* Setup the AP bus rescan timer again. */
	ap_config_timer.expires = jiffies + ap_config_time * HZ;
	add_timer(&ap_config_timer);
}
EXPORT_SYMBOL(ap_bus_force_rescan);

/*
 * AP bus attributes.
 */
+1 −0
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ 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);
void ap_bus_force_rescan(void);

int ap_module_init(void);
void ap_module_exit(void);
+106 −8
Original line number Diff line number Diff line
@@ -38,7 +38,10 @@
#include <linux/atomic.h>
#include <asm/uaccess.h>
#include <linux/hw_random.h>
#include <linux/debugfs.h>
#include <asm/debug.h>

#include "zcrypt_debug.h"
#include "zcrypt_api.h"

/*
@@ -53,6 +56,10 @@ static DEFINE_SPINLOCK(zcrypt_device_lock);
static LIST_HEAD(zcrypt_device_list);
static int zcrypt_device_count = 0;
static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0);

atomic_t zcrypt_rescan_req = ATOMIC_INIT(0);
EXPORT_SYMBOL(zcrypt_rescan_req);

static int zcrypt_rng_device_add(void);
static void zcrypt_rng_device_remove(void);
@@ -60,6 +67,10 @@ static void zcrypt_rng_device_remove(void);
static DEFINE_SPINLOCK(zcrypt_ops_list_lock);
static LIST_HEAD(zcrypt_ops_list);

static debug_info_t *zcrypt_dbf_common;
static debug_info_t *zcrypt_dbf_devices;
static struct dentry *debugfs_root;

/*
 * Device attributes common for all crypto devices.
 */
@@ -89,6 +100,8 @@ static ssize_t zcrypt_online_store(struct device *dev,
	if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
		return -EINVAL;
	zdev->online = online;
	ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid,
		       zdev->online);
	if (!online)
		ap_flush_queue(zdev->ap_dev);
	return count;
@@ -106,6 +119,24 @@ static struct attribute_group zcrypt_device_attr_group = {
	.attrs = zcrypt_device_attrs,
};

/**
 * Process a rescan of the transport layer.
 *
 * Returns 1, if the rescan has been processed, otherwise 0.
 */
static inline int zcrypt_process_rescan(void)
{
	if (atomic_read(&zcrypt_rescan_req)) {
		atomic_set(&zcrypt_rescan_req, 0);
		atomic_inc(&zcrypt_rescan_count);
		ap_bus_force_rescan();
		ZCRYPT_DBF_COMMON(DBF_INFO, "rescan%07d",
				  atomic_inc_return(&zcrypt_rescan_count));
		return 1;
	}
	return 0;
}

/**
 * __zcrypt_increase_preference(): Increase preference of a crypto device.
 * @zdev: Pointer the crypto device
@@ -194,6 +225,7 @@ struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size)
	zdev->reply.length = max_response_size;
	spin_lock_init(&zdev->lock);
	INIT_LIST_HEAD(&zdev->list);
	zdev->dbf_area = zcrypt_dbf_devices;
	return zdev;

out_free:
@@ -229,6 +261,8 @@ int zcrypt_device_register(struct zcrypt_device *zdev)
	kref_init(&zdev->refcount);
	spin_lock_bh(&zcrypt_device_lock);
	zdev->online = 1;	/* New devices are online by default. */
	ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid,
		       zdev->online);
	list_add_tail(&zdev->list, &zcrypt_device_list);
	__zcrypt_increase_preference(zdev);
	zcrypt_device_count++;
@@ -707,6 +741,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
		do {
			rc = zcrypt_rsa_modexpo(&mex);
		} while (rc == -EAGAIN);
		/* on failure: retry once again after a requested rescan */
		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
			do {
				rc = zcrypt_rsa_modexpo(&mex);
			} while (rc == -EAGAIN);
		if (rc)
			return rc;
		return put_user(mex.outputdatalength, &umex->outputdatalength);
@@ -719,6 +758,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
		do {
			rc = zcrypt_rsa_crt(&crt);
		} while (rc == -EAGAIN);
		/* on failure: retry once again after a requested rescan */
		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
			do {
				rc = zcrypt_rsa_crt(&crt);
			} while (rc == -EAGAIN);
		if (rc)
			return rc;
		return put_user(crt.outputdatalength, &ucrt->outputdatalength);
@@ -731,6 +775,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
		do {
			rc = zcrypt_send_cprb(&xcRB);
		} while (rc == -EAGAIN);
		/* on failure: retry once again after a requested rescan */
		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
			do {
				rc = zcrypt_send_cprb(&xcRB);
			} while (rc == -EAGAIN);
		if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
			return -EFAULT;
		return rc;
@@ -837,10 +886,15 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd,
	do {
		rc = zcrypt_rsa_modexpo(&mex64);
	} while (rc == -EAGAIN);
	if (!rc)
		rc = put_user(mex64.outputdatalength,
			      &umex32->outputdatalength);
	/* on failure: retry once again after a requested rescan */
	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
		do {
			rc = zcrypt_rsa_modexpo(&mex64);
		} while (rc == -EAGAIN);
	if (rc)
		return rc;
	return put_user(mex64.outputdatalength,
			&umex32->outputdatalength);
}

struct compat_ica_rsa_modexpo_crt {
@@ -877,10 +931,15 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
	do {
		rc = zcrypt_rsa_crt(&crt64);
	} while (rc == -EAGAIN);
	if (!rc)
		rc = put_user(crt64.outputdatalength,
			      &ucrt32->outputdatalength);
	/* on failure: retry once again after a requested rescan */
	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
		do {
			rc = zcrypt_rsa_crt(&crt64);
		} while (rc == -EAGAIN);
	if (rc)
		return rc;
	return put_user(crt64.outputdatalength,
			&ucrt32->outputdatalength);
}

struct compat_ica_xcRB {
@@ -936,6 +995,11 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
	do {
		rc = zcrypt_send_cprb(&xcRB64);
	} while (rc == -EAGAIN);
	/* on failure: retry once again after a requested rescan */
	if ((rc == -ENODEV) && (zcrypt_process_rescan()))
		do {
			rc = zcrypt_send_cprb(&xcRB64);
		} while (rc == -EAGAIN);
	xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
	xcRB32.reply_data_length = xcRB64.reply_data_length;
	xcRB32.status = xcRB64.status;
@@ -1193,6 +1257,9 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data)
	 */
	if (zcrypt_rng_buffer_index == 0) {
		rc = zcrypt_rng((char *) zcrypt_rng_buffer);
		/* on failure: retry once again after a requested rescan */
		if ((rc == -ENODEV) && (zcrypt_process_rescan()))
			rc = zcrypt_rng((char *) zcrypt_rng_buffer);
		if (rc < 0)
			return -EIO;
		zcrypt_rng_buffer_index = rc / sizeof *data;
@@ -1245,6 +1312,30 @@ static void zcrypt_rng_device_remove(void)
	mutex_unlock(&zcrypt_rng_mutex);
}

int __init zcrypt_debug_init(void)
{
	debugfs_root = debugfs_create_dir("zcrypt", NULL);

	zcrypt_dbf_common = debug_register("zcrypt_common", 1, 1, 16);
	debug_register_view(zcrypt_dbf_common, &debug_hex_ascii_view);
	debug_set_level(zcrypt_dbf_common, DBF_ERR);

	zcrypt_dbf_devices = debug_register("zcrypt_devices", 1, 1, 16);
	debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view);
	debug_set_level(zcrypt_dbf_devices, DBF_ERR);

	return 0;
}

void zcrypt_debug_exit(void)
{
	debugfs_remove(debugfs_root);
	if (zcrypt_dbf_common)
		debug_unregister(zcrypt_dbf_common);
	if (zcrypt_dbf_devices)
		debug_unregister(zcrypt_dbf_devices);
}

/**
 * zcrypt_api_init(): Module initialization.
 *
@@ -1254,6 +1345,12 @@ int __init zcrypt_api_init(void)
{
	int rc;

	rc = zcrypt_debug_init();
	if (rc)
		goto out;

	atomic_set(&zcrypt_rescan_req, 0);

	/* Register the request sprayer. */
	rc = misc_register(&zcrypt_misc_device);
	if (rc < 0)
@@ -1283,6 +1380,7 @@ void zcrypt_api_exit(void)
{
	remove_proc_entry("driver/z90crypt", NULL);
	misc_deregister(&zcrypt_misc_device);
	zcrypt_debug_exit();
}

module_init(zcrypt_api_init);
+8 −1
Original line number Diff line number Diff line
@@ -29,8 +29,10 @@
#ifndef _ZCRYPT_API_H_
#define _ZCRYPT_API_H_

#include "ap_bus.h"
#include <linux/atomic.h>
#include <asm/debug.h>
#include <asm/zcrypt.h>
#include "ap_bus.h"

/* deprecated status calls */
#define ICAZ90STATUS		_IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status)
@@ -112,8 +114,13 @@ struct zcrypt_device {

	struct ap_message reply;	/* Per-device reply structure. */
	int max_exp_bit_length;

	debug_info_t *dbf_area;		/* debugging */
};

/* 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 *);
+59 −0
Original line number Diff line number Diff line
/*
 *  Copyright IBM Corp. 2012
 *  Author(s): Holger Dengler (hd@linux.vnet.ibm.com)
 */
#ifndef ZCRYPT_DEBUG_H
#define ZCRYPT_DEBUG_H

#include <asm/debug.h>
#include "zcrypt_api.h"

/* that gives us 15 characters in the text event views */
#define ZCRYPT_DBF_LEN	16

/* sort out low debug levels early to avoid wasted sprints */
static inline int zcrypt_dbf_passes(debug_info_t *dbf_grp, int level)
{
	return (level <= dbf_grp->level);
}

#define DBF_ERR		3	/* error conditions	*/
#define DBF_WARN	4	/* warning conditions	*/
#define DBF_INFO	6	/* informational	*/

#define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO)

#define ZCRYPT_DBF_COMMON(level, text...) \
	do { \
		if (zcrypt_dbf_passes(zcrypt_dbf_common, level)) { \
			char debug_buffer[ZCRYPT_DBF_LEN]; \
			snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
			debug_text_event(zcrypt_dbf_common, level, \
					 debug_buffer); \
		} \
	} while (0)

#define ZCRYPT_DBF_DEVICES(level, text...) \
	do { \
		if (zcrypt_dbf_passes(zcrypt_dbf_devices, level)) { \
			char debug_buffer[ZCRYPT_DBF_LEN]; \
			snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
			debug_text_event(zcrypt_dbf_devices, level, \
					 debug_buffer); \
		} \
	} while (0)

#define ZCRYPT_DBF_DEV(level, device, text...) \
	do { \
		if (zcrypt_dbf_passes(device->dbf_area, level)) { \
			char debug_buffer[ZCRYPT_DBF_LEN]; \
			snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
			debug_text_event(device->dbf_area, level, \
					 debug_buffer); \
		} \
	} while (0)

int zcrypt_debug_init(void);
void zcrypt_debug_exit(void);

#endif /* ZCRYPT_DEBUG_H */
Loading