Commit 492c30af2567a59413c064f88eb81e1691865195

Authored by aliguori
1 parent 1b435b10

Make DMA bottom-half driven (v2)

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
... ... @@ -24,10 +24,6 @@ void irq_info(void)
24 24 {
25 25 }
26 26  
27   -void DMA_run (void)
28   -{
29   -}
30   -
31 27 /* Board init. */
32 28  
33 29 static void an5206_init(ram_addr_t ram_size, int vga_ram_size,
... ...
hw/dma.c
... ... @@ -78,6 +78,8 @@ enum {
78 78  
79 79 };
80 80  
  81 +static void DMA_run (void);
  82 +
81 83 static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
82 84  
83 85 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)
214 216 d->status &= ~(1 << (ichan + 4));
215 217 }
216 218 d->status &= ~(1 << ichan);
  219 + DMA_run();
217 220 break;
218 221  
219 222 case 0x0a: /* single mask */
... ... @@ -221,6 +224,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data)
221 224 d->mask |= 1 << (data & 3);
222 225 else
223 226 d->mask &= ~(1 << (data & 3));
  227 + DMA_run();
224 228 break;
225 229  
226 230 case 0x0b: /* mode */
... ... @@ -255,10 +259,12 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data)
255 259  
256 260 case 0x0e: /* clear mask for all channels */
257 261 d->mask = 0;
  262 + DMA_run();
258 263 break;
259 264  
260 265 case 0x0f: /* write mask for all channels */
261 266 d->mask = data;
  267 + DMA_run();
262 268 break;
263 269  
264 270 default:
... ... @@ -310,6 +316,7 @@ void DMA_hold_DREQ (int nchan)
310 316 ichan = nchan & 3;
311 317 linfo ("held cont=%d chan=%d\n", ncont, ichan);
312 318 dma_controllers[ncont].status |= 1 << (ichan + 4);
  319 + DMA_run();
313 320 }
314 321  
315 322 void DMA_release_DREQ (int nchan)
... ... @@ -320,6 +327,7 @@ void DMA_release_DREQ (int nchan)
320 327 ichan = nchan & 3;
321 328 linfo ("released cont=%d chan=%d\n", ncont, ichan);
322 329 dma_controllers[ncont].status &= ~(1 << (ichan + 4));
  330 + DMA_run();
323 331 }
324 332  
325 333 static void channel_run (int ncont, int ichan)
... ... @@ -347,10 +355,13 @@ static void channel_run (int ncont, int ichan)
347 355 ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
348 356 }
349 357  
350   -void DMA_run (void)
  358 +static QEMUBH *dma_bh;
  359 +
  360 +static void DMA_run (void)
351 361 {
352 362 struct dma_cont *d;
353 363 int icont, ichan;
  364 + int rearm = 0;
354 365  
355 366 d = dma_controllers;
356 367  
... ... @@ -360,10 +371,20 @@ void DMA_run (void)
360 371  
361 372 mask = 1 << ichan;
362 373  
363   - if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
  374 + if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
364 375 channel_run (icont, ichan);
  376 + rearm = 1;
  377 + }
365 378 }
366 379 }
  380 +
  381 + if (rearm)
  382 + qemu_bh_schedule_idle(dma_bh);
  383 +}
  384 +
  385 +static void DMA_run_bh(void *unused)
  386 +{
  387 + DMA_run();
367 388 }
368 389  
369 390 void DMA_register_channel (int nchan,
... ... @@ -534,6 +555,9 @@ static int dma_load (QEMUFile *f, void *opaque, int version_id)
534 555 qemu_get_8s (f, &r->dack);
535 556 qemu_get_8s (f, &r->eop);
536 557 }
  558 +
  559 + DMA_run();
  560 +
537 561 return 0;
538 562 }
539 563  
... ... @@ -545,4 +569,6 @@ void DMA_init (int high_page_enable)
545 569 high_page_enable ? 0x488 : -1);
546 570 register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
547 571 register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
  572 +
  573 + dma_bh = qemu_bh_new(DMA_run_bh, NULL);
548 574 }
... ...
hw/etraxfs_dma.c
... ... @@ -24,6 +24,8 @@
24 24 #include <stdio.h>
25 25 #include <sys/time.h>
26 26 #include "hw.h"
  27 +#include "qemu-common.h"
  28 +#include "sysemu.h"
