[RFC]DMA API Update


Liu, Baohong
 

Hi everyone,

I would like to propose the update for DMA API.
(https://jira.zephyrproject.org/browse/ZEP-873).

Known Problems
--------

Struct dma_channel_config consists of quite a few variables of enum types,
two callback function pointers, and one callback user data pointer.

- The enums can be collapsed into a bit field.
This will reduce the size of the data structure.

- The two callback function pointers (for normal and error cases) can be combined.
A parameter of error code can be used to differentiate the two cases. So, the
current callback parameter of user data pointer will be replaced by two new
parameters. One for error code and the other one for channel id.

- Callback data pointer can be removed.
Currently, this field holds user data. It can be moved to driver data structure.
The callback function can dig out the information from dev pointer and
channel id passed to it.

Proposed Solution
--------

-- The following are the enums we have now.

handshake_interface /* which peripheral and direction*/
hankshake_polarity /* high or low*/
channel_direction /* memory to memory, memory to peripheral ... */
Source_transfer_width /* source data size */
Destination_transfer_width /* destination data size */
Source_burst_length /* source burst length */
Destination_burst_length /* destination burst length */

All these will be collapsed into a bit field. Some of them will have new names.

Besides the above, three new items will be added.
source_handshake /* HW or SW */
dest_handshake /* HW or SW */
channel_priority /* DMA channel priority */

-- For the callback function, there will be three parameters. They are device pointer,
channel_id, and error code. As said above, the error callback will be removed.

-- The callback_data pointer will be removed.

Final API Format
--------

/**
* @brief DMA configuration structure.
*
* config is a bit field with the following parts:
* dma_slot [ 0 : 5 ] --which peripheral and direction(HW specific)
* hankshake_polarity [ 6 ] --high or low
* channel_direction [ 7 : 9 ] --0-memory to memory, 1-memory to peripheral,
* 2-peripheral to memory
* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128 and 256 bits)
* dest_data_size [ 13 : 15 ] --destination data size(8,16,32,64,128 and 256 bits)
* source_burst_length [ 16 : 18 ] --number of source data unit(1,4,8,16,32,64,128 and 256)
* dest_burst_length [ 19 : 21 ] -- number of dest data unit(1,4,8,16,32,64,128 and 256)
* source_handshake [ 22 ] --HW or SW
* dest_handshake [ 23 ] --HW or SW
* channel_priority [ 24 : 27 ] --DMA channel priority
* RESERVED [ 28 : 31 ]
* dma_callback is the callback function pointer
*/
struct dma_channel_config {
uint32_t config;
void (*dma_callback)(struct device *dev, uint32_t channel, int error_code);
}

The remaining parts will stay the same.
No change to the structure dma_transfer_config.
No change to the API function prototypes:
dma_channel_config(...)
dma_transfer_config(...)
dma_transfer_start(...)
dma_transfer_stop(...)

(Note: for xx_data_size and xx_burst_length in the above bit field, the value will only serve
as an index. For example, for source_data_size, bit field values of 0, 1, 2, 3, 4 and 5 will
correspond to sizes of 8,16,32,64,128 and 256 bits.)

Suggestions and comments are welcome.


Piotr Mieńkowski <piotr.mienkowski at gmail.com...>
 

Hi Baohong,

Thanks for preparing the proposal for the new DMA API. I'm working
currently on the Atmel SAM family DMA driver and am very interested in
the topic.

Before I send my comments I have a general question: Is the DMA API
meant to serve exclusively user applications, the one build on top of
Zephyr, or is it meant to be used also by the device driver code?

The way I understand it providing DMA API exclusively for user
applications means it can be kept simple and portable. Providing DMA API
that can be used by device drivers means it should support all the
intricate features of the given DMA hardware module, i.e. API should not
put (too much) limits on what hardware can do.

Regards,
Piotr

On 11.01.2017 20:49, Liu, Baohong wrote:
Hi everyone,

I would like to propose the update for DMA API.
(https://jira.zephyrproject.org/browse/ZEP-873).

Known Problems
--------

Struct dma_channel_config consists of quite a few variables of enum types,
two callback function pointers, and one callback user data pointer.

- The enums can be collapsed into a bit field.
This will reduce the size of the data structure.

- The two callback function pointers (for normal and error cases) can be combined.
A parameter of error code can be used to differentiate the two cases. So, the
current callback parameter of user data pointer will be replaced by two new
parameters. One for error code and the other one for channel id.

- Callback data pointer can be removed.
Currently, this field holds user data. It can be moved to driver data structure.
The callback function can dig out the information from dev pointer and
channel id passed to it.

Proposed Solution
--------

-- The following are the enums we have now.

handshake_interface /* which peripheral and direction*/
hankshake_polarity /* high or low*/
channel_direction /* memory to memory, memory to peripheral ... */
Source_transfer_width /* source data size */
Destination_transfer_width /* destination data size */
Source_burst_length /* source burst length */
Destination_burst_length /* destination burst length */

All these will be collapsed into a bit field. Some of them will have new names.

Besides the above, three new items will be added.
source_handshake /* HW or SW */
dest_handshake /* HW or SW */
channel_priority /* DMA channel priority */

-- For the callback function, there will be three parameters. They are device pointer,
channel_id, and error code. As said above, the error callback will be removed.

-- The callback_data pointer will be removed.

Final API Format
--------

/**
* @brief DMA configuration structure.
*
* config is a bit field with the following parts:
* dma_slot [ 0 : 5 ] --which peripheral and direction(HW specific)
* hankshake_polarity [ 6 ] --high or low
* channel_direction [ 7 : 9 ] --0-memory to memory, 1-memory to peripheral,
* 2-peripheral to memory
* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128 and 256 bits)
* dest_data_size [ 13 : 15 ] --destination data size(8,16,32,64,128 and 256 bits)
* source_burst_length [ 16 : 18 ] --number of source data unit(1,4,8,16,32,64,128 and 256)
* dest_burst_length [ 19 : 21 ] -- number of dest data unit(1,4,8,16,32,64,128 and 256)
* source_handshake [ 22 ] --HW or SW
* dest_handshake [ 23 ] --HW or SW
* channel_priority [ 24 : 27 ] --DMA channel priority
* RESERVED [ 28 : 31 ]
* dma_callback is the callback function pointer
*/
struct dma_channel_config {
uint32_t config;
void (*dma_callback)(struct device *dev, uint32_t channel, int error_code);
}

The remaining parts will stay the same.
No change to the structure dma_transfer_config.
No change to the API function prototypes:
dma_channel_config(...)
dma_transfer_config(...)
dma_transfer_start(...)
dma_transfer_stop(...)

(Note: for xx_data_size and xx_burst_length in the above bit field, the value will only serve
as an index. For example, for source_data_size, bit field values of 0, 1, 2, 3, 4 and 5 will
correspond to sizes of 8,16,32,64,128 and 256 bits.)

Suggestions and comments are welcome.


Liu, Baohong
 

HI Piotr,

They are for user applications. Drivers are to implement them.

Thanks
Baohong

From: Piotr Mienkowski [mailto:piotr.mienkowski(a)gmail.com]
Sent: Thursday, January 12, 2017 11:25 AM
To: devel(a)lists.zephyrproject.org
Subject: [devel] Re: [RFC]DMA API Update


Hi Baohong,

Thanks for preparing the proposal for the new DMA API. I'm working currently on the Atmel SAM family DMA driver and am very interested in the topic.

Before I send my comments I have a general question: Is the DMA API meant to serve exclusively user applications, the one build on top of Zephyr, or is it meant to be used also by the device driver code?

The way I understand it providing DMA API exclusively for user applications means it can be kept simple and portable. Providing DMA API that can be used by device drivers means it should support all the intricate features of the given DMA hardware module, i.e. API should not put (too much) limits on what hardware can do.

Regards,
Piotr

On 11.01.2017 20:49, Liu, Baohong wrote:



Hi everyone,



I would like to propose the update for DMA API.

(https://jira.zephyrproject.org/browse/ZEP-873).



Known Problems

--------



Struct dma_channel_config consists of quite a few variables of enum types,

two callback function pointers, and one callback user data pointer.



- The enums can be collapsed into a bit field.

This will reduce the size of the data structure.



- The two callback function pointers (for normal and error cases) can be combined.

A parameter of error code can be used to differentiate the two cases. So, the

current callback parameter of user data pointer will be replaced by two new

parameters. One for error code and the other one for channel id.



- Callback data pointer can be removed.

Currently, this field holds user data. It can be moved to driver data structure.

The callback function can dig out the information from dev pointer and

channel id passed to it.



Proposed Solution

--------



-- The following are the enums we have now.



handshake_interface /* which peripheral and direction*/

hankshake_polarity /* high or low*/

channel_direction /* memory to memory, memory to peripheral ... */

Source_transfer_width /* source data size */

Destination_transfer_width /* destination data size */

Source_burst_length /* source burst length */

Destination_burst_length /* destination burst length */



All these will be collapsed into a bit field. Some of them will have new names.



Besides the above, three new items will be added.

source_handshake /* HW or SW */

dest_handshake /* HW or SW */

channel_priority /* DMA channel priority */



-- For the callback function, there will be three parameters. They are device pointer,

channel_id, and error code. As said above, the error callback will be removed.



-- The callback_data pointer will be removed.



Final API Format

--------



/**

* @brief DMA configuration structure.

*

* config is a bit field with the following parts:

* dma_slot [ 0 : 5 ] --which peripheral and direction(HW specific)

* hankshake_polarity [ 6 ] --high or low

* channel_direction [ 7 : 9 ] --0-memory to memory, 1-memory to peripheral,

* 2-peripheral to memory

* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128 and 256 bits)

* dest_data_size [ 13 : 15 ] --destination data size(8,16,32,64,128 and 256 bits)

* source_burst_length [ 16 : 18 ] --number of source data unit(1,4,8,16,32,64,128 and 256)

* dest_burst_length [ 19 : 21 ] -- number of dest data unit(1,4,8,16,32,64,128 and 256)

* source_handshake [ 22 ] --HW or SW

* dest_handshake [ 23 ] --HW or SW

* channel_priority [ 24 : 27 ] --DMA channel priority

* RESERVED [ 28 : 31 ]

* dma_callback is the callback function pointer

*/

struct dma_channel_config {

uint32_t config;

void (*dma_callback)(struct device *dev, uint32_t channel, int error_code);

}



The remaining parts will stay the same.

No change to the structure dma_transfer_config.

No change to the API function prototypes:

dma_channel_config(...)

dma_transfer_config(...)

dma_transfer_start(...)

dma_transfer_stop(...)



(Note: for xx_data_size and xx_burst_length in the above bit field, the value will only serve

as an index. For example, for source_data_size, bit field values of 0, 1, 2, 3, 4 and 5 will

correspond to sizes of 8,16,32,64,128 and 256 bits.)



Suggestions and comments are welcome.


Piotr Mieńkowski <piotr.mienkowski at gmail.com...>
 

Hi Baohong,

They are for user applications. Drivers are to implement them.



Before I send my comments I have a general question: Is the DMA API
meant to serve exclusively user applications, the one build on top of
Zephyr, or is it meant to be used also by the device driver code?
I'm not sure I understood your answer correctly. Let me explain my point
again with an example.

Atmel SAM DMA module has features like linked list which allows to set
up multi block memory transfer, e.g. one could easily set up DMA
transfer for Zephyr's fifo queue. Also features like memory striding to
access data in the interleaved manner (every n-th data element). These
more advanced features are likely going to be used by the device drivers
but probably not by the user application.

From your answer I understand that DMA API update you propose is aimed
at user applications. That means that additionally every SoC family
should provide its own private DMA API to be used by the device drivers.
I.e. when I write Atmel SAM audio driver that uses DMA transfer this
driver should access private Atmel SAM DMA API and not the public DMA
API. Is that correct?

Regards,
Piotr


Liu, Baohong
 

Hi Piotr,

The APIs are for SoC DMA engine. There will be a DMA driver for each SoC to implement these APIs.
Users can use these APIs to play with the DMA engine or do whatever they like. Other device drivers
for example SPI can use them of course. But, they can directly call functions in the DMA driver(ignoring
these APIs and do the thing internally—this is the way for quark currently). What does this mean? The
DMA driver will have all the details for the HW. But, you do not need to expose all the details through
the DMA APIs we are talking about unless the target callers of these APIs need them.

I am OK to change the RFC if you think it is necessary to expose more HW details through these APIs.
Let me know.

Thanks
Baohong

From: Piotr Mienkowski [mailto:piotr.mienkowski(a)gmail.com]
Sent: Thursday, January 12, 2017 2:21 PM
To: Liu, Baohong <baohong.liu(a)intel.com>; devel(a)lists.zephyrproject.org
Subject: Re: [devel] Re: [RFC]DMA API Update

Hi Baohong,


They are for user applications. Drivers are to implement them.

Before I send my comments I have a general question: Is the DMA API meant to serve exclusively user applications, the one build on top of Zephyr, or is it meant to be used also by the device driver code?
I'm not sure I understood your answer correctly. Let me explain my point again with an example.

Atmel SAM DMA module has features like linked list which allows to set up multi block memory transfer, e.g. one could easily set up DMA transfer for Zephyr's fifo queue. Also features like memory striding to access data in the interleaved manner (every n-th data element). These more advanced features are likely going to be used by the device drivers but probably not by the user application.

From your answer I understand that DMA API update you propose is aimed at user applications. That means that additionally every SoC family should provide its own private DMA API to be used by the device drivers. I.e. when I write Atmel SAM audio driver that uses DMA transfer this driver should access private Atmel SAM DMA API and not the public DMA API. Is that correct?

Regards,
Piotr


Nallasellan, Singaravelan
 

It is required to add slave or controller id which is 32 bits. Some DMA controllers require to program mux to connect the hardware handshake signals to the selected peripheral with the channel.

-----Original Message-----
From: Liu, Baohong [mailto:baohong.liu(a)intel.com]
Sent: Thursday, January 12, 2017 1:20 AM
To: devel(a)lists.zephyrproject.org
Subject: [devel] [RFC]DMA API Update


Hi everyone,

I would like to propose the update for DMA API.
(https://jira.zephyrproject.org/browse/ZEP-873).

Known Problems
--------

Struct dma_channel_config consists of quite a few variables of enum types,
two callback function pointers, and one callback user data pointer.

- The enums can be collapsed into a bit field.
This will reduce the size of the data structure.

- The two callback function pointers (for normal and error cases) can be
combined.
A parameter of error code can be used to differentiate the two cases. So,
the
current callback parameter of user data pointer will be replaced by two
new
parameters. One for error code and the other one for channel id.

- Callback data pointer can be removed.
Currently, this field holds user data. It can be moved to driver data
structure.
The callback function can dig out the information from dev pointer and
channel id passed to it.

Proposed Solution
--------

-- The following are the enums we have now.

handshake_interface /* which peripheral and direction*/
hankshake_polarity /* high or low*/
channel_direction /* memory to memory, memory to peripheral ... */
Source_transfer_width /* source data size */
Destination_transfer_width /* destination data size */
Source_burst_length /* source burst length */
Destination_burst_length /* destination burst length */

All these will be collapsed into a bit field. Some of them will have new names.

Besides the above, three new items will be added.
source_handshake /* HW or SW */
dest_handshake /* HW or SW */
channel_priority /* DMA channel priority */

-- For the callback function, there will be three parameters. They are device
pointer,
channel_id, and error code. As said above, the error callback will be
removed.

-- The callback_data pointer will be removed.

Final API Format
--------

/**
* @brief DMA configuration structure.
*
* config is a bit field with the following parts:
* dma_slot [ 0 : 5 ] --which peripheral and
direction(HW specific)
* hankshake_polarity [ 6 ] --high or low
* channel_direction [ 7 : 9 ] --0-memory to memory, 1-
memory to peripheral,
* 2-peripheral to memory
* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128
and 256 bits)
* dest_data_size [ 13 : 15 ] --destination data
size(8,16,32,64,128 and 256 bits)
* source_burst_length [ 16 : 18 ] --number of source data
unit(1,4,8,16,32,64,128 and 256)
* dest_burst_length [ 19 : 21 ] -- number of dest data
unit(1,4,8,16,32,64,128 and 256)
* source_handshake [ 22 ] --HW or SW
* dest_handshake [ 23 ] --HW or SW
* channel_priority [ 24 : 27 ] --DMA channel priority
* RESERVED [ 28 : 31 ]
* dma_callback is the callback function pointer
*/
struct dma_channel_config {
uint32_t config;
void (*dma_callback)(struct device *dev, uint32_t channel, int
error_code); }

The remaining parts will stay the same.
No change to the structure dma_transfer_config.
No change to the API function prototypes:
dma_channel_config(...)
dma_transfer_config(...)
dma_transfer_start(...)
dma_transfer_stop(...)

(Note: for xx_data_size and xx_burst_length in the above bit field, the value
will only serve as an index. For example, for source_data_size, bit field values
of 0, 1, 2, 3, 4 and 5 will correspond to sizes of 8,16,32,64,128 and 256 bits.)

Suggestions and comments are welcome.


Huaqi Fang
 

Hi Baohong,

First thanks for proposal about DMA API update.
I want to post some of our use cases and requirements around DMA API, since I am working on Designware ARC Core support in Synopsys, our hardware platform EMSK is already supported in zephyr, and in EMSK 2.2 version, there is a uDMA component in it.
For uDMA component description: https://www.synopsys.com/dw/ipdir.php?ds=arc-system-integration-options
1. As other developers said, for DMA transfers, there are different types of transfer, single list transfer, linked list transfer. But it seems in this API proposal, there is no consideration.
2. In ARC core, it has many aux registers, and the DMA support not just memory to memory, or memory to peripheral, it also support memory to aux interface. Maybe some other DMA component also support different interfaces.
3. For DMA transfer, each burst transfer can be auto-requested or manual requested by peripheral interface signal.

Currently we have uDMA driver for ARC in embARC project: https://www.embarc.org/, if you want to take a look at it, you can register an account and download it.

I post our use cases and requirements here, so hopes that the DMA API can take these into consideration.

Thanks
Huaqi

-----Original Message-----
From: Nallasellan, Singaravelan [mailto:singaravelan.nallasellan(a)intel.com]
Sent: 2017年1月13日 13:40
To: Liu, Baohong <baohong.liu(a)intel.com>; devel(a)lists.zephyrproject.org
Subject: [devel] Re: [RFC]DMA API Update

It is required to add slave or controller id which is 32 bits. Some DMA controllers require to program mux to connect the hardware handshake signals to the selected peripheral with the channel.

-----Original Message-----
From: Liu, Baohong [mailto:baohong.liu(a)intel.com]
Sent: Thursday, January 12, 2017 1:20 AM
To: devel(a)lists.zephyrproject.org
Subject: [devel] [RFC]DMA API Update


Hi everyone,

I would like to propose the update for DMA API.
(https://urldefense.proofpoint.com/v2/url?u=https-3A__jira.zephyrproject.org_browse_ZEP-2D873&d=DgIFAg&c=DPL6_X_6JkXFx7AXWqB0tg&r=KI3IYdedpLSnsCSZ0k3Gcp6fYWESKi3RE-hGv_ZefTg&m=apJcm5GKxXOZ-B-8xed5zGD7lHnTwvAlcy0LrqN83L0&s=4lO6HbTvx4_-SnlOC8xe3edTD8vU2Ych1Arh29j2ATQ&e= ).

Known Problems
--------

Struct dma_channel_config consists of quite a few variables of enum
types, two callback function pointers, and one callback user data pointer.

- The enums can be collapsed into a bit field.
This will reduce the size of the data structure.

- The two callback function pointers (for normal and error cases) can
be combined.
A parameter of error code can be used to differentiate the two
cases. So, the
current callback parameter of user data pointer will be replaced by
two new
parameters. One for error code and the other one for channel id.

- Callback data pointer can be removed.
Currently, this field holds user data. It can be moved to driver
data structure.
The callback function can dig out the information from dev pointer and
channel id passed to it.

Proposed Solution
--------

-- The following are the enums we have now.

handshake_interface /* which peripheral and direction*/
hankshake_polarity /* high or low*/
channel_direction /* memory to memory, memory to peripheral ... */
Source_transfer_width /* source data size */
Destination_transfer_width /* destination data size */
Source_burst_length /* source burst length */
Destination_burst_length /* destination burst length */

All these will be collapsed into a bit field. Some of them will have new names.

Besides the above, three new items will be added.
source_handshake /* HW or SW */
dest_handshake /* HW or SW */
channel_priority /* DMA channel priority */

-- For the callback function, there will be three parameters. They are
device pointer,
channel_id, and error code. As said above, the error callback
will be removed.

-- The callback_data pointer will be removed.

Final API Format
--------

/**
* @brief DMA configuration structure.
*
* config is a bit field with the following parts:
* dma_slot [ 0 : 5 ] --which peripheral and
direction(HW specific)
* hankshake_polarity [ 6 ] --high or low
* channel_direction [ 7 : 9 ] --0-memory to memory, 1-
memory to peripheral,
* 2-peripheral to memory
* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128
and 256 bits)
* dest_data_size [ 13 : 15 ] --destination data
size(8,16,32,64,128 and 256 bits)
* source_burst_length [ 16 : 18 ] --number of source data
unit(1,4,8,16,32,64,128 and 256)
* dest_burst_length [ 19 : 21 ] -- number of dest data
unit(1,4,8,16,32,64,128 and 256)
* source_handshake [ 22 ] --HW or SW
* dest_handshake [ 23 ] --HW or SW
* channel_priority [ 24 : 27 ] --DMA channel priority
* RESERVED [ 28 : 31 ]
* dma_callback is the callback function pointer
*/
struct dma_channel_config {
uint32_t config;
void (*dma_callback)(struct device *dev, uint32_t channel, int
error_code); }

The remaining parts will stay the same.
No change to the structure dma_transfer_config.
No change to the API function prototypes:
dma_channel_config(...)
dma_transfer_config(...)
dma_transfer_start(...)
dma_transfer_stop(...)

(Note: for xx_data_size and xx_burst_length in the above bit field,
the value will only serve as an index. For example, for
source_data_size, bit field values of 0, 1, 2, 3, 4 and 5 will
correspond to sizes of 8,16,32,64,128 and 256 bits.)

Suggestions and comments are welcome.


Jon Medhurst (Tixy) <tixy@...>
 

On Wed, 2017-01-11 at 19:49 +0000, Liu, Baohong wrote:

/**
* @brief DMA configuration structure.
*
* config is a bit field with the following parts:
* dma_slot [ 0 : 5 ] --which peripheral and direction(HW specific)
* hankshake_polarity [ 6 ] --high or low
Is hankshake_polarity something which affects both source_handshake and
dest_handshake? If so, you sure that no hardware combination might want
different polarities for these? And is handshake something that can have
more than one valid setting, or is it determined by how the hardware is
constructed and wired up? If the latter, then these values probably
shouldn't be in a public API for use by applications and instead set by
the DMA engine to the correct values based on the value of dma_slot or
something other property of the transfer it knows.

* channel_direction [ 7 : 9 ] --0-memory to memory, 1-memory to peripheral,
* 2-peripheral to memory
* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128 and 256 bits)
* dest_data_size [ 13 : 15 ] --destination data size(8,16,32,64,128 and 256 bits)
* source_burst_length [ 16 : 18 ] --number of source data unit(1,4,8,16,32,64,128 and 256)
* dest_burst_length [ 19 : 21 ] -- number of dest data unit(1,4,8,16,32,64,128 and 256)
Why are burst lengths a fixed sequence of power's of two? And why isn't
'2' in the list? Why not just have an arbitrary integer? That's a
rhetorical question, I know why, because it matches the Quark hardware,
and the DMA API, like a lot of APIs in Zephyr, is specific to that one
piece of hardware.

* source_handshake [ 22 ] --HW or SW
* dest_handshake [ 23 ] --HW or SW
* channel_priority [ 24 : 27 ] --DMA channel priority
* RESERVED [ 28 : 31 ]
* dma_callback is the callback function pointer
*/

struct dma_channel_config {
uint32_t config;
void (*dma_callback)(struct device *dev, uint32_t channel, int error_code);
}

The remaining parts will stay the same.
No change to the structure dma_transfer_config.
No change to the API function prototypes:
dma_channel_config(...)
dma_transfer_config(...)
dma_transfer_start(...)
dma_transfer_stop(...)
I also see the existing DMA API doesn't support scatter-gather, that's a
fairly common and useful feature of DMA hardware.

But finally, the big elephant in the room is: how are DMA APIs actually
expected to used? And how should the system be configured?

Currently, the only code in Zephyr that does DMA is of course Quark, and
the driver for each peripheral that can do DMA is Quark specific and
knows about Quark DMA.

So what about an SoC with a some generic DMA IP that has a Zephyr
driver, and a bunch of generic peripherals with there own drivers, and
an application that wants to use one of the said peripherals, which
software component configures the dma channel and how is the system
configured so that has the right knowledge to do that?

That's probably a rhetorical question to. The answer is that Zephyr
get's device-tree support and pinches designed ideas from Linux (which
presumably borrowed heavily from other places as well).

--
Tixy


Liu, Baohong
 

-----Original Message-----
From: Nallasellan, Singaravelan
Sent: Thursday, January 12, 2017 9:40 PM
To: Liu, Baohong <baohong.liu(a)intel.com>; devel(a)lists.zephyrproject.org
Subject: RE: [RFC]DMA API Update

It is required to add slave or controller id which is 32 bits. Some DMA
Please attach document (datasheets for example) and point out which page/section
you were referring to.

controllers require to program mux to connect the hardware handshake
signals to the selected peripheral with the channel.
There are different names for this across SoCs. Dma_slot, handshake_interface...
I chose dma_slot. In other words, it has been taken care.


-----Original Message-----
From: Liu, Baohong [mailto:baohong.liu(a)intel.com]
Sent: Thursday, January 12, 2017 1:20 AM
To: devel(a)lists.zephyrproject.org
Subject: [devel] [RFC]DMA API Update


Hi everyone,

I would like to propose the update for DMA API.
(https://jira.zephyrproject.org/browse/ZEP-873).

Known Problems
--------

Struct dma_channel_config consists of quite a few variables of enum
types, two callback function pointers, and one callback user data pointer.

- The enums can be collapsed into a bit field.
This will reduce the size of the data structure.

- The two callback function pointers (for normal and error cases) can
be combined.
A parameter of error code can be used to differentiate the two
cases. So, the
current callback parameter of user data pointer will be replaced by
two new
parameters. One for error code and the other one for channel id.

- Callback data pointer can be removed.
Currently, this field holds user data. It can be moved to driver
data structure.
The callback function can dig out the information from dev pointer and
channel id passed to it.

Proposed Solution
--------

-- The following are the enums we have now.

handshake_interface /* which peripheral and direction*/
hankshake_polarity /* high or low*/
channel_direction /* memory to memory, memory to peripheral ... */
Source_transfer_width /* source data size */
Destination_transfer_width /* destination data size */
Source_burst_length /* source burst length */
Destination_burst_length /* destination burst length */

All these will be collapsed into a bit field. Some of them will have new
names.

Besides the above, three new items will be added.
source_handshake /* HW or SW */
dest_handshake /* HW or SW */
channel_priority /* DMA channel priority */

-- For the callback function, there will be three parameters. They are
device pointer,
channel_id, and error code. As said above, the error callback
will be removed.

-- The callback_data pointer will be removed.

Final API Format
--------

/**
* @brief DMA configuration structure.
*
* config is a bit field with the following parts:
* dma_slot [ 0 : 5 ] --which peripheral and
direction(HW specific)
* hankshake_polarity [ 6 ] --high or low
* channel_direction [ 7 : 9 ] --0-memory to memory, 1-
memory to peripheral,
* 2-peripheral to memory
* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128
and 256 bits)
* dest_data_size [ 13 : 15 ] --destination data
size(8,16,32,64,128 and 256 bits)
* source_burst_length [ 16 : 18 ] --number of source data
unit(1,4,8,16,32,64,128 and 256)
* dest_burst_length [ 19 : 21 ] -- number of dest data
unit(1,4,8,16,32,64,128 and 256)
* source_handshake [ 22 ] --HW or SW
* dest_handshake [ 23 ] --HW or SW
* channel_priority [ 24 : 27 ] --DMA channel priority
* RESERVED [ 28 : 31 ]
* dma_callback is the callback function pointer
*/
struct dma_channel_config {
uint32_t config;
void (*dma_callback)(struct device *dev, uint32_t channel, int
error_code); }

The remaining parts will stay the same.
No change to the structure dma_transfer_config.
No change to the API function prototypes:
dma_channel_config(...)
dma_transfer_config(...)
dma_transfer_start(...)
dma_transfer_stop(...)

(Note: for xx_data_size and xx_burst_length in the above bit field,
the value will only serve as an index. For example, for
source_data_size, bit field values of 0, 1, 2, 3, 4 and 5 will
correspond to sizes of 8,16,32,64,128 and 256 bits.)

Suggestions and comments are welcome.


Liu, Baohong
 

Thanks for the feedback. See my reply inline.

From: Huaqi Fang [mailto:Huaqi.Fang(a)synopsys.com]
Sent: Thursday, January 12, 2017 10:25 PM

Hi Baohong,

First thanks for proposal about DMA API update.
I want to post some of our use cases and requirements around DMA
API, since I am working on Designware ARC Core support in Synopsys, our
hardware platform EMSK is already supported in zephyr, and in EMSK 2.2
version, there is a uDMA component in it.
For uDMA component description:
https://www.synopsys.com/dw/ipdir.php?ds=arc-system-integration-
options
1. As other developers said, for DMA transfers, there are different
types of transfer, single list transfer, linked list transfer. But it seems in this
API proposal, there is no consideration.
Will add.

2. In ARC core, it has many aux registers, and the DMA support not
just memory to memory, or memory to peripheral, it also support memory to
aux interface. Maybe some other DMA component also support different
interfaces.
dma_slot field has 6 bits and it can cater for 64 different handshake interfaces.

3. For DMA transfer, each burst transfer can be auto-requested or
manual requested by peripheral interface signal.
It has been taken care already. (HW or SW).


Currently we have uDMA driver for ARC in embARC project:
https://www.embarc.org/, if you want to take a look at it, you can register an
account and download it.

I post our use cases and requirements here, so hopes that the DMA
API can take these into consideration.

Thanks
Huaqi


Liu, Baohong
 

Thanks for the feedback. See my reply inline.

From: Jon Medhurst (Tixy) [mailto:tixy(a)linaro.org]
Sent: Friday, January 13, 2017 5:49 AM

On Wed, 2017-01-11 at 19:49 +0000, Liu, Baohong wrote:

/**
* @brief DMA configuration structure.
*
* config is a bit field with the following parts:
* dma_slot [ 0 : 5 ] --which peripheral and
direction(HW specific)
* hankshake_polarity [ 6 ] --high or low
Is hankshake_polarity something which affects both source_handshake and
dest_handshake? If so, you sure that no hardware combination might want
different polarities for these? And is handshake something that can have
more than one valid setting, or is it determined by how the hardware is
constructed and wired up? If the latter, then these values probably shouldn't
be in a public API for use by applications and instead set by the DMA engine
to the correct values based on the value of dma_slot or something other
property of the transfer it knows.
The setting will be set before a new transfer. But, both sending and receiving
sides must follow the same setting.

This is needed to cater for different SoCs.


* channel_direction [ 7 : 9 ] --0-memory to memory, 1-
memory to peripheral,
* 2-peripheral to memory
* source_data_size [ 10 : 12 ] --source data size(8,16,32,64,128
and 256 bits)
* dest_data_size [ 13 : 15 ] --destination data
size(8,16,32,64,128 and 256 bits)
* source_burst_length [ 16 : 18 ] --number of source data
unit(1,4,8,16,32,64,128 and 256)
* dest_burst_length [ 19 : 21 ] -- number of dest data
unit(1,4,8,16,32,64,128 and 256)

Why are burst lengths a fixed sequence of power's of two? And why isn't '2'
in the list? Why not just have an arbitrary integer? That's a rhetorical question,
I know why, because it matches the Quark hardware, and the DMA API, like a
lot of APIs in Zephyr, is specific to that one piece of hardware.
I can add one more value which is 2. So, the burst length will become power's of two.

In my opinion, it does not need to be an arbitrary integer.


* source_handshake [ 22 ] --HW or SW
* dest_handshake [ 23 ] --HW or SW
* channel_priority [ 24 : 27 ] --DMA channel priority
* RESERVED [ 28 : 31 ]
* dma_callback is the callback function pointer
*/

struct dma_channel_config {
uint32_t config;
void (*dma_callback)(struct device *dev, uint32_t channel, int
error_code); }

The remaining parts will stay the same.
No change to the structure dma_transfer_config.
No change to the API function prototypes:
dma_channel_config(...)
dma_transfer_config(...)
dma_transfer_start(...)
dma_transfer_stop(...)
I also see the existing DMA API doesn't support scatter-gather, that's a fairly
common and useful feature of DMA hardware.
Will add.


But finally, the big elephant in the room is: how are DMA APIs actually
expected to used? And how should the system be configured?
The same way as other device drivers. There will be a driver to implement
the APIs for each SoC. App does the config, and initiate the transfer by
calling the APIs.


Currently, the only code in Zephyr that does DMA is of course Quark, and the
driver for each peripheral that can do DMA is Quark specific and knows about
Quark DMA.

So what about an SoC with a some generic DMA IP that has a Zephyr driver,
and a bunch of generic peripherals with there own drivers, and an application
that wants to use one of the said peripherals, which software component
configures the dma channel and how is the system configured so that has the
right knowledge to do that?

That's probably a rhetorical question to. The answer is that Zephyr get's
device-tree support and pinches designed ideas from Linux (which
presumably borrowed heavily from other places as well).

--
Tixy


Jon Medhurst (Tixy) <tixy@...>
 

On Sat, 2017-01-14 at 00:31 +0000, Liu, Baohong wrote:
Thanks for the feedback. See my reply inline.
From: Jon Medhurst (Tixy) [mailto:tixy(a)linaro.org]
[...]

But finally, the big elephant in the room is: how are DMA APIs actually
expected to used? And how should the system be configured?
The same way as other device drivers. There will be a driver to implement
the APIs for each SoC. App does the config, and initiate the transfer by
calling the APIs.
As far as I can see there is no documentation or examples in Zephyr that
give a clue as to how DMA can be used with device drivers. So it's very
difficult to review a DMA API without some more explanation on it's
expected use.

Let me try some more specific questions...

Say I have a system which has:
A) a driver for a DMA Controller (it implement struct dma_driver_api) 
B) a driver for some interface, e.g. SPI
C) an app which wants to talk to a device attached to that interface
e.g. and LCD controller
D) other things

Which of the above will call

- dma_channel_config
- dma_transfer_config
- dma_transfer_start
- dma_transfer_stop

?

The SPI subsystem interface doesn't have anything DMA related in it, so
I can only assume that DMA use will have to be hidden inside the SPI
driver, and for each spi_transceive request made made of it will setup
and operate on an appropriate struct dma_transfer_config? (Or use
scatter-gather lists when API's get that ;-)

If so, every device driver in zephyr that anyone wants to use with DMA
will need to add DMA support to it and make it configurable to
(optionally) use the generic DMA API. Or is it expected that all APIs
like SPI grow new functions for use with DMA specifically?

That still leaves the question as to who calls dma_channel_config and
how the parameters for that get into the system. Is each driver that
implements DMA support going to have a bunch of KConfig entries to
dma_slot, hankshake_polarity etc? Or will the SoC have a bunch of
#defines (like we currently have for IRQ numbers) for setting these DMA
attributes (assuming they are fixed in hardware).

There's also the question as to how channel numbers are allocated. Is
this more per-driver KConfig options or should we have a DMA channel
allocator function so they can just be assigned at runtime?

I'm also thinking about the fact that there are likely to be more
devices capable of DMA than channels available so how about an API to
free a channel? E.g. dma_channel_config claims a channel for use and
dma_channel_free releases for someone else. That way even with static
allocation of channels we have the option of allocating the same channel
to two different devices if we know they can't be active at the same
time.

--
Tixy