pcm: dmix: Allow disabling x86 optimizations

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>
This commit is contained in:
Takashi Iwai 2017-02-10 12:16:12 +01:00
parent e31a3273df
commit 22eca6468b
7 changed files with 39 additions and 0 deletions

View 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 ]

View 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

View 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;
}

View 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;
};

View 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) {

View 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;

View 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;