[S390] cio: Use unbind/bind instead of unregister/register.
authorCornelia Huck <cornelia.huck@de.ibm.com>
Thu, 26 Mar 2009 14:24:05 +0000 (15:24 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 26 Mar 2009 14:24:12 +0000 (15:24 +0100)
The common I/O layer may encounter a situation where the
device number of a ccw device has changed or a device
driver doesn't want to keep a formerly disconnected device
becoming operational again. Instead of using device_del()/
device_add() as now, we can just unbind the driver from the
device and rebind it to get the desired effect (rebinding)
with less overhead.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c

index 23d5752..71b3b73 100644 (file)
@@ -681,35 +681,22 @@ get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
        return dev ? to_ccwdev(dev) : NULL;
 }
 
-static void
-ccw_device_add_changed(struct work_struct *work)
-{
-       struct ccw_device_private *priv;
-       struct ccw_device *cdev;
-
-       priv = container_of(work, struct ccw_device_private, kick_work);
-       cdev = priv->cdev;
-       if (device_add(&cdev->dev)) {
-               put_device(&cdev->dev);
-               return;
-       }
-       set_bit(1, &cdev->private->registered);
-}
-
-void ccw_device_do_unreg_rereg(struct work_struct *work)
+void ccw_device_do_unbind_bind(struct work_struct *work)
 {
        struct ccw_device_private *priv;
        struct ccw_device *cdev;
        struct subchannel *sch;
+       int ret;
 
        priv = container_of(work, struct ccw_device_private, kick_work);
        cdev = priv->cdev;
        sch = to_subchannel(cdev->dev.parent);
 
-       ccw_device_unregister(cdev);
-       PREPARE_WORK(&cdev->private->kick_work,
-                    ccw_device_add_changed);
-       queue_work(ccw_device_work, &cdev->private->kick_work);
+       if (test_bit(1, &cdev->private->registered)) {
+               device_release_driver(&cdev->dev);
+               ret = device_attach(&cdev->dev);
+               WARN_ON(ret == -ENODEV);
+       }
 }
 
 static void
index 0f2e63e..85e0184 100644 (file)
@@ -80,7 +80,7 @@ void io_subchannel_init_config(struct subchannel *sch);
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
 
-void ccw_device_do_unreg_rereg(struct work_struct *);
+void ccw_device_do_unbind_bind(struct work_struct *);
 void ccw_device_move_to_orphanage(struct work_struct *);
 int ccw_device_is_orphan(struct ccw_device *);
 
index 8df5eaa..95f2f35 100644 (file)
@@ -194,7 +194,7 @@ ccw_device_handle_oper(struct ccw_device *cdev)
            cdev->id.dev_type != cdev->private->senseid.dev_type ||
            cdev->id.dev_model != cdev->private->senseid.dev_model) {
                PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_do_unreg_rereg);
+                            ccw_device_do_unbind_bind);
                queue_work(ccw_device_work, &cdev->private->kick_work);
                return 0;
        }
@@ -366,7 +366,7 @@ static void ccw_device_oper_notify(struct ccw_device *cdev)
        }
        /* Driver doesn't want device back. */
        ccw_device_set_notoper(cdev);
-       PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unreg_rereg);
+       PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind);
        queue_work(ccw_device_work, &cdev->private->kick_work);
 }