diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2006-12-08 09:54:21 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-12-08 09:54:21 -0500 |
commit | 7674da77cb2d27ae6559c55151da171ceb02beb4 (patch) | |
tree | dca2646cd8d6d2a36cbddbeb4f38fab2e12e8f7b /drivers/s390/cio/device.c | |
parent | 34249d0f9243fce773c2fa352934ba108320e234 (diff) |
[S390] Some preparations for the dynamic subchannel mapping patch.
- Move adding subchannel attributes to css_register_subchannel().
- Don't call device_trigger_reprobe() for non-operational devices.
- Introduce io_subchannel_create_ccwdev().
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r-- | drivers/s390/cio/device.c | 107 |
1 files changed, 65 insertions, 42 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 0f604621de40..e644fd6905ee 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -294,6 +294,18 @@ online_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
294 | return sprintf(buf, cdev->online ? "1\n" : "0\n"); | 294 | return sprintf(buf, cdev->online ? "1\n" : "0\n"); |
295 | } | 295 | } |
296 | 296 | ||
297 | static void ccw_device_unregister(struct work_struct *work) | ||
298 | { | ||
299 | struct ccw_device_private *priv; | ||
300 | struct ccw_device *cdev; | ||
301 | |||
302 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
303 | cdev = priv->cdev; | ||
304 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
305 | device_unregister(&cdev->dev); | ||
306 | put_device(&cdev->dev); | ||
307 | } | ||
308 | |||
297 | static void | 309 | static void |
298 | ccw_device_remove_disconnected(struct ccw_device *cdev) | 310 | ccw_device_remove_disconnected(struct ccw_device *cdev) |
299 | { | 311 | { |
@@ -498,8 +510,7 @@ static struct attribute_group subch_attr_group = { | |||
498 | .attrs = subch_attrs, | 510 | .attrs = subch_attrs, |
499 | }; | 511 | }; |
500 | 512 | ||
501 | static inline int | 513 | int subchannel_add_files (struct device *dev) |
502 | subchannel_add_files (struct device *dev) | ||
503 | { | 514 | { |
504 | return sysfs_create_group(&dev->kobj, &subch_attr_group); | 515 | return sysfs_create_group(&dev->kobj, &subch_attr_group); |
505 | } | 516 | } |
@@ -676,6 +687,55 @@ ccw_device_release(struct device *dev) | |||
676 | kfree(cdev); | 687 | kfree(cdev); |
677 | } | 688 | } |
678 | 689 | ||
690 | static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) | ||
691 | { | ||
692 | struct ccw_device *cdev; | ||
693 | |||
694 | cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); | ||
695 | if (cdev) { | ||
696 | cdev->private = kzalloc(sizeof(struct ccw_device_private), | ||
697 | GFP_KERNEL | GFP_DMA); | ||
698 | if (cdev->private) | ||
699 | return cdev; | ||
700 | } | ||
701 | kfree(cdev); | ||
702 | return ERR_PTR(-ENOMEM); | ||
703 | } | ||
704 | |||
705 | static int io_subchannel_initialize_dev(struct subchannel *sch, | ||
706 | struct ccw_device *cdev) | ||
707 | { | ||
708 | cdev->private->cdev = cdev; | ||
709 | atomic_set(&cdev->private->onoff, 0); | ||
710 | cdev->dev.parent = &sch->dev; | ||
711 | cdev->dev.release = ccw_device_release; | ||
712 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | ||
713 | /* Do first half of device_register. */ | ||
714 | device_initialize(&cdev->dev); | ||
715 | if (!get_device(&sch->dev)) { | ||
716 | if (cdev->dev.release) | ||
717 | cdev->dev.release(&cdev->dev); | ||
718 | return -ENODEV; | ||
719 | } | ||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch) | ||
724 | { | ||
725 | struct ccw_device *cdev; | ||
726 | int ret; | ||
727 | |||
728 | cdev = io_subchannel_allocate_dev(sch); | ||
729 | if (!IS_ERR(cdev)) { | ||
730 | ret = io_subchannel_initialize_dev(sch, cdev); | ||
731 | if (ret) { | ||
732 | kfree(cdev); | ||
733 | cdev = ERR_PTR(ret); | ||
734 | } | ||
735 | } | ||
736 | return cdev; | ||
737 | } | ||
738 | |||
679 | /* | 739 | /* |
680 | * Register recognized device. | 740 | * Register recognized device. |
681 | */ | 741 | */ |
@@ -724,11 +784,6 @@ io_subchannel_register(struct work_struct *work) | |||
724 | wake_up(&ccw_device_init_wq); | 784 | wake_up(&ccw_device_init_wq); |
725 | return; | 785 | return; |
726 | } | 786 | } |
727 | |||
728 | ret = subchannel_add_files(cdev->dev.parent); | ||
729 | if (ret) | ||
730 | printk(KERN_WARNING "%s: could not add attributes to %s\n", | ||
731 | __func__, sch->dev.bus_id); | ||
732 | put_device(&cdev->dev); | 787 | put_device(&cdev->dev); |
733 | out: | 788 | out: |
734 | cdev->private->flags.recog_done = 1; | 789 | cdev->private->flags.recog_done = 1; |
@@ -851,7 +906,6 @@ io_subchannel_probe (struct subchannel *sch) | |||
851 | cdev = sch->dev.driver_data; | 906 | cdev = sch->dev.driver_data; |
852 | device_initialize(&cdev->dev); | 907 | device_initialize(&cdev->dev); |
853 | ccw_device_register(cdev); | 908 | ccw_device_register(cdev); |
854 | subchannel_add_files(&sch->dev); | ||
855 | /* | 909 | /* |
856 | * Check if the device is already online. If it is | 910 | * Check if the device is already online. If it is |
857 | * the reference count needs to be corrected | 911 | * the reference count needs to be corrected |
@@ -864,28 +918,9 @@ io_subchannel_probe (struct subchannel *sch) | |||
864 | get_device(&cdev->dev); | 918 | get_device(&cdev->dev); |
865 | return 0; | 919 | return 0; |
866 | } | 920 | } |
867 | cdev = kzalloc (sizeof(*cdev), GFP_KERNEL); | 921 | cdev = io_subchannel_create_ccwdev(sch); |
868 | if (!cdev) | 922 | if (IS_ERR(cdev)) |
869 | return -ENOMEM; | 923 | return PTR_ERR(cdev); |
870 | cdev->private = kzalloc(sizeof(struct ccw_device_private), | ||
871 | GFP_KERNEL | GFP_DMA); | ||
872 | if (!cdev->private) { | ||
873 | kfree(cdev); | ||
874 | return -ENOMEM; | ||
875 | } | ||
876 | cdev->private->cdev = cdev; | ||
877 | atomic_set(&cdev->private->onoff, 0); | ||
878 | cdev->dev.parent = &sch->dev; | ||
879 | cdev->dev.release = ccw_device_release; | ||
880 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | ||
881 | /* Do first half of device_register. */ | ||
882 | device_initialize(&cdev->dev); | ||
883 | |||
884 | if (!get_device(&sch->dev)) { | ||
885 | if (cdev->dev.release) | ||
886 | cdev->dev.release(&cdev->dev); | ||
887 | return -ENODEV; | ||
888 | } | ||
889 | 924 | ||
890 | rc = io_subchannel_recog(cdev, sch); | 925 | rc = io_subchannel_recog(cdev, sch); |
891 | if (rc) { | 926 | if (rc) { |
@@ -899,18 +934,6 @@ io_subchannel_probe (struct subchannel *sch) | |||
899 | return rc; | 934 | return rc; |
900 | } | 935 | } |
901 | 936 | ||
902 | static void ccw_device_unregister(struct work_struct *work) | ||
903 | { | ||
904 | struct ccw_device_private *priv; | ||
905 | struct ccw_device *cdev; | ||
906 | |||
907 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
908 | cdev = priv->cdev; | ||
909 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
910 | device_unregister(&cdev->dev); | ||
911 | put_device(&cdev->dev); | ||
912 | } | ||
913 | |||
914 | static int | 937 | static int |
915 | io_subchannel_remove (struct subchannel *sch) | 938 | io_subchannel_remove (struct subchannel *sch) |
916 | { | 939 | { |