[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v4 11/11] docs/devel: Add documentation for the DMA control inter
From: |
Francisco Iglesias |
Subject: |
[PATCH v4 11/11] docs/devel: Add documentation for the DMA control interface |
Date: |
Wed, 1 Dec 2021 15:40:23 +0000 |
Also, since being the author, list myself as maintainer for the file.
Signed-off-by: Francisco Iglesias <francisco.iglesias@xilinx.com>
---
MAINTAINERS | 1 +
docs/devel/dma-ctrl-if.rst | 320 +++++++++++++++++++++++++++++++++++++++++++++
docs/devel/index.rst | 1 +
3 files changed, 322 insertions(+)
create mode 100644 docs/devel/dma-ctrl-if.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index e52cc94840..ffefcc841f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -968,6 +968,7 @@ M: Francisco Iglesias <francisco.iglesias@xilinx.com>
S: Maintained
F: hw/ssi/xlnx-versal-ospi.c
F: include/hw/ssi/xlnx-versal-ospi.h
+F: docs/devel/dma-ctrl-if.rst
ARM ACPI Subsystem
M: Shannon Zhao <shannon.zhaosl@gmail.com>
diff --git a/docs/devel/dma-ctrl-if.rst b/docs/devel/dma-ctrl-if.rst
new file mode 100644
index 0000000000..480e2a7d3a
--- /dev/null
+++ b/docs/devel/dma-ctrl-if.rst
@@ -0,0 +1,320 @@
+DMA control interface
+=====================
+
+About the DMA control interface
+-------------------------------
+
+DMA engines embedded in peripherals can end up being controlled in
+different ways on real hardware. One possible way is to allow software
+drivers to access the DMA engine's register API and to allow the drivers
+to configure and control DMA transfers through the API. A model of a DMA
+engine in QEMU that is embedded and (re)used in this manner does not need
+to implement the DMA control interface.
+
+Another option on real hardware is to allow the peripheral embedding the
+DMA engine to control the engine through a custom hardware DMA control
+interface between the two. Software drivers in this scenario configure and
+trigger DMA operations through the controlling peripheral's register API
+(for example could writing a specific bit in a register propagate down to
+a transfer start signal on the DMA control interface). At the same time
+the status, result and interrupts for the transfer might still be intended
+to be read and catched through the DMA engine's register API (and
+signals).
+
+::
+
+ Hardware example
+ +------------+
+ | |
+ | Peripheral |
+ | |
+ +------------+
+ /\
+ || DMA control IF (custom)
+ \/
+ +------------+
+ | Peripheral |
+ | DMA |
+ +------------+
+
+Figure 1. A peripheral controlling it's embedded DMA engine through a
+custom DMA control interface
+
+Above scenario can be modelled in QEMU by implementing this DMA control
+interface in the DMA engine model. This will allow a peripheral embedding
+the DMA engine to initiate DMA transfers through the engine using the
+interface. At the same time the status, result and interrupts for the
+transfer can be read and catched through the DMA engine's register API and
+signals. An example implementation and usage of the DMA control interface
+can be found in the Xilinx CSU DMA model and Xilinx Versal's OSPI model.
+
+::
+
+ Memory address
+ (register API)
+ 0xf1010000 +---------+
+ | |
+ | Versal |
+ | OSPI |
+ | |
+ +---------+
+ /\
+ || DMA control IF
+ \/
+ 0xf1011000 +---------+
+ | |
+ | CSU DMA |
+ | (src) |
+ | |
+ +---------+
+
+Figure 2. Xilinx Versal's OSPI controls and initiates transfers on it's
+CSU source DMA through a DMA control interface
+
+DMA control interface files
+---------------------------
+
+``include/hw/dma/dma-ctrl-if.h``
+``hw/dma/dma-ctrl-if.c``
+
+DmaCtrlIfClass
+--------------
+
+The ``DmaCtrlIfClass`` contains the interface methods that can be
+implemented by a DMA engine.
+
+.. code-block:: c
+
+ typedef struct DmaCtrlIfClass {
+ InterfaceClass parent;
+
+ /*
+ * read: Start a read transfer on the DMA implementing the DMA control
+ * interface
+ *
+ * @dma_ctrl: the DMA implementing this interface
+ * @addr: the address to read
+ * @len: the amount of bytes to read at 'addr'
+ * @notify: the structure containg a callback to call and opaque
pointer
+ * to pass the callback when the transfer has been completed
+ * @start_dma: true for starting the DMA transfer and false for just
+ * refilling and proceding an already started transfer
+ */
+ void (*read)(DmaCtrlIf *dma, hwaddr addr, uint32_t len,
+ DmaCtrlIfNotify *notify, bool start_dma);
+ } DmaCtrlIfClass;
+
+
+DmaCtrlIfNotify
+---------------
+
+The ``DmaCtrlIfNotify`` contains a callback function that is called when a
+transfer has been completed. It also contains an opaque pointer that is
+passed in to the function as an argument.
+
+.. code-block:: c
+
+ typedef struct DmaCtrlIfNotify {
+ void *opaque;
+ dmactrlif_notify_fn cb;
+ } DmaCtrlIfNotify;
+
+dma_ctrl_if_read_with_notify
+----------------------------
+
+The ``dma_ctrl_if_read_with_notify`` function is used from a model
+embedding the DMA engine for starting DMA read transfers.
+
+.. code-block:: c
+
+ /*
+ * Start a read transfer on a DMA implementing the DMA control interface.
+ * The DMA will notify the caller that 'len' bytes have been read at 'addr'
+ * through the callback in the DmaCtrlIfNotify structure. For allowing
refilling
+ * an already started transfer the DMA notifies the caller before
considering
+ * the transfer done (e.g. before setting done flags, generating IRQs and
+ * modifying other relevant internal device state).
+ *
+ * @dma_ctrl: the DMA implementing this interface
+ * @addr: the address to read
+ * @len: the amount of bytes to read at 'addr'
+ * @notify: the structure containing a callback to call and opaque pointer
+ * to pass the callback when the transfer has been completed
+ * @start_dma: true for starting the DMA transfer and false for just
+ * refilling and proceding an already started transfer
+ */
+ void dma_ctrl_if_read_with_notify(DmaCtrlIf *dma, hwaddr addr, uint32_t
len,
+ DmaCtrlIfNotify *notify, bool start_dma);
+
+Example implementation of the DMA control interface
+---------------------------------------------------
+
+The example code below showing an implementation of the DMA control
+interface is taken from the Xilinx CSU DMA model.
+
+The DMA control interface related code in
+``include/hw/dma/xlnx_csu_dma.h`` is found below. The header includes
+``include/hw/dma/dma-ctrl-if.h`` and makes it possible to keep track of a
+notifier function with a corresponding opaque. The notifier is called when
+the transfer has been completed (with the opaque passed in as argument).
+
+.. code-block:: c
+
+ .
+ .
+ .
+ #include "hw/dma/dma-ctrl-if.h"
+ .
+ .
+ .
+ typedef struct XlnxCSUDMA {
+ .
+ .
+ .
+ dmactrlif_notify_fn dmactrlif_notify;
+ void *dmactrlif_opaque;
+ .
+ .
+ .
+ } XlnxCSUDMA;
+ .
+ .
+ .
+
+The DMA control interface related code inside ``hw/dma/xlnx_csu_dma.c`` is
+shown below. A DMA control interface read function gets installed in the
+class init function through which DMA read transfers can be started. The
+DMA control interface notifier is called once a transfer has been
+completed (with the opaque passed in as argument) but before any DMA
+status has been updated (for allowing refilling the transfer).
+
+.. code-block:: c
+
+ .
+ .
+ .
+ static uint32_t xlnx_csu_dma_advance(XlnxCSUDMA *s, uint32_t len)
+ {
+ .
+ .
+ .
+ /* Notify dma-ctrl-if clients when the transfer has been completed */
+ if (size == 0 && s->dmactrlif_notify) {
+ s->dmactrlif_notify(s->dmactrlif_opaque);
+ }
+
+ if (size == 0) {
+ xlnx_csu_dma_done(s);
+ }
+
+ return size;
+ }
+ .
+ .
+ .
+ static void xlnx_csu_dma_dma_ctrl_if_read(DmaCtrlIf *dma, hwaddr addr,
+ uint32_t len, DmaCtrlIfNotify
*notify,
+ bool start_dma)
+ {
+ .
+ .
+ .
+ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
+ {
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
+ DmaCtrlIfClass *dcic = DMA_CTRL_IF_CLASS(klass);
+ .
+ .
+ .
+ dcic->read = xlnx_csu_dma_dma_ctrl_if_read;
+ }
+ .
+ .
+ .
+ static const TypeInfo xlnx_csu_dma_info = {
+ .
+ .
+ .
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SINK },
+ { TYPE_DMA_CTRL_IF },
+ { }
+ }
+ };
+
+Example DMA control interface read transfer start
+-------------------------------------------------
+
+The DMA read transfer example is taken from the Xilinx Versal's OSPI
+model. The DMA read transfer is started by a register write to the OSPI
+controller.
+
+The DMA control interface related code inside
+``include/hw/ssi/xlnx-versal-ospi.h`` is shown below. The header includes
+``include/hw/dma/dma-ctrl-if.h`` and the state structure contains a
+pointer to a DMA engine that has implemented the DMA control interface.
+
+.. code-block:: c
+
+ .
+ .
+ .
+ #include "hw/dma/dma-ctrl-if.h"
+ .
+ .
+ .
+ typedef struct XlnxVersalOspi {
+ .
+ .
+ .
+ DmaCtrlIf *dma_src;
+ .
+ .
+ .
+ } XlnxVersalOspi;
+ .
+ .
+ .
+
+The DMA control interface related code inside
+``hw/ssi/xlnx-versal-ospi.c`` can be seen below. OSPI DMA read transfers
+are performed and executed through the DMA control interface read function
+(and with the CSU source DMA). The OSPI controller is also able to refill
+the transfer as required through the notifier (which is called when the
+transfer has been completed).
+
+.. code-block:: c
+
+ static void ospi_dma_read(XlnxVersalOspi *s, bool start_dma)
+ {
+ .
+ .
+ .
+ DmaCtrlIfNotify notify = { .cb = ospi_notify,
+ .opaque = (void *)s };
+ .
+ .
+ .
+ dma_ctrl_if_read_with_notify(s->dma_src, 0, dma_len,
+ ¬ify, start_dma);
+ .
+ .
+ .
+ }
+ .
+ .
+ .
+ static void xlnx_versal_ospi_init(Object *obj)
+ {
+ .
+ .
+ .
+ object_property_add_link(obj, "dma-src", TYPE_DMA_CTRL_IF,
+ (Object **)&s->dma_src,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
+ .
+ .
+ .
+ }
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index afd937535e..0d424bdf34 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -37,6 +37,7 @@ modifying QEMU's source code.
reset
s390-dasd-ipl
clocks
+ dma-ctrl-if
qom
modules
block-coroutine-wrapper
--
2.11.0
- [PATCH v4 04/11] hw/dma: Add the DMA control interface, (continued)
- [PATCH v4 04/11] hw/dma: Add the DMA control interface, Francisco Iglesias, 2021/12/01
- [PATCH v4 06/11] hw/ssi: Add a model of Xilinx Versal's OSPI flash memory controller, Francisco Iglesias, 2021/12/01
- [PATCH v4 08/11] hw/block/m25p80: Add support for Micron Xccela flash mt35xu01g, Francisco Iglesias, 2021/12/01
- [PATCH v4 09/11] hw/arm/xlnx-versal-virt: Connect mt35xu01g flashes to the OSPI, Francisco Iglesias, 2021/12/01
- [PATCH v4 07/11] hw/arm/xlnx-versal: Connect the OSPI flash memory controller model, Francisco Iglesias, 2021/12/01
- [PATCH v4 11/11] docs/devel: Add documentation for the DMA control interface,
Francisco Iglesias <=
- [PATCH v4 10/11] MAINTAINERS: Add an entry for Xilinx Versal OSPI, Francisco Iglesias, 2021/12/01