Skip to content

Commit

Permalink
Merge tag 'sound-fix-5.5-rc1' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/tiwai/sound

Pull more sound updates from Takashi Iwai:
 "A few last-minute updates, most of them are the regression fixes:

   - AMD HD-audio HDMI runtime PM improvements

   - Fixes for HD-audio HDMI regressions wrt DP-MST

   - A regression fix for the previous aloop enhancement

   - A fix for a long-time problem in PCM OSS layer that was spotted by
     fuzzer now

   - A few HD-audio quirks"

* tag 'sound-fix-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: pcm: oss: Avoid potential buffer overflows
  ALSA: hda: hdmi - Keep old slot assignment behavior for Intel platforms
  ALSA: hda: Modify stream stripe mask only when needed
  ALSA: hda - fixup for the bass speaker on Lenovo Carbon X1 7th gen
  ALSA: hda: hdmi - preserve non-MST PCM routing for Intel platforms
  ALSA: hda: hdmi - fix kernel oops caused by invalid PCM idx
  ALSA: hda/realtek - Fix inverted bass GPIO pin on Acer 8951G
  ALSA: hda/realtek - Dell headphone has noise on unmute for ALC236
  ALSA: hda: hdmi - fix regression in connect list handling
  ALSA: aloop: Avoid pointer dereference before null-check
  ALSA: hda/hdmi - enable automatic runtime pm for AMD HDMI codecs by default
  ALSA: hda/hdmi - enable runtime pm for newer AMD display audio
  ALSA: hda/hdmi - Add new pci ids for AMD GPU display audio
  ALSA: hda/hdmi - fix vgaswitcheroo detection for AMD
  • Loading branch information
torvalds committed Dec 6, 2019
2 parents ec05759 + 4cc8d65 commit 3cf2890
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 69 deletions.
1 change: 1 addition & 0 deletions include/sound/hdaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ struct hdac_stream {
bool prepared:1;
bool no_period_wakeup:1;
bool locked:1;
bool stripe:1; /* apply stripe control */

/* timestamp */
unsigned long start_wallclk; /* start + minimum wallclk */
Expand Down
2 changes: 2 additions & 0 deletions sound/core/oss/linear.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
}
}
#endif
if (frames > dst_channels[0].frames)
frames = dst_channels[0].frames;
convert(plugin, src_channels, dst_channels, frames);
return frames;
}
Expand Down
2 changes: 2 additions & 0 deletions sound/core/oss/mulaw.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
}
}
#endif
if (frames > dst_channels[0].frames)
frames = dst_channels[0].frames;
data = (struct mulaw_priv *)plugin->extra_data;
data->func(plugin, src_channels, dst_channels, frames);
return frames;
Expand Down
2 changes: 2 additions & 0 deletions sound/core/oss/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
return -ENXIO;
if (frames == 0)
return 0;
if (frames > dst_channels[0].frames)
frames = dst_channels[0].frames;

nsrcs = plugin->src_format.channels;
ndsts = plugin->dst_format.channels;
Expand Down
8 changes: 4 additions & 4 deletions sound/drivers/aloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -727,10 +727,6 @@ static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable,

dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE];
substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
dpcm_play->substream : NULL;
substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ?
dpcm_capt->substream : NULL;

if (event == SNDRV_TIMER_EVENT_MSTOP) {
if (!dpcm_play ||
Expand All @@ -741,6 +737,10 @@ static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable,
}
}

substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
dpcm_play->substream : NULL;
substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ?
dpcm_capt->substream : NULL;
valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
dpcm_play->substream->runtime :
dpcm_capt->substream->runtime;
Expand Down
19 changes: 12 additions & 7 deletions sound/hda/hdac_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,14 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start)
1 << azx_dev->index,
1 << azx_dev->index);
/* set stripe control */
if (azx_dev->substream)
stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream);
else
stripe_ctl = 0;
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
stripe_ctl);
if (azx_dev->stripe) {
if (azx_dev->substream)
stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream);
else
stripe_ctl = 0;
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
stripe_ctl);
}
/* set DMA start and interrupt mask */
snd_hdac_stream_updateb(azx_dev, SD_CTL,
0, SD_CTL_DMA_START | SD_INT_MASK);
Expand All @@ -118,7 +120,10 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
snd_hdac_stream_updateb(azx_dev, SD_CTL,
SD_CTL_DMA_START | SD_INT_MASK, 0);
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
if (azx_dev->stripe) {
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
azx_dev->stripe = 0;
}
azx_dev->running = false;
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_clear);
Expand Down
80 changes: 75 additions & 5 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/clocksource.h>
#include <linux/time.h>
#include <linux/completion.h>
#include <linux/acpi.h>

#ifdef CONFIG_X86
/* for snoop control */
Expand Down Expand Up @@ -1401,6 +1402,34 @@ static int azx_dev_free(struct snd_device *device)
}

#ifdef SUPPORT_VGA_SWITCHEROO
#ifdef CONFIG_ACPI
/* ATPX is in the integrated GPU's namespace */
static bool atpx_present(void)
{
struct pci_dev *pdev = NULL;
acpi_handle dhandle, atpx_handle;
acpi_status status;

while ((pdev = pci_get_class(PCI_BASE_CLASS_DISPLAY << 16, pdev)) != NULL) {
dhandle = ACPI_HANDLE(&pdev->dev);
if (dhandle) {
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
if (!ACPI_FAILURE(status)) {
pci_dev_put(pdev);
return true;
}
}
pci_dev_put(pdev);
}
return false;
}
#else
static bool atpx_present(void)
{
return false;
}
#endif

