diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2016-01-25 23:56:14 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-01-27 07:22:24 -0500 |
commit | 6a25c8da00284f5612b404368bd07b69efd84aa2 (patch) | |
tree | 3ff27bae3e17cc172db46ac8b1ee5e7e9d45fda2 | |
parent | 31739a689f828345a7ef52fd8dbbb200df1b6555 (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.c | 39 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 97 |
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 | ||
319 | static bool rsnd_src_record_error(struct rsnd_mod *mod) | 318 | static 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); |
454 | rsnd_src_interrupt_out: | 428 | rsnd_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 | ||
459 | static irqreturn_t rsnd_src_interrupt(int irq, void *data) | 436 | static 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 | ||
458 | static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) | 449 | static 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 | |||
470 | static 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 | ||
494 | static int rsnd_ssi_start(struct rsnd_mod *mod, | 473 | static 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 | |||
507 | static 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 | ||
534 | static 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 | |||
552 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | 509 | static 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); |
609 | rsnd_ssi_interrupt_out: | 550 | rsnd_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 | ||
616 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | 561 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) |