mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 09:43:56 -06:00
Patch queue for ppc - 2015-07-07
A few last minute PPC changes for 2.4: - spapr: Update SLOF - spapr: Fix a few bugs - spapr: Preparation for hotplug - spapr: Minor code cleanups - linux-user: Add mftb handling - kvm: Enable hugepage support with memory-backend-file - mac99: Remove nonexistent interrupt pin (Mac OS 9 fix) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJVm/TZAAoJECszeR4D/txg0rUP/R1C5IAuY0vM7LOYRbp1jFmn EO6AZpJaXvT2xP0wUd/rqJct/O41vDVbEmnhpUAQwZcgsyw1UaKhRQbnCtY9PHD2 d7NZiBdv3AAbh8pLFadRjDJr/HrfuWVfjKKep5cM87/o3zjVreeIX8Hs77xHia6/ 90n3hcDF4QL8qx6fxCMT4mGpTtbxw85IcK2wyIU45cZSN0VYaTjDwcYokeSKqgxV pi7UjZSM5nZcn7VI1Uray4NkgXGs92Lorrbg08OFQt0AoXROJOk4V/LX3HkHfDbI BYUgaOQNdBkytkB3fJCsTgl2Up82bVP/tghMyZOIyBAU4MslnAOW6HAMX2TtNswx 7itnIb7DQsVDE/U234Xzf5qoH5x4nB9xKh2qLHPKSpgLChs6lAW37Af3N+V03JVb k/WX6i0n70a6kUqCxcMTnVSINWandU2jdJ/S8woIqs6XhfLk7hh0ucg+VhgoQxW7 QpeD69c25eVHeZDoMKR/ZTigJg/EQGuV9B9OSx6SyA9WMS4dImt1m0PBdaUlIAFT 759lMMwQIb5sQYghJ63tgrOI5PBneGnelM1zDWt2SCS0rbSjLWIWP47pHoNmnzzp vIhJX5GgVuzf0NrbZPSR7/6NuKKU6UW5CTGh3vFgRib/CWIbEgCE3yWQfflZKy5q Q2xBuAjyWnBoipzI4hlz =+Uma -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging Patch queue for ppc - 2015-07-07 A few last minute PPC changes for 2.4: - spapr: Update SLOF - spapr: Fix a few bugs - spapr: Preparation for hotplug - spapr: Minor code cleanups - linux-user: Add mftb handling - kvm: Enable hugepage support with memory-backend-file - mac99: Remove nonexistent interrupt pin (Mac OS 9 fix) # gpg: Signature made Tue Jul 7 16:48:41 2015 BST using RSA key ID 03FEDC60 # gpg: Good signature from "Alexander Graf <agraf@suse.de>" # gpg: aka "Alexander Graf <alex@csgraf.de>" * remotes/agraf/tags/signed-ppc-for-upstream: (30 commits) sPAPR: Clear stale MSIx table during EEH reset sPAPR: Reenable EEH functionality on reboot sPAPR: Don't enable EEH on emulated PCI devices spapr-vty: Use TYPE_ definition instead of hardcoding spapr_vty: lookup should only return valid VTY objects spapr_pci: drop redundant args in spapr_[populate, create]_pci_child_dt spapr_pci: populate ibm,loc-code spapr_pci: enumerate and add PCI device tree xics_kvm: Don't enable KVM_CAP_IRQ_XICS if already enabled ppc: Update cpu_model in MachineState spapr: Consolidate cpu init code into a routine spapr: Reorganize CPU dt generation code cpus: Add a macro to walk CPUs in reverse spapr: Support ibm, lrdr-capacity device tree property spapr: Consider max_cpus during xics initialization Revert "hw/ppc/spapr_pci.c: Avoid functions not in glib 2.12 (g_hash_table_iter_*)" spapr_iommu: translate sPAPRTCEAccess to IOMMUAccessFlags spapr_iommu: drop erroneous check in h_put_tce_indirect() spapr_pci: set device node unit address as hex spapr_pci: encode class code including Prog IF register ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7ce0f7dc87
31 changed files with 836 additions and 411 deletions
450
hw/ppc/spapr.c
450
hw/ppc/spapr.c
|
@ -91,25 +91,6 @@
|
|||
|
||||
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
||||
|
||||
typedef struct sPAPRMachineState sPAPRMachineState;
|
||||
|
||||
#define TYPE_SPAPR_MACHINE "spapr-machine"
|
||||
#define SPAPR_MACHINE(obj) \
|
||||
OBJECT_CHECK(sPAPRMachineState, (obj), TYPE_SPAPR_MACHINE)
|
||||
|
||||
/**
|
||||
* sPAPRMachineState:
|
||||
*/
|
||||
struct sPAPRMachineState {
|
||||
/*< private >*/
|
||||
MachineState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
char *kvm_type;
|
||||
};
|
||||
|
||||
sPAPREnvironment *spapr;
|
||||
|
||||
static XICSState *try_create_xics(const char *type, int nr_servers,
|
||||
int nr_irqs, Error **errp)
|
||||
{
|
||||
|
@ -185,7 +166,28 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
||||
static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(cs->numa_node),
|
||||
cpu_to_be32(index)};
|
||||
|
||||
/* Advertise NUMA via ibm,associativity */
|
||||
if (nb_numa_nodes > 1) {
|
||||
ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
|
||||
sizeof(associativity));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
|
||||
{
|
||||
int ret = 0, offset, cpus_offset;
|
||||
CPUState *cs;
|
||||
|
@ -197,12 +199,6 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
|||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(cs->numa_node),
|
||||
cpu_to_be32(index)};
|
||||
|
||||
if ((index % smt) != 0) {
|
||||
continue;
|
||||
|
@ -226,20 +222,17 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ret = spapr_fixup_cpu_numa_dt(fdt, offset, cs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
|
||||
ppc_get_compat_smt_threads(cpu));
|
||||
if (ret < 0) {
|
||||
|
@ -285,15 +278,18 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
|
|||
|
||||
static hwaddr spapr_node0_size(void)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
if (nb_numa_nodes) {
|
||||
int i;
|
||||
for (i = 0; i < nb_numa_nodes; ++i) {
|
||||
if (numa_info[i].node_mem) {
|
||||
return MIN(pow2floor(numa_info[i].node_mem), ram_size);
|
||||
return MIN(pow2floor(numa_info[i].node_mem),
|
||||
machine->ram_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ram_size;
|
||||
return machine->ram_size;
|
||||
}
|
||||
|
||||
#define _FDT(exp) \
|
||||
|
@ -319,18 +315,13 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
|||
uint32_t epow_irq)
|
||||
{
|
||||
void *fdt;
|
||||
CPUState *cs;
|
||||
uint32_t start_prop = cpu_to_be32(initrd_base);
|
||||
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
||||
GString *hypertas = g_string_sized_new(256);
|
||||
GString *qemu_hypertas = g_string_sized_new(256);
|
||||
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
|
||||
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
|
||||
int smt = kvmppc_smt_threads();
|
||||
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(max_cpus)};
|
||||
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
|
||||
QemuOpts *opts = qemu_opts_find(qemu_find_opts("smp-opts"), NULL);
|
||||
unsigned sockets = opts ? qemu_opt_get_number(opts, "sockets", 0) : 0;
|
||||
uint32_t cpus_per_socket = sockets ? (smp_cpus / sockets) : 1;
|
||||
char *buf;
|
||||
|
||||
add_str(hypertas, "hcall-pft");
|
||||
|
@ -416,107 +407,6 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
|||
|
||||
_FDT((fdt_end_node(fdt)));
|
||||
|
||||
/* cpus */
|
||||
_FDT((fdt_begin_node(fdt, "cpus")));
|
||||
|
||||
_FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
|
||||
_FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
char *nodename;
|
||||
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
||||
0xffffffff, 0xffffffff};
|
||||
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
|
||||
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
||||
uint32_t page_sizes_prop[64];
|
||||
size_t page_sizes_prop_size;
|
||||
|
||||
if ((index % smt) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
|
||||
|
||||
_FDT((fdt_begin_node(fdt, nodename)));
|
||||
|
||||
g_free(nodename);
|
||||
|
||||
_FDT((fdt_property_cell(fdt, "reg", index)));
|
||||
_FDT((fdt_property_string(fdt, "device_type", "cpu")));
|
||||
|
||||
_FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
|
||||
_FDT((fdt_property_cell(fdt, "d-cache-block-size",
|
||||
env->dcache_line_size)));
|
||||
_FDT((fdt_property_cell(fdt, "d-cache-line-size",
|
||||
env->dcache_line_size)));
|
||||
_FDT((fdt_property_cell(fdt, "i-cache-block-size",
|
||||
env->icache_line_size)));
|
||||
_FDT((fdt_property_cell(fdt, "i-cache-line-size",
|
||||
env->icache_line_size)));
|
||||
|
||||
if (pcc->l1_dcache_size) {
|
||||
_FDT((fdt_property_cell(fdt, "d-cache-size", pcc->l1_dcache_size)));
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");
|
||||
}
|
||||
if (pcc->l1_icache_size) {
|
||||
_FDT((fdt_property_cell(fdt, "i-cache-size", pcc->l1_icache_size)));
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n");
|
||||
}
|
||||
|
||||
_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_string(fdt, "status", "okay")));
|
||||
_FDT((fdt_property(fdt, "64-bit", NULL, 0)));
|
||||
|
||||
if (env->spr_cb[SPR_PURR].oea_read) {
|
||||
_FDT((fdt_property(fdt, "ibm,purr", NULL, 0)));
|
||||
}
|
||||
|
||||
if (env->mmu_model & POWERPC_MMU_1TSEG) {
|
||||
_FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
|
||||
segs, sizeof(segs))));
|
||||
}
|
||||
|
||||
/* Advertise VMX/VSX (vector extensions) if available
|
||||
* 0 / no property == no vector extensions
|
||||
* 1 == VMX / Altivec available
|
||||
* 2 == VSX available */
|
||||
if (env->insns_flags & PPC_ALTIVEC) {
|
||||
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
|
||||
|
||||
_FDT((fdt_property_cell(fdt, "ibm,vmx", vmx)));
|
||||
}
|
||||
|
||||
/* Advertise DFP (Decimal Floating Point) if available
|
||||
* 0 / no property == no DFP
|
||||
* 1 == DFP available */
|
||||
if (env->insns_flags2 & PPC2_DFP) {
|
||||
_FDT((fdt_property_cell(fdt, "ibm,dfp", 1)));
|
||||
}
|
||||
|
||||
page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
|
||||
sizeof(page_sizes_prop));
|
||||
if (page_sizes_prop_size) {
|
||||
_FDT((fdt_property(fdt, "ibm,segment-page-sizes",
|
||||
page_sizes_prop, page_sizes_prop_size)));
|
||||
}
|
||||
|
||||
_FDT((fdt_property_cell(fdt, "ibm,chip-id",
|
||||
cs->cpu_index / cpus_per_socket)));
|
||||
|
||||
_FDT((fdt_end_node(fdt)));
|
||||
}
|
||||
|
||||
_FDT((fdt_end_node(fdt)));
|
||||
|
||||
/* RTAS */
|
||||
_FDT((fdt_begin_node(fdt, "rtas")));
|
||||
|
||||
|
@ -605,7 +495,8 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
|||
return fdt;
|
||||
}
|
||||
|
||||
int spapr_h_cas_compose_response(target_ulong addr, target_ulong size)
|
||||
int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
|
||||
target_ulong addr, target_ulong size)
|
||||
{
|
||||
void *fdt, *fdt_skel;
|
||||
sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
|
||||
|
@ -666,8 +557,9 @@ static void spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
|
|||
sizeof(associativity))));
|
||||
}
|
||||
|
||||
static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
||||
static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
|
||||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
hwaddr mem_start, node_size;
|
||||
int i, nb_nodes = nb_numa_nodes;
|
||||
NodeInfo *nodes = numa_info;
|
||||
|
@ -676,7 +568,7 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
|||
/* No NUMA nodes, assume there is just one node with whole RAM */
|
||||
if (!nb_numa_nodes) {
|
||||
nb_nodes = 1;
|
||||
ramnode.node_mem = ram_size;
|
||||
ramnode.node_mem = machine->ram_size;
|
||||
nodes = &ramnode;
|
||||
}
|
||||
|
||||
|
@ -684,12 +576,12 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
|||
if (!nodes[i].node_mem) {
|
||||
continue;
|
||||
}
|
||||
if (mem_start >= ram_size) {
|
||||
if (mem_start >= machine->ram_size) {
|
||||
node_size = 0;
|
||||
} else {
|
||||
node_size = nodes[i].node_mem;
|
||||
if (node_size > ram_size - mem_start) {
|
||||
node_size = ram_size - mem_start;
|
||||
if (node_size > machine->ram_size - mem_start) {
|
||||
node_size = machine->ram_size - mem_start;
|
||||
}
|
||||
}
|
||||
if (!mem_start) {
|
||||
|
@ -715,7 +607,138 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
||||
static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||
sPAPRMachineState *spapr)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
||||
0xffffffff, 0xffffffff};
|
||||
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
|
||||
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
||||
uint32_t page_sizes_prop[64];
|
||||
size_t page_sizes_prop_size;
|
||||
QemuOpts *opts = qemu_opts_find(qemu_find_opts("smp-opts"), NULL);
|
||||
unsigned sockets = opts ? qemu_opt_get_number(opts, "sockets", 0) : 0;
|
||||
uint32_t cpus_per_socket = sockets ? (smp_cpus / sockets) : 1;
|
||||
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
|
||||
_FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
|
||||
env->dcache_line_size)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
|
||||
env->dcache_line_size)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
|
||||
env->icache_line_size)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
|
||||
env->icache_line_size)));
|
||||
|
||||
if (pcc->l1_dcache_size) {
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
|
||||
pcc->l1_dcache_size)));
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");
|
||||
}
|
||||
if (pcc->l1_icache_size) {
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
|
||||
pcc->l1_icache_size)));
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n");
|
||||
}
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
|
||||
_FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
|
||||
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
|
||||
|
||||
if (env->spr_cb[SPR_PURR].oea_read) {
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
|
||||
}
|
||||
|
||||
if (env->mmu_model & POWERPC_MMU_1TSEG) {
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
|
||||
segs, sizeof(segs))));
|
||||
}
|
||||
|
||||
/* Advertise VMX/VSX (vector extensions) if available
|
||||
* 0 / no property == no vector extensions
|
||||
* 1 == VMX / Altivec available
|
||||
* 2 == VSX available */
|
||||
if (env->insns_flags & PPC_ALTIVEC) {
|
||||
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
|
||||
}
|
||||
|
||||
/* Advertise DFP (Decimal Floating Point) if available
|
||||
* 0 / no property == no DFP
|
||||
* 1 == DFP available */
|
||||
if (env->insns_flags2 & PPC2_DFP) {
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
|
||||
}
|
||||
|
||||
page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
|
||||
sizeof(page_sizes_prop));
|
||||
if (page_sizes_prop_size) {
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
|
||||
page_sizes_prop, page_sizes_prop_size)));
|
||||
}
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
|
||||
cs->cpu_index / cpus_per_socket)));
|
||||
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
|
||||
pft_size_prop, sizeof(pft_size_prop))));
|
||||
|
||||
_FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
|
||||
|
||||
_FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
|
||||
ppc_get_compat_smt_threads(cpu)));
|
||||
}
|
||||
|
||||
static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
|
||||
{
|
||||
CPUState *cs;
|
||||
int cpus_offset;
|
||||
char *nodename;
|
||||
int smt = kvmppc_smt_threads();
|
||||
|
||||
cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
|
||||
_FDT(cpus_offset);
|
||||
_FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
|
||||
_FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
|
||||
|
||||
/*
|
||||
* We walk the CPUs in reverse order to ensure that CPU DT nodes
|
||||
* created by fdt_add_subnode() end up in the right order in FDT
|
||||
* for the guest kernel the enumerate the CPUs correctly.
|
||||
*/
|
||||
CPU_FOREACH_REVERSE(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
int offset;
|
||||
|
||||
if ((index % smt) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
|
||||
offset = fdt_add_subnode(fdt, cpus_offset, nodename);
|
||||
g_free(nodename);
|
||||
_FDT(offset);
|
||||
spapr_populate_cpu_dt(cs, fdt, offset, spapr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||
hwaddr fdt_addr,
|
||||
hwaddr rtas_addr,
|
||||
hwaddr rtas_size)
|
||||
|
@ -760,11 +783,8 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
|||
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
||||
}
|
||||
|
||||
/* Advertise NUMA via ibm,associativity */
|
||||
ret = spapr_fixup_cpu_dt(fdt, spapr);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
|
||||
}
|
||||
/* cpus */
|
||||
spapr_populate_cpus_dt_node(fdt, spapr);
|
||||
|
||||
bootlist = get_boot_devices_list(&cb, true);
|
||||
if (cb && bootlist) {
|
||||
|
@ -831,7 +851,7 @@ static void emulate_spapr_hypercall(PowerPCCPU *cpu)
|
|||
#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
|
||||
#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
|
||||
|
||||
static void spapr_reset_htab(sPAPREnvironment *spapr)
|
||||
static void spapr_reset_htab(sPAPRMachineState *spapr)
|
||||
{
|
||||
long shift;
|
||||
int index;
|
||||
|
@ -893,7 +913,7 @@ static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
|||
* A guest reset will cause spapr->htab_fd to become stale if being used.
|
||||
* Reopen the file descriptor to make sure the whole HTAB is properly read.
|
||||
*/
|
||||
static int spapr_check_htab_fd(sPAPREnvironment *spapr)
|
||||
static int spapr_check_htab_fd(sPAPRMachineState *spapr)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
|
@ -913,6 +933,7 @@ static int spapr_check_htab_fd(sPAPREnvironment *spapr)
|
|||
|
||||
static void ppc_spapr_reset(void)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
PowerPCCPU *first_ppc_cpu;
|
||||
uint32_t rtas_limit;
|
||||
|
||||
|
@ -946,12 +967,13 @@ static void ppc_spapr_reset(void)
|
|||
first_ppc_cpu->env.gpr[3] = spapr->fdt_addr;
|
||||
first_ppc_cpu->env.gpr[5] = 0;
|
||||
first_cpu->halted = 0;
|
||||
first_ppc_cpu->env.nip = spapr->entry_point;
|
||||
first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT;
|
||||
|
||||
}
|
||||
|
||||
static void spapr_cpu_reset(void *opaque)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
@ -980,12 +1002,12 @@ static void spapr_cpu_reset(void *opaque)
|
|||
* We have 8 hpte per group, and each hpte is 16 bytes.
|
||||
* ie have 128 bytes per hpte entry.
|
||||
*/
|
||||
env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
|
||||
env->htab_mask = (1ULL << (spapr->htab_shift - 7)) - 1;
|
||||
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
|
||||
(spapr->htab_shift - 18);
|
||||
}
|
||||
|
||||
static void spapr_create_nvram(sPAPREnvironment *spapr)
|
||||
static void spapr_create_nvram(sPAPRMachineState *spapr)
|
||||
{
|
||||
DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
|
||||
DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
|
@ -999,7 +1021,7 @@ static void spapr_create_nvram(sPAPREnvironment *spapr)
|
|||
spapr->nvram = (struct sPAPRNVRAM *)dev;
|
||||
}
|
||||
|
||||
static void spapr_rtc_create(sPAPREnvironment *spapr)
|
||||
static void spapr_rtc_create(sPAPRMachineState *spapr)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_SPAPR_RTC);
|
||||
|
||||
|
@ -1029,7 +1051,7 @@ static int spapr_vga_init(PCIBus *pci_bus)
|
|||
|
||||
static int spapr_post_load(void *opaque, int version_id)
|
||||
{
|
||||
sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
|
||||
sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
|
||||
int err = 0;
|
||||
|
||||
/* In earlier versions, there was no separate qdev for the PAPR
|
||||
|
@ -1058,16 +1080,16 @@ static const VMStateDescription vmstate_spapr = {
|
|||
VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
|
||||
|
||||
/* RTC offset */
|
||||
VMSTATE_UINT64_TEST(rtc_offset, sPAPREnvironment, version_before_3),
|
||||
VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3),
|
||||
|
||||
VMSTATE_PPC_TIMEBASE_V(tb, sPAPREnvironment, 2),
|
||||
VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static int htab_save_setup(QEMUFile *f, void *opaque)
|
||||
{
|
||||
sPAPREnvironment *spapr = opaque;
|
||||
sPAPRMachineState *spapr = opaque;
|
||||
|
||||
/* "Iteration" header */
|
||||
qemu_put_be32(f, spapr->htab_shift);
|
||||
|
@ -1091,7 +1113,7 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
||||
static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||
int64_t max_ns)
|
||||
{
|
||||
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
|
||||
|
@ -1141,7 +1163,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
|||
spapr->htab_save_index = index;
|
||||
}
|
||||
|
||||
static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
||||
static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||
int64_t max_ns)
|
||||
{
|
||||
bool final = max_ns < 0;
|
||||
|
@ -1223,7 +1245,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
|||
|
||||
static int htab_save_iterate(QEMUFile *f, void *opaque)
|
||||
{
|
||||
sPAPREnvironment *spapr = opaque;
|
||||
sPAPRMachineState *spapr = opaque;
|
||||
int rc = 0;
|
||||
|
||||
/* Iteration header */
|
||||
|
@ -1258,7 +1280,7 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
|
|||
|
||||
static int htab_save_complete(QEMUFile *f, void *opaque)
|
||||
{
|
||||
sPAPREnvironment *spapr = opaque;
|
||||
sPAPRMachineState *spapr = opaque;
|
||||
|
||||
/* Iteration header */
|
||||
qemu_put_be32(f, 0);
|
||||
|
@ -1293,7 +1315,7 @@ static int htab_save_complete(QEMUFile *f, void *opaque)
|
|||
|
||||
static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
sPAPREnvironment *spapr = opaque;
|
||||
sPAPRMachineState *spapr = opaque;
|
||||
uint32_t section_hdr;
|
||||
int fd = -1;
|
||||
|
||||
|
@ -1387,16 +1409,42 @@ static void spapr_boot_set(void *opaque, const char *boot_device,
|
|||
machine->boot_order = g_strdup(boot_device);
|
||||
}
|
||||
|
||||
static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
/* Set time-base frequency to 512 MHz */
|
||||
cpu_ppc_tb_init(env, TIMEBASE_FREQ);
|
||||
|
||||
/* PAPR always has exception vectors in RAM not ROM. To ensure this,
|
||||
* MSR[IP] should never be set.
|
||||
*/
|
||||
env->msr_mask &= ~(1 << 6);
|
||||
|
||||
/* Tell KVM that we're in PAPR mode */
|
||||
if (kvm_enabled()) {
|
||||
kvmppc_set_papr(cpu);
|
||||
}
|
||||
|
||||
if (cpu->max_compat) {
|
||||
if (ppc_set_compat(cpu, cpu->max_compat) < 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
xics_cpu_setup(spapr->icp, cpu);
|
||||
|
||||
qemu_register_reset(spapr_cpu_reset, cpu);
|
||||
}
|
||||
|
||||
/* pSeries LPAR / sPAPR hardware init */
|
||||
static void ppc_spapr_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
PCIHostState *phb;
|
||||
int i;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
|
@ -1413,7 +1461,6 @@ static void ppc_spapr_init(MachineState *machine)
|
|||
|
||||
msi_supported = true;
|
||||
|
||||
spapr = g_malloc0(sizeof(*spapr));
|
||||
QLIST_INIT(&spapr->phbs);
|
||||
|
||||
cpu_ppc_hypercall = emulate_spapr_hypercall;
|
||||
|
@ -1460,7 +1507,7 @@ static void ppc_spapr_init(MachineState *machine)
|
|||
* 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) {
|
||||
if ((1ULL << (spapr->htab_shift + 7)) >= machine->ram_size) {
|
||||
break;
|
||||
}
|
||||
spapr->htab_shift++;
|
||||
|
@ -1468,43 +1515,21 @@ static void ppc_spapr_init(MachineState *machine)
|
|||
|
||||
/* Set up Interrupt Controller before we create the VCPUs */
|
||||
spapr->icp = xics_system_init(machine,
|
||||
smp_cpus * kvmppc_smt_threads() / smp_threads,
|
||||
DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(),
|
||||
smp_threads),
|
||||
XICS_IRQS);
|
||||
|
||||
/* init CPUs */
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = kvm_enabled() ? "host" : "POWER7";
|
||||
if (machine->cpu_model == NULL) {
|
||||
machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
|
||||
}
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
cpu = cpu_ppc_init(cpu_model);
|
||||
cpu = cpu_ppc_init(machine->cpu_model);
|
||||
if (cpu == NULL) {
|
||||
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
env = &cpu->env;
|
||||
|
||||
/* Set time-base frequency to 512 MHz */
|
||||
cpu_ppc_tb_init(env, TIMEBASE_FREQ);
|
||||
|
||||
/* PAPR always has exception vectors in RAM not ROM. To ensure this,
|
||||
* MSR[IP] should never be set.
|
||||
*/
|
||||
env->msr_mask &= ~(1 << 6);
|
||||
|
||||
/* Tell KVM that we're in PAPR mode */
|
||||
if (kvm_enabled()) {
|
||||
kvmppc_set_papr(cpu);
|
||||
}
|
||||
|
||||
if (cpu->max_compat) {
|
||||
if (ppc_set_compat(cpu, cpu->max_compat) < 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
xics_cpu_setup(spapr->icp, cpu);
|
||||
|
||||
qemu_register_reset(spapr_cpu_reset, cpu);
|
||||
spapr_cpu_init(spapr, cpu);
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
|
@ -1513,9 +1538,8 @@ static void ppc_spapr_init(MachineState *machine)
|
|||
}
|
||||
|
||||
/* allocate RAM */
|
||||
spapr->ram_limit = ram_size;
|
||||
memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
|
||||
spapr->ram_limit);
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(sysmem, 0, ram);
|
||||
|
||||
if (rma_alloc_size && rma) {
|
||||
|
@ -1659,8 +1683,9 @@ static void ppc_spapr_init(MachineState *machine)
|
|||
}
|
||||
g_free(filename);
|
||||
|
||||
spapr->entry_point = 0x100;
|
||||
|
||||
/* FIXME: Should register things through the MachineState's qdev
|
||||
* interface, this is a legacy from the sPAPREnvironment structure
|
||||
* which predated MachineState but had a similar function */
|
||||
vmstate_register(NULL, 0, &vmstate_spapr, spapr);
|
||||
register_savevm_live(NULL, "spapr/htab", -1, 1,
|
||||
&savevm_htab_handlers, spapr);
|
||||
|
@ -1756,17 +1781,17 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
|||
|
||||
static char *spapr_get_kvm_type(Object *obj, Error **errp)
|
||||
{
|
||||
sPAPRMachineState *sm = SPAPR_MACHINE(obj);
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
|
||||
return g_strdup(sm->kvm_type);
|
||||
return g_strdup(spapr->kvm_type);
|
||||
}
|
||||
|
||||
static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
sPAPRMachineState *sm = SPAPR_MACHINE(obj);
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
|
||||
g_free(sm->kvm_type);
|
||||
sm->kvm_type = g_strdup(value);
|
||||
g_free(spapr->kvm_type);
|
||||
spapr->kvm_type = g_strdup(value);
|
||||
}
|
||||
|
||||
static void spapr_machine_initfn(Object *obj)
|
||||
|
@ -1821,6 +1846,7 @@ static const TypeInfo spapr_machine_info = {
|
|||
.abstract = true,
|
||||
.instance_size = sizeof(sPAPRMachineState),
|
||||
.instance_init = spapr_machine_initfn,
|
||||
.class_size = sizeof(sPAPRMachineClass),
|
||||
.class_init = spapr_machine_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_FW_PATH_PROVIDER },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue