qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH][RFT] Make DMA timer driven


From: Anthony Liguori
Subject: [Qemu-devel] [PATCH][RFT] Make DMA timer driven
Date: Thu, 23 Oct 2008 16:30:17 -0500

The current DMA routines are driven by a call in main_loop_wait() after every
select.  The effect of this is that the DMA runs at a 10ms frequency depending
on whether IO is pending.

This patch converts the DMA code from using this implicit 10ms frequency to
having an explicit 10ms frequency using a QEMUTimer.  This means boards no
longer have to stub out DMA_run() functions.

The only two architectures implementing DMA_run() are cris and i386.  For cris,
I converted it to a simple repeating timer.  I've only compile tested this so
I'd appreciate if you could test it Edgar (or point me to an image).

For x86, I've made sure to only fire the DMA timer if there is a DMA channel
that is runnable.  The effect of this is that unless you're using sb16 or a
floppy disk, the DMA timer never fires.

You probably should test this malc.  My own benchmarks actually show slight
improvement by it's possible the change in timing could affect your demos.

Signed-off-by: Anthony Liguori <address@hidden>

diff --git a/hw/an5206.c b/hw/an5206.c
index 862d0cf..10f8b18 100644
--- a/hw/an5206.c
+++ b/hw/an5206.c
@@ -24,10 +24,6 @@ void irq_info(void)
 {
 }
 
-void DMA_run (void)
-{
-}
-
 /* Board init.  */
 
 static void an5206_init(ram_addr_t ram_size, int vga_ram_size,
diff --git a/hw/dma.c b/hw/dma.c
index 00c6332..79ae1d0 100644
--- a/hw/dma.c
+++ b/hw/dma.c
@@ -23,6 +23,7 @@
  */
 #include "hw.h"
 #include "isa.h"
+#include "qemu-timer.h"
 
 /* #define DEBUG_DMA */
 
@@ -78,6 +79,8 @@ enum {
 
 };
 
+static void DMA_run (void);
+
 static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
 
 static void write_page (void *opaque, uint32_t nport, uint32_t data)
@@ -214,6 +217,7 @@ static void write_cont (void *opaque, uint32_t nport, 
uint32_t data)
             d->status &= ~(1 << (ichan + 4));
         }
         d->status &= ~(1 << ichan);
+        DMA_run();
         break;
 
     case 0x0a:                  /* single mask */
@@ -221,6 +225,7 @@ static void write_cont (void *opaque, uint32_t nport, 
uint32_t data)
             d->mask |= 1 << (data & 3);
         else
             d->mask &= ~(1 << (data & 3));
+        DMA_run();
         break;
 
     case 0x0b:                  /* mode */
@@ -255,10 +260,12 @@ static void write_cont (void *opaque, uint32_t nport, 
uint32_t data)
 
     case 0x0e:                  /* clear mask for all channels */
         d->mask = 0;
+        DMA_run();
         break;
 
     case 0x0f:                  /* write mask for all channels */
         d->mask = data;
+        DMA_run();
         break;
 
     default:
@@ -310,6 +317,7 @@ void DMA_hold_DREQ (int nchan)
     ichan = nchan & 3;
     linfo ("held cont=%d chan=%d\n", ncont, ichan);
     dma_controllers[ncont].status |= 1 << (ichan + 4);
+    DMA_run();
 }
 
 void DMA_release_DREQ (int nchan)
@@ -320,6 +328,7 @@ void DMA_release_DREQ (int nchan)
     ichan = nchan & 3;
     linfo ("released cont=%d chan=%d\n", ncont, ichan);
     dma_controllers[ncont].status &= ~(1 << (ichan + 4));
+    DMA_run();
 }
 
 static void channel_run (int ncont, int ichan)
@@ -347,10 +356,29 @@ static void channel_run (int ncont, int ichan)
     ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
 }
 
-void DMA_run (void)
+static QEMUTimer *dma_timer;
+static int dma_timer_armed;
+
+static void DMA_rearm_timer(void)
+{
+    if (dma_timer_armed)
+        return;
+    qemu_mod_timer(dma_timer, qemu_get_clock(vm_clock) + 10);
+    dma_timer_armed = 1;
+}
+
+static void DMA_run_timer(void *unused)
+{
+    dma_timer_armed = 0;
+
+    DMA_run();
+}
+
+static void DMA_run (void)
 {
     struct dma_cont *d;
     int icont, ichan;
+    int rearm = 0;
 
     d = dma_controllers;
 
@@ -360,10 +388,15 @@ void DMA_run (void)
 
             mask = 1 << ichan;
 
-            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
+            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
                 channel_run (icont, ichan);
+                rearm = 1;
+            }
         }
     }
+
+    if (rearm)
+        DMA_rearm_timer();
 }
 
 void DMA_register_channel (int nchan,
@@ -534,6 +567,9 @@ static int dma_load (QEMUFile *f, void *opaque, int 
version_id)
         qemu_get_8s (f, &r->dack);
         qemu_get_8s (f, &r->eop);
     }
