+++ /dev/null
-From fb8b5a39b6310379d7b54c0c7113703a8eaf4a57 Mon Sep 17 00:00:00 2001
-From: Zhao Yakui <yakui.zhao@intel.com>
-Date: Wed, 7 Apr 2010 17:11:19 +0800
-Subject: drm/i915: Configure the TV sense state correctly on GM45 to make TV detection reliable
-
-From: Zhao Yakui <yakui.zhao@intel.com>
-
-commit fb8b5a39b6310379d7b54c0c7113703a8eaf4a57 upstream.
-
-The TV detection logic is not reliable on the Cantiga platform.
-Sometimes the TV will be misdetected as the following two cases:
-- TV is misdetected on some laptops. e.g. There is no TV connector
-port or no TV is attached. But the TV is shown as connected.
-- TV connector type is misdetected. e.g. the component TV is
-attached, but the TV is shown as S-video type.
-
-According to the hardware requirement, the TV sense state bits of TV DAC
-register should be cleared to zero on Cantiga platfrom.
-
-https://bugzilla.kernel.org/show_bug.cgi?id=14792
-
-Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
-Tested-by: Santi <santi@agolina.net>
-Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
-Signed-off-by: Eric Anholt <eric@anholt.net>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- drivers/gpu/drm/i915/intel_tv.c | 9 +++++++++
- 1 file changed, 9 insertions(+)
-
---- a/drivers/gpu/drm/i915/intel_tv.c
-+++ b/drivers/gpu/drm/i915/intel_tv.c
-@@ -1399,6 +1399,15 @@ intel_tv_detect_type (struct drm_crtc *c
- DAC_A_0_7_V |
- DAC_B_0_7_V |
- DAC_C_0_7_V);
-+
-+ /*
-+ * The TV sense state should be cleared to zero on cantiga platform. Otherwise
-+ * the TV is misdetected. This is hardware requirement.
-+ */
-+ if (IS_GM45(dev))
-+ tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
-+ TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
-+
- I915_WRITE(TV_CTL, tv_ctl);
- I915_WRITE(TV_DAC, tv_dac);
- intel_wait_for_vblank(dev);
--- /dev/null
+From a64c876fd357906a1f7193723866562ad290654c Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Wed, 14 Apr 2010 17:15:37 +1000
+Subject: md: manage redundancy group in sysfs when changing level.
+
+From: NeilBrown <neilb@suse.de>
+
+commit a64c876fd357906a1f7193723866562ad290654c upstream.
+
+Some levels expect the 'redundancy group' to be present,
+others don't.
+So when we change level of an array we might need to
+add or remove this group.
+
+This requires fixing up the current practice of overloading ->private
+to indicate (when ->pers == NULL) that something needs to be removed.
+So create a new ->to_remove to fill that role.
+
+When changing levels, we may need to add or remove attributes. When
+changing RAID5 -> RAID6, we both add and remove the same thing. It is
+important to catch this and optimise it out as the removal is delayed
+until a lock is released, so trying to add immediately would cause
+problems.
+
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/md.c | 43 ++++++++++++++++++++++++++++++++-----------
+ drivers/md/md.h | 1 +
+ drivers/md/raid5.c | 7 +++++--
+ 3 files changed, 38 insertions(+), 13 deletions(-)
+
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -509,9 +509,9 @@ static inline int mddev_trylock(mddev_t
+
+ static struct attribute_group md_redundancy_group;
+
+-static inline void mddev_unlock(mddev_t * mddev)
++static void mddev_unlock(mddev_t * mddev)
+ {
+- if (mddev->pers == NULL && mddev->private) {
++ if (mddev->to_remove) {
+ /* These cannot be removed under reconfig_mutex as
+ * an access to the files will try to take reconfig_mutex
+ * while holding the file unremovable, which leads to
+@@ -520,16 +520,20 @@ static inline void mddev_unlock(mddev_t
+ * it while holding reconfig_mutex, and md_run can
+ * use it to wait for the remove to complete.
+ */
++ struct attribute_group *to_remove = mddev->to_remove;
++ mddev->to_remove = NULL;
+ mutex_lock(&mddev->open_mutex);
+ mutex_unlock(&mddev->reconfig_mutex);
+
+- sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
+- if (mddev->private != (void*)1)
+- sysfs_remove_group(&mddev->kobj, mddev->private);
+- if (mddev->sysfs_action)
+- sysfs_put(mddev->sysfs_action);
+- mddev->sysfs_action = NULL;
+- mddev->private = NULL;
++ if (to_remove != &md_redundancy_group)
++ sysfs_remove_group(&mddev->kobj, to_remove);
++ if (mddev->pers == NULL ||
++ mddev->pers->sync_request == NULL) {
++ sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
++ if (mddev->sysfs_action)
++ sysfs_put(mddev->sysfs_action);
++ mddev->sysfs_action = NULL;
++ }
+ mutex_unlock(&mddev->open_mutex);
+ } else
+ mutex_unlock(&mddev->reconfig_mutex);
+@@ -3002,6 +3006,23 @@ level_store(mddev_t *mddev, const char *
+ /* Looks like we have a winner */
+ mddev_suspend(mddev);
+ mddev->pers->stop(mddev);
++
++ if (mddev->pers->sync_request == NULL &&
++ pers->sync_request != NULL) {
++ /* need to add the md_redundancy_group */
++ if (sysfs_create_group(&mddev->kobj, &md_redundancy_group))
++ printk(KERN_WARNING
++ "md: cannot register extra attributes for %s\n",
++ mdname(mddev));
++ mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
++ }
++ if (mddev->pers->sync_request != NULL &&
++ pers->sync_request == NULL) {
++ /* need to remove the md_redundancy_group */
++ if (mddev->to_remove == NULL)
++ mddev->to_remove = &md_redundancy_group;
++ }
++
+ module_put(mddev->pers->owner);
+ /* Invalidate devices that are now superfluous */
+ list_for_each_entry(rdev, &mddev->disks, same_set)
+@@ -4556,8 +4577,8 @@ static int do_md_stop(mddev_t * mddev, i
+ mddev->queue->unplug_fn = NULL;
+ mddev->queue->backing_dev_info.congested_fn = NULL;
+ module_put(mddev->pers->owner);
+- if (mddev->pers->sync_request && mddev->private == NULL)
+- mddev->private = (void*)1;
++ if (mddev->pers->sync_request && mddev->to_remove == NULL)
++ mddev->to_remove = &md_redundancy_group;
+ mddev->pers = NULL;
+ /* tell userspace to handle 'inactive' */
+ sysfs_notify_dirent(mddev->sysfs_state);
+--- a/drivers/md/md.h
++++ b/drivers/md/md.h
+@@ -305,6 +305,7 @@ struct mddev_s
+ atomic_t max_corr_read_errors; /* max read retries */
+ struct list_head all_mddevs;
+
++ struct attribute_group *to_remove;
+ /* Generic barrier handling.
+ * If there is a pending barrier request, all other
+ * writes are blocked while the devices are flushed.
+--- a/drivers/md/raid5.c
++++ b/drivers/md/raid5.c
+@@ -5086,7 +5086,9 @@ static int run(mddev_t *mddev)
+ }
+
+ /* Ok, everything is just fine now */
+- if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group))
++ if (mddev->to_remove == &raid5_attrs_group)
++ mddev->to_remove = NULL;
++ else if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group))
+ printk(KERN_WARNING
+ "raid5: failed to create sysfs attributes for %s\n",
+ mdname(mddev));
+@@ -5133,7 +5135,8 @@ static int stop(mddev_t *mddev)
+ mddev->queue->backing_dev_info.congested_fn = NULL;
+ blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+ free_conf(conf);
+- mddev->private = &raid5_attrs_group;
++ mddev->private = NULL;
++ mddev->to_remove = &raid5_attrs_group;
+ return 0;
+ }
+