aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/device.c75
1 files changed, 56 insertions, 19 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 039ef03cf217..cba33aa1df79 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -718,6 +718,8 @@ ccw_device_release(struct device *dev)
718 struct ccw_device *cdev; 718 struct ccw_device *cdev;
719 719
720 cdev = to_ccwdev(dev); 720 cdev = to_ccwdev(dev);
721 /* Release reference of parent subchannel. */
722 put_device(cdev->dev.parent);
721 kfree(cdev->private); 723 kfree(cdev->private);
722 kfree(cdev); 724 kfree(cdev);
723} 725}
@@ -792,37 +794,55 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
792 struct subchannel *other_sch; 794 struct subchannel *other_sch;
793 int ret; 795 int ret;
794 796
795 other_sch = to_subchannel(get_device(cdev->dev.parent)); 797 /* Get reference for new parent. */
798 if (!get_device(&sch->dev))
799 return;
800 other_sch = to_subchannel(cdev->dev.parent);
801 /* Note: device_move() changes cdev->dev.parent */
796 ret = device_move(&cdev->dev, &sch->dev); 802 ret = device_move(&cdev->dev, &sch->dev);
797 if (ret) { 803 if (ret) {
798 CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed " 804 CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
799 "(ret=%d)!\n", cdev->private->dev_id.ssid, 805 "(ret=%d)!\n", cdev->private->dev_id.ssid,
800 cdev->private->dev_id.devno, ret); 806 cdev->private->dev_id.devno, ret);
801 put_device(&other_sch->dev); 807 /* Put reference for new parent. */
808 put_device(&sch->dev);
802 return; 809 return;
803 } 810 }
804 sch_set_cdev(other_sch, NULL); 811 sch_set_cdev(other_sch, NULL);
805 /* No need to keep a subchannel without ccw device around. */ 812 /* No need to keep a subchannel without ccw device around. */
806 css_sch_device_unregister(other_sch); 813 css_sch_device_unregister(other_sch);
807 put_device(&other_sch->dev);
808 sch_attach_device(sch, cdev); 814 sch_attach_device(sch, cdev);
815 /* Put reference for old parent. */
816 put_device(&other_sch->dev);
809} 817}
810 818
811static void sch_attach_orphaned_device(struct subchannel *sch, 819static void sch_attach_orphaned_device(struct subchannel *sch,
812 struct ccw_device *cdev) 820 struct ccw_device *cdev)
813{ 821{
814 int ret; 822 int ret;
823 struct subchannel *pseudo_sch;
815 824
816 /* Try to move the ccw device to its new subchannel. */ 825 /* Get reference for new parent. */
826 if (!get_device(&sch->dev))
827 return;
828 pseudo_sch = to_subchannel(cdev->dev.parent);
829 /*
830 * Try to move the ccw device to its new subchannel.
831 * Note: device_move() changes cdev->dev.parent
832 */
817 ret = device_move(&cdev->dev, &sch->dev); 833 ret = device_move(&cdev->dev, &sch->dev);
818 if (ret) { 834 if (ret) {
819 CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " 835 CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
820 "failed (ret=%d)!\n", 836 "failed (ret=%d)!\n",
821 cdev->private->dev_id.ssid, 837 cdev->private->dev_id.ssid,
822 cdev->private->dev_id.devno, ret); 838 cdev->private->dev_id.devno, ret);
839 /* Put reference for new parent. */
840 put_device(&sch->dev);
823 return; 841 return;
824 } 842 }
825 sch_attach_device(sch, cdev); 843 sch_attach_device(sch, cdev);
844 /* Put reference on pseudo subchannel. */
845 put_device(&pseudo_sch->dev);
826} 846}
827 847
828static void sch_create_and_recog_new_device(struct subchannel *sch) 848static void sch_create_and_recog_new_device(struct subchannel *sch)
@@ -844,9 +864,11 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
844 spin_lock_irq(sch->lock); 864 spin_lock_irq(sch->lock);
845 sch_set_cdev(sch, NULL); 865 sch_set_cdev(sch, NULL);
846 spin_unlock_irq(sch->lock); 866 spin_unlock_irq(sch->lock);
847 if (cdev->dev.release)
848 cdev->dev.release(&cdev->dev);
849 css_sch_device_unregister(sch); 867 css_sch_device_unregister(sch);
868 /* Put reference from io_subchannel_create_ccwdev(). */
869 put_device(&sch->dev);
870 /* Give up initial reference. */
871 put_device(&cdev->dev);
850 } 872 }
851} 873}
852 874
@@ -868,15 +890,20 @@ void ccw_device_move_to_orphanage(struct work_struct *work)
868 dev_id.devno = sch->schib.pmcw.dev; 890 dev_id.devno = sch->schib.pmcw.dev;
869 dev_id.ssid = sch->schid.ssid; 891 dev_id.ssid = sch->schid.ssid;
870 892
893 /* Increase refcount for pseudo subchannel. */
894 get_device(&css->pseudo_subchannel->dev);
871 /* 895 /*
872 * Move the orphaned ccw device to the orphanage so the replacing 896 * Move the orphaned ccw device to the orphanage so the replacing
873 * ccw device can take its place on the subchannel. 897 * ccw device can take its place on the subchannel.
898 * Note: device_move() changes cdev->dev.parent
874 */ 899 */
875 ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); 900 ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev);
876 if (ret) { 901 if (ret) {
877 CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " 902 CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
878 "(ret=%d)!\n", cdev->private->dev_id.ssid, 903 "(ret=%d)!\n", cdev->private->dev_id.ssid,
879 cdev->private->dev_id.devno, ret); 904 cdev->private->dev_id.devno, ret);
905 /* Decrease refcount for pseudo subchannel again. */
906 put_device(&css->pseudo_subchannel->dev);
880 return; 907 return;
881 } 908 }
882 cdev->ccwlock = css->pseudo_subchannel->lock; 909 cdev->ccwlock = css->pseudo_subchannel->lock;
@@ -890,6 +917,8 @@ void ccw_device_move_to_orphanage(struct work_struct *work)
890 sch_attach_disconnected_device(sch, replacing_cdev); 917 sch_attach_disconnected_device(sch, replacing_cdev);
891 /* Release reference from get_disc_ccwdev_by_dev_id() */ 918 /* Release reference from get_disc_ccwdev_by_dev_id() */
892 put_device(&replacing_cdev->dev); 919 put_device(&replacing_cdev->dev);
920 /* Release reference of subchannel from old cdev. */
921 put_device(&sch->dev);
893 return; 922 return;
894 } 923 }
895 replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id); 924 replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
@@ -897,9 +926,13 @@ void ccw_device_move_to_orphanage(struct work_struct *work)
897 sch_attach_orphaned_device(sch, replacing_cdev); 926 sch_attach_orphaned_device(sch, replacing_cdev);
898 /* Release reference from get_orphaned_ccwdev_by_dev_id() */ 927 /* Release reference from get_orphaned_ccwdev_by_dev_id() */
899 put_device(&replacing_cdev->dev); 928 put_device(&replacing_cdev->dev);
929 /* Release reference of subchannel from old cdev. */
930 put_device(&sch->dev);
900 return; 931 return;
901 } 932 }
902 sch_create_and_recog_new_device(sch); 933 sch_create_and_recog_new_device(sch);
934 /* Release reference of subchannel from old cdev. */
935 put_device(&sch->dev);
903} 936}
904 937
905/* 938/*
@@ -948,13 +981,13 @@ io_subchannel_register(struct work_struct *work)
948 CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", 981 CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n",
949 cdev->private->dev_id.ssid, 982 cdev->private->dev_id.ssid,
950 cdev->private->dev_id.devno, ret); 983 cdev->private->dev_id.devno, ret);
951 put_device(&cdev->dev);
952 spin_lock_irqsave(sch->lock, flags); 984 spin_lock_irqsave(sch->lock, flags);
953 sch_set_cdev(sch, NULL); 985 sch_set_cdev(sch, NULL);
954 spin_unlock_irqrestore(sch->lock, flags); 986 spin_unlock_irqrestore(sch->lock, flags);
955 kfree (cdev->private); 987 /* Release reference for workqueue processing. */
956 kfree (cdev); 988 put_device(&cdev->dev);
957 put_device(&sch->dev); 989 /* Release initial device reference. */
990 put_device(&cdev->dev);
958 if (atomic_dec_and_test(&ccw_device_init_count)) 991 if (atomic_dec_and_test(&ccw_device_init_count))
959 wake_up(&ccw_device_init_wq); 992 wake_up(&ccw_device_init_wq);
960 return; 993 return;
@@ -962,7 +995,6 @@ io_subchannel_register(struct work_struct *work)
962 put_device(&cdev->dev); 995 put_device(&cdev->dev);
963out: 996out:
964 cdev->private->flags.recog_done = 1; 997 cdev->private->flags.recog_done = 1;
965 put_device(&sch->dev);
966 wake_up(&cdev->private->wait_q); 998 wake_up(&cdev->private->wait_q);
967 if (atomic_dec_and_test(&ccw_device_init_count)) 999 if (atomic_dec_and_test(&ccw_device_init_count))
968 wake_up(&ccw_device_init_wq); 1000 wake_up(&ccw_device_init_wq);
@@ -1012,8 +1044,6 @@ io_subchannel_recog_done(struct ccw_device *cdev)
1012 PREPARE_WORK(&cdev->private->kick_work, 1044 PREPARE_WORK(&cdev->private->kick_work,
1013 ccw_device_call_sch_unregister); 1045 ccw_device_call_sch_unregister);
1014 queue_work(slow_path_wq, &cdev->private->kick_work); 1046 queue_work(slow_path_wq, &cdev->private->kick_work);
1015 /* Release subchannel reference for asynchronous recognition. */
1016 put_device(&sch->dev);
1017 if (atomic_dec_and_test(&ccw_device_init_count)) 1047 if (atomic_dec_and_test(&ccw_device_init_count))
1018 wake_up(&ccw_device_init_wq); 1048 wake_up(&ccw_device_init_wq);
1019 break; 1049 break;
@@ -1084,10 +1114,15 @@ static void ccw_device_move_to_sch(struct work_struct *work)
1084 priv = container_of(work, struct ccw_device_private, kick_work); 1114 priv = container_of(work, struct ccw_device_private, kick_work);
1085 sch = priv->sch; 1115 sch = priv->sch;
1086 cdev = priv->cdev; 1116 cdev = priv->cdev;
1087 former_parent = ccw_device_is_orphan(cdev) ? 1117 former_parent = to_subchannel(cdev->dev.parent);
1088 NULL : to_subchannel(get_device(cdev->dev.parent)); 1118 /* Get reference for new parent. */
1119 if (!get_device(&sch->dev))
1120 return;
1089 mutex_lock(&sch->reg_mutex); 1121 mutex_lock(&sch->reg_mutex);
1090 /* Try to move the ccw device to its new subchannel. */ 1122 /*
1123 * Try to move the ccw device to its new subchannel.
1124 * Note: device_move() changes cdev->dev.parent
1125 */
1091 rc = device_move(&cdev->dev, &sch->dev); 1126 rc = device_move(&cdev->dev, &sch->dev);
1092 mutex_unlock(&sch->reg_mutex); 1127 mutex_unlock(&sch->reg_mutex);
1093 if (rc) { 1128 if (rc) {
@@ -1097,9 +1132,11 @@ static void ccw_device_move_to_sch(struct work_struct *work)
1097 cdev->private->dev_id.devno, sch->schid.ssid, 1132 cdev->private->dev_id.devno, sch->schid.ssid,
1098 sch->schid.sch_no, rc); 1133 sch->schid.sch_no, rc);
1099 css_sch_device_unregister(sch); 1134 css_sch_device_unregister(sch);
1135 /* Put reference for new parent again. */
1136 put_device(&sch->dev);
1100 goto out; 1137 goto out;
1101 } 1138 }
1102 if (former_parent) { 1139 if (!sch_is_pseudo_sch(former_parent)) {
1103 spin_lock_irq(former_parent->lock); 1140 spin_lock_irq(former_parent->lock);
1104 sch_set_cdev(former_parent, NULL); 1141 sch_set_cdev(former_parent, NULL);
1105 spin_unlock_irq(former_parent->lock); 1142 spin_unlock_irq(former_parent->lock);
@@ -1110,8 +1147,8 @@ static void ccw_device_move_to_sch(struct work_struct *work)
1110 } 1147 }
1111 sch_attach_device(sch, cdev); 1148 sch_attach_device(sch, cdev);
1112out: 1149out:
1113 if (former_parent) 1150 /* Put reference for old parent. */
1114 put_device(&former_parent->dev); 1151 put_device(&former_parent->dev);
1115 put_device(&cdev->dev); 1152 put_device(&cdev->dev);
1116} 1153}
1117 1154