From 49d9e77e72cf178644b4db08fa211d8b4715ab13 Mon Sep 17 00:00:00 2001 From: Mike Travis Date: Wed, 1 May 2013 14:04:08 -0500 Subject: ALSA: hda - Fix system panic when DMA > 40 bits for Nvidia audio controllers The audio driver mistakenly allows 64 bit addresses to be created for the audio driver on Nvidia GPUs. Unfortunately, the hardware normally only supports up to 40 bits of DMA. This can cause system panics as well as misdirected data when the address is > 40 bits as the upper part the address is truncated. Signed-off-by: Mike Travis Reviewed-by: Mike Habeck Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7b213d589ef6..de18722c4873 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -615,7 +615,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ - AZX_DCAPS_ALIGN_BUFSIZE) + AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT) #define AZX_DCAPS_PRESET_CTHDA \ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY) -- cgit v1.2.3-58-ga151 From ff359b14919c379a365233aa2e1dd469efac8ce8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 4 May 2013 10:57:16 +0200 Subject: ALSA: hda - Fix 3.9 regression of EAPD init on Conexant codecs The older Conexant codecs have up to two EAPDs and these are supposed to be rather statically turned on. The new generic parser code assumes the dynamic on/off per path usage, thus it resulted in the silent output on some machines. This patch fixes the problem by simply assuming the static EAPD on for such old Conexant codecs as we did until 3.8 kernel. Reported-and-tested-by: Christopher K. Cc: [v3.9] Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 84b81c874a4a..b314d3e6d7fa 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -64,6 +64,7 @@ struct conexant_spec { /* extra EAPD pins */ unsigned int num_eapds; hda_nid_t eapds[4]; + bool dynamic_eapd; #ifdef ENABLE_CXT_STATIC_QUIRKS const struct snd_kcontrol_new *mixers[5]; @@ -3155,7 +3156,7 @@ static void cx_auto_parse_eapd(struct hda_codec *codec) * thus it might control over all pins. */ if (spec->num_eapds > 2) - spec->gen.own_eapd_ctl = 1; + spec->dynamic_eapd = 1; } static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, @@ -3194,10 +3195,19 @@ static int cx_auto_build_controls(struct hda_codec *codec) return 0; } +static int cx_auto_init(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + snd_hda_gen_init(codec); + if (!spec->dynamic_eapd) + cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); + return 0; +} + static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = cx_auto_build_controls, .build_pcms = snd_hda_gen_build_pcms, - .init = snd_hda_gen_init, + .init = cx_auto_init, .free = snd_hda_gen_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM @@ -3348,7 +3358,8 @@ static int patch_conexant_auto(struct hda_codec *codec) cx_auto_parse_beep(codec); cx_auto_parse_eapd(codec); - if (spec->gen.own_eapd_ctl) + spec->gen.own_eapd_ctl = 1; + if (spec->dynamic_eapd) spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook; switch (codec->vendor_id) { -- cgit v1.2.3-58-ga151 From 2195b063f6609e4c6268f291683902f25eaf9aa6 Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Tue, 7 May 2013 11:27:33 +0800 Subject: ALSA: HDA: Fix Oops caused by dereference NULL pointer The interrupt handler azx_interrupt will call azx_update_rirb, which may call snd_hda_queue_unsol_event, snd_hda_queue_unsol_event will dereference chip->bus pointer. The problem is we alloc chip->bus in azx_codec_create which will be called after we enable IRQ and enable unsolicited event in azx_probe. This will cause Oops due dereference NULL pointer. I meet it, good luck:) [Rearranged the NULL check before the tracepoint and added another NULL check of bus->workq -- tiwai] Signed-off-by: Wang YanQing Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6f9b64700f6e..86674f67abd1 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -681,6 +681,9 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) struct hda_bus_unsolicited *unsol; unsigned int wp; + if (!bus || !bus->workq) + return 0; + trace_hda_unsol_event(bus, res, res_ex); unsol = bus->unsol; if (!unsol) -- cgit v1.2.3-58-ga151 From 17df3f55652f7ea8fb1197b5c32e227b3da9f215 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 May 2013 08:09:34 +0200 Subject: ALSA: hda - Apply pin-enablement workaround to all Haswell HDMI codecs This is a revised patch based on Mengdong Lin's fix patch, which is a supplement to a previous patch [1611a9c9: ALSA: hda - Add fixup for Haswell to enable all pin and convertor widgets]. Some Haswell BIOS will disable the 2nd and 3rd pin/covertor widgets when the HD-A controller changes state from D3 to D0. So when the controller resumes after a system or runtime suspend, these widgets are disabled and programming these widgets to D0 will cause H/W error and codec will not respond. In addition, we found out that some BIOS disables the pins at S3 although it shows up at boot. This confuses the driver utterly, and the hardware falls into the fatal communication error like the above. So in this patch, we apply intel_haswell_enable_all_pins() not only as a fixup to a certain device (with 8086:2010) but to all Haswell machines. The codec driver basically assumes that all pins are exposed, so it's anyway better to see them from the beginning. Even if all pins and converters are shown by this call, there should be no regression in practice: the pin default configurations are still kept, thus the disabled pins are handled as disabled by the driver properly. Signed-off-by: Mengdong Lin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 54 +++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 32930e668854..e12f7a030c58 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1832,12 +1832,10 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ static void intel_haswell_enable_all_pins(struct hda_codec *codec, - const struct hda_fixup *fix, int action) + bool update_tree) { unsigned int vendor_param; - if (action != HDA_FIXUP_ACT_PRE_PROBE) - return; vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0, INTEL_GET_VENDOR_VERB, 0); if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) @@ -1849,8 +1847,8 @@ static void intel_haswell_enable_all_pins(struct hda_codec *codec, if (vendor_param == -1) return; - snd_hda_codec_update_widgets(codec); - return; + if (update_tree) + snd_hda_codec_update_widgets(codec); } static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) @@ -1868,30 +1866,20 @@ static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) INTEL_SET_VENDOR_VERB, vendor_param); } +/* Haswell needs to re-issue the vendor-specific verbs before turning to D0. + * Otherwise you may get severe h/w communication errors. + */ +static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state) +{ + if (power_state == AC_PWRST_D0) { + intel_haswell_enable_all_pins(codec, false); + intel_haswell_fixup_enable_dp12(codec); + } - -/* available models for fixup */ -enum { - INTEL_HASWELL, -}; - -static const struct hda_model_fixup hdmi_models[] = { - {.id = INTEL_HASWELL, .name = "Haswell"}, - {} -}; - -static const struct snd_pci_quirk hdmi_fixup_tbl[] = { - SND_PCI_QUIRK(0x8086, 0x2010, "Haswell", INTEL_HASWELL), - {} /* terminator */ -}; - -static const struct hda_fixup hdmi_fixups[] = { - [INTEL_HASWELL] = { - .type = HDA_FIXUP_FUNC, - .v.func = intel_haswell_enable_all_pins, - }, -}; - + snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); + snd_hda_codec_set_power_to_all(codec, fg, power_state); +} static int patch_generic_hdmi(struct hda_codec *codec) { @@ -1904,11 +1892,10 @@ static int patch_generic_hdmi(struct hda_codec *codec) codec->spec = spec; hdmi_array_init(spec, 4); - snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - - if (codec->vendor_id == 0x80862807) + if (codec->vendor_id == 0x80862807) { + intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); + } if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; @@ -1916,6 +1903,9 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -EINVAL; } codec->patch_ops = generic_hdmi_patch_ops; + if (codec->vendor_id == 0x80862807) + codec->patch_ops.set_power_state = haswell_set_power_state; + generic_hdmi_init_per_pins(codec); init_channel_allocations(); -- cgit v1.2.3-58-ga151 From 6c35ae3c327ef4b5f51d3428d2ba47ac2153e882 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 May 2013 13:39:50 +0200 Subject: Revert "ALSA: hda - Don't set up active streams twice" This reverts commit affdb62b815b38261f09f9d4ec210a35c7ffb1f3. The commit introduced a regression with AD codecs where the stream is always clean up. Since the patch is just a minor optimization and reverting the commit fixes the issue, let's just revert it. Reported-and-tested-by: Michael Burian Cc: [v3.9+] Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 86674f67abd1..55108b5fb291 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1583,7 +1583,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", nid, stream_tag, channel_id, format); p = get_hda_cvt_setup(codec, nid); - if (!p || p->active) + if (!p) return; if (codec->pcm_format_first) @@ -1630,7 +1630,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); p = get_hda_cvt_setup(codec, nid); - if (p && p->active) { + if (p) { /* here we just clear the active flag when do_now isn't set; * actual clean-ups will be done later in * purify_inactive_streams() called from snd_hda_codec_prpapre() -- cgit v1.2.3-58-ga151