diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-24 19:31:34 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-24 19:31:34 +0300 |
commit | e1dbc5a41051d4791160727829903ec5169c7152 (patch) | |
tree | 730ed06c0e1abe339a0f452d0c858c61d8226287 /drivers/s390/crypto/ap_bus.c | |
parent | 40c431a5a5c2333079c67b03de6c0470e8306374 (diff) | |
parent | 4ec84835900b6eceb5b49f9ffeec9a0916ba43d6 (diff) | |
download | linux-e1dbc5a41051d4791160727829903ec5169c7152.tar.xz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
- A couple of patches for the zcrypt driver:
+ Add two masks to determine which AP cards and queues are host
devices, this will be useful for KVM AP device passthrough
+ Add-on patch to improve the parsing of the new apmask and aqmask
+ Some code beautification
- Second try to reenable the GCC plugins, the first patch set had a
patch to do this but the merge somehow missed this
- Remove the s390 specific GCC version check and use the generic one
- Three patches for kdump, two bug fixes and one cleanup
- Three patches for the PCI layer, one bug fix and two cleanups
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390: remove gcc version check (4.3 or newer)
s390/zcrypt: hex string mask improvements for apmask and aqmask.
s390/zcrypt: AP bus support for alternate driver(s)
s390/zcrypt: code beautify
s390/zcrypt: switch return type to bool for ap_instructions_available()
s390/kdump: Remove kzalloc_panic
s390/kdump: Fix memleak in nt_vmcoreinfo
s390/kdump: Make elfcorehdr size calculation ABI compliant
s390/pci: remove fmb address from debug output
s390/pci: remove stale rc
s390/pci: fix out of bounds access during irq setup
s390/zcrypt: fix ap_instructions_available() returncodes
s390: reenable gcc plugins for real
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 432 |
1 files changed, 392 insertions, 40 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index bf27fc4d1335..ec891bc7d10a 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -34,6 +34,7 @@ #include <linux/crypto.h> #include <linux/mod_devicetable.h> #include <linux/debugfs.h> +#include <linux/ctype.h> #include "ap_bus.h" #include "ap_debug.h" @@ -43,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; @@ -78,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 */ @@ -531,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; @@ -570,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; /* @@ -607,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, @@ -666,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); @@ -751,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); @@ -764,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; @@ -775,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) { @@ -790,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) { @@ -806,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) { @@ -820,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 config_time_show(struct bus_type *bus, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); +} -static ssize_t ap_config_time_store(struct bus_type *bus, - const char *buf, size_t count) +static ssize_t config_time_store(struct bus_type *bus, + const char *buf, size_t count) { int time; @@ -834,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; @@ -857,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) { @@ -886,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) { @@ -899,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, @@ -910,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, }; @@ -938,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++) { @@ -956,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); @@ -1038,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) @@ -1163,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: @@ -1187,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. * @@ -1201,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(); @@ -1214,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; |