diff options
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
| -rw-r--r-- | drivers/s390/crypto/ap_bus.c | 457 | 
1 files changed, 395 insertions, 62 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 35a0c2b52f82..ec891bc7d10a 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -34,9 +34,9 @@  #include <linux/crypto.h>  #include <linux/mod_devicetable.h>  #include <linux/debugfs.h> +#include <linux/ctype.h>  #include "ap_bus.h" -#include "ap_asm.h"  #include "ap_debug.h"  /* @@ -44,19 +44,34 @@   */  int ap_domain_index = -1;	/* Adjunct Processor Domain Index */  static DEFINE_SPINLOCK(ap_domain_lock); -module_param_named(domain, ap_domain_index, int, S_IRUSR|S_IRGRP); +module_param_named(domain, ap_domain_index, int, 0440);  MODULE_PARM_DESC(domain, "domain index for ap devices");  EXPORT_SYMBOL(ap_domain_index); -static int ap_thread_flag = 0; -module_param_named(poll_thread, ap_thread_flag, int, S_IRUSR|S_IRGRP); +static int ap_thread_flag; +module_param_named(poll_thread, ap_thread_flag, int, 0440);  MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); +static char *apm_str; +module_param_named(apmask, apm_str, charp, 0440); +MODULE_PARM_DESC(apmask, "AP bus adapter mask."); + +static char *aqm_str; +module_param_named(aqmask, aqm_str, charp, 0440); +MODULE_PARM_DESC(aqmask, "AP bus domain mask."); +  static struct device *ap_root_device;  DEFINE_SPINLOCK(ap_list_lock);  LIST_HEAD(ap_card_list); +/* Default permissions (card and domain masking) */ +static struct ap_perms { +	DECLARE_BITMAP(apm, AP_DEVICES); +	DECLARE_BITMAP(aqm, AP_DOMAINS); +} ap_perms; +static DEFINE_MUTEX(ap_perms_mutex); +  static struct ap_config_info *ap_configuration;  static bool initialised; @@ -79,22 +94,26 @@ static DECLARE_WORK(ap_scan_work, ap_scan_bus);  static void ap_tasklet_fn(unsigned long);  static DECLARE_TASKLET(ap_tasklet, ap_tasklet_fn, 0);  static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); -static struct task_struct *ap_poll_kthread = NULL; +static struct task_struct *ap_poll_kthread;  static DEFINE_MUTEX(ap_poll_thread_mutex);  static DEFINE_SPINLOCK(ap_poll_timer_lock);  static struct hrtimer ap_poll_timer; -/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. - * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ +/* + * In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. + * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling. + */  static unsigned long long poll_timeout = 250000;  /* Suspend flag */  static int ap_suspend_flag;  /* Maximum domain id */  static int ap_max_domain_id; -/* Flag to check if domain was set through module parameter domain=. This is +/* + * Flag to check if domain was set through module parameter domain=. This is   * important when supsend and resume is done in a z/VM environment where the - * domain might change. */ -static int user_set_domain = 0; + * domain might change. + */ +static int user_set_domain;  static struct bus_type ap_bus_type;  /* Adapter interrupt definitions */ @@ -174,24 +193,6 @@ static inline int ap_qact_available(void)  	return 0;  } -/** - * ap_test_queue(): Test adjunct processor queue. - * @qid: The AP queue number - * @tbit: Test facilities bit - * @info: Pointer to queue descriptor - * - * Returns AP queue status structure. - */ -struct ap_queue_status ap_test_queue(ap_qid_t qid, -				     int tbit, -				     unsigned long *info) -{ -	if (tbit) -		qid |= 1UL << 23; /* set T bit*/ -	return ap_tapq(qid, info); -} -EXPORT_SYMBOL(ap_test_queue); -  /*   * ap_query_configuration(): Fetch cryptographic config info   * @@ -200,7 +201,7 @@ EXPORT_SYMBOL(ap_test_queue);   * is returned, e.g. if the PQAP(QCI) instruction is not   * available, the return value will be -EOPNOTSUPP.   */ -int ap_query_configuration(struct ap_config_info *info) +static inline int ap_query_configuration(struct ap_config_info *info)  {  	if (!ap_configuration_available())  		return -EOPNOTSUPP; @@ -493,7 +494,7 @@ static int ap_poll_thread_start(void)  		return 0;  	mutex_lock(&ap_poll_thread_mutex);  	ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); -	rc = PTR_RET(ap_poll_kthread); +	rc = PTR_ERR_OR_ZERO(ap_poll_kthread);  	if (rc)  		ap_poll_kthread = NULL;  	mutex_unlock(&ap_poll_thread_mutex); @@ -550,7 +551,7 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)   * It sets up a single environment variable DEV_TYPE which contains the   * hardware device type.   */ -static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) +static int ap_uevent(struct device *dev, struct kobj_uevent_env *env)  {  	struct ap_device *ap_dev = to_ap_dev(dev);  	int retval = 0; @@ -589,7 +590,7 @@ static int ap_dev_resume(struct device *dev)  static void ap_bus_suspend(void)  { -	AP_DBF(DBF_DEBUG, "ap_bus_suspend running\n"); +	AP_DBF(DBF_DEBUG, "%s running\n", __func__);  	ap_suspend_flag = 1;  	/* @@ -626,7 +627,7 @@ static void ap_bus_resume(void)  {  	int rc; -	AP_DBF(DBF_DEBUG, "ap_bus_resume running\n"); +	AP_DBF(DBF_DEBUG, "%s running\n", __func__);  	/* remove all queue devices */  	bus_for_each_dev(&ap_bus_type, NULL, NULL, @@ -685,11 +686,97 @@ static struct bus_type ap_bus_type = {  	.pm = &ap_bus_pm_ops,  }; +static int __ap_revise_reserved(struct device *dev, void *dummy) +{ +	int rc, card, queue, devres, drvres; + +	if (is_queue_dev(dev)) { +		card = AP_QID_CARD(to_ap_queue(dev)->qid); +		queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); +		mutex_lock(&ap_perms_mutex); +		devres = test_bit_inv(card, ap_perms.apm) +			&& test_bit_inv(queue, ap_perms.aqm); +		mutex_unlock(&ap_perms_mutex); +		drvres = to_ap_drv(dev->driver)->flags +			& AP_DRIVER_FLAG_DEFAULT; +		if (!!devres != !!drvres) { +			AP_DBF(DBF_DEBUG, "reprobing queue=%02x.%04x\n", +			       card, queue); +			rc = device_reprobe(dev); +		} +	} + +	return 0; +} + +static void ap_bus_revise_bindings(void) +{ +	bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_revise_reserved); +} + +int ap_owned_by_def_drv(int card, int queue) +{ +	int rc = 0; + +	if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >= AP_DOMAINS) +		return -EINVAL; + +	mutex_lock(&ap_perms_mutex); + +	if (test_bit_inv(card, ap_perms.apm) +	    && test_bit_inv(queue, ap_perms.aqm)) +		rc = 1; + +	mutex_unlock(&ap_perms_mutex); + +	return rc; +} +EXPORT_SYMBOL(ap_owned_by_def_drv); + +int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, +				       unsigned long *aqm) +{ +	int card, queue, rc = 0; + +	mutex_lock(&ap_perms_mutex); + +	for (card = 0; !rc && card < AP_DEVICES; card++) +		if (test_bit_inv(card, apm) && +		    test_bit_inv(card, ap_perms.apm)) +			for (queue = 0; !rc && queue < AP_DOMAINS; queue++) +				if (test_bit_inv(queue, aqm) && +				    test_bit_inv(queue, ap_perms.aqm)) +					rc = 1; + +	mutex_unlock(&ap_perms_mutex); + +	return rc; +} +EXPORT_SYMBOL(ap_apqn_in_matrix_owned_by_def_drv); +  static int ap_device_probe(struct device *dev)  {  	struct ap_device *ap_dev = to_ap_dev(dev);  	struct ap_driver *ap_drv = to_ap_drv(dev->driver); -	int rc; +	int card, queue, devres, drvres, rc; + +	if (is_queue_dev(dev)) { +		/* +		 * If the apqn is marked as reserved/used by ap bus and +		 * default drivers, only probe with drivers with the default +		 * flag set. If it is not marked, only probe with drivers +		 * with the default flag not set. +		 */ +		card = AP_QID_CARD(to_ap_queue(dev)->qid); +		queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); +		mutex_lock(&ap_perms_mutex); +		devres = test_bit_inv(card, ap_perms.apm) +			&& test_bit_inv(queue, ap_perms.aqm); +		mutex_unlock(&ap_perms_mutex); +		drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT; +		if (!!devres != !!drvres) +			return -ENODEV; +	}  	/* Add queue/card to list of active queues/cards */  	spin_lock_bh(&ap_list_lock); @@ -770,8 +857,163 @@ void ap_bus_force_rescan(void)  EXPORT_SYMBOL(ap_bus_force_rescan);  /* + * hex2bitmap() - parse hex mask string and set bitmap. + * Valid strings are "0x012345678" with at least one valid hex number. + * Rest of the bitmap to the right is padded with 0. No spaces allowed + * within the string, the leading 0x may be omitted. + * Returns the bitmask with exactly the bits set as given by the hex + * string (both in big endian order). + */ +static int hex2bitmap(const char *str, unsigned long *bitmap, int bits) +{ +	int i, n, b; + +	/* bits needs to be a multiple of 8 */ +	if (bits & 0x07) +		return -EINVAL; + +	memset(bitmap, 0, bits / 8); + +	if (str[0] == '0' && str[1] == 'x') +		str++; +	if (*str == 'x') +		str++; + +	for (i = 0; isxdigit(*str) && i < bits; str++) { +		b = hex_to_bin(*str); +		for (n = 0; n < 4; n++) +			if (b & (0x08 >> n)) +				set_bit_inv(i + n, bitmap); +		i += 4; +	} + +	if (*str == '\n') +		str++; +	if (*str) +		return -EINVAL; +	return 0; +} + +/* + * str2clrsetmasks() - parse bitmask argument and set the clear and + * the set bitmap mask. A concatenation (done with ',') of these terms + * is recognized: + *   +<bitnr>[-<bitnr>] or -<bitnr>[-<bitnr>] + * <bitnr> may be any valid number (hex, decimal or octal) in the range + * 0...bits-1; the leading + or - is required. Here are some examples: + *   +0-15,+32,-128,-0xFF + *   -0-255,+1-16,+0x128 + *   +1,+2,+3,+4,-5,-7-10 + * Returns a clear and a set bitmask. Every positive value in the string + * results in a bit set in the set mask and every negative value in the + * string results in a bit SET in the clear mask. As a bit may be touched + * more than once, the last 'operation' wins: +0-255,-128 = all but bit + * 128 set in the set mask, only bit 128 set in the clear mask. + */ +static int str2clrsetmasks(const char *str, +			   unsigned long *clrmap, +			   unsigned long *setmap, +			   int bits) +{ +	int a, i, z; +	char *np, sign; + +	/* bits needs to be a multiple of 8 */ +	if (bits & 0x07) +		return -EINVAL; + +	memset(clrmap, 0, bits / 8); +	memset(setmap, 0, bits / 8); + +	while (*str) { +		sign = *str++; +		if (sign != '+' && sign != '-') +			return -EINVAL; +		a = z = simple_strtoul(str, &np, 0); +		if (str == np || a >= bits) +			return -EINVAL; +		str = np; +		if (*str == '-') { +			z = simple_strtoul(++str, &np, 0); +			if (str == np || a > z || z >= bits) +				return -EINVAL; +			str = np; +		} +		for (i = a; i <= z; i++) +			if (sign == '+') { +				set_bit_inv(i, setmap); +				clear_bit_inv(i, clrmap); +			} else { +				clear_bit_inv(i, setmap); +				set_bit_inv(i, clrmap); +			} +		while (*str == ',' || *str == '\n') +			str++; +	} + +	return 0; +} + +/* + * process_mask_arg() - parse a bitmap string and clear/set the + * bits in the bitmap accordingly. The string may be given as + * absolute value, a hex string like 0x1F2E3D4C5B6A" simple over- + * writing the current content of the bitmap. Or as relative string + * like "+1-16,-32,-0x40,+128" where only single bits or ranges of + * bits are cleared or set. Distinction is done based on the very + * first character which may be '+' or '-' for the relative string + * and othewise assume to be an absolute value string. If parsing fails + * a negative errno value is returned. All arguments and bitmaps are + * big endian order. + */ +static int process_mask_arg(const char *str, +			    unsigned long *bitmap, int bits, +			    struct mutex *lock) +{ +	int i; + +	/* bits needs to be a multiple of 8 */ +	if (bits & 0x07) +		return -EINVAL; + +	if (*str == '+' || *str == '-') { +		DECLARE_BITMAP(clrm, bits); +		DECLARE_BITMAP(setm, bits); + +		i = str2clrsetmasks(str, clrm, setm, bits); +		if (i) +			return i; +		if (mutex_lock_interruptible(lock)) +			return -ERESTARTSYS; +		for (i = 0; i < bits; i++) { +			if (test_bit_inv(i, clrm)) +				clear_bit_inv(i, bitmap); +			if (test_bit_inv(i, setm)) +				set_bit_inv(i, bitmap); +		} +	} else { +		DECLARE_BITMAP(setm, bits); + +		i = hex2bitmap(str, setm, bits); +		if (i) +			return i; +		if (mutex_lock_interruptible(lock)) +			return -ERESTARTSYS; +		for (i = 0; i < bits; i++) +			if (test_bit_inv(i, setm)) +				set_bit_inv(i, bitmap); +			else +				clear_bit_inv(i, bitmap); +	} +	mutex_unlock(lock); + +	return 0; +} + +/*   * AP bus attributes.   */ +  static ssize_t ap_domain_show(struct bus_type *bus, char *buf)  {  	return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); @@ -783,7 +1025,8 @@ static ssize_t ap_domain_store(struct bus_type *bus,  	int domain;  	if (sscanf(buf, "%i\n", &domain) != 1 || -	    domain < 0 || domain > ap_max_domain_id) +	    domain < 0 || domain > ap_max_domain_id || +	    !test_bit_inv(domain, ap_perms.aqm))  		return -EINVAL;  	spin_lock_bh(&ap_domain_lock);  	ap_domain_index = domain; @@ -794,7 +1037,7 @@ static ssize_t ap_domain_store(struct bus_type *bus,  	return count;  } -static BUS_ATTR(ap_domain, 0644, ap_domain_show, ap_domain_store); +static BUS_ATTR_RW(ap_domain);  static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf)  { @@ -809,8 +1052,7 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf)  			ap_configuration->adm[6], ap_configuration->adm[7]);  } -static BUS_ATTR(ap_control_domain_mask, 0444, -		ap_control_domain_mask_show, NULL); +static BUS_ATTR_RO(ap_control_domain_mask);  static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf)  { @@ -825,13 +1067,7 @@ static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf)  			ap_configuration->aqm[6], ap_configuration->aqm[7]);  } -static BUS_ATTR(ap_usage_domain_mask, 0444, -		ap_usage_domain_mask_show, NULL); - -static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) -{ -	return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); -} +static BUS_ATTR_RO(ap_usage_domain_mask);  static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)  { @@ -839,10 +1075,15 @@ static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)  			ap_using_interrupts() ? 1 : 0);  } -static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL); +static BUS_ATTR_RO(ap_interrupts); -static ssize_t ap_config_time_store(struct bus_type *bus, -				    const char *buf, size_t count) +static ssize_t config_time_show(struct bus_type *bus, char *buf) +{ +	return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); +} + +static ssize_t config_time_store(struct bus_type *bus, +				 const char *buf, size_t count)  {  	int time; @@ -853,15 +1094,15 @@ static ssize_t ap_config_time_store(struct bus_type *bus,  	return count;  } -static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store); +static BUS_ATTR_RW(config_time); -static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf) +static ssize_t poll_thread_show(struct bus_type *bus, char *buf)  {  	return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0);  } -static ssize_t ap_poll_thread_store(struct bus_type *bus, -				    const char *buf, size_t count) +static ssize_t poll_thread_store(struct bus_type *bus, +				 const char *buf, size_t count)  {  	int flag, rc; @@ -876,7 +1117,7 @@ static ssize_t ap_poll_thread_store(struct bus_type *bus,  	return count;  } -static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store); +static BUS_ATTR_RW(poll_thread);  static ssize_t poll_timeout_show(struct bus_type *bus, char *buf)  { @@ -905,7 +1146,7 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,  	return count;  } -static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); +static BUS_ATTR_RW(poll_timeout);  static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf)  { @@ -918,7 +1159,69 @@ static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf)  	return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id);  } -static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL); +static BUS_ATTR_RO(ap_max_domain_id); + +static ssize_t apmask_show(struct bus_type *bus, char *buf) +{ +	int rc; + +	if (mutex_lock_interruptible(&ap_perms_mutex)) +		return -ERESTARTSYS; +	rc = snprintf(buf, PAGE_SIZE, +		      "0x%016lx%016lx%016lx%016lx\n", +		      ap_perms.apm[0], ap_perms.apm[1], +		      ap_perms.apm[2], ap_perms.apm[3]); +	mutex_unlock(&ap_perms_mutex); + +	return rc; +} + +static ssize_t apmask_store(struct bus_type *bus, const char *buf, +			    size_t count) +{ +	int rc; + +	rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex); +	if (rc) +		return rc; + +	ap_bus_revise_bindings(); + +	return count; +} + +static BUS_ATTR_RW(apmask); + +static ssize_t aqmask_show(struct bus_type *bus, char *buf) +{ +	int rc; + +	if (mutex_lock_interruptible(&ap_perms_mutex)) +		return -ERESTARTSYS; +	rc = snprintf(buf, PAGE_SIZE, +		      "0x%016lx%016lx%016lx%016lx\n", +		      ap_perms.aqm[0], ap_perms.aqm[1], +		      ap_perms.aqm[2], ap_perms.aqm[3]); +	mutex_unlock(&ap_perms_mutex); + +	return rc; +} + +static ssize_t aqmask_store(struct bus_type *bus, const char *buf, +			    size_t count) +{ +	int rc; + +	rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex); +	if (rc) +		return rc; + +	ap_bus_revise_bindings(); + +	return count; +} + +static BUS_ATTR_RW(aqmask);  static struct bus_attribute *const ap_bus_attrs[] = {  	&bus_attr_ap_domain, @@ -929,6 +1232,8 @@ static struct bus_attribute *const ap_bus_attrs[] = {  	&bus_attr_ap_interrupts,  	&bus_attr_poll_timeout,  	&bus_attr_ap_max_domain_id, +	&bus_attr_apmask, +	&bus_attr_aqmask,  	NULL,  }; @@ -957,7 +1262,8 @@ static int ap_select_domain(void)  	best_domain = -1;  	max_count = 0;  	for (i = 0; i < AP_DOMAINS; i++) { -		if (!ap_test_config_domain(i)) +		if (!ap_test_config_domain(i) || +		    !test_bit_inv(i, ap_perms.aqm))  			continue;  		count = 0;  		for (j = 0; j < AP_DEVICES; j++) { @@ -975,7 +1281,7 @@ static int ap_select_domain(void)  			best_domain = i;  		}  	} -	if (best_domain >= 0){ +	if (best_domain >= 0) {  		ap_domain_index = best_domain;  		AP_DBF(DBF_DEBUG, "new ap_domain_index=%d\n", ap_domain_index);  		spin_unlock_bh(&ap_domain_lock); @@ -1057,7 +1363,7 @@ static void ap_scan_bus(struct work_struct *unused)  	unsigned int func = 0;  	int rc, id, dom, borked, domains, defdomdevs = 0; -	AP_DBF(DBF_DEBUG, "ap_scan_bus running\n"); +	AP_DBF(DBF_DEBUG, "%s running\n", __func__);  	ap_query_configuration(ap_configuration);  	if (ap_select_domain() != 0) @@ -1182,7 +1488,8 @@ static void ap_scan_bus(struct work_struct *unused)  	} /* end device loop */  	if (defdomdevs < 1) -		AP_DBF(DBF_INFO, "no queue device with default domain %d available\n", +		AP_DBF(DBF_INFO, +		       "no queue device with default domain %d available\n",  		       ap_domain_index);  out: @@ -1206,6 +1513,27 @@ static int __init ap_debug_init(void)  	return 0;  } +static void __init ap_perms_init(void) +{ +	/* all resources useable if no kernel parameter string given */ +	memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm)); +	memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm)); + +	/* apm kernel parameter string */ +	if (apm_str) { +		memset(&ap_perms.apm, 0, sizeof(ap_perms.apm)); +		process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES, +				 &ap_perms_mutex); +	} + +	/* aqm kernel parameter string */ +	if (aqm_str) { +		memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm)); +		process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS, +				 &ap_perms_mutex); +	} +} +  /**   * ap_module_init(): The module initialization code.   * @@ -1220,11 +1548,14 @@ static int __init ap_module_init(void)  	if (rc)  		return rc; -	if (ap_instructions_available() != 0) { +	if (!ap_instructions_available()) {  		pr_warn("The hardware system does not support AP instructions\n");  		return -ENODEV;  	} +	/* set up the AP permissions (ap and aq masks) */ +	ap_perms_init(); +  	/* Get AP configuration data if available */  	ap_init_configuration(); @@ -1233,7 +1564,9 @@ static int __init ap_module_init(void)  			ap_max_domain_id ? ap_max_domain_id : AP_DOMAINS - 1;  	else  		max_domain_id = 15; -	if (ap_domain_index < -1 || ap_domain_index > max_domain_id) { +	if (ap_domain_index < -1 || ap_domain_index > max_domain_id || +	    (ap_domain_index >= 0 && +	     !test_bit_inv(ap_domain_index, ap_perms.aqm))) {  		pr_warn("%d is not a valid cryptographic domain\n",  			ap_domain_index);  		ap_domain_index = -1; @@ -1261,7 +1594,7 @@ static int __init ap_module_init(void)  	/* Create /sys/devices/ap. */  	ap_root_device = root_device_register("ap"); -	rc = PTR_RET(ap_root_device); +	rc = PTR_ERR_OR_ZERO(ap_root_device);  	if (rc)  		goto out_bus;  |