#include "kvm.h"
#include "kvm_ppc.h"
#include "pci.h"
-#include "vga-pci.h"
#include "exec-memory.h"
#include "hw/usb.h"
#define PHANDLE_XICP 0x00001111
+ #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
+
sPAPREnvironment *spapr;
- int spapr_allocate_irq(int hint, enum xics_irq_type type)
+ int spapr_allocate_irq(int hint, bool lsi)
{
int irq;
return 0;
}
- xics_set_irq_type(spapr->icp, irq, type);
+ xics_set_irq_type(spapr->icp, irq, lsi);
return irq;
}
/* Allocate block of consequtive IRQs, returns a number of the first */
- int spapr_allocate_irq_block(int num, enum xics_irq_type type)
+ int spapr_allocate_irq_block(int num, bool lsi)
{
int first = -1;
int i;
for (i = 0; i < num; ++i) {
int irq;
- irq = spapr_allocate_irq(0, type);
+ irq = spapr_allocate_irq(0, lsi);
if (!irq) {
return -1;
}
return first;
}
- static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
+ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
{
int ret = 0, offset;
CPUPPCState *env;
char cpu_model[32];
int smt = kvmppc_smt_threads();
+ uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
assert(spapr->cpu_model);
return offset;
}
- ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
- sizeof(associativity));
+ if (nb_numa_nodes > 1) {
+ ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
+ sizeof(associativity));
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ ret = fdt_setprop(fdt, offset, "ibm,pft-size",
+ pft_size_prop, sizeof(pft_size_prop));
if (ret < 0) {
return ret;
}
return (p - prop) * sizeof(uint32_t);
}
+ #define _FDT(exp) \
+ do { \
+ int ret = (exp); \
+ if (ret < 0) { \
+ fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
+ #exp, fdt_strerror(ret)); \
+ exit(1); \
+ } \
+ } while (0)
+
+
static void *spapr_create_fdt_skel(const char *cpu_model,
- target_phys_addr_t rma_size,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
target_phys_addr_t kernel_size,
const char *boot_device,
- const char *kernel_cmdline,
- long hash_shift)
+ const char *kernel_cmdline)
{
void *fdt;
CPUPPCState *env;
- uint64_t mem_reg_property[2];
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
- uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
"\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
char qemu_hypertas_prop[] = "hcall-memop1";
+ uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
- int i;
char *modelname;
- int smt = kvmppc_smt_threads();
+ int i, smt = kvmppc_smt_threads();
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
- uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
- uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
- cpu_to_be32(0x0), cpu_to_be32(0x0),
- cpu_to_be32(0x0)};
- char mem_name[32];
- target_phys_addr_t node0_size, mem_start;
-
- #define _FDT(exp) \
- do { \
- int ret = (exp); \
- if (ret < 0) { \
- fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
- #exp, fdt_strerror(ret)); \
- exit(1); \
- } \
- } while (0)
fdt = g_malloc0(FDT_MAX_SIZE);
_FDT((fdt_create(fdt, FDT_MAX_SIZE)));
_FDT((fdt_end_node(fdt)));
- /* memory node(s) */
- node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
- if (rma_size > node0_size) {
- rma_size = node0_size;
- }
-
- /* RMA */
- mem_reg_property[0] = 0;
- mem_reg_property[1] = cpu_to_be64(rma_size);
- _FDT((fdt_begin_node(fdt, "memory@0")));
- _FDT((fdt_property_string(fdt, "device_type", "memory")));
- _FDT((fdt_property(fdt, "reg", mem_reg_property,
- sizeof(mem_reg_property))));
- _FDT((fdt_property(fdt, "ibm,associativity", associativity,
- sizeof(associativity))));
- _FDT((fdt_end_node(fdt)));
-
- /* RAM: Node 0 */
- if (node0_size > rma_size) {
- mem_reg_property[0] = cpu_to_be64(rma_size);
- mem_reg_property[1] = cpu_to_be64(node0_size - rma_size);
-
- sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size);
- _FDT((fdt_begin_node(fdt, mem_name)));
- _FDT((fdt_property_string(fdt, "device_type", "memory")));
- _FDT((fdt_property(fdt, "reg", mem_reg_property,
- sizeof(mem_reg_property))));
- _FDT((fdt_property(fdt, "ibm,associativity", associativity,
- sizeof(associativity))));
- _FDT((fdt_end_node(fdt)));
- }
-
- /* RAM: Node 1 and beyond */
- mem_start = node0_size;
- for (i = 1; i < nb_numa_nodes; i++) {
- mem_reg_property[0] = cpu_to_be64(mem_start);
- mem_reg_property[1] = cpu_to_be64(node_mem[i]);
- associativity[3] = associativity[4] = cpu_to_be32(i);
- sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);
- _FDT((fdt_begin_node(fdt, mem_name)));
- _FDT((fdt_property_string(fdt, "device_type", "memory")));
- _FDT((fdt_property(fdt, "reg", mem_reg_property,
- sizeof(mem_reg_property))));
- _FDT((fdt_property(fdt, "ibm,associativity", associativity,
- sizeof(associativity))));
- _FDT((fdt_end_node(fdt)));
- mem_start += node_mem[i];
- }
-
/* cpus */
_FDT((fdt_begin_node(fdt, "cpus")));
_FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq)));
_FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq)));
_FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
- _FDT((fdt_property(fdt, "ibm,pft-size",
- pft_size_prop, sizeof(pft_size_prop))));
_FDT((fdt_property_string(fdt, "status", "okay")));
_FDT((fdt_property(fdt, "64-bit", NULL, 0)));
return fdt;
}
+ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
+ {
+ uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
+ cpu_to_be32(0x0), cpu_to_be32(0x0),
+ cpu_to_be32(0x0)};
+ char mem_name[32];
+ target_phys_addr_t node0_size, mem_start;
+ uint64_t mem_reg_property[2];
+ int i, off;
+
+ /* memory node(s) */
+ node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
+ if (spapr->rma_size > node0_size) {
+ spapr->rma_size = node0_size;
+ }
+
+ /* RMA */
+ mem_reg_property[0] = 0;
+ mem_reg_property[1] = cpu_to_be64(spapr->rma_size);
+ off = fdt_add_subnode(fdt, 0, "memory@0");
+ _FDT(off);
+ _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
+ _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
+ sizeof(mem_reg_property))));
+ _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
+ sizeof(associativity))));
+
+ /* RAM: Node 0 */
+ if (node0_size > spapr->rma_size) {
+ mem_reg_property[0] = cpu_to_be64(spapr->rma_size);
+ mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size);
+
+ sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size);
+ off = fdt_add_subnode(fdt, 0, mem_name);
+ _FDT(off);
+ _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
+ _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
+ sizeof(mem_reg_property))));
+ _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
+ sizeof(associativity))));
+ }
+
+ /* RAM: Node 1 and beyond */
+ mem_start = node0_size;
+ for (i = 1; i < nb_numa_nodes; i++) {
+ mem_reg_property[0] = cpu_to_be64(mem_start);
+ mem_reg_property[1] = cpu_to_be64(node_mem[i]);
+ associativity[3] = associativity[4] = cpu_to_be32(i);
+ sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);
+ off = fdt_add_subnode(fdt, 0, mem_name);
+ _FDT(off);
+ _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
+ _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
+ sizeof(mem_reg_property))));
+ _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
+ sizeof(associativity))));
+ mem_start += node_mem[i];
+ }
+
+ return 0;
+ }
+
static void spapr_finalize_fdt(sPAPREnvironment *spapr,
target_phys_addr_t fdt_addr,
target_phys_addr_t rtas_addr,
/* open out the base tree into a temp buffer for the final tweaks */
_FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
+ ret = spapr_populate_memory(spapr, fdt);
+ if (ret < 0) {
+ fprintf(stderr, "couldn't setup memory nodes in fdt\n");
+ exit(1);
+ }
+
ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
if (ret < 0) {
fprintf(stderr, "couldn't setup vio devices in fdt\n");
}
/* Advertise NUMA via ibm,associativity */
- if (nb_numa_nodes > 1) {
- ret = spapr_set_associativity(fdt, spapr);
- if (ret < 0) {
- fprintf(stderr, "Couldn't set up NUMA device tree properties\n");
- }
+ ret = spapr_fixup_cpu_dt(fdt, spapr);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
}
if (!spapr->has_graphics) {
static void emulate_spapr_hypercall(CPUPPCState *env)
{
- env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
+ if (msr_pr) {
+ hcall_dprintf("Hypercall made with MSR[PR]=1\n");
+ env->gpr[3] = H_PRIVILEGE;
+ } else {
+ env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
+ }
+ }
+
+ static void spapr_reset_htab(sPAPREnvironment *spapr)
+ {
+ long shift;
+
+ /* allocate hash page table. For now we always make this 16mb,
+ * later we should probably make it scale to the size of guest
+ * RAM */
+
+ shift = kvmppc_reset_htab(spapr->htab_shift);
+
+ if (shift > 0) {
+ /* Kernel handles htab, we don't need to allocate one */
+ spapr->htab_shift = shift;
+ } else {
+ if (!spapr->htab) {
+ /* Allocate an htab if we don't yet have one */
+ spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr));
+ }
+
+ /* And clear it */
+ memset(spapr->htab, 0, HTAB_SIZE(spapr));
+ }
+
+ /* Update the RMA size if necessary */
+ if (spapr->vrma_adjust) {
+ spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift);
+ }
}
- static void spapr_reset(void *opaque)
+ static void ppc_spapr_reset(void)
{
- sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
+ /* Reset the hash table & recalc the RMA */
+ spapr_reset_htab(spapr);
- /* flush out the hash table */
- memset(spapr->htab, 0, spapr->htab_size);
+ qemu_devices_reset();
/* Load the fdt */
spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
static void spapr_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
+ CPUPPCState *env = &cpu->env;
cpu_reset(CPU(cpu));
+
+ /* All CPUs start halted. CPU0 is unhalted from the machine level
+ * reset code and the rest are explicitly started up by the guest
+ * using an RTAS call */
+ env->halted = 1;
+
+ env->spr[SPR_HIOR] = 0;
+
+ env->external_htab = spapr->htab;
+ env->htab_base = -1;
+ env->htab_mask = HTAB_SIZE(spapr) - 1;
+ env->spr[SPR_SDR1] = (unsigned long)spapr->htab |
+ (spapr->htab_shift - 18);
}
/* Returns whether we want to use VGA or not */
static int spapr_vga_init(PCIBus *pci_bus)
{
switch (vga_interface_type) {
- case VGA_STD:
- pci_vga_init(pci_bus);
- return 1;
case VGA_NONE:
- return 0;
+ case VGA_STD:
+ return pci_vga_init(pci_bus) != NULL;
default:
fprintf(stderr, "This vga model is not supported,"
"currently it only supports -vga std\n");
int i;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
- target_phys_addr_t rma_alloc_size, rma_size;
+ target_phys_addr_t rma_alloc_size;
uint32_t initrd_base = 0;
long kernel_size = 0, initrd_size = 0;
long load_limit, rtas_limit, fw_size;
- long pteg_shift = 17;
char *filename;
msi_supported = true;
hw_error("qemu: Unable to create RMA\n");
exit(1);
}
+
if (rma_alloc_size && (rma_alloc_size < ram_size)) {
- rma_size = rma_alloc_size;
+ spapr->rma_size = rma_alloc_size;
} else {
- rma_size = ram_size;
+ spapr->rma_size = ram_size;
+
+ /* With KVM, we don't actually know whether KVM supports an
+ * unbounded RMA (PR KVM) or is limited by the hash table size
+ * (HV KVM using VRMA), so we always assume the latter
+ *
+ * In that case, we also limit the initial allocations for RTAS
+ * etc... to 256M since we have no way to know what the VRMA size
+ * is going to be as it depends on the size of the hash table
+ * isn't determined yet.
+ */
+ if (kvm_enabled()) {
+ spapr->vrma_adjust = 1;
+ spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
+ }
}
/* We place the device tree and RTAS just below either the top of the RMA,
* or just below 2GB, whichever is lowere, so that it can be
* processed with 32-bit real mode code if necessary */
- rtas_limit = MIN(rma_size, 0x80000000);
+ rtas_limit = MIN(spapr->rma_size, 0x80000000);
spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
load_limit = spapr->fdt_addr - FW_OVERHEAD;
+ /* We aim for a hash table of size 1/128 the size of RAM. The
+ * normal rule of thumb is 1/64 the size of RAM, but that's much
+ * more than needed for the Linux guests we support. */
+ spapr->htab_shift = 18; /* Minimum architected size */
+ while (spapr->htab_shift <= 46) {
+ if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) {
+ break;
+ }
+ spapr->htab_shift++;
+ }
+
/* init CPUs */
if (cpu_model == NULL) {
cpu_model = kvm_enabled() ? "host" : "POWER7";
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, TIMEBASE_FREQ);
- qemu_register_reset(spapr_cpu_reset, cpu);
- env->hreset_vector = 0x60;
+ /* PAPR always has exception vectors in RAM not ROM */
env->hreset_excp_prefix = 0;
- env->gpr[3] = env->cpu_index;
+
+ /* Tell KVM that we're in PAPR mode */
+ if (kvm_enabled()) {
+ kvmppc_set_papr(env);
+ }
+
+ qemu_register_reset(spapr_cpu_reset, cpu);
}
/* allocate RAM */
memory_region_add_subregion(sysmem, nonrma_base, ram);
}
- /* allocate hash page table. For now we always make this 16mb,
- * later we should probably make it scale to the size of guest
- * RAM */
- spapr->htab_size = 1ULL << (pteg_shift + 7);
- spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size);
-
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- env->external_htab = spapr->htab;
- env->htab_base = -1;
- env->htab_mask = spapr->htab_size - 1;
-
- /* Tell KVM that we're in PAPR mode */
- env->spr[SPR_SDR1] = (unsigned long)spapr->htab |
- ((pteg_shift + 7) - 18);
- env->spr[SPR_HIOR] = 0;
-
- if (kvm_enabled()) {
- kvmppc_set_papr(env);
- }
- }
-
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
rtas_limit - spapr->rtas_addr);
}
}
- if (rma_size < (MIN_RMA_SLOF << 20)) {
+ if (spapr->rma_size < (MIN_RMA_SLOF << 20)) {
fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
"%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
exit(1);
spapr->entry_point = 0x100;
- /* SLOF will startup the secondary CPUs using RTAS */
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- env->halted = 1;
- }
-
/* Prepare the device tree */
- spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size,
+ spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
initrd_base, initrd_size,
kernel_size,
- boot_device, kernel_cmdline,
- pteg_shift + 7);
+ boot_device, kernel_cmdline);
assert(spapr->fdt_skel != NULL);
-
- qemu_register_reset(spapr_reset, spapr);
}
static QEMUMachine spapr_machine = {
.name = "pseries",
.desc = "pSeries Logical Partition (PAPR compliant)",
.init = ppc_spapr_init,
+ .reset = ppc_spapr_reset,
.max_cpus = MAX_CPUS,
.no_parallel = 1,
.use_scsi = 1,
static int cap_ppc_smt;
static int cap_ppc_rma;
static int cap_spapr_tce;
+ static int cap_hior;
/* XXX We have a race condition where we actually have a level triggered
* interrupt, but the infrastructure can't expose that yet, so the guest
cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT);
cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
+ cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
if (!cap_interrupt_level) {
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
env->tlb_dirty = false;
}
+ if (cap_segstate && (level >= KVM_PUT_RESET_STATE)) {
+ struct kvm_sregs sregs;
+
+ sregs.pvr = env->spr[SPR_PVR];
+
+ sregs.u.s.sdr1 = env->spr[SPR_SDR1];
+
+ /* Sync SLB */
+ #ifdef TARGET_PPC64
+ for (i = 0; i < 64; i++) {
+ sregs.u.s.ppc64.slb[i].slbe = env->slb[i].esid;
+ sregs.u.s.ppc64.slb[i].slbv = env->slb[i].vsid;
+ }
+ #endif
+
+ /* Sync SRs */
+ for (i = 0; i < 16; i++) {
+ sregs.u.s.ppc32.sr[i] = env->sr[i];
+ }
+
+ /* Sync BATs */
+ for (i = 0; i < 8; i++) {
+ /* Beware. We have to swap upper and lower bits here */
+ sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[0][i] << 32)
+ | env->DBAT[1][i];
+ sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[0][i] << 32)
+ | env->IBAT[1][i];
+ }
+
+ ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ if (cap_hior && (level >= KVM_PUT_RESET_STATE)) {
+ uint64_t hior = env->spr[SPR_HIOR];
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_HIOR,
+ .addr = (uintptr_t) &hior,
+ };
+
+ ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ }
+
return ret;
}
break;
}
if (!strncmp(line, field, field_len)) {
- strncpy(value, line, len);
+ pstrcpy(value, len, line);
ret = 0;
break;
}
void kvmppc_set_papr(CPUPPCState *env)
{
struct kvm_enable_cap cap = {};
- struct kvm_one_reg reg = {};
- struct kvm_sregs sregs = {};
int ret;
- uint64_t hior = env->spr[SPR_HIOR];
cap.cap = KVM_CAP_PPC_PAPR;
ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap);
if (ret) {
- goto fail;
- }
-
- /*
- * XXX We set HIOR here. It really should be a qdev property of
- * the CPU node, but we don't have CPUs converted to qdev yet.
- *
- * Once we have qdev CPUs, move HIOR to a qdev property and
- * remove this chunk.
- */
- reg.id = KVM_REG_PPC_HIOR;
- reg.addr = (uintptr_t)&hior;
- ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®);
- if (ret) {
- fprintf(stderr, "Couldn't set HIOR. Maybe you're running an old \n"
- "kernel with support for HV KVM but no PAPR PR \n"
- "KVM in which case things will work. If they don't \n"
- "please update your host kernel!\n");
- }
-
- /* Set SDR1 so kernel space finds the HTAB */
- ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
- if (ret) {
- goto fail;
+ cpu_abort(env, "This KVM version does not support PAPR\n");
}
-
- sregs.u.s.sdr1 = env->spr[SPR_SDR1];
-
- ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs);
- if (ret) {
- goto fail;
- }
-
- return;
-
- fail:
- cpu_abort(env, "This KVM version does not support PAPR\n");
}
int kvmppc_smt_threads(void)
return cap_ppc_smt ? cap_ppc_smt : 1;
}
+ #ifdef TARGET_PPC64
off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
{
void *rma;
return size;
}
+ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
+ {
+ if (cap_ppc_rma >= 2) {
+ return current_size;
+ }
+ return MIN(current_size,
+ getrampagesize() << (hash_shift - 7));
+ }
+ #endif
+
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
{
struct kvm_create_spapr_tce args = {
return 0;
}
+ int kvmppc_reset_htab(int shift_hint)
+ {
+ uint32_t shift = shift_hint;
+
+ if (!kvm_enabled()) {
+ /* Full emulation, tell caller to allocate htab itself */
+ return 0;
+ }
+ if (kvm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) {
+ int ret;
+ ret = kvm_vm_ioctl(kvm_state, KVM_PPC_ALLOCATE_HTAB, &shift);
+ if (ret == -ENOTTY) {
+ /* At least some versions of PR KVM advertise the
+ * capability, but don't implement the ioctl(). Oops.
+ * Return 0 so that we allocate the htab in qemu, as is
+ * correct for PR. */
+ return 0;
+ } else if (ret < 0) {
+ return ret;
+ }
+ return shift;
+ }
+
+ /* We have a kernel that predates the htab reset calls. For PR
+ * KVM, we need to allocate the htab ourselves, for an HV KVM of
+ * this era, it has allocated a 16MB fixed size hash table
+ * already. Kernels of this era have the GET_PVINFO capability
+ * only on PR, so we use this hack to determine the right
+ * answer */
+ if (kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_PVINFO)) {
+ /* PR - tell caller to allocate htab */
+ return 0;
+ } else {
+ /* HV - assume 16MB kernel allocated htab */
+ return 24;
+ }
+ }
+
static inline uint32_t mfpvr(void)
{
uint32_t pvr;