From: Greg Kroah-Hartman Date: Tue, 24 Mar 2015 12:32:32 +0000 (+0100) Subject: 3.14-stable patches X-Git-Tag: v3.19.3~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=df9e759e2c3dec8d64d69328ecae5ffbdc7578c5;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: alsa-control-add-sanity-checks-for-user-ctl-id-name-string.patch alsa-hda-add-workaround-for-macbook-air-5-2-built-in-mic.patch alsa-hda-don-t-access-stereo-amps-for-mono-channel-widgets.patch alsa-hda-fix-built-in-mic-on-compaq-presario-cq60.patch alsa-hda-fix-regression-of-hd-audio-controller-fallback-modes.patch alsa-hda-set-single_adc_amp-flag-for-cs420x-codecs.patch alsa-hda-treat-stereo-to-mono-mix-properly.patch alsa-snd-usb-add-quirks-for-roland-ua-22.patch bnx2x-force-fundamental-reset-for-eeh-recovery.patch can-add-missing-initialisations-in-can-related-skbuffs.patch cpuset-fix-cpuset-sched_relax_domain_level.patch drm-vmwgfx-reorder-device-takedown-somewhat.patch mtd-nand-pxa3xx-fix-pio-fifo-draining.patch nilfs2-fix-deadlock-of-segment-constructor-during-recovery.patch regulator-core-fix-enable-gpio-reference-counting.patch regulator-only-enable-disabled-regulators-on-resume.patch spi-atmel-fix-interrupt-setup-for-pdc-transfers.patch spi-pl022-fix-race-in-giveback-leading-to-driver-lock-up.patch tpm-ibmvtpm-additional-le-support-for-tpm_ibmvtpm_send.patch workqueue-fix-hang-involving-racing-cancel_work_sync-s-for-preempt_none.patch --- diff --git a/queue-3.14/alsa-control-add-sanity-checks-for-user-ctl-id-name-string.patch b/queue-3.14/alsa-control-add-sanity-checks-for-user-ctl-id-name-string.patch new file mode 100644 index 00000000000..212fb6265f6 --- /dev/null +++ b/queue-3.14/alsa-control-add-sanity-checks-for-user-ctl-id-name-string.patch @@ -0,0 +1,33 @@ +From be3bb8236db2d0fcd705062ae2e2a9d75131222f Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 11 Mar 2015 18:12:49 +0100 +Subject: ALSA: control: Add sanity checks for user ctl id name string + +From: Takashi Iwai + +commit be3bb8236db2d0fcd705062ae2e2a9d75131222f upstream. + +There was no check about the id string of user control elements, so we +accepted even a control element with an empty string, which is +obviously bogus. This patch adds more sanity checks of id strings. + +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/control.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -1168,6 +1168,10 @@ static int snd_ctl_elem_add(struct snd_c + + if (info->count < 1) + return -EINVAL; ++ if (!*info->id.name) ++ return -EINVAL; ++ if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name)) ++ return -EINVAL; + access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : + (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| + SNDRV_CTL_ELEM_ACCESS_INACTIVE| diff --git a/queue-3.14/alsa-hda-add-workaround-for-macbook-air-5-2-built-in-mic.patch b/queue-3.14/alsa-hda-add-workaround-for-macbook-air-5-2-built-in-mic.patch new file mode 100644 index 00000000000..4f84592256a --- /dev/null +++ b/queue-3.14/alsa-hda-add-workaround-for-macbook-air-5-2-built-in-mic.patch @@ -0,0 +1,32 @@ +From 2ddee91abe9cc34ddb6294ee14702b46ae07d460 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 12 Mar 2015 20:47:15 +0100 +Subject: ALSA: hda - Add workaround for MacBook Air 5,2 built-in mic + +From: Takashi Iwai + +commit 2ddee91abe9cc34ddb6294ee14702b46ae07d460 upstream. + +MacBook Air 5,2 has the same problem as MacBook Pro 8,1 where the +built-in mic records only the right channel. Apply the same +workaround as MBP8,1 to spread the mono channel via a Cirrus codec +vendor-specific COEF setup. + +Reported-and-tested-by: Vasil Zlatanov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/pci/hda/patch_cirrus.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/pci/hda/patch_cirrus.c ++++ b/sound/pci/hda/patch_cirrus.c +@@ -396,6 +396,7 @@ static const struct snd_pci_quirk cs420x + SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), + SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), + SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), ++ SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81), + SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42), + SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), + {} /* terminator */ diff --git a/queue-3.14/alsa-hda-don-t-access-stereo-amps-for-mono-channel-widgets.patch b/queue-3.14/alsa-hda-don-t-access-stereo-amps-for-mono-channel-widgets.patch new file mode 100644 index 00000000000..17043a707f1 --- /dev/null +++ b/queue-3.14/alsa-hda-don-t-access-stereo-amps-for-mono-channel-widgets.patch @@ -0,0 +1,87 @@ +From ef403edb75580a3ec5d155f5de82155f0419c621 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 12 Mar 2015 08:30:11 +0100 +Subject: ALSA: hda - Don't access stereo amps for mono channel widgets + +From: Takashi Iwai + +commit ef403edb75580a3ec5d155f5de82155f0419c621 upstream. + +The current HDA generic parser initializes / modifies the amp values +always in stereo, but this seems causing the problem on ALC3229 codec +that has a few mono channel widgets: namely, these mono widgets react +to actions for both channels equally. + +In the driver code, we do care the mono channel and create a control +only for the left channel (as defined in HD-audio spec) for such a +node. When the control is updated, only the left channel value is +changed. However, in the resume, the right channel value is also +restored from the initial value we took as stereo, and this overwrites +the left channel value. This ends up being the silent output as the +right channel has been never touched and remains muted. + +This patch covers the places where unconditional stereo amp accesses +are done and converts to the conditional accesses. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94581 +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/pci/hda/hda_generic.c | 30 ++++++++++++++++++++++-------- + 1 file changed, 22 insertions(+), 8 deletions(-) + +--- a/sound/pci/hda/hda_generic.c ++++ b/sound/pci/hda/hda_generic.c +@@ -658,7 +658,23 @@ static void init_amp(struct hda_codec *c + { + unsigned int caps = query_amp_caps(codec, nid, dir); + int val = get_amp_val_to_activate(codec, nid, dir, caps, false); +- snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); ++ ++ if (get_wcaps(codec, nid) & AC_WCAP_STEREO) ++ snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); ++ else ++ snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val); ++} ++ ++/* update the amp, doing in stereo or mono depending on NID */ ++static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, ++ unsigned int mask, unsigned int val) ++{ ++ if (get_wcaps(codec, nid) & AC_WCAP_STEREO) ++ return snd_hda_codec_amp_stereo(codec, nid, dir, idx, ++ mask, val); ++ else ++ return snd_hda_codec_amp_update(codec, nid, 0, dir, idx, ++ mask, val); + } + + /* calculate amp value mask we can modify; +@@ -698,7 +714,7 @@ static void activate_amp(struct hda_code + return; + + val &= mask; +- snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); ++ update_amp(codec, nid, dir, idx, mask, val); + } + + static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, +@@ -4337,13 +4353,11 @@ static void mute_all_mixer_nid(struct hd + has_amp = nid_has_mute(codec, mix, HDA_INPUT); + for (i = 0; i < nums; i++) { + if (has_amp) +- snd_hda_codec_amp_stereo(codec, mix, +- HDA_INPUT, i, +- 0xff, HDA_AMP_MUTE); ++ update_amp(codec, mix, HDA_INPUT, i, ++ 0xff, HDA_AMP_MUTE); + else if (nid_has_volume(codec, conn[i], HDA_OUTPUT)) +- snd_hda_codec_amp_stereo(codec, conn[i], +- HDA_OUTPUT, 0, +- 0xff, HDA_AMP_MUTE); ++ update_amp(codec, conn[i], HDA_OUTPUT, 0, ++ 0xff, HDA_AMP_MUTE); + } + } + diff --git a/queue-3.14/alsa-hda-fix-built-in-mic-on-compaq-presario-cq60.patch b/queue-3.14/alsa-hda-fix-built-in-mic-on-compaq-presario-cq60.patch new file mode 100644 index 00000000000..ec05c97c223 --- /dev/null +++ b/queue-3.14/alsa-hda-fix-built-in-mic-on-compaq-presario-cq60.patch @@ -0,0 +1,55 @@ +From ddb6ca75b5671b8fbf1909bc588c449ee74b34f9 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 11 Mar 2015 16:05:19 +0100 +Subject: ALSA: hda - Fix built-in mic on Compaq Presario CQ60 + +From: Takashi Iwai + +commit ddb6ca75b5671b8fbf1909bc588c449ee74b34f9 upstream. + +Compaq Presario CQ60 laptop with CX20561 gives a wrong pin for the +built-in mic NID 0x17 instead of NID 0x1d, and it results in the +non-working mic. This patch just remaps the pin correctly via fixup. + +Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=920604 +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/pci/hda/patch_conexant.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -3232,6 +3232,7 @@ enum { + CXT_PINCFG_LENOVO_TP410, + CXT_PINCFG_LEMOTE_A1004, + CXT_PINCFG_LEMOTE_A1205, ++ CXT_PINCFG_COMPAQ_CQ60, + CXT_FIXUP_STEREO_DMIC, + CXT_FIXUP_INC_MIC_BOOST, + CXT_FIXUP_HEADPHONE_MIC_PIN, +@@ -3368,6 +3369,15 @@ static const struct hda_fixup cxt_fixups + .type = HDA_FIXUP_PINS, + .v.pins = cxt_pincfg_lemote, + }, ++ [CXT_PINCFG_COMPAQ_CQ60] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ /* 0x17 was falsely set up as a mic, it should 0x1d */ ++ { 0x17, 0x400001f0 }, ++ { 0x1d, 0x97a70120 }, ++ { } ++ } ++ }, + [CXT_FIXUP_STEREO_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_stereo_dmic, +@@ -3411,6 +3421,7 @@ static const struct hda_fixup cxt_fixups + }; + + static const struct snd_pci_quirk cxt5051_fixups[] = { ++ SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60), + SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200), + {} + }; diff --git a/queue-3.14/alsa-hda-fix-regression-of-hd-audio-controller-fallback-modes.patch b/queue-3.14/alsa-hda-fix-regression-of-hd-audio-controller-fallback-modes.patch new file mode 100644 index 00000000000..728ade38440 --- /dev/null +++ b/queue-3.14/alsa-hda-fix-regression-of-hd-audio-controller-fallback-modes.patch @@ -0,0 +1,51 @@ +From a1f3f1ca66bd12c339b17a0c2ef93a093f90a277 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Sun, 8 Mar 2015 18:29:50 +0100 +Subject: ALSA: hda - Fix regression of HD-audio controller fallback modes + +From: Takashi Iwai + +commit a1f3f1ca66bd12c339b17a0c2ef93a093f90a277 upstream. + +The commit [63e51fd708f5: ALSA: hda - Don't take unresponsive D3 +transition too serious] introduced a conditional fallback behavior to +the HD-audio controller depending on the flag set. However, it +introduced a silly bug, too, that the flag was evaluated in a reverse +way. This resulted in a regression of HD-audio controller driver +where it can't go to the fallback mode at communication errors. + +Unfortunately (or fortunately?) this didn't come up until recently +because the affected code path is an error handling that happens only +on an unstable hardware chip. Most of recent chips work stably, thus +they didn't hit this problem. Now, we've got a regression report with +a VIA chip, and this seems indeed requiring the fallback to the +polling mode, and finally the bug was revealed. + +The fix is a oneliner to remove the wrong logical NOT in the check. +(Lesson learned - be careful about double negation.) + +The bug should be backported to stable, but the patch won't be +applicable to 3.13 or earlier because of the code splits. The stable +fix patches for earlier kernels will be posted later manually. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94021 +Fixes: 63e51fd708f5 ('ALSA: hda - Don't take unresponsive D3 transition too serious') +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + + +--- + sound/pci/hda/hda_intel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -959,7 +959,7 @@ static unsigned int azx_rirb_get_respons + } + } + +- if (!bus->no_response_fallback) ++ if (bus->no_response_fallback) + return -1; + + if (!chip->polling_mode && chip->poll_count < 2) { diff --git a/queue-3.14/alsa-hda-set-single_adc_amp-flag-for-cs420x-codecs.patch b/queue-3.14/alsa-hda-set-single_adc_amp-flag-for-cs420x-codecs.patch new file mode 100644 index 00000000000..1149d60948c --- /dev/null +++ b/queue-3.14/alsa-hda-set-single_adc_amp-flag-for-cs420x-codecs.patch @@ -0,0 +1,34 @@ +From bad994f5b4ab57eec8d56c180edca00505c3eeb2 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 12 Mar 2015 20:28:04 +0100 +Subject: ALSA: hda - Set single_adc_amp flag for CS420x codecs + +From: Takashi Iwai + +commit bad994f5b4ab57eec8d56c180edca00505c3eeb2 upstream. + +CS420x codecs seem to deal only the single amps of ADC nodes even +though the nodes receive multiple inputs. This leads to the +inconsistent amp value after S3/S4 resume, for example. + +The fix is just to set codec->single_adc_amp flag. Then the driver +handles these ADC amps as if single connections. + +Reported-and-tested-by: Vasil Zlatanov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/pci/hda/patch_cirrus.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/pci/hda/patch_cirrus.c ++++ b/sound/pci/hda/patch_cirrus.c +@@ -587,6 +587,7 @@ static int patch_cs420x(struct hda_codec + return -ENOMEM; + + spec->gen.automute_hook = cs_automute; ++ codec->single_adc_amp = 1; + + snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, + cs420x_fixups); diff --git a/queue-3.14/alsa-hda-treat-stereo-to-mono-mix-properly.patch b/queue-3.14/alsa-hda-treat-stereo-to-mono-mix-properly.patch new file mode 100644 index 00000000000..b91beb9cde3 --- /dev/null +++ b/queue-3.14/alsa-hda-treat-stereo-to-mono-mix-properly.patch @@ -0,0 +1,143 @@ +From cc261738add93947d138d2fabad9f4dbed4e5c00 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 16 Mar 2015 10:18:08 +0100 +Subject: ALSA: hda - Treat stereo-to-mono mix properly + +From: Takashi Iwai + +commit cc261738add93947d138d2fabad9f4dbed4e5c00 upstream. + +The commit [ef403edb7558: ALSA: hda - Don't access stereo amps for +mono channel widgets] fixed the handling of mono widgets in general, +but it still misses an exceptional case: namely, a mono mixer widget +taking a single stereo input. In this case, it has stereo volumes +although it's a mono widget, and thus we have to take care of both +left and right input channels, as stated in HD-audio spec ("7.1.3 +Widget Interconnection Rules"). + +This patch covers this missing piece by adding proper checks of stereo +amps in both the generic parser and the proc output codes. + +Reported-by: Raymond Yau +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/pci/hda/hda_generic.c | 21 +++++++++++++++++++-- + sound/pci/hda/hda_proc.c | 38 ++++++++++++++++++++++++++++++-------- + 2 files changed, 49 insertions(+), 10 deletions(-) + +--- a/sound/pci/hda/hda_generic.c ++++ b/sound/pci/hda/hda_generic.c +@@ -653,13 +653,30 @@ static int get_amp_val_to_activate(struc + return val; + } + ++/* is this a stereo widget or a stereo-to-mono mix? */ ++static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir) ++{ ++ unsigned int wcaps = get_wcaps(codec, nid); ++ hda_nid_t conn; ++ ++ if (wcaps & AC_WCAP_STEREO) ++ return true; ++ if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX) ++ return false; ++ if (snd_hda_get_num_conns(codec, nid) != 1) ++ return false; ++ if (snd_hda_get_connections(codec, nid, &conn, 1) < 0) ++ return false; ++ return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO); ++} ++ + /* initialize the amp value (only at the first time) */ + static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) + { + unsigned int caps = query_amp_caps(codec, nid, dir); + int val = get_amp_val_to_activate(codec, nid, dir, caps, false); + +- if (get_wcaps(codec, nid) & AC_WCAP_STEREO) ++ if (is_stereo_amps(codec, nid, dir)) + snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); + else + snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val); +@@ -669,7 +686,7 @@ static void init_amp(struct hda_codec *c + static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, + unsigned int mask, unsigned int val) + { +- if (get_wcaps(codec, nid) & AC_WCAP_STEREO) ++ if (is_stereo_amps(codec, nid, dir)) + return snd_hda_codec_amp_stereo(codec, nid, dir, idx, + mask, val); + else +--- a/sound/pci/hda/hda_proc.c ++++ b/sound/pci/hda/hda_proc.c +@@ -134,13 +134,38 @@ static void print_amp_caps(struct snd_in + (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT); + } + ++/* is this a stereo widget or a stereo-to-mono mix? */ ++static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, ++ int dir, unsigned int wcaps, int indices) ++{ ++ hda_nid_t conn; ++ ++ if (wcaps & AC_WCAP_STEREO) ++ return true; ++ /* check for a stereo-to-mono mix; it must be: ++ * only a single connection, only for input, and only a mixer widget ++ */ ++ if (indices != 1 || dir != HDA_INPUT || ++ get_wcaps_type(wcaps) != AC_WID_AUD_MIX) ++ return false; ++ ++ if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0) ++ return false; ++ /* the connection source is a stereo? */ ++ wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP); ++ return !!(wcaps & AC_WCAP_STEREO); ++} ++ + static void print_amp_vals(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid, +- int dir, int stereo, int indices) ++ int dir, unsigned int wcaps, int indices) + { + unsigned int val; ++ bool stereo; + int i; + ++ stereo = is_stereo_amps(codec, nid, dir, wcaps, indices); ++ + dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; + for (i = 0; i < indices; i++) { + snd_iprintf(buffer, " ["); +@@ -757,12 +782,10 @@ static void print_codec_info(struct snd_ + (codec->single_adc_amp && + wid_type == AC_WID_AUD_IN)) + print_amp_vals(buffer, codec, nid, HDA_INPUT, +- wid_caps & AC_WCAP_STEREO, +- 1); ++ wid_caps, 1); + else + print_amp_vals(buffer, codec, nid, HDA_INPUT, +- wid_caps & AC_WCAP_STEREO, +- conn_len); ++ wid_caps, conn_len); + } + if (wid_caps & AC_WCAP_OUT_AMP) { + snd_iprintf(buffer, " Amp-Out caps: "); +@@ -771,11 +794,10 @@ static void print_codec_info(struct snd_ + if (wid_type == AC_WID_PIN && + codec->pin_amp_workaround) + print_amp_vals(buffer, codec, nid, HDA_OUTPUT, +- wid_caps & AC_WCAP_STEREO, +- conn_len); ++ wid_caps, conn_len); + else + print_amp_vals(buffer, codec, nid, HDA_OUTPUT, +- wid_caps & AC_WCAP_STEREO, 1); ++ wid_caps, 1); + } + + switch (wid_type) { diff --git a/queue-3.14/alsa-snd-usb-add-quirks-for-roland-ua-22.patch b/queue-3.14/alsa-snd-usb-add-quirks-for-roland-ua-22.patch new file mode 100644 index 00000000000..af8d7d47ae3 --- /dev/null +++ b/queue-3.14/alsa-snd-usb-add-quirks-for-roland-ua-22.patch @@ -0,0 +1,66 @@ +From fcdcd1dec6d2c7b718385ec743ae5a9a233edad4 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Thu, 12 Mar 2015 09:41:32 +0100 +Subject: ALSA: snd-usb: add quirks for Roland UA-22 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Mack + +commit fcdcd1dec6d2c7b718385ec743ae5a9a233edad4 upstream. + +The device complies to the UAC1 standard but hides that fact with +proprietary descriptors. The autodetect quirk for Roland devices +catches the audio interface but misses the MIDI part, so a specific +quirk is needed. + +Signed-off-by: Daniel Mack +Reported-by: Rafa Lafuente +Tested-by: Raphaël Doursenaud +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/quirks-table.h | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -1773,6 +1773,36 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, ++{ ++ USB_DEVICE(0x0582, 0x0159), ++ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ /* .vendor_name = "Roland", */ ++ /* .product_name = "UA-22", */ ++ .ifnum = QUIRK_ANY_INTERFACE, ++ .type = QUIRK_COMPOSITE, ++ .data = (const struct snd_usb_audio_quirk[]) { ++ { ++ .ifnum = 0, ++ .type = QUIRK_AUDIO_STANDARD_INTERFACE ++ }, ++ { ++ .ifnum = 1, ++ .type = QUIRK_AUDIO_STANDARD_INTERFACE ++ }, ++ { ++ .ifnum = 2, ++ .type = QUIRK_MIDI_FIXED_ENDPOINT, ++ .data = & (const struct snd_usb_midi_endpoint_info) { ++ .out_cables = 0x0001, ++ .in_cables = 0x0001 ++ } ++ }, ++ { ++ .ifnum = -1 ++ } ++ } ++ } ++}, + /* this catches most recent vendor-specific Roland devices */ + { + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | diff --git a/queue-3.14/bnx2x-force-fundamental-reset-for-eeh-recovery.patch b/queue-3.14/bnx2x-force-fundamental-reset-for-eeh-recovery.patch new file mode 100644 index 00000000000..742ba37811a --- /dev/null +++ b/queue-3.14/bnx2x-force-fundamental-reset-for-eeh-recovery.patch @@ -0,0 +1,34 @@ +From da293700568ed3d96fcf062ac15d7d7c41377f11 Mon Sep 17 00:00:00 2001 +From: Brian King +Date: Wed, 4 Mar 2015 08:09:44 -0600 +Subject: bnx2x: Force fundamental reset for EEH recovery + +From: Brian King + +commit da293700568ed3d96fcf062ac15d7d7c41377f11 upstream. + +EEH recovery for bnx2x based adapters is not reliable on all Power +systems using the default hot reset, which can result in an +unrecoverable EEH error. Forcing the use of fundamental reset +during EEH recovery fixes this. + +Signed-off-by: Brian King +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c ++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +@@ -12395,6 +12395,9 @@ static int bnx2x_init_dev(struct bnx2x * + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); + ++ /* Set PCIe reset type to fundamental for EEH recovery */ ++ pdev->needs_freset = 1; ++ + /* AER (Advanced Error reporting) configuration */ + rc = pci_enable_pcie_error_reporting(pdev); + if (!rc) diff --git a/queue-3.14/can-add-missing-initialisations-in-can-related-skbuffs.patch b/queue-3.14/can-add-missing-initialisations-in-can-related-skbuffs.patch new file mode 100644 index 00000000000..5a9b7a7d319 --- /dev/null +++ b/queue-3.14/can-add-missing-initialisations-in-can-related-skbuffs.patch @@ -0,0 +1,55 @@ +From 969439016d2cf61fef53a973d7e6d2061c3793b1 Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Mon, 23 Feb 2015 20:37:54 +0100 +Subject: can: add missing initialisations in CAN related skbuffs + +From: Oliver Hartkopp + +commit 969439016d2cf61fef53a973d7e6d2061c3793b1 upstream. + +When accessing CAN network interfaces with AF_PACKET sockets e.g. by dhclient +this can lead to a skb_under_panic due to missing skb initialisations. + +Add the missing initialisations at the CAN skbuff creation times on driver +level (rx path) and in the network layer (tx path). + +Reported-by: Austin Schuh +Reported-by: Daniel Steer +Signed-off-by: Oliver Hartkopp +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/can/dev.c | 8 ++++++++ + net/can/af_can.c | 3 +++ + 2 files changed, 11 insertions(+) + +--- a/drivers/net/can/dev.c ++++ b/drivers/net/can/dev.c +@@ -502,6 +502,14 @@ struct sk_buff *alloc_can_skb(struct net + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ skb_reset_transport_header(skb); ++ ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ skb_reset_transport_header(skb); ++ + can_skb_reserve(skb); + can_skb_prv(skb)->ifindex = dev->ifindex; + +--- a/net/can/af_can.c ++++ b/net/can/af_can.c +@@ -262,6 +262,9 @@ int can_send(struct sk_buff *skb, int lo + goto inval_skb; + } + ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ ++ skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + diff --git a/queue-3.14/cpuset-fix-cpuset-sched_relax_domain_level.patch b/queue-3.14/cpuset-fix-cpuset-sched_relax_domain_level.patch new file mode 100644 index 00000000000..b81f8201856 --- /dev/null +++ b/queue-3.14/cpuset-fix-cpuset-sched_relax_domain_level.patch @@ -0,0 +1,44 @@ +From 283cb41f426b723a0255702b761b0fc5d1b53a81 Mon Sep 17 00:00:00 2001 +From: Jason Low +Date: Fri, 13 Feb 2015 11:58:07 +0800 +Subject: cpuset: Fix cpuset sched_relax_domain_level + +From: Jason Low + +commit 283cb41f426b723a0255702b761b0fc5d1b53a81 upstream. + +The cpuset.sched_relax_domain_level can control how far we do +immediate load balancing on a system. However, it was found on recent +kernels that echo'ing a value into cpuset.sched_relax_domain_level +did not reduce any immediate load balancing. + +The reason this occurred was because the update_domain_attr_tree() traversal +did not update for the "top_cpuset". This resulted in nothing being changed +when modifying the sched_relax_domain_level parameter. + +This patch is able to address that problem by having update_domain_attr_tree() +allow updates for the root in the cpuset traversal. + +Fixes: fc560a26acce ("cpuset: replace cpuset->stack_list with cpuset_for_each_descendant_pre()") +Signed-off-by: Jason Low +Signed-off-by: Zefan Li +Signed-off-by: Tejun Heo +Tested-by: Serge Hallyn +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/cpuset.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/kernel/cpuset.c ++++ b/kernel/cpuset.c +@@ -503,9 +503,6 @@ static void update_domain_attr_tree(stru + + rcu_read_lock(); + cpuset_for_each_descendant_pre(cp, pos_css, root_cs) { +- if (cp == root_cs) +- continue; +- + /* skip the whole subtree if @cp doesn't have any CPU */ + if (cpumask_empty(cp->cpus_allowed)) { + pos_css = css_rightmost_descendant(pos_css); diff --git a/queue-3.14/drm-vmwgfx-reorder-device-takedown-somewhat.patch b/queue-3.14/drm-vmwgfx-reorder-device-takedown-somewhat.patch new file mode 100644 index 00000000000..f66b304a5a0 --- /dev/null +++ b/queue-3.14/drm-vmwgfx-reorder-device-takedown-somewhat.patch @@ -0,0 +1,143 @@ +From 3458390b9f0ba784481d23134798faee27b5f16f Mon Sep 17 00:00:00 2001 +From: Thomas Hellstrom +Date: Thu, 5 Mar 2015 02:33:24 -0800 +Subject: drm/vmwgfx: Reorder device takedown somewhat + +From: Thomas Hellstrom + +commit 3458390b9f0ba784481d23134798faee27b5f16f upstream. + +To take down the MOB and GMR memory types, the driver may have to issue +fence objects and thus make sure that the fence manager is taken down +after those memory types. +Reorder device init accordingly. + +Signed-off-by: Thomas Hellstrom +Reviewed-by: Sinclair Yeh +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 77 ++++++++++++++++++------------------ + 1 file changed, 40 insertions(+), 37 deletions(-) + +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +@@ -733,32 +733,6 @@ static int vmw_driver_load(struct drm_de + goto out_err1; + } + +- ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM, +- (dev_priv->vram_size >> PAGE_SHIFT)); +- if (unlikely(ret != 0)) { +- DRM_ERROR("Failed initializing memory manager for VRAM.\n"); +- goto out_err2; +- } +- +- dev_priv->has_gmr = true; +- if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || +- refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, +- VMW_PL_GMR) != 0) { +- DRM_INFO("No GMR memory available. " +- "Graphics memory resources are very limited.\n"); +- dev_priv->has_gmr = false; +- } +- +- if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { +- dev_priv->has_mob = true; +- if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB, +- VMW_PL_MOB) != 0) { +- DRM_INFO("No MOB memory available. " +- "3D will be disabled.\n"); +- dev_priv->has_mob = false; +- } +- } +- + dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start, + dev_priv->mmio_size); + +@@ -821,6 +795,33 @@ static int vmw_driver_load(struct drm_de + goto out_no_fman; + } + ++ ++ ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM, ++ (dev_priv->vram_size >> PAGE_SHIFT)); ++ if (unlikely(ret != 0)) { ++ DRM_ERROR("Failed initializing memory manager for VRAM.\n"); ++ goto out_no_vram; ++ } ++ ++ dev_priv->has_gmr = true; ++ if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || ++ refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, ++ VMW_PL_GMR) != 0) { ++ DRM_INFO("No GMR memory available. " ++ "Graphics memory resources are very limited.\n"); ++ dev_priv->has_gmr = false; ++ } ++ ++ if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { ++ dev_priv->has_mob = true; ++ if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB, ++ VMW_PL_MOB) != 0) { ++ DRM_INFO("No MOB memory available. " ++ "3D will be disabled.\n"); ++ dev_priv->has_mob = false; ++ } ++ } ++ + vmw_kms_save_vga(dev_priv); + + /* Start kms and overlay systems, needs fifo. */ +@@ -846,6 +847,12 @@ out_no_fifo: + vmw_kms_close(dev_priv); + out_no_kms: + vmw_kms_restore_vga(dev_priv); ++ if (dev_priv->has_mob) ++ (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); ++ if (dev_priv->has_gmr) ++ (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); ++ (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); ++out_no_vram: + vmw_fence_manager_takedown(dev_priv->fman); + out_no_fman: + if (dev_priv->capabilities & SVGA_CAP_IRQMASK) +@@ -861,12 +868,6 @@ out_err4: + iounmap(dev_priv->mmio_virt); + out_err3: + arch_phys_wc_del(dev_priv->mmio_mtrr); +- if (dev_priv->has_mob) +- (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); +- if (dev_priv->has_gmr) +- (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); +- (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); +-out_err2: + (void)ttm_bo_device_release(&dev_priv->bdev); + out_err1: + vmw_ttm_global_release(dev_priv); +@@ -896,6 +897,13 @@ static int vmw_driver_unload(struct drm_ + } + vmw_kms_close(dev_priv); + vmw_overlay_close(dev_priv); ++ ++ if (dev_priv->has_mob) ++ (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); ++ if (dev_priv->has_gmr) ++ (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); ++ (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); ++ + vmw_fence_manager_takedown(dev_priv->fman); + if (dev_priv->capabilities & SVGA_CAP_IRQMASK) + drm_irq_uninstall(dev_priv->dev); +@@ -907,11 +915,6 @@ static int vmw_driver_unload(struct drm_ + ttm_object_device_release(&dev_priv->tdev); + iounmap(dev_priv->mmio_virt); + arch_phys_wc_del(dev_priv->mmio_mtrr); +- if (dev_priv->has_mob) +- (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); +- if (dev_priv->has_gmr) +- (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); +- (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); + (void)ttm_bo_device_release(&dev_priv->bdev); + vmw_ttm_global_release(dev_priv); + diff --git a/queue-3.14/mtd-nand-pxa3xx-fix-pio-fifo-draining.patch b/queue-3.14/mtd-nand-pxa3xx-fix-pio-fifo-draining.patch new file mode 100644 index 00000000000..2fcc72d66f7 --- /dev/null +++ b/queue-3.14/mtd-nand-pxa3xx-fix-pio-fifo-draining.patch @@ -0,0 +1,96 @@ +From 8dad0386b97c4bd6edd56752ca7f2e735fe5beb4 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 18 Feb 2015 11:32:07 +0100 +Subject: mtd: nand: pxa3xx: Fix PIO FIFO draining + +From: Maxime Ripard + +commit 8dad0386b97c4bd6edd56752ca7f2e735fe5beb4 upstream. + +The NDDB register holds the data that are needed by the read and write +commands. + +However, during a read PIO access, the datasheet specifies that after each 32 +bytes read in that register, when BCH is enabled, we have to make sure that the +RDDREQ bit is set in the NDSR register. + +This fixes an issue that was seen on the Armada 385, and presumably other mvebu +SoCs, when a read on a newly erased page would end up in the driver reporting a +timeout from the NAND. + +Signed-off-by: Maxime Ripard +Reviewed-by: Boris Brezillon +Acked-by: Ezequiel Garcia +Signed-off-by: Brian Norris +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mtd/nand/pxa3xx_nand.c | 48 +++++++++++++++++++++++++++++++++++------ + 1 file changed, 42 insertions(+), 6 deletions(-) + +--- a/drivers/mtd/nand/pxa3xx_nand.c ++++ b/drivers/mtd/nand/pxa3xx_nand.c +@@ -481,6 +481,42 @@ static void disable_int(struct pxa3xx_na + nand_writel(info, NDCR, ndcr | int_mask); + } + ++static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) ++{ ++ if (info->ecc_bch) { ++ int timeout; ++ ++ /* ++ * According to the datasheet, when reading from NDDB ++ * with BCH enabled, after each 32 bytes reads, we ++ * have to make sure that the NDSR.RDDREQ bit is set. ++ * ++ * Drain the FIFO 8 32 bits reads at a time, and skip ++ * the polling on the last read. ++ */ ++ while (len > 8) { ++ __raw_readsl(info->mmio_base + NDDB, data, 8); ++ ++ for (timeout = 0; ++ !(nand_readl(info, NDSR) & NDSR_RDDREQ); ++ timeout++) { ++ if (timeout >= 5) { ++ dev_err(&info->pdev->dev, ++ "Timeout on RDDREQ while draining the FIFO\n"); ++ return; ++ } ++ ++ mdelay(1); ++ } ++ ++ data += 32; ++ len -= 8; ++ } ++ } ++ ++ __raw_readsl(info->mmio_base + NDDB, data, len); ++} ++ + static void handle_data_pio(struct pxa3xx_nand_info *info) + { + unsigned int do_bytes = min(info->data_size, info->chunk_size); +@@ -497,14 +533,14 @@ static void handle_data_pio(struct pxa3x + DIV_ROUND_UP(info->oob_size, 4)); + break; + case STATE_PIO_READING: +- __raw_readsl(info->mmio_base + NDDB, +- info->data_buff + info->data_buff_pos, +- DIV_ROUND_UP(do_bytes, 4)); ++ drain_fifo(info, ++ info->data_buff + info->data_buff_pos, ++ DIV_ROUND_UP(do_bytes, 4)); + + if (info->oob_size > 0) +- __raw_readsl(info->mmio_base + NDDB, +- info->oob_buff + info->oob_buff_pos, +- DIV_ROUND_UP(info->oob_size, 4)); ++ drain_fifo(info, ++ info->oob_buff + info->oob_buff_pos, ++ DIV_ROUND_UP(info->oob_size, 4)); + break; + default: + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, diff --git a/queue-3.14/nilfs2-fix-deadlock-of-segment-constructor-during-recovery.patch b/queue-3.14/nilfs2-fix-deadlock-of-segment-constructor-during-recovery.patch new file mode 100644 index 00000000000..96daa549770 --- /dev/null +++ b/queue-3.14/nilfs2-fix-deadlock-of-segment-constructor-during-recovery.patch @@ -0,0 +1,93 @@ +From 283ee1482f349d6c0c09dfb725db5880afc56813 Mon Sep 17 00:00:00 2001 +From: Ryusuke Konishi +Date: Thu, 12 Mar 2015 16:26:00 -0700 +Subject: nilfs2: fix deadlock of segment constructor during recovery + +From: Ryusuke Konishi + +commit 283ee1482f349d6c0c09dfb725db5880afc56813 upstream. + +According to a report from Yuxuan Shui, nilfs2 in kernel 3.19 got stuck +during recovery at mount time. The code path that caused the deadlock was +as follows: + + nilfs_fill_super() + load_nilfs() + nilfs_salvage_orphan_logs() + * Do roll-forwarding, attach segment constructor for recovery, + and kick it. + + nilfs_segctor_thread() + nilfs_segctor_thread_construct() + * A lock is held with nilfs_transaction_lock() + nilfs_segctor_do_construct() + nilfs_segctor_drop_written_files() + iput() + iput_final() + write_inode_now() + writeback_single_inode() + __writeback_single_inode() + do_writepages() + nilfs_writepage() + nilfs_construct_dsync_segment() + nilfs_transaction_lock() --> deadlock + +This can happen if commit 7ef3ff2fea8b ("nilfs2: fix deadlock of segment +constructor over I_SYNC flag") is applied and roll-forward recovery was +performed at mount time. The roll-forward recovery can happen if datasync +write is done and the file system crashes immediately after that. For +instance, we can reproduce the issue with the following steps: + + < nilfs2 is mounted on /nilfs (device: /dev/sdb1) > + # dd if=/dev/zero of=/nilfs/test bs=4k count=1 && sync + # dd if=/dev/zero of=/nilfs/test conv=notrunc oflag=dsync bs=4k + count=1 && reboot -nfh + < the system will immediately reboot > + # mount -t nilfs2 /dev/sdb1 /nilfs + +The deadlock occurs because iput() can run segment constructor through +writeback_single_inode() if MS_ACTIVE flag is not set on sb->s_flags. The +above commit changed segment constructor so that it calls iput() +asynchronously for inodes with i_nlink == 0, but that change was +imperfect. + +This fixes the another deadlock by deferring iput() in segment constructor +even for the case that mount is not finished, that is, for the case that +MS_ACTIVE flag is not set. + +Signed-off-by: Ryusuke Konishi +Reported-by: Yuxuan Shui +Tested-by: Ryusuke Konishi +Cc: Al Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nilfs2/segment.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/fs/nilfs2/segment.c ++++ b/fs/nilfs2/segment.c +@@ -1906,6 +1906,7 @@ static void nilfs_segctor_drop_written_f + struct the_nilfs *nilfs) + { + struct nilfs_inode_info *ii, *n; ++ int during_mount = !(sci->sc_super->s_flags & MS_ACTIVE); + int defer_iput = false; + + spin_lock(&nilfs->ns_inode_lock); +@@ -1918,10 +1919,10 @@ static void nilfs_segctor_drop_written_f + brelse(ii->i_bh); + ii->i_bh = NULL; + list_del_init(&ii->i_dirty); +- if (!ii->vfs_inode.i_nlink) { ++ if (!ii->vfs_inode.i_nlink || during_mount) { + /* +- * Defer calling iput() to avoid a deadlock +- * over I_SYNC flag for inodes with i_nlink == 0 ++ * Defer calling iput() to avoid deadlocks if ++ * i_nlink == 0 or mount is not yet finished. + */ + list_add_tail(&ii->i_dirty, &sci->sc_iput_queue); + defer_iput = true; diff --git a/queue-3.14/regulator-core-fix-enable-gpio-reference-counting.patch b/queue-3.14/regulator-core-fix-enable-gpio-reference-counting.patch new file mode 100644 index 00000000000..0ef2c198d8b --- /dev/null +++ b/queue-3.14/regulator-core-fix-enable-gpio-reference-counting.patch @@ -0,0 +1,108 @@ +From 29d62ec5f87fbeec8413e2215ddad12e7f972e4c Mon Sep 17 00:00:00 2001 +From: Doug Anderson +Date: Tue, 3 Mar 2015 15:20:47 -0800 +Subject: regulator: core: Fix enable GPIO reference counting + +From: Doug Anderson + +commit 29d62ec5f87fbeec8413e2215ddad12e7f972e4c upstream. + +Normally _regulator_do_enable() isn't called on an already-enabled +rdev. That's because the main caller, _regulator_enable() always +calls _regulator_is_enabled() and only calls _regulator_do_enable() if +the rdev was not already enabled. + +However, there is one caller of _regulator_do_enable() that doesn't +check: regulator_suspend_finish(). While we might want to make +regulator_suspend_finish() behave more like _regulator_enable(), it's +probably also a good idea to make _regulator_do_enable() robust if it +is called on an already enabled rdev. + +At the moment, _regulator_do_enable() is _not_ robust for already +enabled rdevs if we're using an ena_pin. Each time +_regulator_do_enable() is called for an rdev using an ena_pin the +reference count of the ena_pin is incremented even if the rdev was +already enabled. This is not as intended because the ena_pin is for +something else: for keeping track of how many active rdevs there are +sharing the same ena_pin. + +Here's how the reference counting works here: + +* Each time _regulator_enable() is called we increment + rdev->use_count, so _regulator_enable() calls need to be balanced + with _regulator_disable() calls. + +* There is no explicit reference counting in _regulator_do_enable() + which is normally just a warapper around rdev->desc->ops->enable() + with code for supporting delays. It's not expected that the + "ops->enable()" call do reference counting. + +* Since regulator_ena_gpio_ctrl() does have reference counting + (handling the sharing of the pin amongst multiple rdevs), we + shouldn't call it if the current rdev is already enabled. + +Note that as part of this we cleanup (remove) the initting of +ena_gpio_state in regulator_register(). In _regulator_do_enable(), +_regulator_do_disable() and _regulator_is_enabled() is is clear that +ena_gpio_state should be the state of whether this particular rdev has +requested the GPIO be enabled. regulator_register() was initting it +as the actual state of the pin. + +Fixes: 967cfb18c0e3 ("regulator: core: manage enable GPIO list") +Signed-off-by: Doug Anderson +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/regulator/core.c | 26 ++++++++++++-------------- + 1 file changed, 12 insertions(+), 14 deletions(-) + +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1764,10 +1764,12 @@ static int _regulator_do_enable(struct r + trace_regulator_enable(rdev_get_name(rdev)); + + if (rdev->ena_pin) { +- ret = regulator_ena_gpio_ctrl(rdev, true); +- if (ret < 0) +- return ret; +- rdev->ena_gpio_state = 1; ++ if (!rdev->ena_gpio_state) { ++ ret = regulator_ena_gpio_ctrl(rdev, true); ++ if (ret < 0) ++ return ret; ++ rdev->ena_gpio_state = 1; ++ } + } else if (rdev->desc->ops->enable) { + ret = rdev->desc->ops->enable(rdev); + if (ret < 0) +@@ -1897,10 +1899,12 @@ static int _regulator_do_disable(struct + trace_regulator_disable(rdev_get_name(rdev)); + + if (rdev->ena_pin) { +- ret = regulator_ena_gpio_ctrl(rdev, false); +- if (ret < 0) +- return ret; +- rdev->ena_gpio_state = 0; ++ if (rdev->ena_gpio_state) { ++ ret = regulator_ena_gpio_ctrl(rdev, false); ++ if (ret < 0) ++ return ret; ++ rdev->ena_gpio_state = 0; ++ } + + } else if (rdev->desc->ops->disable) { + ret = rdev->desc->ops->disable(rdev); +@@ -3454,12 +3458,6 @@ regulator_register(const struct regulato + config->ena_gpio, ret); + goto wash; + } +- +- if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH) +- rdev->ena_gpio_state = 1; +- +- if (config->ena_gpio_invert) +- rdev->ena_gpio_state = !rdev->ena_gpio_state; + } + + /* set regulator constraints */ diff --git a/queue-3.14/regulator-only-enable-disabled-regulators-on-resume.patch b/queue-3.14/regulator-only-enable-disabled-regulators-on-resume.patch new file mode 100644 index 00000000000..833640787c3 --- /dev/null +++ b/queue-3.14/regulator-only-enable-disabled-regulators-on-resume.patch @@ -0,0 +1,48 @@ +From 0548bf4f5ad6fc3bd93c4940fa48078b34609682 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 2 Mar 2015 21:40:39 +0100 +Subject: regulator: Only enable disabled regulators on resume + +From: Javier Martinez Canillas + +commit 0548bf4f5ad6fc3bd93c4940fa48078b34609682 upstream. + +The _regulator_do_enable() call ought to be a no-op when called on an +already-enabled regulator. However, as an optimization +_regulator_enable() doesn't call _regulator_do_enable() on an already +enabled regulator. That means we never test the case of calling +_regulator_do_enable() during normal usage and there may be hidden +bugs or warnings. We have seen warnings issued by the tps65090 driver +and bugs when using the GPIO enable pin. + +Let's match the same optimization that _regulator_enable() in +regulator_suspend_finish(). That may speed up suspend/resume and also +avoids exposing hidden bugs. + +[Use much clearer commit message from Doug Anderson] + +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/regulator/core.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -3631,9 +3631,11 @@ int regulator_suspend_finish(void) + list_for_each_entry(rdev, ®ulator_list, list) { + mutex_lock(&rdev->mutex); + if (rdev->use_count > 0 || rdev->constraints->always_on) { +- error = _regulator_do_enable(rdev); +- if (error) +- ret = error; ++ if (!_regulator_is_enabled(rdev)) { ++ error = _regulator_do_enable(rdev); ++ if (error) ++ ret = error; ++ } + } else { + if (!have_full_constraints()) + goto unlock; diff --git a/queue-3.14/series b/queue-3.14/series index 16c22c5d803..44779129724 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -31,3 +31,23 @@ console-fix-console-name-size-mismatch.patch virtio_console-init-work-unconditionally.patch virtio_console-avoid-config-access-from-irq.patch change-email-address-for-8250_pci.patch +can-add-missing-initialisations-in-can-related-skbuffs.patch +workqueue-fix-hang-involving-racing-cancel_work_sync-s-for-preempt_none.patch +cpuset-fix-cpuset-sched_relax_domain_level.patch +tpm-ibmvtpm-additional-le-support-for-tpm_ibmvtpm_send.patch +spi-atmel-fix-interrupt-setup-for-pdc-transfers.patch +spi-pl022-fix-race-in-giveback-leading-to-driver-lock-up.patch +alsa-snd-usb-add-quirks-for-roland-ua-22.patch +alsa-control-add-sanity-checks-for-user-ctl-id-name-string.patch +alsa-hda-fix-built-in-mic-on-compaq-presario-cq60.patch +alsa-hda-don-t-access-stereo-amps-for-mono-channel-widgets.patch +alsa-hda-set-single_adc_amp-flag-for-cs420x-codecs.patch +alsa-hda-add-workaround-for-macbook-air-5-2-built-in-mic.patch +alsa-hda-fix-regression-of-hd-audio-controller-fallback-modes.patch +alsa-hda-treat-stereo-to-mono-mix-properly.patch +mtd-nand-pxa3xx-fix-pio-fifo-draining.patch +bnx2x-force-fundamental-reset-for-eeh-recovery.patch +regulator-only-enable-disabled-regulators-on-resume.patch +regulator-core-fix-enable-gpio-reference-counting.patch +nilfs2-fix-deadlock-of-segment-constructor-during-recovery.patch +drm-vmwgfx-reorder-device-takedown-somewhat.patch diff --git a/queue-3.14/spi-atmel-fix-interrupt-setup-for-pdc-transfers.patch b/queue-3.14/spi-atmel-fix-interrupt-setup-for-pdc-transfers.patch new file mode 100644 index 00000000000..e66581f2704 --- /dev/null +++ b/queue-3.14/spi-atmel-fix-interrupt-setup-for-pdc-transfers.patch @@ -0,0 +1,58 @@ +From 76e1d14b316d6f501ebc001e7a5d86b24ce5b615 Mon Sep 17 00:00:00 2001 +From: Torsten Fleischer +Date: Tue, 24 Feb 2015 16:32:57 +0100 +Subject: spi: atmel: Fix interrupt setup for PDC transfers + +From: Torsten Fleischer + +commit 76e1d14b316d6f501ebc001e7a5d86b24ce5b615 upstream. + +Additionally to the current DMA transfer the PDC allows to set up a next DMA +transfer. This is useful for larger SPI transfers. + +The driver currently waits for ENDRX as end of the transfer. But ENDRX is set +when the current DMA transfer is done (RCR = 0), i.e. it doesn't include the +next DMA transfer. +Thus a subsequent SPI transfer could be started although there is currently a +transfer in progress. This can cause invalid accesses to the SPI slave devices +and to SPI transfer errors. + +This issue has been observed on a hardware with a M25P128 SPI NOR flash. + +So instead of ENDRX we should wait for RXBUFF. This flag is set if there is +no more DMA transfer in progress (RCR = RNCR = 0). + +Signed-off-by: Torsten Fleischer +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/spi/spi-atmel.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/spi/spi-atmel.c ++++ b/drivers/spi/spi-atmel.c +@@ -781,17 +781,17 @@ static void atmel_spi_pdc_next_xfer(stru + (unsigned long long)xfer->rx_dma); + } + +- /* REVISIT: We're waiting for ENDRX before we start the next ++ /* REVISIT: We're waiting for RXBUFF before we start the next + * transfer because we need to handle some difficult timing +- * issues otherwise. If we wait for ENDTX in one transfer and +- * then starts waiting for ENDRX in the next, it's difficult +- * to tell the difference between the ENDRX interrupt we're +- * actually waiting for and the ENDRX interrupt of the ++ * issues otherwise. If we wait for TXBUFE in one transfer and ++ * then starts waiting for RXBUFF in the next, it's difficult ++ * to tell the difference between the RXBUFF interrupt we're ++ * actually waiting for and the RXBUFF interrupt of the + * previous transfer. + * + * It should be doable, though. Just not now... + */ +- spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES)); ++ spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES)); + spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); + } + diff --git a/queue-3.14/spi-pl022-fix-race-in-giveback-leading-to-driver-lock-up.patch b/queue-3.14/spi-pl022-fix-race-in-giveback-leading-to-driver-lock-up.patch new file mode 100644 index 00000000000..16bc4a23ef3 --- /dev/null +++ b/queue-3.14/spi-pl022-fix-race-in-giveback-leading-to-driver-lock-up.patch @@ -0,0 +1,73 @@ +From cd6fa8d2ca53cac3226fdcffcf763be390abae32 Mon Sep 17 00:00:00 2001 +From: Alexander Sverdlin +Date: Fri, 27 Feb 2015 16:30:21 +0100 +Subject: spi: pl022: Fix race in giveback() leading to driver lock-up + +From: Alexander Sverdlin + +commit cd6fa8d2ca53cac3226fdcffcf763be390abae32 upstream. + +Commit fd316941c ("spi/pl022: disable port when unused") introduced a race, +which leads to possible driver lock up (easily reproducible on SMP). + +The problem happens in giveback() function where the completion of the transfer +is signalled to SPI subsystem and then the HW SPI controller is disabled. Another +transfer might be setup in between, which brings driver in locked-up state. + +Exact event sequence on SMP: + +core0 core1 + + => pump_transfers() + /* message->state == STATE_DONE */ + => giveback() + => spi_finalize_current_message() + +=> pl022_unprepare_transfer_hardware() +=> pl022_transfer_one_message + => flush() + => do_interrupt_dma_transfer() + => set_up_next_transfer() + /* Enable SSP, turn on interrupts */ + writew((readw(SSP_CR1(pl022->virtbase)) | + SSP_CR1_MASK_SSE), SSP_CR1(pl022->virtbase)); + +... + +=> pl022_interrupt_handler() + => readwriter() + + /* disable the SPI/SSP operation */ + => writew((readw(SSP_CR1(pl022->virtbase)) & + (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); + +Lockup! SPI controller is disabled and the data will never be received. Whole +SPI subsystem is waiting for transfer ACK and blocked. + +So, only signal transfer completion after disabling the controller. + +Fixes: fd316941c (spi/pl022: disable port when unused) +Signed-off-by: Alexander Sverdlin +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/spi/spi-pl022.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/spi/spi-pl022.c ++++ b/drivers/spi/spi-pl022.c +@@ -503,12 +503,12 @@ static void giveback(struct pl022 *pl022 + pl022->cur_msg = NULL; + pl022->cur_transfer = NULL; + pl022->cur_chip = NULL; +- spi_finalize_current_message(pl022->master); + + /* disable the SPI/SSP operation */ + writew((readw(SSP_CR1(pl022->virtbase)) & + (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); + ++ spi_finalize_current_message(pl022->master); + } + + /** diff --git a/queue-3.14/tpm-ibmvtpm-additional-le-support-for-tpm_ibmvtpm_send.patch b/queue-3.14/tpm-ibmvtpm-additional-le-support-for-tpm_ibmvtpm_send.patch new file mode 100644 index 00000000000..46f2fa7719c --- /dev/null +++ b/queue-3.14/tpm-ibmvtpm-additional-le-support-for-tpm_ibmvtpm_send.patch @@ -0,0 +1,81 @@ +From 62dfd912ab3b5405b6fe72d0135c37e9648071f1 Mon Sep 17 00:00:00 2001 +From: "jmlatten@linux.vnet.ibm.com" +Date: Fri, 20 Feb 2015 18:11:24 -0600 +Subject: tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send + +From: "jmlatten@linux.vnet.ibm.com" + +commit 62dfd912ab3b5405b6fe72d0135c37e9648071f1 upstream. + +Problem: When IMA and VTPM are both enabled in kernel config, +kernel hangs during bootup on LE OS. + +Why?: IMA calls tpm_pcr_read() which results in tpm_ibmvtpm_send +and tpm_ibmtpm_recv getting called. A trace showed that +tpm_ibmtpm_recv was hanging. + +Resolution: tpm_ibmtpm_recv was hanging because tpm_ibmvtpm_send +was sending CRQ message that probably did not make much sense +to phype because of Endianness. The fix below sends correctly +converted CRQ for LE. This was not caught before because it +seems IMA is not enabled by default in kernel config and +IMA exercises this particular code path in vtpm. + +Tested with IMA and VTPM enabled in kernel config and VTPM +enabled on both a BE OS and a LE OS ppc64 lpar. This exercised +CRQ and TPM command code paths in vtpm. +Patch is against Peter's tpmdd tree on github which included +Vicky's previous vtpm le patches. + +Signed-off-by: Joy Latten +Reviewed-by: Ashley Lai +Signed-off-by: Peter Huewe +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/tpm/tpm_ibmvtpm.c | 10 +++++----- + drivers/char/tpm/tpm_ibmvtpm.h | 6 +++--- + 2 files changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/char/tpm/tpm_ibmvtpm.c ++++ b/drivers/char/tpm/tpm_ibmvtpm.c +@@ -124,7 +124,7 @@ static int tpm_ibmvtpm_send(struct tpm_c + { + struct ibmvtpm_dev *ibmvtpm; + struct ibmvtpm_crq crq; +- u64 *word = (u64 *) &crq; ++ __be64 *word = (__be64 *)&crq; + int rc; + + ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); +@@ -145,11 +145,11 @@ static int tpm_ibmvtpm_send(struct tpm_c + memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); + crq.valid = (u8)IBMVTPM_VALID_CMD; + crq.msg = (u8)VTPM_TPM_COMMAND; +- crq.len = (u16)count; +- crq.data = ibmvtpm->rtce_dma_handle; ++ crq.len = cpu_to_be16(count); ++ crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle); + +- rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]), +- cpu_to_be64(word[1])); ++ rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), ++ be64_to_cpu(word[1])); + if (rc != H_SUCCESS) { + dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); + rc = 0; +--- a/drivers/char/tpm/tpm_ibmvtpm.h ++++ b/drivers/char/tpm/tpm_ibmvtpm.h +@@ -22,9 +22,9 @@ + struct ibmvtpm_crq { + u8 valid; + u8 msg; +- u16 len; +- u32 data; +- u64 reserved; ++ __be16 len; ++ __be32 data; ++ __be64 reserved; + } __attribute__((packed, aligned(8))); + + struct ibmvtpm_crq_queue { diff --git a/queue-3.14/workqueue-fix-hang-involving-racing-cancel_work_sync-s-for-preempt_none.patch b/queue-3.14/workqueue-fix-hang-involving-racing-cancel_work_sync-s-for-preempt_none.patch new file mode 100644 index 00000000000..ab254666371 --- /dev/null +++ b/queue-3.14/workqueue-fix-hang-involving-racing-cancel_work_sync-s-for-preempt_none.patch @@ -0,0 +1,172 @@ +From 8603e1b30027f943cc9c1eef2b291d42c3347af1 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 5 Mar 2015 08:04:13 -0500 +Subject: workqueue: fix hang involving racing cancel[_delayed]_work_sync()'s for PREEMPT_NONE + +From: Tejun Heo + +commit 8603e1b30027f943cc9c1eef2b291d42c3347af1 upstream. + +cancel[_delayed]_work_sync() are implemented using +__cancel_work_timer() which grabs the PENDING bit using +try_to_grab_pending() and then flushes the work item with PENDING set +to prevent the on-going execution of the work item from requeueing +itself. + +try_to_grab_pending() can always grab PENDING bit without blocking +except when someone else is doing the above flushing during +cancelation. In that case, try_to_grab_pending() returns -ENOENT. In +this case, __cancel_work_timer() currently invokes flush_work(). The +assumption is that the completion of the work item is what the other +canceling task would be waiting for too and thus waiting for the same +condition and retrying should allow forward progress without excessive +busy looping + +Unfortunately, this doesn't work if preemption is disabled or the +latter task has real time priority. Let's say task A just got woken +up from flush_work() by the completion of the target work item. If, +before task A starts executing, task B gets scheduled and invokes +__cancel_work_timer() on the same work item, its try_to_grab_pending() +will return -ENOENT as the work item is still being canceled by task A +and flush_work() will also immediately return false as the work item +is no longer executing. This puts task B in a busy loop possibly +preventing task A from executing and clearing the canceling state on +the work item leading to a hang. + +task A task B worker + + executing work +__cancel_work_timer() + try_to_grab_pending() + set work CANCELING + flush_work() + block for work completion + completion, wakes up A + __cancel_work_timer() + while (forever) { + try_to_grab_pending() + -ENOENT as work is being canceled + flush_work() + false as work is no longer executing + } + +This patch removes the possible hang by updating __cancel_work_timer() +to explicitly wait for clearing of CANCELING rather than invoking +flush_work() after try_to_grab_pending() fails with -ENOENT. + +Link: http://lkml.kernel.org/g/20150206171156.GA8942@axis.com + +v3: bit_waitqueue() can't be used for work items defined in vmalloc + area. Switched to custom wake function which matches the target + work item and exclusive wait and wakeup. + +v2: v1 used wake_up() on bit_waitqueue() which leads to NULL deref if + the target bit waitqueue has wait_bit_queue's on it. Use + DEFINE_WAIT_BIT() and __wake_up_bit() instead. Reported by Tomeu + Vizoso. + +Signed-off-by: Tejun Heo +Reported-by: Rabin Vincent +Cc: Tomeu Vizoso +Tested-by: Jesper Nilsson +Tested-by: Rabin Vincent +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/workqueue.h | 3 +- + kernel/workqueue.c | 56 ++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 54 insertions(+), 5 deletions(-) + +--- a/include/linux/workqueue.h ++++ b/include/linux/workqueue.h +@@ -71,7 +71,8 @@ enum { + /* data contains off-queue information when !WORK_STRUCT_PWQ */ + WORK_OFFQ_FLAG_BASE = WORK_STRUCT_COLOR_SHIFT, + +- WORK_OFFQ_CANCELING = (1 << WORK_OFFQ_FLAG_BASE), ++ __WORK_OFFQ_CANCELING = WORK_OFFQ_FLAG_BASE, ++ WORK_OFFQ_CANCELING = (1 << __WORK_OFFQ_CANCELING), + + /* + * When a work item is off queue, its high bits point to the last +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -2893,19 +2893,57 @@ bool flush_work(struct work_struct *work + } + EXPORT_SYMBOL_GPL(flush_work); + ++struct cwt_wait { ++ wait_queue_t wait; ++ struct work_struct *work; ++}; ++ ++static int cwt_wakefn(wait_queue_t *wait, unsigned mode, int sync, void *key) ++{ ++ struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait); ++ ++ if (cwait->work != key) ++ return 0; ++ return autoremove_wake_function(wait, mode, sync, key); ++} ++ + static bool __cancel_work_timer(struct work_struct *work, bool is_dwork) + { ++ static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq); + unsigned long flags; + int ret; + + do { + ret = try_to_grab_pending(work, is_dwork, &flags); + /* +- * If someone else is canceling, wait for the same event it +- * would be waiting for before retrying. ++ * If someone else is already canceling, wait for it to ++ * finish. flush_work() doesn't work for PREEMPT_NONE ++ * because we may get scheduled between @work's completion ++ * and the other canceling task resuming and clearing ++ * CANCELING - flush_work() will return false immediately ++ * as @work is no longer busy, try_to_grab_pending() will ++ * return -ENOENT as @work is still being canceled and the ++ * other canceling task won't be able to clear CANCELING as ++ * we're hogging the CPU. ++ * ++ * Let's wait for completion using a waitqueue. As this ++ * may lead to the thundering herd problem, use a custom ++ * wake function which matches @work along with exclusive ++ * wait and wakeup. + */ +- if (unlikely(ret == -ENOENT)) +- flush_work(work); ++ if (unlikely(ret == -ENOENT)) { ++ struct cwt_wait cwait; ++ ++ init_wait(&cwait.wait); ++ cwait.wait.func = cwt_wakefn; ++ cwait.work = work; ++ ++ prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait, ++ TASK_UNINTERRUPTIBLE); ++ if (work_is_canceling(work)) ++ schedule(); ++ finish_wait(&cancel_waitq, &cwait.wait); ++ } + } while (unlikely(ret < 0)); + + /* tell other tasks trying to grab @work to back off */ +@@ -2914,6 +2952,16 @@ static bool __cancel_work_timer(struct w + + flush_work(work); + clear_work_data(work); ++ ++ /* ++ * Paired with prepare_to_wait() above so that either ++ * waitqueue_active() is visible here or !work_is_canceling() is ++ * visible there. ++ */ ++ smp_mb(); ++ if (waitqueue_active(&cancel_waitq)) ++ __wake_up(&cancel_waitq, TASK_NORMAL, 1, work); ++ + return ret; + } +