]> git.proxmox.com Git - qemu.git/commitdiff
Make DMA bottom-half driven (v2)
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 31 Oct 2008 17:25:56 +0000 (17:25 +0000)
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 31 Oct 2008 17:25:56 +0000 (17:25 +0000)
The current DMA routines are driven by a call in main_loop_wait() after every
select.

This patch converts the DMA code to be driven by a constantly rescheduled
bottom half.  The advantage of using a scheduled bottom half is that we can
stop scheduling the bottom half when there no DMA channels are runnable.  This
means we can potentially detect this case and sleep longer in the main loop.

The only two architectures implementing DMA_run() are cris and i386.  For cris,
I converted it to a simple repeating bottom half.  I've only compile tested
this as cris does not seem to work on a 64-bit host.  It should be functionally
identical to the previous implementation so I expect it to work.

For x86, I've made sure to only fire the DMA bottom half 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 bottom half 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.

Since v1, I've changed the code to use a BH instead of a timer.  cris at least
seems to depend on faster than 10ms polling.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5573 c046a42c-6fe2-441c-8c8c-71466251a162

hw/an5206.c
hw/dma.c
hw/etraxfs_dma.c
hw/integratorcp.c
hw/isa.h
hw/shix.c
hw/sun4m.c
hw/sun4u.c
vl.c

index 29812631e71700d8802b83ec39ee00d5f7820aef..9d315f3aa40ee9a2aaf83acb0103670fcc89e7b4 100644 (file)
@@ -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,
index 00c6332b4fc35e4547a2f01bd6984bddaf80e27f..b247a0cd89896e434682a0305cb1f1f8edd723b6 100644 (file)
--- a/hw/dma.c
+++ b/hw/dma.c
@@ -78,6 +78,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 +216,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 +224,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 +259,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 +316,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 +327,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 +355,13 @@ 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 QEMUBH *dma_bh;
+
+static void DMA_run (void)
 {
     struct dma_cont *d;
     int icont, ichan;
+    int rearm = 0;
 
     d = dma_controllers;
 
@@ -360,10 +371,20 @@ 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)
+        qemu_bh_schedule_idle(dma_bh);
+}
+
+static void DMA_run_bh(void *unused)
+{
+    DMA_run();
 }
 
 void DMA_register_channel (int nchan,
@@ -534,6 +555,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 +569,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_bh = qemu_bh_new(DMA_run_bh, NULL);
 }
index a871b0630e9cdd9ceedf42c080dd352291ceff2f..a7e547c08a7d811d80bbc549fce3444e1b8d6234 100644 (file)
@@ -24,6 +24,8 @@
 #include <stdio.h>
 #include <sys/time.h>
 #include "hw.h"
+#include "qemu-common.h"
+#include "sysemu.h"
 
 #include "etraxfs_dma.h"
 
@@ -190,6 +192,8 @@ struct fs_dma_ctrl
 
        int nr_channels;
        struct fs_dma_channel *channels;
+
+        QEMUBH *bh;
 };
 
 static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
@@ -712,11 +716,12 @@ 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;
+    if (vm_running)
+        etraxfs_dmac_run(etraxfs_dmac);
+    qemu_bh_schedule_idle(etraxfs_dmac->bh);
 }
 
 void *etraxfs_dmac_init(CPUState *env, 
@@ -729,6 +734,9 @@ void *etraxfs_dmac_init(CPUState *env,
        if (!ctrl)
                return NULL;
 
+        ctrl->bh = qemu_bh_new(DMA_run, ctrl);
+        qemu_bh_schedule_idle(ctrl->bh);
+
        ctrl->base = base;
        ctrl->env = env;
        ctrl->nr_channels = nr_channels;
@@ -747,8 +755,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);
index 779d46b70ed7422ce00958dfe9763141c492ab5c..c0e2b66bc337c2ce379bd8e94598356bddfc4f03 100644 (file)
 #include "arm-misc.h"
 #include "net.h"
 
-void DMA_run (void)
-{
-}
-
 typedef struct {
     uint32_t flash_offset;
     uint32_t cm_osc;
index 222e4f347b88f2356309c71d2788fe8e48248197..a8c1a56a4536ef06693f10f6d88dd4bf89ce0657 100644 (file)
--- 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,
index 140efe90a5fe06a028204ae187e8cc9757c6b95d..eb53ee59d0787cf00670f737d7e07181ac81cfb8 100644 (file)
--- a/hw/shix.c
+++ b/hw/shix.c
 #define BIOS_FILENAME "shix_bios.bin"
 #define BIOS_ADDRESS 0xA0000000
 
-void DMA_run(void)
-{
-    /* XXXXX */
-}
-
 void irq_info(void)
 {
     /* XXXXX */
index d1c5b94e9f558c35818a04792bc23361de7a40d4..f3c6501fb1ff998e8e70278d8119ccd7eed9e5b4 100644 (file)
@@ -164,7 +164,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,
index a70ad201ab7a7fe2967d707e43295a624e0780ce..057d598d7f5acf46ad606ff42c46487accbef8dc 100644 (file)
@@ -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 137074b9efc5d2e381664fb0b1fc87e1cce226c3..a7c55516de18af1dca5f82d76fea70ef345f61ab 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -7983,8 +7983,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 */