dma: simple i/f to control flow between platform and lib

Less globals.
Path to dynamic dma discovery enabled on platforms that support it.
Avoid linker issues as platform lib still keeps refs to dma
array once probing is deferred (patch is coming).

Signed-off-by: Marcin Maka <marcin.maka@linux.intel.com>
This commit is contained in:
Marcin Maka 2018-09-28 13:07:18 +02:00
parent 44c6402cb4
commit a6c8c25438
10 changed files with 69 additions and 37 deletions

View File

@ -167,10 +167,25 @@ struct dma {
uint32_t private_size;
};
struct dma *dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags);
/**
* \brief Plugs platform specific DMA array once initialized into the lib.
*
* Lib serves the DMAs to other FW elements by dma_get()
*
* \param[in] dma_array Array of DMAs.
* \param[in] num_dmas Number of elements in dma_array.
*/
void dma_install(struct dma *dma_array, size_t num_dmas);
/* initialize all platform DMAC's */
int dmac_init(void);
/**
* \brief API to request a platform DMAC.
*
* Users can request DMAC based on dev type, copy direction, capabilities
* and access privilege.
* For exclusive access, ret DMAC with no channels draining.
* For shared access, ret DMAC with the least number of channels draining.
*/
struct dma *dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags);
#define dma_set_drvdata(dma, data) \
dma->private = data; \

View File

@ -32,57 +32,69 @@
#include <sof/atomic.h>
#include <platform/dma.h>
/*
* API to request a platform DMAC.
* Users can request DMAC based on dev type, copy direction, capabilities
* and access privilege.
* For exclusive access, ret DMAC with no channels draining.
* For shared access, ret DMAC with the least number of channels draining.
*/
struct dma_info {
struct dma *dma_array;
size_t num_dmas;
};
static struct dma_info lib_dma = {
.dma_array = NULL,
.num_dmas = 0
};
void dma_install(struct dma *dma_array, size_t num_dmas)
{
lib_dma.dma_array = dma_array;
lib_dma.num_dmas = num_dmas;
}
struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
{
int i, ch_count;
int ch_count;
int min_ch_count = INT32_MAX;
int dma_index = -1;
for (i = 0; i < PLATFORM_NUM_DMACS; i++) {
struct dma *d = NULL, *dmin = NULL;
if (!lib_dma.num_dmas) {
trace_error(TRACE_CLASS_DMA, "No DMAs installed");
return NULL;
}
for (d = lib_dma.dma_array; d < lib_dma.dma_array + lib_dma.num_dmas;
d++) {
/* skip if this DMAC does not support the requested dir */
if (dir && (dma[i].plat_data.dir & dir) == 0)
if (dir && (d->plat_data.dir & dir) == 0)
continue;
/* skip if this DMAC does not support the requested caps */
if (cap && (dma[i].plat_data.caps & cap) == 0)
if (cap && (d->plat_data.caps & cap) == 0)
continue;
/* skip if this DMAC does not support the requested dev */
if (dev && (dma[i].plat_data.devs & dev) == 0)
if (dev && (d->plat_data.devs & dev) == 0)
continue;
/* if exclusive access is requested */
if (flags & DMA_ACCESS_EXCLUSIVE) {
/* ret DMA with no channels draining */
if (!atomic_read(&dma[i].num_channels_busy))
return &dma[i];
if (!atomic_read(&d->num_channels_busy))
return d;
} else {
/* get number of channels draining in this DMAC*/
ch_count = atomic_read(&dma[i].num_channels_busy);
ch_count = atomic_read(&d->num_channels_busy);
/* pick DMAC with the least num of channels draining */
if (ch_count < min_ch_count) {
dma_index = i;
dmin = d;
min_ch_count = ch_count;
}
}
}
/* return DMAC */
if (dma_index >= 0) {
tracev_value(dma[dma_index].plat_data.id);
return &dma[dma_index];
if (dmin) {
tracev_value(dmin->plat_data.id);
return dmin;
}
return NULL;

View File

@ -37,8 +37,6 @@
#include <arch/cache.h>
#include <sof/dma.h>
#define PLATFORM_NUM_DMACS 6
/* available DMACs */
#define DMA_GP_LP_DMAC0 0
#define DMA_GP_LP_DMAC1 1
@ -75,6 +73,6 @@
#define DMA_HANDSHAKE_SSP5_TX 12
#define DMA_HANDSHAKE_SSP5_RX 13
extern struct dma dma[PLATFORM_NUM_DMACS];
int dmac_init(void);
#endif

View File

@ -206,5 +206,8 @@ int dmac_init(void)
}
}
/* tell the lib DMAs are ready to use */
dma_install(dma, ARRAY_SIZE(dma));
return 0;
}

View File

@ -60,6 +60,6 @@
#define DMA_HANDSHAKE_SSP6_RX 12
#define DMA_HANDSHAKE_SSP6_TX 13
extern struct dma dma[PLATFORM_NUM_DMACS];
int dmac_init(void);
#endif

View File

@ -35,8 +35,6 @@
#include <sof/dma.h>
#define PLATFORM_NUM_DMACS 6
/* available DMACs */
#define DMA_GP_LP_DMAC0 0
#define DMA_GP_LP_DMAC1 1
@ -73,6 +71,6 @@
#define DMA_HANDSHAKE_SSP5_TX 12
#define DMA_HANDSHAKE_SSP5_RX 13
extern struct dma dma[PLATFORM_NUM_DMACS];
int dmac_init(void);
#endif

View File

@ -155,5 +155,8 @@ int dmac_init(void)
io_reg_update_bits(SHIM_BASE + SHIM_IMRD,
SHIM_IMRD_DMAC1, 0);
/* tell the lib DMAs are ready to use */
dma_install(dma, ARRAY_SIZE(dma));
return 0;
}

View File

@ -34,7 +34,7 @@
#include <stdint.h>
#include <sof/dma.h>
#define PLATFORM_NUM_DMACS 2
#define PLATFORM_NUM_DMACS 2
#define DMA_ID_DMAC0 0
#define DMA_ID_DMAC1 1
@ -56,6 +56,6 @@
#define DMA_HANDSHAKE_OBFF_10 14
#define DMA_HANDSHAKE_OBFF_11 15
extern struct dma dma[PLATFORM_NUM_DMACS];
int dmac_init(void);
#endif

View File

@ -35,8 +35,6 @@
#include <sof/dma.h>
#define PLATFORM_NUM_DMACS 6
/* available DMACs */
#define DMA_GP_LP_DMAC0 0
#define DMA_GP_LP_DMAC1 1
@ -73,6 +71,6 @@
#define DMA_HANDSHAKE_SSP5_TX 12
#define DMA_HANDSHAKE_SSP5_RX 13
extern struct dma dma[PLATFORM_NUM_DMACS];
int dmac_init(void);
#endif

View File

@ -40,6 +40,8 @@
#include <stdint.h>
#include <string.h>
#define CAVS_PLATFORM_NUM_DMACS 6
#if defined(CONFIG_APOLLOLAKE)
#define DMAC0_CLASS 1
#define DMAC1_CLASS 2
@ -124,7 +126,7 @@ static struct dw_drv_plat_data dmac1 = {
},
};
struct dma dma[PLATFORM_NUM_DMACS] = {
static struct dma dma[CAVS_PLATFORM_NUM_DMACS] = {
{ /* Low Power GP DMAC 0 */
.plat_data = {
.id = DMA_GP_LP_DMAC0,
@ -222,5 +224,8 @@ int dmac_init(void)
}
}
/* tell the lib DMAs are ready to use */
dma_install(dma, ARRAY_SIZE(dma));
return 0;
}