diff options
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 65 |
1 files changed, 48 insertions, 17 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 6ed0985c0c9..ad60afe5dd1 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -33,11 +33,12 @@ #include <linux/kthread.h> #include <linux/mutex.h> #include <asm/s390_rdev.h> +#include <asm/reset.h> #include "ap_bus.h" /* Some prototypes. */ -static void ap_scan_bus(void *); +static void ap_scan_bus(struct work_struct *); static void ap_poll_all(unsigned long); static void ap_poll_timeout(unsigned long); static int ap_poll_thread_start(void); @@ -71,7 +72,7 @@ static struct device *ap_root_device = NULL; static struct workqueue_struct *ap_work_queue; static struct timer_list ap_config_timer; static int ap_config_time = AP_CONFIG_TIME; -static DECLARE_WORK(ap_config_work, ap_scan_bus, NULL); +static DECLARE_WORK(ap_config_work, ap_scan_bus); /** * Tasklet & timer for AP request polling. @@ -431,7 +432,15 @@ static int ap_uevent (struct device *dev, char **envp, int num_envp, ap_dev->device_type); if (buffer_size - length <= 0) return -ENOMEM; - envp[1] = 0; + buffer += length; + buffer_size -= length; + /* Add MODALIAS= */ + envp[1] = buffer; + length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X", + ap_dev->device_type); + if (buffer_size - length <= 0) + return -ENOMEM; + envp[2] = NULL; return 0; } @@ -449,8 +458,6 @@ static int ap_device_probe(struct device *dev) ap_dev->drv = ap_drv; rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; - if (rc) - ap_dev->unregistered = 1; return rc; } @@ -487,14 +494,7 @@ static int ap_device_remove(struct device *dev) struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = ap_dev->drv; - spin_lock_bh(&ap_dev->lock); - __ap_flush_queue(ap_dev); - /** - * set ->unregistered to 1 while holding the lock. This prevents - * new messages to be put on the queue from now on. - */ - ap_dev->unregistered = 1; - spin_unlock_bh(&ap_dev->lock); + ap_flush_queue(ap_dev); if (ap_drv->remove) ap_drv->remove(ap_dev); return 0; @@ -733,7 +733,7 @@ static void ap_device_release(struct device *dev) kfree(ap_dev); } -static void ap_scan_bus(void *data) +static void ap_scan_bus(struct work_struct *unused) { struct ap_device *ap_dev; struct device *dev; @@ -748,11 +748,16 @@ static void ap_scan_bus(void *data) dev = bus_find_device(&ap_bus_type, NULL, (void *)(unsigned long)qid, __ap_scan_bus); + rc = ap_query_queue(qid, &queue_depth, &device_type); + if (dev && rc) { + put_device(dev); + device_unregister(dev); + continue; + } if (dev) { put_device(dev); continue; } - rc = ap_query_queue(qid, &queue_depth, &device_type); if (rc) continue; rc = ap_init_queue(qid); @@ -763,6 +768,7 @@ static void ap_scan_bus(void *data) break; ap_dev->qid = qid; ap_dev->queue_depth = queue_depth; + ap_dev->unregistered = 1; spin_lock_init(&ap_dev->lock); INIT_LIST_HEAD(&ap_dev->pendingq); INIT_LIST_HEAD(&ap_dev->requestq); @@ -784,7 +790,12 @@ static void ap_scan_bus(void *data) /* Add device attributes. */ rc = sysfs_create_group(&ap_dev->device.kobj, &ap_dev_attr_group); - if (rc) + if (!rc) { + spin_lock_bh(&ap_dev->lock); + ap_dev->unregistered = 0; + spin_unlock_bh(&ap_dev->lock); + } + else device_unregister(&ap_dev->device); } } @@ -970,6 +981,8 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) rc = __ap_queue_message(ap_dev, ap_msg); if (!rc) wake_up(&ap_poll_wait); + if (rc == -ENODEV) + ap_dev->unregistered = 1; } else { ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); rc = 0; @@ -1028,6 +1041,8 @@ static int __ap_poll_all(struct device *dev, void *data) spin_lock(&ap_dev->lock); if (!ap_dev->unregistered) { rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data); + if (rc) + ap_dev->unregistered = 1; } else rc = 0; spin_unlock(&ap_dev->lock); @@ -1061,7 +1076,7 @@ static int ap_poll_thread(void *data) unsigned long flags; int requests; - set_user_nice(current, -20); + set_user_nice(current, 19); while (1) { if (need_resched()) { schedule(); @@ -1114,6 +1129,19 @@ static void ap_poll_thread_stop(void) mutex_unlock(&ap_poll_thread_mutex); } +static void ap_reset(void) +{ + int i, j; + + for (i = 0; i < AP_DOMAINS; i++) + for (j = 0; j < AP_DEVICES; j++) + ap_reset_queue(AP_MKQID(j, i)); +} + +static struct reset_call ap_reset_call = { + .fn = ap_reset, +}; + /** * The module initialization code. */ @@ -1130,6 +1158,7 @@ int __init ap_module_init(void) printk(KERN_WARNING "AP instructions not installed.\n"); return -ENODEV; } + register_reset_call(&ap_reset_call); /* Create /sys/bus/ap. */ rc = bus_register(&ap_bus_type); @@ -1183,6 +1212,7 @@ out_bus: bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); bus_unregister(&ap_bus_type); out: + unregister_reset_call(&ap_reset_call); return rc; } @@ -1213,6 +1243,7 @@ void ap_module_exit(void) for (i = 0; ap_bus_attrs[i]; i++) bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); bus_unregister(&ap_bus_type); + unregister_reset_call(&ap_reset_call); } #ifndef CONFIG_ZCRYPT_MONOLITHIC |