/*
* Check of disabled HDMI controller by vga_switcheroo
*/
Expand All @@ -1412,6 +1441,22 @@ static struct pci_dev *get_bound_vga(struct pci_dev *pci)
switch (pci->vendor) {
case PCI_VENDOR_ID_ATI:
case PCI_VENDOR_ID_AMD:
if (pci->devfn == 1) {
p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
pci->bus->number, 0);
if (p) {
/* ATPX is in the integrated GPU's ACPI namespace
* rather than the dGPU's namespace. However,
* the dGPU is the one who is involved in
* vgaswitcheroo.
*/
if (((p->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
atpx_present())
return p;
pci_dev_put(p);
}
}
break;
case PCI_VENDOR_ID_NVIDIA:
if (pci->devfn == 1) {
p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
Expand Down Expand Up @@ -2547,13 +2592,38 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x1002, 0xaac8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaad8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaae8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xaae0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xaae8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xaaf0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xaaf8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xab00),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xab08),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xab10),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xab18),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xab20),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xab38),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
/* VIA VT8251/VT8237A */
{ PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
/* VIA GFX VT7122/VX900 */
Expand Down
68 changes: 31 additions & 37 deletions sound/pci/hda/patch_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_jack.h"
#include "hda_controller.h"

static bool static_hdmi_pcm;
module_param(static_hdmi_pcm, bool, 0644);
Expand Down Expand Up @@ -1249,6 +1250,10 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
per_pin->cvt_nid = per_cvt->cvt_nid;
hinfo->nid = per_cvt->cvt_nid;

/* flip stripe flag for the assigned stream if supported */
if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE)
azx_stream(get_azx_dev(substream))->stripe = 1;

snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL,
Expand Down Expand Up @@ -1302,6 +1307,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid;
int dev_id = per_pin->dev_id;
int conns;

if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
codec_warn(codec,
Expand All @@ -1312,10 +1318,18 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)

snd_hda_set_dev_select(codec, pin_nid, dev_id);

if (spec->intel_hsw_fixup) {
conns = spec->num_cvts;
memcpy(per_pin->mux_nids, spec->cvt_nids,
sizeof(hda_nid_t) * conns);
} else {
conns = snd_hda_get_raw_connections(codec, pin_nid,
per_pin->mux_nids,
HDA_MAX_CONNECTIONS);
}

/* all the device entries on the same pin have the same conn list */
per_pin->num_mux_nids =
snd_hda_get_raw_connections(codec, pin_nid, per_pin->mux_nids,
HDA_MAX_CONNECTIONS);
per_pin->num_mux_nids = conns;

return 0;
}
Expand All @@ -1326,24 +1340,26 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
int i;

/*
* generic_hdmi_build_pcms() allocates (num_nids + dev_num - 1)
* number of pcms.
* generic_hdmi_build_pcms() may allocate extra PCMs on some
* platforms (with maximum of 'num_nids + dev_num - 1')
*
* The per_pin of pin_nid_idx=n and dev_id=m prefers to get pcm-n
* if m==0. This guarantees that dynamic pcm assignments are compatible
* with the legacy static per_pin-pmc assignment that existed in the
* with the legacy static per_pin-pcm assignment that existed in the
* days before DP-MST.
*
* Intel DP-MST prefers this legacy behavior for compatibility, too.
*
* per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)).
*/
if (per_pin->dev_id == 0 &&
!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap))
return per_pin->pin_nid_idx;

if (per_pin->dev_id != 0 &&
!(test_bit(spec->num_nids + (per_pin->dev_id - 1),
&spec->pcm_bitmap))) {
return spec->num_nids + (per_pin->dev_id - 1);

if (per_pin->dev_id == 0 || spec->intel_hsw_fixup) {
if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap))
return per_pin->pin_nid_idx;
} else {
i = spec->num_nids + (per_pin->dev_id - 1);
if (i < spec->pcm_used && !(test_bit(i, &spec->pcm_bitmap)))
return i;
}

/* have a second try; check the area over num_nids */
Expand Down Expand Up @@ -1713,9 +1729,6 @@ static void hdmi_repoll_eld(struct work_struct *work)
mutex_unlock(&spec->pcm_lock);
}

static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid);

static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
{
struct hdmi_spec *spec = codec->spec;
Expand Down Expand Up @@ -1790,8 +1803,6 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
per_pin->dev_id = i;
per_pin->non_pcm = false;
snd_hda_set_dev_select(codec, pin_nid, i);
if (spec->intel_hsw_fixup)
intel_haswell_fixup_connect_list(codec, pin_nid);
err = hdmi_read_pin_conn(codec, pin_idx);
if (err < 0)
return err;
Expand Down Expand Up @@ -2603,24 +2614,6 @@ static void generic_acomp_init(struct hda_codec *codec,
* Intel codec parsers and helpers
*/

static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid)
{
struct hdmi_spec *spec = codec->spec;
hda_nid_t conns[4];
int nconns;

nconns = snd_hda_get_raw_connections(codec, nid, conns,
ARRAY_SIZE(conns));
if (nconns == spec->num_cvts &&
!memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t)))
return;

/* override pins connection list */
codec_dbg(codec, "hdmi: haswell: override pin connection 0x%x\n", nid);
snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
}

#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
Expand Down Expand Up @@ -4063,6 +4056,7 @@ static int atihdmi_init(struct hda_codec *codec)
ATI_VERB_SET_MULTICHANNEL_MODE,
ATI_MULTICHANNEL_MODE_SINGLE);
}
codec->auto_runtime_pm = 1;

return 0;
}
Expand Down
Loading

0 comments on commit 3cf2890

Please sign in to comment.