From: Greg Kroah-Hartman Date: Wed, 2 Nov 2011 16:29:08 +0000 (-0700) Subject: 3.0 patches X-Git-Tag: v3.0.9~43 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d42cefe0b78c78207287192ead2cec2c4f643a36;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0 patches --- diff --git a/queue-3.0/asoc-ak4535-fixup-cache-register-table.patch b/queue-3.0/asoc-ak4535-fixup-cache-register-table.patch new file mode 100644 index 00000000000..e6e71c28bed --- /dev/null +++ b/queue-3.0/asoc-ak4535-fixup-cache-register-table.patch @@ -0,0 +1,38 @@ +From 7c04241acbdaf97f1448dcccd27ea0fcd1a57684 Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Thu, 13 Oct 2011 17:17:06 +0800 +Subject: ASoC: ak4535: fixup cache register table + +From: Axel Lin + +commit 7c04241acbdaf97f1448dcccd27ea0fcd1a57684 upstream. + +ak4535_reg should be 8bit, but cache table is defined as 16bit. + +Signed-off-by: Axel Lin +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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, + }; + + /* diff --git a/queue-3.0/asoc-ak4642-fixup-cache-register-table.patch b/queue-3.0/asoc-ak4642-fixup-cache-register-table.patch new file mode 100644 index 00000000000..f16bb8108de --- /dev/null +++ b/queue-3.0/asoc-ak4642-fixup-cache-register-table.patch @@ -0,0 +1,51 @@ +From 19b115e523208a926813751aac8934cf3fc6085e Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Thu, 13 Oct 2011 02:03:54 -0700 +Subject: ASoC: ak4642: fixup cache register table + +From: Kuninori Morimoto + +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 +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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, + }; + + /* diff --git a/queue-3.0/asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch b/queue-3.0/asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch new file mode 100644 index 00000000000..b248db380df --- /dev/null +++ b/queue-3.0/asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch @@ -0,0 +1,31 @@ +From fbc7c62a3ff831aef24894b7982cd1adb2b7e070 Mon Sep 17 00:00:00 2001 +From: Susan Gao +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 + +commit fbc7c62a3ff831aef24894b7982cd1adb2b7e070 upstream. + +Signed-off-by: Susan Gao +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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) { diff --git a/queue-3.0/asoc-remove-direct-register-cache-accesses-from-wm8962.patch b/queue-3.0/asoc-remove-direct-register-cache-accesses-from-wm8962.patch new file mode 100644 index 00000000000..40e7f00cbd2 --- /dev/null +++ b/queue-3.0/asoc-remove-direct-register-cache-accesses-from-wm8962.patch @@ -0,0 +1,72 @@ +From 38f3f31a0a797bdbcc0cdb12553bbecc2f9a91c4 Mon Sep 17 00:00:00 2001 +From: Mark Brown +Date: Fri, 23 Sep 2011 21:26:33 +0100 +Subject: ASoC: Remove direct register cache accesses from WM8962 driver + +From: Mark Brown + +commit 38f3f31a0a797bdbcc0cdb12553bbecc2f9a91c4 upstream. + +Also fix return values for speaker switch updates. + +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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; diff --git a/queue-3.0/asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch b/queue-3.0/asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch new file mode 100644 index 00000000000..6e8ad364160 --- /dev/null +++ b/queue-3.0/asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch @@ -0,0 +1,48 @@ +From 3a340104fad6ecbea5ad6792a2ea855f0507a6e0 Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Mon, 17 Oct 2011 20:14:56 +0800 +Subject: ASoC: wm8741: Fix setting interface format for DSP modes + +From: Axel Lin + +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 +Acked-by: Liam Girdwood +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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; diff --git a/queue-3.0/asoc-wm8940-properly-set-codec-dapm.bias_level.patch b/queue-3.0/asoc-wm8940-properly-set-codec-dapm.bias_level.patch new file mode 100644 index 00000000000..fd0d167bd47 --- /dev/null +++ b/queue-3.0/asoc-wm8940-properly-set-codec-dapm.bias_level.patch @@ -0,0 +1,29 @@ +From 5927f94700e860ae27ff24e7f3bc9e4f7b9922eb Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Wed, 26 Oct 2011 09:53:41 +0800 +Subject: ASoC: wm8940: Properly set codec->dapm.bias_level + +From: Axel Lin + +commit 5927f94700e860ae27ff24e7f3bc9e4f7b9922eb upstream. + +Reported-by: Chris Paulson-Ellis +Signed-off-by: Axel Lin +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } + diff --git a/queue-3.0/asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch b/queue-3.0/asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch new file mode 100644 index 00000000000..2bee0a1f7a4 --- /dev/null +++ b/queue-3.0/asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch @@ -0,0 +1,29 @@ +From 35024f4922f7b271e7529673413889aa3d51c5fc Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Thu, 20 Oct 2011 12:13:24 +0800 +Subject: ASoC: wm8994: Use SND_SOC_DAPM_AIF_OUT for AIF3 Capture + +From: Axel Lin + +commit 35024f4922f7b271e7529673413889aa3d51c5fc upstream. + +Signed-off-by: Axel Lin +Acked-by: Liam Girdwood +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + 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), + diff --git a/queue-3.0/carminefb-fix-module-parameters-permissions.patch b/queue-3.0/carminefb-fix-module-parameters-permissions.patch new file mode 100644 index 00000000000..46e0331c841 --- /dev/null +++ b/queue-3.0/carminefb-fix-module-parameters-permissions.patch @@ -0,0 +1,61 @@ +From c84c14224bbca6ec60d5851fcc87be0e34df2f44 Mon Sep 17 00:00:00 2001 +From: Jean Delvare +Date: Fri, 8 Jul 2011 11:04:38 +0200 +Subject: carminefb: Fix module parameters permissions + +From: Jean Delvare + +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 +Cc: Paul Mundt +Cc: Sebastian Siewior +Signed-off-by: Paul Mundt +Signed-off-by: Greg Kroah-Hartman + +--- + 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 { diff --git a/queue-3.0/ccwgroup-move-attributes-to-attribute-group.patch b/queue-3.0/ccwgroup-move-attributes-to-attribute-group.patch new file mode 100644 index 00000000000..ad50394addf --- /dev/null +++ b/queue-3.0/ccwgroup-move-attributes-to-attribute-group.patch @@ -0,0 +1,125 @@ +From dbdf1afcaaabe83dea15a3cb9b9013e73ae3b1ad Mon Sep 17 00:00:00 2001 +From: Sebastian Ott +Date: Sun, 30 Oct 2011 15:16:52 +0100 +Subject: [S390] ccwgroup: move attributes to attribute group + +From: Sebastian Ott + +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 +Signed-off-by: Martin Schwidefsky +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + diff --git a/queue-3.0/dib0700-protect-the-dib0700-buffer-access.patch b/queue-3.0/dib0700-protect-the-dib0700-buffer-access.patch new file mode 100644 index 00000000000..71e6fdb47bc --- /dev/null +++ b/queue-3.0/dib0700-protect-the-dib0700-buffer-access.patch @@ -0,0 +1,250 @@ +From bff469f4167fdabfe15294f375577d7eadbaa1bb Mon Sep 17 00:00:00 2001 +From: Olivier Grenie +Date: Mon, 1 Aug 2011 12:45:58 -0300 +Subject: [media] dib0700: protect the dib0700 buffer access + +From: Olivier Grenie + +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 +Cc: Florian Mickler +Signed-off-by: Javier Marcet +Signed-off-by: Olivier Grenie +Signed-off-by: Patrick Boettcher +[mchehab@redhat.com: dprint requires 3 arguments. Replaced by dib_info] +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } + diff --git a/queue-3.0/dibcom-protect-the-i2c-bufer-access.patch b/queue-3.0/dibcom-protect-the-i2c-bufer-access.patch new file mode 100644 index 00000000000..540a64f3884 --- /dev/null +++ b/queue-3.0/dibcom-protect-the-i2c-bufer-access.patch @@ -0,0 +1,1145 @@ +From 79fcce3230b140f7675f8529ee53fe2f9644f902 Mon Sep 17 00:00:00 2001 +From: Patrick Boettcher +Date: Wed, 3 Aug 2011 12:08:21 -0300 +Subject: [media] DiBcom: protect the I2C bufer access + +From: Patrick Boettcher + +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 +Cc: Florian Mickler +Signed-off-by: Olivier Grenie +Signed-off-by: Patrick Boettcher +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + #include ++#include + + #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 + #include + #include ++#include + + #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 + #include + #include ++#include + + #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 + #include + #include ++#include + + #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 + #include + #include ++#include ++ + #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 ++#include + + #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, diff --git a/queue-3.0/fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch b/queue-3.0/fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch new file mode 100644 index 00000000000..10d1e3f284e --- /dev/null +++ b/queue-3.0/fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch @@ -0,0 +1,150 @@ +From 9e769ff3f585db8f978f9113be83d36c7e3965dd Mon Sep 17 00:00:00 2001 +From: Herton Ronaldo Krzesinski +Date: Fri, 17 Jun 2011 19:02:39 +0000 +Subject: fb: avoid possible deadlock caused by fb_set_suspend + +From: Herton Ronaldo Krzesinski + +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: + [] __mutex_lock_slowpath+0x11a/0x1e0 + [] ? _raw_spin_lock_irq+0x22/0x40 + [] mutex_lock+0x23/0x50 + [] lock_fb_info+0x25/0x60 + [] fb_set_suspend+0x20/0x80 + [] store_fbstate+0x4f/0x70 + [] dev_attr_store+0x20/0x30 + [] sysfs_write_file+0xd4/0x160 + [] vfs_write+0xc6/0x190 + [] sys_write+0x51/0x90 + [] 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: + [] schedule_timeout+0x215/0x310 + [] ? get_parent_ip+0x11/0x50 + [] __down+0x6d/0xb0 + [] down+0x41/0x50 + [] acquire_console_sem+0x2c/0x50 + [] unbind_con_driver+0xad/0x2d0 + [] fbcon_event_notify+0x457/0x890 + [] ? _raw_spin_unlock_irqrestore+0x1f/0x50 + [] ? get_parent_ip+0x11/0x50 + [] notifier_call_chain+0x4d/0x70 + [] __blocking_notifier_call_chain+0x58/0x80 + [] blocking_notifier_call_chain+0x16/0x20 + [] fb_notifier_call_chain+0x1b/0x20 + [] unregister_framebuffer+0x7c/0x130 + [] remove_conflicting_framebuffers+0x153/0x180 + [] register_framebuffer+0x93/0x2c0 + [] drm_fb_helper_single_fb_probe+0x252/0x2f0 [drm_kms_helper] + [] drm_fb_helper_initial_config+0x2f3/0x6d0 [drm_kms_helper] + [] ? drm_fb_helper_single_add_all_connectors+0x5d/0x1c0 [drm_kms_helper] + [] intel_fbdev_init+0xa8/0x160 [i915] + [] i915_driver_load+0x854/0x12b0 [i915] + [] drm_get_pci_dev+0x19e/0x360 [drm] + [] ? sub_preempt_count+0x9d/0xd0 + [] i915_pci_probe+0x15/0x17 [i915] + [] local_pci_probe+0x5f/0xd0 + [] pci_device_probe+0x119/0x120 + [] ? driver_sysfs_add+0x7a/0xb0 + [] driver_probe_device+0xa3/0x290 + [] ? __driver_attach+0x0/0xb0 + [] __driver_attach+0xab/0xb0 + [] ? __driver_attach+0x0/0xb0 + [] bus_for_each_dev+0x5e/0x90 + [] driver_attach+0x1e/0x20 + [] bus_add_driver+0xe2/0x320 + [] ? i915_init+0x0/0x96 [i915] + [] driver_register+0x76/0x140 + [] ? i915_init+0x0/0x96 [i915] + [] __pci_register_driver+0x56/0xd0 + [] drm_pci_init+0xe4/0xf0 [drm] + [] ? i915_init+0x0/0x96 [i915] + [] drm_init+0x58/0x70 [drm] + [] i915_init+0x94/0x96 [i915] + [] do_one_initcall+0x44/0x190 + [] sys_init_module+0xcb/0x210 + [] 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 +Signed-off-by: Florian Tobias Schandinat +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } diff --git a/queue-3.0/fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch b/queue-3.0/fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch new file mode 100644 index 00000000000..b93d502fc59 --- /dev/null +++ b/queue-3.0/fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch @@ -0,0 +1,117 @@ +From 4a47a0e09c504e3ce0ccdb405411aefc5b09deb8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= +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?= + +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 +Signed-off-by: Guennadi Liakhovetski +Signed-off-by: Florian Tobias Schandinat +Signed-off-by: Greg Kroah-Hartman + +--- + 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: diff --git a/queue-3.0/io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch b/queue-3.0/io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch new file mode 100644 index 00000000000..20bdf97e741 --- /dev/null +++ b/queue-3.0/io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch @@ -0,0 +1,55 @@ +From 24dd85ff723f142093f44244764b9b5c152235b8 Mon Sep 17 00:00:00 2001 +From: Daniel Vetter +Date: Wed, 28 Sep 2011 11:57:23 +0200 +Subject: io-mapping: ensure io_mapping_map_atomic _is_ atomic + +From: Daniel Vetter + +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 +Reviewed-by: Chris Wilson +Signed-off-by: Keith Packard +Signed-off-by: Greg Kroah-Hartman + +--- + 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 ++ + /* 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 */ diff --git a/queue-3.0/iommu-amd-fix-wrong-shift-direction.patch b/queue-3.0/iommu-amd-fix-wrong-shift-direction.patch new file mode 100644 index 00000000000..459b2d6fd5a --- /dev/null +++ b/queue-3.0/iommu-amd-fix-wrong-shift-direction.patch @@ -0,0 +1,30 @@ +From fcd0861db1cf4e6ed99f60a815b7b72c2ed36ea4 Mon Sep 17 00:00:00 2001 +From: Joerg Roedel +Date: Tue, 11 Oct 2011 17:41:32 +0200 +Subject: iommu/amd: Fix wrong shift direction + +From: Joerg Roedel + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-3.0/kvm-s390-check-cpu_id-prior-to-using-it.patch b/queue-3.0/kvm-s390-check-cpu_id-prior-to-using-it.patch new file mode 100644 index 00000000000..3a8b1ea735e --- /dev/null +++ b/queue-3.0/kvm-s390-check-cpu_id-prior-to-using-it.patch @@ -0,0 +1,53 @@ +From 4d47555a80495657161a7e71ec3014ff2021e450 Mon Sep 17 00:00:00 2001 +From: Carsten Otte +Date: Tue, 18 Oct 2011 12:27:12 +0200 +Subject: KVM: s390: check cpu_id prior to using it + +From: Carsten Otte + +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 +Signed-off-by: Christian Borntraeger +Signed-off-by: Marcelo Tosatti +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + } + diff --git a/queue-3.0/memory-leak-with-rcu_table_free.patch b/queue-3.0/memory-leak-with-rcu_table_free.patch new file mode 100644 index 00000000000..f1a6b24bc54 --- /dev/null +++ b/queue-3.0/memory-leak-with-rcu_table_free.patch @@ -0,0 +1,35 @@ +From e73b7fffe487c315fd1a4fa22282e3362b440a06 Mon Sep 17 00:00:00 2001 +From: Martin Schwidefsky +Date: Sun, 30 Oct 2011 15:16:08 +0100 +Subject: [S390] memory leak with RCU_TABLE_FREE + +From: Martin Schwidefsky + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-3.0/proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch b/queue-3.0/proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch new file mode 100644 index 00000000000..50936c47ba6 --- /dev/null +++ b/queue-3.0/proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch @@ -0,0 +1,41 @@ +From fc360bd9cdcf875639a77f07fafec26699c546f3 Mon Sep 17 00:00:00 2001 +From: Andrew Morton +Date: Mon, 31 Oct 2011 17:06:32 -0700 +Subject: /proc/self/numa_maps: restore "huge" tag for hugetlb vmas + +From: Andrew Morton + +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 +Tested-by: Stephen Hemminger +Reviewed-by: Stephen Wilson +Cc: KOSAKI Motohiro +Cc: Hugh Dickins +Acked-by: David Rientjes +Cc: Lee Schermerhorn +Cc: Alexey Dobriyan +Cc: Christoph Lameter +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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) diff --git a/queue-3.0/series b/queue-3.0/series index 0dd9da09816..da04bef9a4b 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -96,3 +96,27 @@ nfsd4-fix-open-downgrade-again.patch 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 diff --git a/queue-3.0/tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch b/queue-3.0/tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch new file mode 100644 index 00000000000..8026a48cd6e --- /dev/null +++ b/queue-3.0/tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch @@ -0,0 +1,32 @@ +From 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +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 + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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, diff --git a/queue-3.0/user-per-registers-vs.-ptrace-single-stepping.patch b/queue-3.0/user-per-registers-vs.-ptrace-single-stepping.patch new file mode 100644 index 00000000000..897ec753917 --- /dev/null +++ b/queue-3.0/user-per-registers-vs.-ptrace-single-stepping.patch @@ -0,0 +1,74 @@ +From a45aff5285871bf7be1781d9462d3fdbb6c913f9 Mon Sep 17 00:00:00 2001 +From: Martin Schwidefsky +Date: Sun, 30 Oct 2011 15:16:07 +0100 +Subject: [S390] user per registers vs. ptrace single stepping + +From: Martin Schwidefsky + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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) diff --git a/queue-3.0/uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch b/queue-3.0/uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch new file mode 100644 index 00000000000..94c5287b853 --- /dev/null +++ b/queue-3.0/uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch @@ -0,0 +1,74 @@ +From d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 Mon Sep 17 00:00:00 2001 +From: Ming Lei +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 + +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 +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + 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); diff --git a/queue-3.0/viafb-improve-pitch-handling.patch b/queue-3.0/viafb-improve-pitch-handling.patch new file mode 100644 index 00000000000..5b104dba9e1 --- /dev/null +++ b/queue-3.0/viafb-improve-pitch-handling.patch @@ -0,0 +1,62 @@ +From 936a3f770b8de7042d793272f008ef1bb08522e9 Mon Sep 17 00:00:00 2001 +From: Florian Tobias Schandinat +Date: Mon, 6 Jun 2011 01:27:34 +0000 +Subject: viafb: improve pitch handling + +From: Florian Tobias Schandinat + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + ++ ++#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, diff --git a/queue-3.0/viafb-use-display-information-in-info-not-in-var-for.patch b/queue-3.0/viafb-use-display-information-in-info-not-in-var-for.patch new file mode 100644 index 00000000000..d3250bbd6b3 --- /dev/null +++ b/queue-3.0/viafb-use-display-information-in-info-not-in-var-for.patch @@ -0,0 +1,37 @@ +From d933990c57b498c092ceef591c7c5d69dbfe9f30 Mon Sep 17 00:00:00 2001 +From: Florian Tobias Schandinat +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 + +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 +Reported-by: Laurent Pinchart +Acked-by: Laurent Pinchart +Signed-off-by: Greg Kroah-Hartman + +--- + 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) { diff --git a/queue-3.0/wmi-properly-cleanup-devices-to-avoid-crashes.patch b/queue-3.0/wmi-properly-cleanup-devices-to-avoid-crashes.patch new file mode 100644 index 00000000000..9da4cd2b548 --- /dev/null +++ b/queue-3.0/wmi-properly-cleanup-devices-to-avoid-crashes.patch @@ -0,0 +1,41 @@ +From 023b9565972a4a5e0f01b9aa32680af6e9b5c388 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Wed, 7 Sep 2011 15:00:02 -0700 +Subject: WMI: properly cleanup devices to avoid crashes + +From: Dmitry Torokhov + +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 +Signed-off-by: Dmitry Torokhov +Acked-by: Carlos Corbacho +Signed-off-by: Matthew Garrett +Signed-off-by: Greg Kroah-Hartman + +--- + 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)