From eb32ae8d0e052d1a287f99f93130ea2ad9af317e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 26 Mar 2009 15:24:05 +0100 Subject: [PATCH] [S390] cio: Use unbind/bind instead of unregister/register. 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 Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 27 +++++++-------------------- drivers/s390/cio/device.h | 2 +- drivers/s390/cio/device_fsm.c | 4 ++-- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 23d5752349b5..71b3b73e8ebe 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -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 diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 0f2e63ea48de..85e01846ca65 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -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 *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8df5eaafc5ab..95f2f352cb9d 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -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); }