Skip to content

Commit 4d024fe

Browse files
committed
ALSA: hda: Apply aligned MMIO access only conditionally
It turned out that the recent simplification of HD-audio bus access helpers caused a regression on the virtual HD-audio device on QEMU with ARM platforms. The driver got a CORB/RIRB timeout and couldn't probe any codecs. The essential difference that caused a problem was the enforced aligned MMIO accesses by simplification. Since snd-hda-tegra driver is enabled on ARM, it enables CONFIG_SND_HDA_ALIGNED_MMIO, which makes the all HD-audio drivers using the aligned MMIO accesses. While this is mandatory for snd-hda-tegra, it seems that snd-hda-intel on ARM gets broken by this access pattern. For addressing the regression, this patch introduces a new flag, aligned_mmio, to hdac_bus object, and applies the aligned MMIO only when this flag is set. This change affects only platforms with CONFIG_SND_HDA_ALIGNED_MMIO set, i.e. mostly only for ARM platforms. Unfortunately the patch became a big bigger than it should be, just because the former calls didn't take hdac_bus object in the argument, hence we had to extend the call patterns. Fixes: 19abfef ("ALSA: hda: Direct MMIO accesses") BugLink: https://bugzilla.opensuse.org/show_bug.cgi?id=1161152 Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent e5dbdcb commit 4d024fe

File tree

2 files changed

+54
-24
lines changed

2 files changed

+54
-24
lines changed

include/sound/hdaudio.h

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/device.h>
1010
#include <linux/interrupt.h>
11+
#include <linux/io.h>
1112
#include <linux/pm_runtime.h>
1213
#include <linux/timecounter.h>
1314
#include <sound/core.h>
@@ -330,6 +331,7 @@ struct hdac_bus {
330331
bool chip_init:1; /* h/w initialized */
331332

332333
/* behavior flags */
334+
bool aligned_mmio:1; /* aligned MMIO access */
333335
bool sync_write:1; /* sync after verb write */
334336
bool use_posbuf:1; /* use position buffer */
335337
bool snoop:1; /* enable snooping */
@@ -405,34 +407,61 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus);
405407
unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask);
406408
void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
407409
unsigned int mask);
408-
#define snd_hdac_reg_writeb(v, addr) snd_hdac_aligned_write(v, addr, 0xff)
409-
#define snd_hdac_reg_writew(v, addr) snd_hdac_aligned_write(v, addr, 0xffff)
410-
#define snd_hdac_reg_readb(addr) snd_hdac_aligned_read(addr, 0xff)
411-
#define snd_hdac_reg_readw(addr) snd_hdac_aligned_read(addr, 0xffff)
412-
#else /* CONFIG_SND_HDA_ALIGNED_MMIO */
413-
#define snd_hdac_reg_writeb(val, addr) writeb(val, addr)
414-
#define snd_hdac_reg_writew(val, addr) writew(val, addr)
415-
#define snd_hdac_reg_readb(addr) readb(addr)
416-
#define snd_hdac_reg_readw(addr) readw(addr)
417-
#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */
418-
#define snd_hdac_reg_writel(val, addr) writel(val, addr)
419-
#define snd_hdac_reg_readl(addr) readl(addr)
410+
#define snd_hdac_aligned_mmio(bus) (bus)->aligned_mmio
411+
#else
412+
#define snd_hdac_aligned_mmio(bus) false
413+
#define snd_hdac_aligned_read(addr, mask) 0
414+
#define snd_hdac_aligned_write(val, addr, mask) do {} while (0)
415+
#endif
416+
417+
static inline void snd_hdac_reg_writeb(struct hdac_bus *bus, void __iomem *addr,
418+
u8 val)
419+
{
420+
if (snd_hdac_aligned_mmio(bus))
421+
snd_hdac_aligned_write(val, addr, 0xff);
422+
else
423+
writeb(val, addr);
424+
}
425+
426+
static inline void snd_hdac_reg_writew(struct hdac_bus *bus, void __iomem *addr,
427+
u16 val)
428+
{
429+
if (snd_hdac_aligned_mmio(bus))
430+
snd_hdac_aligned_write(val, addr, 0xffff);
431+
else
432+
writew(val, addr);
433+
}
434+
435+
static inline u8 snd_hdac_reg_readb(struct hdac_bus *bus, void __iomem *addr)
436+
{
437+
return snd_hdac_aligned_mmio(bus) ?
438+
snd_hdac_aligned_read(addr, 0xff) : readb(addr);
439+
}
440+
441+
static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr)
442+
{
443+
return snd_hdac_aligned_mmio(bus) ?
444+
snd_hdac_aligned_read(addr, 0xffff) : readw(addr);
445+
}
446+
447+
#define snd_hdac_reg_writel(bus, addr, val) writel(val, addr)
448+
#define snd_hdac_reg_readl(bus, addr) readl(addr)
420449

