diff options
-rw-r--r-- | include/sound/soc.h | 1 | ||||
-rw-r--r-- | sound/soc/Kconfig | 15 | ||||
-rw-r--r-- | sound/soc/soc-cache.c | 384 |
3 files changed, 0 insertions, 400 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h index 02a5c5519f3..b21b3047e91 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -266,7 +266,6 @@ enum snd_soc_control_type { | |||
266 | 266 | ||
267 | enum snd_soc_compress_type { | 267 | enum snd_soc_compress_type { |
268 | SND_SOC_FLAT_COMPRESSION = 1, | 268 | SND_SOC_FLAT_COMPRESSION = 1, |
269 | SND_SOC_LZO_COMPRESSION, | ||
270 | SND_SOC_RBTREE_COMPRESSION | 269 | SND_SOC_RBTREE_COMPRESSION |
271 | }; | 270 | }; |
272 | 271 | ||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 1381db853ef..35e662d270e 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -22,21 +22,6 @@ menuconfig SND_SOC | |||
22 | 22 | ||
23 | if SND_SOC | 23 | if SND_SOC |
24 | 24 | ||
25 | config SND_SOC_CACHE_LZO | ||
26 | bool "Support LZO compression for register caches" | ||
27 | select LZO_COMPRESS | ||
28 | select LZO_DECOMPRESS | ||
29 | ---help--- | ||
30 | Select this to enable LZO compression for register caches. | ||
31 | This will allow machine or CODEC drivers to compress register | ||
32 | caches in memory, reducing the memory consumption at the | ||
33 | expense of performance. If this is not present and is used | ||
34 | the system will fall back to uncompressed caches. | ||
35 | |||
36 | Usually it is safe to disable this option, where cache | ||
37 | compression in used the rbtree option will typically perform | ||
38 | better. | ||
39 | |||
40 | config SND_SOC_AC97_BUS | 25 | config SND_SOC_AC97_BUS |
41 | bool | 26 | bool |
42 | 27 | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 9077aa4b3b4..18bb6b3335e 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
15 | #include <linux/spi/spi.h> | 15 | #include <linux/spi/spi.h> |
16 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
17 | #include <linux/lzo.h> | ||
18 | #include <linux/bitmap.h> | 17 | #include <linux/bitmap.h> |
19 | #include <linux/rbtree.h> | 18 | #include <linux/rbtree.h> |
20 | #include <linux/export.h> | 19 | #include <linux/export.h> |
@@ -439,378 +438,6 @@ err: | |||
439 | return ret; | 438 | return ret; |
440 | } | 439 | } |
441 | 440 | ||
442 | #ifdef CONFIG_SND_SOC_CACHE_LZO | ||
443 | struct snd_soc_lzo_ctx { | ||
444 | void *wmem; | ||
445 | void *dst; | ||
446 | const void *src; | ||
447 | size_t src_len; | ||
448 | size_t dst_len; | ||
449 | size_t decompressed_size; | ||
450 | unsigned long *sync_bmp; | ||
451 | int sync_bmp_nbits; | ||
452 | }; | ||
453 | |||
454 | #define LZO_BLOCK_NUM 8 | ||
455 | static int snd_soc_lzo_block_count(void) | ||
456 | { | ||
457 | return LZO_BLOCK_NUM; | ||
458 | } | ||
459 | |||
460 | static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx) | ||
461 | { | ||
462 | lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); | ||
463 | if (!lzo_ctx->wmem) | ||
464 | return -ENOMEM; | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx) | ||
469 | { | ||
470 | size_t compress_size; | ||
471 | int ret; | ||
472 | |||
473 | ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len, | ||
474 | lzo_ctx->dst, &compress_size, lzo_ctx->wmem); | ||
475 | if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len) | ||
476 | return -EINVAL; | ||
477 | lzo_ctx->dst_len = compress_size; | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx) | ||
482 | { | ||
483 | size_t dst_len; | ||
484 | int ret; | ||
485 | |||
486 | dst_len = lzo_ctx->dst_len; | ||
487 | ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len, | ||
488 | lzo_ctx->dst, &dst_len); | ||
489 | if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len) | ||
490 | return -EINVAL; | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec, | ||
495 | struct snd_soc_lzo_ctx *lzo_ctx) | ||
496 | { | ||
497 | int ret; | ||
498 | |||
499 | lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE); | ||
500 | lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); | ||
501 | if (!lzo_ctx->dst) { | ||
502 | lzo_ctx->dst_len = 0; | ||
503 | return -ENOMEM; | ||
504 | } | ||
505 | |||
506 | ret = snd_soc_lzo_compress(lzo_ctx); | ||
507 | if (ret < 0) | ||
508 | return ret; | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec, | ||
513 | struct snd_soc_lzo_ctx *lzo_ctx) | ||
514 | { | ||
515 | int ret; | ||
516 | |||
517 | lzo_ctx->dst_len = lzo_ctx->decompressed_size; | ||
518 | lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); | ||
519 | if (!lzo_ctx->dst) { | ||
520 | lzo_ctx->dst_len = 0; | ||
521 | return -ENOMEM; | ||
522 | } | ||
523 | |||
524 | ret = snd_soc_lzo_decompress(lzo_ctx); | ||
525 | if (ret < 0) | ||
526 | return ret; | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec, | ||
531 | unsigned int reg) | ||
532 | { | ||
533 | const struct snd_soc_codec_driver *codec_drv; | ||
534 | |||
535 | codec_drv = codec->driver; | ||
536 | return (reg * codec_drv->reg_word_size) / | ||
537 | DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); | ||
538 | } | ||
539 | |||
540 | static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec, | ||
541 | unsigned int reg) | ||
542 | { | ||
543 | const struct snd_soc_codec_driver *codec_drv; | ||
544 | |||
545 | codec_drv = codec->driver; | ||
546 | return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) / | ||
547 | codec_drv->reg_word_size); | ||
548 | } | ||
549 | |||
550 | static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec) | ||
551 | { | ||
552 | return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); | ||
553 | } | ||
554 | |||
555 | static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) | ||
556 | { | ||
557 | struct snd_soc_lzo_ctx **lzo_blocks; | ||
558 | unsigned int val; | ||
559 | int i; | ||
560 | int ret; | ||
561 | |||
562 | lzo_blocks = codec->reg_cache; | ||
563 | for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) { | ||
564 | WARN_ON(!snd_soc_codec_writable_register(codec, i)); | ||
565 | ret = snd_soc_cache_read(codec, i, &val); | ||
566 | if (ret) | ||
567 | return ret; | ||
568 | codec->cache_bypass = 1; | ||
569 | ret = snd_soc_write(codec, i, val); | ||
570 | codec->cache_bypass = 0; | ||
571 | if (ret) | ||
572 | return ret; | ||
573 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | ||
574 | i, val); | ||
575 | } | ||
576 | |||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec, | ||
581 | unsigned int reg, unsigned int value) | ||
582 | { | ||
583 | struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks; | ||
584 | int ret, blkindex, blkpos; | ||
585 | size_t blksize, tmp_dst_len; | ||
586 | void *tmp_dst; | ||
587 | |||
588 | /* index of the compressed lzo block */ | ||
589 | blkindex = snd_soc_lzo_get_blkindex(codec, reg); | ||
590 | /* register index within the decompressed block */ | ||
591 | blkpos = snd_soc_lzo_get_blkpos(codec, reg); | ||
592 | /* size of the compressed block */ | ||
593 | blksize = snd_soc_lzo_get_blksize(codec); | ||
594 | lzo_blocks = codec->reg_cache; | ||
595 | lzo_block = lzo_blocks[blkindex]; | ||
596 | |||
597 | /* save the pointer and length of the compressed block */ | ||
598 | tmp_dst = lzo_block->dst; | ||
599 | tmp_dst_len = lzo_block->dst_len; | ||
600 | |||
601 | /* prepare the source to be the compressed block */ | ||
602 | lzo_block->src = lzo_block->dst; | ||
603 | lzo_block->src_len = lzo_block->dst_len; | ||
604 | |||
605 | /* decompress the block */ | ||
606 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); | ||
607 | if (ret < 0) { | ||
608 | kfree(lzo_block->dst); | ||
609 | goto out; | ||
610 | } | ||
611 | |||
612 | /* write the new value to the cache */ | ||
613 | if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value, | ||
614 | codec->driver->reg_word_size)) { | ||
615 | kfree(lzo_block->dst); | ||
616 | goto out; | ||
617 | } | ||
618 | |||
619 | /* prepare the source to be the decompressed block */ | ||
620 | lzo_block->src = lzo_block->dst; | ||
621 | lzo_block->src_len = lzo_block->dst_len; | ||
622 | |||
623 | /* compress the block */ | ||
624 | ret = snd_soc_lzo_compress_cache_block(codec, lzo_block); | ||
625 | if (ret < 0) { | ||
626 | kfree(lzo_block->dst); | ||
627 | kfree(lzo_block->src); | ||
628 | goto out; | ||
629 | } | ||
630 | |||
631 | /* set the bit so we know we have to sync this register */ | ||
632 | set_bit(reg, lzo_block->sync_bmp); | ||
633 | kfree(tmp_dst); | ||
634 | kfree(lzo_block->src); | ||
635 | return 0; | ||
636 | out: | ||
637 | lzo_block->dst = tmp_dst; | ||
638 | lzo_block->dst_len = tmp_dst_len; | ||
639 | return ret; | ||
640 | } | ||
641 | |||
642 | static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec, | ||
643 | unsigned int reg, unsigned int *value) | ||
644 | { | ||
645 | struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks; | ||
646 | int ret, blkindex, blkpos; | ||
647 | size_t blksize, tmp_dst_len; | ||
648 | void *tmp_dst; | ||
649 | |||
650 | *value = 0; | ||
651 | /* index of the compressed lzo block */ | ||
652 | blkindex = snd_soc_lzo_get_blkindex(codec, reg); | ||
653 | /* register index within the decompressed block */ | ||
654 | blkpos = snd_soc_lzo_get_blkpos(codec, reg); | ||
655 | /* size of the compressed block */ | ||
656 | blksize = snd_soc_lzo_get_blksize(codec); | ||
657 | lzo_blocks = codec->reg_cache; | ||
658 | lzo_block = lzo_blocks[blkindex]; | ||
659 | |||
660 | /* save the pointer and length of the compressed block */ | ||
661 | tmp_dst = lzo_block->dst; | ||
662 | tmp_dst_len = lzo_block->dst_len; | ||
663 | |||
664 | /* prepare the source to be the compressed block */ | ||
665 | lzo_block->src = lzo_block->dst; | ||
666 | lzo_block->src_len = lzo_block->dst_len; | ||
667 | |||
668 | /* decompress the block */ | ||
669 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); | ||
670 | if (ret >= 0) | ||
671 | /* fetch the value from the cache */ | ||
672 | *value = snd_soc_get_cache_val(lzo_block->dst, blkpos, | ||
673 | codec->driver->reg_word_size); | ||
674 | |||
675 | kfree(lzo_block->dst); | ||
676 | /* restore the pointer and length of the compressed block */ | ||
677 | lzo_block->dst = tmp_dst; | ||
678 | lzo_block->dst_len = tmp_dst_len; | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec) | ||
683 | { | ||
684 | struct snd_soc_lzo_ctx **lzo_blocks; | ||
685 | int i, blkcount; | ||
686 | |||
687 | lzo_blocks = codec->reg_cache; | ||
688 | if (!lzo_blocks) | ||
689 | return 0; | ||
690 | |||
691 | blkcount = snd_soc_lzo_block_count(); | ||
692 | /* | ||
693 | * the pointer to the bitmap used for syncing the cache | ||
694 | * is shared amongst all lzo_blocks. Ensure it is freed | ||
695 | * only once. | ||
696 | */ | ||
697 | if (lzo_blocks[0]) | ||
698 | kfree(lzo_blocks[0]->sync_bmp); | ||
699 | for (i = 0; i < blkcount; ++i) { | ||
700 | if (lzo_blocks[i]) { | ||
701 | kfree(lzo_blocks[i]->wmem); | ||
702 | kfree(lzo_blocks[i]->dst); | ||
703 | } | ||
704 | /* each lzo_block is a pointer returned by kmalloc or NULL */ | ||
705 | kfree(lzo_blocks[i]); | ||
706 | } | ||
707 | kfree(lzo_blocks); | ||
708 | codec->reg_cache = NULL; | ||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | ||
713 | { | ||
714 | struct snd_soc_lzo_ctx **lzo_blocks; | ||
715 | size_t bmp_size; | ||
716 | const struct snd_soc_codec_driver *codec_drv; | ||
717 | int ret, tofree, i, blksize, blkcount; | ||
718 | const char *p, *end; | ||
719 | unsigned long *sync_bmp; | ||
720 | |||
721 | ret = 0; | ||
722 | codec_drv = codec->driver; | ||
723 | |||
724 | /* | ||
725 | * If we have not been given a default register cache | ||
726 | * then allocate a dummy zero-ed out region, compress it | ||
727 | * and remember to free it afterwards. | ||
728 | */ | ||
729 | tofree = 0; | ||
730 | if (!codec->reg_def_copy) | ||
731 | tofree = 1; | ||
732 | |||
733 | if (!codec->reg_def_copy) { | ||
734 | codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL); | ||
735 | if (!codec->reg_def_copy) | ||
736 | return -ENOMEM; | ||
737 | } | ||
738 | |||
739 | blkcount = snd_soc_lzo_block_count(); | ||
740 | codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks, | ||
741 | GFP_KERNEL); | ||
742 | if (!codec->reg_cache) { | ||
743 | ret = -ENOMEM; | ||
744 | goto err_tofree; | ||
745 | } | ||
746 | lzo_blocks = codec->reg_cache; | ||
747 | |||
748 | /* | ||
749 | * allocate a bitmap to be used when syncing the cache with | ||
750 | * the hardware. Each time a register is modified, the corresponding | ||
751 | * bit is set in the bitmap, so we know that we have to sync | ||
752 | * that register. | ||
753 | */ | ||
754 | bmp_size = codec_drv->reg_cache_size; | ||
755 | sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long), | ||
756 | GFP_KERNEL); | ||
757 | if (!sync_bmp) { | ||
758 | ret = -ENOMEM; | ||
759 | goto err; | ||
760 | } | ||
761 | bitmap_zero(sync_bmp, bmp_size); | ||
762 | |||
763 | /* allocate the lzo blocks and initialize them */ | ||
764 | for (i = 0; i < blkcount; ++i) { | ||
765 | lzo_blocks[i] = kzalloc(sizeof **lzo_blocks, | ||
766 | GFP_KERNEL); | ||
767 | if (!lzo_blocks[i]) { | ||
768 | kfree(sync_bmp); | ||
769 | ret = -ENOMEM; | ||
770 | goto err; | ||
771 | } | ||
772 | lzo_blocks[i]->sync_bmp = sync_bmp; | ||
773 | lzo_blocks[i]->sync_bmp_nbits = bmp_size; | ||
774 | /* alloc the working space for the compressed block */ | ||
775 | ret = snd_soc_lzo_prepare(lzo_blocks[i]); | ||
776 | if (ret < 0) | ||
777 | goto err; | ||
778 | } | ||
779 | |||
780 | blksize = snd_soc_lzo_get_blksize(codec); | ||
781 | p = codec->reg_def_copy; | ||
782 | end = codec->reg_def_copy + codec->reg_size; | ||
783 | /* compress the register map and fill the lzo blocks */ | ||
784 | for (i = 0; i < blkcount; ++i, p += blksize) { | ||
785 | lzo_blocks[i]->src = p; | ||
786 | if (p + blksize > end) | ||
787 | lzo_blocks[i]->src_len = end - p; | ||
788 | else | ||
789 | lzo_blocks[i]->src_len = blksize; | ||
790 | ret = snd_soc_lzo_compress_cache_block(codec, | ||
791 | lzo_blocks[i]); | ||
792 | if (ret < 0) | ||
793 | goto err; | ||
794 | lzo_blocks[i]->decompressed_size = | ||
795 | lzo_blocks[i]->src_len; | ||
796 | } | ||
797 | |||
798 | if (tofree) { | ||
799 | kfree(codec->reg_def_copy); | ||
800 | codec->reg_def_copy = NULL; | ||
801 | } | ||
802 | return 0; | ||
803 | err: | ||
804 | snd_soc_cache_exit(codec); | ||
805 | err_tofree: | ||
806 | if (tofree) { | ||
807 | kfree(codec->reg_def_copy); | ||
808 | codec->reg_def_copy = NULL; | ||
809 | } | ||
810 | return ret; | ||
811 | } | ||
812 | #endif | ||
813 | |||
814 | static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | 441 | static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) |
815 | { | 442 | { |
816 | int i; | 443 | int i; |
@@ -889,17 +516,6 @@ static const struct snd_soc_cache_ops cache_types[] = { | |||
889 | .write = snd_soc_flat_cache_write, | 516 | .write = snd_soc_flat_cache_write, |
890 | .sync = snd_soc_flat_cache_sync | 517 | .sync = snd_soc_flat_cache_sync |
891 | }, | 518 | }, |
892 | #ifdef CONFIG_SND_SOC_CACHE_LZO | ||
893 | { | ||
894 | .id = SND_SOC_LZO_COMPRESSION, | ||
895 | .name = "LZO", | ||
896 | .init = snd_soc_lzo_cache_init, | ||
897 | .exit = snd_soc_lzo_cache_exit, | ||
898 | .read = snd_soc_lzo_cache_read, | ||
899 | .write = snd_soc_lzo_cache_write, | ||
900 | .sync = snd_soc_lzo_cache_sync | ||
901 | }, | ||
902 | #endif | ||
903 | { | 519 | { |
904 | .id = SND_SOC_RBTREE_COMPRESSION, | 520 | .id = SND_SOC_RBTREE_COMPRESSION, |
905 | .name = "rbtree", | 521 | .name = "rbtree", |