]> git.alsa-project.org Git - alsa-lib.git/commitdiff
pcm: dmix: Allow disabling x86 optimizations
authorTakashi Iwai <tiwai@suse.de>
Fri, 10 Feb 2017 11:16:12 +0000 (12:16 +0100)
committerTakashi Iwai <tiwai@suse.de>
Fri, 10 Feb 2017 11:16:12 +0000 (12:16 +0100)
The dmix plugin has some optimized implementations for x86 using the
direct memory accesses, which was rather the original version, in
addition to the "generic" implementation using the semaphore
blocking.  The x86 implementation relies on the memory coherency *and*
the fast read/write on it.

For other architectures, this has been always disabled just because of
memory coherency.  But, the recent LPE audio development revealed
that, even on x86 platforms, the read/write performance might become
extremely bad when the buffer is marked as uncached.  Some drivers
already know the buffer is uncached, we need to switch to the generic
mode in such a case.

This patch introduces yet another flag to dmix configuration,
direct_memory_access, that indicates whether the x86-specific
optimization can be used or not.  Each driver can set the flag in its
cards config namespace, and the default dmix config refers to it.

As of this patch, only HDMI LPE Audio driver sets it.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
src/conf/cards/HdmiLpeAudio.conf
src/conf/pcm/dmix.conf
src/pcm/pcm_direct.c
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dmix_i386.c
src/pcm/pcm_dmix_x86_64.c

index f5836c05219e04df90d7da9def44243efe093414..61bdfeae29176f0443b52268dc5eb30f4e5b5971 100644 (file)
@@ -20,6 +20,9 @@ HdmiLpeAudio.pcm.front.0 {
        }
 }
 
+# uncached memory reads have a high penalty
+HdmiLpeAudio.dmix.direct_memory_access false
+
 # default with dmix+softvol
 HdmiLpeAudio.pcm.default {
        @args [ CARD ]
index 7d0aa0158c429f1245f7a405f1ff825e1f1ff626..2d3b329e533ae33fb26d3e42ba56e87b509cc2a9 100644 (file)
@@ -49,6 +49,21 @@ pcm.!dmix {
                @func refer
                name defaults.pcm.ipc_perm
        }
+       direct_memory_access {
+               @func refer
+               name {
+                       @func concat
+                       strings [
+                               "cards."
+                               {
+                                       @func card_driver
+                                       card $CARD
+                               }
+                               ".dmix.direct_memory_access"
+                       ]
+               }
+               default true
+       }
        slave {
                pcm {
                        type hw
index e4bef7860d016b92f95efe228a0f8b5295302e0b..364191b20bab1e89a7b54005bea7dd064cd5d9b5 100644 (file)
@@ -1861,6 +1861,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf,
        rec->slowptr = 1;
        rec->max_periods = 0;
        rec->var_periodsize = 1;
+       rec->direct_memory_access = 1;
 
        /* read defaults */
        if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) {
@@ -1974,6 +1975,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf,
                        rec->var_periodsize = err;
                        continue;
                }
+               if (strcmp(id, "direct_memory_access") == 0) {
+                       err = snd_config_get_bool(n);
+                       if (err < 0)
+                               return err;
+                       rec->direct_memory_access = err;
+                       continue;
+               }
                SNDERR("Unknown field %s", id);
                return -EINVAL;
        }
index 66107ec07477a98a1eab159aa99283894be00781..fba55fdcb5b3696ef28162f1a9813371265413fb 100644 (file)
@@ -159,6 +159,7 @@ struct snd_pcm_direct {
        unsigned int channels;          /* client's channels */
        unsigned int *bindings;
        unsigned int recoveries;        /* mirror of executed recoveries on slave */
+       int direct_memory_access;       /* use arch-optimized buffer RW */
        union {
                struct {
                        int shmid_sum;                  /* IPC global sum ring buffer memory identification */
@@ -340,6 +341,7 @@ struct snd_pcm_direct_open_conf {
        int slowptr;
        int max_periods;
        int var_periodsize;
+       int direct_memory_access;
        snd_config_t *slave;
        snd_config_t *bindings;
 };
index 2ef61599f4b0bcf60fdd68a2c84245735cd736d6..dd0356e9114d1d89694a6bff861b86b380f9e2cc 100644 (file)
@@ -1065,6 +1065,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
        dmix->max_periods = opts->max_periods;
        dmix->var_periodsize = opts->var_periodsize;
        dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
+       dmix->direct_memory_access = opts->direct_memory_access;
 
  retry:
        if (first_instance) {
index dcc6b9a4222e909c15b10785af6f3874ef14d5b6..1ab983a8a373e4fbe9c5e996f90f8fe7d23e6de1 100644 (file)
@@ -87,6 +87,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix)
 {
        static int smp = 0, mmx = 0, cmov = 0;
 
+       if (!dmix->direct_memory_access) {
+               generic_mix_select_callbacks(dmix);
+               return;
+       }
+
        if (!((1ULL<< dmix->shmptr->s.format) & i386_dmix_supported_format)) {
                generic_mix_select_callbacks(dmix);
                return;
index 831046d909a4148e63328dbfd7ff6ba5cd8f047f..34c40d4e9d1d0610cadbab884e9356ef36519771 100644 (file)
@@ -70,6 +70,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix)
 {
        static int smp = 0;
        
+       if (!dmix->direct_memory_access) {
+               generic_mix_select_callbacks(dmix);
+               return;
+       }
+
        if (!((1ULL<< dmix->shmptr->s.format) & x86_64_dmix_supported_format)) {
                generic_mix_select_callbacks(dmix);
                return;