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