aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/ccwgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/ccwgroup.c')
-rw-r--r--drivers/s390/cio/ccwgroup.c84
1 files changed, 42 insertions, 42 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 97b25d68e3e7..5c567414c4bb 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -67,6 +67,27 @@ __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
67} 67}
68 68
69/* 69/*
70 * Remove references from ccw devices to ccw group device and from
71 * ccw group device to ccw devices.
72 */
73static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev)
74{
75 struct ccw_device *cdev;
76 int i;
77
78 for (i = 0; i < gdev->count; i++) {
79 cdev = gdev->cdev[i];
80 if (!cdev)
81 continue;
82 spin_lock_irq(cdev->ccwlock);
83 dev_set_drvdata(&cdev->dev, NULL);
84 spin_unlock_irq(cdev->ccwlock);
85 gdev->cdev[i] = NULL;
86 put_device(&cdev->dev);
87 }
88}
89
90/*
70 * Provide an 'ungroup' attribute so the user can remove group devices no 91 * Provide an 'ungroup' attribute so the user can remove group devices no
71 * longer needed or accidentially created. Saves memory :) 92 * longer needed or accidentially created. Saves memory :)
72 */ 93 */
@@ -78,6 +99,7 @@ static void ccwgroup_ungroup_callback(struct device *dev)
78 if (device_is_registered(&gdev->dev)) { 99 if (device_is_registered(&gdev->dev)) {
79 __ccwgroup_remove_symlinks(gdev); 100 __ccwgroup_remove_symlinks(gdev);
80 device_unregister(dev); 101 device_unregister(dev);
102 __ccwgroup_remove_cdev_refs(gdev);
81 } 103 }
82 mutex_unlock(&gdev->reg_mutex); 104 mutex_unlock(&gdev->reg_mutex);
83} 105}
@@ -116,21 +138,7 @@ static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
116static void 138static void
117ccwgroup_release (struct device *dev) 139ccwgroup_release (struct device *dev)
118{ 140{
119 struct ccwgroup_device *gdev; 141 kfree(to_ccwgroupdev(dev));
120 int i;
121
122 gdev = to_ccwgroupdev(dev);
123
124 for (i = 0; i < gdev->count; i++) {
125 if (gdev->cdev[i]) {
126 spin_lock_irq(gdev->cdev[i]->ccwlock);
127 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
128 dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
129 spin_unlock_irq(gdev->cdev[i]->ccwlock);
130 put_device(&gdev->cdev[i]->dev);
131 }
132 }
133 kfree(gdev);
134} 142}
135 143
136static int 144static int
@@ -420,7 +428,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
420 gdev = to_ccwgroupdev(dev); 428 gdev = to_ccwgroupdev(dev);
421 gdrv = to_ccwgroupdrv(dev->driver); 429 gdrv = to_ccwgroupdrv(dev->driver);
422 430
423 if (!try_module_get(gdrv->owner)) 431 if (!try_module_get(gdrv->driver.owner))
424 return -EINVAL; 432 return -EINVAL;
425 433
426 ret = strict_strtoul(buf, 0, &value); 434 ret = strict_strtoul(buf, 0, &value);
@@ -434,7 +442,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
434 else 442 else
435 ret = -EINVAL; 443 ret = -EINVAL;
436out: 444out:
437 module_put(gdrv->owner); 445 module_put(gdrv->driver.owner);
438 return (ret == 0) ? count : ret; 446 return (ret == 0) ? count : ret;
439} 447}
440 448
@@ -608,8 +616,6 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
608{ 616{
609 /* register our new driver with the core */ 617 /* register our new driver with the core */
610 cdriver->driver.bus = &ccwgroup_bus_type; 618 cdriver->driver.bus = &ccwgroup_bus_type;
611 cdriver->driver.name = cdriver->name;
612 cdriver->driver.owner = cdriver->owner;
613 619
614 return driver_register(&cdriver->driver); 620 return driver_register(&cdriver->driver);
615} 621}
@@ -639,6 +645,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
639 mutex_lock(&gdev->reg_mutex); 645 mutex_lock(&gdev->reg_mutex);
640 __ccwgroup_remove_symlinks(gdev); 646 __ccwgroup_remove_symlinks(gdev);
641 device_unregister(dev); 647 device_unregister(dev);
648 __ccwgroup_remove_cdev_refs(gdev);
642 mutex_unlock(&gdev->reg_mutex); 649 mutex_unlock(&gdev->reg_mutex);
643 put_device(dev); 650 put_device(dev);
644 } 651 }
@@ -660,25 +667,6 @@ int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
660 return 0; 667 return 0;
661} 668}
662 669
663static struct ccwgroup_device *
664__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
665{
666 struct ccwgroup_device *gdev;
667
668 gdev = dev_get_drvdata(&cdev->dev);
669 if (gdev) {
670 if (get_device(&gdev->dev)) {
671 mutex_lock(&gdev->reg_mutex);
672 if (device_is_registered(&gdev->dev))
673 return gdev;
674 mutex_unlock(&gdev->reg_mutex);
675 put_device(&gdev->dev);
676 }
677 return NULL;
678 }
679 return NULL;
680}
681
682/** 670/**
683 * ccwgroup_remove_ccwdev() - remove function for slave devices 671 * ccwgroup_remove_ccwdev() - remove function for slave devices
684 * @cdev: ccw device to be removed 672 * @cdev: ccw device to be removed
@@ -694,13 +682,25 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
694 /* Ignore offlining errors, device is gone anyway. */ 682 /* Ignore offlining errors, device is gone anyway. */
695 ccw_device_set_offline(cdev); 683 ccw_device_set_offline(cdev);
696 /* If one of its devices is gone, the whole group is done for. */ 684 /* If one of its devices is gone, the whole group is done for. */
697 gdev = __ccwgroup_get_gdev_by_cdev(cdev); 685 spin_lock_irq(cdev->ccwlock);
698 if (gdev) { 686 gdev = dev_get_drvdata(&cdev->dev);
687 if (!gdev) {
688 spin_unlock_irq(cdev->ccwlock);
689 return;
690 }
691 /* Get ccwgroup device reference for local processing. */
692 get_device(&gdev->dev);
693 spin_unlock_irq(cdev->ccwlock);
694 /* Unregister group device. */
695 mutex_lock(&gdev->reg_mutex);
696 if (device_is_registered(&gdev->dev)) {
699 __ccwgroup_remove_symlinks(gdev); 697 __ccwgroup_remove_symlinks(gdev);
700 device_unregister(&gdev->dev); 698 device_unregister(&gdev->dev);
701 mutex_unlock(&gdev->reg_mutex); 699 __ccwgroup_remove_cdev_refs(gdev);
702 put_device(&gdev->dev);
703 } 700 }
701 mutex_unlock(&gdev->reg_mutex);
702 /* Release ccwgroup device reference for local processing. */
703 put_device(&gdev->dev);
704} 704}
705 705
706MODULE_LICENSE("GPL"); 706MODULE_LICENSE("GPL");