Pull asus into release branch
[pandora-kernel.git] / drivers / s390 / crypto / ap_bus.c
index ad60afe..bf37cdf 100644 (file)
@@ -65,6 +65,8 @@ module_param_named(poll_thread, ap_thread_flag, int, 0000);
 MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 1 (on).");
 
 static struct device *ap_root_device = NULL;
+static DEFINE_SPINLOCK(ap_device_lock);
+static LIST_HEAD(ap_device_list);
 
 /**
  * Workqueue & timer for bus rescan.
@@ -457,6 +459,9 @@ static int ap_device_probe(struct device *dev)
        int rc;
 
        ap_dev->drv = ap_drv;
+       spin_lock_bh(&ap_device_lock);
+       list_add(&ap_dev->list, &ap_device_list);
+       spin_unlock_bh(&ap_device_lock);
        rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
        return rc;
 }
@@ -465,7 +470,7 @@ static int ap_device_probe(struct device *dev)
  * Flush all requests from the request/pending queue of an AP device.
  * @ap_dev: pointer to the AP device.
  */
-static inline void __ap_flush_queue(struct ap_device *ap_dev)
+static void __ap_flush_queue(struct ap_device *ap_dev)
 {
        struct ap_message *ap_msg, *next;
 
@@ -497,6 +502,12 @@ static int ap_device_remove(struct device *dev)
        ap_flush_queue(ap_dev);
        if (ap_drv->remove)
                ap_drv->remove(ap_dev);
+       spin_lock_bh(&ap_device_lock);
+       list_del_init(&ap_dev->list);
+       spin_unlock_bh(&ap_device_lock);
+       spin_lock_bh(&ap_dev->lock);
+       atomic_sub(ap_dev->queue_count, &ap_poll_requests);
+       spin_unlock_bh(&ap_dev->lock);
        return 0;
 }
 
@@ -587,7 +598,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
 /**
  * Pick one of the 16 ap domains.
  */
-static inline int ap_select_domain(void)
+static int ap_select_domain(void)
 {
        int queue_depth, device_type, count, max_count, best_domain;
        int rc, i, j;
@@ -749,10 +760,16 @@ static void ap_scan_bus(struct work_struct *unused)
                                      (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) {
+                       ap_dev = to_ap_dev(dev);
+                       spin_lock_bh(&ap_dev->lock);
+                       if (rc || ap_dev->unregistered) {
+                               spin_unlock_bh(&ap_dev->lock);
+                               put_device(dev);
+                               device_unregister(dev);
+                               continue;
+                       } else
+                               spin_unlock_bh(&ap_dev->lock);
                }
                if (dev) {
                        put_device(dev);
@@ -772,6 +789,7 @@ static void ap_scan_bus(struct work_struct *unused)
                spin_lock_init(&ap_dev->lock);
                INIT_LIST_HEAD(&ap_dev->pendingq);
                INIT_LIST_HEAD(&ap_dev->requestq);
+               INIT_LIST_HEAD(&ap_dev->list);
                if (device_type == 0)
                        ap_probe_device_type(ap_dev);
                else
@@ -825,7 +843,7 @@ static inline void ap_schedule_poll_timer(void)
  *        required, bit 2^1 is set if the poll timer needs to get armed
  * Returns 0 if the device is still present, -ENODEV if not.
  */
-static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
 {
        struct ap_queue_status status;
        struct ap_message *ap_msg;
@@ -852,6 +870,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
        case AP_RESPONSE_NO_PENDING_REPLY:
                if (status.queue_empty) {
                        /* The card shouldn't forget requests but who knows. */
+                       atomic_sub(ap_dev->queue_count, &ap_poll_requests);
                        ap_dev->queue_count = 0;
                        list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
                        ap_dev->requestq_count += ap_dev->pendingq_count;
@@ -872,7 +891,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
  *        required, bit 2^1 is set if the poll timer needs to get armed
  * Returns 0 if the device is still present, -ENODEV if not.
  */
-static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
 {
        struct ap_queue_status status;
        struct ap_message *ap_msg;
@@ -985,7 +1004,7 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
                        ap_dev->unregistered = 1;
        } else {
                ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
-               rc = 0;
+               rc = -ENODEV;
        }
        spin_unlock_bh(&ap_dev->lock);
        if (rc == -ENODEV)
@@ -1033,31 +1052,29 @@ static void ap_poll_timeout(unsigned long unused)
  * polling until bit 2^0 of the control flags is not set. If bit 2^1
  * of the control flags has been set arm the poll timer.
  */
-static int __ap_poll_all(struct device *dev, void *data)
+static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags)
 {
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       int rc;
-
        spin_lock(&ap_dev->lock);
        if (!ap_dev->unregistered) {
-               rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data);
-               if (rc)
+               if (ap_poll_queue(ap_dev, flags))
                        ap_dev->unregistered = 1;
-       } else
-               rc = 0;
+       }
        spin_unlock(&ap_dev->lock);
-       if (rc)
-               device_unregister(&ap_dev->device);
        return 0;
 }
 
 static void ap_poll_all(unsigned long dummy)
 {
        unsigned long flags;
+       struct ap_device *ap_dev;
 
        do {
                flags = 0;
-               bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
+               spin_lock(&ap_device_lock);
+               list_for_each_entry(ap_dev, &ap_device_list, list) {
+                       __ap_poll_all(ap_dev, &flags);
+               }
+               spin_unlock(&ap_device_lock);
        } while (flags & 1);
        if (flags & 2)
                ap_schedule_poll_timer();
@@ -1075,6 +1092,7 @@ static int ap_poll_thread(void *data)
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        int requests;
+       struct ap_device *ap_dev;
 
        set_user_nice(current, 19);
        while (1) {
@@ -1092,10 +1110,12 @@ static int ap_poll_thread(void *data)
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&ap_poll_wait, &wait);
 
-               local_bh_disable();
                flags = 0;
-               bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
-               local_bh_enable();
+               spin_lock_bh(&ap_device_lock);
+               list_for_each_entry(ap_dev, &ap_device_list, list) {
+                       __ap_poll_all(ap_dev, &flags);
+               }
+               spin_unlock_bh(&ap_device_lock);
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&ap_poll_wait, &wait);
@@ -1129,7 +1149,15 @@ static void ap_poll_thread_stop(void)
        mutex_unlock(&ap_poll_thread_mutex);
 }
 
-static void ap_reset(void)
+static void ap_reset_domain(void)
+{
+       int i;
+
+       for (i = 0; i < AP_DEVICES; i++)
+               ap_reset_queue(AP_MKQID(i, ap_domain_index));
+}
+
+static void ap_reset_all(void)
 {
        int i, j;
 
@@ -1139,7 +1167,7 @@ static void ap_reset(void)
 }
 
 static struct reset_call ap_reset_call = {
-       .fn = ap_reset,
+       .fn = ap_reset_all,
 };
 
 /**
@@ -1229,10 +1257,12 @@ void ap_module_exit(void)
        int i;
        struct device *dev;
 
+       ap_reset_domain();
        ap_poll_thread_stop();
        del_timer_sync(&ap_config_timer);
        del_timer_sync(&ap_poll_timer);
        destroy_workqueue(ap_work_queue);
+       tasklet_kill(&ap_tasklet);
        s390_root_dev_unregister(ap_root_device);
        while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,
                    __ap_match_all)))