[Sound-open-firmware] [RFC PATCH 3/6] dma: introduce new API for requesting DMAC

Ranjani Sridharan ranjani.sridharan at linux.intel.com
Thu Jun 7 19:26:24 CEST 2018


On Wed, 2018-06-06 at 11:20 +0800, Keyon Jie wrote:
> 
> On 2018年06月06日 03:18, Ranjani Sridharan wrote:
> > On Tue, 2018-06-05 at 19:05 +0800, Keyon Jie wrote:
> > > 
> > > On 2018年06月05日 12:23, 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,
> > > > +};
> > > 
> > > I can't understand this, what is read and what is write?
> > > For DMA, it always read from some buffer and write them to
> > > another
> > > buffer.
> > > 
> > > [edit] after reading the patch, I got your point. maybe naming it
> > > with
> > > 
> > > +enum dmac_dir_cap {
> > > +	DMAC_CAP_READ = 0,
> > > +	DMAC_CAP_WRITE,
> > > +	DMAC_CAP_DUPLEX,
> > > +};
> > > 
> > > or we can use bit mask for that, which can be reused with user
> > > type
> > > below also, e.g.
> > > 
> > > bit 0: cap_read
> > > bit 1: cap_write
> > > bit 2: host/link
> > > bit 3: lp/hp.
> > > bit 4: share/exclusive
> > 
> > I can rename the enum but I'd like to stick with the arguments for
> > the
> > dma_get API. It is really only 3 arguments and it makes deciphering
> > code much easier than applying bitmasks.
> > 
> > Unless, you have a compelling reason for me not to use separate
> > arguments?
> 
> I think using the bitmasks is more object oriented, e.g. for
> direction, 
> what directions does your dmac supported? host_mem_to_mem(1)? 
> mem_to_mem(2)? mem_to_dev(3)? dev_to_dev(4)? mem_to_link(5)? or the 
> opposite? The combination of these can be up to 10.
> 
> for byt/bdw, we can support (1)(2)(3)(4)(6)(7)(8)(9);
> for apl/cnl, host_dmac_output can support (1) only, host_dmac_input
> can 
> support (6) only, gpdma can support (2)(3)(4)(7)(8)(9),
> link_dmac_output 
> can support (5), link_dmac_input can support (10) only.
> 
> if you tell these clear enough, you will be able to use unify logic
> in a 
> common dma_get():
> 		/* check DMAC copy dir */
> 		if (dma[i].plat_data.caps & require_cap == require_cap)
> 			retrun dma[i]; // very simple, isn't it?
> 
> for the user:
> byt/bdw: playback,
> 	host: dma_get(host_mem_to_mem);
> 	dai: dma_get(mem_to_dev);
>      capture,
> 	host: dma_get(mem_to_hostmem);
> 	dai: dma_get(dev_to_mem_);
>      page_table_parsing,
> 	dma_get(host_mem_to_mem);
>      dma_trace,
> 	dma_get(mem_to_host_mem).
> apl/cnl: playback,
> 	host: dma_get(host_mem_to_mem);
> 	dai: dma_get(mem_to_dev);
>      capture,
> 	host: dma_get(mem_to_hostmem);
> 	dai: dma_get(dev_to_mem_);
>      page_table_parsing,
> 	dma_get(host_mem_to_mem);
>      dma_trace,
> 	dma_get(mem_to_host_mem).Keyon/Rander,
> 
> 
Keyon/Rander,

I did some experiments with the new API suggested and ran into issues
with the APL platform. And the problem was with the ipc DMAC. What type
would I use for ipc? We've been using the GP LP DMA for ipc but with
this API, there's no way for me to request a GPLP DMA and requesting a
capability of mem_to_mem or mem_dev/dev_to_mem, just to get a GP_LP DMA
, would be misleading. So I think I am leaning back to the original
solution proposed by Liam. 

We will have to qualify DMAC with a type and copy cap like like these:

DMAC_TYPE would be one of: GP_LP_DMA, GP_HP_DMA, Host_DMA or Link DMA

DMAC_COPY_CAP would be one of: REDA, WRITE or DUPLEX

With this it is easy for me to choose the dma like this: 

host: dma_get(Host_DMA, READ/WRITE, FLAGS)
dai: dma_get(GP_LP_DMA, READ/WRITE, FLAGS)
page table: dma_get(HOST_DMA, READ, FLAGS)
ipc: dma_get(GP_LP_DMA, DUPLEX)

Let me know your thoughts.

Thanks,
Ranjani

> 
> 
> can you see what? with this, you can make the code very clean/unified
> in 
> host/dai/dma_trace...
> 
> 
> > 
> > > ...
> > > 
> > > > +
> > > > +/* DMAC user types */
> > > > +enum dmac_user {
> > > > +	DMAC_USER_HOST_DMA = 0,
> > > > +	DMAC_USER_LINK_DMA,
> > > 
> > > do we need split into output and input for these?
> > > 
> > > > +	DMAC_USER_GP_LP_DMA,
> > > > +	DMAC_USER_GP_HP_DMA,
> > > > +};
> > > > +
> > > > +/* DMAC flags */
> > > > +#define DMAC_FLAGS_SHARED	0
> > > > +#define DMAC_FLAGS_EXCLUSIVE	(1 << 0)
> > > 
> > > Can you explain what is shared and how channels are shared?
> > > Are you meaning channel reservation for specific user with
> > > exclusive?
> > > I can't image the use case for this.
> > 
> > Shared is the most common usage, where we share DMAC between users.
> > 
> > Exclusive as Liam explained will be fore critical usages that
> > require
> > that only one user will use the DMAC at any time. ie there will
> > only be
> > one channel draining at any time.
> 
> Hi Liam, can you explain more about this? Where is the limitation
> about 
> only one channel draining at the same time, from DMAC or the user?
> Per 
> my understanding, channels of the same DMAC are quite independent,
> they 
> can in draining at the same time from the point of DMAC. And, we
> event 
> don't use the DMA draining feature yet.
> 
> Thanks,
> ~Keyon
> 
> > 
> > I havent seen the need for exclusive access so far. But we might
> > need
> > it in the future.
> > 
> > > 
> > > 
> > > > +
> > > >    /* 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;
> > > >    }
> > > 
> > > again, this function can be shared also?
> > > 
> > > Thanks,
> > > ~Keyon
> > > 
> > > >    
> > > > 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-firmw
> > > are


More information about the Sound-open-firmware mailing list