aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitris Papastamos <dp@opensource.wolfsonmicro.com>2011-07-24 15:59:27 -0400
committerPaolo Pisati <paolo.pisati@canonical.com>2012-08-17 04:18:13 -0400
commita8232e7afef8dc27349cd9969664133330e49561 (patch)
treea2e0d6779667d32ec935cb1cb750c9911d2a3171
parentf4646ffb3b100d23d64217edbdde2b1ae024fb60 (diff)
Subject: [PATCH 001/104] 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>
-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 039b9532b27..aa161703d9b 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -483,31 +483,85 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
483} 483}
484 484
485struct snd_soc_rbtree_node { 485struct snd_soc_rbtree_node {
486 struct rb_node node; 486 struct rb_node node; /* the actual rbtree node holding this block */
487 unsigned int reg; 487 unsigned int base_reg; /* base register handled by this block */
488 unsigned int value; 488 unsigned int word_size; /* number of bytes needed to represent the register index */
489 unsigned int defval; 489 void *block; /* block of adjacent registers */
490 unsigned int blklen; /* number of registers available in the block */
490} __attribute__ ((packed)); 491} __attribute__ ((packed));
491 492
492struct snd_soc_rbtree_ctx { 493struct snd_soc_rbtree_ctx {
493 struct rb_root root; 494 struct rb_root root;
494}; 495};
495 496
497static inline void snd_soc_rbtree_get_base_top_reg(
498 struct snd_soc_rbtree_node *rbnode,
499 unsigned int *base, unsigned int *top)
500{
501 *base = rbnode->base_reg;
502 *top = rbnode->base_reg + rbnode->blklen - 1;
503}
504
505static unsigned int snd_soc_rbtree_get_register(
506 struct snd_soc_rbtree_node *rbnode, unsigned int idx)
507{
508 unsigned int val;
509
510 switch (rbnode->word_size) {
511 case 1: {
512 u8 *p = rbnode->block;
513 val = p[idx];
514 return val;
515 }
516 case 2: {
517 u16 *p = rbnode->block;
518 val = p[idx];
519 return val;
520 }
521 default:
522 BUG();
523 break;
524 }
525 return -1;
526}
527
528static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
529 unsigned int idx, unsigned int val)
530{
531 switch (rbnode->word_size) {
532 case 1: {
533 u8 *p = rbnode->block;
534 p[idx] = val;
535 break;
536 }
537 case 2: {
538 u16 *p = rbnode->block;
539 p[idx] = val;
540 break;
541 }
542 default:
543 BUG();
544 break;
545 }
546}
547
496static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup( 548static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
497 struct rb_root *root, unsigned int reg) 549 struct rb_root *root, unsigned int reg)
498{ 550{
499 struct rb_node *node; 551 struct rb_node *node;
500 struct snd_soc_rbtree_node *rbnode; 552 struct snd_soc_rbtree_node *rbnode;
553 unsigned int base_reg, top_reg;
501 554
502 node = root->rb_node; 555 node = root->rb_node;
503 while (node) { 556 while (node) {
504 rbnode = container_of(node, struct snd_soc_rbtree_node, node); 557 rbnode = container_of(node, struct snd_soc_rbtree_node, node);
505 if (rbnode->reg < reg) 558 snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
506 node = node->rb_left; 559 if (reg >= base_reg && reg <= top_reg)
507 else if (rbnode->reg > reg)
508 node = node->rb_right;
509 else
510 return rbnode; 560 return rbnode;
561 else if (reg > top_reg)
562 node = node->rb_right;
563 else if (reg < base_reg)
564 node = node->rb_left;
511 } 565 }
512 566
513 return NULL; 567 return NULL;
@@ -518,19 +572,28 @@ static int snd_soc_rbtree_insert(struct rb_root *root,
518{ 572{
519 struct rb_node **new, *parent; 573 struct rb_node **new, *parent;
520 struct snd_soc_rbtree_node *rbnode_tmp; 574 struct snd_soc_rbtree_node *rbnode_tmp;
575 unsigned int base_reg_tmp, top_reg_tmp;
576 unsigned int base_reg;
521 577
522 parent = NULL; 578 parent = NULL;
523 new = &root->rb_node; 579 new = &root->rb_node;
524 while (*new) { 580 while (*new) {
525 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node, 581 rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
526 node); 582 node);
583 /* base and top registers of the current rbnode */
584 snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
585 &top_reg_tmp);
586 /* base register of the rbnode to be added */
587 base_reg = rbnode->base_reg;
527 parent = *new; 588 parent = *new;
528 if (rbnode_tmp->reg < rbnode->reg) 589 /* if this register has already been inserted, just return */
529 new = &((*new)->rb_left); 590 if (base_reg >= base_reg_tmp &&
530 else if (rbnode_tmp->reg > rbnode->reg) 591 base_reg <= top_reg_tmp)
531 new = &((*new)->rb_right);
532 else
533 return 0; 592 return 0;
593 else if (base_reg > top_reg_tmp)
594 new = &((*new)->rb_right);
595 else if (base_reg < base_reg_tmp)
596 new = &((*new)->rb_left);
534 } 597 }
535 598
536 /* insert the node into the rbtree */ 599 /* insert the node into the rbtree */
@@ -545,57 +608,120 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
545 struct snd_soc_rbtree_ctx *rbtree_ctx; 608 struct snd_soc_rbtree_ctx *rbtree_ctx;
546 struct rb_node *node; 609 struct rb_node *node;
547 struct snd_soc_rbtree_node *rbnode; 610 struct snd_soc_rbtree_node *rbnode;
611 unsigned int regtmp;
548 unsigned int val; 612 unsigned int val;
549 int ret; 613 int ret;
614 int i;
550 615
551 rbtree_ctx = codec->reg_cache; 616 rbtree_ctx = codec->reg_cache;
552 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { 617 for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
553 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); 618 rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
554 if (rbnode->value == rbnode->defval) 619 for (i = 0; i < rbnode->blklen; ++i) {
555 continue; 620 regtmp = rbnode->base_reg + i;
556 WARN_ON(codec->writable_register && 621 WARN_ON(codec->writable_register &&
557 codec->writable_register(codec, rbnode->reg)); 622 codec->writable_register(codec, regtmp));
558 ret = snd_soc_cache_read(codec, rbnode->reg, &val); 623 val = snd_soc_rbtree_get_register(rbnode, i);
559 if (ret) 624 codec->cache_bypass = 1;
560 return ret; 625 ret = snd_soc_write(codec, regtmp, val);
561 codec->cache_bypass = 1; 626 codec->cache_bypass = 0;
562 ret = snd_soc_write(codec, rbnode->reg, val); 627 if (ret)
563 codec->cache_bypass = 0; 628 return ret;
564 if (ret) 629 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
565 return ret; 630 regtmp, val);
566 dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", 631 }
567 rbnode->reg, val);
568 } 632 }
569 633
570 return 0; 634 return 0;
571} 635}
572 636
637static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
638 unsigned int pos, unsigned int reg,
639 unsigned int value)
640{
641 u8 *blk;
642
643 blk = krealloc(rbnode->block,
644 (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
645 if (!blk)
646 return -ENOMEM;
647
648 /* insert the register value in the correct place in the rbnode block */
649 memmove(blk + (pos + 1) * rbnode->word_size,
650 blk + pos * rbnode->word_size,
651 (rbnode->blklen - pos) * rbnode->word_size);
652
653 /* update the rbnode block, its size and the base register */
654 rbnode->block = blk;
655 rbnode->blklen++;
656 if (!pos)
657 rbnode->base_reg = reg;
658
659 snd_soc_rbtree_set_register(rbnode, pos, value);
660 return 0;
661}
662
573static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, 663static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
574 unsigned int reg, unsigned int value) 664 unsigned int reg, unsigned int value)
575{ 665{
576 struct snd_soc_rbtree_ctx *rbtree_ctx; 666 struct snd_soc_rbtree_ctx *rbtree_ctx;
577 struct snd_soc_rbtree_node *rbnode; 667 struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
668 struct rb_node *node;
669 unsigned int val;
670 unsigned int reg_tmp;
671 unsigned int pos;
672 int i;
673 int ret;
578 674
579 rbtree_ctx = codec->reg_cache; 675 rbtree_ctx = codec->reg_cache;
580 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); 676 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
581 if (rbnode) { 677 if (rbnode) {
582 if (rbnode->value == value) 678 reg_tmp = reg - rbnode->base_reg;
679 val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
680 if (val == value)
583 return 0; 681 return 0;
584 rbnode->value = value; 682 snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
585 } else { 683 } else {
586 /* bail out early, no need to create the rbnode yet */ 684 /* bail out early, no need to create the rbnode yet */
587 if (!value) 685 if (!value)
588 return 0; 686 return 0;
589 /* 687 /* look for an adjacent register to the one we are about to add */
590 * for uninitialized registers whose value is changed 688 for (node = rb_first(&rbtree_ctx->root); node;
591 * from the default zero, create an rbnode and insert 689 node = rb_next(node)) {
592 * it into the tree. 690 rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
691 for (i = 0; i < rbnode_tmp->blklen; ++i) {
692 reg_tmp = rbnode_tmp->base_reg + i;
693 if (abs(reg_tmp - reg) != 1)
694 continue;
695 /* decide where in the block to place our register */
696 if (reg_tmp + 1 == reg)
697 pos = i + 1;
698 else
699 pos = i;
700 ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
701 reg, value);
702 if (ret)
703 return ret;
704 return 0;
705 }
706 }
707 /* we did not manage to find a place to insert it in an existing
708 * block so create a new rbnode with a single register in its block.
709 * This block will get populated further if any other adjacent
710 * registers get modified in the future.
593 */ 711 */
594 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); 712 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
595 if (!rbnode) 713 if (!rbnode)
596 return -ENOMEM; 714 return -ENOMEM;
597 rbnode->reg = reg; 715 rbnode->blklen = 1;
598 rbnode->value = value; 716 rbnode->base_reg = reg;
717 rbnode->word_size = codec->driver->reg_word_size;
718 rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
719 GFP_KERNEL);
720 if (!rbnode->block) {
721 kfree(rbnode);
722 return -ENOMEM;
723 }
724 snd_soc_rbtree_set_register(rbnode, 0, value);
599 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode); 725 snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
600 } 726 }
601 727
@@ -607,11 +733,13 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
607{ 733{
608 struct snd_soc_rbtree_ctx *rbtree_ctx; 734 struct snd_soc_rbtree_ctx *rbtree_ctx;
609 struct snd_soc_rbtree_node *rbnode; 735 struct snd_soc_rbtree_node *rbnode;
736 unsigned int reg_tmp;
610 737
611 rbtree_ctx = codec->reg_cache; 738 rbtree_ctx = codec->reg_cache;
612 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); 739 rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
613 if (rbnode) { 740 if (rbnode) {
614 *value = rbnode->value; 741 reg_tmp = reg - rbnode->base_reg;
742 *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
615 } else { 743 } else {
616 /* uninitialized registers default to 0 */ 744 /* uninitialized registers default to 0 */
617 *value = 0; 745 *value = 0;
@@ -637,6 +765,7 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
637 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node); 765 rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
638 next = rb_next(&rbtree_node->node); 766 next = rb_next(&rbtree_node->node);
639 rb_erase(&rbtree_node->node, &rbtree_ctx->root); 767 rb_erase(&rbtree_node->node, &rbtree_ctx->root);
768 kfree(rbtree_node->block);
640 kfree(rbtree_node); 769 kfree(rbtree_node);
641 } 770 }
642 771
@@ -649,10 +778,9 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
649 778
650static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) 779static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
651{ 780{
652 struct snd_soc_rbtree_node *rbtree_node;
653 struct snd_soc_rbtree_ctx *rbtree_ctx; 781 struct snd_soc_rbtree_ctx *rbtree_ctx;
654 unsigned int val;
655 unsigned int word_size; 782 unsigned int word_size;
783 unsigned int val;
656 int i; 784 int i;
657 int ret; 785 int ret;
658 786
@@ -666,28 +794,22 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
666 if (!codec->reg_def_copy) 794 if (!codec->reg_def_copy)
667 return 0; 795 return 0;
668 796
669 /*
670 * populate the rbtree with the initialized registers. All other
671 * registers will be inserted when they are first modified.
672 */
673 word_size = codec->driver->reg_word_size; 797 word_size = codec->driver->reg_word_size;
674 for (i = 0; i < codec->driver->reg_cache_size; ++i) { 798 for (i = 0; i < codec->driver->reg_cache_size; ++i) {
675 val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); 799 val = snd_soc_get_cache_val(codec->reg_def_copy, i,
800 word_size);
676 if (!val) 801 if (!val)
677 continue; 802 continue;
678 rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); 803 ret = snd_soc_rbtree_cache_write(codec, i, val);
679 if (!rbtree_node) { 804 if (ret)
680 ret = -ENOMEM; 805 goto err;
681 snd_soc_cache_exit(codec);
682 break;
683 }
684 rbtree_node->reg = i;
685 rbtree_node->value = val;
686 rbtree_node->defval = val;
687 snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
688 } 806 }
689 807
690 return 0; 808 return 0;
809
810err:
811 snd_soc_cache_exit(codec);
812 return ret;
691} 813}
692 814
693#ifdef CONFIG_SND_SOC_CACHE_LZO 815#ifdef CONFIG_SND_SOC_CACHE_LZO