--- /dev/null
+From 7c04241acbdaf97f1448dcccd27ea0fcd1a57684 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Thu, 13 Oct 2011 17:17:06 +0800
+Subject: ASoC: ak4535: fixup cache register table
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 7c04241acbdaf97f1448dcccd27ea0fcd1a57684 upstream.
+
+ak4535_reg should be 8bit, but cache table is defined as 16bit.
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/ak4535.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/codecs/ak4535.c
++++ b/sound/soc/codecs/ak4535.c
+@@ -40,11 +40,11 @@ struct ak4535_priv {
+ /*
+ * ak4535 register cache
+ */
+-static const u16 ak4535_reg[AK4535_CACHEREGNUM] = {
+- 0x0000, 0x0080, 0x0000, 0x0003,
+- 0x0002, 0x0000, 0x0011, 0x0001,
+- 0x0000, 0x0040, 0x0036, 0x0010,
+- 0x0000, 0x0000, 0x0057, 0x0000,
++static const u8 ak4535_reg[AK4535_CACHEREGNUM] = {
++ 0x00, 0x80, 0x00, 0x03,
++ 0x02, 0x00, 0x11, 0x01,
++ 0x00, 0x40, 0x36, 0x10,
++ 0x00, 0x00, 0x57, 0x00,
+ };
+
+ /*
--- /dev/null
+From 19b115e523208a926813751aac8934cf3fc6085e Mon Sep 17 00:00:00 2001
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Date: Thu, 13 Oct 2011 02:03:54 -0700
+Subject: ASoC: ak4642: fixup cache register table
+
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+commit 19b115e523208a926813751aac8934cf3fc6085e upstream.
+
+ak4642 register was 8bit, but cache table was defined as 16bit.
+ak4642 doesn't work correctry without this patch.
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/ak4642.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+--- a/sound/soc/codecs/ak4642.c
++++ b/sound/soc/codecs/ak4642.c
+@@ -162,17 +162,17 @@ struct ak4642_priv {
+ /*
+ * ak4642 register cache
+ */
+-static const u16 ak4642_reg[AK4642_CACHEREGNUM] = {
+- 0x0000, 0x0000, 0x0001, 0x0000,
+- 0x0002, 0x0000, 0x0000, 0x0000,
+- 0x00e1, 0x00e1, 0x0018, 0x0000,
+- 0x00e1, 0x0018, 0x0011, 0x0008,
+- 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0000,
++static const u8 ak4642_reg[AK4642_CACHEREGNUM] = {
++ 0x00, 0x00, 0x01, 0x00,
++ 0x02, 0x00, 0x00, 0x00,
++ 0xe1, 0xe1, 0x18, 0x00,
++ 0xe1, 0x18, 0x11, 0x08,
++ 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00,
++ 0x00,
+ };
+
+ /*
--- /dev/null
+From fbc7c62a3ff831aef24894b7982cd1adb2b7e070 Mon Sep 17 00:00:00 2001
+From: Susan Gao <sgao@opensource.wolfsonmicro.com>
+Date: Thu, 29 Sep 2011 11:08:18 +0100
+Subject: ASoC: Fix a bug in WM8962 DSP_A and DSP_B settings
+
+From: Susan Gao <sgao@opensource.wolfsonmicro.com>
+
+commit fbc7c62a3ff831aef24894b7982cd1adb2b7e070 upstream.
+
+Signed-off-by: Susan Gao <sgao@opensource.wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmico.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8962.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/codecs/wm8962.c
++++ b/sound/soc/codecs/wm8962.c
+@@ -3028,9 +3028,9 @@ static int wm8962_set_dai_fmt(struct snd
+ int aif0 = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+- case SND_SOC_DAIFMT_DSP_A:
+- aif0 |= WM8962_LRCLK_INV;
+ case SND_SOC_DAIFMT_DSP_B:
++ aif0 |= WM8962_LRCLK_INV | 3;
++ case SND_SOC_DAIFMT_DSP_A:
+ aif0 |= 3;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
--- /dev/null
+From 38f3f31a0a797bdbcc0cdb12553bbecc2f9a91c4 Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Fri, 23 Sep 2011 21:26:33 +0100
+Subject: ASoC: Remove direct register cache accesses from WM8962 driver
+
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+
+commit 38f3f31a0a797bdbcc0cdb12553bbecc2f9a91c4 upstream.
+
+Also fix return values for speaker switch updates.
+
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8962.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/sound/soc/codecs/wm8962.c
++++ b/sound/soc/codecs/wm8962.c
+@@ -2018,7 +2018,6 @@ static int wm8962_put_spk_sw(struct snd_
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+- u16 *reg_cache = codec->reg_cache;
+ int ret;
+
+ /* Apply the update (if any) */
+@@ -2027,16 +2026,19 @@ static int wm8962_put_spk_sw(struct snd_
+ return 0;
+
+ /* If the left PGA is enabled hit that VU bit... */
+- if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
+- return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+- reg_cache[WM8962_SPKOUTL_VOLUME]);
++ ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
++ if (ret & WM8962_SPKOUTL_PGA_ENA) {
++ snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
++ snd_soc_read(codec, WM8962_SPKOUTL_VOLUME));
++ return 1;
++ }
+
+ /* ...otherwise the right. The VU is stereo. */
+- if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
+- return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+- reg_cache[WM8962_SPKOUTR_VOLUME]);
++ if (ret & WM8962_SPKOUTR_PGA_ENA)
++ snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
++ snd_soc_read(codec, WM8962_SPKOUTR_VOLUME));
+
+- return 0;
++ return 1;
+ }
+
+ static const char *cap_hpf_mode_text[] = {
+@@ -2336,7 +2338,6 @@ static int out_pga_event(struct snd_soc_
+ struct snd_kcontrol *kcontrol, int event)
+ {
+ struct snd_soc_codec *codec = w->codec;
+- u16 *reg_cache = codec->reg_cache;
+ int reg;
+
+ switch (w->shift) {
+@@ -2359,7 +2360,7 @@ static int out_pga_event(struct snd_soc_
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+- return snd_soc_write(codec, reg, reg_cache[reg]);
++ return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
+ default:
+ BUG();
+ return -EINVAL;
--- /dev/null
+From 3a340104fad6ecbea5ad6792a2ea855f0507a6e0 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Mon, 17 Oct 2011 20:14:56 +0800
+Subject: ASoC: wm8741: Fix setting interface format for DSP modes
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 3a340104fad6ecbea5ad6792a2ea855f0507a6e0 upstream.
+
+According to the datasheet:
+Format Control (05h)
+BITS[3:2]
+ FMT[1:0] Audio data format selection
+ 00 = right justified mode
+ 01 = left justified mode
+ 10 = I2S mode
+ 11 = DSP mode
+BIT[4] LRP Polarity selec for LRCLK/DSP mode select
+ 0 = normal LRCLK poalrity/DSP mode A
+ 1 = inverted LRCLK poarity/DSP mode B
+
+For SND_SOC_DAIFMT_DSP_A, we should set 0x000C instead of 0x0003.
+For SND_SOC_DAIFMT_DSP_B, we should set 0x001C instead of 0x0013.
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Acked-by: Liam Girdwood <lrg@ti.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8741.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/codecs/wm8741.c
++++ b/sound/soc/codecs/wm8741.c
+@@ -337,10 +337,10 @@ static int wm8741_set_dai_fmt(struct snd
+ iface |= 0x0004;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+- iface |= 0x0003;
++ iface |= 0x000C;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+- iface |= 0x0013;
++ iface |= 0x001C;
+ break;
+ default:
+ return -EINVAL;
--- /dev/null
+From 5927f94700e860ae27ff24e7f3bc9e4f7b9922eb Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Wed, 26 Oct 2011 09:53:41 +0800
+Subject: ASoC: wm8940: Properly set codec->dapm.bias_level
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 5927f94700e860ae27ff24e7f3bc9e4f7b9922eb upstream.
+
+Reported-by: Chris Paulson-Ellis <chris@edesix.com>
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8940.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/codecs/wm8940.c
++++ b/sound/soc/codecs/wm8940.c
+@@ -472,6 +472,8 @@ static int wm8940_set_bias_level(struct
+ break;
+ }
+
++ codec->dapm.bias_level = level;
++
+ return ret;
+ }
+
--- /dev/null
+From 35024f4922f7b271e7529673413889aa3d51c5fc Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Thu, 20 Oct 2011 12:13:24 +0800
+Subject: ASoC: wm8994: Use SND_SOC_DAPM_AIF_OUT for AIF3 Capture
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 35024f4922f7b271e7529673413889aa3d51c5fc upstream.
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Acked-by: Liam Girdwood <lrg@ti.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8994.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/wm8994.c
++++ b/sound/soc/codecs/wm8994.c
+@@ -1266,7 +1266,7 @@ SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_
+ SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
+
+ SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+-SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
++SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
+
--- /dev/null
+From c84c14224bbca6ec60d5851fcc87be0e34df2f44 Mon Sep 17 00:00:00 2001
+From: Jean Delvare <jdelvare@suse.de>
+Date: Fri, 8 Jul 2011 11:04:38 +0200
+Subject: carminefb: Fix module parameters permissions
+
+From: Jean Delvare <jdelvare@suse.de>
+
+commit c84c14224bbca6ec60d5851fcc87be0e34df2f44 upstream.
+
+The third parameter of module_param is supposed to be an octal value.
+The missing leading "0" causes the following:
+
+$ ls -l /sys/module/carminefb/parameters/
+total 0
+-rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_displays
+-rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_mode
+-rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_mode_str
+
+After fixing the perm parameter, we get the expected:
+
+$ ls -l /sys/module/carminefb/parameters/
+total 0
+-r--r--r-- 1 root root 4096 Jul 8 08:56 fb_displays
+-r--r--r-- 1 root root 4096 Jul 8 08:56 fb_mode
+-r--r--r-- 1 root root 4096 Jul 8 08:56 fb_mode_str
+
+Signed-off-by: Jean Delvare <jdelvare@suse.de>
+Cc: Paul Mundt <lethal@linux-sh.org>
+Cc: Sebastian Siewior <bigeasy@linutronix.de>
+Signed-off-by: Paul Mundt <lethal@linux-sh.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/carminefb.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/video/carminefb.c
++++ b/drivers/video/carminefb.c
+@@ -32,11 +32,11 @@
+ #define CARMINEFB_DEFAULT_VIDEO_MODE 1
+
+ static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
+-module_param(fb_mode, uint, 444);
++module_param(fb_mode, uint, 0444);
+ MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
+
+ static char *fb_mode_str;
+-module_param(fb_mode_str, charp, 444);
++module_param(fb_mode_str, charp, 0444);
+ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
+
+ /*
+@@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial v
+ * 0b010 Display 1
+ */
+ static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
+-module_param(fb_displays, int, 444);
++module_param(fb_displays, int, 0444);
+ MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
+
+ struct carmine_hw {
--- /dev/null
+From dbdf1afcaaabe83dea15a3cb9b9013e73ae3b1ad Mon Sep 17 00:00:00 2001
+From: Sebastian Ott <sebott@linux.vnet.ibm.com>
+Date: Sun, 30 Oct 2011 15:16:52 +0100
+Subject: [S390] ccwgroup: move attributes to attribute group
+
+From: Sebastian Ott <sebott@linux.vnet.ibm.com>
+
+commit dbdf1afcaaabe83dea15a3cb9b9013e73ae3b1ad upstream.
+
+Put sysfs attributes of ccwgroup devices in an attribute group to
+ensure that these attributes are actually present when userspace
+is notified via uevents.
+
+Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/s390/cio/ccwgroup.c | 42 ++++++++++++++++++++++--------------------
+ 1 file changed, 22 insertions(+), 20 deletions(-)
+
+--- a/drivers/s390/cio/ccwgroup.c
++++ b/drivers/s390/cio/ccwgroup.c
+@@ -87,6 +87,12 @@ static void __ccwgroup_remove_cdev_refs(
+ }
+ }
+
++static ssize_t ccwgroup_online_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count);
++static ssize_t ccwgroup_online_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf);
+ /*
+ * Provide an 'ungroup' attribute so the user can remove group devices no
+ * longer needed or accidentially created. Saves memory :)
+@@ -134,6 +140,20 @@ out:
+ }
+
+ static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
++static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
++
++static struct attribute *ccwgroup_attrs[] = {
++ &dev_attr_online.attr,
++ &dev_attr_ungroup.attr,
++ NULL,
++};
++static struct attribute_group ccwgroup_attr_group = {
++ .attrs = ccwgroup_attrs,
++};
++static const struct attribute_group *ccwgroup_attr_groups[] = {
++ &ccwgroup_attr_group,
++ NULL,
++};
+
+ static void
+ ccwgroup_release (struct device *dev)
+@@ -293,25 +313,17 @@ int ccwgroup_create_from_string(struct d
+ }
+
+ dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev));
+-
++ gdev->dev.groups = ccwgroup_attr_groups;
+ rc = device_add(&gdev->dev);
+ if (rc)
+ goto error;
+ get_device(&gdev->dev);
+- rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
+-
+- if (rc) {
+- device_unregister(&gdev->dev);
+- goto error;
+- }
+-
+ rc = __ccwgroup_create_symlinks(gdev);
+ if (!rc) {
+ mutex_unlock(&gdev->reg_mutex);
+ put_device(&gdev->dev);
+ return 0;
+ }
+- device_remove_file(&gdev->dev, &dev_attr_ungroup);
+ device_unregister(&gdev->dev);
+ error:
+ for (i = 0; i < num_devices; i++)
+@@ -423,7 +435,7 @@ ccwgroup_online_store (struct device *de
+ int ret;
+
+ if (!dev->driver)
+- return -ENODEV;
++ return -EINVAL;
+
+ gdev = to_ccwgroupdev(dev);
+ gdrv = to_ccwgroupdrv(dev->driver);
+@@ -456,8 +468,6 @@ ccwgroup_online_show (struct device *dev
+ return sprintf(buf, online ? "1\n" : "0\n");
+ }
+
+-static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
+-
+ static int
+ ccwgroup_probe (struct device *dev)
+ {
+@@ -469,12 +479,7 @@ ccwgroup_probe (struct device *dev)
+ gdev = to_ccwgroupdev(dev);
+ gdrv = to_ccwgroupdrv(dev->driver);
+
+- if ((ret = device_create_file(dev, &dev_attr_online)))
+- return ret;
+-
+ ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV;
+- if (ret)
+- device_remove_file(dev, &dev_attr_online);
+
+ return ret;
+ }
+@@ -485,9 +490,6 @@ ccwgroup_remove (struct device *dev)
+ struct ccwgroup_device *gdev;
+ struct ccwgroup_driver *gdrv;
+
+- device_remove_file(dev, &dev_attr_online);
+- device_remove_file(dev, &dev_attr_ungroup);
+-
+ if (!dev->driver)
+ return 0;
+
--- /dev/null
+From bff469f4167fdabfe15294f375577d7eadbaa1bb Mon Sep 17 00:00:00 2001
+From: Olivier Grenie <olivier.grenie@dibcom.fr>
+Date: Mon, 1 Aug 2011 12:45:58 -0300
+Subject: [media] dib0700: protect the dib0700 buffer access
+
+From: Olivier Grenie <olivier.grenie@dibcom.fr>
+
+commit bff469f4167fdabfe15294f375577d7eadbaa1bb upstream.
+
+This patch protects the common buffer access inside the dib0700 in order
+to manage concurrent access. This protection is done using mutex.
+
+Cc: Mauro Carvalho Chehab <mchehab@redhat.com>
+Cc: Florian Mickler <florian@mickler.org>
+Signed-off-by: Javier Marcet <javier@marcet.info>
+Signed-off-by: Olivier Grenie <olivier.grenie@dibcom.fr>
+Signed-off-by: Patrick Boettcher <patrick.boettcher@dibcom.fr>
+[mchehab@redhat.com: dprint requires 3 arguments. Replaced by dib_info]
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/dvb-usb/dib0700_core.c | 81 +++++++++++++++++++++++++++----
+ 1 file changed, 72 insertions(+), 9 deletions(-)
+
+--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
+@@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_d
+ struct dib0700_state *st = d->priv;
+ int ret;
+
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
++
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+ REQUEST_GET_VERSION,
+ USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+@@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_d
+ if (fwtype != NULL)
+ *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) |
+ (st->buf[14] << 8) | st->buf[15];
++ mutex_unlock(&d->usb_mutex);
+ return ret;
+ }
+
+@@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_devic
+ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
+ {
+ struct dib0700_state *st = d->priv;
+- s16 ret;
++ int ret;
++
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
+
+ st->buf[0] = REQUEST_SET_GPIO;
+ st->buf[1] = gpio;
+@@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_devi
+
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
+
++ mutex_unlock(&d->usb_mutex);
+ return ret;
+ }
+
+@@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(stru
+ int ret;
+
+ if (st->fw_version >= 0x10201) {
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
++
+ st->buf[0] = REQUEST_SET_USB_XFER_LEN;
+ st->buf[1] = (nb_ts_packets >> 8) & 0xff;
+ st->buf[2] = nb_ts_packets & 0xff;
+@@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(stru
+ deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
++ mutex_unlock(&d->usb_mutex);
+ } else {
+ deb_info("this firmware does not allow to change the USB xfer len\n");
+ ret = -EIO;
+@@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i
+
+ } else {
+ /* Write request */
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
+ st->buf[0] = REQUEST_NEW_I2C_WRITE;
+ st->buf[1] = msg[i].addr << 1;
+ st->buf[2] = (en_start << 7) | (en_stop << 6) |
+@@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ 0, 0, st->buf, msg[i].len + 4,
+ USB_CTRL_GET_TIMEOUT);
++ mutex_unlock(&d->usb_mutex);
+ if (result < 0) {
+ deb_info("i2c write error (status = %d)\n", result);
+ break;
+@@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struc
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
+
+ for (i = 0; i < num; i++) {
+ /* fill in the address */
+@@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struc
+ break;
+ }
+ }
++ mutex_unlock(&d->usb_mutex);
+ mutex_unlock(&d->i2c_mutex);
+
+ return i;
+@@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_
+ u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
+ {
+ struct dib0700_state *st = d->priv;
+- s16 ret;
++ int ret;
++
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
+
+ st->buf[0] = REQUEST_SET_CLOCK;
+ st->buf[1] = (en_pll << 7) | (pll_src << 6) |
+@@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_
+ st->buf[9] = dsuScaler & 0xff; /* LSB */
+
+ ret = dib0700_ctrl_wr(d, st->buf, 10);
++ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+ }
+@@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb
+ {
+ struct dib0700_state *st = d->priv;
+ u16 divider;
++ int ret;
+
+ if (scl_kHz == 0)
+ return -EINVAL;
+
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
++
+ st->buf[0] = REQUEST_SET_I2C_PARAM;
+ divider = (u16) (30000 / scl_kHz);
+ st->buf[1] = 0;
+@@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb
+ deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
+ (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
+ st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
+- return dib0700_ctrl_wr(d, st->buf, 8);
++
++ ret = dib0700_ctrl_wr(d, st->buf, 8);
++ mutex_unlock(&d->usb_mutex);
++
++ return ret;
+ }
+
+
+@@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_us
+ }
+ }
+
++ if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
++
+ st->buf[0] = REQUEST_ENABLE_VIDEO;
+ /* this bit gives a kind of command,
+ * rather than enabling something or not */
+@@ -548,7 +597,10 @@ int dib0700_streaming_ctrl(struct dvb_us
+
+ deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
+
+- return dib0700_ctrl_wr(adap->dev, st->buf, 4);
++ ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
++ mutex_unlock(&adap->dev->usb_mutex);
++
++ return ret;
+ }
+
+ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+@@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_de
+ struct dib0700_state *st = d->priv;
+ int new_proto, ret;
+
++ if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++ deb_info("could not acquire lock");
++ return 0;
++ }
++
+ st->buf[0] = REQUEST_SET_RC;
+ st->buf[1] = 0;
+ st->buf[2] = 0;
+@@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_de
+ else if (rc_type == RC_TYPE_NEC)
+ new_proto = 0;
+ else if (rc_type == RC_TYPE_RC6) {
+- if (st->fw_version < 0x10200)
+- return -EINVAL;
++ if (st->fw_version < 0x10200) {
++ ret = -EINVAL;
++ goto out;
++ }
+
+ new_proto = 2;
+- } else
+- return -EINVAL;
++ } else {
++ ret = -EINVAL;
++ goto out;
++ }
+
+ st->buf[1] = new_proto;
+
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
+ if (ret < 0) {
+ err("ir protocol setup failed");
+- return ret;
++ goto out;
+ }
+
+ d->props.rc.core.protocol = rc_type;
+
++out:
++ mutex_unlock(&d->usb_mutex);
+ return ret;
+ }
+
--- /dev/null
+From 79fcce3230b140f7675f8529ee53fe2f9644f902 Mon Sep 17 00:00:00 2001
+From: Patrick Boettcher <Patrick.Boettcher@dibcom.fr>
+Date: Wed, 3 Aug 2011 12:08:21 -0300
+Subject: [media] DiBcom: protect the I2C bufer access
+
+From: Patrick Boettcher <Patrick.Boettcher@dibcom.fr>
+
+commit 79fcce3230b140f7675f8529ee53fe2f9644f902 upstream.
+
+This patch protects the I2C buffer access in order to manage concurrent
+access. This protection is done using mutex.
+Furthermore, for the dib9000, if a pid filtering command is
+received during the tuning, this pid filtering command is delayed to
+avoid any concurrent access issue.
+
+Cc: Mauro Carvalho Chehab <mchehab@redhat.com>
+Cc: Florian Mickler <florian@mickler.org>
+Signed-off-by: Olivier Grenie <olivier.grenie@dibcom.fr>
+Signed-off-by: Patrick Boettcher <Patrick.Boettcher@dibcom.fr>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/frontends/dib0070.c | 37 ++++--
+ drivers/media/dvb/frontends/dib0090.c | 70 +++++++++--
+ drivers/media/dvb/frontends/dib7000m.c | 27 ++++
+ drivers/media/dvb/frontends/dib7000p.c | 32 ++++-
+ drivers/media/dvb/frontends/dib8000.c | 72 ++++++++++-
+ drivers/media/dvb/frontends/dib9000.c | 164 +++++++++++++++++++++++----
+ drivers/media/dvb/frontends/dibx000_common.c | 76 ++++++++++--
+ drivers/media/dvb/frontends/dibx000_common.h | 1
+ 8 files changed, 412 insertions(+), 67 deletions(-)
+
+--- a/drivers/media/dvb/frontends/dib0070.c
++++ b/drivers/media/dvb/frontends/dib0070.c
+@@ -27,6 +27,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+
+ #include "dvb_frontend.h"
+
+@@ -78,10 +79,18 @@ struct dib0070_state {
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[3];
+ u8 i2c_read_buffer[2];
++ struct mutex i2c_buffer_lock;
+ };
+
+-static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
++static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
+ {
++ u16 ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
+ state->i2c_write_buffer[0] = reg;
+
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+@@ -96,13 +105,23 @@ static uint16_t dib0070_read_reg(struct
+
+ if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+ printk(KERN_WARNING "DiB0070 I2C read failed\n");
+- return 0;
+- }
+- return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ ret = 0;
++ } else
++ ret = (state->i2c_read_buffer[0] << 8)
++ | state->i2c_read_buffer[1];
++
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+ {
++ int ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
+ state->i2c_write_buffer[0] = reg;
+ state->i2c_write_buffer[1] = val >> 8;
+ state->i2c_write_buffer[2] = val & 0xff;
+@@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0
+
+ if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+ printk(KERN_WARNING "DiB0070 I2C write failed\n");
+- return -EREMOTEIO;
+- }
+- return 0;
++ ret = -EREMOTEIO;
++ } else
++ ret = 0;
++
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ #define HARD_RESET(state) do { \
+@@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(stru
+ state->cfg = cfg;
+ state->i2c = i2c;
+ state->fe = fe;
++ mutex_init(&state->i2c_buffer_lock);
+ fe->tuner_priv = state;
+
+ if (dib0070_reset(fe) != 0)
+--- a/drivers/media/dvb/frontends/dib0090.c
++++ b/drivers/media/dvb/frontends/dib0090.c
+@@ -27,6 +27,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+
+ #include "dvb_frontend.h"
+
+@@ -196,6 +197,7 @@ struct dib0090_state {
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[3];
+ u8 i2c_read_buffer[2];
++ struct mutex i2c_buffer_lock;
+ };
+
+ struct dib0090_fw_state {
+@@ -208,10 +210,18 @@ struct dib0090_fw_state {
+ struct i2c_msg msg;
+ u8 i2c_write_buffer[2];
+ u8 i2c_read_buffer[2];
++ struct mutex i2c_buffer_lock;
+ };
+
+ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
+ {
++ u16 ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
+ state->i2c_write_buffer[0] = reg;
+
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+@@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib00
+
+ if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+ printk(KERN_WARNING "DiB0090 I2C read failed\n");
+- return 0;
+- }
++ ret = 0;
++ } else
++ ret = (state->i2c_read_buffer[0] << 8)
++ | state->i2c_read_buffer[1];
+
+- return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
+ {
++ int ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
+ state->i2c_write_buffer[0] = reg & 0xff;
+ state->i2c_write_buffer[1] = val >> 8;
+ state->i2c_write_buffer[2] = val & 0xff;
+@@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0
+
+ if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+ printk(KERN_WARNING "DiB0090 I2C write failed\n");
+- return -EREMOTEIO;
+- }
+- return 0;
++ ret = -EREMOTEIO;
++ } else
++ ret = 0;
++
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
+ {
++ u16 ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
+ state->i2c_write_buffer[0] = reg;
+
+ memset(&state->msg, 0, sizeof(struct i2c_msg));
+@@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct di
+ state->msg.len = 2;
+ if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+ printk(KERN_WARNING "DiB0090 I2C read failed\n");
+- return 0;
+- }
+- return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ ret = 0;
++ } else
++ ret = (state->i2c_read_buffer[0] << 8)
++ | state->i2c_read_buffer[1];
++
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
+ {
++ int ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
+ state->i2c_write_buffer[0] = val >> 8;
+ state->i2c_write_buffer[1] = val & 0xff;
+
+@@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct d
+ state->msg.len = 2;
+ if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+ printk(KERN_WARNING "DiB0090 I2C write failed\n");
+- return -EREMOTEIO;
+- }
+- return 0;
++ ret = -EREMOTEIO;
++ } else
++ ret = 0;
++
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ #define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0)
+@@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(st
+ st->config = config;
+ st->i2c = i2c;
+ st->fe = fe;
++ mutex_init(&st->i2c_buffer_lock);
+ fe->tuner_priv = st;
+
+ if (config->wbd == NULL)
+@@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register
+ st->config = config;
+ st->i2c = i2c;
+ st->fe = fe;
++ mutex_init(&st->i2c_buffer_lock);
+ fe->tuner_priv = st;
+
+ if (dib0090_fw_reset_digital(fe, st->config) != 0)
+--- a/drivers/media/dvb/frontends/dib7000m.c
++++ b/drivers/media/dvb/frontends/dib7000m.c
+@@ -11,6 +11,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+
+ #include "dvb_frontend.h"
+
+@@ -55,6 +56,7 @@ struct dib7000m_state {
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[4];
+ u8 i2c_read_buffer[2];
++ struct mutex i2c_buffer_lock;
+ };
+
+ enum dib7000m_power_mode {
+@@ -69,6 +71,13 @@ enum dib7000m_power_mode {
+
+ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+ {
++ u16 ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
+ state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
+ state->i2c_write_buffer[1] = reg & 0xff;
+
+@@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib
+ if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+ dprintk("i2c read error on %d",reg);
+
+- return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ mutex_unlock(&state->i2c_buffer_lock);
++
++ return ret;
+ }
+
+ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+ {
++ int ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
+ state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ state->i2c_write_buffer[1] = reg & 0xff;
+ state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -101,7 +120,10 @@ static int dib7000m_write_word(struct di
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 4;
+
+- return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++ ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
++ -EREMOTEIO : 0);
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+ static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+ {
+@@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(st
+ demod = &st->demod;
+ demod->demodulator_priv = st;
+ memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
++ mutex_init(&st->i2c_buffer_lock);
+
+ st->timf_default = cfg->bw->timf;
+
+--- a/drivers/media/dvb/frontends/dib7000p.c
++++ b/drivers/media/dvb/frontends/dib7000p.c
+@@ -10,6 +10,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+
+ #include "dvb_math.h"
+ #include "dvb_frontend.h"
+@@ -68,6 +69,7 @@ struct dib7000p_state {
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[4];
+ u8 i2c_read_buffer[2];
++ struct mutex i2c_buffer_lock;
+ };
+
+ enum dib7000p_power_mode {
+@@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(stru
+
+ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+ {
++ u16 ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
+ state->i2c_write_buffer[0] = reg >> 8;
+ state->i2c_write_buffer[1] = reg & 0xff;
+
+@@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib
+ if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+ dprintk("i2c read error on %d", reg);
+
+- return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+ {
++ int ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
+ state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ state->i2c_write_buffer[1] = reg & 0xff;
+ state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -113,7 +131,10 @@ static int dib7000p_write_word(struct di
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 4;
+
+- return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++ ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
++ -EREMOTEIO : 0);
++ mutex_unlock(&state->i2c_buffer_lock);
++ return ret;
+ }
+
+ static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
+@@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_
+ return -ENOMEM;
+
+ dpst->i2c_adap = i2c;
++ mutex_init(&dpst->i2c_buffer_lock);
+
+ for (k = no_of_demods - 1; k >= 0; k--) {
+ dpst->cfg = cfg[k];
+@@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(str
+ demod = &st->demod;
+ demod->demodulator_priv = st;
+ memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
++ mutex_init(&st->i2c_buffer_lock);
+
+ dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
+
+@@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(str
+ st->version = dib7000p_read_word(st, 897);
+
+ /* FIXME: make sure the dev.parent field is initialized, or else
+- request_firmware() will hit an OOPS (this should be moved somewhere
+- more common) */
++ request_firmware() will hit an OOPS (this should be moved somewhere
++ more common) */
++ st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
+
+ dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
+
+--- a/drivers/media/dvb/frontends/dib8000.c
++++ b/drivers/media/dvb/frontends/dib8000.c
+@@ -10,6 +10,8 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
++
+ #include "dvb_math.h"
+
+ #include "dvb_frontend.h"
+@@ -37,6 +39,7 @@ struct i2c_device {
+ u8 addr;
+ u8 *i2c_write_buffer;
+ u8 *i2c_read_buffer;
++ struct mutex *i2c_buffer_lock;
+ };
+
+ struct dib8000_state {
+@@ -77,6 +80,7 @@ struct dib8000_state {
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[4];
+ u8 i2c_read_buffer[2];
++ struct mutex i2c_buffer_lock;
+ };
+
+ enum dib8000_power_mode {
+@@ -86,24 +90,39 @@ enum dib8000_power_mode {
+
+ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
+ {
++ u16 ret;
+ struct i2c_msg msg[2] = {
+- {.addr = i2c->addr >> 1, .flags = 0,
+- .buf = i2c->i2c_write_buffer, .len = 2},
+- {.addr = i2c->addr >> 1, .flags = I2C_M_RD,
+- .buf = i2c->i2c_read_buffer, .len = 2},
++ {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
++ {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
+ };
+
++ if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
++ msg[0].buf = i2c->i2c_write_buffer;
+ msg[0].buf[0] = reg >> 8;
+ msg[0].buf[1] = reg & 0xff;
++ msg[1].buf = i2c->i2c_read_buffer;
+
+ if (i2c_transfer(i2c->adap, msg, 2) != 2)
+ dprintk("i2c read error on %d", reg);
+
+- return (msg[1].buf[0] << 8) | msg[1].buf[1];
++ ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
++ mutex_unlock(i2c->i2c_buffer_lock);
++ return ret;
+ }
+
+ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+ {
++ u16 ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
+ state->i2c_write_buffer[0] = reg >> 8;
+ state->i2c_write_buffer[1] = reg & 0xff;
+
+@@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8
+ if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
+ dprintk("i2c read error on %d", reg);
+
+- return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++ mutex_unlock(&state->i2c_buffer_lock);
++
++ return ret;
+ }
+
+ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
+@@ -135,22 +157,35 @@ static u32 dib8000_read32(struct dib8000
+
+ static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+ {
+- struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
+- .buf = i2c->i2c_write_buffer, .len = 4};
++ struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
+ int ret = 0;
+
++ if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
++ msg.buf = i2c->i2c_write_buffer;
+ msg.buf[0] = (reg >> 8) & 0xff;
+ msg.buf[1] = reg & 0xff;
+ msg.buf[2] = (val >> 8) & 0xff;
+ msg.buf[3] = val & 0xff;
+
+ ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
++ mutex_unlock(i2c->i2c_buffer_lock);
+
+ return ret;
+ }
+
+ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
+ {
++ int ret;
++
++ if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
+ state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ state->i2c_write_buffer[1] = reg & 0xff;
+ state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -162,7 +197,11 @@ static int dib8000_write_word(struct dib
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 4;
+
+- return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++ ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
++ -EREMOTEIO : 0);
++ mutex_unlock(&state->i2c_buffer_lock);
++
++ return ret;
+ }
+
+ static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
+@@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_a
+ if (!client.i2c_read_buffer) {
+ dprintk("%s: not enough memory", __func__);
+ ret = -ENOMEM;
+- goto error_memory;
++ goto error_memory_read;
++ }
++ client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
++ if (!client.i2c_buffer_lock) {
++ dprintk("%s: not enough memory", __func__);
++ ret = -ENOMEM;
++ goto error_memory_lock;
+ }
++ mutex_init(client.i2c_buffer_lock);
+
+ for (k = no_of_demods - 1; k >= 0; k--) {
+ /* designated i2c address */
+@@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_a
+ }
+
+ error:
++ kfree(client.i2c_buffer_lock);
++error_memory_lock:
+ kfree(client.i2c_read_buffer);
+-error_memory:
++error_memory_read:
+ kfree(client.i2c_write_buffer);
+
+ return ret;
+@@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(stru
+ state->i2c.addr = i2c_addr;
+ state->i2c.i2c_write_buffer = state->i2c_write_buffer;
+ state->i2c.i2c_read_buffer = state->i2c_read_buffer;
++ mutex_init(&state->i2c_buffer_lock);
++ state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
+ state->gpio_val = cfg->gpio_val;
+ state->gpio_dir = cfg->gpio_dir;
+
+--- a/drivers/media/dvb/frontends/dib9000.c
++++ b/drivers/media/dvb/frontends/dib9000.c
+@@ -38,6 +38,15 @@ struct i2c_device {
+ #define DibInitLock(lock) mutex_init(lock)
+ #define DibFreeLock(lock)
+
++struct dib9000_pid_ctrl {
++#define DIB9000_PID_FILTER_CTRL 0
++#define DIB9000_PID_FILTER 1
++ u8 cmd;
++ u8 id;
++ u16 pid;
++ u8 onoff;
++};
++
+ struct dib9000_state {
+ struct i2c_device i2c;
+
+@@ -99,6 +108,10 @@ struct dib9000_state {
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[255];
+ u8 i2c_read_buffer[255];
++ DIB_LOCK demod_lock;
++ u8 get_frontend_internal;
++ struct dib9000_pid_ctrl pid_ctrl[10];
++ s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
+ };
+
+ static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+@@ -1743,19 +1756,56 @@ EXPORT_SYMBOL(dib9000_set_gpio);
+ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+ {
+ struct dib9000_state *state = fe->demodulator_priv;
+- u16 val = dib9000_read_word(state, 294 + 1) & 0xffef;
++ u16 val;
++ int ret;
++
++ if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
++ /* postpone the pid filtering cmd */
++ dprintk("pid filter cmd postpone");
++ state->pid_ctrl_index++;
++ state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
++ state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
++ return 0;
++ }
++
++ DibAcquireLock(&state->demod_lock);
++
++ val = dib9000_read_word(state, 294 + 1) & 0xffef;
+ val |= (onoff & 0x1) << 4;
+
+ dprintk("PID filter enabled %d", onoff);
+- return dib9000_write_word(state, 294 + 1, val);
++ ret = dib9000_write_word(state, 294 + 1, val);
++ DibReleaseLock(&state->demod_lock);
++ return ret;
++
+ }
+ EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
+
+ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+ {
+ struct dib9000_state *state = fe->demodulator_priv;
++ int ret;
++
++ if (state->pid_ctrl_index != -2) {
++ /* postpone the pid filtering cmd */
++ dprintk("pid filter postpone");
++ if (state->pid_ctrl_index < 9) {
++ state->pid_ctrl_index++;
++ state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
++ state->pid_ctrl[state->pid_ctrl_index].id = id;
++ state->pid_ctrl[state->pid_ctrl_index].pid = pid;
++ state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
++ } else
++ dprintk("can not add any more pid ctrl cmd");
++ return 0;
++ }
++
++ DibAcquireLock(&state->demod_lock);
+ dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+- return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0);
++ ret = dib9000_write_word(state, 300 + 1 + id,
++ onoff ? (1 << 13) | pid : 0);
++ DibReleaseLock(&state->demod_lock);
++ return ret;
+ }
+ EXPORT_SYMBOL(dib9000_fw_pid_filter);
+
+@@ -1778,6 +1828,7 @@ static void dib9000_release(struct dvb_f
+ DibFreeLock(&state->platform.risc.mbx_lock);
+ DibFreeLock(&state->platform.risc.mem_lock);
+ DibFreeLock(&state->platform.risc.mem_mbx_lock);
++ DibFreeLock(&state->demod_lock);
+ dibx000_exit_i2c_master(&st->i2c_master);
+
+ i2c_del_adapter(&st->tuner_adap);
+@@ -1795,14 +1846,19 @@ static int dib9000_sleep(struct dvb_fron
+ {
+ struct dib9000_state *state = fe->demodulator_priv;
+ u8 index_frontend;
+- int ret;
++ int ret = 0;
+
++ DibAcquireLock(&state->demod_lock);
+ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
+ if (ret < 0)
+- return ret;
++ goto error;
+ }
+- return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
++ ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
++
++error:
++ DibReleaseLock(&state->demod_lock);
++ return ret;
+ }
+
+ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
+@@ -1816,7 +1872,10 @@ static int dib9000_get_frontend(struct d
+ struct dib9000_state *state = fe->demodulator_priv;
+ u8 index_frontend, sub_index_frontend;
+ fe_status_t stat;
+- int ret;
++ int ret = 0;
++
++ if (state->get_frontend_internal == 0)
++ DibAcquireLock(&state->demod_lock);
+
+ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
+@@ -1846,14 +1905,15 @@ static int dib9000_get_frontend(struct d
+ state->fe[index_frontend]->dtv_property_cache.rolloff;
+ }
+ }
+- return 0;
++ ret = 0;
++ goto return_value;
+ }
+ }
+
+ /* get the channel from master chip */
+ ret = dib9000_fw_get_channel(fe, fep);
+ if (ret != 0)
+- return ret;
++ goto return_value;
+
+ /* synchronize the cache with the other frontends */
+ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+@@ -1866,8 +1926,12 @@ static int dib9000_get_frontend(struct d
+ state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
+ state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
+ }
++ ret = 0;
+
+- return 0;
++return_value:
++ if (state->get_frontend_internal == 0)
++ DibReleaseLock(&state->demod_lock);
++ return ret;
+ }
+
+ static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+@@ -1912,6 +1976,10 @@ static int dib9000_set_frontend(struct d
+ dprintk("dib9000: must specify bandwidth ");
+ return 0;
+ }
++
++ state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
++ DibAcquireLock(&state->demod_lock);
++
+ fe->dtv_property_cache.delivery_system = SYS_DVBT;
+
+ /* set the master status */
+@@ -1974,13 +2042,18 @@ static int dib9000_set_frontend(struct d
+ /* check the tune result */
+ if (exit_condition == 1) { /* tune failed */
+ dprintk("tune failed");
++ DibReleaseLock(&state->demod_lock);
++ /* tune failed; put all the pid filtering cmd to junk */
++ state->pid_ctrl_index = -1;
+ return 0;
+ }
+
+ dprintk("tune success on frontend%i", index_frontend_success);
+
+ /* synchronize all the channel cache */
++ state->get_frontend_internal = 1;
+ dib9000_get_frontend(state->fe[0], fep);
++ state->get_frontend_internal = 0;
+
+ /* retune the other frontends with the found channel */
+ channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
+@@ -2025,6 +2098,28 @@ static int dib9000_set_frontend(struct d
+ /* turn off the diversity for the last frontend */
+ dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
+
++ DibReleaseLock(&state->demod_lock);
++ if (state->pid_ctrl_index >= 0) {
++ u8 index_pid_filter_cmd;
++ u8 pid_ctrl_index = state->pid_ctrl_index;
++
++ state->pid_ctrl_index = -2;
++ for (index_pid_filter_cmd = 0;
++ index_pid_filter_cmd <= pid_ctrl_index;
++ index_pid_filter_cmd++) {
++ if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
++ dib9000_fw_pid_filter_ctrl(state->fe[0],
++ state->pid_ctrl[index_pid_filter_cmd].onoff);
++ else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
++ dib9000_fw_pid_filter(state->fe[0],
++ state->pid_ctrl[index_pid_filter_cmd].id,
++ state->pid_ctrl[index_pid_filter_cmd].pid,
++ state->pid_ctrl[index_pid_filter_cmd].onoff);
++ }
++ }
++ /* do not postpone any more the pid filtering */
++ state->pid_ctrl_index = -2;
++
+ return 0;
+ }
+
+@@ -2041,6 +2136,7 @@ static int dib9000_read_status(struct dv
+ u8 index_frontend;
+ u16 lock = 0, lock_slave = 0;
+
++ DibAcquireLock(&state->demod_lock);
+ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+ lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
+
+@@ -2059,6 +2155,8 @@ static int dib9000_read_status(struct dv
+ if ((lock & 0x0008) || (lock_slave & 0x0008))
+ *stat |= FE_HAS_LOCK;
+
++ DibReleaseLock(&state->demod_lock);
++
+ return 0;
+ }
+
+@@ -2066,10 +2164,14 @@ static int dib9000_read_ber(struct dvb_f
+ {
+ struct dib9000_state *state = fe->demodulator_priv;
+ u16 *c;
++ int ret = 0;
+
++ DibAcquireLock(&state->demod_lock);
+ DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+- if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+- return -EIO;
++ if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++ ret = -EIO;
++ goto error;
++ }
+ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
+ state->i2c_read_buffer, 16 * 2);
+ DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+@@ -2077,7 +2179,10 @@ static int dib9000_read_ber(struct dvb_f
+ c = (u16 *)state->i2c_read_buffer;
+
+ *ber = c[10] << 16 | c[11];
+- return 0;
++
++error:
++ DibReleaseLock(&state->demod_lock);
++ return ret;
+ }
+
+ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+@@ -2086,7 +2191,9 @@ static int dib9000_read_signal_strength(
+ u8 index_frontend;
+ u16 *c = (u16 *)state->i2c_read_buffer;
+ u16 val;
++ int ret = 0;
+
++ DibAcquireLock(&state->demod_lock);
+ *strength = 0;
+ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
+@@ -2097,8 +2204,10 @@ static int dib9000_read_signal_strength(
+ }
+
+ DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+- if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+- return -EIO;
++ if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++ ret = -EIO;
++ goto error;
++ }
+ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+ DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+
+@@ -2107,7 +2216,10 @@ static int dib9000_read_signal_strength(
+ *strength = 65535;
+ else
+ *strength += val;
+- return 0;
++
++error:
++ DibReleaseLock(&state->demod_lock);
++ return ret;
+ }
+
+ static u32 dib9000_get_snr(struct dvb_frontend *fe)
+@@ -2151,6 +2263,7 @@ static int dib9000_read_snr(struct dvb_f
+ u8 index_frontend;
+ u32 snr_master;
+
++ DibAcquireLock(&state->demod_lock);
+ snr_master = dib9000_get_snr(fe);
+ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+ snr_master += dib9000_get_snr(state->fe[index_frontend]);
+@@ -2161,6 +2274,8 @@ static int dib9000_read_snr(struct dvb_f
+ } else
+ *snr = 0;
+
++ DibReleaseLock(&state->demod_lock);
++
+ return 0;
+ }
+
+@@ -2168,15 +2283,22 @@ static int dib9000_read_unc_blocks(struc
+ {
+ struct dib9000_state *state = fe->demodulator_priv;
+ u16 *c = (u16 *)state->i2c_read_buffer;
++ int ret = 0;
+
++ DibAcquireLock(&state->demod_lock);
+ DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+- if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+- return -EIO;
++ if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++ ret = -EIO;
++ goto error;
++ }
+ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+ DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+
+ *unc = c[12];
+- return 0;
++
++error:
++ DibReleaseLock(&state->demod_lock);
++ return ret;
+ }
+
+ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
+@@ -2322,6 +2444,10 @@ struct dvb_frontend *dib9000_attach(stru
+ DibInitLock(&st->platform.risc.mbx_lock);
+ DibInitLock(&st->platform.risc.mem_lock);
+ DibInitLock(&st->platform.risc.mem_mbx_lock);
++ DibInitLock(&st->demod_lock);
++ st->get_frontend_internal = 0;
++
++ st->pid_ctrl_index = -2;
+
+ st->fe[0] = fe;
+ fe->demodulator_priv = st;
+--- a/drivers/media/dvb/frontends/dibx000_common.c
++++ b/drivers/media/dvb/frontends/dibx000_common.c
+@@ -1,4 +1,5 @@
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+
+ #include "dibx000_common.h"
+
+@@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debuggi
+
+ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+ {
++ int ret;
++
++ if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
+ mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ mst->i2c_write_buffer[1] = reg & 0xff;
+ mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -21,11 +29,21 @@ static int dibx000_write_word(struct dib
+ mst->msg[0].buf = mst->i2c_write_buffer;
+ mst->msg[0].len = 4;
+
+- return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
++ ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
++ mutex_unlock(&mst->i2c_buffer_lock);
++
++ return ret;
+ }
+
+ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
+ {
++ u16 ret;
++
++ if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return 0;
++ }
++
+ mst->i2c_write_buffer[0] = reg >> 8;
+ mst->i2c_write_buffer[1] = reg & 0xff;
+
+@@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx
+ if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
+ dprintk("i2c read error on %d", reg);
+
+- return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
++ ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
++ mutex_unlock(&mst->i2c_buffer_lock);
++
++ return ret;
+ }
+
+ static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
+@@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer
+ struct i2c_msg msg[], int num)
+ {
+ struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++ int ret;
+
+ if (num > 32) {
+ dprintk("%s: too much I2C message to be transmitted (%i).\
+@@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer
+ return -ENOMEM;
+ }
+
+- memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+-
+ dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
+
++ if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++
++ memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++
+ /* open the gate */
+ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+ mst->msg[0].addr = mst->i2c_addr;
+@@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer
+ mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+ mst->msg[num + 1].len = 4;
+
+- return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++ ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
++ num : -EIO);
++
++ mutex_unlock(&mst->i2c_buffer_lock);
++ return ret;
+ }
+
+ static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
+@@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(
+ struct i2c_msg msg[], int num)
+ {
+ struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++ int ret;
+
+ if (num > 32) {
+ dprintk("%s: too much I2C message to be transmitted (%i).\
+@@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(
+ return -ENOMEM;
+ }
+
+- memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+-
+ dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
+
++ if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++ memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++
+ /* open the gate */
+ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+ mst->msg[0].addr = mst->i2c_addr;
+@@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(
+ mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+ mst->msg[num + 1].len = 4;
+
+- return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++ ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
++ num : -EIO);
++ mutex_unlock(&mst->i2c_buffer_lock);
++ return ret;
+ }
+
+ static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
+@@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_a
+ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
+ struct i2c_adapter *i2c_adap, u8 i2c_addr)
+ {
+- u8 tx[4];
+- struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
++ int ret;
++
++ mutex_init(&mst->i2c_buffer_lock);
++ if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++ dprintk("could not acquire lock");
++ return -EINVAL;
++ }
++ memset(mst->msg, 0, sizeof(struct i2c_msg));
++ mst->msg[0].addr = i2c_addr >> 1;
++ mst->msg[0].flags = 0;
++ mst->msg[0].buf = mst->i2c_write_buffer;
++ mst->msg[0].len = 4;
+
+ mst->device_rev = device_rev;
+ mst->i2c_adap = i2c_adap;
+@@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx0
+ "DiBX000: could not initialize the master i2c_adapter\n");
+
+ /* initialize the i2c-master by closing the gate */
+- dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
++ dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
++
++ ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
++ mutex_unlock(&mst->i2c_buffer_lock);
+
+- return i2c_transfer(i2c_adap, &m, 1) == 1;
++ return ret;
+ }
+
+ EXPORT_SYMBOL(dibx000_init_i2c_master);
+--- a/drivers/media/dvb/frontends/dibx000_common.h
++++ b/drivers/media/dvb/frontends/dibx000_common.h
+@@ -33,6 +33,7 @@ struct dibx000_i2c_master {
+ struct i2c_msg msg[34];
+ u8 i2c_write_buffer[8];
+ u8 i2c_read_buffer[2];
++ struct mutex i2c_buffer_lock;
+ };
+
+ extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
--- /dev/null
+From 9e769ff3f585db8f978f9113be83d36c7e3965dd Mon Sep 17 00:00:00 2001
+From: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+Date: Fri, 17 Jun 2011 19:02:39 +0000
+Subject: fb: avoid possible deadlock caused by fb_set_suspend
+
+From: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+
+commit 9e769ff3f585db8f978f9113be83d36c7e3965dd upstream.
+
+A lock ordering issue can cause deadlocks: in framebuffer/console code,
+all needed struct fb_info locks are taken before acquire_console_sem(),
+in places which need to take console semaphore.
+
+But fb_set_suspend is always called with console semaphore held, and
+inside it we call lock_fb_info which gets the fb_info lock, inverse
+locking order of what the rest of the code does. This causes a real
+deadlock issue, when we write to state fb sysfs attribute (which calls
+fb_set_suspend) while a framebuffer is being unregistered by
+remove_conflicting_framebuffers, as can be shown by following show
+blocked state trace on a test program which loads i915 and runs another
+forked processes writing to state attribute:
+
+Test process with semaphore held and trying to get fb_info lock:
+..
+fb-test2 D 0000000000000000 0 237 228 0x00000000
+ ffff8800774f3d68 0000000000000082 00000000000135c0 00000000000135c0
+ ffff880000000000 ffff8800774f3fd8 ffff8800774f3fd8 ffff880076ee4530
+ 00000000000135c0 ffff8800774f3fd8 ffff8800774f2000 00000000000135c0
+Call Trace:
+ [<ffffffff8141287a>] __mutex_lock_slowpath+0x11a/0x1e0
+ [<ffffffff814142f2>] ? _raw_spin_lock_irq+0x22/0x40
+ [<ffffffff814123d3>] mutex_lock+0x23/0x50
+ [<ffffffff8125dfc5>] lock_fb_info+0x25/0x60
+ [<ffffffff8125e3f0>] fb_set_suspend+0x20/0x80
+ [<ffffffff81263e2f>] store_fbstate+0x4f/0x70
+ [<ffffffff812e7f70>] dev_attr_store+0x20/0x30
+ [<ffffffff811c46b4>] sysfs_write_file+0xd4/0x160
+ [<ffffffff81155a26>] vfs_write+0xc6/0x190
+ [<ffffffff81155d51>] sys_write+0x51/0x90
+ [<ffffffff8100c012>] system_call_fastpath+0x16/0x1b
+..
+modprobe process stalled because has the fb_info lock (got inside
+unregister_framebuffer) but waiting for the semaphore held by the
+test process which is waiting to get the fb_info lock:
+..
+modprobe D 0000000000000000 0 230 218 0x00000000
+ ffff880077a4d618 0000000000000082 0000000000000001 0000000000000001
+ ffff880000000000 ffff880077a4dfd8 ffff880077a4dfd8 ffff8800775a2e20
+ 00000000000135c0 ffff880077a4dfd8 ffff880077a4c000 00000000000135c0
+Call Trace:
+ [<ffffffff81411fe5>] schedule_timeout+0x215/0x310
+ [<ffffffff81058051>] ? get_parent_ip+0x11/0x50
+ [<ffffffff814130dd>] __down+0x6d/0xb0
+ [<ffffffff81089f71>] down+0x41/0x50
+ [<ffffffff810629ac>] acquire_console_sem+0x2c/0x50
+ [<ffffffff812ca53d>] unbind_con_driver+0xad/0x2d0
+ [<ffffffff8126f5f7>] fbcon_event_notify+0x457/0x890
+ [<ffffffff814144ff>] ? _raw_spin_unlock_irqrestore+0x1f/0x50
+ [<ffffffff81058051>] ? get_parent_ip+0x11/0x50
+ [<ffffffff8141836d>] notifier_call_chain+0x4d/0x70
+ [<ffffffff8108a3b8>] __blocking_notifier_call_chain+0x58/0x80
+ [<ffffffff8108a3f6>] blocking_notifier_call_chain+0x16/0x20
+ [<ffffffff8125dabb>] fb_notifier_call_chain+0x1b/0x20
+ [<ffffffff8125e6ac>] unregister_framebuffer+0x7c/0x130
+ [<ffffffff8125e8b3>] remove_conflicting_framebuffers+0x153/0x180
+ [<ffffffff8125eef3>] register_framebuffer+0x93/0x2c0
+ [<ffffffffa0331112>] drm_fb_helper_single_fb_probe+0x252/0x2f0 [drm_kms_helper]
+ [<ffffffffa03314a3>] drm_fb_helper_initial_config+0x2f3/0x6d0 [drm_kms_helper]
+ [<ffffffffa03318dd>] ? drm_fb_helper_single_add_all_connectors+0x5d/0x1c0 [drm_kms_helper]
+ [<ffffffffa037b588>] intel_fbdev_init+0xa8/0x160 [i915]
+ [<ffffffffa0343d74>] i915_driver_load+0x854/0x12b0 [i915]
+ [<ffffffffa02f0e7e>] drm_get_pci_dev+0x19e/0x360 [drm]
+ [<ffffffff8141821d>] ? sub_preempt_count+0x9d/0xd0
+ [<ffffffffa0386f91>] i915_pci_probe+0x15/0x17 [i915]
+ [<ffffffff8124481f>] local_pci_probe+0x5f/0xd0
+ [<ffffffff81244f89>] pci_device_probe+0x119/0x120
+ [<ffffffff812eccaa>] ? driver_sysfs_add+0x7a/0xb0
+ [<ffffffff812ed003>] driver_probe_device+0xa3/0x290
+ [<ffffffff812ed1f0>] ? __driver_attach+0x0/0xb0
+ [<ffffffff812ed29b>] __driver_attach+0xab/0xb0
+ [<ffffffff812ed1f0>] ? __driver_attach+0x0/0xb0
+ [<ffffffff812ebd3e>] bus_for_each_dev+0x5e/0x90
+ [<ffffffff812ecc2e>] driver_attach+0x1e/0x20
+ [<ffffffff812ec6f2>] bus_add_driver+0xe2/0x320
+ [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
+ [<ffffffff812ed536>] driver_register+0x76/0x140
+ [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
+ [<ffffffff81245216>] __pci_register_driver+0x56/0xd0
+ [<ffffffffa02f1264>] drm_pci_init+0xe4/0xf0 [drm]
+ [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
+ [<ffffffffa02e84a8>] drm_init+0x58/0x70 [drm]
+ [<ffffffffa03aa094>] i915_init+0x94/0x96 [i915]
+ [<ffffffff81002194>] do_one_initcall+0x44/0x190
+ [<ffffffff810a066b>] sys_init_module+0xcb/0x210
+ [<ffffffff8100c012>] system_call_fastpath+0x16/0x1b
+..
+
+fb-test2 which reproduces above is available on kernel.org bug #26232.
+To solve this issue, avoid calling lock_fb_info inside fb_set_suspend,
+and move it out to where needed (callers of fb_set_suspend must call
+lock_fb_info before if needed). So far, the only place which needs to
+call lock_fb_info is store_fbstate, all other places which calls
+fb_set_suspend are suspend/resume hooks that should not need the lock as
+they should be run only when processes are already frozen in
+suspend/resume.
+
+References: https://bugzilla.kernel.org/show_bug.cgi?id=26232
+Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/fbmem.c | 3 ---
+ drivers/video/fbsysfs.c | 3 +++
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/video/fbmem.c
++++ b/drivers/video/fbmem.c
+@@ -1738,8 +1738,6 @@ void fb_set_suspend(struct fb_info *info
+ {
+ struct fb_event event;
+
+- if (!lock_fb_info(info))
+- return;
+ event.info = info;
+ if (state) {
+ fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
+@@ -1748,7 +1746,6 @@ void fb_set_suspend(struct fb_info *info
+ info->state = FBINFO_STATE_RUNNING;
+ fb_notifier_call_chain(FB_EVENT_RESUME, &event);
+ }
+- unlock_fb_info(info);
+ }
+
+ /**
+--- a/drivers/video/fbsysfs.c
++++ b/drivers/video/fbsysfs.c
+@@ -399,9 +399,12 @@ static ssize_t store_fbstate(struct devi
+
+ state = simple_strtoul(buf, &last, 0);
+
++ if (!lock_fb_info(fb_info))
++ return -ENODEV;
+ console_lock();
+ fb_set_suspend(fb_info, (int)state);
+ console_unlock();
++ unlock_fb_info(fb_info);
+
+ return count;
+ }
--- /dev/null
+From 4a47a0e09c504e3ce0ccdb405411aefc5b09deb8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= <bonbons@linux-vserver.org>
+Date: Fri, 2 Sep 2011 19:24:03 +0200
+Subject: fb: sh-mobile: Fix deadlock risk between lock_fb_info() and console_lock()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= <bonbons@linux-vserver.org>
+
+commit 4a47a0e09c504e3ce0ccdb405411aefc5b09deb8 upstream.
+
+Following on Herton's patch "fb: avoid possible deadlock caused by
+fb_set_suspend" which moves lock_fb_info() out of fb_set_suspend()
+to its callers, correct sh-mobile's locking around call to
+fb_set_suspend() and the same sort of deaklocks with console_lock()
+due to order of taking the lock.
+
+console_lock() must be taken while fb_info is already locked and fb_info
+must be locked while calling fb_set_suspend().
+
+Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
+Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/sh_mobile_hdmi.c | 47 ++++++++++++++++++++++-------------------
+ 1 file changed, 26 insertions(+), 21 deletions(-)
+
+--- a/drivers/video/sh_mobile_hdmi.c
++++ b/drivers/video/sh_mobile_hdmi.c
+@@ -1111,6 +1111,7 @@ static long sh_hdmi_clk_configure(struct
+ static void sh_hdmi_edid_work_fn(struct work_struct *work)
+ {
+ struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
++ struct fb_info *info;
+ struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+ struct sh_mobile_lcdc_chan *ch;
+ int ret;
+@@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct
+
+ mutex_lock(&hdmi->mutex);
+
++ info = hdmi->info;
++
+ if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
+- struct fb_info *info = hdmi->info;
+ unsigned long parent_rate = 0, hdmi_rate;
+
+ ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
+@@ -1148,42 +1150,45 @@ static void sh_hdmi_edid_work_fn(struct
+
+ ch = info->par;
+
+- console_lock();
++ if (lock_fb_info(info)) {
++ console_lock();
+
+- /* HDMI plug in */
+- if (!sh_hdmi_must_reconfigure(hdmi) &&
+- info->state == FBINFO_STATE_RUNNING) {
+- /*
+- * First activation with the default monitor - just turn
+- * on, if we run a resume here, the logo disappears
+- */
+- if (lock_fb_info(info)) {
++ /* HDMI plug in */
++ if (!sh_hdmi_must_reconfigure(hdmi) &&
++ info->state == FBINFO_STATE_RUNNING) {
++ /*
++ * First activation with the default monitor - just turn
++ * on, if we run a resume here, the logo disappears
++ */
+ info->var.width = hdmi->var.width;
+ info->var.height = hdmi->var.height;
+ sh_hdmi_display_on(hdmi, info);
+- unlock_fb_info(info);
++ } else {
++ /* New monitor or have to wake up */
++ fb_set_suspend(info, 0);
+ }
+- } else {
+- /* New monitor or have to wake up */
+- fb_set_suspend(info, 0);
+- }
+
+- console_unlock();
++ console_unlock();
++ unlock_fb_info(info);
++ }
+ } else {
+ ret = 0;
+- if (!hdmi->info)
++ if (!info)
+ goto out;
+
+ hdmi->monspec.modedb_len = 0;
+ fb_destroy_modedb(hdmi->monspec.modedb);
+ hdmi->monspec.modedb = NULL;
+
+- console_lock();
++ if (lock_fb_info(info)) {
++ console_lock();
+
+- /* HDMI disconnect */
+- fb_set_suspend(hdmi->info, 1);
++ /* HDMI disconnect */
++ fb_set_suspend(info, 1);
+
+- console_unlock();
++ console_unlock();
++ unlock_fb_info(info);
++ }
+ }
+
+ out:
--- /dev/null
+From 24dd85ff723f142093f44244764b9b5c152235b8 Mon Sep 17 00:00:00 2001
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+Date: Wed, 28 Sep 2011 11:57:23 +0200
+Subject: io-mapping: ensure io_mapping_map_atomic _is_ atomic
+
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+
+commit 24dd85ff723f142093f44244764b9b5c152235b8 upstream.
+
+For the !HAVE_ATOMIC_IOMAP case the stub functions did not call
+pagefault_disable/_enable. The i915 driver relies on the map
+actually being atomic, otherwise it can deadlock with it's own
+pagefault handler in the gtt pwrite fastpath.
+
+This is exercised by gem_mmap_gtt from the intel-gpu-toosl gem
+testsuite.
+
+v2: Chris Wilson noted the lack of an include.
+
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=38115
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Keith Packard <keithp@keithp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/io-mapping.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/include/linux/io-mapping.h
++++ b/include/linux/io-mapping.h
+@@ -117,6 +117,8 @@ io_mapping_unmap(void __iomem *vaddr)
+
+ #else
+
++#include <linux/uaccess.h>
++
+ /* this struct isn't actually defined anywhere */
+ struct io_mapping;
+
+@@ -138,12 +140,14 @@ static inline void __iomem *
+ io_mapping_map_atomic_wc(struct io_mapping *mapping,
+ unsigned long offset)
+ {
++ pagefault_disable();
+ return ((char __force __iomem *) mapping) + offset;
+ }
+
+ static inline void
+ io_mapping_unmap_atomic(void __iomem *vaddr)
+ {
++ pagefault_enable();
+ }
+
+ /* Non-atomic map/unmap */
--- /dev/null
+From fcd0861db1cf4e6ed99f60a815b7b72c2ed36ea4 Mon Sep 17 00:00:00 2001
+From: Joerg Roedel <joerg.roedel@amd.com>
+Date: Tue, 11 Oct 2011 17:41:32 +0200
+Subject: iommu/amd: Fix wrong shift direction
+
+From: Joerg Roedel <joerg.roedel@amd.com>
+
+commit fcd0861db1cf4e6ed99f60a815b7b72c2ed36ea4 upstream.
+
+The shift direction was wrong because the function takes a
+page number and i is the address is the loop.
+
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kernel/amd_iommu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/amd_iommu.c
++++ b/arch/x86/kernel/amd_iommu.c
+@@ -1203,7 +1203,7 @@ static int alloc_new_range(struct dma_op
+ if (!pte || !IOMMU_PTE_PRESENT(*pte))
+ continue;
+
+- dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1);
++ dma_ops_reserve_addresses(dma_dom, i >> PAGE_SHIFT, 1);
+ }
+
+ update_domain(&dma_dom->domain);
--- /dev/null
+From 4d47555a80495657161a7e71ec3014ff2021e450 Mon Sep 17 00:00:00 2001
+From: Carsten Otte <cotte@de.ibm.com>
+Date: Tue, 18 Oct 2011 12:27:12 +0200
+Subject: KVM: s390: check cpu_id prior to using it
+
+From: Carsten Otte <cotte@de.ibm.com>
+
+commit 4d47555a80495657161a7e71ec3014ff2021e450 upstream.
+
+We use the cpu id provided by userspace as array index here. Thus we
+clearly need to check it first. Ooops.
+
+Signed-off-by: Carsten Otte <cotte@de.ibm.com>
+Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
+Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/s390/kvm/kvm-s390.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -301,11 +301,17 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu
+ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
+ unsigned int id)
+ {
+- struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+- int rc = -ENOMEM;
++ struct kvm_vcpu *vcpu;
++ int rc = -EINVAL;
+
++ if (id >= KVM_MAX_VCPUS)
++ goto out;
++
++ rc = -ENOMEM;
++
++ vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+ if (!vcpu)
+- goto out_nomem;
++ goto out;
+
+ vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
+ get_zeroed_page(GFP_KERNEL);
+@@ -341,7 +347,7 @@ out_free_sie_block:
+ free_page((unsigned long)(vcpu->arch.sie_block));
+ out_free_cpu:
+ kfree(vcpu);
+-out_nomem:
++out:
+ return ERR_PTR(rc);
+ }
+
--- /dev/null
+From e73b7fffe487c315fd1a4fa22282e3362b440a06 Mon Sep 17 00:00:00 2001
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Sun, 30 Oct 2011 15:16:08 +0100
+Subject: [S390] memory leak with RCU_TABLE_FREE
+
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+
+commit e73b7fffe487c315fd1a4fa22282e3362b440a06 upstream.
+
+The rcu page table free code uses a couple of bits in the page table
+pointer passed to tlb_remove_table to discern the different page table
+types. __tlb_remove_table extracts the type with an incorrect mask which
+leads to memory leaks. The correct mask is ((FRAG_MASK << 4) | FRAG_MASK).
+
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/s390/mm/pgtable.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/arch/s390/mm/pgtable.c
++++ b/arch/s390/mm/pgtable.c
+@@ -291,8 +291,9 @@ void page_table_free_rcu(struct mmu_gath
+
+ void __tlb_remove_table(void *_table)
+ {
+- void *table = (void *)((unsigned long) _table & PAGE_MASK);
+- unsigned type = (unsigned long) _table & ~PAGE_MASK;
++ const unsigned long mask = (FRAG_MASK << 4) | FRAG_MASK;
++ void *table = (void *)((unsigned long) _table & ~mask);
++ unsigned type = (unsigned long) _table & mask;
+
+ if (type)
+ __page_table_free_rcu(table, type);
--- /dev/null
+From fc360bd9cdcf875639a77f07fafec26699c546f3 Mon Sep 17 00:00:00 2001
+From: Andrew Morton <akpm@linux-foundation.org>
+Date: Mon, 31 Oct 2011 17:06:32 -0700
+Subject: /proc/self/numa_maps: restore "huge" tag for hugetlb vmas
+
+From: Andrew Morton <akpm@linux-foundation.org>
+
+commit fc360bd9cdcf875639a77f07fafec26699c546f3 upstream.
+
+The display of the "huge" tag was accidentally removed in 29ea2f698 ("mm:
+use walk_page_range() instead of custom page table walking code").
+
+Reported-by: Stephen Hemminger <shemminger@vyatta.com>
+Tested-by: Stephen Hemminger <shemminger@vyatta.com>
+Reviewed-by: Stephen Wilson <wilsons@start.ca>
+Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Cc: Hugh Dickins <hughd@google.com>
+Acked-by: David Rientjes <rientjes@google.com>
+Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
+Cc: Alexey Dobriyan <adobriyan@gmail.com>
+Cc: Christoph Lameter <cl@linux-foundation.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/proc/task_mmu.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -1039,6 +1039,9 @@ static int show_numa_map(struct seq_file
+ seq_printf(m, " stack");
+ }
+
++ if (is_vm_hugetlb_page(vma))
++ seq_printf(m, " huge");
++
+ walk_page_range(vma->vm_start, vma->vm_end, &walk);
+
+ if (!md->pages)
nfsd4-ignore-want-bits-in-open-downgrade.patch
hppfs-missing-include.patch
vfs-add-device-tag-to-proc-self-mountstats.patch
+io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch
+asoc-wm8940-properly-set-codec-dapm.bias_level.patch
+asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch
+asoc-ak4642-fixup-cache-register-table.patch
+asoc-ak4535-fixup-cache-register-table.patch
+asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch
+asoc-remove-direct-register-cache-accesses-from-wm8962.patch
+asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch
+kvm-s390-check-cpu_id-prior-to-using-it.patch
+user-per-registers-vs.-ptrace-single-stepping.patch
+memory-leak-with-rcu_table_free.patch
+ccwgroup-move-attributes-to-attribute-group.patch
+wmi-properly-cleanup-devices-to-avoid-crashes.patch
+iommu-amd-fix-wrong-shift-direction.patch
+carminefb-fix-module-parameters-permissions.patch
+fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch
+fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch
+viafb-use-display-information-in-info-not-in-var-for.patch
+viafb-improve-pitch-handling.patch
+uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch
+dibcom-protect-the-i2c-bufer-access.patch
+dib0700-protect-the-dib0700-buffer-access.patch
+tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch
+proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch
--- /dev/null
+From 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@redhat.com>
+Date: Thu, 28 Jul 2011 16:38:54 -0300
+Subject: [media] tuner_xc2028: Allow selection of the frequency adjustment code for XC3028
+
+From: Mauro Carvalho Chehab <mchehab@redhat.com>
+
+commit 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e upstream.
+
+This device is not using the proper demod IF. Instead of using the
+IF macro, it is specifying a IF frequency. This doesn't work, as xc3028
+needs to load an specific SCODE for the tuner. In this case, there's
+no IF table for 5 MHz.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/cx23885/cx23885-dvb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/video/cx23885/cx23885-dvb.c
++++ b/drivers/media/video/cx23885/cx23885-dvb.c
+@@ -843,7 +843,7 @@ static int dvb_register(struct cx23885_t
+ static struct xc2028_ctrl ctl = {
+ .fname = XC3028L_DEFAULT_FIRMWARE,
+ .max_len = 64,
+- .demod = 5000,
++ .demod = XC3028_FE_DIBCOM52,
+ /* This is true for all demods with
+ v36 firmware? */
+ .type = XC2028_D2633,
--- /dev/null
+From a45aff5285871bf7be1781d9462d3fdbb6c913f9 Mon Sep 17 00:00:00 2001
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Sun, 30 Oct 2011 15:16:07 +0100
+Subject: [S390] user per registers vs. ptrace single stepping
+
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+
+commit a45aff5285871bf7be1781d9462d3fdbb6c913f9 upstream.
+
+git commit 5e9a2692 "[S390] ptrace cleanup" introduced a regression
+for the case when both a user PER set (e.g. a storage alteration trace) and
+PTRACE_SINGLESTEP are active. The new code will overrule the user PER set
+with a instruction-fetch PER set over the whole address space for ptrace
+single stepping. The inferior process will be stopped after each instruction
+with an instruction fetch event. Any other events that may have occurred
+concurrently are not reported (e.g. storage alteration event) because the
+control bits for them are not set. The solution is to merge the PER control
+bits of the user PER set with the PER_EVENT_IFETCH control bit for
+PTRACE_SINGLESTEP.
+
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/s390/kernel/ptrace.c | 28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+--- a/arch/s390/kernel/ptrace.c
++++ b/arch/s390/kernel/ptrace.c
+@@ -47,29 +47,31 @@ enum s390_regset {
+
+ void update_per_regs(struct task_struct *task)
+ {
+- static const struct per_regs per_single_step = {
+- .control = PER_EVENT_IFETCH,
+- .start = 0,
+- .end = PSW_ADDR_INSN,
+- };
+ struct pt_regs *regs = task_pt_regs(task);
+ struct thread_struct *thread = &task->thread;
+- const struct per_regs *new;
+- struct per_regs old;
++ struct per_regs old, new;
+
+- /* TIF_SINGLE_STEP overrides the user specified PER registers. */
+- new = test_tsk_thread_flag(task, TIF_SINGLE_STEP) ?
+- &per_single_step : &thread->per_user;
++ /* Copy user specified PER registers */
++ new.control = thread->per_user.control;
++ new.start = thread->per_user.start;
++ new.end = thread->per_user.end;
++
++ /* merge TIF_SINGLE_STEP into user specified PER registers. */
++ if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
++ new.control |= PER_EVENT_IFETCH;
++ new.start = 0;
++ new.end = PSW_ADDR_INSN;
++ }
+
+ /* Take care of the PER enablement bit in the PSW. */
+- if (!(new->control & PER_EVENT_MASK)) {
++ if (!(new.control & PER_EVENT_MASK)) {
+ regs->psw.mask &= ~PSW_MASK_PER;
+ return;
+ }
+ regs->psw.mask |= PSW_MASK_PER;
+ __ctl_store(old, 9, 11);
+- if (memcmp(new, &old, sizeof(struct per_regs)) != 0)
+- __ctl_load(*new, 9, 11);
++ if (memcmp(&new, &old, sizeof(struct per_regs)) != 0)
++ __ctl_load(new, 9, 11);
+ }
+
+ void user_enable_single_step(struct task_struct *task)
--- /dev/null
+From d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 Mon Sep 17 00:00:00 2001
+From: Ming Lei <tom.leiming@gmail.com>
+Date: Sat, 16 Jul 2011 00:51:00 -0300
+Subject: [media] uvcvideo: Set alternate setting 0 on resume if the bus has been reset
+
+From: Ming Lei <tom.leiming@gmail.com>
+
+commit d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 upstream.
+
+If the bus has been reset on resume, set the alternate setting to 0.
+This should be the default value, but some devices crash or otherwise
+misbehave if they don't receive a SET_INTERFACE request before any other
+video control request.
+
+Microdia's 0c45:6437 camera has been found to require this change or it
+will stop sending video data after resume.
+
+uvc_video.c]
+
+Signed-off-by: Ming Lei <ming.lei@canonical.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/uvc/uvc_driver.c | 2 +-
+ drivers/media/video/uvc/uvc_video.c | 10 +++++++++-
+ drivers/media/video/uvc/uvcvideo.h | 2 +-
+ 3 files changed, 11 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/video/uvc/uvc_driver.c
++++ b/drivers/media/video/uvc/uvc_driver.c
+@@ -1960,7 +1960,7 @@ static int __uvc_resume(struct usb_inter
+
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->intf == intf)
+- return uvc_video_resume(stream);
++ return uvc_video_resume(stream, reset);
+ }
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
+--- a/drivers/media/video/uvc/uvc_video.c
++++ b/drivers/media/video/uvc/uvc_video.c
+@@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streami
+ * buffers, making sure userspace applications are notified of the problem
+ * instead of waiting forever.
+ */
+-int uvc_video_resume(struct uvc_streaming *stream)
++int uvc_video_resume(struct uvc_streaming *stream, int reset)
+ {
+ int ret;
+
++ /* If the bus has been reset on resume, set the alternate setting to 0.
++ * This should be the default value, but some devices crash or otherwise
++ * misbehave if they don't receive a SET_INTERFACE request before any
++ * other video control request.
++ */
++ if (reset)
++ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
++
+ stream->frozen = 0;
+
+ ret = uvc_commit_video(stream, &stream->ctrl);
+--- a/drivers/media/video/uvc/uvcvideo.h
++++ b/drivers/media/video/uvc/uvcvideo.h
+@@ -639,7 +639,7 @@ extern void uvc_mc_cleanup_entity(struct
+ /* Video */
+ extern int uvc_video_init(struct uvc_streaming *stream);
+ extern int uvc_video_suspend(struct uvc_streaming *stream);
+-extern int uvc_video_resume(struct uvc_streaming *stream);
++extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
+ extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
+ extern int uvc_probe_video(struct uvc_streaming *stream,
+ struct uvc_streaming_control *probe);
--- /dev/null
+From 936a3f770b8de7042d793272f008ef1bb08522e9 Mon Sep 17 00:00:00 2001
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Date: Mon, 6 Jun 2011 01:27:34 +0000
+Subject: viafb: improve pitch handling
+
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+
+commit 936a3f770b8de7042d793272f008ef1bb08522e9 upstream.
+
+This patch adds checks for minimum and maximum pitch size to prevent
+invalid settings which could otherwise crash the machine. Also the
+alignment is done in a slightly more readable way.
+
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/via/via_modesetting.h | 5 +++++
+ drivers/video/via/viafbdev.c | 11 ++++++++---
+ 2 files changed, 13 insertions(+), 3 deletions(-)
+
+--- a/drivers/video/via/via_modesetting.h
++++ b/drivers/video/via/via_modesetting.h
+@@ -28,6 +28,11 @@
+
+ #include <linux/types.h>
+
++
++#define VIA_PITCH_SIZE (1<<3)
++#define VIA_PITCH_MAX 0x3FF8
++
++
+ void via_set_primary_address(u32 addr);
+ void via_set_secondary_address(u32 addr);
+ void via_set_primary_pitch(u32 pitch);
+--- a/drivers/video/via/viafbdev.c
++++ b/drivers/video/via/viafbdev.c
+@@ -151,7 +151,8 @@ static void viafb_update_fix(struct fb_i
+
+ info->fix.visual =
+ bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+- info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
++ info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
++ VIA_PITCH_SIZE);
+ }
+
+ static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
+@@ -238,8 +239,12 @@ static int viafb_check_var(struct fb_var
+ depth = 24;
+
+ viafb_fill_var_color_info(var, depth);
+- line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
+- if (line * var->yres_virtual > ppar->memsize)
++ if (var->xres_virtual < var->xres)
++ var->xres_virtual = var->xres;
++
++ line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
++ VIA_PITCH_SIZE);
++ if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
+ return -EINVAL;
+
+ /* Based on var passed in to calculate the refresh,
--- /dev/null
+From d933990c57b498c092ceef591c7c5d69dbfe9f30 Mon Sep 17 00:00:00 2001
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Date: Mon, 23 May 2011 21:39:58 +0000
+Subject: viafb: use display information in info not in var for panning
+
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+
+commit d933990c57b498c092ceef591c7c5d69dbfe9f30 upstream.
+
+As Laurent pointed out we must not use any information in the passed
+var besides xoffset, yoffset and vmode as otherwise applications
+might abuse it. Also use the aligned fix.line_length and not the
+(possible) unaligned xres_virtual.
+
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/via/viafbdev.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/video/via/viafbdev.c
++++ b/drivers/video/via/viafbdev.c
+@@ -348,8 +348,9 @@ static int viafb_pan_display(struct fb_v
+ struct fb_info *info)
+ {
+ struct viafb_par *viapar = info->par;
+- u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset)
+- * (var->bits_per_pixel / 8) + viapar->vram_addr;
++ u32 vram_addr = viapar->vram_addr
++ + var->yoffset * info->fix.line_length
++ + var->xoffset * info->var.bits_per_pixel / 8;
+
+ DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
+ if (!viafb_dual_fb) {
--- /dev/null
+From 023b9565972a4a5e0f01b9aa32680af6e9b5c388 Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Wed, 7 Sep 2011 15:00:02 -0700
+Subject: WMI: properly cleanup devices to avoid crashes
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+commit 023b9565972a4a5e0f01b9aa32680af6e9b5c388 upstream.
+
+We need to remove devices that we destroy from the list, otherwise
+we'll crash if there are more than one "_WDG" methods in DSDT.
+
+This fixes https://bugzilla.kernel.org/show_bug.cgi?id=32052
+
+Tested-by: Ilya Tumaykin <librarian_rus@yahoo.com>
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Acked-by: Carlos Corbacho <carlos@strangeworlds.co.uk>
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/wmi.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/platform/x86/wmi.c
++++ b/drivers/platform/x86/wmi.c
+@@ -754,9 +754,13 @@ static void wmi_free_devices(void)
+ struct wmi_block *wblock, *next;
+
+ /* Delete devices for all the GUIDs */
+- list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
++ list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
++ list_del(&wblock->list);
+ if (wblock->dev.class)
+ device_unregister(&wblock->dev);
++ else
++ kfree(wblock);
++ }
+ }
+
+ static bool guid_already_parsed(const char *guid_string)