27 29  
28 30 #include "etraxfs_dma.h"
29 31  
... ... @@ -190,6 +192,8 @@ struct fs_dma_ctrl
190 192  
191 193 int nr_channels;
192 194 struct fs_dma_channel *channels;
  195 +
  196 + QEMUBH *bh;
193 197 };
194 198  
195 199 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,
712 716 }
713 717  
714 718  
715   -static void *etraxfs_dmac;
716   -void DMA_run(void)
  719 +static void DMA_run(void *opaque)
717 720 {
718   - if (etraxfs_dmac)
719   - etraxfs_dmac_run(etraxfs_dmac);
  721 + struct fs_dma_ctrl *etraxfs_dmac = opaque;
  722 + if (vm_running)
  723 + etraxfs_dmac_run(etraxfs_dmac);
  724 + qemu_bh_schedule_idle(etraxfs_dmac->bh);
720 725 }
721 726  
722 727 void *etraxfs_dmac_init(CPUState *env,
... ... @@ -729,6 +734,9 @@ void *etraxfs_dmac_init(CPUState *env,
729 734 if (!ctrl)
730 735 return NULL;
731 736  
  737 + ctrl->bh = qemu_bh_new(DMA_run, ctrl);
  738 + qemu_bh_schedule_idle(ctrl->bh);
  739 +
732 740 ctrl->base = base;
733 741 ctrl->env = env;
734 742 ctrl->nr_channels = nr_channels;
... ... @@ -747,8 +755,6 @@ void *etraxfs_dmac_init(CPUState *env,
747 755 ctrl->channels[i].regmap);
748 756 }
749 757  
750   - /* Hax, we only support one DMA controller at a time. */
751   - etraxfs_dmac = ctrl;
752 758 return ctrl;
753 759 err:
754 760 qemu_free(ctrl->channels);
... ...
hw/integratorcp.c
... ... @@ -15,10 +15,6 @@
15 15 #include "arm-misc.h"
16 16 #include "net.h"
17 17  
18   -void DMA_run (void)
19   -{
20   -}
21   -
22 18 typedef struct {
23 19 uint32_t flash_offset;
24 20 uint32_t cm_osc;
... ...
hw/isa.h
... ... @@ -19,7 +19,6 @@ int DMA_write_memory (int nchan, void *buf, int pos, int size);
19 19 void DMA_hold_DREQ (int nchan);
20 20 void DMA_release_DREQ (int nchan);
21 21 void DMA_schedule(int nchan);
22   -void DMA_run (void);
23 22 void DMA_init (int high_page_enable);
24 23 void DMA_register_channel (int nchan,
25 24 DMA_transfer_handler transfer_handler,
... ...
hw/shix.c
... ... @@ -35,11 +35,6 @@
35 35 #define BIOS_FILENAME "shix_bios.bin"
36 36 #define BIOS_ADDRESS 0xA0000000
37 37  
38   -void DMA_run(void)
39   -{
40   - /* XXXXX */
41   -}
42   -
43 38 void irq_info(void)
44 39 {
45 40 /* XXXXX */
... ...
hw/sun4m.c
... ... @@ -164,7 +164,6 @@ int DMA_write_memory (int nchan, void *buf, int pos, int size)
164 164 void DMA_hold_DREQ (int nchan) {}
165 165 void DMA_release_DREQ (int nchan) {}
166 166 void DMA_schedule(int nchan) {}
167   -void DMA_run (void) {}
168 167 void DMA_init (int high_page_enable) {}
169 168 void DMA_register_channel (int nchan,
170 169 DMA_transfer_handler transfer_handler,
... ...
hw/sun4u.c
... ... @@ -79,7 +79,6 @@ int DMA_write_memory (int nchan, void *buf, int pos, int size)
79 79 void DMA_hold_DREQ (int nchan) {}
80 80 void DMA_release_DREQ (int nchan) {}
81 81 void DMA_schedule(int nchan) {}
82   -void DMA_run (void) {}
83 82 void DMA_init (int high_page_enable) {}
84 83 void DMA_register_channel (int nchan,
85 84 DMA_transfer_handler transfer_handler,
... ...
... ... @@ -7983,8 +7983,6 @@ void main_loop_wait(int timeout)
7983 7983 if (likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
7984 7984 qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
7985 7985 qemu_get_clock(vm_clock));
7986   - /* run dma transfers, if any */
7987   - DMA_run();
7988 7986 }
7989 7987  
7990 7988 /* real time timers */
... ...