421450
/*
422451
* macros for easy use
423452
*/
424453
#define _snd_hdac_chip_writeb(chip, reg, value) \
425-
snd_hdac_reg_writeb(value, (chip)->remap_addr + (reg))
454+
snd_hdac_reg_writeb(chip, (chip)->remap_addr + (reg), value)
426455
#define _snd_hdac_chip_readb(chip, reg) \
427-
snd_hdac_reg_readb((chip)->remap_addr + (reg))
456+
snd_hdac_reg_readb(chip, (chip)->remap_addr + (reg))
428457
#define _snd_hdac_chip_writew(chip, reg, value) \
429-
snd_hdac_reg_writew(value, (chip)->remap_addr + (reg))
458+
snd_hdac_reg_writew(chip, (chip)->remap_addr + (reg), value)
430459
#define _snd_hdac_chip_readw(chip, reg) \
431-
snd_hdac_reg_readw((chip)->remap_addr + (reg))
460+
snd_hdac_reg_readw(chip, (chip)->remap_addr + (reg))
432461
#define _snd_hdac_chip_writel(chip, reg, value) \
433-
snd_hdac_reg_writel(value, (chip)->remap_addr + (reg))
462+
snd_hdac_reg_writel(chip, (chip)->remap_addr + (reg), value)
434463
#define _snd_hdac_chip_readl(chip, reg) \
435-
snd_hdac_reg_readl((chip)->remap_addr + (reg))
464+
snd_hdac_reg_readl(chip, (chip)->remap_addr + (reg))
436465

437466
/* read/write a register, pass without AZX_REG_ prefix */
438467
#define snd_hdac_chip_writel(chip, reg, value) \
@@ -540,17 +569,17 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus,
540569
*/
541570
/* read/write a register, pass without AZX_REG_ prefix */
542571
#define snd_hdac_stream_writel(dev, reg, value) \
543-
snd_hdac_reg_writel(value, (dev)->sd_addr + AZX_REG_ ## reg)
572+
snd_hdac_reg_writel((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value)
544573
#define snd_hdac_stream_writew(dev, reg, value) \
545-
snd_hdac_reg_writew(value, (dev)->sd_addr + AZX_REG_ ## reg)
574+
snd_hdac_reg_writew((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value)
546575
#define snd_hdac_stream_writeb(dev, reg, value) \
547-
snd_hdac_reg_writeb(value, (dev)->sd_addr + AZX_REG_ ## reg)
576+
snd_hdac_reg_writeb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value)
548577
#define snd_hdac_stream_readl(dev, reg) \
549-
snd_hdac_reg_readl((dev)->sd_addr + AZX_REG_ ## reg)
578+
snd_hdac_reg_readl((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
550579
#define snd_hdac_stream_readw(dev, reg) \
551-
snd_hdac_reg_readw((dev)->sd_addr + AZX_REG_ ## reg)
580+
snd_hdac_reg_readw((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
552581
#define snd_hdac_stream_readb(dev, reg) \
553-
snd_hdac_reg_readb((dev)->sd_addr + AZX_REG_ ## reg)
582+
snd_hdac_reg_readb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
554583

555584
/* update a register, pass without AZX_REG_ prefix */
556585
#define snd_hdac_stream_updatel(dev, reg, mask, val) \

sound/pci/hda/hda_tegra.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ static int hda_tegra_create(struct snd_card *card,
398398
return err;
399399

400400
chip->bus.needs_damn_long_delay = 1;
401+
chip->bus.core.aligned_mmio = 1;
401402

402403
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
403404
if (err < 0) {

0 commit comments

Comments
 (0)