+
+    DMA_run();
+
     return 0;
 }
 
@@ -545,4 +581,6 @@ void DMA_init (int high_page_enable)
               high_page_enable ? 0x488 : -1);
     register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
     register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
+
+    dma_timer = qemu_new_timer(vm_clock, DMA_run_timer, NULL);
 }
diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
index f95f4f7..1c8fb83 100644
--- a/hw/etraxfs_dma.c
+++ b/hw/etraxfs_dma.c
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <sys/time.h>
 #include "hw.h"
+#include "qemu-timer.h"
 
 #include "etraxfs_dma.h"
 
@@ -190,6 +191,8 @@ struct fs_dma_ctrl
 
        int nr_channels;
        struct fs_dma_channel *channels;
+
+        QEMUTimer *dma_timer;
 };
 
 static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
@@ -710,11 +713,11 @@ void etraxfs_dmac_connect_client(void *opaque, int c,
 }
 
 
-static void *etraxfs_dmac;
-void DMA_run(void)
+static void DMA_run(void *opaque)
 {
-       if (etraxfs_dmac)
-               etraxfs_dmac_run(etraxfs_dmac);
+    struct fs_dma_ctrl *etraxfs_dmac = opaque;
+    qemu_mod_timer(etraxfs_dmac->dma_timer, qemu_get_clock(vm_clock) + 10);
+    etraxfs_dmac_run(etraxfs_dmac);
 }
 
 void *etraxfs_dmac_init(CPUState *env, 
@@ -727,6 +730,9 @@ void *etraxfs_dmac_init(CPUState *env,
        if (!ctrl)
                return NULL;
 
+        ctrl->dma_timer = qemu_new_timer(vm_clock, DMA_run, ctrl);
+        qemu_mod_timer(ctrl->dma_timer, qemu_get_clock(vm_clock) + 10);
+
        ctrl->base = base;
        ctrl->env = env;
        ctrl->nr_channels = nr_channels;
@@ -745,8 +751,6 @@ void *etraxfs_dmac_init(CPUState *env,
                                              ctrl->channels[i].regmap);
        }
 
-       /* Hax, we only support one DMA controller at a time.  */
-       etraxfs_dmac = ctrl;
        return ctrl;
   err:
        qemu_free(ctrl->channels);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 1ae5d2a..9a415b7 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -15,10 +15,6 @@
 #include "arm-misc.h"
 #include "net.h"
 
-void DMA_run (void)
-{
-}
-
 typedef struct {
     uint32_t flash_offset;
     uint32_t cm_osc;
diff --git a/hw/isa.h b/hw/isa.h
index 222e4f3..a8c1a56 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -19,7 +19,6 @@ int DMA_write_memory (int nchan, void *buf, int pos, int 
size);
 void DMA_hold_DREQ (int nchan);
 void DMA_release_DREQ (int nchan);
 void DMA_schedule(int nchan);
-void DMA_run (void);
 void DMA_init (int high_page_enable);
 void DMA_register_channel (int nchan,
                            DMA_transfer_handler transfer_handler,
diff --git a/hw/shix.c b/hw/shix.c
index 3cc41fb..334ef4c 100644
--- a/hw/shix.c
+++ b/hw/shix.c
@@ -35,11 +35,6 @@
 #define BIOS_FILENAME "shix_bios.bin"
 #define BIOS_ADDRESS 0xA0000000
 
-void DMA_run(void)
-{
-    /* XXXXX */
-}
-
 void irq_info(void)
 {
     /* XXXXX */
diff --git a/hw/sun4m.c b/hw/sun4m.c
index dd0433a..3e8b17a 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -146,7 +146,6 @@ int DMA_write_memory (int nchan, void *buf, int pos, int 
size)
 void DMA_hold_DREQ (int nchan) {}
 void DMA_release_DREQ (int nchan) {}
 void DMA_schedule(int nchan) {}
-void DMA_run (void) {}
 void DMA_init (int high_page_enable) {}
 void DMA_register_channel (int nchan,
                            DMA_transfer_handler transfer_handler,
diff --git a/hw/sun4u.c b/hw/sun4u.c
index a70ad20..057d598 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -79,7 +79,6 @@ int DMA_write_memory (int nchan, void *buf, int pos, int size)
 void DMA_hold_DREQ (int nchan) {}
 void DMA_release_DREQ (int nchan) {}
 void DMA_schedule(int nchan) {}
-void DMA_run (void) {}
 void DMA_init (int high_page_enable) {}
 void DMA_register_channel (int nchan,
                            DMA_transfer_handler transfer_handler,
diff --git a/vl.c b/vl.c
index c0e43ac..1bd0914 100644
--- a/vl.c
+++ b/vl.c
@@ -7968,8 +7968,6 @@ void main_loop_wait(int timeout)
         if (likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
         qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
                         qemu_get_clock(vm_clock));
-        /* run dma transfers, if any */
-        DMA_run();
     }
 
     /* real time timers */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]