Skip to content

Commit c02f77d

Browse files
committed
ALSA: hda - Workaround for crackled sound on AMD controller (1022:1457)
A long-time problem on the recent AMD chip (X370, X470, B450, etc with PCI ID 1022:1457) with Realtek codecs is the crackled or distorted sound for capture streams, as well as occasional playback hiccups. After lengthy debugging sessions, the workarounds we've found are like the following: - Set up the proper driver caps for this controller, similar as the other AMD controller. - Correct the DMA position reporting with the fixed FIFO size, which is similar like as workaround used for VIA chip set. - Even after the position correction, PulseAudio still shows mysterious stalls of playback streams when a capture is triggered in timer-scheduled mode. Since we have no clear way to eliminate the stall, pass the BATCH PCM flag for PA to suppress the tsched mode as a temporary workaround. This patch implements the workarounds. For the driver caps, it defines a new preset, AXZ_DCAPS_PRESET_AMD_SB. It enables the FIFO- corrected position reporting (corresponding to the new position_fix=6) and enforces the SNDRV_PCM_INFO_BATCH flag. Note that the current implementation is merely a workaround. Hopefully we'll find a better alternative in future, especially about removing the BATCH flag hack again. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=195303 Cc: <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 3d92aa4 commit c02f77d

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

sound/pci/hda/hda_controller.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
613613
20,
614614
178000000);
615615

616+
/* by some reason, the playback stream stalls on PulseAudio with
617+
* tsched=1 when a capture stream triggers. Until we figure out the
618+
* real cause, disable tsched mode by telling the PCM info flag.
619+
*/
620+
if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND)
621+
runtime->hw.info |= SNDRV_PCM_INFO_BATCH;
622+
616623
if (chip->align_buffer_size)
617624
/* constrain buffer sizes to be multiple of 128
618625
bytes. This is more efficient in terms of memory

sound/pci/hda/hda_controller.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
/* 14 unused */
3232
#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
3333
#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */
34-
/* 17 unused */
34+
#define AZX_DCAPS_AMD_WORKAROUND (1 << 17) /* AMD-specific workaround */
3535
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
3636
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
3737
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */

sound/pci/hda/hda_intel.c

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ enum {
6464
POS_FIX_VIACOMBO,
6565
POS_FIX_COMBO,
6666
POS_FIX_SKL,
67+
POS_FIX_FIFO,
6768
};
6869

6970
/* Defines for ATI HD Audio support in SB450 south bridge */
@@ -135,7 +136,7 @@ module_param_array(model, charp, NULL, 0444);
135136
MODULE_PARM_DESC(model, "Use the given board model.");
136137
module_param_array(position_fix, int, NULL, 0444);
137138
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
138-
"(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+).");
139+
"(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+, 6 = FIFO).");
139140
module_param_array(bdl_pos_adj, int, NULL, 0644);
140141
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
141142
module_param_array(probe_mask, int, NULL, 0444);
@@ -332,6 +333,11 @@ enum {
332333
#define AZX_DCAPS_PRESET_ATI_HDMI_NS \
333334
(AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF)
334335

336+
/* quirks for AMD SB */
337+
#define AZX_DCAPS_PRESET_AMD_SB \
338+
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_AMD_WORKAROUND |\
339+
AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME)
340+
335341
/* quirks for Nvidia */
336342
#define AZX_DCAPS_PRESET_NVIDIA \
337343
(AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\
@@ -841,6 +847,49 @@ static unsigned int azx_via_get_position(struct azx *chip,
841847
return bound_pos + mod_dma_pos;
842848
}
843849

850+
#define AMD_FIFO_SIZE 32
851+
852+
/* get the current DMA position with FIFO size correction */
853+
static unsigned int azx_get_pos_fifo(struct azx *chip, struct azx_dev *azx_dev)
854+
{
855+
struct snd_pcm_substream *substream = azx_dev->core.substream;
856+
struct snd_pcm_runtime *runtime = substream->runtime;
857+
unsigned int pos, delay;
858+
859+
pos = snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev));
860+
if (!runtime)
861+
return pos;
862+
863+
runtime->delay = AMD_FIFO_SIZE;
864+
delay = frames_to_bytes(runtime, AMD_FIFO_SIZE);
865+
if (azx_dev->insufficient) {
866+
if (pos < delay) {
867+
delay = pos;
868+
runtime->delay = bytes_to_frames(runtime, pos);
869+
} else {
870+
azx_dev->insufficient = 0;
871+
}
872+
}
873+
874+
/* correct the DMA position for capture stream */
875+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
876+
if (pos < delay)
877+
pos += azx_dev->core.bufsize;
878+
pos -= delay;
879+
}
880+
881+
return pos;
882+
}
883+
884+
static int azx_get_delay_from_fifo(struct azx *chip, struct azx_dev *azx_dev,
885+
unsigned int pos)
886+
{
887+
struct snd_pcm_substream *substream = azx_dev->core.substream;
888+
889+
/* just read back the calculated value in the above */
890+
return substream->runtime->delay;
891+
}
892+
844893
static unsigned int azx_skl_get_dpib_pos(struct azx *chip,
845894
struct azx_dev *azx_dev)
846895
{
@@ -1417,6 +1466,7 @@ static int check_position_fix(struct azx *chip, int fix)
14171466
case POS_FIX_VIACOMBO:
14181467
case POS_FIX_COMBO:
14191468
case POS_FIX_SKL:
1469+
case POS_FIX_FIFO:
14201470
return fix;
14211471
}
14221472

@@ -1433,6 +1483,10 @@ static int check_position_fix(struct azx *chip, int fix)
14331483
dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
14341484
return POS_FIX_VIACOMBO;
14351485
}
1486+
if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND) {
1487+
dev_dbg(chip->card->dev, "Using FIFO position fix\n");
1488+
return POS_FIX_FIFO;
1489+
}
14361490
if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
14371491
dev_dbg(chip->card->dev, "Using LPIB position fix\n");
14381492
return POS_FIX_LPIB;
@@ -1453,6 +1507,7 @@ static void assign_position_fix(struct azx *chip, int fix)
14531507
[POS_FIX_VIACOMBO] = azx_via_get_position,
14541508
[POS_FIX_COMBO] = azx_get_pos_lpib,
14551509
[POS_FIX_SKL] = azx_get_pos_skl,
1510+
[POS_FIX_FIFO] = azx_get_pos_fifo,
14561511
};
14571512

14581513
chip->get_position[0] = chip->get_position[1] = callbacks[fix];
@@ -1467,6 +1522,9 @@ static void assign_position_fix(struct azx *chip, int fix)
14671522
azx_get_delay_from_lpib;
14681523
}
14691524

1525+
if (fix == POS_FIX_FIFO)
1526+
chip->get_delay[0] = chip->get_delay[1] =
1527+
azx_get_delay_from_fifo;
14701528
}
14711529

14721530
/*
@@ -2447,6 +2505,9 @@ static const struct pci_device_id azx_ids[] = {
24472505
/* AMD Hudson */
24482506
{ PCI_DEVICE(0x1022, 0x780d),
24492507
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
2508+
/* AMD, X370 & co */
2509+
{ PCI_DEVICE(0x1022, 0x1457),
2510+
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
24502511
/* AMD Stoney */
24512512
{ PCI_DEVICE(0x1022, 0x157a),
24522513
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |

0 commit comments

Comments
 (0)