aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2016-01-25 23:56:14 -0500
committerMark Brown <broonie@kernel.org>2016-01-27 07:22:24 -0500
commit6a25c8da00284f5612b404368bd07b69efd84aa2 (patch)
tree3ff27bae3e17cc172db46ac8b1ee5e7e9d45fda2
parent31739a689f828345a7ef52fd8dbbb200df1b6555 (diff)
ASoC: rsnd: don't auto-recover when under/over run error
Renesas R-Car sound needs recovery (= restart) when under/over run error occurred, and current driver tries it on under/over run error handler automatically. But this recovery should be handled by userland, not kernel. This patch stops XRUN when under/over run error occur, and will leave the recovery of HW in userland. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/sh/rcar/src.c39
-rw-r--r--sound/soc/sh/rcar/ssi.c97
2 files changed, 29 insertions, 107 deletions
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 7749615bd404..cccca154e4c3 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -25,7 +25,6 @@ struct rsnd_src {
25 struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ 25 struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
26 struct rsnd_kctrl_cfg_s sync; /* sync convert */ 26 struct rsnd_kctrl_cfg_s sync; /* sync convert */
27 u32 convert_rate; /* sampling rate convert */ 27 u32 convert_rate; /* sampling rate convert */
28 int err;
29 int irq; 28 int irq;
30}; 29};
31 30
@@ -316,7 +315,7 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod)
316 rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); 315 rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
317} 316}
318 317
319static bool rsnd_src_record_error(struct rsnd_mod *mod) 318static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
320{ 319{
321 struct rsnd_src *src = rsnd_mod_to_src(mod); 320 struct rsnd_src *src = rsnd_mod_to_src(mod);
322 u32 val0, val1; 321 u32 val0, val1;
@@ -333,12 +332,8 @@ static bool rsnd_src_record_error(struct rsnd_mod *mod)
333 val0 = val0 & 0xffff; 332 val0 = val0 & 0xffff;
334 333
335 if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) || 334 if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) ||
336 (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) { 335 (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1))
337 struct rsnd_src *src = rsnd_mod_to_src(mod);
338
339 src->err++;
340 ret = true; 336 ret = true;
341 }
342 337
343 return ret; 338 return ret;
344} 339}
@@ -388,8 +383,6 @@ static int rsnd_src_init(struct rsnd_mod *mod,
388 383
389 rsnd_src_irq_enable(mod); 384 rsnd_src_irq_enable(mod);
390 385
391 src->err = 0;
392
393 /* reset sync convert_rate */ 386 /* reset sync convert_rate */
394 src->sync.val = 0; 387 src->sync.val = 0;
395 388
@@ -401,7 +394,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
401 struct rsnd_priv *priv) 394 struct rsnd_priv *priv)
402{ 395{
403 struct rsnd_src *src = rsnd_mod_to_src(mod); 396 struct rsnd_src *src = rsnd_mod_to_src(mod);
404 struct device *dev = rsnd_priv_to_dev(priv);
405 397
406 rsnd_src_irq_disable(mod); 398 rsnd_src_irq_disable(mod);
407 399
@@ -409,10 +401,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
409 401
410 rsnd_mod_power_off(mod); 402 rsnd_mod_power_off(mod);
411 403
412 if (src->err)
413 dev_warn(dev, "%s[%d] under/over flow err = %d\n",
414 rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
415
416 src->convert_rate = 0; 404 src->convert_rate = 0;
417 405
418 /* reset sync convert_rate */ 406 /* reset sync convert_rate */
@@ -425,8 +413,7 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod,
425 struct rsnd_dai_stream *io) 413 struct rsnd_dai_stream *io)
426{ 414{
427 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 415 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
428 struct rsnd_src *src = rsnd_mod_to_src(mod); 416 bool stop = false;
429 struct device *dev = rsnd_priv_to_dev(priv);
430 417
431 spin_lock(&priv->lock); 418 spin_lock(&priv->lock);
432 419
@@ -434,26 +421,16 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod,
434 if (!rsnd_io_is_working(io)) 421 if (!rsnd_io_is_working(io))
435 goto rsnd_src_interrupt_out; 422 goto rsnd_src_interrupt_out;
436 423
437 if (rsnd_src_record_error(mod)) { 424 if (rsnd_src_error_occurred(mod))
438 425 stop = true;
439 dev_dbg(dev, "%s[%d] restart\n",
440 rsnd_mod_name(mod), rsnd_mod_id(mod));
441
442 rsnd_src_stop(mod, io, priv);
443 rsnd_src_start(mod, io, priv);
444 }
445
446 if (src->err > 1024) {
447 rsnd_src_irq_disable(mod);
448
449 dev_warn(dev, "no more %s[%d] restart\n",
450 rsnd_mod_name(mod), rsnd_mod_id(mod));
451 }
452 426
453 rsnd_src_status_clear(mod); 427 rsnd_src_status_clear(mod);
454rsnd_src_interrupt_out: 428rsnd_src_interrupt_out:
455 429
456 spin_unlock(&priv->lock); 430 spin_unlock(&priv->lock);
431
432 if (stop)
433 snd_pcm_stop_xrun(io->substream);
457} 434}
458 435
459static irqreturn_t rsnd_src_interrupt(int irq, void *data) 436static irqreturn_t rsnd_src_interrupt(int irq, void *data)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 90674137aa90..5870434bbc58 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -74,7 +74,6 @@ struct rsnd_ssi {
74 u32 wsr; 74 u32 wsr;
75 int chan; 75 int chan;
76 int rate; 76 int rate;
77 int err;
78 int irq; 77 int irq;
79 unsigned int usrcnt; 78 unsigned int usrcnt;
80}; 79};
@@ -385,8 +384,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
385 if (ret < 0) 384 if (ret < 0)
386 return ret; 385 return ret;
387 386
388 ssi->err = -1; /* ignore 1st error */
389
390 /* clear error status */ 387 /* clear error status */
391 rsnd_ssi_status_clear(mod); 388 rsnd_ssi_status_clear(mod);
392 389
@@ -409,13 +406,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
409 } 406 }
410 407
411 if (!rsnd_ssi_is_parent(mod, io)) { 408 if (!rsnd_ssi_is_parent(mod, io)) {
412 if (ssi->err > 0)
413 dev_warn(dev, "%s[%d] under/over flow err = %d\n",
414 rsnd_mod_name(mod), rsnd_mod_id(mod),
415 ssi->err);
416
417 ssi->cr_own = 0; 409 ssi->cr_own = 0;
418 ssi->err = 0;
419 410
420 rsnd_ssi_irq_disable(mod); 411 rsnd_ssi_irq_disable(mod);
421 } 412 }
@@ -455,21 +446,9 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
455 return 0; 446 return 0;
456} 447}
457 448
458static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) 449static int rsnd_ssi_start(struct rsnd_mod *mod,
459{ 450 struct rsnd_dai_stream *io,
460 struct rsnd_mod *mod = rsnd_mod_get(ssi); 451 struct rsnd_priv *priv)
461 u32 status = rsnd_ssi_status_get(mod);
462
463 /* under/over flow error */
464 if (status & (UIRQ | OIRQ))
465 ssi->err++;
466
467 return status;
468}
469
470static int __rsnd_ssi_start(struct rsnd_mod *mod,
471 struct rsnd_dai_stream *io,
472 struct rsnd_priv *priv)
473{ 452{
474 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); 453 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
475 u32 cr; 454 u32 cr;
@@ -491,25 +470,21 @@ static int __rsnd_ssi_start(struct rsnd_mod *mod,
491 return 0; 470 return 0;
492} 471}
493 472
494static int rsnd_ssi_start(struct rsnd_mod *mod, 473static int rsnd_ssi_stop(struct rsnd_mod *mod,
495 struct rsnd_dai_stream *io, 474 struct rsnd_dai_stream *io,
496 struct rsnd_priv *priv) 475 struct rsnd_priv *priv)
497{ 476{
477 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
478 u32 cr;
479
498 /* 480 /*
499 * no limit to start 481 * don't stop if not last user
500 * see also 482 * see also
501 * rsnd_ssi_stop 483 * rsnd_ssi_start
502 * rsnd_ssi_interrupt 484 * rsnd_ssi_interrupt
503 */ 485 */
504 return __rsnd_ssi_start(mod, io, priv); 486 if (ssi->usrcnt > 1)
505} 487 return 0;
506
507static int __rsnd_ssi_stop(struct rsnd_mod *mod,
508 struct rsnd_dai_stream *io,
509 struct rsnd_priv *priv)
510{
511 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
512 u32 cr;
513 488
514 /* 489 /*
515 * disable all IRQ, 490 * disable all IRQ,
@@ -531,33 +506,14 @@ static int __rsnd_ssi_stop(struct rsnd_mod *mod,
531 return 0; 506 return 0;
532} 507}
533 508
534static int rsnd_ssi_stop(struct rsnd_mod *mod,
535 struct rsnd_dai_stream *io,
536 struct rsnd_priv *priv)
537{
538 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
539
540 /*
541 * don't stop if not last user
542 * see also
543 * rsnd_ssi_start
544 * rsnd_ssi_interrupt
545 */
546 if (ssi->usrcnt > 1)
547 return 0;
548
549 return __rsnd_ssi_stop(mod, io, priv);
550}
551
552static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, 509static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
553 struct rsnd_dai_stream *io) 510 struct rsnd_dai_stream *io)
554{ 511{
555 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
556 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 512 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
557 struct device *dev = rsnd_priv_to_dev(priv);
558 int is_dma = rsnd_ssi_is_dma_mode(mod); 513 int is_dma = rsnd_ssi_is_dma_mode(mod);
559 u32 status; 514 u32 status;
560 bool elapsed = false; 515 bool elapsed = false;
516 bool stop = false;
561 517
562 spin_lock(&priv->lock); 518 spin_lock(&priv->lock);
563 519
@@ -565,7 +521,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
565 if (!rsnd_io_is_working(io)) 521 if (!rsnd_io_is_working(io))
566 goto rsnd_ssi_interrupt_out; 522 goto rsnd_ssi_interrupt_out;
567 523
568 status = rsnd_ssi_record_error(ssi); 524 status = rsnd_ssi_status_get(mod);
569 525
570 /* PIO only */ 526 /* PIO only */
571 if (!is_dma && (status & DIRQ)) { 527 if (!is_dma && (status & DIRQ)) {
@@ -587,23 +543,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
587 } 543 }
588 544
589 /* DMA only */ 545 /* DMA only */
590 if (is_dma && (status & (UIRQ | OIRQ))) { 546 if (is_dma && (status & (UIRQ | OIRQ)))
591 /* 547 stop = true;
592 * restart SSI
593 */
594 dev_dbg(dev, "%s[%d] restart\n",
595 rsnd_mod_name(mod), rsnd_mod_id(mod));
596
597 __rsnd_ssi_stop(mod, io, priv);
598 __rsnd_ssi_start(mod, io, priv);
599 }
600
601 if (ssi->err > 1024) {
602 rsnd_ssi_irq_disable(mod);
603
604 dev_warn(dev, "no more %s[%d] restart\n",
605 rsnd_mod_name(mod), rsnd_mod_id(mod));
606 }
607 548
608 rsnd_ssi_status_clear(mod); 549 rsnd_ssi_status_clear(mod);
609rsnd_ssi_interrupt_out: 550rsnd_ssi_interrupt_out:
@@ -611,6 +552,10 @@ rsnd_ssi_interrupt_out:
611 552
612 if (elapsed) 553 if (elapsed)
613 rsnd_dai_period_elapsed(io); 554 rsnd_dai_period_elapsed(io);
555
556 if (stop)
557 snd_pcm_stop_xrun(io->substream);
558
614} 559}
615 560
616static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) 561static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)