summaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto/ap_bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r--drivers/s390/crypto/ap_bus.c65
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