Skip to content

Commit c8d251f

Browse files
bebarinobroonie
authored andcommitted
ASoC: qcom: Actually clear DMA interrupt register for HDMI
In commit da0363f ("ASoC: qcom: Fix for DMA interrupt clear reg overwriting") we changed regmap_write() to regmap_update_bits() so that we can avoid overwriting bits that we didn't intend to modify. Unfortunately this change breaks the case where a register is writable but not readable, which is exactly how the HDMI irq clear register is designed (grep around LPASS_HDMITX_APP_IRQCLEAR_REG to see how it's write only). That's because regmap_update_bits() tries to read the register from the hardware and if it isn't readable it looks in the regmap cache to see what was written there last time to compare against what we want to write there. Eventually, we're unable to modify this register at all because the bits that we're trying to set are already set in the cache. This is doubly bad for the irq clear register because you have to write the bit to clear an interrupt. Given the irq is level triggered, we see an interrupt storm upon plugging in an HDMI cable and starting audio playback. The irq storm is so great that performance degrades significantly, leading to CPU soft lockups. Fix it by using regmap_write_bits() so that we really do write the bits in the clear register that we want to. This brings the number of irqs handled by lpass_dma_interrupt_handler() down from ~150k/sec to ~10/sec. Fixes: da0363f ("ASoC: qcom: Fix for DMA interrupt clear reg overwriting") Cc: Srinivasa Rao Mandadapu <srivasam@codeaurora.org> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Stephen Boyd <swboyd@chromium.org> Link: https://lore.kernel.org/r/20220209232520.4017634-1-swboyd@chromium.org Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent e4e3a93 commit c8d251f

1 file changed

Lines changed: 4 additions & 4 deletions

File tree

sound/soc/qcom/lpass-platform.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
524524
return -EINVAL;
525525
}
526526

527-
ret = regmap_update_bits(map, reg_irqclr, val_irqclr, val_irqclr);
527+
ret = regmap_write_bits(map, reg_irqclr, val_irqclr, val_irqclr);
528528
if (ret) {
529529
dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
530530
return ret;
@@ -665,7 +665,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
665665
return -EINVAL;
666666
}
667667
if (interrupts & LPAIF_IRQ_PER(chan)) {
668-
rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));
668+
rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));
669669
if (rv) {
670670
dev_err(soc_runtime->dev,
671671
"error writing to irqclear reg: %d\n", rv);
@@ -676,7 +676,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
676676
}
677677

678678
if (interrupts & LPAIF_IRQ_XRUN(chan)) {
679-
rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val));
679+
rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val));
680680
if (rv) {
681681
dev_err(soc_runtime->dev,
682682
"error writing to irqclear reg: %d\n", rv);
@@ -688,7 +688,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
688688
}
689689

690690
if (interrupts & LPAIF_IRQ_ERR(chan)) {
691-
rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val));
691+
rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val));
692692
if (rv) {
693693
dev_err(soc_runtime->dev,
694694
"error writing to irqclear reg: %d\n", rv);

0 commit comments

Comments
 (0)