sPAPR Patch Queue: 2015-09-23
Highlights: * pseries-2.5 machine type * Memory hotplug for "pseries" guests * Fixes to the PAPR Dynamic Reconfiguration hotplug code * Several PAPR compliance fixes * New SLOF with: * GPT support * Much faster VGA handling -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAlYCBVIACgkQaILKxv3ab8YyMQCfdQhq52YNHotvL9ZUgE5iQsJ0 drYAmQGzSDBr/VaaSwkaLASkDnGKyCLV =3ZcM -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgibson/tags/spapr-next-20150923' into staging sPAPR Patch Queue: 2015-09-23 Highlights: * pseries-2.5 machine type * Memory hotplug for "pseries" guests * Fixes to the PAPR Dynamic Reconfiguration hotplug code * Several PAPR compliance fixes * New SLOF with: * GPT support * Much faster VGA handling # gpg: Signature made Wed 23 Sep 2015 02:50:10 BST using DSA key ID FDDA6FC6 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: F730 2185 38B4 D13E FD80 34F2 6882 CAC6 FDDA 6FC6 * remotes/dgibson/tags/spapr-next-20150923: (36 commits) sPAPR: Enable EEH on VFIO PCI device only sPAPR: Revert don't enable EEH on emulated PCI devices ppc/spapr: Implement H_RANDOM hypercall in QEMU ppc/spapr: Fix buffer overflow in spapr_populate_drconf_memory() spapr: Fix default NUMA node allocation for threads spapr: Move memory hotplug to RTAS_LOG_V6_HP_ID_DRC_COUNT type spapr: Support hotplug by specifying DRC count spapr: Revert to memory@XXXX representation for non-hotplugged memory spapr: Populate ibm,associativity-lookup-arrays correctly for non-NUMA spapr: Provide better error message when slots exceed max allowed spapr: Don't allow memory hotplug to memory less nodes spapr: Memory hotplug support spapr: Make hash table size a factor of maxram_size spapr: Support ibm,dynamic-reconfiguration-memory spapr: Add LMB DR connectors spapr: Use QEMU limit for maximum CPUs number spapr: Don't use QOM [*] syntax for DR connectors. spapr_drc: use RTAS return codes for methods called by RTAS spapr: Initialize hotplug memory address space spapr_drc: don't allow 'empty' DRCs to be unisolated or allocated ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
684bb5770e
|
@ -52,3 +52,4 @@ CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||||
# For PReP
|
# For PReP
|
||||||
CONFIG_MC146818RTC=y
|
CONFIG_MC146818RTC=y
|
||||||
CONFIG_ISA_TESTDEV=y
|
CONFIG_ISA_TESTDEV=y
|
||||||
|
CONFIG_MEM_HOTPLUG=y
|
||||||
|
|
|
@ -302,4 +302,52 @@ consisting of <phys>, <size> and <maxcpus>.
|
||||||
pseries guests use this property to note the maximum allowed CPUs for the
|
pseries guests use this property to note the maximum allowed CPUs for the
|
||||||
guest.
|
guest.
|
||||||
|
|
||||||
|
== ibm,dynamic-reconfiguration-memory ==
|
||||||
|
|
||||||
|
ibm,dynamic-reconfiguration-memory is a device tree node that represents
|
||||||
|
dynamically reconfigurable logical memory blocks (LMB). This node
|
||||||
|
is generated only when the guest advertises the support for it via
|
||||||
|
ibm,client-architecture-support call. Memory that is not dynamically
|
||||||
|
reconfigurable is represented by /memory nodes. The properties of this
|
||||||
|
node that are of interest to the sPAPR memory hotplug implementation
|
||||||
|
in QEMU are described here.
|
||||||
|
|
||||||
|
ibm,lmb-size
|
||||||
|
|
||||||
|
This 64bit integer defines the size of each dynamically reconfigurable LMB.
|
||||||
|
|
||||||
|
ibm,associativity-lookup-arrays
|
||||||
|
|
||||||
|
This property defines a lookup array in which the NUMA associativity
|
||||||
|
information for each LMB can be found. It is a property encoded array
|
||||||
|
that begins with an integer M, the number of associativity lists followed
|
||||||
|
by an integer N, the number of entries per associativity list and terminated
|
||||||
|
by M associativity lists each of length N integers.
|
||||||
|
|
||||||
|
This property provides the same information as given by ibm,associativity
|
||||||
|
property in a /memory node. Each assigned LMB has an index value between
|
||||||
|
0 and M-1 which is used as an index into this table to select which
|
||||||
|
associativity list to use for the LMB. This index value for each LMB
|
||||||
|
is defined in ibm,dynamic-memory property.
|
||||||
|
|
||||||
|
ibm,dynamic-memory
|
||||||
|
|
||||||
|
This property describes the dynamically reconfigurable memory. It is a
|
||||||
|
property encoded array that has an integer N, the number of LMBs followed
|
||||||
|
by N LMB list entires.
|
||||||
|
|
||||||
|
Each LMB list entry consists of the following elements:
|
||||||
|
|
||||||
|
- Logical address of the start of the LMB encoded as a 64bit integer. This
|
||||||
|
corresponds to reg property in /memory node.
|
||||||
|
- DRC index of the LMB that corresponds to ibm,my-drc-index property
|
||||||
|
in a /memory node.
|
||||||
|
- Four bytes reserved for expansion.
|
||||||
|
- Associativity list index for the LMB that is used as an index into
|
||||||
|
ibm,associativity-lookup-arrays property described earlier. This
|
||||||
|
is used to retrieve the right associativity list to be used for this
|
||||||
|
LMB.
|
||||||
|
- A 32bit flags word. The bit at bit position 0x00000008 defines whether
|
||||||
|
the LMB is assigned to the the partition as of boot time.
|
||||||
|
|
||||||
[1] http://thread.gmane.org/gmane.linux.ports.ppc.embedded/75350/focus=106867
|
[1] http://thread.gmane.org/gmane.linux.ports.ppc.embedded/75350/focus=106867
|
||||||
|
|
|
@ -3,7 +3,7 @@ obj-y += ppc.o ppc_booke.o
|
||||||
# IBM pSeries (sPAPR)
|
# IBM pSeries (sPAPR)
|
||||||
obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
|
obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
|
||||||
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
|
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
|
||||||
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o
|
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o
|
||||||
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
|
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
|
||||||
obj-y += spapr_pci_vfio.o
|
obj-y += spapr_pci_vfio.o
|
||||||
endif
|
endif
|
||||||
|
|
483
hw/ppc/spapr.c
483
hw/ppc/spapr.c
|
@ -30,9 +30,11 @@
|
||||||
#include "hw/fw-path-provider.h"
|
#include "hw/fw-path-provider.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
|
#include "sysemu/device_tree.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
|
#include "sysemu/device_tree.h"
|
||||||
#include "kvm_ppc.h"
|
#include "kvm_ppc.h"
|
||||||
#include "migration/migration.h"
|
#include "migration/migration.h"
|
||||||
#include "mmu-hash64.h"
|
#include "mmu-hash64.h"
|
||||||
|
@ -60,6 +62,7 @@
|
||||||
#include "hw/nmi.h"
|
#include "hw/nmi.h"
|
||||||
|
|
||||||
#include "hw/compat.h"
|
#include "hw/compat.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
@ -73,7 +76,7 @@
|
||||||
*
|
*
|
||||||
* We load our kernel at 4M, leaving space for SLOF initial image
|
* We load our kernel at 4M, leaving space for SLOF initial image
|
||||||
*/
|
*/
|
||||||
#define FDT_MAX_SIZE 0x40000
|
#define FDT_MAX_SIZE 0x100000
|
||||||
#define RTAS_MAX_SIZE 0x10000
|
#define RTAS_MAX_SIZE 0x10000
|
||||||
#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */
|
#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */
|
||||||
#define FW_MAX_SIZE 0x400000
|
#define FW_MAX_SIZE 0x400000
|
||||||
|
@ -85,8 +88,6 @@
|
||||||
|
|
||||||
#define TIMEBASE_FREQ 512000000ULL
|
#define TIMEBASE_FREQ 512000000ULL
|
||||||
|
|
||||||
#define MAX_CPUS 255
|
|
||||||
|
|
||||||
#define PHANDLE_XICP 0x00001111
|
#define PHANDLE_XICP 0x00001111
|
||||||
|
|
||||||
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
||||||
|
@ -375,6 +376,11 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||||
_FDT((fdt_property_string(fdt, "vm,uuid", buf)));
|
_FDT((fdt_property_string(fdt, "vm,uuid", buf)));
|
||||||
g_free(buf);
|
g_free(buf);
|
||||||
|
|
||||||
|
if (qemu_get_vm_name()) {
|
||||||
|
_FDT((fdt_property_string(fdt, "ibm,partition-name",
|
||||||
|
qemu_get_vm_name())));
|
||||||
|
}
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
|
_FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
|
||||||
_FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
|
_FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
|
||||||
|
|
||||||
|
@ -427,6 +433,10 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||||
_FDT((fdt_property_cell(fdt, "rtas-event-scan-rate",
|
_FDT((fdt_property_cell(fdt, "rtas-event-scan-rate",
|
||||||
RTAS_EVENT_SCAN_RATE)));
|
RTAS_EVENT_SCAN_RATE)));
|
||||||
|
|
||||||
|
if (msi_supported) {
|
||||||
|
_FDT((fdt_property(fdt, "ibm,change-msix-capable", NULL, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to PAPR, rtas ibm,os-term does not guarantee a return
|
* According to PAPR, rtas ibm,os-term does not guarantee a return
|
||||||
* back to the guest cpu.
|
* back to the guest cpu.
|
||||||
|
@ -495,44 +505,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||||
return fdt;
|
return fdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
|
static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
|
||||||
target_ulong addr, target_ulong size)
|
|
||||||
{
|
|
||||||
void *fdt, *fdt_skel;
|
|
||||||
sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
|
|
||||||
|
|
||||||
size -= sizeof(hdr);
|
|
||||||
|
|
||||||
/* Create sceleton */
|
|
||||||
fdt_skel = g_malloc0(size);
|
|
||||||
_FDT((fdt_create(fdt_skel, size)));
|
|
||||||
_FDT((fdt_begin_node(fdt_skel, "")));
|
|
||||||
_FDT((fdt_end_node(fdt_skel)));
|
|
||||||
_FDT((fdt_finish(fdt_skel)));
|
|
||||||
fdt = g_malloc0(size);
|
|
||||||
_FDT((fdt_open_into(fdt_skel, fdt, size)));
|
|
||||||
g_free(fdt_skel);
|
|
||||||
|
|
||||||
/* Fix skeleton up */
|
|
||||||
_FDT((spapr_fixup_cpu_dt(fdt, spapr)));
|
|
||||||
|
|
||||||
/* Pack resulting tree */
|
|
||||||
_FDT((fdt_pack(fdt)));
|
|
||||||
|
|
||||||
if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
|
|
||||||
trace_spapr_cas_failed(size);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
|
|
||||||
cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
|
|
||||||
trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
|
|
||||||
g_free(fdt);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
|
|
||||||
hwaddr size)
|
hwaddr size)
|
||||||
{
|
{
|
||||||
uint32_t associativity[] = {
|
uint32_t associativity[] = {
|
||||||
|
@ -555,6 +528,7 @@ static void spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
|
||||||
sizeof(mem_reg_property))));
|
sizeof(mem_reg_property))));
|
||||||
_FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
|
_FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
|
||||||
sizeof(associativity))));
|
sizeof(associativity))));
|
||||||
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
|
static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
|
||||||
|
@ -620,9 +594,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||||
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
||||||
uint32_t page_sizes_prop[64];
|
uint32_t page_sizes_prop[64];
|
||||||
size_t page_sizes_prop_size;
|
size_t page_sizes_prop_size;
|
||||||
QemuOpts *opts = qemu_opts_find(qemu_find_opts("smp-opts"), NULL);
|
uint32_t vcpus_per_socket = smp_threads * smp_cores;
|
||||||
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)};
|
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
|
||||||
|
|
||||||
_FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
|
_FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
|
||||||
|
@ -691,7 +663,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
|
||||||
cs->cpu_index / cpus_per_socket)));
|
cs->cpu_index / vcpus_per_socket)));
|
||||||
|
|
||||||
_FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
|
_FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
|
||||||
pft_size_prop, sizeof(pft_size_prop))));
|
pft_size_prop, sizeof(pft_size_prop))));
|
||||||
|
@ -738,12 +710,155 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds ibm,dynamic-reconfiguration-memory node.
|
||||||
|
* Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
|
||||||
|
* of this device tree node.
|
||||||
|
*/
|
||||||
|
static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
|
||||||
|
{
|
||||||
|
MachineState *machine = MACHINE(spapr);
|
||||||
|
int ret, i, offset;
|
||||||
|
uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
|
||||||
|
uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
|
||||||
|
uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
|
||||||
|
uint32_t *int_buf, *cur_index, buf_len;
|
||||||
|
int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate enough buffer size to fit in ibm,dynamic-memory
|
||||||
|
* or ibm,associativity-lookup-arrays
|
||||||
|
*/
|
||||||
|
buf_len = MAX(nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1, nr_nodes * 4 + 2)
|
||||||
|
* sizeof(uint32_t);
|
||||||
|
cur_index = int_buf = g_malloc0(buf_len);
|
||||||
|
|
||||||
|
offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
|
||||||
|
|
||||||
|
ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
|
||||||
|
sizeof(prop_lmb_size));
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ibm,dynamic-memory */
|
||||||
|
int_buf[0] = cpu_to_be32(nr_lmbs);
|
||||||
|
cur_index++;
|
||||||
|
for (i = 0; i < nr_lmbs; i++) {
|
||||||
|
sPAPRDRConnector *drc;
|
||||||
|
sPAPRDRConnectorClass *drck;
|
||||||
|
uint64_t addr = i * lmb_size + spapr->hotplug_memory.base;;
|
||||||
|
uint32_t *dynamic_memory = cur_index;
|
||||||
|
|
||||||
|
drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
|
||||||
|
addr/lmb_size);
|
||||||
|
g_assert(drc);
|
||||||
|
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
|
|
||||||
|
dynamic_memory[0] = cpu_to_be32(addr >> 32);
|
||||||
|
dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
|
||||||
|
dynamic_memory[2] = cpu_to_be32(drck->get_index(drc));
|
||||||
|
dynamic_memory[3] = cpu_to_be32(0); /* reserved */
|
||||||
|
dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL));
|
||||||
|
if (addr < machine->ram_size ||
|
||||||
|
memory_region_present(get_system_memory(), addr)) {
|
||||||
|
dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
|
||||||
|
} else {
|
||||||
|
dynamic_memory[5] = cpu_to_be32(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
|
||||||
|
}
|
||||||
|
ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ibm,associativity-lookup-arrays */
|
||||||
|
cur_index = int_buf;
|
||||||
|
int_buf[0] = cpu_to_be32(nr_nodes);
|
||||||
|
int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
|
||||||
|
cur_index += 2;
|
||||||
|
for (i = 0; i < nr_nodes; i++) {
|
||||||
|
uint32_t associativity[] = {
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(i)
|
||||||
|
};
|
||||||
|
memcpy(cur_index, associativity, sizeof(associativity));
|
||||||
|
cur_index += 4;
|
||||||
|
}
|
||||||
|
ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
|
||||||
|
(cur_index - int_buf) * sizeof(uint32_t));
|
||||||
|
out:
|
||||||
|
g_free(int_buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
|
||||||
|
target_ulong addr, target_ulong size,
|
||||||
|
bool cpu_update, bool memory_update)
|
||||||
|
{
|
||||||
|
void *fdt, *fdt_skel;
|
||||||
|
sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
|
||||||
|
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine());
|
||||||
|
|
||||||
|
size -= sizeof(hdr);
|
||||||
|
|
||||||
|
/* Create sceleton */
|
||||||
|
fdt_skel = g_malloc0(size);
|
||||||
|
_FDT((fdt_create(fdt_skel, size)));
|
||||||
|
_FDT((fdt_begin_node(fdt_skel, "")));
|
||||||
|
_FDT((fdt_end_node(fdt_skel)));
|
||||||
|
_FDT((fdt_finish(fdt_skel)));
|
||||||
|
fdt = g_malloc0(size);
|
||||||
|
_FDT((fdt_open_into(fdt_skel, fdt, size)));
|
||||||
|
g_free(fdt_skel);
|
||||||
|
|
||||||
|
/* Fixup cpu nodes */
|
||||||
|
if (cpu_update) {
|
||||||
|
_FDT((spapr_fixup_cpu_dt(fdt, spapr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate memory nodes or ibm,dynamic-reconfiguration-memory node */
|
||||||
|
if (memory_update && smc->dr_lmb_enabled) {
|
||||||
|
_FDT((spapr_populate_drconf_memory(spapr, fdt)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pack resulting tree */
|
||||||
|
_FDT((fdt_pack(fdt)));
|
||||||
|
|
||||||
|
if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
|
||||||
|
trace_spapr_cas_failed(size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
|
||||||
|
cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
|
||||||
|
trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
|
||||||
|
g_free(fdt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||||
hwaddr fdt_addr,
|
hwaddr fdt_addr,
|
||||||
hwaddr rtas_addr,
|
hwaddr rtas_addr,
|
||||||
hwaddr rtas_size)
|
hwaddr rtas_size)
|
||||||
{
|
{
|
||||||
MachineState *machine = MACHINE(qdev_get_machine());
|
MachineState *machine = MACHINE(qdev_get_machine());
|
||||||
|
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
|
||||||
const char *boot_device = machine->boot_order;
|
const char *boot_device = machine->boot_order;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
size_t cb = 0;
|
size_t cb = 0;
|
||||||
|
@ -768,6 +883,14 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
|
||||||
|
ret = spapr_rng_populate_dt(fdt);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "could not set up rng device in the fdt\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QLIST_FOREACH(phb, &spapr->phbs, list) {
|
QLIST_FOREACH(phb, &spapr->phbs, list) {
|
||||||
ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
|
ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
|
||||||
}
|
}
|
||||||
|
@ -814,6 +937,10 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||||
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (smc->dr_lmb_enabled) {
|
||||||
|
_FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
|
||||||
|
}
|
||||||
|
|
||||||
_FDT((fdt_pack(fdt)));
|
_FDT((fdt_pack(fdt)));
|
||||||
|
|
||||||
if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
|
if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
|
||||||
|
@ -822,6 +949,7 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
|
||||||
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
||||||
|
|
||||||
g_free(bootlist);
|
g_free(bootlist);
|
||||||
|
@ -1329,6 +1457,8 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
if (section_hdr) {
|
if (section_hdr) {
|
||||||
/* First section, just the hash shift */
|
/* First section, just the hash shift */
|
||||||
if (spapr->htab_shift != section_hdr) {
|
if (spapr->htab_shift != section_hdr) {
|
||||||
|
error_report("htab_shift mismatch: source %d target %d",
|
||||||
|
section_hdr, spapr->htab_shift);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1437,10 +1567,77 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu)
|
||||||
qemu_register_reset(spapr_cpu_reset, cpu);
|
qemu_register_reset(spapr_cpu_reset, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset routine for LMB DR devices.
|
||||||
|
*
|
||||||
|
* Unlike PCI DR devices, LMB DR devices explicitly register this reset
|
||||||
|
* routine. Reset for PCI DR devices will be handled by PHB reset routine
|
||||||
|
* when it walks all its children devices. LMB devices reset occurs
|
||||||
|
* as part of spapr_ppc_reset().
|
||||||
|
*/
|
||||||
|
static void spapr_drc_reset(void *opaque)
|
||||||
|
{
|
||||||
|
sPAPRDRConnector *drc = opaque;
|
||||||
|
DeviceState *d = DEVICE(drc);
|
||||||
|
|
||||||
|
if (d) {
|
||||||
|
device_reset(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
|
||||||
|
{
|
||||||
|
MachineState *machine = MACHINE(spapr);
|
||||||
|
uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
|
||||||
|
uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_lmbs; i++) {
|
||||||
|
sPAPRDRConnector *drc;
|
||||||
|
uint64_t addr;
|
||||||
|
|
||||||
|
addr = i * lmb_size + spapr->hotplug_memory.base;
|
||||||
|
drc = spapr_dr_connector_new(OBJECT(spapr), SPAPR_DR_CONNECTOR_TYPE_LMB,
|
||||||
|
addr/lmb_size);
|
||||||
|
qemu_register_reset(spapr_drc_reset, drc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If RAM size, maxmem size and individual node mem sizes aren't aligned
|
||||||
|
* to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
|
||||||
|
* since we can't support such unaligned sizes with DRCONF_MEMORY.
|
||||||
|
*/
|
||||||
|
static void spapr_validate_node_memory(MachineState *machine)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE ||
|
||||||
|
machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
|
||||||
|
error_report("Can't support memory configuration where RAM size "
|
||||||
|
"0x" RAM_ADDR_FMT " or maxmem size "
|
||||||
|
"0x" RAM_ADDR_FMT " isn't aligned to %llu MB",
|
||||||
|
machine->ram_size, machine->maxram_size,
|
||||||
|
SPAPR_MEMORY_BLOCK_SIZE/M_BYTE);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nb_numa_nodes; i++) {
|
||||||
|
if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
|
||||||
|
error_report("Can't support memory configuration where memory size"
|
||||||
|
" %" PRIx64 " of node %d isn't aligned to %llu MB",
|
||||||
|
numa_info[i].node_mem, i,
|
||||||
|
SPAPR_MEMORY_BLOCK_SIZE/M_BYTE);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* pSeries LPAR / sPAPR hardware init */
|
/* pSeries LPAR / sPAPR hardware init */
|
||||||
static void ppc_spapr_init(MachineState *machine)
|
static void ppc_spapr_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
|
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
|
||||||
|
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
|
||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
|
@ -1507,7 +1704,7 @@ static void ppc_spapr_init(MachineState *machine)
|
||||||
* more than needed for the Linux guests we support. */
|
* more than needed for the Linux guests we support. */
|
||||||
spapr->htab_shift = 18; /* Minimum architected size */
|
spapr->htab_shift = 18; /* Minimum architected size */
|
||||||
while (spapr->htab_shift <= 46) {
|
while (spapr->htab_shift <= 46) {
|
||||||
if ((1ULL << (spapr->htab_shift + 7)) >= machine->ram_size) {
|
if ((1ULL << (spapr->htab_shift + 7)) >= machine->maxram_size) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
spapr->htab_shift++;
|
spapr->htab_shift++;
|
||||||
|
@ -1519,6 +1716,10 @@ static void ppc_spapr_init(MachineState *machine)
|
||||||
smp_threads),
|
smp_threads),
|
||||||
XICS_IRQS);
|
XICS_IRQS);
|
||||||
|
|
||||||
|
if (smc->dr_lmb_enabled) {
|
||||||
|
spapr_validate_node_memory(machine);
|
||||||
|
}
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
if (machine->cpu_model == NULL) {
|
if (machine->cpu_model == NULL) {
|
||||||
machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
|
machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
|
||||||
|
@ -1535,6 +1736,7 @@ static void ppc_spapr_init(MachineState *machine)
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
/* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
|
/* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
|
||||||
kvmppc_enable_logical_ci_hcalls();
|
kvmppc_enable_logical_ci_hcalls();
|
||||||
|
kvmppc_enable_set_mode_hcall();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate RAM */
|
/* allocate RAM */
|
||||||
|
@ -1550,6 +1752,28 @@ static void ppc_spapr_init(MachineState *machine)
|
||||||
memory_region_add_subregion(sysmem, 0, rma_region);
|
memory_region_add_subregion(sysmem, 0, rma_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* initialize hotplug memory address space */
|
||||||
|
if (machine->ram_size < machine->maxram_size) {
|
||||||
|
ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size;
|
||||||
|
|
||||||
|
if (machine->ram_slots > SPAPR_MAX_RAM_SLOTS) {
|
||||||
|
error_report("Specified number of memory slots %"PRIu64" exceeds max supported %d\n",
|
||||||
|
machine->ram_slots, SPAPR_MAX_RAM_SLOTS);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
spapr->hotplug_memory.base = ROUND_UP(machine->ram_size,
|
||||||
|
SPAPR_HOTPLUG_MEM_ALIGN);
|
||||||
|
memory_region_init(&spapr->hotplug_memory.mr, OBJECT(spapr),
|
||||||
|
"hotplug-memory", hotplug_mem_size);
|
||||||
|
memory_region_add_subregion(sysmem, spapr->hotplug_memory.base,
|
||||||
|
&spapr->hotplug_memory.mr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smc->dr_lmb_enabled) {
|
||||||
|
spapr_create_lmb_dr_connectors(spapr);
|
||||||
|
}
|
||||||
|
|
||||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
|
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
|
error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
|
||||||
|
@ -1820,23 +2044,166 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size,
|
||||||
|
uint32_t node, Error **errp)
|
||||||
|
{
|
||||||
|
sPAPRDRConnector *drc;
|
||||||
|
sPAPRDRConnectorClass *drck;
|
||||||
|
uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
|
||||||
|
int i, fdt_offset, fdt_size;
|
||||||
|
void *fdt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for DRC connectors and send hotplug notification to the
|
||||||
|
* guest only in case of hotplugged memory. This allows cold plugged
|
||||||
|
* memory to be specified at boot time.
|
||||||
|
*/
|
||||||
|
if (!dev->hotplugged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nr_lmbs; i++) {
|
||||||
|
drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
|
||||||
|
addr/SPAPR_MEMORY_BLOCK_SIZE);
|
||||||
|
g_assert(drc);
|
||||||
|
|
||||||
|
fdt = create_device_tree(&fdt_size);
|
||||||
|
fdt_offset = spapr_populate_memory_node(fdt, node, addr,
|
||||||
|
SPAPR_MEMORY_BLOCK_SIZE);
|
||||||
|
|
||||||
|
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
|
drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp);
|
||||||
|
addr += SPAPR_MEMORY_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
|
uint32_t node, Error **errp)
|
||||||
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
|
sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
|
||||||
|
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||||
|
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
||||||
|
MemoryRegion *mr = ddc->get_memory_region(dimm);
|
||||||
|
uint64_t align = memory_region_get_alignment(mr);
|
||||||
|
uint64_t size = memory_region_size(mr);
|
||||||
|
uint64_t addr;
|
||||||
|
|
||||||
|
if (size % SPAPR_MEMORY_BLOCK_SIZE) {
|
||||||
|
error_setg(&local_err, "Hotplugged memory size must be a multiple of "
|
||||||
|
"%lld MB", SPAPR_MEMORY_BLOCK_SIZE/M_BYTE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
spapr_add_lmbs(dev, addr, size, node, &error_abort);
|
||||||
|
|
||||||
|
out:
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine());
|
||||||
|
|
||||||
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||||
|
int node;
|
||||||
|
|
||||||
|
if (!smc->dr_lmb_enabled) {
|
||||||
|
error_setg(errp, "Memory hotplug not supported for this machine");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP, errp);
|
||||||
|
if (*errp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Currently PowerPC kernel doesn't allow hot-adding memory to
|
||||||
|
* memory-less node, but instead will silently add the memory
|
||||||
|
* to the first node that has some memory. This causes two
|
||||||
|
* unexpected behaviours for the user.
|
||||||
|
*
|
||||||
|
* - Memory gets hotplugged to a different node than what the user
|
||||||
|
* specified.
|
||||||
|
* - Since pc-dimm subsystem in QEMU still thinks that memory belongs
|
||||||
|
* to memory-less node, a reboot will set things accordingly
|
||||||
|
* and the previously hotplugged memory now ends in the right node.
|
||||||
|
* This appears as if some memory moved from one node to another.
|
||||||
|
*
|
||||||
|
* So until kernel starts supporting memory hotplug to memory-less
|
||||||
|
* nodes, just prevent such attempts upfront in QEMU.
|
||||||
|
*/
|
||||||
|
if (nb_numa_nodes && !numa_info[node].node_mem) {
|
||||||
|
error_setg(errp, "Can't hotplug memory to memory-less node %d",
|
||||||
|
node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spapr_memory_plug(hotplug_dev, dev, node, errp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||||
|
error_setg(errp, "Memory hot unplug not supported by sPAPR");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HotplugHandler *spapr_get_hotpug_handler(MachineState *machine,
|
||||||
|
DeviceState *dev)
|
||||||
|
{
|
||||||
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||||
|
return HOTPLUG_HANDLER(machine);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index)
|
||||||
|
{
|
||||||
|
/* Allocate to NUMA nodes on a "socket" basis (not that concept of
|
||||||
|
* socket means much for the paravirtualized PAPR platform) */
|
||||||
|
return cpu_index / smp_threads / smp_cores;
|
||||||
|
}
|
||||||
|
|
||||||
static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
|
||||||
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
|
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
|
||||||
NMIClass *nc = NMI_CLASS(oc);
|
NMIClass *nc = NMI_CLASS(oc);
|
||||||
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
||||||
|
|
||||||
mc->init = ppc_spapr_init;
|
mc->init = ppc_spapr_init;
|
||||||
mc->reset = ppc_spapr_reset;
|
mc->reset = ppc_spapr_reset;
|
||||||
mc->block_default_type = IF_SCSI;
|
mc->block_default_type = IF_SCSI;
|
||||||
mc->max_cpus = MAX_CPUS;
|
mc->max_cpus = MAX_CPUMASK_BITS;
|
||||||
mc->no_parallel = 1;
|
mc->no_parallel = 1;
|
||||||
mc->default_boot_order = "";
|
mc->default_boot_order = "";
|
||||||
mc->default_ram_size = 512 * M_BYTE;
|
mc->default_ram_size = 512 * M_BYTE;
|
||||||
mc->kvm_type = spapr_kvm_type;
|
mc->kvm_type = spapr_kvm_type;
|
||||||
mc->has_dynamic_sysbus = true;
|
mc->has_dynamic_sysbus = true;
|
||||||
mc->pci_allow_0_address = true;
|
mc->pci_allow_0_address = true;
|
||||||
|
mc->get_hotplug_handler = spapr_get_hotpug_handler;
|
||||||
|
hc->plug = spapr_machine_device_plug;
|
||||||
|
hc->unplug = spapr_machine_device_unplug;
|
||||||
|
mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
|
||||||
|
|
||||||
|
smc->dr_lmb_enabled = false;
|
||||||
fwc->get_dev_path = spapr_get_fw_dev_path;
|
fwc->get_dev_path = spapr_get_fw_dev_path;
|
||||||
nc->nmi_monitor_handler = spapr_nmi;
|
nc->nmi_monitor_handler = spapr_nmi;
|
||||||
}
|
}
|
||||||
|
@ -1852,6 +2219,7 @@ static const TypeInfo spapr_machine_info = {
|
||||||
.interfaces = (InterfaceInfo[]) {
|
.interfaces = (InterfaceInfo[]) {
|
||||||
{ TYPE_FW_PATH_PROVIDER },
|
{ TYPE_FW_PATH_PROVIDER },
|
||||||
{ TYPE_NMI },
|
{ TYPE_NMI },
|
||||||
|
{ TYPE_HOTPLUG_HANDLER },
|
||||||
{ }
|
{ }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1974,7 +2342,7 @@ static void spapr_machine_2_4_class_init(ObjectClass *oc, void *data)
|
||||||
|
|
||||||
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.4";
|
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.4";
|
||||||
mc->alias = "pseries";
|
mc->alias = "pseries";
|
||||||
mc->is_default = 1;
|
mc->is_default = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo spapr_machine_2_4_info = {
|
static const TypeInfo spapr_machine_2_4_info = {
|
||||||
|
@ -1983,6 +2351,24 @@ static const TypeInfo spapr_machine_2_4_info = {
|
||||||
.class_init = spapr_machine_2_4_class_init,
|
.class_init = spapr_machine_2_4_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void spapr_machine_2_5_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->name = "pseries-2.5";
|
||||||
|
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.5";
|
||||||
|
mc->alias = "pseries";
|
||||||
|
mc->is_default = 1;
|
||||||
|
smc->dr_lmb_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo spapr_machine_2_5_info = {
|
||||||
|
.name = MACHINE_TYPE_NAME("pseries-2.5"),
|
||||||
|
.parent = TYPE_SPAPR_MACHINE,
|
||||||
|
.class_init = spapr_machine_2_5_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void spapr_machine_register_types(void)
|
static void spapr_machine_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&spapr_machine_info);
|
type_register_static(&spapr_machine_info);
|
||||||
|
@ -1990,6 +2376,7 @@ static void spapr_machine_register_types(void)
|
||||||
type_register_static(&spapr_machine_2_2_info);
|
type_register_static(&spapr_machine_2_2_info);
|
||||||
type_register_static(&spapr_machine_2_3_info);
|
type_register_static(&spapr_machine_2_3_info);
|
||||||
type_register_static(&spapr_machine_2_4_info);
|
type_register_static(&spapr_machine_2_4_info);
|
||||||
|
type_register_static(&spapr_machine_2_5_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(spapr_machine_register_types)
|
type_init(spapr_machine_register_types)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "hw/qdev.h"
|
#include "hw/qdev.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/ppc/spapr.h" /* for RTAS return codes */
|
||||||
|
|
||||||
/* #define DEBUG_SPAPR_DRC */
|
/* #define DEBUG_SPAPR_DRC */
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
|
|
||||||
#define DRC_CONTAINER_PATH "/dr-connector"
|
#define DRC_CONTAINER_PATH "/dr-connector"
|
||||||
#define DRC_INDEX_TYPE_SHIFT 28
|
#define DRC_INDEX_TYPE_SHIFT 28
|
||||||
#define DRC_INDEX_ID_MASK (~(~0 << DRC_INDEX_TYPE_SHIFT))
|
#define DRC_INDEX_ID_MASK ((1ULL << DRC_INDEX_TYPE_SHIFT) - 1)
|
||||||
|
|
||||||
static sPAPRDRConnectorTypeShift get_type_shift(sPAPRDRConnectorType type)
|
static sPAPRDRConnectorTypeShift get_type_shift(sPAPRDRConnectorType type)
|
||||||
{
|
{
|
||||||
|
@ -59,13 +60,23 @@ static uint32_t get_index(sPAPRDRConnector *drc)
|
||||||
(drc->id & DRC_INDEX_ID_MASK);
|
(drc->id & DRC_INDEX_ID_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_isolation_state(sPAPRDRConnector *drc,
|
static uint32_t set_isolation_state(sPAPRDRConnector *drc,
|
||||||
sPAPRDRIsolationState state)
|
sPAPRDRIsolationState state)
|
||||||
{
|
{
|
||||||
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
|
|
||||||
DPRINTFN("drc: %x, set_isolation_state: %x", get_index(drc), state);
|
DPRINTFN("drc: %x, set_isolation_state: %x", get_index(drc), state);
|
||||||
|
|
||||||
|
if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
|
||||||
|
/* cannot unisolate a non-existant resource, and, or resources
|
||||||
|
* which are in an 'UNUSABLE' allocation state. (PAPR 2.7, 13.5.3.5)
|
||||||
|
*/
|
||||||
|
if (!drc->dev ||
|
||||||
|
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
|
||||||
|
return RTAS_OUT_NO_SUCH_INDICATOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
drc->isolation_state = state;
|
drc->isolation_state = state;
|
||||||
|
|
||||||
if (drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
|
if (drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
|
||||||
|
@ -89,24 +100,35 @@ static int set_isolation_state(sPAPRDRConnector *drc,
|
||||||
drc->configured = false;
|
drc->configured = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return RTAS_OUT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_indicator_state(sPAPRDRConnector *drc,
|
static uint32_t set_indicator_state(sPAPRDRConnector *drc,
|
||||||
sPAPRDRIndicatorState state)
|
sPAPRDRIndicatorState state)
|
||||||
{
|
{
|
||||||
DPRINTFN("drc: %x, set_indicator_state: %x", get_index(drc), state);
|
DPRINTFN("drc: %x, set_indicator_state: %x", get_index(drc), state);
|
||||||
drc->indicator_state = state;
|
drc->indicator_state = state;
|
||||||
return 0;
|
return RTAS_OUT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_allocation_state(sPAPRDRConnector *drc,
|
static uint32_t set_allocation_state(sPAPRDRConnector *drc,
|
||||||
sPAPRDRAllocationState state)
|
sPAPRDRAllocationState state)
|
||||||
{
|
{
|
||||||
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
|
|
||||||
DPRINTFN("drc: %x, set_allocation_state: %x", get_index(drc), state);
|
DPRINTFN("drc: %x, set_allocation_state: %x", get_index(drc), state);
|
||||||
|
|
||||||
|
if (state == SPAPR_DR_ALLOCATION_STATE_USABLE) {
|
||||||
|
/* if there's no resource/device associated with the DRC, there's
|
||||||
|
* no way for us to put it in an allocation state consistent with
|
||||||
|
* being 'USABLE'. PAPR 2.7, 13.5.3.4 documents that this should
|
||||||
|
* result in an RTAS return code of -3 / "no such indicator"
|
||||||
|
*/
|
||||||
|
if (!drc->dev) {
|
||||||
|
return RTAS_OUT_NO_SUCH_INDICATOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
|
if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
|
||||||
drc->allocation_state = state;
|
drc->allocation_state = state;
|
||||||
if (drc->awaiting_release &&
|
if (drc->awaiting_release &&
|
||||||
|
@ -116,7 +138,7 @@ static int set_allocation_state(sPAPRDRConnector *drc,
|
||||||
drc->detach_cb_opaque, NULL);
|
drc->detach_cb_opaque, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return RTAS_OUT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t get_type(sPAPRDRConnector *drc)
|
static uint32_t get_type(sPAPRDRConnector *drc)
|
||||||
|
@ -157,10 +179,8 @@ static void set_configured(sPAPRDRConnector *drc)
|
||||||
* based on the current allocation/indicator/power states
|
* based on the current allocation/indicator/power states
|
||||||
* for the DR connector.
|
* for the DR connector.
|
||||||
*/
|
*/
|
||||||
static sPAPRDREntitySense entity_sense(sPAPRDRConnector *drc)
|
static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state)
|
||||||
{
|
{
|
||||||
sPAPRDREntitySense state;
|
|
||||||
|
|
||||||
if (drc->dev) {
|
if (drc->dev) {
|
||||||
if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
|
if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
|
||||||
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
|
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
|
||||||
|
@ -169,7 +189,7 @@ static sPAPRDREntitySense entity_sense(sPAPRDRConnector *drc)
|
||||||
* Otherwise, report the state as USABLE/PRESENT,
|
* Otherwise, report the state as USABLE/PRESENT,
|
||||||
* as we would for PCI.
|
* as we would for PCI.
|
||||||
*/
|
*/
|
||||||
state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
|
*state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
|
||||||
} else {
|
} else {
|
||||||
/* this assumes all PCI devices are assigned to
|
/* this assumes all PCI devices are assigned to
|
||||||
* a 'live insertion' power domain, where QEMU
|
* a 'live insertion' power domain, where QEMU
|
||||||
|
@ -177,21 +197,21 @@ static sPAPRDREntitySense entity_sense(sPAPRDRConnector *drc)
|
||||||
* to the guest. present, non-PCI resources are
|
* to the guest. present, non-PCI resources are
|
||||||
* unaffected by power state.
|
* unaffected by power state.
|
||||||
*/
|
*/
|
||||||
state = SPAPR_DR_ENTITY_SENSE_PRESENT;
|
*state = SPAPR_DR_ENTITY_SENSE_PRESENT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
|
if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
|
||||||
/* PCI devices, and only PCI devices, use EMPTY
|
/* PCI devices, and only PCI devices, use EMPTY
|
||||||
* in cases where we'd otherwise use UNUSABLE
|
* in cases where we'd otherwise use UNUSABLE
|
||||||
*/
|
*/
|
||||||
state = SPAPR_DR_ENTITY_SENSE_EMPTY;
|
*state = SPAPR_DR_ENTITY_SENSE_EMPTY;
|
||||||
} else {
|
} else {
|
||||||
state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
|
*state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTFN("drc: %x, entity_sense: %x", get_index(drc), state);
|
DPRINTFN("drc: %x, entity_sense: %x", get_index(drc), state);
|
||||||
return state;
|
return RTAS_OUT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prop_get_index(Object *obj, Visitor *v, void *opaque,
|
static void prop_get_index(Object *obj, Visitor *v, void *opaque,
|
||||||
|
@ -224,7 +244,9 @@ static void prop_get_entity_sense(Object *obj, Visitor *v, void *opaque,
|
||||||
{
|
{
|
||||||
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
|
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
|
||||||
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
uint32_t value = (uint32_t)drck->entity_sense(drc);
|
uint32_t value;
|
||||||
|
|
||||||
|
drck->entity_sense(drc, &value);
|
||||||
visit_type_uint32(v, &value, name, errp);
|
visit_type_uint32(v, &value, name, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +332,7 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
|
||||||
drc->dev = d;
|
drc->dev = d;
|
||||||
drc->fdt = fdt;
|
drc->fdt = fdt;
|
||||||
drc->fdt_start_offset = fdt_start_offset;
|
drc->fdt_start_offset = fdt_start_offset;
|
||||||
drc->configured = false;
|
drc->configured = coldplug;
|
||||||
|
|
||||||
object_property_add_link(OBJECT(drc), "device",
|
object_property_add_link(OBJECT(drc), "device",
|
||||||
object_get_typename(OBJECT(drc->dev)),
|
object_get_typename(OBJECT(drc->dev)),
|
||||||
|
@ -451,14 +473,17 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
|
||||||
{
|
{
|
||||||
sPAPRDRConnector *drc =
|
sPAPRDRConnector *drc =
|
||||||
SPAPR_DR_CONNECTOR(object_new(TYPE_SPAPR_DR_CONNECTOR));
|
SPAPR_DR_CONNECTOR(object_new(TYPE_SPAPR_DR_CONNECTOR));
|
||||||
|
char *prop_name;
|
||||||
|
|
||||||
g_assert(type);
|
g_assert(type);
|
||||||
|
|
||||||
drc->type = type;
|
drc->type = type;
|
||||||
drc->id = id;
|
drc->id = id;
|
||||||
drc->owner = owner;
|
drc->owner = owner;
|
||||||
object_property_add_child(owner, "dr-connector[*]", OBJECT(drc), NULL);
|
prop_name = g_strdup_printf("dr-connector[%"PRIu32"]", get_index(drc));
|
||||||
|
object_property_add_child(owner, prop_name, OBJECT(drc), NULL);
|
||||||
object_property_set_bool(OBJECT(drc), true, "realized", NULL);
|
object_property_set_bool(OBJECT(drc), true, "realized", NULL);
|
||||||
|
g_free(prop_name);
|
||||||
|
|
||||||
/* human-readable name for a DRC to encode into the DT
|
/* human-readable name for a DRC to encode into the DT
|
||||||
* description. this is mainly only used within a guest in place
|
* description. this is mainly only used within a guest in place
|
||||||
|
|
|
@ -386,7 +386,9 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
|
||||||
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
|
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_hotplug_req_event(sPAPRDRConnector *drc, uint8_t hp_action)
|
static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
|
||||||
|
sPAPRDRConnectorType drc_type,
|
||||||
|
uint32_t drc)
|
||||||
{
|
{
|
||||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
struct hp_log_full *new_hp;
|
struct hp_log_full *new_hp;
|
||||||
|
@ -395,8 +397,6 @@ static void spapr_hotplug_req_event(sPAPRDRConnector *drc, uint8_t hp_action)
|
||||||
struct rtas_event_log_v6_maina *maina;
|
struct rtas_event_log_v6_maina *maina;
|
||||||
struct rtas_event_log_v6_mainb *mainb;
|
struct rtas_event_log_v6_mainb *mainb;
|
||||||
struct rtas_event_log_v6_hp *hp;
|
struct rtas_event_log_v6_hp *hp;
|
||||||
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
|
||||||
sPAPRDRConnectorType drc_type = drck->get_type(drc);
|
|
||||||
|
|
||||||
new_hp = g_malloc0(sizeof(struct hp_log_full));
|
new_hp = g_malloc0(sizeof(struct hp_log_full));
|
||||||
hdr = &new_hp->hdr;
|
hdr = &new_hp->hdr;
|
||||||
|
@ -427,14 +427,15 @@ static void spapr_hotplug_req_event(sPAPRDRConnector *drc, uint8_t hp_action)
|
||||||
hp->hdr.section_length = cpu_to_be16(sizeof(*hp));
|
hp->hdr.section_length = cpu_to_be16(sizeof(*hp));
|
||||||
hp->hdr.section_version = 1; /* includes extended modifier */
|
hp->hdr.section_version = 1; /* includes extended modifier */
|
||||||
hp->hotplug_action = hp_action;
|
hp->hotplug_action = hp_action;
|
||||||
|
hp->hotplug_identifier = hp_id;
|
||||||
|
|
||||||
switch (drc_type) {
|
switch (drc_type) {
|
||||||
case SPAPR_DR_CONNECTOR_TYPE_PCI:
|
case SPAPR_DR_CONNECTOR_TYPE_PCI:
|
||||||
hp->drc.index = cpu_to_be32(drck->get_index(drc));
|
|
||||||
hp->hotplug_identifier = RTAS_LOG_V6_HP_ID_DRC_INDEX;
|
|
||||||
hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PCI;
|
hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PCI;
|
||||||
break;
|
break;
|
||||||
|
case SPAPR_DR_CONNECTOR_TYPE_LMB:
|
||||||
|
hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_MEMORY;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* we shouldn't be signaling hotplug events for resources
|
/* we shouldn't be signaling hotplug events for resources
|
||||||
* that don't support them
|
* that don't support them
|
||||||
|
@ -443,19 +444,49 @@ static void spapr_hotplug_req_event(sPAPRDRConnector *drc, uint8_t hp_action)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT) {
|
||||||
|
hp->drc.count = cpu_to_be32(drc);
|
||||||
|
} else if (hp_id == RTAS_LOG_V6_HP_ID_DRC_INDEX) {
|
||||||
|
hp->drc.index = cpu_to_be32(drc);
|
||||||
|
}
|
||||||
|
|
||||||
rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);
|
rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);
|
||||||
|
|
||||||
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
|
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
|
||||||
}
|
}
|
||||||
|
|
||||||
void spapr_hotplug_req_add_event(sPAPRDRConnector *drc)
|
void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
|
||||||
{
|
{
|
||||||
spapr_hotplug_req_event(drc, RTAS_LOG_V6_HP_ACTION_ADD);
|
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
|
sPAPRDRConnectorType drc_type = drck->get_type(drc);
|
||||||
|
uint32 index = drck->get_index(drc);
|
||||||
|
|
||||||
|
spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
|
||||||
|
RTAS_LOG_V6_HP_ACTION_ADD, drc_type, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spapr_hotplug_req_remove_event(sPAPRDRConnector *drc)
|
void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc)
|
||||||
{
|
{
|
||||||
spapr_hotplug_req_event(drc, RTAS_LOG_V6_HP_ACTION_REMOVE);
|
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
|
sPAPRDRConnectorType drc_type = drck->get_type(drc);
|
||||||
|
uint32 index = drck->get_index(drc);
|
||||||
|
|
||||||
|
spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
|
||||||
|
RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
|
||||||
|
uint32_t count)
|
||||||
|
{
|
||||||
|
spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
|
||||||
|
RTAS_LOG_V6_HP_ACTION_ADD, drc_type, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
|
||||||
|
uint32_t count)
|
||||||
|
{
|
||||||
|
spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
|
||||||
|
RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
|
|
|
@ -808,6 +808,32 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the offset to the requested option vector @vector in the
|
||||||
|
* option vector table @table.
|
||||||
|
*/
|
||||||
|
static target_ulong cas_get_option_vector(int vector, target_ulong table)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char nr_vectors, nr_entries;
|
||||||
|
|
||||||
|
if (!table) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nr_vectors = (ldl_phys(&address_space_memory, table) >> 24) + 1;
|
||||||
|
if (!vector || vector > nr_vectors) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
table++; /* skip nr option vectors */
|
||||||
|
|
||||||
|
for (i = 0; i < vector - 1; i++) {
|
||||||
|
nr_entries = ldl_phys(&address_space_memory, table) >> 24;
|
||||||
|
table += nr_entries + 2;
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PowerPCCPU *cpu;
|
PowerPCCPU *cpu;
|
||||||
uint32_t cpu_version;
|
uint32_t cpu_version;
|
||||||
|
@ -828,19 +854,22 @@ static void do_set_compat(void *arg)
|
||||||
((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
|
((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
|
||||||
((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
|
((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
|
||||||
|
|
||||||
|
#define OV5_DRCONF_MEMORY 0x20
|
||||||
|
|
||||||
static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
|
static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
|
||||||
sPAPRMachineState *spapr,
|
sPAPRMachineState *spapr,
|
||||||
target_ulong opcode,
|
target_ulong opcode,
|
||||||
target_ulong *args)
|
target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong list = args[0];
|
target_ulong list = args[0], ov_table;
|
||||||
PowerPCCPUClass *pcc_ = POWERPC_CPU_GET_CLASS(cpu_);
|
PowerPCCPUClass *pcc_ = POWERPC_CPU_GET_CLASS(cpu_);
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
bool cpu_match = false;
|
bool cpu_match = false, cpu_update = true, memory_update = false;
|
||||||
unsigned old_cpu_version = cpu_->cpu_version;
|
unsigned old_cpu_version = cpu_->cpu_version;
|
||||||
unsigned compat_lvl = 0, cpu_version = 0;
|
unsigned compat_lvl = 0, cpu_version = 0;
|
||||||
unsigned max_lvl = get_compat_level(cpu_->max_compat);
|
unsigned max_lvl = get_compat_level(cpu_->max_compat);
|
||||||
int counter;
|
int counter;
|
||||||
|
char ov5_byte2;
|
||||||
|
|
||||||
/* Parse PVR list */
|
/* Parse PVR list */
|
||||||
for (counter = 0; counter < 512; ++counter) {
|
for (counter = 0; counter < 512; ++counter) {
|
||||||
|
@ -890,8 +919,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For the future use: here @list points to the first capability */
|
|
||||||
|
|
||||||
/* Parsing finished */
|
/* Parsing finished */
|
||||||
trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
|
trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
|
||||||
cpu_version, pcc_->pcr_mask);
|
cpu_version, pcc_->pcr_mask);
|
||||||
|
@ -915,14 +942,26 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cpu_version) {
|
if (!cpu_version) {
|
||||||
return H_SUCCESS;
|
cpu_update = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For the future use: here @ov_table points to the first option vector */
|
||||||
|
ov_table = list;
|
||||||
|
|
||||||
|
list = cas_get_option_vector(5, ov_table);
|
||||||
if (!list) {
|
if (!list) {
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spapr_h_cas_compose_response(spapr, args[1], args[2])) {
|
/* @list now points to OV 5 */
|
||||||
|
list += 2;
|
||||||
|
ov5_byte2 = rtas_ld(list, 0) >> 24;
|
||||||
|
if (ov5_byte2 & OV5_DRCONF_MEMORY) {
|
||||||
|
memory_update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spapr_h_cas_compose_response(spapr, args[1], args[2],
|
||||||
|
cpu_update, memory_update)) {
|
||||||
qemu_system_reset_request();
|
qemu_system_reset_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -971,7 +1010,8 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
|
qemu_log_mask(LOG_UNIMP, "Unimplemented SPAPR hcall 0x" TARGET_FMT_lx "\n",
|
||||||
|
opcode);
|
||||||
return H_FUNCTION;
|
return H_FUNCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
size = rtas_ld(args, 3);
|
size = rtas_ld(args, 3);
|
||||||
addr = rtas_ld(args, 0);
|
addr = rtas_ld(args, 0);
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
val = rtas_ld(args, 4);
|
val = rtas_ld(args, 4);
|
||||||
size = rtas_ld(args, 3);
|
size = rtas_ld(args, 3);
|
||||||
addr = rtas_ld(args, 0);
|
addr = rtas_ld(args, 0);
|
||||||
|
@ -269,7 +269,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong rets)
|
target_ulong rets)
|
||||||
{
|
{
|
||||||
uint32_t config_addr = rtas_ld(args, 0);
|
uint32_t config_addr = rtas_ld(args, 0);
|
||||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
uint64_t buid = rtas_ldq(args, 1);
|
||||||
unsigned int func = rtas_ld(args, 3);
|
unsigned int func = rtas_ld(args, 3);
|
||||||
unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
|
unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
|
||||||
unsigned int seq_num = rtas_ld(args, 5);
|
unsigned int seq_num = rtas_ld(args, 5);
|
||||||
|
@ -375,7 +375,9 @@ out:
|
||||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||||
rtas_st(rets, 1, req_num);
|
rtas_st(rets, 1, req_num);
|
||||||
rtas_st(rets, 2, ++seq_num);
|
rtas_st(rets, 2, ++seq_num);
|
||||||
rtas_st(rets, 3, ret_intr_type);
|
if (nret > 3) {
|
||||||
|
rtas_st(rets, 3, ret_intr_type);
|
||||||
|
}
|
||||||
|
|
||||||
trace_spapr_pci_rtas_ibm_change_msi(config_addr, func, req_num, irq);
|
trace_spapr_pci_rtas_ibm_change_msi(config_addr, func, req_num, irq);
|
||||||
}
|
}
|
||||||
|
@ -389,7 +391,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
|
||||||
target_ulong rets)
|
target_ulong rets)
|
||||||
{
|
{
|
||||||
uint32_t config_addr = rtas_ld(args, 0);
|
uint32_t config_addr = rtas_ld(args, 0);
|
||||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
uint64_t buid = rtas_ldq(args, 1);
|
||||||
unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
|
unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
|
||||||
sPAPRPHBState *phb = NULL;
|
sPAPRPHBState *phb = NULL;
|
||||||
PCIDevice *pdev = NULL;
|
PCIDevice *pdev = NULL;
|
||||||
|
@ -429,7 +431,6 @@ static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu,
|
||||||
{
|
{
|
||||||
sPAPRPHBState *sphb;
|
sPAPRPHBState *sphb;
|
||||||
sPAPRPHBClass *spc;
|
sPAPRPHBClass *spc;
|
||||||
PCIDevice *pdev;
|
|
||||||
uint32_t addr, option;
|
uint32_t addr, option;
|
||||||
uint64_t buid;
|
uint64_t buid;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -438,7 +439,7 @@ static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu,
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
addr = rtas_ld(args, 0);
|
addr = rtas_ld(args, 0);
|
||||||
option = rtas_ld(args, 3);
|
option = rtas_ld(args, 3);
|
||||||
|
|
||||||
|
@ -447,12 +448,6 @@ static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu,
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdev = pci_find_device(PCI_HOST_BRIDGE(sphb)->bus,
|
|
||||||
(addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
|
|
||||||
if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
|
|
||||||
goto param_error_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
|
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
|
||||||
if (!spc->eeh_set_option) {
|
if (!spc->eeh_set_option) {
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
|
@ -482,7 +477,7 @@ static void rtas_ibm_get_config_addr_info2(PowerPCCPU *cpu,
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
sphb = spapr_pci_find_phb(spapr, buid);
|
sphb = spapr_pci_find_phb(spapr, buid);
|
||||||
if (!sphb) {
|
if (!sphb) {
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
|
@ -537,7 +532,7 @@ static void rtas_ibm_read_slot_reset_state2(PowerPCCPU *cpu,
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
sphb = spapr_pci_find_phb(spapr, buid);
|
sphb = spapr_pci_find_phb(spapr, buid);
|
||||||
if (!sphb) {
|
if (!sphb) {
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
|
@ -582,7 +577,7 @@ static void rtas_ibm_set_slot_reset(PowerPCCPU *cpu,
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
option = rtas_ld(args, 3);
|
option = rtas_ld(args, 3);
|
||||||
sphb = spapr_pci_find_phb(spapr, buid);
|
sphb = spapr_pci_find_phb(spapr, buid);
|
||||||
if (!sphb) {
|
if (!sphb) {
|
||||||
|
@ -617,7 +612,7 @@ static void rtas_ibm_configure_pe(PowerPCCPU *cpu,
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
sphb = spapr_pci_find_phb(spapr, buid);
|
sphb = spapr_pci_find_phb(spapr, buid);
|
||||||
if (!sphb) {
|
if (!sphb) {
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
|
@ -652,7 +647,7 @@ static void rtas_ibm_slot_error_detail(PowerPCCPU *cpu,
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
buid = rtas_ldq(args, 1);
|
||||||
sphb = spapr_pci_find_phb(spapr, buid);
|
sphb = spapr_pci_find_phb(spapr, buid);
|
||||||
if (!sphb) {
|
if (!sphb) {
|
||||||
goto param_error_exit;
|
goto param_error_exit;
|
||||||
|
@ -955,6 +950,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
|
||||||
int pci_status, err;
|
int pci_status, err;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
|
uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
|
||||||
|
uint32_t max_msi, max_msix;
|
||||||
|
|
||||||
if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
|
if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
|
||||||
PCI_HEADER_TYPE_BRIDGE) {
|
PCI_HEADER_TYPE_BRIDGE) {
|
||||||
|
@ -1035,8 +1031,15 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
|
||||||
RESOURCE_CELLS_ADDRESS));
|
RESOURCE_CELLS_ADDRESS));
|
||||||
_FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
|
_FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
|
||||||
RESOURCE_CELLS_SIZE));
|
RESOURCE_CELLS_SIZE));
|
||||||
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x",
|
|
||||||
RESOURCE_CELLS_SIZE));
|
max_msi = msi_nr_vectors_allocated(dev);
|
||||||
|
if (max_msi) {
|
||||||
|
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi", max_msi));
|
||||||
|
}
|
||||||
|
max_msix = dev->msix_entries_nr;
|
||||||
|
if (max_msix) {
|
||||||
|
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x", max_msix));
|
||||||
|
}
|
||||||
|
|
||||||
populate_resource_props(dev, &rp);
|
populate_resource_props(dev, &rp);
|
||||||
_FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len));
|
_FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len));
|
||||||
|
@ -1177,7 +1180,7 @@ static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (plugged_dev->hotplugged) {
|
if (plugged_dev->hotplugged) {
|
||||||
spapr_hotplug_req_add_event(drc);
|
spapr_hotplug_req_add_by_index(drc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1205,7 +1208,7 @@ static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler,
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spapr_hotplug_req_remove_event(drc);
|
spapr_hotplug_req_remove_by_index(drc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ static int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
|
||||||
phb = PCI_HOST_BRIDGE(sphb);
|
phb = PCI_HOST_BRIDGE(sphb);
|
||||||
pdev = pci_find_device(phb->bus,
|
pdev = pci_find_device(phb->bus,
|
||||||
(addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
|
(addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
|
||||||
if (!pdev) {
|
if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
|
||||||
return RTAS_OUT_PARAM_ERROR;
|
return RTAS_OUT_PARAM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* QEMU sPAPR random number generator "device" for H_RANDOM hypercall
|
||||||
|
*
|
||||||
|
* Copyright 2015 Thomas Huth, Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License,
|
||||||
|
* or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/device_tree.h"
|
||||||
|
#include "sysemu/rng.h"
|
||||||
|
#include "hw/ppc/spapr.h"
|
||||||
|
#include "kvm_ppc.h"
|
||||||
|
|
||||||
|
#define SPAPR_RNG(obj) \
|
||||||
|
OBJECT_CHECK(sPAPRRngState, (obj), TYPE_SPAPR_RNG)
|
||||||
|
|
||||||
|
struct sPAPRRngState {
|
||||||
|
/*< private >*/
|
||||||
|
DeviceState ds;
|
||||||
|
RngBackend *backend;
|
||||||
|
bool use_kvm;
|
||||||
|
};
|
||||||
|
typedef struct sPAPRRngState sPAPRRngState;
|
||||||
|
|
||||||
|
struct HRandomData {
|
||||||
|
QemuSemaphore sem;
|
||||||
|
union {
|
||||||
|
uint64_t v64;
|
||||||
|
uint8_t v8[8];
|
||||||
|
} val;
|
||||||
|
int received;
|
||||||
|
};
|
||||||
|
typedef struct HRandomData HRandomData;
|
||||||
|
|
||||||
|
/* Callback function for the RngBackend */
|
||||||
|
static void random_recv(void *dest, const void *src, size_t size)
|
||||||
|
{
|
||||||
|
HRandomData *hrdp = dest;
|
||||||
|
|
||||||
|
if (src && size > 0) {
|
||||||
|
assert(size + hrdp->received <= sizeof(hrdp->val.v8));
|
||||||
|
memcpy(&hrdp->val.v8[hrdp->received], src, size);
|
||||||
|
hrdp->received += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_sem_post(&hrdp->sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handler for the H_RANDOM hypercall */
|
||||||
|
static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
|
target_ulong opcode, target_ulong *args)
|
||||||
|
{
|
||||||
|
sPAPRRngState *rngstate;
|
||||||
|
HRandomData hrdata;
|
||||||
|
|
||||||
|
rngstate = SPAPR_RNG(object_resolve_path_type("", TYPE_SPAPR_RNG, NULL));
|
||||||
|
|
||||||
|
if (!rngstate || !rngstate->backend) {
|
||||||
|
return H_HARDWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_sem_init(&hrdata.sem, 0);
|
||||||
|
hrdata.val.v64 = 0;
|
||||||
|
hrdata.received = 0;
|
||||||
|
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
while (hrdata.received < 8) {
|
||||||
|
rng_backend_request_entropy(rngstate->backend, 8 - hrdata.received,
|
||||||
|
random_recv, &hrdata);
|
||||||
|
qemu_sem_wait(&hrdata.sem);
|
||||||
|
}
|
||||||
|
qemu_mutex_lock_iothread();
|
||||||
|
|
||||||
|
qemu_sem_destroy(&hrdata.sem);
|
||||||
|
args[0] = hrdata.val.v64;
|
||||||
|
|
||||||
|
return H_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_rng_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
sPAPRRngState *rngstate = SPAPR_RNG(obj);
|
||||||
|
|
||||||
|
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL) != NULL) {
|
||||||
|
error_report("spapr-rng can not be instantiated twice!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||||
|
(Object **)&rngstate->backend,
|
||||||
|
object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||||
|
object_property_set_description(obj, "rng",
|
||||||
|
"ID of the random number generator backend",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_rng_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
|
||||||
|
sPAPRRngState *rngstate = SPAPR_RNG(dev);
|
||||||
|
|
||||||
|
if (rngstate->use_kvm) {
|
||||||
|
if (kvmppc_enable_hwrng() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If user specified both, use-kvm and a backend, we fall back to
|
||||||
|
* the backend now. If not, provide an appropriate error message.
|
||||||
|
*/
|
||||||
|
if (!rngstate->backend) {
|
||||||
|
error_setg(errp, "Could not initialize in-kernel H_RANDOM call!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rngstate->backend) {
|
||||||
|
spapr_register_hypercall(H_RANDOM, h_random);
|
||||||
|
} else {
|
||||||
|
error_setg(errp, "spapr-rng needs an RNG backend!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int spapr_rng_populate_dt(void *fdt)
|
||||||
|
{
|
||||||
|
int node;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
|
||||||
|
if (node <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = fdt_setprop_string(fdt, node, "device_type",
|
||||||
|
"ibm,platform-facilities");
|
||||||
|
ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
|
||||||
|
ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
|
||||||
|
|
||||||
|
node = fdt_add_subnode(fdt, node, "ibm,random-v1");
|
||||||
|
if (node <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
|
||||||
|
|
||||||
|
return ret ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property spapr_rng_properties[] = {
|
||||||
|
DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void spapr_rng_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
|
||||||
|
dc->realize = spapr_rng_realize;
|
||||||
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
|
dc->props = spapr_rng_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo spapr_rng_info = {
|
||||||
|
.name = TYPE_SPAPR_RNG,
|
||||||
|
.parent = TYPE_DEVICE,
|
||||||
|
.instance_size = sizeof(sPAPRRngState),
|
||||||
|
.instance_init = spapr_rng_instance_init,
|
||||||
|
.class_init = spapr_rng_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void spapr_rng_register_type(void)
|
||||||
|
{
|
||||||
|
type_register_static(&spapr_rng_info);
|
||||||
|
}
|
||||||
|
type_init(spapr_rng_register_type)
|
|
@ -34,6 +34,7 @@
|
||||||
#include "hw/ppc/spapr.h"
|
#include "hw/ppc/spapr.h"
|
||||||
#include "hw/ppc/spapr_vio.h"
|
#include "hw/ppc/spapr_vio.h"
|
||||||
#include "qapi-event.h"
|
#include "qapi-event.h"
|
||||||
|
#include "hw/boards.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
#include "hw/ppc/spapr_drc.h"
|
#include "hw/ppc/spapr_drc.h"
|
||||||
|
@ -240,8 +241,14 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
|
||||||
|
|
||||||
switch (parameter) {
|
switch (parameter) {
|
||||||
case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
|
case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
|
||||||
char *param_val = g_strdup_printf("MaxEntCap=%d,MaxPlatProcs=%d",
|
char *param_val = g_strdup_printf("MaxEntCap=%d,"
|
||||||
max_cpus, smp_cpus);
|
"DesMem=%llu,"
|
||||||
|
"DesProcs=%d,"
|
||||||
|
"MaxPlatProcs=%d",
|
||||||
|
max_cpus,
|
||||||
|
current_machine->ram_size / M_BYTE,
|
||||||
|
smp_cpus,
|
||||||
|
max_cpus);
|
||||||
rtas_st_buffer(buffer, length, (uint8_t *)param_val, strlen(param_val));
|
rtas_st_buffer(buffer, length, (uint8_t *)param_val, strlen(param_val));
|
||||||
g_free(param_val);
|
g_free(param_val);
|
||||||
break;
|
break;
|
||||||
|
@ -365,12 +372,13 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t sensor_type;
|
uint32_t sensor_type;
|
||||||
uint32_t sensor_index;
|
uint32_t sensor_index;
|
||||||
uint32_t sensor_state;
|
uint32_t sensor_state;
|
||||||
|
uint32_t ret = RTAS_OUT_SUCCESS;
|
||||||
sPAPRDRConnector *drc;
|
sPAPRDRConnector *drc;
|
||||||
sPAPRDRConnectorClass *drck;
|
sPAPRDRConnectorClass *drck;
|
||||||
|
|
||||||
if (nargs != 3 || nret != 1) {
|
if (nargs != 3 || nret != 1) {
|
||||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
ret = RTAS_OUT_PARAM_ERROR;
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sensor_type = rtas_ld(args, 0);
|
sensor_type = rtas_ld(args, 0);
|
||||||
|
@ -386,8 +394,8 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
if (!drc) {
|
if (!drc) {
|
||||||
DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n",
|
DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n",
|
||||||
sensor_index);
|
sensor_index);
|
||||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
ret = RTAS_OUT_PARAM_ERROR;
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
|
|
||||||
|
@ -406,19 +414,20 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
spapr_ccs_remove(spapr, ccs);
|
spapr_ccs_remove(spapr, ccs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drck->set_isolation_state(drc, sensor_state);
|
ret = drck->set_isolation_state(drc, sensor_state);
|
||||||
break;
|
break;
|
||||||
case RTAS_SENSOR_TYPE_DR:
|
case RTAS_SENSOR_TYPE_DR:
|
||||||
drck->set_indicator_state(drc, sensor_state);
|
ret = drck->set_indicator_state(drc, sensor_state);
|
||||||
break;
|
break;
|
||||||
case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
|
case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
|
||||||
drck->set_allocation_state(drc, sensor_state);
|
ret = drck->set_allocation_state(drc, sensor_state);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out_unimplemented;
|
goto out_unimplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
out:
|
||||||
|
rtas_st(rets, 0, ret);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
out_unimplemented:
|
out_unimplemented:
|
||||||
|
@ -435,13 +444,14 @@ static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
{
|
{
|
||||||
uint32_t sensor_type;
|
uint32_t sensor_type;
|
||||||
uint32_t sensor_index;
|
uint32_t sensor_index;
|
||||||
|
uint32_t sensor_state = 0;
|
||||||
sPAPRDRConnector *drc;
|
sPAPRDRConnector *drc;
|
||||||
sPAPRDRConnectorClass *drck;
|
sPAPRDRConnectorClass *drck;
|
||||||
uint32_t entity_sense;
|
uint32_t ret = RTAS_OUT_SUCCESS;
|
||||||
|
|
||||||
if (nargs != 2 || nret != 2) {
|
if (nargs != 2 || nret != 2) {
|
||||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
ret = RTAS_OUT_PARAM_ERROR;
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sensor_type = rtas_ld(args, 0);
|
sensor_type = rtas_ld(args, 0);
|
||||||
|
@ -451,22 +461,23 @@ static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
/* currently only DR-related sensors are implemented */
|
/* currently only DR-related sensors are implemented */
|
||||||
DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n",
|
DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n",
|
||||||
sensor_type);
|
sensor_type);
|
||||||
rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
|
ret = RTAS_OUT_NOT_SUPPORTED;
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
drc = spapr_dr_connector_by_index(sensor_index);
|
drc = spapr_dr_connector_by_index(sensor_index);
|
||||||
if (!drc) {
|
if (!drc) {
|
||||||
DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n",
|
DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n",
|
||||||
sensor_index);
|
sensor_index);
|
||||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
ret = RTAS_OUT_PARAM_ERROR;
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
entity_sense = drck->entity_sense(drc);
|
ret = drck->entity_sense(drc, &sensor_state);
|
||||||
|
|
||||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
out:
|
||||||
rtas_st(rets, 1, entity_sense);
|
rtas_st(rets, 0, ret);
|
||||||
|
rtas_st(rets, 1, sensor_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* configure-connector work area offsets, int32_t units for field
|
/* configure-connector work area offsets, int32_t units for field
|
||||||
|
@ -515,6 +526,12 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
|
||||||
|
|
||||||
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||||
fdt = drck->get_fdt(drc, NULL);
|
fdt = drck->get_fdt(drc, NULL);
|
||||||
|
if (!fdt) {
|
||||||
|
DPRINTF("rtas_ibm_configure_connector: Missing FDT for DRC index: %xh\n",
|
||||||
|
drc_index);
|
||||||
|
rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ccs = spapr_ccs_find(spapr, drc_index);
|
ccs = spapr_ccs_find(spapr, drc_index);
|
||||||
if (!ccs) {
|
if (!ccs) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/ppc/xics.h"
|
#include "hw/ppc/xics.h"
|
||||||
#include "hw/ppc/spapr_drc.h"
|
#include "hw/ppc/spapr_drc.h"
|
||||||
|
#include "hw/mem/pc-dimm.h"
|
||||||
|
|
||||||
struct VIOsPAPRBus;
|
struct VIOsPAPRBus;
|
||||||
struct sPAPRPHBState;
|
struct sPAPRPHBState;
|
||||||
|
@ -34,6 +35,7 @@ struct sPAPRMachineClass {
|
||||||
MachineClass parent_class;
|
MachineClass parent_class;
|
||||||
|
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,6 +78,7 @@ struct sPAPRMachineState {
|
||||||
|
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
char *kvm_type;
|
char *kvm_type;
|
||||||
|
MemoryHotplugState hotplug_memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define H_SUCCESS 0
|
#define H_SUCCESS 0
|
||||||
|
@ -331,6 +334,7 @@ struct sPAPRMachineState {
|
||||||
#define H_SET_MPP 0x2D0
|
#define H_SET_MPP 0x2D0
|
||||||
#define H_GET_MPP 0x2D4
|
#define H_GET_MPP 0x2D4
|
||||||
#define H_XIRR_X 0x2FC
|
#define H_XIRR_X 0x2FC
|
||||||
|
#define H_RANDOM 0x300
|
||||||
#define H_SET_MODE 0x31C
|
#define H_SET_MODE 0x31C
|
||||||
#define MAX_HCALL_OPCODE H_SET_MODE
|
#define MAX_HCALL_OPCODE H_SET_MODE
|
||||||
|
|
||||||
|
@ -353,15 +357,10 @@ typedef struct sPAPRDeviceTreeUpdateHeader {
|
||||||
uint32_t version_id;
|
uint32_t version_id;
|
||||||
} sPAPRDeviceTreeUpdateHeader;
|
} sPAPRDeviceTreeUpdateHeader;
|
||||||
|
|
||||||
/*#define DEBUG_SPAPR_HCALLS*/
|
|
||||||
|
|
||||||
#ifdef DEBUG_SPAPR_HCALLS
|
|
||||||
#define hcall_dprintf(fmt, ...) \
|
#define hcall_dprintf(fmt, ...) \
|
||||||
do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0)
|
do { \
|
||||||
#else
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt, __func__, ## __VA_ARGS__); \
|
||||||
#define hcall_dprintf(fmt, ...) \
|
} while (0)
|
||||||
do { } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPRMachineState *sm,
|
typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPRMachineState *sm,
|
||||||
target_ulong opcode,
|
target_ulong opcode,
|
||||||
|
@ -414,6 +413,7 @@ int spapr_allocate_irq_block(int num, bool lsi, bool msi);
|
||||||
#define RTAS_OUT_BUSY -2
|
#define RTAS_OUT_BUSY -2
|
||||||
#define RTAS_OUT_PARAM_ERROR -3
|
#define RTAS_OUT_PARAM_ERROR -3
|
||||||
#define RTAS_OUT_NOT_SUPPORTED -3
|
#define RTAS_OUT_NOT_SUPPORTED -3
|
||||||
|
#define RTAS_OUT_NO_SUCH_INDICATOR -3
|
||||||
#define RTAS_OUT_NOT_AUTHORIZED -9002
|
#define RTAS_OUT_NOT_AUTHORIZED -9002
|
||||||
|
|
||||||
/* RTAS tokens */
|
/* RTAS tokens */
|
||||||
|
@ -494,6 +494,11 @@ static inline uint32_t rtas_ld(target_ulong phys, int n)
|
||||||
return ldl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n));
|
return ldl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t rtas_ldq(target_ulong phys, int n)
|
||||||
|
{
|
||||||
|
return (uint64_t)rtas_ld(phys, n) << 32 | rtas_ld(phys, n + 1);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void rtas_st(target_ulong phys, int n, uint32_t val)
|
static inline void rtas_st(target_ulong phys, int n, uint32_t val)
|
||||||
{
|
{
|
||||||
stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val);
|
stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val);
|
||||||
|
@ -577,7 +582,8 @@ struct sPAPREventLogEntry {
|
||||||
void spapr_events_init(sPAPRMachineState *sm);
|
void spapr_events_init(sPAPRMachineState *sm);
|
||||||
void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq);
|
void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq);
|
||||||
int spapr_h_cas_compose_response(sPAPRMachineState *sm,
|
int spapr_h_cas_compose_response(sPAPRMachineState *sm,
|
||||||
target_ulong addr, target_ulong size);
|
target_ulong addr, target_ulong size,
|
||||||
|
bool cpu_update, bool memory_update);
|
||||||
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
|
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
|
||||||
uint64_t bus_offset,
|
uint64_t bus_offset,
|
||||||
uint32_t page_shift,
|
uint32_t page_shift,
|
||||||
|
@ -589,8 +595,12 @@ int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||||
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
|
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
|
||||||
sPAPRTCETable *tcet);
|
sPAPRTCETable *tcet);
|
||||||
void spapr_pci_switch_vga(bool big_endian);
|
void spapr_pci_switch_vga(bool big_endian);
|
||||||
void spapr_hotplug_req_add_event(sPAPRDRConnector *drc);
|
void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc);
|
||||||
void spapr_hotplug_req_remove_event(sPAPRDRConnector *drc);
|
void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc);
|
||||||
|
void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
|
||||||
|
uint32_t count);
|
||||||
|
void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
|
||||||
|
uint32_t count);
|
||||||
|
|
||||||
/* rtas-configure-connector state */
|
/* rtas-configure-connector state */
|
||||||
struct sPAPRConfigureConnectorState {
|
struct sPAPRConfigureConnectorState {
|
||||||
|
@ -603,10 +613,35 @@ struct sPAPRConfigureConnectorState {
|
||||||
void spapr_ccs_reset_hook(void *opaque);
|
void spapr_ccs_reset_hook(void *opaque);
|
||||||
|
|
||||||
#define TYPE_SPAPR_RTC "spapr-rtc"
|
#define TYPE_SPAPR_RTC "spapr-rtc"
|
||||||
|
#define TYPE_SPAPR_RNG "spapr-rng"
|
||||||
|
|
||||||
void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns);
|
void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns);
|
||||||
int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset);
|
int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset);
|
||||||
|
|
||||||
|
int spapr_rng_populate_dt(void *fdt);
|
||||||
|
|
||||||
#define SPAPR_MEMORY_BLOCK_SIZE (1 << 28) /* 256MB */
|
#define SPAPR_MEMORY_BLOCK_SIZE (1 << 28) /* 256MB */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This defines the maximum number of DIMM slots we can have for sPAPR
|
||||||
|
* guest. This is not defined by sPAPR but we are defining it to 32 slots
|
||||||
|
* based on default number of slots provided by PowerPC kernel.
|
||||||
|
*/
|
||||||
|
#define SPAPR_MAX_RAM_SLOTS 32
|
||||||
|
|
||||||
|
/* 1GB alignment for hotplug memory region */
|
||||||
|
#define SPAPR_HOTPLUG_MEM_ALIGN (1ULL << 30)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of 32 bit words in each LMB list entry in ibm,dynamic-memory
|
||||||
|
* property under ibm,dynamic-reconfiguration-memory node.
|
||||||
|
*/
|
||||||
|
#define SPAPR_DR_LMB_LIST_ENTRY_SIZE 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This flag value defines the LMB as assigned in ibm,dynamic-memory
|
||||||
|
* property under ibm,dynamic-reconfiguration-memory node.
|
||||||
|
*/
|
||||||
|
#define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008
|
||||||
|
|
||||||
#endif /* !defined (__HW_SPAPR_H__) */
|
#endif /* !defined (__HW_SPAPR_H__) */
|
||||||
|
|
|
@ -119,13 +119,14 @@ typedef enum {
|
||||||
} sPAPRDREntitySense;
|
} sPAPRDREntitySense;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPAPR_DR_CC_RESPONSE_NEXT_SIB = 1, /* currently unused */
|
SPAPR_DR_CC_RESPONSE_NEXT_SIB = 1, /* currently unused */
|
||||||
SPAPR_DR_CC_RESPONSE_NEXT_CHILD = 2,
|
SPAPR_DR_CC_RESPONSE_NEXT_CHILD = 2,
|
||||||
SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY = 3,
|
SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY = 3,
|
||||||
SPAPR_DR_CC_RESPONSE_PREV_PARENT = 4,
|
SPAPR_DR_CC_RESPONSE_PREV_PARENT = 4,
|
||||||
SPAPR_DR_CC_RESPONSE_SUCCESS = 0,
|
SPAPR_DR_CC_RESPONSE_SUCCESS = 0,
|
||||||
SPAPR_DR_CC_RESPONSE_ERROR = -1,
|
SPAPR_DR_CC_RESPONSE_ERROR = -1,
|
||||||
SPAPR_DR_CC_RESPONSE_CONTINUE = -2,
|
SPAPR_DR_CC_RESPONSE_CONTINUE = -2,
|
||||||
|
SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE = -9003,
|
||||||
} sPAPRDRCCResponse;
|
} sPAPRDRCCResponse;
|
||||||
|
|
||||||
typedef void (spapr_drc_detach_cb)(DeviceState *d, void *opaque);
|
typedef void (spapr_drc_detach_cb)(DeviceState *d, void *opaque);
|
||||||
|
@ -164,17 +165,17 @@ typedef struct sPAPRDRConnectorClass {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
/* accessors for guest-visible (generally via RTAS) DR state */
|
/* accessors for guest-visible (generally via RTAS) DR state */
|
||||||
int (*set_isolation_state)(sPAPRDRConnector *drc,
|
uint32_t (*set_isolation_state)(sPAPRDRConnector *drc,
|
||||||
sPAPRDRIsolationState state);
|
sPAPRDRIsolationState state);
|
||||||
int (*set_indicator_state)(sPAPRDRConnector *drc,
|
uint32_t (*set_indicator_state)(sPAPRDRConnector *drc,
|
||||||
sPAPRDRIndicatorState state);
|
sPAPRDRIndicatorState state);
|
||||||
int (*set_allocation_state)(sPAPRDRConnector *drc,
|
uint32_t (*set_allocation_state)(sPAPRDRConnector *drc,
|
||||||
sPAPRDRAllocationState state);
|
sPAPRDRAllocationState state);
|
||||||
uint32_t (*get_index)(sPAPRDRConnector *drc);
|
uint32_t (*get_index)(sPAPRDRConnector *drc);
|
||||||
uint32_t (*get_type)(sPAPRDRConnector *drc);
|
uint32_t (*get_type)(sPAPRDRConnector *drc);
|
||||||
const char *(*get_name)(sPAPRDRConnector *drc);
|
const char *(*get_name)(sPAPRDRConnector *drc);
|
||||||
|
|
||||||
sPAPRDREntitySense (*entity_sense)(sPAPRDRConnector *drc);
|
uint32_t (*entity_sense)(sPAPRDRConnector *drc, sPAPRDREntitySense *state);
|
||||||
|
|
||||||
/* QEMU interfaces for managing FDT/configure-connector */
|
/* QEMU interfaces for managing FDT/configure-connector */
|
||||||
const void *(*get_fdt)(sPAPRDRConnector *drc, int *fdt_start_offset);
|
const void *(*get_fdt)(sPAPRDRConnector *drc, int *fdt_start_offset);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||||
implementation for certain IBM POWER hardware. The sources are at
|
implementation for certain IBM POWER hardware. The sources are at
|
||||||
https://github.com/aik/SLOF, and the image currently in qemu is
|
https://github.com/aik/SLOF, and the image currently in qemu is
|
||||||
built from git tag qemu-slof-20150429.
|
built from git tag qemu-slof-20150813.
|
||||||
|
|
||||||
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
|
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
|
||||||
legacy x86 software to communicate with an attached serial console as
|
legacy x86 software to communicate with an attached serial console as
|
||||||
|
|
BIN
pc-bios/slof.bin
BIN
pc-bios/slof.bin
Binary file not shown.
|
@ -1 +1 @@
|
||||||
Subproject commit 7d766a3ac9b2474f6c7da0084d43590cbbf047bf
|
Subproject commit 811277ac91f674a9273e2b529791e9b75350f3e8
|
|
@ -1953,6 +1953,11 @@ void kvmppc_enable_logical_ci_hcalls(void)
|
||||||
kvmppc_enable_hcall(kvm_state, H_LOGICAL_CI_STORE);
|
kvmppc_enable_hcall(kvm_state, H_LOGICAL_CI_STORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvmppc_enable_set_mode_hcall(void)
|
||||||
|
{
|
||||||
|
kvmppc_enable_hcall(kvm_state, H_SET_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
void kvmppc_set_papr(PowerPCCPU *cpu)
|
void kvmppc_set_papr(PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
|
@ -2484,3 +2489,12 @@ int kvm_arch_msi_data_to_gsi(uint32_t data)
|
||||||
{
|
{
|
||||||
return data & 0xffff;
|
return data & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvmppc_enable_hwrng(void)
|
||||||
|
{
|
||||||
|
if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_PPC_HWRNG)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kvmppc_enable_hcall(kvm_state, H_RANDOM);
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ int kvmppc_get_hasidle(CPUPPCState *env);
|
||||||
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len);
|
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len);
|
||||||
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
|
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
|
||||||
void kvmppc_enable_logical_ci_hcalls(void);
|
void kvmppc_enable_logical_ci_hcalls(void);
|
||||||
|
void kvmppc_enable_set_mode_hcall(void);
|
||||||
void kvmppc_set_papr(PowerPCCPU *cpu);
|
void kvmppc_set_papr(PowerPCCPU *cpu);
|
||||||
int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
|
int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
|
||||||
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
|
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
|
||||||
|
@ -53,6 +54,7 @@ void kvmppc_hash64_free_pteg(uint64_t token);
|
||||||
void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
|
void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
|
||||||
target_ulong pte0, target_ulong pte1);
|
target_ulong pte0, target_ulong pte1);
|
||||||
bool kvmppc_has_cap_fixup_hcalls(void);
|
bool kvmppc_has_cap_fixup_hcalls(void);
|
||||||
|
int kvmppc_enable_hwrng(void);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -110,6 +112,10 @@ static inline void kvmppc_enable_logical_ci_hcalls(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void kvmppc_enable_set_mode_hcall(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline void kvmppc_set_papr(PowerPCCPU *cpu)
|
static inline void kvmppc_set_papr(PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -246,6 +252,10 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int kvmppc_enable_hwrng(void)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_KVM
|
#ifndef CONFIG_KVM
|
||||||
|
|
Loading…
Reference in New Issue