From: Harald Freudenberger <freude@xxxxxxxxxxxxx> This patch enables modifications of the apmask and aqmask on a live system. Until now these both masks are read-only on a live system. The only way to change these masks was via kernel command line parameter. This patch makes the sysfs attributes /sys/bus/ap/apmask and /sys/bus/ap/aqmask writeable by root. With changing the mask(s) a revision of the existing queue to driver bindings is done. So all APQNs which are bound to the 'wrong' driver are reprobed via kernel function device_reprobe() and thus the new correct driver will be assigned with respect of the changed apmask and aqmask bits. Signed-off-by: Harald Freudenberger <freude@xxxxxxxxxxxxx> Signed-off-by: Christian Borntraeger <borntraeger@xxxxxxxxxx> --- drivers/s390/crypto/ap_bus.c | 153 ++++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 10 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index b36a4e17a734..c47d1f2fe0d8 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -70,6 +70,7 @@ static struct ap_rights { DECLARE_BITMAP(apm, AP_DEVICES); DECLARE_BITMAP(aqm, AP_DOMAINS); } ap_rights; +static DEFINE_MUTEX(ap_rights_mutex); static struct ap_config_info *ap_configuration; static bool initialised; @@ -681,6 +682,34 @@ static struct bus_type ap_bus_type = { .pm = &ap_bus_pm_ops, }; +static int __ap_revice_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_rights_mutex); + devres = test_bit_inv(card, ap_rights.apm) + && test_bit_inv(queue, ap_rights.aqm); + mutex_unlock(&ap_rights_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_revice_reserved); +} + int ap_owned_by_def_drv(int card, int queue) { int rc = 0; @@ -688,10 +717,14 @@ int ap_owned_by_def_drv(int card, int queue) if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >= AP_DOMAINS) return -EINVAL; + mutex_lock(&ap_rights_mutex); + if (test_bit_inv(card, ap_rights.apm) && test_bit_inv(queue, ap_rights.aqm)) rc = 1; + mutex_unlock(&ap_rights_mutex); + return rc; } EXPORT_SYMBOL(ap_owned_by_def_drv); @@ -700,6 +733,8 @@ int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, unsigned long *aqm) { int card, queue, rc = 0; + mutex_lock(&ap_rights_mutex); + for (card = 0; !rc && card < AP_DEVICES; card++) if (test_bit_inv(card, apm) && test_bit_inv(card, ap_rights.apm)) @@ -708,6 +743,8 @@ int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, unsigned long *aqm) test_bit_inv(queue, ap_rights.aqm)) rc = 1; + mutex_unlock(&ap_rights_mutex); + return rc; } EXPORT_SYMBOL(ap_apqn_in_matrix_owned_by_def_drv); @@ -726,8 +763,10 @@ static int ap_device_probe(struct device *dev) */ card = AP_QID_CARD(to_ap_queue(dev)->qid); queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); + mutex_lock(&ap_rights_mutex); devres = test_bit_inv(card, ap_rights.apm) && test_bit_inv(queue, ap_rights.aqm); + mutex_unlock(&ap_rights_mutex); drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT; if ((devres && !drvres) || (!devres && drvres)) return -ENODEV; @@ -991,23 +1030,117 @@ static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL); static ssize_t ap_apmask_show(struct bus_type *bus, char *buf) { - return snprintf(buf, PAGE_SIZE, - "0x%016lx%016lx%016lx%016lx\n", - ap_rights.apm[0], ap_rights.apm[1], - ap_rights.apm[2], ap_rights.apm[3]); + int rc; + + if (mutex_lock_interruptible(&ap_rights_mutex)) + return -ERESTARTSYS; + rc = snprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_rights.apm[0], ap_rights.apm[1], + ap_rights.apm[2], ap_rights.apm[3]); + mutex_unlock(&ap_rights_mutex); + + return rc; } -static BUS_ATTR(apmask, 0444, ap_apmask_show, NULL); +static ssize_t ap_apmask_store(struct bus_type *bus, const char *buf, + size_t count) +{ + int i; + + if (*buf == '+' || *buf == '-') { + if (kstrtoint(buf, 0, &i)) + return -EINVAL; + if (i <= -AP_DEVICES || i >= AP_DEVICES) + return -EINVAL; + if (mutex_lock_interruptible(&ap_rights_mutex)) + return -ERESTARTSYS; + if (*buf == '-') + clear_bit_inv(-i, ap_rights.apm); + else + set_bit_inv(i, ap_rights.apm); + } else { + DECLARE_BITMAP(apm, AP_DEVICES); + + i = hex2bitmap(buf, apm, AP_DEVICES); + if (i) + return i; + if (mutex_lock_interruptible(&ap_rights_mutex)) + return -ERESTARTSYS; + for (i = 0; i < AP_DEVICES; i++) + if (test_bit_inv(i, apm)) { + if (!test_bit_inv(i, ap_rights.apm)) + set_bit_inv(i, ap_rights.apm); + } else { + if (test_bit_inv(i, ap_rights.apm)) + clear_bit_inv(i, ap_rights.apm); + } + } + mutex_unlock(&ap_rights_mutex); + + ap_bus_revise_bindings(); + + return count; +} + +static BUS_ATTR(apmask, 0644, ap_apmask_show, ap_apmask_store); static ssize_t ap_aqmask_show(struct bus_type *bus, char *buf) { - return snprintf(buf, PAGE_SIZE, - "0x%016lx%016lx%016lx%016lx\n", - ap_rights.aqm[0], ap_rights.aqm[1], - ap_rights.aqm[2], ap_rights.aqm[3]); + int rc; + + if (mutex_lock_interruptible(&ap_rights_mutex)) + return -ERESTARTSYS; + rc = snprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_rights.aqm[0], ap_rights.aqm[1], + ap_rights.aqm[2], ap_rights.aqm[3]); + mutex_unlock(&ap_rights_mutex); + + return rc; } -static BUS_ATTR(aqmask, 0444, ap_aqmask_show, NULL); +static ssize_t ap_aqmask_store(struct bus_type *bus, const char *buf, + size_t count) +{ + int i; + + if (*buf == '+' || *buf == '-') { + if (kstrtoint(buf, 0, &i)) + return -EINVAL; + if (i <= -AP_DEVICES || i >= AP_DEVICES) + return -EINVAL; + if (mutex_lock_interruptible(&ap_rights_mutex)) + return -ERESTARTSYS; + if (*buf == '-') + clear_bit_inv(-i, ap_rights.aqm); + else + set_bit_inv(i, ap_rights.aqm); + } else { + DECLARE_BITMAP(aqm, AP_DEVICES); + + i = hex2bitmap(buf, aqm, AP_DEVICES); + if (i) + return i; + if (mutex_lock_interruptible(&ap_rights_mutex)) + return -ERESTARTSYS; + for (i = 0; i < AP_DEVICES; i++) + if (test_bit_inv(i, aqm)) { + if (!test_bit_inv(i, ap_rights.aqm)) + set_bit_inv(i, ap_rights.aqm); + } else { + if (test_bit_inv(i, ap_rights.aqm)) + clear_bit_inv(i, ap_rights.aqm); + } + } + mutex_unlock(&ap_rights_mutex); + + ap_bus_revise_bindings(); + + return count; +} + +static BUS_ATTR(aqmask, 0644, ap_aqmask_show, ap_aqmask_store); static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, -- 2.17.0