Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging

* x86 TCG fixes for 64-bit call gates (Andrew)
* qumu-guest-agent freeze-hook tweak (Christian)
* pm_smbus improvements (Corey)
* Move validation to pre_plug for pc-dimm (David)
* Fix memory leaks (Eduardo, Marc-André)
* synchronization profiler (Emilio)
* Convert the CPU list to RCU (Emilio)
* LSI support for PPR Extended Message (George)
* vhost-scsi support for protection information (Greg)
* Mark mptsas as a storage device in the help (Guenter)
* checkpatch tweak cherry-picked from Linux (me)
* Typos, cleanups and dead-code removal (Julia, Marc-André)
* qemu-pr-helper support for old libmultipath (Murilo)
* Annotate fallthroughs (me)
* MemoryRegionOps cleanup (me, Peter)
* Make s390 qtests independent from libqos, which doesn't actually support it (me)
* Make cpu_get_ticks independent from BQL (me)
* Introspection fixes (Thomas)
* Support QEMU_MODULE_DIR environment variable (ryang)

# gpg: Signature made Thu 23 Aug 2018 17:46:30 BST
# gpg:                using RSA key BFFBD25F78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream: (69 commits)
  KVM: cleanup unnecessary #ifdef KVM_CAP_...
  target/i386: update MPX flags when CPL changes
  i2c: pm_smbus: Add the ability to force block transfer enable
  i2c: pm_smbus: Don't delay host status register busy bit when interrupts are enabled
  i2c: pm_smbus: Add interrupt handling
  i2c: pm_smbus: Add block transfer capability
  i2c: pm_smbus: Make the I2C block read command read-only
  i2c: pm_smbus: Fix the semantics of block I2C transfers
  i2c: pm_smbus: Clean up some style issues
  pc-dimm: assign and verify the "addr" property during pre_plug
  pc: drop memory region alignment check for 0
  util/oslib-win32: indicate alignment for qemu_anon_ram_alloc()
  pc-dimm: assign and verify the "slot" property during pre_plug
  ipmi: Use proper struct reference for BT vmstate
  vhost-scsi: expose 't10_pi' property for VIRTIO_SCSI_F_T10_PI
  vhost-scsi: unify vhost-scsi get_features implementations
  vhost-user-scsi: move host_features into VHostSCSICommon
  cpus: allow cpu_get_ticks out of BQL
  cpus: protect TimerState writes with a spinlock
  seqlock: add QemuLockable support
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2018-08-23 19:03:54 +01:00
101 changed files with 2538 additions and 745 deletions
+10 -1
View File
@@ -1696,7 +1696,6 @@ F: qom/
X: qom/cpu.c
F: tests/check-qom-interface.c
F: tests/check-qom-proplist.c
F: tests/qom-test.c
QMP
M: Markus Armbruster <armbru@redhat.com>
@@ -1708,6 +1707,16 @@ F: scripts/qmp/
F: tests/qmp-test.c
T: git git://repo.or.cz/qemu/armbru.git qapi-next
qtest
M: Paolo Bonzini <pbonzini@redhat.com>
M: Thomas Huth <thuth@redhat.com>
M: Laurent Vivier <lvivier@redhat.com>
S: Maintained
F: qtest.c
F: tests/libqtest.*
F: tests/libqos/
F: tests/*-test.c
Register API
M: Alistair Francis <alistair@alistair23.me>
S: Maintained
-2
View File
@@ -1639,10 +1639,8 @@ static int kvm_init(MachineState *ms)
s->irq_set_ioctl = KVM_IRQ_LINE_STATUS;
}
#ifdef KVM_CAP_READONLY_MEM
kvm_readonly_mem_allowed =
(kvm_check_extension(s, KVM_CAP_READONLY_MEM) > 0);
#endif
kvm_eventfds_allowed =
(kvm_check_extension(s, KVM_CAP_IOEVENTFD) > 0);
Vendored
+23 -4
View File
@@ -3612,6 +3612,7 @@ fi
# libmpathpersist probe
if test "$mpath" != "no" ; then
# probe for the new API
cat > $TMPC <<EOF
#include <libudev.h>
#include <mpath_persist.h>
@@ -3633,8 +3634,26 @@ int main(void) {
EOF
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
mpathpersist=yes
mpathpersist_new_api=yes
else
mpathpersist=no
# probe for the old API
cat > $TMPC <<EOF
#include <libudev.h>
#include <mpath_persist.h>
unsigned mpath_mx_alloc_len = 1024;
int logsink;
int main(void) {
struct udev *udev = udev_new();
mpath_lib_init(udev);
return 0;
}
EOF
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
mpathpersist=yes
mpathpersist_new_api=no
else
mpathpersist=no
fi
fi
else
mpathpersist=no
@@ -6409,9 +6428,6 @@ if test "$bluez" = "yes" ; then
echo "CONFIG_BLUEZ=y" >> $config_host_mak
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
fi
if test "$glib_subprocess" = "yes" ; then
echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak
fi
if test "$gtk" = "yes" ; then
echo "CONFIG_GTK=m" >> $config_host_mak
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
@@ -6495,6 +6511,9 @@ if test "$virtfs" = "yes" ; then
fi
if test "$mpath" = "yes" ; then
echo "CONFIG_MPATH=y" >> $config_host_mak
if test "$mpathpersist_new_api" = "yes"; then
echo "CONFIG_MPATH_NEW_API=y" >> $config_host_mak
fi
fi
if test "$vhost_scsi" = "yes" ; then
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
+2 -2
View File
@@ -84,7 +84,7 @@ void cpu_list_add(CPUState *cpu)
} else {
assert(!cpu_index_auto_assigned);
}
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node);
qemu_mutex_unlock(&qemu_cpu_list_lock);
finish_safe_work(cpu);
@@ -101,7 +101,7 @@ void cpu_list_remove(CPUState *cpu)
assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
QTAILQ_REMOVE(&cpus, cpu, node);
QTAILQ_REMOVE_RCU(&cpus, cpu, node);
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
qemu_mutex_unlock(&qemu_cpu_list_lock);
}
+120 -72
View File
@@ -121,8 +121,6 @@ static bool all_cpu_threads_idle(void)
/* Protected by TimersState seqlock */
static bool icount_sleep = true;
/* Conversion factor from emulated instructions to virtual clock ticks. */
static int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
#define MAX_ICOUNT_SHIFT 10
@@ -131,20 +129,27 @@ typedef struct TimersState {
int64_t cpu_ticks_prev;
int64_t cpu_ticks_offset;
/* cpu_clock_offset can be read out of BQL, so protect it with
* this lock.
/* Protect fields that can be respectively read outside the
* BQL, and written from multiple threads.
*/
QemuSeqLock vm_clock_seqlock;
int64_t cpu_clock_offset;
int32_t cpu_ticks_enabled;
int64_t dummy;
QemuSpin vm_clock_lock;
int16_t cpu_ticks_enabled;
/* Conversion factor from emulated instructions to virtual clock ticks. */
int16_t icount_time_shift;
/* Compensate for varying guest execution speed. */
int64_t qemu_icount_bias;
int64_t vm_clock_warp_start;
int64_t cpu_clock_offset;
/* Only written by TCG thread */
int64_t qemu_icount;
/* for adjusting icount */
int64_t vm_clock_warp_start;
QEMUTimer *icount_rt_timer;
QEMUTimer *icount_vm_timer;
QEMUTimer *icount_warp_timer;
@@ -245,16 +250,19 @@ void cpu_update_icount(CPUState *cpu)
int64_t executed = cpu_get_icount_executed(cpu);
cpu->icount_budget -= executed;
#ifdef CONFIG_ATOMIC64
#ifndef CONFIG_ATOMIC64
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
#endif
atomic_set__nocheck(&timers_state.qemu_icount,
atomic_read__nocheck(&timers_state.qemu_icount) +
executed);
#else /* FIXME: we need 64bit atomics to do this safely */
timers_state.qemu_icount += executed;
timers_state.qemu_icount + executed);
#ifndef CONFIG_ATOMIC64
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
#endif
}
int64_t cpu_get_icount_raw(void)
static int64_t cpu_get_icount_raw_locked(void)
{
CPUState *cpu = current_cpu;
@@ -266,20 +274,30 @@ int64_t cpu_get_icount_raw(void)
/* Take into account what has run */
cpu_update_icount(cpu);
}
#ifdef CONFIG_ATOMIC64
/* The read is protected by the seqlock, so __nocheck is okay. */
return atomic_read__nocheck(&timers_state.qemu_icount);
#else /* FIXME: we need 64bit atomics to do this safely */
return timers_state.qemu_icount;
#endif
}
static int64_t cpu_get_icount_locked(void)
{
int64_t icount = cpu_get_icount_raw_locked();
return atomic_read__nocheck(&timers_state.qemu_icount_bias) + cpu_icount_to_ns(icount);
}
int64_t cpu_get_icount_raw(void)
{
int64_t icount;
unsigned start;
do {
start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
icount = cpu_get_icount_raw_locked();
} while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
return icount;
}
/* Return the virtual CPU time, based on the instruction counter. */
static int64_t cpu_get_icount_locked(void)
{
int64_t icount = cpu_get_icount_raw();
return timers_state.qemu_icount_bias + cpu_icount_to_ns(icount);
}
int64_t cpu_get_icount(void)
{
int64_t icount;
@@ -295,14 +313,29 @@ int64_t cpu_get_icount(void)
int64_t cpu_icount_to_ns(int64_t icount)
{
return icount << icount_time_shift;
return icount << atomic_read(&timers_state.icount_time_shift);
}
static int64_t cpu_get_ticks_locked(void)
{
int64_t ticks = timers_state.cpu_ticks_offset;
if (timers_state.cpu_ticks_enabled) {
ticks += cpu_get_host_ticks();
}
if (timers_state.cpu_ticks_prev > ticks) {
/* Non increasing ticks may happen if the host uses software suspend. */
timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
ticks = timers_state.cpu_ticks_prev;
}
timers_state.cpu_ticks_prev = ticks;
return ticks;
}
/* return the time elapsed in VM between vm_start and vm_stop. Unless
* icount is active, cpu_get_ticks() uses units of the host CPU cycle
* counter.
*
* Caller must hold the BQL
*/
int64_t cpu_get_ticks(void)
{
@@ -312,19 +345,9 @@ int64_t cpu_get_ticks(void)
return cpu_get_icount();
}
ticks = timers_state.cpu_ticks_offset;
if (timers_state.cpu_ticks_enabled) {
ticks += cpu_get_host_ticks();
}
if (timers_state.cpu_ticks_prev > ticks) {
/* Note: non increasing ticks may happen if the host uses
software suspend */
timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
ticks = timers_state.cpu_ticks_prev;
}
timers_state.cpu_ticks_prev = ticks;
qemu_spin_lock(&timers_state.vm_clock_lock);
ticks = cpu_get_ticks_locked();
qemu_spin_unlock(&timers_state.vm_clock_lock);
return ticks;
}
@@ -361,14 +384,15 @@ int64_t cpu_get_clock(void)
*/
void cpu_enable_ticks(void)
{
/* Here, the really thing protected by seqlock is cpu_clock_offset. */
seqlock_write_begin(&timers_state.vm_clock_seqlock);
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
if (!timers_state.cpu_ticks_enabled) {
timers_state.cpu_ticks_offset -= cpu_get_host_ticks();
timers_state.cpu_clock_offset -= get_clock();
timers_state.cpu_ticks_enabled = 1;
}
seqlock_write_end(&timers_state.vm_clock_seqlock);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
}
/* disable cpu_get_ticks() : the clock is stopped. You must not call
@@ -377,14 +401,15 @@ void cpu_enable_ticks(void)
*/
void cpu_disable_ticks(void)
{
/* Here, the really thing protected by seqlock is cpu_clock_offset. */
seqlock_write_begin(&timers_state.vm_clock_seqlock);
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
if (timers_state.cpu_ticks_enabled) {
timers_state.cpu_ticks_offset += cpu_get_host_ticks();
timers_state.cpu_clock_offset = cpu_get_clock_locked();
timers_state.cpu_ticks_enabled = 0;
}
seqlock_write_end(&timers_state.vm_clock_seqlock);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
}
/* Correlation between real and virtual time is always going to be
@@ -407,7 +432,8 @@ static void icount_adjust(void)
return;
}
seqlock_write_begin(&timers_state.vm_clock_seqlock);
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
cur_time = cpu_get_clock_locked();
cur_icount = cpu_get_icount_locked();
@@ -415,20 +441,24 @@ static void icount_adjust(void)
/* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
if (delta > 0
&& last_delta + ICOUNT_WOBBLE < delta * 2
&& icount_time_shift > 0) {
&& timers_state.icount_time_shift > 0) {
/* The guest is getting too far ahead. Slow time down. */
icount_time_shift--;
atomic_set(&timers_state.icount_time_shift,
timers_state.icount_time_shift - 1);
}
if (delta < 0
&& last_delta - ICOUNT_WOBBLE > delta * 2
&& icount_time_shift < MAX_ICOUNT_SHIFT) {
&& timers_state.icount_time_shift < MAX_ICOUNT_SHIFT) {
/* The guest is getting too far behind. Speed time up. */
icount_time_shift++;
atomic_set(&timers_state.icount_time_shift,
timers_state.icount_time_shift + 1);
}
last_delta = delta;
timers_state.qemu_icount_bias = cur_icount
- (timers_state.qemu_icount << icount_time_shift);
seqlock_write_end(&timers_state.vm_clock_seqlock);
atomic_set__nocheck(&timers_state.qemu_icount_bias,
cur_icount - (timers_state.qemu_icount
<< timers_state.icount_time_shift));
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
}
static void icount_adjust_rt(void *opaque)
@@ -448,7 +478,8 @@ static void icount_adjust_vm(void *opaque)
static int64_t qemu_icount_round(int64_t count)
{
return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
int shift = atomic_read(&timers_state.icount_time_shift);
return (count + (1 << shift) - 1) >> shift;
}
static void icount_warp_rt(void)
@@ -468,7 +499,8 @@ static void icount_warp_rt(void)
return;
}
seqlock_write_begin(&timers_state.vm_clock_seqlock);
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
if (runstate_is_running()) {
int64_t clock = REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT,
cpu_get_clock_locked());
@@ -484,10 +516,12 @@ static void icount_warp_rt(void)
int64_t delta = clock - cur_icount;
warp_delta = MIN(warp_delta, delta);
}
timers_state.qemu_icount_bias += warp_delta;
atomic_set__nocheck(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + warp_delta);
}
timers_state.vm_clock_warp_start = -1;
seqlock_write_end(&timers_state.vm_clock_seqlock);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) {
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
@@ -512,9 +546,12 @@ void qtest_clock_warp(int64_t dest)
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
seqlock_write_begin(&timers_state.vm_clock_seqlock);
timers_state.qemu_icount_bias += warp;
seqlock_write_end(&timers_state.vm_clock_seqlock);
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
atomic_set__nocheck(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + warp);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]);
@@ -581,9 +618,12 @@ void qemu_start_warp_timer(void)
* It is useful when we want a deterministic execution time,
* isolated from host latencies.
*/
seqlock_write_begin(&timers_state.vm_clock_seqlock);
timers_state.qemu_icount_bias += deadline;
seqlock_write_end(&timers_state.vm_clock_seqlock);
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
atomic_set__nocheck(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + deadline);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
} else {
/*
@@ -594,12 +634,14 @@ void qemu_start_warp_timer(void)
* you will not be sending network packets continuously instead of
* every 100ms.
*/
seqlock_write_begin(&timers_state.vm_clock_seqlock);
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
if (timers_state.vm_clock_warp_start == -1
|| timers_state.vm_clock_warp_start > clock) {
timers_state.vm_clock_warp_start = clock;
}
seqlock_write_end(&timers_state.vm_clock_seqlock);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
timer_mod_anticipate(timers_state.icount_warp_timer,
clock + deadline);
}
@@ -700,7 +742,7 @@ static const VMStateDescription vmstate_timers = {
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT64(cpu_ticks_offset, TimersState),
VMSTATE_INT64(dummy, TimersState),
VMSTATE_UNUSED(8),
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
VMSTATE_END_OF_LIST()
},
@@ -812,7 +854,7 @@ void configure_icount(QemuOpts *opts, Error **errp)
}
if (strcmp(option, "auto") != 0) {
errno = 0;
icount_time_shift = strtol(option, &rem_str, 0);
timers_state.icount_time_shift = strtol(option, &rem_str, 0);
if (errno != 0 || *rem_str != '\0' || !strlen(option)) {
error_setg(errp, "icount: Invalid shift value");
}
@@ -828,7 +870,7 @@ void configure_icount(QemuOpts *opts, Error **errp)
/* 125MIPS seems a reasonable initial guess at the guest speed.
It will be corrected fairly quickly anyway. */
icount_time_shift = 3;
timers_state.icount_time_shift = 3;
/* Have both realtime and virtual time triggers for speed adjustment.
The realtime trigger catches emulated time passing too slowly,
@@ -1491,7 +1533,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
atomic_mb_set(&cpu->exit_request, 0);
}
qemu_tcg_rr_wait_io_event(cpu ? cpu : QTAILQ_FIRST(&cpus));
qemu_tcg_rr_wait_io_event(cpu ? cpu : first_cpu);
deal_with_unplugged_cpus();
}
@@ -1762,10 +1804,16 @@ bool qemu_mutex_iothread_locked(void)
return iothread_locked;
}
void qemu_mutex_lock_iothread(void)
/*
* The BQL is taken from so many places that it is worth profiling the
* callers directly, instead of funneling them all through a single function.
*/
void qemu_mutex_lock_iothread_impl(const char *file, int line)
{
QemuMutexLockFunc bql_lock = atomic_read(&qemu_bql_mutex_lock_func);
g_assert(!qemu_mutex_iothread_locked());
qemu_mutex_lock(&qemu_global_mutex);
bql_lock(&qemu_global_mutex, file, line);
iothread_locked = true;
}
+1
View File
@@ -1623,6 +1623,7 @@ print_insn_arg (const char *d,
case 'X':
place = '8';
/* fall through */
case 'Y':
case 'Z':
case 'W':
+1 -1
View File
@@ -1742,7 +1742,7 @@ static void dump_init(DumpState *s, int fd, bool has_format,
warn_report("guest note is not present");
} else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
warn_report("guest note size is invalid: %" PRIu32, size);
} else if (format != VMCOREINFO_FORMAT_ELF) {
} else if (format != FW_CFG_VMCOREINFO_FORMAT_ELF) {
warn_report("guest note format is unsupported: %" PRIu16, format);
} else {
s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
+22
View File
@@ -297,6 +297,28 @@ STEXI
@item info opcount
@findex info opcount
Show dynamic compiler opcode counters
ETEXI
{
.name = "sync-profile",
.args_type = "mean:-m,no_coalesce:-n,max:i?",
.params = "[-m] [-n] [max]",
.help = "show synchronization profiling info, up to max entries "
"(default: 10), sorted by total wait time. (-m: sort by "
"mean wait time; -n: do not coalesce objects with the "
"same call site)",
.cmd = hmp_info_sync_profile,
},
STEXI
@item info sync-profile [-m|-n] [@var{max}]
@findex info sync-profile
Show synchronization profiling info, up to @var{max} entries (default: 10),
sorted by total wait time.
-m: sort by mean wait time
-n: do not coalesce objects with the same call site
When different objects that share the same call site are coalesced, the "Object"
field shows---enclosed in brackets---the number of objects being coalesced.
ETEXI
{
+15
View File
@@ -643,6 +643,21 @@ sendkey ctrl-alt-f1
This command is useful to send keys that your graphical user interface
intercepts at low level, such as @code{ctrl-alt-f1} in X Window.
ETEXI
{
.name = "sync-profile",
.args_type = "op:s?",
.params = "[on|off|reset]",
.help = "enable, disable or reset synchronization profiling. "
"With no arguments, prints whether profiling is on or off.",
.cmd = hmp_sync_profile,
},
STEXI
@item sync-profile [on|off|reset]
@findex sync-profile
Enable, disable or reset synchronization profiling. With no arguments, prints
whether profiling is on or off.
ETEXI
{
+24
View File
@@ -1062,6 +1062,30 @@ void hmp_stop(Monitor *mon, const QDict *qdict)
qmp_stop(NULL);
}
void hmp_sync_profile(Monitor *mon, const QDict *qdict)
{
const char *op = qdict_get_try_str(qdict, "op");
if (op == NULL) {
bool on = qsp_is_enabled();
monitor_printf(mon, "sync-profile is %s\n", on ? "on" : "off");
return;
}
if (!strcmp(op, "on")) {
qsp_enable();
} else if (!strcmp(op, "off")) {
qsp_disable();
} else if (!strcmp(op, "reset")) {
qsp_reset();
} else {
Error *err = NULL;
error_setg(&err, QERR_INVALID_PARAMETER, op);
hmp_handle_error(mon, &err);
}
}
void hmp_system_reset(Monitor *mon, const QDict *qdict)
{
qmp_system_reset(NULL);
+1
View File
@@ -42,6 +42,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict);
void hmp_info_iothreads(Monitor *mon, const QDict *qdict);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_sync_profile(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
void hmp_exit_preconfig(Monitor *mon, const QDict *qdict);
+1 -1
View File
@@ -512,7 +512,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
pci_conf[0x90] = s->smb_io_base | 1;
pci_conf[0x91] = s->smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
pm_smbus_init(DEVICE(dev), &s->smb);
pm_smbus_init(DEVICE(dev), &s->smb, true);
memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
memory_region_add_subregion(pci_address_space_io(dev),
s->smb_io_base, &s->smb.io);
+1 -1
View File
@@ -409,7 +409,7 @@ static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr,
case MDCNFG ... SA1110:
if ((addr & 3) == 0)
return s->mm_regs[addr >> 2];
/* fall through */
default:
printf("%s: Bad register " REG_FMT "\n", __func__, addr);
break;
+1
View File
@@ -305,6 +305,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)
case 6:
as.endianness = 1;
/* fall through */
case 2:
as.fmt = AUD_FMT_S16;
s->shift = as.nchannels;
+25 -210
View File
@@ -474,82 +474,7 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
return addr;
}
static void es1370_writeb(void *opaque, uint32_t addr, uint32_t val)
{
ES1370State *s = opaque;
uint32_t shift, mask;
addr = es1370_fixup (s, addr);
switch (addr) {
case ES1370_REG_CONTROL:
case ES1370_REG_CONTROL + 1:
case ES1370_REG_CONTROL + 2:
case ES1370_REG_CONTROL + 3:
shift = (addr - ES1370_REG_CONTROL) << 3;
mask = 0xff << shift;
val = (s->ctl & ~mask) | ((val & 0xff) << shift);
es1370_update_voices (s, val, s->sctl);
print_ctl (val);
break;
case ES1370_REG_MEMPAGE:
s->mempage = val;
break;
case ES1370_REG_SERIAL_CONTROL:
case ES1370_REG_SERIAL_CONTROL + 1:
case ES1370_REG_SERIAL_CONTROL + 2:
case ES1370_REG_SERIAL_CONTROL + 3:
shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
mask = 0xff << shift;
val = (s->sctl & ~mask) | ((val & 0xff) << shift);
es1370_maybe_lower_irq (s, val);
es1370_update_voices (s, s->ctl, val);
print_sctl (val);
break;
default:
lwarn ("writeb %#x <- %#x\n", addr, val);
break;
}
}
static void es1370_writew(void *opaque, uint32_t addr, uint32_t val)
{
ES1370State *s = opaque;
addr = es1370_fixup (s, addr);
uint32_t shift, mask;
struct chan *d = &s->chan[0];
switch (addr) {
case ES1370_REG_CODEC:
dolog ("ignored codec write address %#x, data %#x\n",
(val >> 8) & 0xff, val & 0xff);
s->codec = val;
break;
case ES1370_REG_CONTROL:
case ES1370_REG_CONTROL + 2:
shift = (addr != ES1370_REG_CONTROL) << 4;
mask = 0xffff << shift;
val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
es1370_update_voices (s, val, s->sctl);
print_ctl (val);
break;
case ES1370_REG_ADC_SCOUNT:
d++;
case ES1370_REG_DAC2_SCOUNT:
d++;
case ES1370_REG_DAC1_SCOUNT:
d->scount = (d->scount & ~0xffff) | (val & 0xffff);
break;
default:
lwarn ("writew %#x <- %#x\n", addr, val);
break;
}
}
static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
ES1370State *s = opaque;
struct chan *d = &s->chan[0];
@@ -572,21 +497,19 @@ static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
print_sctl (val);
break;
case ES1370_REG_ADC_SCOUNT:
d++;
case ES1370_REG_DAC2_SCOUNT:
d++;
case ES1370_REG_DAC1_SCOUNT:
case ES1370_REG_DAC2_SCOUNT:
case ES1370_REG_ADC_SCOUNT:
d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
d->scount = (val & 0xffff) | (d->scount & ~0xffff);
ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
d - &s->chan[0], val >> 16, (val & 0xffff));
break;
case ES1370_REG_ADC_FRAMEADR:
d++;
case ES1370_REG_DAC2_FRAMEADR:
d++;
case ES1370_REG_DAC1_FRAMEADR:
case ES1370_REG_DAC2_FRAMEADR:
case ES1370_REG_ADC_FRAMEADR:
d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
d->frame_addr = val;
ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
break;
@@ -598,11 +521,10 @@ static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
lwarn ("writing to phantom frame address %#x\n", val);
break;
case ES1370_REG_ADC_FRAMECNT:
d++;
case ES1370_REG_DAC2_FRAMECNT:
d++;
case ES1370_REG_DAC1_FRAMECNT:
case ES1370_REG_DAC2_FRAMECNT:
case ES1370_REG_ADC_FRAMECNT:
d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
d->frame_cnt = val;
d->leftover = 0;
ldebug ("chan %td frame count %d, buffer size %d\n",
@@ -615,84 +537,7 @@ static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
}
}
static uint32_t es1370_readb(void *opaque, uint32_t addr)
{
ES1370State *s = opaque;
uint32_t val;
addr = es1370_fixup (s, addr);
switch (addr) {
case 0x1b: /* Legacy */
lwarn ("Attempt to read from legacy register\n");
val = 5;
break;
case ES1370_REG_MEMPAGE:
val = s->mempage;
break;
case ES1370_REG_CONTROL + 0:
case ES1370_REG_CONTROL + 1:
case ES1370_REG_CONTROL + 2:
case ES1370_REG_CONTROL + 3:
val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
break;
case ES1370_REG_STATUS + 0:
case ES1370_REG_STATUS + 1:
case ES1370_REG_STATUS + 2:
case ES1370_REG_STATUS + 3:
val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
break;
default:
val = ~0;
lwarn ("readb %#x -> %#x\n", addr, val);
break;
}
return val;
}
static uint32_t es1370_readw(void *opaque, uint32_t addr)
{
ES1370State *s = opaque;
struct chan *d = &s->chan[0];
uint32_t val;
addr = es1370_fixup (s, addr);
switch (addr) {
case ES1370_REG_ADC_SCOUNT + 2:
d++;
case ES1370_REG_DAC2_SCOUNT + 2:
d++;
case ES1370_REG_DAC1_SCOUNT + 2:
val = d->scount >> 16;
break;
case ES1370_REG_ADC_FRAMECNT:
d++;
case ES1370_REG_DAC2_FRAMECNT:
d++;
case ES1370_REG_DAC1_FRAMECNT:
val = d->frame_cnt & 0xffff;
break;
case ES1370_REG_ADC_FRAMECNT + 2:
d++;
case ES1370_REG_DAC2_FRAMECNT + 2:
d++;
case ES1370_REG_DAC1_FRAMECNT + 2:
val = d->frame_cnt >> 16;
break;
default:
val = ~0;
lwarn ("readw %#x -> %#x\n", addr, val);
break;
}
return val;
}
static uint32_t es1370_readl(void *opaque, uint32_t addr)
static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size)
{
ES1370State *s = opaque;
uint32_t val;
@@ -717,11 +562,10 @@ static uint32_t es1370_readl(void *opaque, uint32_t addr)
val = s->sctl;
break;
case ES1370_REG_ADC_SCOUNT:
d++;
case ES1370_REG_DAC2_SCOUNT:
d++;
case ES1370_REG_DAC1_SCOUNT:
case ES1370_REG_DAC2_SCOUNT:
case ES1370_REG_ADC_SCOUNT:
d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
val = d->scount;
#ifdef DEBUG_ES1370
{
@@ -735,11 +579,10 @@ static uint32_t es1370_readl(void *opaque, uint32_t addr)
#endif
break;
case ES1370_REG_ADC_FRAMECNT:
d++;
case ES1370_REG_DAC2_FRAMECNT:
d++;
case ES1370_REG_DAC1_FRAMECNT:
case ES1370_REG_DAC2_FRAMECNT:
case ES1370_REG_ADC_FRAMECNT:
d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
val = d->frame_cnt;
#ifdef DEBUG_ES1370
{
@@ -753,11 +596,10 @@ static uint32_t es1370_readl(void *opaque, uint32_t addr)
#endif
break;
case ES1370_REG_ADC_FRAMEADR:
d++;
case ES1370_REG_DAC2_FRAMEADR:
d++;
case ES1370_REG_DAC1_FRAMEADR:
case ES1370_REG_DAC2_FRAMEADR:
case ES1370_REG_ADC_FRAMEADR:
d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
val = d->frame_addr;
break;
@@ -908,44 +750,17 @@ static void es1370_adc_callback (void *opaque, int avail)
es1370_run_channel (s, ADC_CHANNEL, avail);
}
static uint64_t es1370_read(void *opaque, hwaddr addr,
unsigned size)
{
switch (size) {
case 1:
return es1370_readb(opaque, addr);
case 2:
return es1370_readw(opaque, addr);
case 4:
return es1370_readl(opaque, addr);
default:
return -1;
}
}
static void es1370_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
switch (size) {
case 1:
es1370_writeb(opaque, addr, val);
break;
case 2:
es1370_writew(opaque, addr, val);
break;
case 4:
es1370_writel(opaque, addr, val);
break;
}
}
static const MemoryRegionOps es1370_io_ops = {
.read = es1370_read,
.write = es1370_write,
.impl = {
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
.impl = {
.min_access_size = 4,
.max_access_size = 4,
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
+1
View File
@@ -261,6 +261,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUSregb(IRQStatReg2x6) = 0x10;
GUS_irqrequest(state, state->gusirq, 1);
}
/* fall through */
case 0x20D: /* SB2xCd no IRQ */
GUSregb(SB2xCd) = (uint8_t) data;
break;
+8 -3
View File
@@ -741,10 +741,15 @@ static void complete (SB16State *s)
ldebug ("set time const %d\n", s->time_const);
break;
case 0x42: /* FT2 sets output freq with this, go figure */
qemu_log_mask(LOG_UNIMP, "cmd 0x42 might not do what it think it"
" should\n");
case 0x41:
case 0x42:
/*
* 0x41 is documented as setting the output sample rate,
* and 0x42 the input sample rate, but in fact SB16 hardware
* seems to have only a single sample rate under the hood,
* and FT2 sets output freq with this (go figure). Compare:
* http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html#SamplingRate
*/
s->freq = dsp_get_hilo (s);
ldebug ("set freq %d\n", s->freq);
break;
+1
View File
@@ -232,6 +232,7 @@ static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
s->b[s->dac_index] = regval;
/* Index autoincrement */
s->dac_index = (s->dac_index + 1) & 0xff;
/* fall through */
default:
s->dac_state = 0;
break;
+2 -1
View File
@@ -1426,7 +1426,8 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
s->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
break;
case 0x07: // Extended Sequencer Mode
cirrus_update_memory_access(s);
cirrus_update_memory_access(s);
/* fall through */
case 0x08: // EEPROM Control
case 0x09: // Scratch Register 0
case 0x0a: // Scratch Register 1
+214 -40
View File
@@ -22,8 +22,6 @@
#include "hw/i2c/pm_smbus.h"
#include "hw/i2c/smbus.h"
/* no save/load? */
#define SMBHSTSTS 0x00
#define SMBHSTCNT 0x02
#define SMBHSTCMD 0x03
@@ -31,20 +29,40 @@
#define SMBHSTDAT0 0x05
#define SMBHSTDAT1 0x06
#define SMBBLKDAT 0x07
#define SMBAUXCTL 0x0d
#define STS_HOST_BUSY (1)
#define STS_INTR (1<<1)
#define STS_DEV_ERR (1<<2)
#define STS_BUS_ERR (1<<3)
#define STS_FAILED (1<<4)
#define STS_SMBALERT (1<<5)
#define STS_INUSE_STS (1<<6)
#define STS_BYTE_DONE (1<<7)
#define STS_HOST_BUSY (1 << 0)
#define STS_INTR (1 << 1)
#define STS_DEV_ERR (1 << 2)
#define STS_BUS_ERR (1 << 3)
#define STS_FAILED (1 << 4)
#define STS_SMBALERT (1 << 5)
#define STS_INUSE_STS (1 << 6)
#define STS_BYTE_DONE (1 << 7)
/* Signs of successfully transaction end :
* ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR )
*/
//#define DEBUG
#define CTL_INTREN (1 << 0)
#define CTL_KILL (1 << 1)
#define CTL_LAST_BYTE (1 << 5)
#define CTL_START (1 << 6)
#define CTL_PEC_EN (1 << 7)
#define CTL_RETURN_MASK 0x1f
#define PROT_QUICK 0
#define PROT_BYTE 1
#define PROT_BYTE_DATA 2
#define PROT_WORD_DATA 3
#define PROT_PROC_CALL 4
#define PROT_BLOCK_DATA 5
#define PROT_I2C_BLOCK_READ 6
#define AUX_PEC (1 << 0)
#define AUX_BLK (1 << 1)
#define AUX_MASK 0x3
/*#define DEBUG*/
#ifdef DEBUG
# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
@@ -62,19 +80,17 @@ static void smb_transaction(PMSMBus *s)
I2CBus *bus = s->smbus;
int ret;
assert(s->smb_stat & STS_HOST_BUSY);
s->smb_stat &= ~STS_HOST_BUSY;
SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
/* Transaction isn't exec if STS_DEV_ERR bit set */
if ((s->smb_stat & STS_DEV_ERR) != 0) {
goto error;
}
switch(prot) {
case 0x0:
case PROT_QUICK:
ret = smbus_quick_command(bus, addr, read);
goto done;
case 0x1:
case PROT_BYTE:
if (read) {
ret = smbus_receive_byte(bus, addr);
goto data8;
@@ -82,7 +98,7 @@ static void smb_transaction(PMSMBus *s)
ret = smbus_send_byte(bus, addr, cmd);
goto done;
}
case 0x2:
case PROT_BYTE_DATA:
if (read) {
ret = smbus_read_byte(bus, addr, cmd);
goto data8;
@@ -91,22 +107,73 @@ static void smb_transaction(PMSMBus *s)
goto done;
}
break;
case 0x3:
case PROT_WORD_DATA:
if (read) {
ret = smbus_read_word(bus, addr, cmd);
goto data16;
} else {
ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
ret = smbus_write_word(bus, addr, cmd,
(s->smb_data1 << 8) | s->smb_data0);
goto done;
}
break;
case 0x5:
case PROT_I2C_BLOCK_READ:
if (read) {
ret = smbus_read_block(bus, addr, cmd, s->smb_data);
int xfersize = s->smb_data0;
if (xfersize > sizeof(s->smb_data)) {
xfersize = sizeof(s->smb_data);
}
ret = smbus_read_block(bus, addr, s->smb_data1, s->smb_data,
xfersize, false, true);
goto data8;
} else {
ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
goto done;
/* The manual says the behavior is undefined, just set DEV_ERR. */
goto error;
}
break;
case PROT_BLOCK_DATA:
if (read) {
ret = smbus_read_block(bus, addr, cmd, s->smb_data,
sizeof(s->smb_data), !s->i2c_enable,
!s->i2c_enable);
if (ret < 0) {
goto error;
}
s->smb_index = 0;
s->op_done = false;
if (s->smb_auxctl & AUX_BLK) {
s->smb_stat |= STS_INTR;
} else {
s->smb_blkdata = s->smb_data[0];
s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
}
s->smb_data0 = ret;
goto out;
} else {
if (s->smb_auxctl & AUX_BLK) {
if (s->smb_index != s->smb_data0) {
s->smb_index = 0;
goto error;
}
/* Data is already all written to the queue, just do
the operation. */
s->smb_index = 0;
ret = smbus_write_block(bus, addr, cmd, s->smb_data,
s->smb_data0, !s->i2c_enable);
if (ret < 0) {
goto error;
}
s->op_done = true;
s->smb_stat |= STS_INTR;
s->smb_stat &= ~STS_HOST_BUSY;
} else {
s->op_done = false;
s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
s->smb_data[0] = s->smb_blkdata;
s->smb_index = 0;
ret = 0;
}
goto out;
}
break;
default:
@@ -128,20 +195,35 @@ done:
if (ret < 0) {
goto error;
}
s->smb_stat |= STS_BYTE_DONE | STS_INTR;
s->smb_stat |= STS_INTR;
out:
return;
error:
s->smb_stat |= STS_DEV_ERR;
return;
}
static void smb_transaction_start(PMSMBus *s)
{
/* Do not execute immediately the command ; it will be
* executed when guest will read SMB_STAT register */
s->smb_stat |= STS_HOST_BUSY;
if (s->smb_ctl & CTL_INTREN) {
smb_transaction(s);
} else {
/* Do not execute immediately the command; it will be
* executed when guest will read SMB_STAT register. This
* is to work around a bug in AMIBIOS (that is working
* around another bug in some specific hardware) where
* it waits for STS_HOST_BUSY to be set before waiting
* checking for status. If STS_HOST_BUSY doesn't get
* set, it gets stuck. */
s->smb_stat |= STS_HOST_BUSY;
}
}
static bool
smb_irq_value(PMSMBus *s)
{
return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN);
}
static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
@@ -153,13 +235,61 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
" val=0x%02" PRIx64 "\n", addr, val);
switch(addr) {
case SMBHSTSTS:
s->smb_stat = (~(val & 0xff)) & s->smb_stat;
s->smb_index = 0;
s->smb_stat &= ~(val & ~STS_HOST_BUSY);
if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) {
uint8_t read = s->smb_addr & 0x01;
s->smb_index++;
if (!read && s->smb_index == s->smb_data0) {
uint8_t prot = (s->smb_ctl >> 2) & 0x07;
uint8_t cmd = s->smb_cmd;
uint8_t addr = s->smb_addr >> 1;
int ret;
if (prot == PROT_I2C_BLOCK_READ) {
s->smb_stat |= STS_DEV_ERR;
goto out;
}
ret = smbus_write_block(s->smbus, addr, cmd, s->smb_data,
s->smb_data0, !s->i2c_enable);
if (ret < 0) {
s->smb_stat |= STS_DEV_ERR;
goto out;
}
s->op_done = true;
s->smb_stat |= STS_INTR;
s->smb_stat &= ~STS_HOST_BUSY;
} else if (!read) {
s->smb_data[s->smb_index] = s->smb_blkdata;
s->smb_stat |= STS_BYTE_DONE;
} else if (s->smb_ctl & CTL_LAST_BYTE) {
s->op_done = true;
s->smb_blkdata = s->smb_data[s->smb_index];
s->smb_index = 0;
s->smb_stat |= STS_INTR;
s->smb_stat &= ~STS_HOST_BUSY;
} else {
s->smb_blkdata = s->smb_data[s->smb_index];
s->smb_stat |= STS_BYTE_DONE;
}
}
break;
case SMBHSTCNT:
s->smb_ctl = val;
if (val & 0x40)
s->smb_ctl = val & ~CTL_START; /* CTL_START always reads 0 */
if (val & CTL_START) {
if (!s->op_done) {
s->smb_index = 0;
s->op_done = true;
}
smb_transaction_start(s);
}
if (s->smb_ctl & CTL_KILL) {
s->op_done = true;
s->smb_index = 0;
s->smb_stat |= STS_FAILED;
s->smb_stat &= ~STS_HOST_BUSY;
}
break;
case SMBHSTCMD:
s->smb_cmd = val;
@@ -174,13 +304,26 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
s->smb_data1 = val;
break;
case SMBBLKDAT:
s->smb_data[s->smb_index++] = val;
if (s->smb_index > 31)
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
s->smb_index = 0;
}
if (s->smb_auxctl & AUX_BLK) {
s->smb_data[s->smb_index++] = val;
} else {
s->smb_blkdata = val;
}
break;
case SMBAUXCTL:
s->smb_auxctl = val & AUX_MASK;
break;
default:
break;
}
out:
if (s->set_irq) {
s->set_irq(s, smb_irq_value(s));
}
}
static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
@@ -193,12 +336,12 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
val = s->smb_stat;
if (s->smb_stat & STS_HOST_BUSY) {
/* execute command now */
s->smb_stat &= ~STS_HOST_BUSY;
smb_transaction(s);
}
break;
case SMBHSTCNT:
s->smb_index = 0;
val = s->smb_ctl & 0x1f;
val = s->smb_ctl & CTL_RETURN_MASK;
break;
case SMBHSTCMD:
val = s->smb_cmd;
@@ -213,18 +356,44 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
val = s->smb_data1;
break;
case SMBBLKDAT:
val = s->smb_data[s->smb_index++];
if (s->smb_index > 31)
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
s->smb_index = 0;
}
if (s->smb_auxctl & AUX_BLK) {
val = s->smb_data[s->smb_index++];
if (!s->op_done && s->smb_index == s->smb_data0) {
s->op_done = true;
s->smb_index = 0;
s->smb_stat &= ~STS_HOST_BUSY;
}
} else {
val = s->smb_blkdata;
}
break;
case SMBAUXCTL:
val = s->smb_auxctl;
break;
default:
val = 0;
break;
}
SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", addr, val);
SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n",
addr, val);
if (s->set_irq) {
s->set_irq(s, smb_irq_value(s));
}
return val;
}
static void pm_smbus_reset(PMSMBus *s)
{
s->op_done = true;
s->smb_index = 0;
s->smb_stat = 0;
}
static const MemoryRegionOps pm_smbus_ops = {
.read = smb_ioport_readb,
.write = smb_ioport_writeb,
@@ -233,9 +402,14 @@ static const MemoryRegionOps pm_smbus_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk)
{
smb->op_done = true;
smb->reset = pm_smbus_reset;
smb->smbus = i2c_init_bus(parent, "i2c");
if (force_aux_blk) {
smb->smb_auxctl |= AUX_BLK;
}
memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb,
"pm-smbus", 64);
}

Some files were not shown because too many files have changed in this diff Show More