On 6/6/2018 3:12 AM, Ranjani Sridharan wrote:
On Tue, 2018-06-05 at 16:14 +0800, rander.wang wrote:
On 6/5/2018 12:23 PM, Ranjani Sridharan wrote:
This patch introduces a new API for procuring DMAC for various user based on the type of DMAC, copy direction and other flags for share/exclusive access. It defines the necessary DMAC user types, copy direction and the flags to suuport the new API.It also adds two new members to dma_plat_data to differentiate the DMAC based on usage and copy direction.
Finally, it also contains the platform specific implementation of the new dma_get() API.
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com
src/include/sof/dma.h | 26 ++++++++++++++++- src/platform/apollolake/dma.c | 53 ++++++++++++++++++++++++++++++++--- src/platform/baytrail/dma.c | 41 ++++++++++++++++++++++++--- src/platform/cannonlake/dma.c | 53 ++++++++++++++++++++++++++++++++--- src/platform/haswell/dma.c | 49 ++++++++++++++++++++++++++-----
- 5 files changed, 201 insertions(+), 21 deletions(-)
diff --git a/src/include/sof/dma.h b/src/include/sof/dma.h index 1de9efc..25581e6 100644 --- a/src/include/sof/dma.h +++ b/src/include/sof/dma.h @@ -48,6 +48,28 @@ enum dma_copy_dir { DMA_DIR_DEV_TO_DEV, };
+/*
- DMAC copy directions
- These are used to specify the copy direction while requesting a
DMAC
- */
+enum dmac_copy_dir {
- DMAC_DIR_READ = 0,
- DMAC_DIR_WRITE,
- DMAC_DIR_DUPLEX,
+};
On HSW and BDW, one difference between two DMA. Both DMA support Memory to memory copy, but DMA two supports memory <=> device copy. So MEM_TO_DEV, DEV_TO_MEM, HOST_TO_MEM ... should be added for this case.
Rander, there's another enum called dma_copy_dir() which defines those. Are you suggesting we qualify each DMAC with its capabilities in terms of dma_copy_dir as well?
yes, i find only dam_copy_dir is fit for capabilities. how do you think about it?
+/* DMAC user types */ +enum dmac_user {
- DMAC_USER_HOST_DMA = 0,
- DMAC_USER_LINK_DMA,
- DMAC_USER_GP_LP_DMA,
- DMAC_USER_GP_HP_DMA,
+};
+/* 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)
@@ -119,6 +141,8 @@ struct dma_ops { /* DMA platform data */ struct dma_plat_data { uint32_t id;
- enum dmac_user type;
- enum dmac_copy_dir copy_dir; uint32_t base; uint32_t channels; uint32_t irq;
@@ -139,7 +163,7 @@ struct dma_int { uint32_t irq; };
-struct dma *dma_get(int dmac_id); +struct dma *dma_get(enum dmac_user, enum dmac_copy_dir, int flags);
/* initialize all platform DMAC's */ void dmac_init(void); diff --git a/src/platform/apollolake/dma.c b/src/platform/apollolake/dma.c index 001bb67..1ae097e 100644 --- a/src/platform/apollolake/dma.c +++ b/src/platform/apollolake/dma.c @@ -112,6 +112,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 0 */ .plat_data = { .id = DMA_GP_LP_DMAC0,
.type = DMAC_USER_GP_LP_DMA,
.base = LP_GP_DMA_BASE(0), .channels = 8, .irq = IRQ_EXT_LP_GPDMA0_LVL5(0,.copy_dir = DMAC_DIR_DUPLEX,
0), @@ -122,6 +124,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 1 */ .plat_data = { .id = DMA_GP_LP_DMAC1,
.type = DMAC_USER_GP_LP_DMA,
.base = LP_GP_DMA_BASE(1), .channels = 8, .irq = IRQ_EXT_LP_GPDMA1_LVL5(0,.copy_dir = DMAC_DIR_DUPLEX,
0), @@ -132,6 +136,8 @@ static struct dma dma[] = { { /* Host In DMAC */ .plat_data = { .id = DMA_HOST_IN_DMAC,
.type = DMAC_USER_HOST_DMA,
.base = GTW_HOST_IN_STREAM_BASE(0), .channels = 7, .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0,.copy_dir = DMAC_DIR_WRITE,
0), @@ -142,6 +148,8 @@ static struct dma dma[] = { { /* Host out DMAC */ .plat_data = { .id = DMA_HOST_OUT_DMAC,
.type = DMAC_USER_HOST_DMA,
.base =.copy_dir = DMAC_DIR_READ,
GTW_HOST_OUT_STREAM_BASE(0), .channels = 6, .irq = IRQ_EXT_HOST_DMA_OUT_LVL3(0, 0), @@ -152,6 +160,8 @@ static struct dma dma[] = { { /* Link In DMAC */ .plat_data = { .id = DMA_LINK_IN_DMAC,
.type = DMAC_USER_LINK_DMA,
.base = GTW_LINK_IN_STREAM_BASE(0), .channels = 8, .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0,.copy_dir = DMAC_DIR_WRITE,
0), @@ -162,6 +172,8 @@ static struct dma dma[] = { { /* Link out DMAC */ .plat_data = { .id = DMA_LINK_OUT_DMAC,
.type = DMAC_USER_LINK_DMA,
.base =.copy_dir = DMAC_DIR_READ,
GTW_LINK_OUT_STREAM_BASE(0), .channels = 8, .irq = IRQ_EXT_LINK_DMA_OUT_LVL4(0, 0), @@ -170,15 +182,48 @@ static struct dma dma[] = { .ops = &hda_link_dma_ops, },};
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- int i;
int i, ch_count;
int dma_index = -1;
int min_ch_count = INT32_MAX;
for (i = 0; i < ARRAY_SIZE(dma); i++) {
if (dma[i].plat_data.id == dmac_id)
return &dma[i];
/* check DMAC user type */
if (dma[i].plat_data.type != user)
continue;
/* check DMAC copy dir */
if (dma[i].plat_data.copy_dir != dir)
continue;
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
return &dma[i];
} else {
/* get number of channels in use */
ch_count = dma_channel_status(&dma[i]);
/* Use this DMAC if its channel count is
lower */
if (ch_count < min_ch_count) {
dma_index = i;
min_ch_count = ch_count;
}
}
}
if (dma_index >= 0)
return &dma[dma_index];
return NULL; }
diff --git a/src/platform/baytrail/dma.c b/src/platform/baytrail/dma.c index 5a0b650..71ea241 100644 --- a/src/platform/baytrail/dma.c +++ b/src/platform/baytrail/dma.c @@ -175,15 +175,48 @@ static struct dma dma[] = { #endif };
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- For BYT/CHT, ignore the dmac_user and copy_dir arguments
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- int i;
int i, ch_count;
int min_ch_count = INT32_MAX;
int dma_index = -1;
for (i = 0; i < ARRAY_SIZE(dma); i++) {
if (dma[i].plat_data.id == dmac_id)
return &dma[i];
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
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_channel_status(&dma[i]);
/* 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)
return &dma[dma_index];
return NULL; }
diff --git a/src/platform/cannonlake/dma.c b/src/platform/cannonlake/dma.c index 9031c17..697b9a8 100644 --- a/src/platform/cannonlake/dma.c +++ b/src/platform/cannonlake/dma.c @@ -113,6 +113,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 0 */ .plat_data = { .id = DMA_GP_LP_DMAC0,
.type = DMAC_USER_GP_LP_DMA,
.base = LP_GP_DMA_BASE(0), .channels = 8, .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0),.copy_dir = DMAC_DIR_DUPLEX,
@@ -123,6 +125,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 1 */ .plat_data = { .id = DMA_GP_LP_DMAC1,
.type = DMAC_USER_GP_LP_DMA,
.base = LP_GP_DMA_BASE(1), .channels = 8, .irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0),.copy_dir = DMAC_DIR_DUPLEX,
@@ -133,6 +137,8 @@ static struct dma dma[] = { { /* Host In DMAC */ .plat_data = { .id = DMA_HOST_IN_DMAC,
.type = DMAC_USER_HOST_DMA,
.base = GTW_HOST_IN_STREAM_BASE(0), .channels = 7, .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0, 0),.copy_dir = DMAC_DIR_WRITE,
@@ -143,6 +149,8 @@ static struct dma dma[] = { { /* Host out DMAC */ .plat_data = { .id = DMA_HOST_OUT_DMAC,
.type = DMAC_USER_HOST_DMA,
.base =.copy_dir = DMAC_DIR_READ,
GTW_HOST_OUT_STREAM_BASE(0), .channels = 9, .irq = IRQ_EXT_HOST_DMA_OUT_LVL3(0, 0), @@ -153,6 +161,8 @@ static struct dma dma[] = { { /* Link In DMAC */ .plat_data = { .id = DMA_LINK_IN_DMAC,
.type = DMAC_USER_LINK_DMA,
.base = GTW_LINK_IN_STREAM_BASE(0), .channels = 9, .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0, 0),.copy_dir = DMAC_DIR_WRITE,
@@ -163,6 +173,8 @@ static struct dma dma[] = { { /* Link out DMAC */ .plat_data = { .id = DMA_LINK_OUT_DMAC,
.type = DMAC_USER_LINK_DMA,
.base =.copy_dir = DMAC_DIR_READ,
GTW_LINK_OUT_STREAM_BASE(0), .channels = 7, .irq = IRQ_EXT_LINK_DMA_OUT_LVL4(0, 0), @@ -171,15 +183,48 @@ static struct dma dma[] = { .ops = &hda_link_dma_ops, },};
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- int i;
int i, ch_count;
int dma_index = -1;
int min_ch_count = INT32_MAX;
for (i = 0; i < ARRAY_SIZE(dma); i++) {
if (dma[i].plat_data.id == dmac_id)
return &dma[i];
/* check DMAC user type */
if (dma[i].plat_data.type != user)
continue;
/* check DMAC copy dir */
if (dma[i].plat_data.copy_dir != dir)
continue;
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
return &dma[i];
} else {
/* get number of channels in use */
ch_count = dma_channel_status(&dma[i]);
/* Use this DMAC if its channel count is
lower */
if (ch_count < min_ch_count) {
dma_index = i;
min_ch_count = ch_count;
}
}
}
if (dma_index >= 0)
return &dma[dma_index];
return NULL; }
diff --git a/src/platform/haswell/dma.c b/src/platform/haswell/dma.c index 5d1e308..9138e78 100644 --- a/src/platform/haswell/dma.c +++ b/src/platform/haswell/dma.c @@ -124,16 +124,49 @@ static struct dma dma[] = { .ops = &dw_dma_ops, },};
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- For BYT/CHT, ignore the dmac_user and copy_dir arguments
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- switch (dmac_id) {
- case DMA_ID_DMAC0:
return &dma[0];
- case DMA_ID_DMAC1:
return &dma[1];
- default:
return NULL;
- int i, ch_count;
- int min_ch_count = INT32_MAX;
- int dma_index = -1;
- for (i = 0; i < ARRAY_SIZE(dma); i++) {
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
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_channel_status(&dma[i]);
/* 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)
return &dma[dma_index];
return NULL; }
/* Initialize all platform DMAC's */