aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-cache.c
diff options
context:
space:
mode:
authorDimitris Papastamos <dp@opensource.wolfsonmicro.com>2011-05-19 08:45:29 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-05-20 06:21:53 -0400
commit0944cc392e9a41dd36b65b2f8cb31dff437a9fdb (patch)
tree5ccf873f15156e9f525025b55adf6c5199af1777 /sound/soc/soc-cache.c
parent0f3c6af92100193cf9a86bdd0ee35e6da3e0c56e (diff)
ASoC: soc-cache: Block based rbtree compression
This patch prepares the ground for the actual rbtree optimization patch which will save a pointer to the last accessed rbnode that was used in either the read() or write() functions. Each rbnode manages a variable length block of registers. There can be no two nodes with overlapping blocks. Each block has a base register and a currently top register, all the other registers, if any, lie in between these two and in ascending order. The reasoning behind the construction of this rbtree is simple. In the snd_soc_rbtree_cache_init() function, we iterate over the register defaults provided by the driver. For each register value that is non-zero we insert it in the rbtree. In order to determine in which rbnode we need to add the register, we first look if there is another register already added that is adjacent to the one we are about to add. If that is the case we append it in that rbnode block, otherwise we create a new rbnode with a single register in its block and add it to the tree. In the next patch, where a cached rbnode is used by both the write() and the read() functions, we also check if the register we are about to add is in the cached rbnode (the least recently accessed one) and if so we append it in that rbnode block. Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/soc-cache.c')
-rw-r--r--sound/soc/soc-cache.c232
1 files changed, 177 insertions, 55 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 687beec56476..78c9869615df 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -595,31 +595,85 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
595} 595}
596 596
597struct snd_soc_rbtree_node { 597struct snd_soc_rbtree_node {
598 struct rb_node node; 598 struct rb_node node; /* the actual rbtree node holding this block */
599 unsigned int reg; 599 unsigned int base_reg; /* base register handled by this block */
600 unsigned int value; 600 unsigned int word_size; /* number of bytes needed to represent the register index */
601 unsigned int defval; 601 void *block; /* block of adjacent registers */
602 unsigned int blklen; /* number of registers available in the block */
602} __attribute__ ((packed)); 603} __attribute__ ((packed));
603 604
604struct snd_soc_rbtree_ctx { 605struct snd_soc_rbtree_ctx {
605 struct rb_root root; 606 struct rb_root root;
606}; 607};
607 608
609static inline void snd_soc_rbtree_get_base_top_reg(
610 struct snd_soc_rbtree_node *rbnode,
611 unsigned int *base, unsigned int *top)
612{
613 *base = rbnode->base_reg;
614 *top = rbnode->base_reg + rbnode->blklen - 1;
615}
616
617static unsigned int snd_soc_rbtree_get_register(
618 struct snd_soc_rbtree_node *rbnode, unsigned int idx)
619{
620 unsigned int val;
621
622 switch (rbnode->word_size) {
623 case 1: {
624 u8 *p = rbnode->block;
625 val = p[idx];
626 return val;
627 }
628 case 2: {
629 u16 *p = rbnode->block;
630 val = p[idx];
631 return val;
632 }
633 default:
634 BUG();
635 break;
636 }
637 return -1;
638}
639
640static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
641 unsigned int idx, unsigned int val)
642{
643 switch (rbnode->word_size) {
644 case 1: {
645 u8 *p = rbnode->block;
646 p[idx] = val;
647 break;
648 }
649 case 2: {
650 u16 *p = rbnode->block;
651 p[idx] = val;
652 break;
653 }
654 default:
655 BUG();
656 break;
657 }
658}
659
608static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup( 660static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
609 struct rb_root *root, unsigned int reg) 661 struct rb_root *root, unsigned int reg)
610{ 662{
611 struct rb_node *node; 663 struct rb_node *node;
612 struct snd_soc_rbtree_node *rbnode; 664 struct snd_soc_rbtree_node *rbnode;
665 unsigned int base_reg, top_reg;
613 666
614 node = root->rb_node; 667 node = root->rb_node;
615 while (node) { 668 while (node) {
616 rbnode = container_of(node, struct snd_soc_rbtree_node, node); 669 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
617 if (rbnode->reg < reg) 670 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
618 node = node->rb_left; 671 if (reg >= base_reg && reg <= top_reg)
619 else if (rbnode->reg > reg)
620 node = node->rb_right;
621 else
622 return rbnode; 672 return rbnode;
673 else if (reg > top_reg)
674 node = node->rb_right;
675 else if (reg < base_reg)
676 node = node->rb_left;
623 } 677 }
624 678
625 return NULL; 679 return NULL;
@@ -630,19 +684,28 @@ static int snd_soc_rbtree_insert(struct rb_root *root,
630{ 684{
631 struct rb_node **new, *parent; 685 struct rb_node **new, *parent;
632 struct snd_soc_rbtree_node *rbnode_tmp; 686 struct snd_soc_rbtree_node *rbnode_tmp;
687 unsigned int base_reg_tmp, top_reg_tmp;
688 unsigned int base_reg;
633 689
634 parent = NULL; 690 parent = NULL;
635 new = &root->rb_node; 691 new = &root->rb_node;
636 while (*new) { 692 while (*new) {
637 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node, 693 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
638 node); 694 node);
695 /* base and top registers of the current rbnode */
696 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
697 &top_reg_tmp);
698 /* base register of the rbnode to be added */
699 base_reg = rbnode->base_reg;
639 parent = *new; 700 parent = *new;
640 if (rbnode_tmp->reg < rbnode->reg) 701 /* if this register has already been inserted, just return */
641 new = &((*new)->rb_left); 702 if (base_reg >= base_reg_tmp &&
642 else if (rbnode_tmp->reg > rbnode->reg) 703 base_reg <= top_reg_tmp)
643 new = &((*new)->rb_right);
644 else
645 return 0; 704 return 0;
705 else if (base_reg > top_reg_tmp)
706 new = &((*new)->rb_right);
707 else if (base_reg < base_reg_tmp)
708 new = &((*new)->rb_left);
646 } 709 }
647 710
648 /* insert the node into the rbtree */ 711 /* insert the node into the rbtree */
@@ -657,57 +720,120 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
657 struct snd_soc_rbtree_ctx *rbtree_ctx; 720 struct snd_soc_rbtree_ctx *rbtree_ctx;
658 struct rb_node *node; 721 struct rb_node *node;
659 struct snd_soc_rbtree_node *rbnode; 722 struct snd_soc_rbtree_node *rbnode;
723 unsigned int regtmp;
660 unsigned int val; 724 unsigned int val;
661 int ret; 725 int ret;
726 int i;
662 727
663 rbtree_ctx = codec->reg_cache; 728 rbtree_ctx = codec->reg_cache;
664 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { 729 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
665 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); 730 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
666 if (rbnode->value == rbnode->defval) 731 for (i = 0; i < rbnode->blklen; ++i) {
667 continue; 732 regtmp = rbnode->base_reg + i;
668 WARN_ON(codec->writable_register && 733 WARN_ON(codec->writable_register &&
669 codec->writable_register(codec, rbnode->reg)); 734 codec->writable_register(codec, regtmp));
670 ret = snd_soc_cache_read(codec, rbnode->reg, &val); 735 val = snd_soc_rbtree_get_register(rbnode, i);
671 if (ret) 736 codec->cache_bypass = 1;
672 return ret; 737 ret = snd_soc_write(codec, regtmp, val);
673 codec->cache_bypass = 1; 738 codec->cache_bypass = 0;
674 ret = snd_soc_write(codec, rbnode->reg, val); 739 if (ret)
675 codec->cache_bypass = 0; 740 return ret;
676 if (ret) 741 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
677 return ret; 742 regtmp, val);
678 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", 743 }
679 rbnode->reg, val);
680 } 744 }
681 745
682 return 0; 746 return 0;
683} 747}
684 748
749static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
750 unsigned int pos, unsigned int reg,
751 unsigned int value)
752{
753 u8 *blk;
754
755 blk = krealloc(rbnode->block,
756 (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
757 if (!blk)
758 return -ENOMEM;
759
760 /* insert the register value in the correct place in the rbnode block */
761 memmove(blk + (pos + 1) * rbnode->word_size,
762 blk + pos * rbnode->word_size,
763 (rbnode->blklen - pos) * rbnode->word_size);
764
765 /* update the rbnode block, its size and the base register */
766 rbnode->block = blk;
767 rbnode->blklen++;
768 if (!pos)
769 rbnode->base_reg = reg;
770
771 snd_soc_rbtree_set_register(rbnode, pos, value);
772 return 0;
773}
774
685static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, 775static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
686 unsigned int reg, unsigned int value) 776 unsigned int reg, unsigned int value)
687{ 777{
688 struct snd_soc_rbtree_ctx *rbtree_ctx; 778 struct snd_soc_rbtree_ctx *rbtree_ctx;
689 struct snd_soc_rbtree_node *rbnode; 779 struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
780 struct rb_node *node;
781 unsigned int val;
782 unsigned int reg_tmp;
783 unsigned int pos;
784 int i;
785 int ret;
690 786
691 rbtree_ctx = codec->reg_cache; 787 rbtree_ctx = codec->reg_cache;
692 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); 788 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
693 if (rbnode) { 789 if (rbnode) {
694 if (rbnode->value == value) 790 reg_tmp = reg - rbnode->base_reg;
791 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
792 if (val == value)
695 return 0; 793 return 0;
696 rbnode->value = value; 794 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
697 } else { 795 } else {
698 /* bail out early, no need to create the rbnode yet */ 796 /* bail out early, no need to create the rbnode yet */
699 if (!value) 797 if (!value)
700 return 0; 798 return 0;
701 /* 799 /* look for an adjacent register to the one we are about to add */
702 * for uninitialized registers whose value is changed 800 for (node = rb_first(&rbtree_ctx->root); node;
703 * from the default zero, create an rbnode and insert 801 node = rb_next(node)) {
704 * it into the tree. 802 rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
803 for (i = 0; i < rbnode_tmp->blklen; ++i) {
804 reg_tmp = rbnode_tmp->base_reg + i;
805 if (abs(reg_tmp - reg) != 1)
806 continue;
807 /* decide where in the block to place our register */
808 if (reg_tmp + 1 == reg)
809 pos = i + 1;
810 else
811 pos = i;
812 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
813 reg, value);
814 if (ret)
815 return ret;
816 return 0;
817 }
818 }
819 /* we did not manage to find a place to insert it in an existing
820 * block so create a new rbnode with a single register in its block.
821 * This block will get populated further if any other adjacent
822 * registers get modified in the future.
705 */ 823 */
706 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); 824 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
707 if (!rbnode) 825 if (!rbnode)
708 return -ENOMEM; 826 return -ENOMEM;
709 rbnode->reg = reg; 827 rbnode->blklen = 1;
710 rbnode->value = value; 828 rbnode->base_reg = reg;
829 rbnode->word_size = codec->driver->reg_word_size;
830 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
831 GFP_KERNEL);
832 if (!rbnode->block) {
833 kfree(rbnode);
834 return -ENOMEM;
835 }
836 snd_soc_rbtree_set_register(rbnode, 0, value);
711 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode); 837 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
712 } 838 }
713 839
@@ -719,11 +845,13 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
719{ 845{
720 struct snd_soc_rbtree_ctx *rbtree_ctx; 846 struct snd_soc_rbtree_ctx *rbtree_ctx;
721 struct snd_soc_rbtree_node *rbnode; 847 struct snd_soc_rbtree_node *rbnode;
848 unsigned int reg_tmp;
722 849
723 rbtree_ctx = codec->reg_cache; 850 rbtree_ctx = codec->reg_cache;
724 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); 851 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
725 if (rbnode) { 852 if (rbnode) {
726 *value = rbnode->value; 853 reg_tmp = reg - rbnode->base_reg;
854 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
727 } else { 855 } else {
728 /* uninitialized registers default to 0 */ 856 /* uninitialized registers default to 0 */
729 *value = 0; 857 *value = 0;
@@ -749,6 +877,7 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
749 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node); 877 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
750 next = rb_next(&rbtree_node->node); 878 next = rb_next(&rbtree_node->node);
751 rb_erase(&rbtree_node->node, &rbtree_ctx->root); 879 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
880 kfree(rbtree_node->block);
752 kfree(rbtree_node); 881 kfree(rbtree_node);
753 } 882 }
754 883
@@ -761,10 +890,9 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
761 890
762static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) 891static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
763{ 892{
764 struct snd_soc_rbtree_node *rbtree_node;
765 struct snd_soc_rbtree_ctx *rbtree_ctx; 893 struct snd_soc_rbtree_ctx *rbtree_ctx;
766 unsigned int val;
767 unsigned int word_size; 894 unsigned int word_size;
895 unsigned int val;
768 int i; 896 int i;
769 int ret; 897 int ret;
770 898
@@ -778,28 +906,22 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
778 if (!codec->reg_def_copy) 906 if (!codec->reg_def_copy)
779 return 0; 907 return 0;
780 908
781 /*
782 * populate the rbtree with the initialized registers. All other
783 * registers will be inserted when they are first modified.
784 */
785 word_size = codec->driver->reg_word_size; 909 word_size = codec->driver->reg_word_size;
786 for (i = 0; i < codec->driver->reg_cache_size; ++i) { 910 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
787 val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); 911 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
912 word_size);
788 if (!val) 913 if (!val)
789 continue; 914 continue;
790 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); 915 ret = snd_soc_rbtree_cache_write(codec, i, val);
791 if (!rbtree_node) { 916 if (ret)
792 ret = -ENOMEM; 917 goto err;
793 snd_soc_cache_exit(codec);
794 break;
795 }
796 rbtree_node->reg = i;
797 rbtree_node->value = val;
798 rbtree_node->defval = val;
799 snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
800 } 918 }
801 919
802 return 0; 920 return 0;
921
922err:
923 snd_soc_cache_exit(codec);
924 return ret;
803} 925}
804 926
805#ifdef CONFIG_SND_SOC_CACHE_LZO 927#ifdef CONFIG_SND_SOC_CACHE_LZO