aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2008-10-10 15:33:05 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-10-10 15:33:47 -0400
commit46fbe4e46ddb88805245a24f684400b50ead68a7 (patch)
tree0a8257d7802a8b15567bc8275b770a6b79e69a9d /drivers/s390/cio/device.c
parent4bcb3a37180ee4dffaef8298f373b334a7bedabb (diff)
[S390] cio: move device unregistration to dedicated work queue
Use dedicated slow path work queue when unregistering a device due to a user action. This ensures serialialization of other register/ unregister requests. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r--drivers/s390/cio/device.c56
1 files changed, 25 insertions, 31 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 28221030b886..38a79ecfc743 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -296,36 +296,33 @@ static void ccw_device_unregister(struct ccw_device *cdev)
296 device_del(&cdev->dev); 296 device_del(&cdev->dev);
297} 297}
298 298
299static void ccw_device_remove_orphan_cb(struct device *dev) 299static void ccw_device_remove_orphan_cb(struct work_struct *work)
300{ 300{
301 struct ccw_device *cdev = to_ccwdev(dev); 301 struct ccw_device_private *priv;
302 struct ccw_device *cdev;
302 303
304 priv = container_of(work, struct ccw_device_private, kick_work);
305 cdev = priv->cdev;
303 ccw_device_unregister(cdev); 306 ccw_device_unregister(cdev);
304 put_device(&cdev->dev); 307 put_device(&cdev->dev);
308 /* Release cdev reference for workqueue processing. */
309 put_device(&cdev->dev);
305} 310}
306 311
307static void ccw_device_remove_sch_cb(struct device *dev) 312static void ccw_device_call_sch_unregister(struct work_struct *work);
308{
309 struct subchannel *sch;
310
311 sch = to_subchannel(dev);
312 css_sch_device_unregister(sch);
313 /* Reset intparm to zeroes. */
314 sch->schib.pmcw.intparm = 0;
315 cio_modify(sch);
316 put_device(&sch->dev);
317}
318 313
319static void 314static void
320ccw_device_remove_disconnected(struct ccw_device *cdev) 315ccw_device_remove_disconnected(struct ccw_device *cdev)
321{ 316{
322 unsigned long flags; 317 unsigned long flags;
323 int rc;
324 318
325 /* 319 /*
326 * Forced offline in disconnected state means 320 * Forced offline in disconnected state means
327 * 'throw away device'. 321 * 'throw away device'.
328 */ 322 */
323 /* Get cdev reference for workqueue processing. */
324 if (!get_device(&cdev->dev))
325 return;
329 if (ccw_device_is_orphan(cdev)) { 326 if (ccw_device_is_orphan(cdev)) {
330 /* 327 /*
331 * Deregister ccw device. 328 * Deregister ccw device.
@@ -335,23 +332,13 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
335 spin_lock_irqsave(cdev->ccwlock, flags); 332 spin_lock_irqsave(cdev->ccwlock, flags);
336 cdev->private->state = DEV_STATE_NOT_OPER; 333 cdev->private->state = DEV_STATE_NOT_OPER;
337 spin_unlock_irqrestore(cdev->ccwlock, flags); 334 spin_unlock_irqrestore(cdev->ccwlock, flags);
338 rc = device_schedule_callback(&cdev->dev, 335 PREPARE_WORK(&cdev->private->kick_work,
339 ccw_device_remove_orphan_cb); 336 ccw_device_remove_orphan_cb);
340 if (rc) 337 } else
341 CIO_MSG_EVENT(0, "Couldn't unregister orphan " 338 /* Deregister subchannel, which will kill the ccw device. */
342 "0.%x.%04x\n", 339 PREPARE_WORK(&cdev->private->kick_work,
343 cdev->private->dev_id.ssid, 340 ccw_device_call_sch_unregister);
344 cdev->private->dev_id.devno); 341 queue_work(slow_path_wq, &cdev->private->kick_work);
345 return;
346 }
347 /* Deregister subchannel, which will kill the ccw device. */
348 rc = device_schedule_callback(cdev->dev.parent,
349 ccw_device_remove_sch_cb);
350 if (rc)
351 CIO_MSG_EVENT(0, "Couldn't unregister disconnected device "
352 "0.%x.%04x\n",
353 cdev->private->dev_id.ssid,
354 cdev->private->dev_id.devno);
355} 342}
356 343
357/** 344/**
@@ -970,12 +957,17 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
970 957
971 priv = container_of(work, struct ccw_device_private, kick_work); 958 priv = container_of(work, struct ccw_device_private, kick_work);
972 cdev = priv->cdev; 959 cdev = priv->cdev;
960 /* Get subchannel reference for local processing. */
961 if (!get_device(cdev->dev.parent))
962 return;
973 sch = to_subchannel(cdev->dev.parent); 963 sch = to_subchannel(cdev->dev.parent);
974 css_sch_device_unregister(sch); 964 css_sch_device_unregister(sch);
975 /* Reset intparm to zeroes. */ 965 /* Reset intparm to zeroes. */
976 sch->schib.pmcw.intparm = 0; 966 sch->schib.pmcw.intparm = 0;
977 cio_modify(sch); 967 cio_modify(sch);
968 /* Release cdev reference for workqueue processing.*/
978 put_device(&cdev->dev); 969 put_device(&cdev->dev);
970 /* Release subchannel reference for local processing. */
979 put_device(&sch->dev); 971 put_device(&sch->dev);
980} 972}
981 973
@@ -1001,6 +993,8 @@ io_subchannel_recog_done(struct ccw_device *cdev)
1001 PREPARE_WORK(&cdev->private->kick_work, 993 PREPARE_WORK(&cdev->private->kick_work,
1002 ccw_device_call_sch_unregister); 994 ccw_device_call_sch_unregister);
1003 queue_work(slow_path_wq, &cdev->private->kick_work); 995 queue_work(slow_path_wq, &cdev->private->kick_work);
996 /* Release subchannel reference for asynchronous recognition. */
997 put_device(&sch->dev);
1004 if (atomic_dec_and_test(&ccw_device_init_count)) 998 if (atomic_dec_and_test(&ccw_device_init_count))
1005 wake_up(&ccw_device_init_wq); 999 wake_up(&ccw_device_init_wq);
1006 break; 1000 break;