ASoC: rsnd: Don't stop HW even if a large number of errors occur
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 26 Oct 2015 08:41:36 +0000 (08:41 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 16 Nov 2015 10:09:29 +0000 (10:09 +0000)
Current SSI/SRC restarts HW if under/over flow happened to avoid L/R
invert issue. But it will stop HW if too many error happen.
But if it stops on HW, other side under/over flow happen. OTHA, it will
be forever loop interrupt if something strange error happen on
HW/driver without escape route of large number error.

To avoid this issue, it indicates error message if large number error
occur, and disables error interrupt.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c

index 3f6993facf697a34cd74ba89b84499b1ebb30f8c..0d96ce5ed9cc7bb81dd55bc7d03d35c7455991ed 100644 (file)
@@ -690,6 +690,8 @@ static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod,
                                      struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
 
        spin_lock(&priv->lock);
 
@@ -698,18 +700,19 @@ static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod,
                goto rsnd_src_interrupt_gen2_out;
 
        if (rsnd_src_error_record_gen2(mod)) {
-               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-               struct rsnd_src *src = rsnd_mod_to_src(mod);
-               struct device *dev = rsnd_priv_to_dev(priv);
 
                dev_dbg(dev, "%s[%d] restart\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
 
                _rsnd_src_stop_gen2(mod);
-               if (src->err < 1024)
-                       _rsnd_src_start_gen2(mod, io);
-               else
-                       dev_warn(dev, "no more SRC restart\n");
+               _rsnd_src_start_gen2(mod, io);
+       }
+
+       if (src->err > 1024) {
+               rsnd_src_irq_disable_gen2(mod);
+
+               dev_warn(dev, "no more %s[%d] restart\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod));
        }
 
 rsnd_src_interrupt_gen2_out:
index c7d943411ae5a1b011e4e096667ef2b66f400e11..86e51ce66b10a9709f9eb9d5d602d9745d238e8e 100644 (file)
@@ -456,6 +456,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
        int is_dma = rsnd_ssi_is_dma_mode(mod);
        u32 status;
        bool elapsed = false;
@@ -489,8 +490,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 
        /* DMA only */
        if (is_dma && (status & (UIRQ | OIRQ))) {
-               struct device *dev = rsnd_priv_to_dev(priv);
-
                /*
                 * restart SSI
                 */
@@ -498,14 +497,18 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
 
                rsnd_ssi_stop(mod, io, priv);
-               if (ssi->err < 1024)
-                       rsnd_ssi_start(mod, io, priv);
-               else
-                       dev_warn(dev, "no more SSI restart\n");
+               rsnd_ssi_start(mod, io, priv);
        }
 
        rsnd_ssi_record_error(ssi, status);
 
+       if (ssi->err > 1024) {
+               rsnd_ssi_irq_disable(mod);
+
+               dev_warn(dev, "no more %s[%d] restart\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod));
+       }
+
 rsnd_ssi_interrupt_out:
        spin_unlock(&priv->lock);