diff options
author | Eduardo Habkost <ehabkost@redhat.com> | 2018-06-25 14:10:56 -0300 |
---|---|---|
committer | Eduardo Habkost <ehabkost@redhat.com> | 2018-06-25 14:10:56 -0300 |
commit | 0b6e9aa89e02c8b213af019aad816e00ba8243f8 (patch) | |
tree | 27eb6832830ebf44939c7b968df9044c6d4433ae | |
parent | 6b2942f966d5e54c37d305c80f5f98d504c2bc55 (diff) | |
parent | 35e238c9330669882487f9929e0aa97900431853 (diff) |
Merge branch 'master' of git://git.qemu.org/qemu into x86-next
-rw-r--r-- | accel/stubs/tcg-stub.c | 4 | ||||
-rw-r--r-- | audio/audio.c | 3 | ||||
-rw-r--r-- | cpus.c | 4 | ||||
-rw-r--r-- | exec.c | 3 | ||||
-rw-r--r-- | hw/audio/hda-codec.c | 287 | ||||
-rw-r--r-- | hw/audio/intel-hda.c | 7 | ||||
-rw-r--r-- | hw/audio/trace-events | 6 | ||||
-rw-r--r-- | include/hw/compat.h | 4 | ||||
-rwxr-xr-x | scripts/qmp/qemu-ga-client | 3 | ||||
-rwxr-xr-x | scripts/qmp/qmp | 3 | ||||
-rwxr-xr-x | scripts/qmp/qmp-shell | 3 | ||||
-rwxr-xr-x | scripts/qmp/qom-fuse | 3 | ||||
-rwxr-xr-x | scripts/qmp/qom-get | 3 | ||||
-rwxr-xr-x | scripts/qmp/qom-list | 3 | ||||
-rwxr-xr-x | scripts/qmp/qom-set | 3 | ||||
-rwxr-xr-x | scripts/qmp/qom-tree | 3 |
16 files changed, 282 insertions, 60 deletions
diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index ee575a8718..76ae461749 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -21,10 +21,6 @@ void tb_flush(CPUState *cpu) { } -void tb_unlock(void) -{ -} - void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) { } diff --git a/audio/audio.c b/audio/audio.c index 6eccdb17ee..d6e91901aa 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -335,9 +335,8 @@ static int audio_get_conf_int (const char *key, int defval, int *defaultp) char *strval; strval = getenv (key); - if (strval) { + if (strval && !qemu_strtoi(strval, NULL, 10, &val)) { *defaultp = 0; - val = atoi (strval); return val; } else { @@ -1355,6 +1355,7 @@ static int tcg_cpu_exec(CPUState *cpu) int64_t ti; #endif + assert(tcg_enabled()); #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif @@ -1397,6 +1398,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) { CPUState *cpu = arg; + assert(tcg_enabled()); rcu_register_thread(); tcg_register_thread(); @@ -1631,6 +1633,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) { CPUState *cpu = arg; + assert(tcg_enabled()); g_assert(!use_icount); rcu_register_thread(); @@ -1854,6 +1857,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) static QemuThread *single_tcg_cpu_thread; static int tcg_region_inited; + assert(tcg_enabled()); /* * Initialize TCG regions--once. Now is a good time, because: * (1) TCG's init context, prologue and target globals have been set up. @@ -1323,6 +1323,7 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length) RAMBlock *block; ram_addr_t end; + assert(tcg_enabled()); end = TARGET_PAGE_ALIGN(start + length); start &= TARGET_PAGE_MASK; @@ -2655,6 +2656,7 @@ void memory_notdirty_write_prepare(NotDirtyInfo *ndi, void memory_notdirty_write_complete(NotDirtyInfo *ndi) { if (ndi->pages) { + assert(tcg_enabled()); page_collection_unlock(ndi->pages); ndi->pages = NULL; } @@ -3046,6 +3048,7 @@ static void tcg_commit(MemoryListener *listener) CPUAddressSpace *cpuas; AddressSpaceDispatch *d; + assert(tcg_enabled()); /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index e8aa7842e6..fc4945086b 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -18,11 +18,13 @@ */ #include "qemu/osdep.h" +#include "qemu/atomic.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "intel-hda.h" #include "intel-hda-defs.h" #include "audio/audio.h" +#include "trace.h" /* -------------------------------------------------------------------------- */ @@ -126,6 +128,10 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #define PARAM nomixemu #include "hda-codec-common.h" +#define HDA_TIMER_TICKS (SCALE_MS) +#define B_SIZE sizeof(st->buf) +#define B_MASK (sizeof(st->buf) - 1) + /* -------------------------------------------------------------------------- */ static const char *fmt2name[] = { @@ -154,8 +160,13 @@ struct HDAAudioStream { SWVoiceIn *in; SWVoiceOut *out; } voice; - uint8_t buf[HDA_BUFFER_SIZE]; - uint32_t bpos; + uint8_t compat_buf[HDA_BUFFER_SIZE]; + uint32_t compat_bpos; + uint8_t buf[8192]; /* size must be power of two */ + int64_t rpos; + int64_t wpos; + QEMUTimer *buft; + int64_t buft_start; }; #define TYPE_HDA_AUDIO "hda-audio" @@ -174,55 +185,217 @@ struct HDAAudioState { /* properties */ uint32_t debug; bool mixer; + bool use_timer; }; +static inline int64_t hda_bytes_per_second(HDAAudioStream *st) +{ + return 2 * st->as.nchannels * st->as.freq; +} + +static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos) +{ + int64_t limit = B_SIZE / 8; + int64_t corr = 0; + + if (target_pos > limit) { + corr = HDA_TIMER_TICKS; + } + if (target_pos < -limit) { + corr = -HDA_TIMER_TICKS; + } + if (corr == 0) { + return; + } + + trace_hda_audio_adjust(st->node->name, target_pos); + atomic_fetch_add(&st->buft_start, corr); +} + +static void hda_audio_input_timer(void *opaque) +{ + HDAAudioStream *st = opaque; + + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); + int64_t wpos = atomic_fetch_add(&st->wpos, 0); + int64_t rpos = atomic_fetch_add(&st->rpos, 0); + + int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) + / NANOSECONDS_PER_SECOND; + wanted_rpos &= -4; /* IMPORTANT! clip to frames */ + + if (wanted_rpos <= rpos) { + /* we already transmitted the data */ + goto out_timer; + } + + int64_t to_transfer = audio_MIN(wpos - rpos, wanted_rpos - rpos); + while (to_transfer) { + uint32_t start = (rpos & B_MASK); + uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); + int rc = hda_codec_xfer( + &st->state->hda, st->stream, false, st->buf + start, chunk); + if (!rc) { + break; + } + rpos += chunk; + to_transfer -= chunk; + atomic_fetch_add(&st->rpos, chunk); + } + +out_timer: + + if (st->running) { + timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); + } +} + static void hda_audio_input_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; + + int64_t wpos = atomic_fetch_add(&st->wpos, 0); + int64_t rpos = atomic_fetch_add(&st->rpos, 0); + + int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail); + + hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1))); + + while (to_transfer) { + uint32_t start = (uint32_t) (wpos & B_MASK); + uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); + uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk); + wpos += read; + to_transfer -= read; + atomic_fetch_add(&st->wpos, read); + if (chunk != read) { + break; + } + } +} + +static void hda_audio_output_timer(void *opaque) +{ + HDAAudioStream *st = opaque; + + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); + int64_t wpos = atomic_fetch_add(&st->wpos, 0); + int64_t rpos = atomic_fetch_add(&st->rpos, 0); + + int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) + / NANOSECONDS_PER_SECOND; + wanted_wpos &= -4; /* IMPORTANT! clip to frames */ + + if (wanted_wpos <= wpos) { + /* we already received the data */ + goto out_timer; + } + + int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos); + while (to_transfer) { + uint32_t start = (wpos & B_MASK); + uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); + int rc = hda_codec_xfer( + &st->state->hda, st->stream, true, st->buf + start, chunk); + if (!rc) { + break; + } + wpos += chunk; + to_transfer -= chunk; + atomic_fetch_add(&st->wpos, chunk); + } + +out_timer: + + if (st->running) { + timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); + } +} + +static void hda_audio_output_cb(void *opaque, int avail) +{ + HDAAudioStream *st = opaque; + + int64_t wpos = atomic_fetch_add(&st->wpos, 0); + int64_t rpos = atomic_fetch_add(&st->rpos, 0); + + int64_t to_transfer = audio_MIN(wpos - rpos, avail); + + if (wpos - rpos == B_SIZE) { + /* drop buffer, reset timer adjust */ + st->rpos = 0; + st->wpos = 0; + st->buft_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + trace_hda_audio_overrun(st->node->name); + return; + } + + hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1)); + + while (to_transfer) { + uint32_t start = (uint32_t) (rpos & B_MASK); + uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); + uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk); + rpos += written; + to_transfer -= written; + atomic_fetch_add(&st->rpos, written); + if (chunk != written) { + break; + } + } +} + +static void hda_audio_compat_input_cb(void *opaque, int avail) +{ + HDAAudioStream *st = opaque; int recv = 0; int len; bool rc; - while (avail - recv >= sizeof(st->buf)) { - if (st->bpos != sizeof(st->buf)) { - len = AUD_read(st->voice.in, st->buf + st->bpos, - sizeof(st->buf) - st->bpos); - st->bpos += len; + while (avail - recv >= sizeof(st->compat_buf)) { + if (st->compat_bpos != sizeof(st->compat_buf)) { + len = AUD_read(st->voice.in, st->compat_buf + st->compat_bpos, + sizeof(st->compat_buf) - st->compat_bpos); + st->compat_bpos += len; recv += len; - if (st->bpos != sizeof(st->buf)) { + if (st->compat_bpos != sizeof(st->compat_buf)) { break; } } rc = hda_codec_xfer(&st->state->hda, st->stream, false, - st->buf, sizeof(st->buf)); + st->compat_buf, sizeof(st->compat_buf)); if (!rc) { break; } - st->bpos = 0; + st->compat_bpos = 0; } } -static void hda_audio_output_cb(void *opaque, int avail) +static void hda_audio_compat_output_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int sent = 0; int len; bool rc; - while (avail - sent >= sizeof(st->buf)) { - if (st->bpos == sizeof(st->buf)) { + while (avail - sent >= sizeof(st->compat_buf)) { + if (st->compat_bpos == sizeof(st->compat_buf)) { rc = hda_codec_xfer(&st->state->hda, st->stream, true, - st->buf, sizeof(st->buf)); + st->compat_buf, sizeof(st->compat_buf)); if (!rc) { break; } - st->bpos = 0; + st->compat_bpos = 0; } - len = AUD_write(st->voice.out, st->buf + st->bpos, - sizeof(st->buf) - st->bpos); - st->bpos += len; + len = AUD_write(st->voice.out, st->compat_buf + st->compat_bpos, + sizeof(st->compat_buf) - st->compat_bpos); + st->compat_bpos += len; sent += len; - if (st->bpos != sizeof(st->buf)) { + if (st->compat_bpos != sizeof(st->compat_buf)) { break; } } @@ -237,8 +410,18 @@ static void hda_audio_set_running(HDAAudioStream *st, bool running) return; } st->running = running; - dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, - st->running ? "on" : "off", st->stream); + trace_hda_audio_running(st->node->name, st->stream, st->running); + if (st->state->use_timer) { + if (running) { + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + st->rpos = 0; + st->wpos = 0; + st->buft_start = now; + timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); + } else { + timer_del(st->buft); + } + } if (st->output) { AUD_set_active_out(st->voice.out, st->running); } else { @@ -274,22 +457,36 @@ static void hda_audio_set_amp(HDAAudioStream *st) static void hda_audio_setup(HDAAudioStream *st) { + bool use_timer = st->state->use_timer; + audio_callback_fn cb; + if (st->node == NULL) { return; } - dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n", - st->node->name, st->as.nchannels, - fmt2name[st->as.fmt], st->as.freq); + trace_hda_audio_format(st->node->name, st->as.nchannels, + fmt2name[st->as.fmt], st->as.freq); if (st->output) { + if (use_timer) { + cb = hda_audio_output_cb; + st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, + hda_audio_output_timer, st); + } else { + cb = hda_audio_compat_output_cb; + } st->voice.out = AUD_open_out(&st->state->card, st->voice.out, - st->node->name, st, - hda_audio_output_cb, &st->as); + st->node->name, st, cb, &st->as); } else { + if (use_timer) { + cb = hda_audio_input_cb; + st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, + hda_audio_input_timer, st); + } else { + cb = hda_audio_compat_input_cb; + } st->voice.in = AUD_open_in(&st->state->card, st->voice.in, - st->node->name, st, - hda_audio_input_cb, &st->as); + st->node->name, st, cb, &st->as); } } @@ -505,7 +702,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) /* unmute output by default */ st->gain_left = QEMU_HDA_AMP_STEPS; st->gain_right = QEMU_HDA_AMP_STEPS; - st->bpos = sizeof(st->buf); + st->compat_bpos = sizeof(st->compat_buf); st->output = true; } else { st->output = false; @@ -532,6 +729,9 @@ static void hda_audio_exit(HDACodecDevice *hda) if (st->node == NULL) { continue; } + if (a->use_timer) { + timer_del(st->buft); + } if (st->output) { AUD_close_out(&a->card, st->voice.out); } else { @@ -581,6 +781,26 @@ static void hda_audio_reset(DeviceState *dev) } } +static bool vmstate_hda_audio_stream_buf_needed(void *opaque) +{ + HDAAudioStream *st = opaque; + return st->state->use_timer; +} + +static const VMStateDescription vmstate_hda_audio_stream_buf = { + .name = "hda-audio-stream/buffer", + .version_id = 1, + .needed = vmstate_hda_audio_stream_buf_needed, + .fields = (VMStateField[]) { + VMSTATE_BUFFER(buf, HDAAudioStream), + VMSTATE_INT64(rpos, HDAAudioStream), + VMSTATE_INT64(wpos, HDAAudioStream), + VMSTATE_TIMER_PTR(buft, HDAAudioStream), + VMSTATE_INT64(buft_start, HDAAudioStream), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_hda_audio_stream = { .name = "hda-audio-stream", .version_id = 1, @@ -592,9 +812,13 @@ static const VMStateDescription vmstate_hda_audio_stream = { VMSTATE_UINT32(gain_right, HDAAudioStream), VMSTATE_BOOL(mute_left, HDAAudioStream), VMSTATE_BOOL(mute_right, HDAAudioStream), - VMSTATE_UINT32(bpos, HDAAudioStream), - VMSTATE_BUFFER(buf, HDAAudioStream), + VMSTATE_UINT32(compat_bpos, HDAAudioStream), + VMSTATE_BUFFER(compat_buf, HDAAudioStream), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_hda_audio_stream_buf, + NULL } }; @@ -615,6 +839,7 @@ static const VMStateDescription vmstate_hda_audio = { static Property hda_audio_properties[] = { DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0), DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true), + DEFINE_PROP_BOOL("use-timer", HDAAudioState, use_timer, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 948268afd8..23a2cf6484 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -407,13 +407,6 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, if (st->bpl == NULL) { return false; } - if (st->ctl & (1 << 26)) { - /* - * Wait with the next DMA xfer until the guest - * has acked the buffer completion interrupt - */ - return false; - } left = len; s = st->bentries; diff --git a/hw/audio/trace-events b/hw/audio/trace-events index fa1646d169..5891b4e2b9 100644 --- a/hw/audio/trace-events +++ b/hw/audio/trace-events @@ -17,3 +17,9 @@ milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u" milkymist_ac97_in_cb_transferred(int transferred) "transferred %d" milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u" milkymist_ac97_out_cb_transferred(int transferred) "transferred %d" + +# hw/audio/hda-codec.c +hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run %d" +hda_audio_format(const char *stream, int chan, const char *fmt, int freq) "st %s, %d x %s @ %d Hz" +hda_audio_adjust(const char *stream, int pos) "st %s, pos %d" +hda_audio_overrun(const char *stream) "st %s" diff --git a/include/hw/compat.h b/include/hw/compat.h index 563908b874..44d5964060 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -6,6 +6,10 @@ .driver = "migration",\ .property = "decompress-error-check",\ .value = "off",\ + },{\ + .driver = "hda-audio",\ + .property = "use-timer",\ + .value = "false",\ }, #define HW_COMPAT_2_11 \ diff --git a/scripts/qmp/qemu-ga-client b/scripts/qmp/qemu-ga-client index 976e69e05f..e8cb7646a0 100755 --- a/scripts/qmp/qemu-ga-client +++ b/scripts/qmp/qemu-ga-client @@ -37,11 +37,10 @@ # from __future__ import print_function -from __future__ import absolute_import import base64 import random -from . import qmp +import qmp class QemuGuestAgent(qmp.QEMUMonitorProtocol): diff --git a/scripts/qmp/qmp b/scripts/qmp/qmp index 33a0d6b73a..6cb46fdae2 100755 --- a/scripts/qmp/qmp +++ b/scripts/qmp/qmp @@ -11,9 +11,8 @@ # See the COPYING file in the top-level directory. from __future__ import print_function -from __future__ import absolute_import import sys, os -from .qmp import QEMUMonitorProtocol +from qmp import QEMUMonitorProtocol def print_response(rsp, prefix=[]): if type(rsp) == list: diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 26418dab95..a42306dd89 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -66,8 +66,7 @@ # sent to QEMU, which is useful for debugging and documentation generation. from __future__ import print_function -from __future__ import absolute_import -from . import qmp +import qmp import json import ast import readline diff --git a/scripts/qmp/qom-fuse b/scripts/qmp/qom-fuse index e524e798fc..4d85970a78 100755 --- a/scripts/qmp/qom-fuse +++ b/scripts/qmp/qom-fuse @@ -11,12 +11,11 @@ # the COPYING file in the top-level directory. ## -from __future__ import absolute_import import fuse, stat from fuse import Fuse import os, posix from errno import * -from .qmp import QEMUMonitorProtocol +from qmp import QEMUMonitorProtocol fuse.fuse_python_api = (0, 2) diff --git a/scripts/qmp/qom-get b/scripts/qmp/qom-get index a3f5d7660e..ec5275d53a 100755 --- a/scripts/qmp/qom-get +++ b/scripts/qmp/qom-get @@ -12,10 +12,9 @@ ## from __future__ import print_function -from __future__ import absolute_import import sys import os -from .qmp import QEMUMonitorProtocol +from qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None diff --git a/scripts/qmp/qom-list b/scripts/qmp/qom-list index 2ba25e1792..0f97440973 100755 --- a/scripts/qmp/qom-list +++ b/scripts/qmp/qom-list @@ -12,10 +12,9 @@ ## from __future__ import print_function -from __future__ import absolute_import import sys import os -from .qmp import QEMUMonitorProtocol +from qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None diff --git a/scripts/qmp/qom-set b/scripts/qmp/qom-set index 0352668812..26ed9e3263 100755 --- a/scripts/qmp/qom-set +++ b/scripts/qmp/qom-set @@ -12,10 +12,9 @@ ## from __future__ import print_function -from __future__ import absolute_import import sys import os -from .qmp import QEMUMonitorProtocol +from qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None diff --git a/scripts/qmp/qom-tree b/scripts/qmp/qom-tree index 32e708a13e..31603c681f 100755 --- a/scripts/qmp/qom-tree +++ b/scripts/qmp/qom-tree @@ -14,10 +14,9 @@ ## from __future__ import print_function -from __future__ import absolute_import import sys import os -from .qmp import QEMUMonitorProtocol +from qmp import QEMUMonitorProtocol cmd, args = sys.argv[0], sys.argv[1:] socket_path = None |