This patch introduces a new API for procuring the DMAC that takes into account the dma copy capability and access control requested by the user. With this new API DMAC's are allocated depending on the number of channels that are currently draining, thereby providing a primitive level of QoS and preventing DMAC overuse.
This patch also consolidates the dma_get() API into a common file.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- src/arch/xtensa/Makefile.am | 1 + src/include/sof/dma.h | 6 ++- src/lib/Makefile.am | 11 +++++ src/lib/dma.c | 84 +++++++++++++++++++++++++++++++++++ src/platform/apollolake/dma.c | 12 ----- src/platform/baytrail/dma.c | 12 ----- src/platform/cannonlake/dma.c | 12 ----- src/platform/haswell/dma.c | 12 ----- 8 files changed, 101 insertions(+), 49 deletions(-) create mode 100644 src/lib/dma.c
diff --git a/src/arch/xtensa/Makefile.am b/src/arch/xtensa/Makefile.am index 309635c..2712031 100644 --- a/src/arch/xtensa/Makefile.am +++ b/src/arch/xtensa/Makefile.am @@ -58,6 +58,7 @@ sof_LDADD = \ ../../lib/libcore.a \ ../../platform/$(PLATFORM)/libplatform.a \ ../../ipc/libsof_ipc.a \ + ../../lib/libdma.a \ ../../audio/libaudio.a \ ../../drivers/libdrivers.a \ ../../math/libsof_math.a \ diff --git a/src/include/sof/dma.h b/src/include/sof/dma.h index 8a6e645..e8a64e7 100644 --- a/src/include/sof/dma.h +++ b/src/include/sof/dma.h @@ -56,6 +56,10 @@ enum dma_copy_dir { */ #define DMA_COPY_CAPS_ALL 0xFF
+/* DMAC flags */ +#define DMAC_FLAGS_SHARED 0 +#define DMAC_FLAGS_EXCLUSIVE (1 << 0) + /* DMA IRQ types */ #define DMA_IRQ_TYPE_BLOCK (1 << 0) #define DMA_IRQ_TYPE_LLIST (1 << 1) @@ -147,7 +151,7 @@ struct dma_int { uint32_t irq; };
-struct dma *dma_get(int dmac_id); +struct dma *dma_get(int dma_cap, int flags);
struct dma *get_platform_dmacs(void);
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 825bfbd..28f8f6f 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -16,3 +16,14 @@ libcore_a_CFLAGS = \ $(ARCH_INCDIR) \ $(SOF_INCDIR) \ $(PLATFORM_INCDIR) + +noinst_LIBRARIES = libdma.a + +libdma_a_SOURCES = \ + dma.c + +libdma_a_CFLAGS = \ + $(ARCH_CFLAGS) \ + $(ARCH_INCDIR) \ + $(SOF_INCDIR) \ + $(PLATFORM_INCDIR) diff --git a/src/lib/dma.c b/src/lib/dma.c new file mode 100644 index 0000000..c72dd2b --- /dev/null +++ b/src/lib/dma.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include <sof/dma.h> +#include <sof/trace.h> + +/* + * get DMAC based on user type, copy dir and flags + * For BYT/CHT, ignore the dmac_type and copy_dir arguments + * "flags" is used to set the type of access requested + * (ex: shared/exclusive access) + */ +struct dma *dma_get(int dma_cap, int flags) +{ + struct dma *dma = get_platform_dmacs(); + int i, ch_count; + int min_ch_count = INT32_MAX; + int dma_index = -1; + + for (i = 0; i < get_platform_num_dmacs(); i++) { + + /* skip if this DMAC does not support the requested cap */ + if ((dma[i].plat_data.dma_cap & dma_cap) == 0) + continue; + + /* if exclusive access is requested */ + if (flags & DMAC_FLAGS_EXCLUSIVE) { + + /* ret DMA with no channel in use */ + if (!dma[i].num_channels_busy) + return &dma[i]; + } else { + + /* + * for shared access requests, return DMAC + * with the least number of channels in use + */ + + /* get number of channels in use for this DMAC*/ + ch_count = dma[i].num_channels_busy; + + /* Use this DMAC if its channel count is lower */ + if (ch_count < min_ch_count) { + dma_index = i; + min_ch_count = ch_count; + } + } + } + + /* return DMAC */ + if (dma_index >= 0) { + tracev_value(dma[dma_index].plat_data.id); + return &dma[dma_index]; + } + + return NULL; +} diff --git a/src/platform/apollolake/dma.c b/src/platform/apollolake/dma.c index 396ad74..07aaad9 100644 --- a/src/platform/apollolake/dma.c +++ b/src/platform/apollolake/dma.c @@ -180,18 +180,6 @@ static struct dma dma[] = { .ops = &hda_link_dma_ops, },};
-struct dma *dma_get(int dmac_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dma); i++) { - if (dma[i].plat_data.id == dmac_id) - return &dma[i]; - } - - return NULL; -} - /* Initialize all platform DMAC's */ void dmac_init(void) { diff --git a/src/platform/baytrail/dma.c b/src/platform/baytrail/dma.c index b05eaa6..30d2304 100644 --- a/src/platform/baytrail/dma.c +++ b/src/platform/baytrail/dma.c @@ -178,18 +178,6 @@ static struct dma dma[] = { #endif };
-struct dma *dma_get(int dmac_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dma); i++) { - if (dma[i].plat_data.id == dmac_id) - return &dma[i]; - } - - return NULL; -} - /* Initialize all platform DMAC's */ void dmac_init(void) { diff --git a/src/platform/cannonlake/dma.c b/src/platform/cannonlake/dma.c index 49e2b71..21686db 100644 --- a/src/platform/cannonlake/dma.c +++ b/src/platform/cannonlake/dma.c @@ -180,18 +180,6 @@ static struct dma dma[] = { .ops = &hda_link_dma_ops, },};
-struct dma *dma_get(int dmac_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dma); i++) { - if (dma[i].plat_data.id == dmac_id) - return &dma[i]; - } - - return NULL; -} - /* Initialize all platform DMAC's */ void dmac_init(void) { diff --git a/src/platform/haswell/dma.c b/src/platform/haswell/dma.c index 09f5f6b..ca7200e 100644 --- a/src/platform/haswell/dma.c +++ b/src/platform/haswell/dma.c @@ -126,18 +126,6 @@ static struct dma dma[] = { .ops = &dw_dma_ops, },};
-struct dma *dma_get(int dmac_id) -{ - switch (dmac_id) { - case DMA_ID_DMAC0: - return &dma[0]; - case DMA_ID_DMAC1: - return &dma[1]; - default: - return NULL; - } -} - /* Initialize all platform DMAC's */ void dmac_init(void) {