summaryrefslogtreecommitdiffstats
path: root/include/sound
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2015-08-11 15:38:00 -0400
committerMark Brown <broonie@kernel.org>2015-08-13 07:40:16 -0400
commita3423b02cf745c1418f1f199646c450d6fc9ca4e (patch)
treefb31992296571629eebadfcc082802c13602d85a /include/sound
parent30abbe7727b23c6661daeea5d36be36ed7a41665 (diff)
ASoC: dapm: Consolidate input and output path handling
After the recent cleanups and generalizations of the DAPM algorithm the handling of input and output paths is now fully symmetric. This means by making some slight changes to the data structure and using arrays with one entry for each direction, rather than separate fields, it is possible to create a generic implementation that is capable of handling both input and output paths. Unfortunately this generalization significantly increases the code size on the hot path of is_connected_{input,output}_ep() and dapm_widget_invalidate_{input,output}_paths(), which has a negative impact on the overall performance. The inner loops of those functions are quite small and the generic implementation adds extra pointer arithmetic in a few places. Testing on ARM shows that the combined code size of the specialized functions is about 50% larger than the generalized function in relative numbers. But in absolute numbers its less than 200 bytes, which is still quite small. On the other hand the generalized function increases the execution time of dapm_power_one_widget() by 30%. Given that this function is one of the most often called functions of the DAPM framework the trade-off of getting better performance at expense of generating slightly larger code at seems to be worth it. To avoid this still keep two versions of these functions around, one for input and one for output. But have a generic implementation of the algorithm which gets inlined by those two versions. And then let the compiler take care of optimizing it and removing he extra instructions. This still reduces the source code size as well as the makes making changes to the implementation more straight forward since the same change does no longer need to be done in two separate places. Also on the slow paths we can use a generic implementations that handle both input and output paths. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'include/sound')
-rw-r--r--include/sound/soc-dapm.h69
1 files changed, 55 insertions, 14 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 4973083d89ce..5abba037d245 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -512,9 +512,18 @@ struct snd_soc_dapm_route {
512struct snd_soc_dapm_path { 512struct snd_soc_dapm_path {
513 const char *name; 513 const char *name;
514 514
515 /* source (input) and sink (output) widgets */ 515 /*
516 struct snd_soc_dapm_widget *source; 516 * source (input) and sink (output) widgets
517 struct snd_soc_dapm_widget *sink; 517 * The union is for convience, since it is a lot nicer to type
518 * p->source, rather than p->node[SND_SOC_DAPM_DIR_IN]
519 */
520 union {
521 struct {
522 struct snd_soc_dapm_widget *source;
523 struct snd_soc_dapm_widget *sink;
524 };
525 struct snd_soc_dapm_widget *node[2];
526 };
518 527
519 /* status */ 528 /* status */
520 u32 connect:1; /* source and sink widgets are connected */ 529 u32 connect:1; /* source and sink widgets are connected */
@@ -525,8 +534,7 @@ struct snd_soc_dapm_path {
525 int (*connected)(struct snd_soc_dapm_widget *source, 534 int (*connected)(struct snd_soc_dapm_widget *source,
526 struct snd_soc_dapm_widget *sink); 535 struct snd_soc_dapm_widget *sink);
527 536
528 struct list_head list_source; 537 struct list_head list_node[2];
529 struct list_head list_sink;
530 struct list_head list_kcontrol; 538 struct list_head list_kcontrol;
531 struct list_head list; 539 struct list_head list;
532}; 540};
@@ -560,8 +568,7 @@ struct snd_soc_dapm_widget {
560 unsigned char new_power:1; /* power from this run */ 568 unsigned char new_power:1; /* power from this run */
561 unsigned char power_checked:1; /* power checked this run */ 569 unsigned char power_checked:1; /* power checked this run */
562 unsigned char is_supply:1; /* Widget is a supply type widget */ 570 unsigned char is_supply:1; /* Widget is a supply type widget */
563 unsigned char is_sink:1; /* Widget is a sink type widget */ 571 unsigned char is_ep:2; /* Widget is a endpoint type widget */
564 unsigned char is_source:1; /* Widget is a source type widget */
565 int subseq; /* sort within widget type */ 572 int subseq; /* sort within widget type */
566 573
567 int (*power_check)(struct snd_soc_dapm_widget *w); 574 int (*power_check)(struct snd_soc_dapm_widget *w);
@@ -576,16 +583,14 @@ struct snd_soc_dapm_widget {
576 struct snd_kcontrol **kcontrols; 583 struct snd_kcontrol **kcontrols;
577 struct snd_soc_dobj dobj; 584 struct snd_soc_dobj dobj;
578 585
579 /* widget input and outputs */ 586 /* widget input and output edges */
580 struct list_head sources; 587 struct list_head edges[2];
581 struct list_head sinks;
582 588
583 /* used during DAPM updates */ 589 /* used during DAPM updates */
584 struct list_head work_list; 590 struct list_head work_list;
585 struct list_head power_list; 591 struct list_head power_list;
586 struct list_head dirty; 592 struct list_head dirty;
587 int inputs; 593 int endpoints[2];
588 int outputs;
589 594
590 struct clk *clk; 595 struct clk *clk;
591}; 596};
@@ -673,6 +678,42 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
673 return dapm->bias_level; 678 return dapm->bias_level;
674} 679}
675 680
681enum snd_soc_dapm_direction {
682 SND_SOC_DAPM_DIR_IN,
683 SND_SOC_DAPM_DIR_OUT
684};
685
686#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x)
687
688#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
689#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
690
691/**
692 * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the
693 * specified direction of a widget
694 * @w: The widget
695 * @dir: Whether to iterate over the paths where the specified widget is the
696 * incoming or outgoing widgets
697 * @p: The path iterator variable
698 */
699#define snd_soc_dapm_widget_for_each_path(w, dir, p) \
700 list_for_each_entry(p, &w->edges[dir], list_node[dir])
701
702/**
703 * snd_soc_dapm_widget_for_each_sink_path_safe - Iterates over all paths in the
704 * specified direction of a widget
705 * @w: The widget
706 * @dir: Whether to iterate over the paths where the specified widget is the
707 * incoming or outgoing widgets
708 * @p: The path iterator variable
709 * @next_p: Temporary storage for the next path
710 *
711 * This function works like snd_soc_dapm_widget_for_each_sink_path, expect that
712 * it is safe to remove the current path from the list while iterating
713 */
714#define snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) \
715 list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir])
716
676/** 717/**
677 * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a 718 * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a
678 * widget 719 * widget
@@ -680,7 +721,7 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
680 * @p: The path iterator variable 721 * @p: The path iterator variable
681 */ 722 */
682#define snd_soc_dapm_widget_for_each_sink_path(w, p) \ 723#define snd_soc_dapm_widget_for_each_sink_path(w, p) \
683 list_for_each_entry(p, &w->sinks, list_source) 724 snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_IN, p)
684 725
685/** 726/**
686 * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to 727 * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to
@@ -689,6 +730,6 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
689 * @p: The path iterator variable 730 * @p: The path iterator variable
690 */ 731 */
691#define snd_soc_dapm_widget_for_each_source_path(w, p) \ 732#define snd_soc_dapm_widget_for_each_source_path(w, p) \
692 list_for_each_entry(p, &w->sources, list_sink) 733 snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_OUT, p)
693 734
694#endif 735#endif