PPC: tell the guest about the time base frequency

Our guest systems need to know by how much the timebase increases every second,
so there usually is a "timebase-frequency" property in the cpu leaf of the
device tree.

This property is missing in OpenBIOS.

With qemu, Linux's fallback timebase speed and qemu's internal timebase speed
match up. With KVM, that is no longer true. The guest is running at the same
timebase speed as the host.

This leads to massive timing problems. On my test machine, a "sleep 2" takes
about 14 seconds with KVM enabled.

This patch exports the timebase frequency to OpenBIOS, so it can then put them
into the device tree.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Alexander Graf 2010-02-09 17:37:05 +01:00 committed by Michael S. Tsirkin
parent fa0be69a17
commit dc333cd609
5 changed files with 68 additions and 0 deletions

View File

@ -46,5 +46,6 @@ enum {
#define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03)
#define PPC_SERIAL_MM_BAUDBASE 399193

View File

@ -64,6 +64,7 @@
#include "loader.h"
#include "elf.h"
#include "kvm.h"
#include "kvm_ppc.h"
#define MAX_IDE_BUS 2
#define VGA_BIOS_SIZE 65536
@ -413,6 +414,14 @@ static void ppc_core99_init (ram_addr_t ram_size,
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
if (kvm_enabled()) {
#ifdef CONFIG_KVM
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
#endif
} else {
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
}
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}

View File

@ -40,6 +40,7 @@
#include "loader.h"
#include "elf.h"
#include "kvm.h"
#include "kvm_ppc.h"
#define MAX_IDE_BUS 2
#define VGA_BIOS_SIZE 65536
@ -401,6 +402,14 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
if (kvm_enabled()) {
#ifdef CONFIG_KVM
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
#endif
} else {
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
}
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}

View File

@ -252,3 +252,50 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
return ret;
}
static int read_cpuinfo(const char *field, char *value, int len)
{
FILE *f;
int ret = -1;
int field_len = strlen(field);
char line[512];
f = fopen("/proc/cpuinfo", "r");
if (!f) {
return -1;
}
do {
if(!fgets(line, sizeof(line), f)) {
break;
}
if (!strncmp(line, field, field_len)) {
strncpy(value, line, len);
ret = 0;
break;
}
} while(*line);
fclose(f);
return ret;
}
uint32_t kvmppc_get_tbfreq(void)
{
char line[512];
char *ns;
uint32_t retval = get_ticks_per_sec();
if (read_cpuinfo("timebase", line, sizeof(line))) {
return retval;
}
if (!(ns = strchr(line, ':'))) {
return retval;
}
ns++;
retval = atoi(ns);
return retval;
}

View File

@ -14,4 +14,6 @@ void kvmppc_fdt_update(void *fdt);
int kvmppc_read_host_property(const char *node_path, const char *prop,
void *val, size_t len);
uint32_t kvmppc_get_tbfreq(void);
#endif /* __KVM_PPC_H__ */