[Sound-open-firmware] [RFC PATCH 3/6] dma: introduce new API for requesting DMAC
rander.wang
rander.wang at linux.intel.com
Wed Jun 6 08:16:45 CEST 2018
On 6/6/2018 2:06 PM, Ranjani Sridharan wrote:
> On Wed, 2018-06-06 at 10:23 +0800, rander.wang wrote:
>> 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 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?
>> yes, i find only dam_copy_dir is fit for capabilities. how
>> do
>> you think about it?
> OK, keyon has a similar suggestion and I think it makes sense.
> But he mentioned that for BDW, both DMAC's support all possible caps.
>
> Could you please reply to that and correct if something is wrong? It
> will be useful for me when I implement. I'll verify with the HAS as
> well.
Hi, i just talk to keyon, no such conclusion, he just made some
examples.
please do as we talked.
thank you!
>>>>> +/* 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 */
>> _______________________________________________
>> Sound-open-firmware mailing list
>> Sound-open-firmware at alsa-project.org
>> http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
More information about the Sound-open-firmware
mailing list