diff mbox series

[v4,04/11] hw/dma: Add the DMA control interface

Message ID 20211201154023.13931-5-francisco.iglesias@xilinx.com
State New
Headers show
Series Xilinx Versal's PMC SLCR and OSPI support | expand

Commit Message

Francisco Iglesias Dec. 1, 2021, 3:40 p.m. UTC
An option on real hardware when embedding a DMA engine into a peripheral
is to make the peripheral control the engine through a custom DMA control
(hardware) 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, results and interrupts for the transfer might
still be intended to be read and catched through the DMA engine's register
API (and signals).

This patch adds a QEMU DMA control interface that can be used for
modelling above scenario. Through this new interface a peripheral model
embedding a DMA engine model will be able to directly initiate transfers
through the DMA. At the same time the transfer state, result and
completion signaling will be read and catched through the DMA engine
model's register API and signaling.

Signed-off-by: Francisco Iglesias <francisco.iglesias@xilinx.com>
---
 hw/dma/dma-ctrl-if.c         | 31 +++++++++++++++++++
 hw/dma/meson.build           |  1 +
 include/hw/dma/dma-ctrl-if.h | 72 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+)
 create mode 100644 hw/dma/dma-ctrl-if.c
 create mode 100644 include/hw/dma/dma-ctrl-if.h

Comments

Peter Maydell Dec. 10, 2021, 3:17 p.m. UTC | #1
On Wed, 1 Dec 2021 at 15:40, Francisco Iglesias
<francisco.iglesias@xilinx.com> wrote:
>
> An option on real hardware when embedding a DMA engine into a peripheral
> is to make the peripheral control the engine through a custom DMA control
> (hardware) 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, results and interrupts for the transfer might
> still be intended to be read and catched through the DMA engine's register
> API (and signals).
>
> This patch adds a QEMU DMA control interface that can be used for
> modelling above scenario. Through this new interface a peripheral model
> embedding a DMA engine model will be able to directly initiate transfers
> through the DMA. At the same time the transfer state, result and
> completion signaling will be read and catched through the DMA engine
> model's register API and signaling.
>
> Signed-off-by: Francisco Iglesias <francisco.iglesias@xilinx.com>

My review of the interface is against the patch 11 documentation;
please copy the typo etc fixes from there into the comments in this patch
where relevant.

thanks
-- PMM
diff mbox series

Patch

diff --git a/hw/dma/dma-ctrl-if.c b/hw/dma/dma-ctrl-if.c
new file mode 100644
index 0000000000..d82372bc12
--- /dev/null
+++ b/hw/dma/dma-ctrl-if.c
@@ -0,0 +1,31 @@ 
+/*
+ * DMA control interface.
+ *
+ * Copyright (c) 2021 Xilinx Inc.
+ * Written by Francisco Iglesias <francisco.iglesias@xilinx.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "exec/hwaddr.h"
+#include "hw/dma/dma-ctrl-if.h"
+
+void dma_ctrl_if_read_with_notify(DmaCtrlIf *dma, hwaddr addr, uint32_t len,
+                                  DmaCtrlIfNotify *notify, bool start_dma)
+{
+    DmaCtrlIfClass *dcc =  DMA_CTRL_IF_GET_CLASS(dma);
+    dcc->read(dma, addr, len, notify, start_dma);
+}
+
+static const TypeInfo dma_ctrl_if_info = {
+    .name          = TYPE_DMA_CTRL_IF,
+    .parent        = TYPE_INTERFACE,
+    .class_size = sizeof(DmaCtrlIfClass),
+};
+
+static void dma_ctrl_if_register_types(void)
+{
+    type_register_static(&dma_ctrl_if_info);
+}
+
+type_init(dma_ctrl_if_register_types)
diff --git a/hw/dma/meson.build b/hw/dma/meson.build
index f3f0661bc3..c43c067856 100644
--- a/hw/dma/meson.build
+++ b/hw/dma/meson.build
@@ -14,3 +14,4 @@  softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
 softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
 softmmu_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
 softmmu_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
+common_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('dma-ctrl-if.c'))
diff --git a/include/hw/dma/dma-ctrl-if.h b/include/hw/dma/dma-ctrl-if.h
new file mode 100644
index 0000000000..bfd1db4c02
--- /dev/null
+++ b/include/hw/dma/dma-ctrl-if.h
@@ -0,0 +1,72 @@ 
+/*
+ * DMA control interface.
+ *
+ * Copyright (c) 2021 Xilinx Inc.
+ * Written by Francisco Iglesias <francisco.iglesias@xilinx.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_DMA_CTRL_IF_H
+#define HW_DMA_CTRL_IF_H
+
+#include "hw/hw.h"
+#include "qom/object.h"
+
+#define TYPE_DMA_CTRL_IF "dma-ctrl-if"
+typedef struct DmaCtrlIfClass DmaCtrlIfClass;
+DECLARE_CLASS_CHECKERS(DmaCtrlIfClass, DMA_CTRL_IF,
+                       TYPE_DMA_CTRL_IF)
+
+#define DMA_CTRL_IF(obj) \
+     INTERFACE_CHECK(DmaCtrlIf, (obj), TYPE_DMA_CTRL_IF)
+
+typedef void (*dmactrlif_notify_fn)(void *opaque);
+
+typedef struct DmaCtrlIfNotify {
+    void *opaque;
+    dmactrlif_notify_fn cb;
+} DmaCtrlIfNotify;
+
+typedef struct DmaCtrlIf {
+    Object Parent;
+} DmaCtrlIf;
+
+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;
+
+/*
+ * 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);
+
+#endif /* HW_DMA_CTRL_IF_H */