[Sound-open-firmware] [RFC PATCH 3/6] dma: introduce new API for requesting DMAC
Ranjani Sridharan
ranjani.sridharan at linux.intel.com
Tue Jun 5 21:12:03 CEST 2018
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 at 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?
>
> > +/* 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,
> > + .copy_dir = DMAC_DIR_DUPLEX,
> > .base = LP_GP_DMA_BASE(0),
> > .channels = 8,
> > .irq = IRQ_EXT_LP_GPDMA0_LVL5(0,
> > 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,
> > + .copy_dir = DMAC_DIR_DUPLEX,
> > .base = LP_GP_DMA_BASE(1),
> > .channels = 8,
> > .irq = IRQ_EXT_LP_GPDMA1_LVL5(0,
> > 0),
> > @@ -132,6 +136,8 @@ static struct dma dma[] = {
> > { /* Host In DMAC */
> > .plat_data = {
> > .id = DMA_HOST_IN_DMAC,
> > + .type = DMAC_USER_HOST_DMA,
> > + .copy_dir = DMAC_DIR_WRITE,
> > .base = GTW_HOST_IN_STREAM_BASE(0),
> > .channels = 7,
> > .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0,
> > 0),
> > @@ -142,6 +148,8 @@ static struct dma dma[] = {
> > { /* Host out DMAC */
> > .plat_data = {
> > .id = DMA_HOST_OUT_DMAC,
> > + .type = DMAC_USER_HOST_DMA,
> > + .copy_dir = DMAC_DIR_READ,
> > .base =
> > 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,
> > + .copy_dir = DMAC_DIR_WRITE,
> > .base = GTW_LINK_IN_STREAM_BASE(0),
> > .channels = 8,
> > .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0,
> > 0),
> > @@ -162,6 +172,8 @@ static struct dma dma[] = {
> > { /* Link out DMAC */
> > .plat_data = {
> > .id = DMA_LINK_OUT_DMAC,
> > + .type = DMAC_USER_LINK_DMA,
> > + .copy_dir = DMAC_DIR_READ,
> > .base =
> > 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,
> > + .copy_dir = DMAC_DIR_DUPLEX,
> > .base = LP_GP_DMA_BASE(0),
> > .channels = 8,
> > .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0),
> > @@ -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,
> > + .copy_dir = DMAC_DIR_DUPLEX,
> > .base = LP_GP_DMA_BASE(1),
> > .channels = 8,
> > .irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0),
> > @@ -133,6 +137,8 @@ static struct dma dma[] = {
> > { /* Host In DMAC */
> > .plat_data = {
> > .id = DMA_HOST_IN_DMAC,
> > + .type = DMAC_USER_HOST_DMA,
> > + .copy_dir = DMAC_DIR_WRITE,
> > .base = GTW_HOST_IN_STREAM_BASE(0),
> > .channels = 7,
> > .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0, 0),
> > @@ -143,6 +149,8 @@ static struct dma dma[] = {
> > { /* Host out DMAC */
> > .plat_data = {
> > .id = DMA_HOST_OUT_DMAC,
> > + .type = DMAC_USER_HOST_DMA,
> > + .copy_dir = DMAC_DIR_READ,
> > .base =
> > 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,
> > + .copy_dir = DMAC_DIR_WRITE,
> > .base = GTW_LINK_IN_STREAM_BASE(0),
> > .channels = 9,
> > .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0, 0),
> > @@ -163,6 +173,8 @@ static struct dma dma[] = {
> > { /* Link out DMAC */
> > .plat_data = {
> > .id = DMA_LINK_OUT_DMAC,
> > + .type = DMAC_USER_LINK_DMA,
> > + .copy_dir = DMAC_DIR_READ,
> > .base =
> > 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 */
More information about the Sound-open-firmware
mailing list