mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-5.0-20191217' into staging
ppc patch queue 2019-12-17
This is the first pull request for the qemu-5.0 branch. It has a lot
of accumulated changes, including:
* SLOF update to support boot using the IOMMU (will become
necessary for secure guests)
* Clean ups to pnv handling of chip models
* A number of extensions to the powernv machine model
* TCG extensions to allow powernv emulated systems to run KVM guests
* Outline support for POWER10 chips in powernv
* Cleanups to the ibm,client-architecture-support feature negotiation path
* XIVE reworks to better handle the powernv machine
* Improvements to not waste interrupt queues and other semi-scarce
resources when using XIVE under KVM
# gpg: Signature made Tue 17 Dec 2019 04:42:20 GMT
# gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-5.0-20191217: (88 commits)
pseries: Update SLOF firmware image
ppc/pnv: Drop PnvChipClass::type
ppc/pnv: Introduce PnvChipClass::xscom_pcba() method
ppc/pnv: Drop pnv_chip_is_power9() and pnv_chip_is_power10() helpers
ppc/pnv: Pass content of the "compatible" property to pnv_dt_xscom()
ppc/pnv: Pass XSCOM base address and address size to pnv_dt_xscom()
ppc/pnv: Introduce PnvChipClass::xscom_core_base() method
ppc/pnv: Introduce PnvChipClass::intc_print_info() method
ppc/pnv: Drop pnv_is_power9() and pnv_is_power10() helpers
ppc/pnv: Introduce PnvMachineClass::dt_power_mgt()
ppc/pnv: Introduce PnvMachineClass and PnvMachineClass::compat
ppc/pnv: Drop PnvPsiClass::chip_type
ppc/pnv: Introduce PnvPsiClass::compat
ppc: Drop useless extern annotation for functions
ppc/pnv: Fix OCC common area region mapping
ppc/pnv: Introduce PBA registers
ppc/pnv: Make PnvXScomInterface an incomplete type
ppc/pnv: populate the DT with realized XSCOM devices
ppc/pnv: Loop on the whole hierarchy to populate the DT with the XSCOM nodes
target/ppc: Add SPR TBU40
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+277
-138
File diff suppressed because it is too large
Load Diff
+90
-12
@@ -205,6 +205,35 @@ void spapr_xive_mmio_set_enabled(SpaprXive *xive, bool enable)
|
||||
memory_region_set_enabled(&xive->end_source.esb_mmio, false);
|
||||
}
|
||||
|
||||
static void spapr_xive_tm_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
XiveTCTX *tctx = spapr_cpu_state(POWERPC_CPU(current_cpu))->tctx;
|
||||
|
||||
xive_tctx_tm_write(XIVE_PRESENTER(opaque), tctx, offset, value, size);
|
||||
}
|
||||
|
||||
static uint64_t spapr_xive_tm_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
XiveTCTX *tctx = spapr_cpu_state(POWERPC_CPU(current_cpu))->tctx;
|
||||
|
||||
return xive_tctx_tm_read(XIVE_PRESENTER(opaque), tctx, offset, size);
|
||||
}
|
||||
|
||||
const MemoryRegionOps spapr_xive_tm_ops = {
|
||||
.read = spapr_xive_tm_read,
|
||||
.write = spapr_xive_tm_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
};
|
||||
|
||||
static void spapr_xive_end_reset(XiveEND *end)
|
||||
{
|
||||
memset(end, 0, sizeof(*end));
|
||||
@@ -276,8 +305,8 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp)
|
||||
*/
|
||||
object_property_set_int(OBJECT(xsrc), xive->nr_irqs, "nr-irqs",
|
||||
&error_fatal);
|
||||
object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(xive),
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(xsrc), OBJECT(xive), "xive",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -290,8 +319,8 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp)
|
||||
*/
|
||||
object_property_set_int(OBJECT(end_xsrc), xive->nr_irqs, "nr-ends",
|
||||
&error_fatal);
|
||||
object_property_add_const_link(OBJECT(end_xsrc), "xive", OBJECT(xive),
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(end_xsrc), OBJECT(xive), "xive",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(end_xsrc), true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -314,8 +343,8 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp)
|
||||
qemu_register_reset(spapr_xive_reset, dev);
|
||||
|
||||
/* TIMA initialization */
|
||||
memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive,
|
||||
"xive.tima", 4ull << TM_SHIFT);
|
||||
memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &spapr_xive_tm_ops,
|
||||
xive, "xive.tima", 4ull << TM_SHIFT);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio);
|
||||
|
||||
/*
|
||||
@@ -398,11 +427,55 @@ static int spapr_xive_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static XiveTCTX *spapr_xive_get_tctx(XiveRouter *xrtr, CPUState *cs)
|
||||
static int spapr_xive_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUState *cs;
|
||||
int count = 0;
|
||||
|
||||
return spapr_cpu_state(cpu)->tctx;
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
XiveTCTX *tctx = spapr_cpu_state(cpu)->tctx;
|
||||
int ring;
|
||||
|
||||
/*
|
||||
* Skip partially initialized vCPUs. This can happen when
|
||||
* vCPUs are hotplugged.
|
||||
*/
|
||||
if (!tctx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the thread context CAM lines and record matches.
|
||||
*/
|
||||
ring = xive_presenter_tctx_match(xptr, tctx, format, nvt_blk, nvt_idx,
|
||||
cam_ignore, logic_serv);
|
||||
/*
|
||||
* Save the matching thread interrupt context and follow on to
|
||||
* check for duplicates which are invalid.
|
||||
*/
|
||||
if (ring != -1) {
|
||||
if (match->tctx) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: already found a thread "
|
||||
"context NVT %x/%x\n", nvt_blk, nvt_idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
match->ring = ring;
|
||||
match->tctx = tctx;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static uint8_t spapr_xive_get_block_id(XiveRouter *xrtr)
|
||||
{
|
||||
return SPAPR_XIVE_BLOCK_ID;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_spapr_xive_end = {
|
||||
@@ -651,12 +724,14 @@ static void spapr_xive_dt(SpaprInterruptController *intc, uint32_t nr_servers,
|
||||
plat_res_int_priorities, sizeof(plat_res_int_priorities)));
|
||||
}
|
||||
|
||||
static int spapr_xive_activate(SpaprInterruptController *intc, Error **errp)
|
||||
static int spapr_xive_activate(SpaprInterruptController *intc,
|
||||
uint32_t nr_servers, Error **errp)
|
||||
{
|
||||
SpaprXive *xive = SPAPR_XIVE(intc);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
int rc = spapr_irq_init_kvm(kvmppc_xive_connect, intc, errp);
|
||||
int rc = spapr_irq_init_kvm(kvmppc_xive_connect, intc, nr_servers,
|
||||
errp);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
@@ -684,6 +759,7 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
|
||||
SpaprInterruptControllerClass *sicc = SPAPR_INTC_CLASS(klass);
|
||||
XivePresenterClass *xpc = XIVE_PRESENTER_CLASS(klass);
|
||||
|
||||
dc->desc = "sPAPR XIVE Interrupt Controller";
|
||||
dc->props = spapr_xive_properties;
|
||||
@@ -695,7 +771,7 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data)
|
||||
xrc->write_end = spapr_xive_write_end;
|
||||
xrc->get_nvt = spapr_xive_get_nvt;
|
||||
xrc->write_nvt = spapr_xive_write_nvt;
|
||||
xrc->get_tctx = spapr_xive_get_tctx;
|
||||
xrc->get_block_id = spapr_xive_get_block_id;
|
||||
|
||||
sicc->activate = spapr_xive_activate;
|
||||
sicc->deactivate = spapr_xive_deactivate;
|
||||
@@ -708,6 +784,8 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data)
|
||||
sicc->print_info = spapr_xive_print_info;
|
||||
sicc->dt = spapr_xive_dt;
|
||||
sicc->post_load = spapr_xive_post_load;
|
||||
|
||||
xpc->match_nvt = spapr_xive_match_nvt;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_xive_info = {
|
||||
|
||||
+25
-17
@@ -152,7 +152,8 @@ void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp)
|
||||
|
||||
void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
|
||||
{
|
||||
SpaprXive *xive = SPAPR_MACHINE(qdev_get_machine())->xive;
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
SpaprXive *xive = SPAPR_MACHINE(ms)->xive;
|
||||
unsigned long vcpu_id;
|
||||
int ret;
|
||||
|
||||
@@ -171,8 +172,16 @@ void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
|
||||
ret = kvm_vcpu_enable_cap(tctx->cs, KVM_CAP_PPC_IRQ_XIVE, 0, xive->fd,
|
||||
vcpu_id, 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "XIVE: unable to connect CPU%ld to KVM device: %s",
|
||||
Error *local_err = NULL;
|
||||
|
||||
error_setg(&local_err,
|
||||
"XIVE: unable to connect CPU%ld to KVM device: %s",
|
||||
vcpu_id, strerror(errno));
|
||||
if (errno == ENOSPC) {
|
||||
error_append_hint(&local_err, "Try -smp maxcpus=N with N < %u\n",
|
||||
ms->smp.max_cpus);
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -354,32 +363,20 @@ static void kvmppc_xive_source_get_state(XiveSource *xsrc)
|
||||
void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val)
|
||||
{
|
||||
XiveSource *xsrc = opaque;
|
||||
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
|
||||
struct kvm_irq_level args;
|
||||
int rc;
|
||||
|
||||
/* The KVM XIVE device should be in use */
|
||||
assert(xive->fd != -1);
|
||||
|
||||
args.irq = srcno;
|
||||
if (!xive_source_irq_is_lsi(xsrc, srcno)) {
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
args.level = KVM_INTERRUPT_SET;
|
||||
} else {
|
||||
if (val) {
|
||||
xsrc->status[srcno] |= XIVE_STATUS_ASSERTED;
|
||||
args.level = KVM_INTERRUPT_SET_LEVEL;
|
||||
} else {
|
||||
xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED;
|
||||
args.level = KVM_INTERRUPT_UNSET;
|
||||
}
|
||||
}
|
||||
rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args);
|
||||
if (rc < 0) {
|
||||
error_report("XIVE: kvm_irq_line() failed : %s", strerror(errno));
|
||||
}
|
||||
|
||||
xive_esb_trigger(xsrc, srcno);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -740,7 +737,8 @@ static void *kvmppc_xive_mmap(SpaprXive *xive, int pgoff, size_t len,
|
||||
* All the XIVE memory regions are now backed by mappings from the KVM
|
||||
* XIVE device.
|
||||
*/
|
||||
int kvmppc_xive_connect(SpaprInterruptController *intc, Error **errp)
|
||||
int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
|
||||
Error **errp)
|
||||
{
|
||||
SpaprXive *xive = SPAPR_XIVE(intc);
|
||||
XiveSource *xsrc = &xive->source;
|
||||
@@ -769,6 +767,16 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, Error **errp)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Tell KVM about the # of VCPUs we may have */
|
||||
if (kvm_device_check_attr(xive->fd, KVM_DEV_XIVE_GRP_CTRL,
|
||||
KVM_DEV_XIVE_NR_SERVERS)) {
|
||||
if (kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL,
|
||||
KVM_DEV_XIVE_NR_SERVERS, &nr_servers, true,
|
||||
&local_err)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Source ESB pages - KVM mapping
|
||||
*/
|
||||
|
||||
+16
-43
@@ -289,9 +289,6 @@ void icp_reset(ICPState *icp)
|
||||
icp->pending_priority = 0xff;
|
||||
icp->mfrr = 0xff;
|
||||
|
||||
/* Make all outputs are deasserted */
|
||||
qemu_set_irq(icp->output, 0);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -305,33 +302,13 @@ void icp_reset(ICPState *icp)
|
||||
static void icp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ICPState *icp = ICP(dev);
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
Object *obj;
|
||||
Error *err = NULL;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), ICP_PROP_XICS, &err);
|
||||
if (!obj) {
|
||||
error_propagate_prepend(errp, err,
|
||||
"required link '" ICP_PROP_XICS
|
||||
"' not found: ");
|
||||
return;
|
||||
}
|
||||
assert(icp->xics);
|
||||
assert(icp->cs);
|
||||
|
||||
icp->xics = XICS_FABRIC(obj);
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), ICP_PROP_CPU, &err);
|
||||
if (!obj) {
|
||||
error_propagate_prepend(errp, err,
|
||||
"required link '" ICP_PROP_CPU
|
||||
"' not found: ");
|
||||
return;
|
||||
}
|
||||
|
||||
cpu = POWERPC_CPU(obj);
|
||||
icp->cs = CPU(obj);
|
||||
|
||||
env = &cpu->env;
|
||||
env = &POWERPC_CPU(icp->cs)->env;
|
||||
switch (PPC_INPUT(env)) {
|
||||
case PPC_FLAGS_INPUT_POWER7:
|
||||
icp->output = env->irq_inputs[POWER7_INPUT_INT];
|
||||
@@ -368,12 +345,20 @@ static void icp_unrealize(DeviceState *dev, Error **errp)
|
||||
vmstate_unregister(NULL, &vmstate_icp_server, icp);
|
||||
}
|
||||
|
||||
static Property icp_properties[] = {
|
||||
DEFINE_PROP_LINK(ICP_PROP_XICS, ICPState, xics, TYPE_XICS_FABRIC,
|
||||
XICSFabric *),
|
||||
DEFINE_PROP_LINK(ICP_PROP_CPU, ICPState, cs, TYPE_CPU, CPUState *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void icp_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = icp_realize;
|
||||
dc->unrealize = icp_unrealize;
|
||||
dc->props = icp_properties;
|
||||
/*
|
||||
* Reason: part of XICS interrupt controller, needs to be wired up
|
||||
* by icp_create().
|
||||
@@ -397,11 +382,8 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp)
|
||||
obj = object_new(type);
|
||||
object_property_add_child(cpu, type, obj, &error_abort);
|
||||
object_unref(obj);
|
||||
object_ref(OBJECT(xi));
|
||||
object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(xi),
|
||||
&error_abort);
|
||||
object_ref(cpu);
|
||||
object_property_add_const_link(obj, ICP_PROP_CPU, cpu, &error_abort);
|
||||
object_property_set_link(obj, OBJECT(xi), ICP_PROP_XICS, &error_abort);
|
||||
object_property_set_link(obj, cpu, ICP_PROP_CPU, &error_abort);
|
||||
object_property_set_bool(obj, true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
object_unparent(obj);
|
||||
@@ -416,8 +398,6 @@ void icp_destroy(ICPState *icp)
|
||||
{
|
||||
Object *obj = OBJECT(icp);
|
||||
|
||||
object_unref(object_property_get_link(obj, ICP_PROP_CPU, &error_abort));
|
||||
object_unref(object_property_get_link(obj, ICP_PROP_XICS, &error_abort));
|
||||
object_unparent(obj);
|
||||
}
|
||||
|
||||
@@ -609,17 +589,8 @@ static void ics_reset_handler(void *dev)
|
||||
static void ics_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
Error *local_err = NULL;
|
||||
Object *obj;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &local_err);
|
||||
if (!obj) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"required link '" ICS_PROP_XICS
|
||||
"' not found: ");
|
||||
return;
|
||||
}
|
||||
ics->xics = XICS_FABRIC(obj);
|
||||
assert(ics->xics);
|
||||
|
||||
if (!ics->nr_irqs) {
|
||||
error_setg(errp, "Number of interrupts needs to be greater 0");
|
||||
@@ -699,6 +670,8 @@ static const VMStateDescription vmstate_ics = {
|
||||
|
||||
static Property ics_properties[] = {
|
||||
DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0),
|
||||
DEFINE_PROP_LINK(ICS_PROP_XICS, ICSState, xics, TYPE_XICS_FABRIC,
|
||||
XICSFabric *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
+21
-3
@@ -165,8 +165,15 @@ void icp_kvm_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, vcpu_id);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to connect CPU%ld to kernel XICS: %s", vcpu_id,
|
||||
strerror(errno));
|
||||
Error *local_err = NULL;
|
||||
|
||||
error_setg(&local_err, "Unable to connect CPU%ld to kernel XICS: %s",
|
||||
vcpu_id, strerror(errno));
|
||||
if (errno == ENOSPC) {
|
||||
error_append_hint(&local_err, "Try -smp maxcpus=N with N < %u\n",
|
||||
MACHINE(qdev_get_machine())->smp.max_cpus);
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
enabled_icp = g_malloc(sizeof(*enabled_icp));
|
||||
@@ -342,7 +349,8 @@ void ics_kvm_set_irq(ICSState *ics, int srcno, int val)
|
||||
}
|
||||
}
|
||||
|
||||
int xics_kvm_connect(SpaprInterruptController *intc, Error **errp)
|
||||
int xics_kvm_connect(SpaprInterruptController *intc, uint32_t nr_servers,
|
||||
Error **errp)
|
||||
{
|
||||
ICSState *ics = ICS_SPAPR(intc);
|
||||
int rc;
|
||||
@@ -398,6 +406,16 @@ int xics_kvm_connect(SpaprInterruptController *intc, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Tell KVM about the # of VCPUs we may have (POWER9 and newer only) */
|
||||
if (kvm_device_check_attr(rc, KVM_DEV_XICS_GRP_CTRL,
|
||||
KVM_DEV_XICS_NR_SERVERS)) {
|
||||
if (kvm_device_access(rc, KVM_DEV_XICS_GRP_CTRL,
|
||||
KVM_DEV_XICS_NR_SERVERS, &nr_servers, true,
|
||||
&local_err)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_xics_fd = rc;
|
||||
kvm_kernel_irqchip = true;
|
||||
kvm_msi_via_irqfd_allowed = true;
|
||||
|
||||
@@ -422,10 +422,11 @@ static int xics_spapr_post_load(SpaprInterruptController *intc, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xics_spapr_activate(SpaprInterruptController *intc, Error **errp)
|
||||
static int xics_spapr_activate(SpaprInterruptController *intc,
|
||||
uint32_t nr_servers, Error **errp)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
return spapr_irq_init_kvm(xics_kvm_connect, intc, errp);
|
||||
return spapr_irq_init_kvm(xics_kvm_connect, intc, nr_servers, errp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+215
-185
File diff suppressed because it is too large
Load Diff
+6
-44
@@ -167,32 +167,14 @@ typedef struct IPMISensor {
|
||||
#define MAX_SENSORS 20
|
||||
#define IPMI_WATCHDOG_SENSOR 0
|
||||
|
||||
typedef struct IPMIBmcSim IPMIBmcSim;
|
||||
typedef struct RspBuffer RspBuffer;
|
||||
|
||||
#define MAX_NETFNS 64
|
||||
|
||||
typedef struct IPMICmdHandler {
|
||||
void (*cmd_handler)(IPMIBmcSim *s,
|
||||
uint8_t *cmd, unsigned int cmd_len,
|
||||
RspBuffer *rsp);
|
||||
unsigned int cmd_len_min;
|
||||
} IPMICmdHandler;
|
||||
|
||||
typedef struct IPMINetfn {
|
||||
unsigned int cmd_nums;
|
||||
const IPMICmdHandler *cmd_handlers;
|
||||
} IPMINetfn;
|
||||
|
||||
typedef struct IPMIRcvBufEntry {
|
||||
QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
|
||||
uint8_t len;
|
||||
uint8_t buf[MAX_IPMI_MSG_SIZE];
|
||||
} IPMIRcvBufEntry;
|
||||
|
||||
#define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
|
||||
#define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
|
||||
TYPE_IPMI_BMC_SIMULATOR)
|
||||
struct IPMIBmcSim {
|
||||
IPMIBmc parent;
|
||||
|
||||
@@ -279,28 +261,8 @@ struct IPMIBmcSim {
|
||||
#define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
|
||||
#define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
|
||||
|
||||
struct RspBuffer {
|
||||
uint8_t buffer[MAX_IPMI_MSG_SIZE];
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
#define RSP_BUFFER_INITIALIZER { }
|
||||
|
||||
static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
|
||||
{
|
||||
rsp->buffer[2] = byte;
|
||||
}
|
||||
|
||||
/* Add a byte to the response. */
|
||||
static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
|
||||
{
|
||||
if (rsp->len >= sizeof(rsp->buffer)) {
|
||||
rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
|
||||
return;
|
||||
}
|
||||
rsp->buffer[rsp->len++] = byte;
|
||||
}
|
||||
|
||||
static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
|
||||
unsigned int n)
|
||||
{
|
||||
@@ -630,8 +592,8 @@ static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
|
||||
}
|
||||
}
|
||||
|
||||
static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
|
||||
const IPMINetfn *netfnd)
|
||||
int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
|
||||
const IPMINetfn *netfnd)
|
||||
{
|
||||
if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
|
||||
return -1;
|
||||
@@ -1860,10 +1822,10 @@ static const IPMINetfn storage_netfn = {
|
||||
|
||||
static void register_cmds(IPMIBmcSim *s)
|
||||
{
|
||||
ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
|
||||
ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
|
||||
ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
|
||||
ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
|
||||
ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
|
||||
ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
|
||||
ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
|
||||
ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
|
||||
}
|
||||
|
||||
static uint8_t init_sdrs[] = {
|
||||
|
||||
@@ -9,7 +9,9 @@ obj-$(CONFIG_PSERIES) += spapr_tpm_proxy.o
|
||||
obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o
|
||||
# IBM PowerNV
|
||||
obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o
|
||||
obj-$(CONFIG_POWERNV) += pnv_homer.o
|
||||
obj-$(CONFIG_POWERNV) += pnv_homer.o pnv_pnor.o
|
||||
|
||||
|
||||
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
|
||||
obj-y += spapr_pci_vfio.o spapr_pci_nvlink2.o
|
||||
endif
|
||||
|
||||
+419
-85
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "target/ppc/cpu.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/ipmi/ipmi.h"
|
||||
@@ -114,3 +116,117 @@ void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt)
|
||||
sdr->sensor_type)));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* HIOMAP protocol handler
|
||||
*/
|
||||
#define HIOMAP_C_RESET 1
|
||||
#define HIOMAP_C_GET_INFO 2
|
||||
#define HIOMAP_C_GET_FLASH_INFO 3
|
||||
#define HIOMAP_C_CREATE_READ_WINDOW 4
|
||||
#define HIOMAP_C_CLOSE_WINDOW 5
|
||||
#define HIOMAP_C_CREATE_WRITE_WINDOW 6
|
||||
#define HIOMAP_C_MARK_DIRTY 7
|
||||
#define HIOMAP_C_FLUSH 8
|
||||
#define HIOMAP_C_ACK 9
|
||||
#define HIOMAP_C_ERASE 10
|
||||
#define HIOMAP_C_DEVICE_NAME 11
|
||||
#define HIOMAP_C_LOCK 12
|
||||
|
||||
#define BLOCK_SHIFT 12 /* 4K */
|
||||
|
||||
static uint16_t bytes_to_blocks(uint32_t bytes)
|
||||
{
|
||||
return bytes >> BLOCK_SHIFT;
|
||||
}
|
||||
|
||||
static void hiomap_cmd(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len,
|
||||
RspBuffer *rsp)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
|
||||
PnvPnor *pnor = pnv->pnor;
|
||||
uint32_t pnor_size = pnor->size;
|
||||
uint32_t pnor_addr = PNOR_SPI_OFFSET;
|
||||
bool readonly = false;
|
||||
|
||||
rsp_buffer_push(rsp, cmd[2]);
|
||||
rsp_buffer_push(rsp, cmd[3]);
|
||||
|
||||
switch (cmd[2]) {
|
||||
case HIOMAP_C_MARK_DIRTY:
|
||||
case HIOMAP_C_FLUSH:
|
||||
case HIOMAP_C_ERASE:
|
||||
case HIOMAP_C_ACK:
|
||||
break;
|
||||
|
||||
case HIOMAP_C_GET_INFO:
|
||||
rsp_buffer_push(rsp, 2); /* Version 2 */
|
||||
rsp_buffer_push(rsp, BLOCK_SHIFT); /* block size */
|
||||
rsp_buffer_push(rsp, 0); /* Timeout */
|
||||
rsp_buffer_push(rsp, 0); /* Timeout */
|
||||
break;
|
||||
|
||||
case HIOMAP_C_GET_FLASH_INFO:
|
||||
rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) & 0xFF);
|
||||
rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) >> 8);
|
||||
rsp_buffer_push(rsp, 0x01); /* erase size */
|
||||
rsp_buffer_push(rsp, 0x00); /* erase size */
|
||||
break;
|
||||
|
||||
case HIOMAP_C_CREATE_READ_WINDOW:
|
||||
readonly = true;
|
||||
/* Fall through */
|
||||
|
||||
case HIOMAP_C_CREATE_WRITE_WINDOW:
|
||||
memory_region_set_readonly(&pnor->mmio, readonly);
|
||||
memory_region_set_enabled(&pnor->mmio, true);
|
||||
|
||||
rsp_buffer_push(rsp, bytes_to_blocks(pnor_addr) & 0xFF);
|
||||
rsp_buffer_push(rsp, bytes_to_blocks(pnor_addr) >> 8);
|
||||
rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) & 0xFF);
|
||||
rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) >> 8);
|
||||
rsp_buffer_push(rsp, 0x00); /* offset */
|
||||
rsp_buffer_push(rsp, 0x00); /* offset */
|
||||
break;
|
||||
|
||||
case HIOMAP_C_CLOSE_WINDOW:
|
||||
memory_region_set_enabled(&pnor->mmio, false);
|
||||
break;
|
||||
|
||||
case HIOMAP_C_DEVICE_NAME:
|
||||
case HIOMAP_C_RESET:
|
||||
case HIOMAP_C_LOCK:
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "HIOMAP: unknow command %02X\n", cmd[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define HIOMAP 0x5a
|
||||
|
||||
static const IPMICmdHandler hiomap_cmds[] = {
|
||||
[HIOMAP] = { hiomap_cmd, 3 },
|
||||
};
|
||||
|
||||
static const IPMINetfn hiomap_netfn = {
|
||||
.cmd_nums = ARRAY_SIZE(hiomap_cmds),
|
||||
.cmd_handlers = hiomap_cmds
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiate the machine BMC. PowerNV uses the QEMU internal
|
||||
* simulator but it could also be external.
|
||||
*/
|
||||
IPMIBmc *pnv_bmc_create(void)
|
||||
{
|
||||
Object *obj;
|
||||
|
||||
obj = object_new(TYPE_IPMI_BMC_SIMULATOR);
|
||||
object_property_set_bool(obj, true, "realized", &error_fatal);
|
||||
|
||||
/* Install the HIOMAP protocol handlers to access the PNOR */
|
||||
ipmi_sim_register_netfn(IPMI_BMC_SIMULATOR(obj), IPMI_NETFN_OEM,
|
||||
&hiomap_netfn);
|
||||
|
||||
return IPMI_BMC(obj);
|
||||
}
|
||||
|
||||
+12
-8
@@ -217,15 +217,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
|
||||
void *obj;
|
||||
int i, j;
|
||||
char name[32];
|
||||
Object *chip;
|
||||
|
||||
chip = object_property_get_link(OBJECT(dev), "chip", &local_err);
|
||||
if (!chip) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"required link 'chip' not found: ");
|
||||
return;
|
||||
}
|
||||
pc->chip = PNV_CHIP(chip);
|
||||
assert(pc->chip);
|
||||
|
||||
pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
|
||||
for (i = 0; i < cc->nr_threads; i++) {
|
||||
@@ -254,6 +247,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
|
||||
/* TODO: check PNV_XSCOM_EX_SIZE for p10 */
|
||||
pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
|
||||
pc, name, PNV_XSCOM_EX_SIZE);
|
||||
|
||||
@@ -297,6 +291,7 @@ static void pnv_core_unrealize(DeviceState *dev, Error **errp)
|
||||
|
||||
static Property pnv_core_properties[] = {
|
||||
DEFINE_PROP_UINT32("pir", PnvCore, pir, 0),
|
||||
DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -314,6 +309,14 @@ static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
|
||||
pcc->xscom_ops = &pnv_core_power9_xscom_ops;
|
||||
}
|
||||
|
||||
static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
|
||||
|
||||
/* TODO: Use the P9 XSCOMs for now on P10 */
|
||||
pcc->xscom_ops = &pnv_core_power9_xscom_ops;
|
||||
}
|
||||
|
||||
static void pnv_core_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
@@ -343,6 +346,7 @@ static const TypeInfo pnv_core_infos[] = {
|
||||
DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
|
||||
DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
|
||||
DEFINE_PNV_CORE_TYPE(power9, "power9_v2.0"),
|
||||
DEFINE_PNV_CORE_TYPE(power10, "power10_v1.0"),
|
||||
};
|
||||
|
||||
DEFINE_TYPES(pnv_core_infos)
|
||||
|
||||
+118
-9
@@ -17,13 +17,16 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qapi/error.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "exec/memory.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/ppc/pnv.h"
|
||||
#include "hw/ppc/pnv_homer.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
|
||||
|
||||
static bool core_max_array(PnvHomer *homer, hwaddr addr)
|
||||
@@ -113,10 +116,67 @@ static const MemoryRegionOps pnv_power8_homer_ops = {
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
/* P8 PBA BARs */
|
||||
#define PBA_BAR0 0x00
|
||||
#define PBA_BAR1 0x01
|
||||
#define PBA_BAR2 0x02
|
||||
#define PBA_BAR3 0x03
|
||||
#define PBA_BARMASK0 0x04
|
||||
#define PBA_BARMASK1 0x05
|
||||
#define PBA_BARMASK2 0x06
|
||||
#define PBA_BARMASK3 0x07
|
||||
|
||||
static uint64_t pnv_homer_power8_pba_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
PnvHomer *homer = PNV_HOMER(opaque);
|
||||
PnvChip *chip = homer->chip;
|
||||
uint32_t reg = addr >> 3;
|
||||
uint64_t val = 0;
|
||||
|
||||
switch (reg) {
|
||||
case PBA_BAR0:
|
||||
val = PNV_HOMER_BASE(chip);
|
||||
break;
|
||||
case PBA_BARMASK0: /* P8 homer region mask */
|
||||
val = (PNV_HOMER_SIZE - 1) & 0x300000;
|
||||
break;
|
||||
case PBA_BAR3: /* P8 occ common area */
|
||||
val = PNV_OCC_COMMON_AREA_BASE;
|
||||
break;
|
||||
case PBA_BARMASK3: /* P8 occ common area mask */
|
||||
val = (PNV_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
|
||||
HWADDR_PRIx "\n", addr >> 3);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pnv_homer_power8_pba_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
|
||||
HWADDR_PRIx "\n", addr >> 3);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pnv_homer_power8_pba_ops = {
|
||||
.read = pnv_homer_power8_pba_read,
|
||||
.write = pnv_homer_power8_pba_write,
|
||||
.valid.min_access_size = 8,
|
||||
.valid.max_access_size = 8,
|
||||
.impl.min_access_size = 8,
|
||||
.impl.max_access_size = 8,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void pnv_homer_power8_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
|
||||
|
||||
homer->pba_size = PNV_XSCOM_PBA_SIZE;
|
||||
homer->pba_ops = &pnv_homer_power8_pba_ops;
|
||||
homer->homer_size = PNV_HOMER_SIZE;
|
||||
homer->homer_ops = &pnv_power8_homer_ops;
|
||||
homer->core_max_base = PNV8_CORE_MAX_BASE;
|
||||
@@ -209,10 +269,57 @@ static const MemoryRegionOps pnv_power9_homer_ops = {
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static uint64_t pnv_homer_power9_pba_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
PnvHomer *homer = PNV_HOMER(opaque);
|
||||
PnvChip *chip = homer->chip;
|
||||
uint32_t reg = addr >> 3;
|
||||
uint64_t val = 0;
|
||||
|
||||
switch (reg) {
|
||||
case PBA_BAR0:
|
||||
val = PNV9_HOMER_BASE(chip);
|
||||
break;
|
||||
case PBA_BARMASK0: /* P9 homer region mask */
|
||||
val = (PNV9_HOMER_SIZE - 1) & 0x300000;
|
||||
break;
|
||||
case PBA_BAR2: /* P9 occ common area */
|
||||
val = PNV9_OCC_COMMON_AREA_BASE;
|
||||
break;
|
||||
case PBA_BARMASK2: /* P9 occ common area size */
|
||||
val = (PNV9_OCC_COMMON_AREA_SIZE - 1) & 0x700000;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "PBA: read to unimplemented register: Ox%"
|
||||
HWADDR_PRIx "\n", addr >> 3);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pnv_homer_power9_pba_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "PBA: write to unimplemented register: Ox%"
|
||||
HWADDR_PRIx "\n", addr >> 3);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pnv_homer_power9_pba_ops = {
|
||||
.read = pnv_homer_power9_pba_read,
|
||||
.write = pnv_homer_power9_pba_write,
|
||||
.valid.min_access_size = 8,
|
||||
.valid.max_access_size = 8,
|
||||
.impl.min_access_size = 8,
|
||||
.impl.max_access_size = 8,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void pnv_homer_power9_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
|
||||
|
||||
homer->pba_size = PNV9_XSCOM_PBA_SIZE;
|
||||
homer->pba_ops = &pnv_homer_power9_pba_ops;
|
||||
homer->homer_size = PNV9_HOMER_SIZE;
|
||||
homer->homer_ops = &pnv_power9_homer_ops;
|
||||
homer->core_max_base = PNV9_CORE_MAX_BASE;
|
||||
@@ -229,28 +336,30 @@ static void pnv_homer_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PnvHomer *homer = PNV_HOMER(dev);
|
||||
PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
|
||||
Object *obj;
|
||||
Error *local_err = NULL;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), "chip", &local_err);
|
||||
if (!obj) {
|
||||
error_propagate(errp, local_err);
|
||||
error_prepend(errp, "required link 'chip' not found: ");
|
||||
return;
|
||||
}
|
||||
homer->chip = PNV_CHIP(obj);
|
||||
assert(homer->chip);
|
||||
|
||||
pnv_xscom_region_init(&homer->pba_regs, OBJECT(dev), hmrc->pba_ops,
|
||||
homer, "xscom-pba", hmrc->pba_size);
|
||||
|
||||
/* homer region */
|
||||
memory_region_init_io(&homer->regs, OBJECT(dev),
|
||||
hmrc->homer_ops, homer, "homer-main-memory",
|
||||
hmrc->homer_size);
|
||||
}
|
||||
|
||||
static Property pnv_homer_properties[] = {
|
||||
DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pnv_homer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = pnv_homer_realize;
|
||||
dc->desc = "PowerNV HOMER Memory";
|
||||
dc->props = pnv_homer_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_homer_type_info = {
|
||||
|
||||
+56
-20
@@ -24,7 +24,7 @@
|
||||
#include "qemu/module.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/isa/isa.h"
|
||||
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/ppc/pnv.h"
|
||||
#include "hw/ppc/pnv_lpc.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
@@ -86,7 +86,7 @@ enum {
|
||||
#define ISA_FW_SIZE 0x10000000
|
||||
#define LPC_IO_OPB_ADDR 0xd0010000
|
||||
#define LPC_IO_OPB_SIZE 0x00010000
|
||||
#define LPC_MEM_OPB_ADDR 0xe0010000
|
||||
#define LPC_MEM_OPB_ADDR 0xe0000000
|
||||
#define LPC_MEM_OPB_SIZE 0x10000000
|
||||
#define LPC_FW_OPB_ADDR 0xf0000000
|
||||
#define LPC_FW_OPB_SIZE 0x10000000
|
||||
@@ -122,26 +122,36 @@ static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
|
||||
}
|
||||
|
||||
/* POWER9 only */
|
||||
int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset)
|
||||
int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset, uint64_t lpcm_addr,
|
||||
uint64_t lpcm_size)
|
||||
{
|
||||
const char compat[] = "ibm,power9-lpcm-opb\0simple-bus";
|
||||
const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc";
|
||||
char *name;
|
||||
int offset, lpcm_offset;
|
||||
uint64_t lpcm_addr = PNV9_LPCM_BASE(chip);
|
||||
uint32_t opb_ranges[8] = { 0,
|
||||
cpu_to_be32(lpcm_addr >> 32),
|
||||
cpu_to_be32((uint32_t)lpcm_addr),
|
||||
cpu_to_be32(PNV9_LPCM_SIZE / 2),
|
||||
cpu_to_be32(PNV9_LPCM_SIZE / 2),
|
||||
cpu_to_be32(lpcm_size / 2),
|
||||
cpu_to_be32(lpcm_size / 2),
|
||||
cpu_to_be32(lpcm_addr >> 32),
|
||||
cpu_to_be32(PNV9_LPCM_SIZE / 2),
|
||||
cpu_to_be32(PNV9_LPCM_SIZE / 2),
|
||||
cpu_to_be32(lpcm_size / 2),
|
||||
cpu_to_be32(lpcm_size / 2),
|
||||
};
|
||||
uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32),
|
||||
cpu_to_be32((uint32_t)lpcm_addr),
|
||||
cpu_to_be32(PNV9_LPCM_SIZE >> 32),
|
||||
cpu_to_be32((uint32_t)PNV9_LPCM_SIZE),
|
||||
cpu_to_be32(lpcm_size >> 32),
|
||||
cpu_to_be32((uint32_t)lpcm_size),
|
||||
};
|
||||
uint32_t lpc_ranges[12] = { 0, 0,
|
||||
cpu_to_be32(LPC_MEM_OPB_ADDR),
|
||||
cpu_to_be32(LPC_MEM_OPB_SIZE),
|
||||
cpu_to_be32(1), 0,
|
||||
cpu_to_be32(LPC_IO_OPB_ADDR),
|
||||
cpu_to_be32(LPC_IO_OPB_SIZE),
|
||||
cpu_to_be32(3), 0,
|
||||
cpu_to_be32(LPC_FW_OPB_ADDR),
|
||||
cpu_to_be32(LPC_FW_OPB_SIZE),
|
||||
};
|
||||
uint32_t reg[2];
|
||||
|
||||
@@ -211,6 +221,8 @@ int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset)
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
|
||||
_FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat,
|
||||
sizeof(lpc_compat))));
|
||||
_FDT((fdt_setprop(fdt, offset, "ranges", lpc_ranges,
|
||||
sizeof(lpc_ranges))));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -679,20 +691,24 @@ static const TypeInfo pnv_lpc_power9_info = {
|
||||
.class_init = pnv_lpc_power9_class_init,
|
||||
};
|
||||
|
||||
static void pnv_lpc_power10_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "PowerNV LPC Controller POWER10";
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_lpc_power10_info = {
|
||||
.name = TYPE_PNV10_LPC,
|
||||
.parent = TYPE_PNV9_LPC,
|
||||
.class_init = pnv_lpc_power10_class_init,
|
||||
};
|
||||
|
||||
static void pnv_lpc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PnvLpcController *lpc = PNV_LPC(dev);
|
||||
Object *obj;
|
||||
Error *local_err = NULL;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
|
||||
if (!obj) {
|
||||
error_propagate(errp, local_err);
|
||||
error_prepend(errp, "required link 'psi' not found: ");
|
||||
return;
|
||||
}
|
||||
/* The LPC controller needs PSI to generate interrupts */
|
||||
lpc->psi = PNV_PSI(obj);
|
||||
assert(lpc->psi);
|
||||
|
||||
/* Reg inits */
|
||||
lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B;
|
||||
@@ -734,12 +750,18 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
|
||||
&lpc->lpc_hc_regs);
|
||||
}
|
||||
|
||||
static Property pnv_lpc_properties[] = {
|
||||
DEFINE_PROP_LINK("psi", PnvLpcController, psi, TYPE_PNV_PSI, PnvPsi *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pnv_lpc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = pnv_lpc_realize;
|
||||
dc->desc = "PowerNV LPC Controller";
|
||||
dc->props = pnv_lpc_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_lpc_info = {
|
||||
@@ -755,6 +777,7 @@ static void pnv_lpc_register_types(void)
|
||||
type_register_static(&pnv_lpc_info);
|
||||
type_register_static(&pnv_lpc_power8_info);
|
||||
type_register_static(&pnv_lpc_power9_info);
|
||||
type_register_static(&pnv_lpc_power10_info);
|
||||
}
|
||||
|
||||
type_init(pnv_lpc_register_types)
|
||||
@@ -801,6 +824,7 @@ ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
|
||||
ISABus *isa_bus;
|
||||
qemu_irq *irqs;
|
||||
qemu_irq_handler handler;
|
||||
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
|
||||
|
||||
/* let isa_bus_new() create its own bridge on SysBus otherwise
|
||||
* devices speficied on the command line won't find the bus and
|
||||
@@ -825,5 +849,17 @@ ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
|
||||
irqs = qemu_allocate_irqs(handler, lpc, ISA_NUM_IRQS);
|
||||
|
||||
isa_bus_irqs(isa_bus, irqs);
|
||||
|
||||
/*
|
||||
* TODO: Map PNOR on the LPC FW address space on demand ?
|
||||
*/
|
||||
memory_region_add_subregion(&lpc->isa_fw, PNOR_SPI_OFFSET,
|
||||
&pnv->pnor->mmio);
|
||||
/*
|
||||
* Start disabled. The HIOMAP protocol will activate the mapping
|
||||
* with HIOMAP_C_CREATE_WRITE_WINDOW
|
||||
*/
|
||||
memory_region_set_enabled(&pnv->pnor->mmio, false);
|
||||
|
||||
return isa_bus;
|
||||
}
|
||||
|
||||
+13
-18
@@ -21,7 +21,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/ppc/pnv.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
#include "hw/ppc/pnv_occ.h"
|
||||
@@ -167,9 +167,7 @@ static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
|
||||
PnvOCCClass *poc = PNV_OCC_CLASS(klass);
|
||||
|
||||
poc->xscom_size = PNV_XSCOM_OCC_SIZE;
|
||||
poc->sram_size = PNV_OCC_COMMON_AREA_SIZE;
|
||||
poc->xscom_ops = &pnv_occ_power8_xscom_ops;
|
||||
poc->sram_ops = &pnv_occ_sram_ops;
|
||||
poc->psi_irq = PSIHB_IRQ_OCC;
|
||||
}
|
||||
|
||||
@@ -240,9 +238,7 @@ static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
|
||||
PnvOCCClass *poc = PNV_OCC_CLASS(klass);
|
||||
|
||||
poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
|
||||
poc->sram_size = PNV9_OCC_COMMON_AREA_SIZE;
|
||||
poc->xscom_ops = &pnv_occ_power9_xscom_ops;
|
||||
poc->sram_ops = &pnv_occ_sram_ops;
|
||||
poc->psi_irq = PSIHB9_IRQ_OCC;
|
||||
}
|
||||
|
||||
@@ -257,34 +253,33 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PnvOCC *occ = PNV_OCC(dev);
|
||||
PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
|
||||
Object *obj;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(occ->psi);
|
||||
|
||||
occ->occmisc = 0;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
|
||||
if (!obj) {
|
||||
error_propagate(errp, local_err);
|
||||
error_prepend(errp, "required link 'psi' not found: ");
|
||||
return;
|
||||
}
|
||||
occ->psi = PNV_PSI(obj);
|
||||
|
||||
/* XScom region for OCC registers */
|
||||
pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
|
||||
occ, "xscom-occ", poc->xscom_size);
|
||||
|
||||
/* XScom region for OCC SRAM registers */
|
||||
pnv_xscom_region_init(&occ->sram_regs, OBJECT(dev), poc->sram_ops,
|
||||
occ, "occ-common-area", poc->sram_size);
|
||||
/* OCC common area mmio region for OCC SRAM registers */
|
||||
memory_region_init_io(&occ->sram_regs, OBJECT(dev), &pnv_occ_sram_ops,
|
||||
occ, "occ-common-area",
|
||||
PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static Property pnv_occ_properties[] = {
|
||||
DEFINE_PROP_LINK("psi", PnvOCC, psi, TYPE_PNV_PSI, PnvPsi *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pnv_occ_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = pnv_occ_realize;
|
||||
dc->desc = "PowerNV OCC Controller";
|
||||
dc->props = pnv_occ_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_occ_type_info = {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* QEMU PowerNV PNOR simple model
|
||||
*
|
||||
* Copyright (c) 2015-2019, IBM Corporation.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/ppc/pnv_pnor.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
||||
static uint64_t pnv_pnor_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
PnvPnor *s = PNV_PNOR(opaque);
|
||||
uint64_t ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
ret |= (uint64_t) s->storage[addr + i] << (8 * (size - i - 1));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pnv_pnor_update(PnvPnor *s, int offset, int size)
|
||||
{
|
||||
int offset_end;
|
||||
|
||||
if (s->blk) {
|
||||
return;
|
||||
}
|
||||
|
||||
offset_end = offset + size;
|
||||
offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
|
||||
offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
|
||||
|
||||
blk_pwrite(s->blk, offset, s->storage + offset,
|
||||
offset_end - offset, 0);
|
||||
}
|
||||
|
||||
static void pnv_pnor_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned size)
|
||||
{
|
||||
PnvPnor *s = PNV_PNOR(opaque);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
s->storage[addr + i] = (data >> (8 * (size - i - 1))) & 0xFF;
|
||||
}
|
||||
pnv_pnor_update(s, addr, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Check endianness: skiboot is BIG, Aspeed AHB is LITTLE, flash
|
||||
* is BIG.
|
||||
*/
|
||||
static const MemoryRegionOps pnv_pnor_ops = {
|
||||
.read = pnv_pnor_read,
|
||||
.write = pnv_pnor_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void pnv_pnor_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PnvPnor *s = PNV_PNOR(dev);
|
||||
int ret;
|
||||
|
||||
if (s->blk) {
|
||||
uint64_t perm = BLK_PERM_CONSISTENT_READ |
|
||||
(blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
|
||||
ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->size = blk_getlength(s->blk);
|
||||
if (s->size <= 0) {
|
||||
error_setg(errp, "failed to get flash size");
|
||||
return;
|
||||
}
|
||||
|
||||
s->storage = blk_blockalign(s->blk, s->size);
|
||||
|
||||
if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) {
|
||||
error_setg(errp, "failed to read the initial flash content");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
s->storage = blk_blockalign(NULL, s->size);
|
||||
memset(s->storage, 0xFF, s->size);
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &pnv_pnor_ops, s,
|
||||
TYPE_PNV_PNOR, s->size);
|
||||
}
|
||||
|
||||
static Property pnv_pnor_properties[] = {
|
||||
DEFINE_PROP_UINT32("size", PnvPnor, size, 128 << 20),
|
||||
DEFINE_PROP_DRIVE("drive", PnvPnor, blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pnv_pnor_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = pnv_pnor_realize;
|
||||
dc->props = pnv_pnor_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_pnor_info = {
|
||||
.name = TYPE_PNV_PNOR,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PnvPnor),
|
||||
.class_init = pnv_pnor_class_init,
|
||||
};
|
||||
|
||||
static void pnv_pnor_register_types(void)
|
||||
{
|
||||
type_register_static(&pnv_pnor_info);
|
||||
}
|
||||
|
||||
type_init(pnv_pnor_register_types)
|
||||
+36
-18
@@ -497,8 +497,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* Create PSI interrupt control source */
|
||||
object_property_add_const_link(OBJECT(ics), ICS_PROP_XICS, obj,
|
||||
&error_abort);
|
||||
object_property_set_link(OBJECT(ics), obj, ICS_PROP_XICS, &error_abort);
|
||||
object_property_set_int(OBJECT(ics), PSI_NUM_INTERRUPTS, "nr-irqs", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
@@ -537,9 +536,6 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
|
||||
qemu_register_reset(pnv_psi_reset, dev);
|
||||
}
|
||||
|
||||
static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
|
||||
static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
|
||||
|
||||
static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
|
||||
{
|
||||
PnvPsiClass *ppc = PNV_PSI_GET_CLASS(dev);
|
||||
@@ -558,13 +554,8 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
|
||||
_FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
|
||||
_FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
|
||||
_FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
|
||||
if (ppc->chip_type == PNV_CHIP_POWER9) {
|
||||
_FDT(fdt_setprop(fdt, offset, "compatible", compat_p9,
|
||||
sizeof(compat_p9)));
|
||||
} else {
|
||||
_FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
|
||||
sizeof(compat_p8)));
|
||||
}
|
||||
_FDT(fdt_setprop(fdt, offset, "compatible", ppc->compat,
|
||||
ppc->compat_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -578,15 +569,17 @@ static void pnv_psi_power8_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
|
||||
static const char compat[] = "ibm,power8-psihb-x\0ibm,psihb-x";
|
||||
|
||||
dc->desc = "PowerNV PSI Controller POWER8";
|
||||
dc->realize = pnv_psi_power8_realize;
|
||||
|
||||
ppc->chip_type = PNV_CHIP_POWER8;
|
||||
ppc->xscom_pcba = PNV_XSCOM_PSIHB_BASE;
|
||||
ppc->xscom_size = PNV_XSCOM_PSIHB_SIZE;
|
||||
ppc->bar_mask = PSIHB_BAR_MASK;
|
||||
ppc->irq_set = pnv_psi_power8_irq_set;
|
||||
ppc->compat = compat;
|
||||
ppc->compat_size = sizeof(compat);
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_psi_power8_info = {
|
||||
@@ -609,9 +602,12 @@ static const TypeInfo pnv_psi_power8_info = {
|
||||
#define PSIHB9_IRQ_METHOD PPC_BIT(0)
|
||||
#define PSIHB9_IRQ_RESET PPC_BIT(1)
|
||||
#define PSIHB9_ESB_CI_BASE 0x60
|
||||
#define PSIHB9_ESB_CI_VALID 1
|
||||
#define PSIHB9_ESB_CI_64K PPC_BIT(1)
|
||||
#define PSIHB9_ESB_CI_ADDR_MASK PPC_BITMASK(8, 47)
|
||||
#define PSIHB9_ESB_CI_VALID PPC_BIT(63)
|
||||
#define PSIHB9_ESB_NOTIF_ADDR 0x68
|
||||
#define PSIHB9_ESB_NOTIF_VALID 1
|
||||
#define PSIHB9_ESB_NOTIF_ADDR_MASK PPC_BITMASK(8, 60)
|
||||
#define PSIHB9_ESB_NOTIF_VALID PPC_BIT(63)
|
||||
#define PSIHB9_IVT_OFFSET 0x70
|
||||
#define PSIHB9_IVT_OFF_SHIFT 32
|
||||
|
||||
@@ -851,8 +847,7 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
|
||||
&error_fatal);
|
||||
object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs",
|
||||
&error_fatal);
|
||||
object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(psi),
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(xsrc), OBJECT(psi), "xive", &error_abort);
|
||||
object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -883,15 +878,17 @@ static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
|
||||
XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
|
||||
static const char compat[] = "ibm,power9-psihb-x\0ibm,psihb-x";
|
||||
|
||||
dc->desc = "PowerNV PSI Controller POWER9";
|
||||
dc->realize = pnv_psi_power9_realize;
|
||||
|
||||
ppc->chip_type = PNV_CHIP_POWER9;
|
||||
ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
|
||||
ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
|
||||
ppc->bar_mask = PSIHB9_BAR_MASK;
|
||||
ppc->irq_set = pnv_psi_power9_irq_set;
|
||||
ppc->compat = compat;
|
||||
ppc->compat_size = sizeof(compat);
|
||||
|
||||
xfc->notify = pnv_psi_notify;
|
||||
}
|
||||
@@ -908,6 +905,26 @@ static const TypeInfo pnv_psi_power9_info = {
|
||||
},
|
||||
};
|
||||
|
||||
static void pnv_psi_power10_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
|
||||
static const char compat[] = "ibm,power10-psihb-x\0ibm,psihb-x";
|
||||
|
||||
dc->desc = "PowerNV PSI Controller POWER10";
|
||||
|
||||
ppc->xscom_pcba = PNV10_XSCOM_PSIHB_BASE;
|
||||
ppc->xscom_size = PNV10_XSCOM_PSIHB_SIZE;
|
||||
ppc->compat = compat;
|
||||
ppc->compat_size = sizeof(compat);
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_psi_power10_info = {
|
||||
.name = TYPE_PNV10_PSI,
|
||||
.parent = TYPE_PNV9_PSI,
|
||||
.class_init = pnv_psi_power10_class_init,
|
||||
};
|
||||
|
||||
static void pnv_psi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@@ -937,6 +954,7 @@ static void pnv_psi_register_types(void)
|
||||
type_register_static(&pnv_psi_info);
|
||||
type_register_static(&pnv_psi_power8_info);
|
||||
type_register_static(&pnv_psi_power9_info);
|
||||
type_register_static(&pnv_psi_power10_info);
|
||||
}
|
||||
|
||||
type_init(pnv_psi_register_types);
|
||||
|
||||
+16
-63
@@ -36,16 +36,6 @@
|
||||
#define PRD_P9_IPOLL_REG_MASK 0x000F0033
|
||||
#define PRD_P9_IPOLL_REG_STATUS 0x000F0034
|
||||
|
||||
/* PBA BARs */
|
||||
#define P8_PBA_BAR0 0x2013f00
|
||||
#define P8_PBA_BAR2 0x2013f02
|
||||
#define P8_PBA_BARMASK0 0x2013f04
|
||||
#define P8_PBA_BARMASK2 0x2013f06
|
||||
#define P9_PBA_BAR0 0x5012b00
|
||||
#define P9_PBA_BAR2 0x5012b02
|
||||
#define P9_PBA_BARMASK0 0x5012b04
|
||||
#define P9_PBA_BARMASK2 0x5012b06
|
||||
|
||||
static void xscom_complete(CPUState *cs, uint64_t hmer_bits)
|
||||
{
|
||||
/*
|
||||
@@ -67,13 +57,7 @@ static void xscom_complete(CPUState *cs, uint64_t hmer_bits)
|
||||
|
||||
static uint32_t pnv_xscom_pcba(PnvChip *chip, uint64_t addr)
|
||||
{
|
||||
addr &= (PNV_XSCOM_SIZE - 1);
|
||||
|
||||
if (pnv_chip_is_power9(chip)) {
|
||||
return addr >> 3;
|
||||
} else {
|
||||
return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
|
||||
}
|
||||
return PNV_CHIP_GET_CLASS(chip)->xscom_pcba(chip, addr);
|
||||
}
|
||||
|
||||
static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
|
||||
@@ -84,26 +68,6 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
|
||||
case 0x18002: /* ECID2 */
|
||||
return 0;
|
||||
|
||||
case P9_PBA_BAR0:
|
||||
return PNV9_HOMER_BASE(chip);
|
||||
case P8_PBA_BAR0:
|
||||
return PNV_HOMER_BASE(chip);
|
||||
|
||||
case P9_PBA_BARMASK0: /* P9 homer region size */
|
||||
return PNV9_HOMER_SIZE;
|
||||
case P8_PBA_BARMASK0: /* P8 homer region size */
|
||||
return PNV_HOMER_SIZE;
|
||||
|
||||
case P9_PBA_BAR2: /* P9 occ common area */
|
||||
return PNV9_OCC_COMMON_AREA(chip);
|
||||
case P8_PBA_BAR2: /* P8 occ common area */
|
||||
return PNV_OCC_COMMON_AREA(chip);
|
||||
|
||||
case P9_PBA_BARMASK2: /* P9 occ common area size */
|
||||
return PNV9_OCC_COMMON_AREA_SIZE;
|
||||
case P8_PBA_BARMASK2: /* P8 occ common area size */
|
||||
return PNV_OCC_COMMON_AREA_SIZE;
|
||||
|
||||
case 0x1010c00: /* PIBAM FIR */
|
||||
case 0x1010c03: /* PIBAM FIR MASK */
|
||||
|
||||
@@ -124,9 +88,7 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
|
||||
case 0x202000f: /* ADU stuff, receive status register*/
|
||||
return 0;
|
||||
case 0x2013f01: /* PBA stuff */
|
||||
case 0x2013f03: /* PBA stuff */
|
||||
case 0x2013f05: /* PBA stuff */
|
||||
case 0x2013f07: /* PBA stuff */
|
||||
return 0;
|
||||
case 0x2013028: /* CAPP stuff */
|
||||
case 0x201302a: /* CAPP stuff */
|
||||
@@ -298,31 +260,25 @@ static int xscom_dt_child(Object *child, void *opaque)
|
||||
PnvXScomInterface *xd = PNV_XSCOM_INTERFACE(child);
|
||||
PnvXScomInterfaceClass *xc = PNV_XSCOM_INTERFACE_GET_CLASS(xd);
|
||||
|
||||
if (xc->dt_xscom) {
|
||||
/*
|
||||
* Only "realized" devices should be configured in the DT
|
||||
*/
|
||||
if (xc->dt_xscom && DEVICE(child)->realized) {
|
||||
_FDT((xc->dt_xscom(xd, args->fdt, args->xscom_offset)));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char compat_p8[] = "ibm,power8-xscom\0ibm,xscom";
|
||||
static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom";
|
||||
|
||||
int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
|
||||
int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset,
|
||||
uint64_t xscom_base, uint64_t xscom_size,
|
||||
const char *compat, int compat_size)
|
||||
{
|
||||
uint64_t reg[2];
|
||||
uint64_t reg[] = { xscom_base, xscom_size };
|
||||
int xscom_offset;
|
||||
ForeachPopulateArgs args;
|
||||
char *name;
|
||||
|
||||
if (pnv_chip_is_power9(chip)) {
|
||||
reg[0] = cpu_to_be64(PNV9_XSCOM_BASE(chip));
|
||||
reg[1] = cpu_to_be64(PNV9_XSCOM_SIZE);
|
||||
} else {
|
||||
reg[0] = cpu_to_be64(PNV_XSCOM_BASE(chip));
|
||||
reg[1] = cpu_to_be64(PNV_XSCOM_SIZE);
|
||||
}
|
||||
|
||||
name = g_strdup_printf("xscom@%" PRIx64, be64_to_cpu(reg[0]));
|
||||
xscom_offset = fdt_add_subnode(fdt, root_offset, name);
|
||||
_FDT(xscom_offset);
|
||||
@@ -331,21 +287,18 @@ int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
|
||||
_FDT((fdt_setprop_cell(fdt, xscom_offset, "#address-cells", 1)));
|
||||
_FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
|
||||
_FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
|
||||
|
||||
if (pnv_chip_is_power9(chip)) {
|
||||
_FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p9,
|
||||
sizeof(compat_p9))));
|
||||
} else {
|
||||
_FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p8,
|
||||
sizeof(compat_p8))));
|
||||
}
|
||||
|
||||
_FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat, compat_size)));
|
||||
_FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
|
||||
|
||||
args.fdt = fdt;
|
||||
args.xscom_offset = xscom_offset;
|
||||
|
||||
object_child_foreach(OBJECT(chip), xscom_dt_child, &args);
|
||||
/*
|
||||
* Loop on the whole object hierarchy to catch all
|
||||
* PnvXScomInterface objects which can lie a bit deeper than the
|
||||
* first layer.
|
||||
*/
|
||||
object_child_foreach_recursive(OBJECT(chip), xscom_dt_child, &args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+53
-26
@@ -275,10 +275,9 @@ void ppc970_irq_init(PowerPCCPU *cpu)
|
||||
static void power7_set_irq(void *opaque, int pin, int level)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
env, pin, level);
|
||||
&cpu->env, pin, level);
|
||||
|
||||
switch (pin) {
|
||||
case POWER7_INPUT_INT:
|
||||
@@ -292,11 +291,6 @@ static void power7_set_irq(void *opaque, int pin, int level)
|
||||
LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
|
||||
return;
|
||||
}
|
||||
if (level) {
|
||||
env->irq_input_state |= 1 << pin;
|
||||
} else {
|
||||
env->irq_input_state &= ~(1 << pin);
|
||||
}
|
||||
}
|
||||
|
||||
void ppcPOWER7_irq_init(PowerPCCPU *cpu)
|
||||
@@ -311,10 +305,9 @@ void ppcPOWER7_irq_init(PowerPCCPU *cpu)
|
||||
static void power9_set_irq(void *opaque, int pin, int level)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
env, pin, level);
|
||||
&cpu->env, pin, level);
|
||||
|
||||
switch (pin) {
|
||||
case POWER9_INPUT_INT:
|
||||
@@ -334,11 +327,6 @@ static void power9_set_irq(void *opaque, int pin, int level)
|
||||
LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
|
||||
return;
|
||||
}
|
||||
if (level) {
|
||||
env->irq_input_state |= 1 << pin;
|
||||
} else {
|
||||
env->irq_input_state &= ~(1 << pin);
|
||||
}
|
||||
}
|
||||
|
||||
void ppcPOWER9_irq_init(PowerPCCPU *cpu)
|
||||
@@ -694,6 +682,35 @@ void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
|
||||
&tb_env->atb_offset, ((uint64_t)value << 32) | tb);
|
||||
}
|
||||
|
||||
uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
|
||||
return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
tb_env->vtb_offset);
|
||||
}
|
||||
|
||||
void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
|
||||
cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
&tb_env->vtb_offset, value);
|
||||
}
|
||||
|
||||
void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
uint64_t tb;
|
||||
|
||||
tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
tb_env->tb_offset);
|
||||
tb &= 0xFFFFFFUL;
|
||||
tb |= (value & ~0xFFFFFFUL);
|
||||
cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
&tb_env->tb_offset, tb);
|
||||
}
|
||||
|
||||
static void cpu_ppc_tb_stop (CPUPPCState *env)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
@@ -805,12 +822,9 @@ target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
|
||||
uint64_t cpu_ppc_load_purr (CPUPPCState *env)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
uint64_t diff;
|
||||
|
||||
diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start;
|
||||
|
||||
return tb_env->purr_load +
|
||||
muldiv64(diff, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
|
||||
return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
tb_env->purr_offset);
|
||||
}
|
||||
|
||||
/* When decrementer expires,
|
||||
@@ -969,12 +983,12 @@ static void cpu_ppc_hdecr_cb(void *opaque)
|
||||
cpu_ppc_hdecr_excp(cpu);
|
||||
}
|
||||
|
||||
static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
|
||||
void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
|
||||
{
|
||||
ppc_tb_t *tb_env = cpu->env.tb_env;
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
|
||||
tb_env->purr_load = value;
|
||||
tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
&tb_env->purr_offset, value);
|
||||
}
|
||||
|
||||
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
|
||||
@@ -991,7 +1005,7 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
|
||||
*/
|
||||
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
|
||||
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
|
||||
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
|
||||
cpu_ppc_store_purr(env, 0x0000000000000000ULL);
|
||||
}
|
||||
|
||||
static void timebase_save(PPCTimebase *tb)
|
||||
@@ -1495,18 +1509,31 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
int ppc_cpu_pir(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
return env->spr_cb[SPR_PIR].default_value;
|
||||
}
|
||||
|
||||
PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
if (env->spr_cb[SPR_PIR].default_value == pir) {
|
||||
if (ppc_cpu_pir(cpu) == pir) {
|
||||
return cpu;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ppc_irq_reset(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->irq_input_state = 0;
|
||||
kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
|
||||
}
|
||||
|
||||
+47
-86
@@ -76,7 +76,6 @@
|
||||
#include "hw/nmi.h"
|
||||
#include "hw/intc/intc.h"
|
||||
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/ppc/spapr_cpu_core.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "hw/ppc/spapr_tpm_proxy.h"
|
||||
@@ -897,69 +896,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool spapr_hotplugged_dev_before_cas(void)
|
||||
{
|
||||
Object *drc_container, *obj;
|
||||
ObjectProperty *prop;
|
||||
ObjectPropertyIterator iter;
|
||||
|
||||
drc_container = container_get(object_get_root(), "/dr-connector");
|
||||
object_property_iter_init(&iter, drc_container);
|
||||
while ((prop = object_property_iter_next(&iter))) {
|
||||
if (!strstart(prop->type, "link<", NULL)) {
|
||||
continue;
|
||||
}
|
||||
obj = object_property_get_link(drc_container, prop->name, NULL);
|
||||
if (spapr_drc_needed(obj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset);
|
||||
|
||||
int spapr_h_cas_compose_response(SpaprMachineState *spapr,
|
||||
target_ulong addr, target_ulong size,
|
||||
SpaprOptionVector *ov5_updates)
|
||||
{
|
||||
void *fdt;
|
||||
SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
|
||||
|
||||
if (spapr_hotplugged_dev_before_cas()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
|
||||
error_report("SLOF provided an unexpected CAS buffer size "
|
||||
TARGET_FMT_lu " (min: %zu, max: %u)",
|
||||
size, sizeof(hdr), FW_MAX_SIZE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
size -= sizeof(hdr);
|
||||
|
||||
fdt = spapr_build_fdt(spapr, false);
|
||||
_FDT((fdt_pack(fdt)));
|
||||
|
||||
if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
|
||||
g_free(fdt);
|
||||
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(spapr->fdt_blob);
|
||||
spapr->fdt_size = fdt_totalsize(fdt);
|
||||
spapr->fdt_initial_size = spapr->fdt_size;
|
||||
spapr->fdt_blob = fdt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
|
||||
{
|
||||
MachineState *ms = MACHINE(spapr);
|
||||
@@ -1197,7 +1133,7 @@ static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
|
||||
}
|
||||
}
|
||||
|
||||
static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
|
||||
void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
|
||||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
@@ -1207,8 +1143,8 @@ static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
|
||||
SpaprPhbState *phb;
|
||||
char *buf;
|
||||
|
||||
fdt = g_malloc0(FDT_MAX_SIZE);
|
||||
_FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
|
||||
fdt = g_malloc0(space);
|
||||
_FDT((fdt_create_empty_tree(fdt, space)));
|
||||
|
||||
/* Root node */
|
||||
_FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
|
||||
@@ -1723,19 +1659,13 @@ static void spapr_machine_reset(MachineState *machine)
|
||||
*/
|
||||
fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
|
||||
|
||||
fdt = spapr_build_fdt(spapr, true);
|
||||
fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
|
||||
|
||||
rc = fdt_pack(fdt);
|
||||
|
||||
/* Should only fail if we've built a corrupted tree */
|
||||
assert(rc == 0);
|
||||
|
||||
if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
|
||||
error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
|
||||
fdt_totalsize(fdt), FDT_MAX_SIZE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Load the fdt */
|
||||
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
|
||||
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
||||
@@ -1910,8 +1840,6 @@ static bool spapr_ov5_cas_needed(void *opaque)
|
||||
{
|
||||
SpaprMachineState *spapr = opaque;
|
||||
SpaprOptionVector *ov5_mask = spapr_ovec_new();
|
||||
SpaprOptionVector *ov5_legacy = spapr_ovec_new();
|
||||
SpaprOptionVector *ov5_removed = spapr_ovec_new();
|
||||
bool cas_needed;
|
||||
|
||||
/* Prior to the introduction of SpaprOptionVector, we had two option
|
||||
@@ -1943,17 +1871,11 @@ static bool spapr_ov5_cas_needed(void *opaque)
|
||||
spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
|
||||
spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
|
||||
|
||||
/* spapr_ovec_diff returns true if bits were removed. we avoid using
|
||||
* the mask itself since in the future it's possible "legacy" bits may be
|
||||
* removed via machine options, which could generate a false positive
|
||||
* that breaks migration.
|
||||
*/
|
||||
spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
|
||||
cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
|
||||
/* We need extra information if we have any bits outside the mask
|
||||
* defined above */
|
||||
cas_needed = !spapr_ovec_subset(spapr->ov5, ov5_mask);
|
||||
|
||||
spapr_ovec_cleanup(ov5_mask);
|
||||
spapr_ovec_cleanup(ov5_legacy);
|
||||
spapr_ovec_cleanup(ov5_removed);
|
||||
|
||||
return cas_needed;
|
||||
}
|
||||
@@ -2564,7 +2486,7 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
|
||||
" requires the use of VSMT mode %d.\n",
|
||||
smp_threads, kvm_smt, spapr->vsmt);
|
||||
}
|
||||
kvmppc_hint_smt_possible(&local_err);
|
||||
kvmppc_error_append_smt_possible_hint(&local_err);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -4275,6 +4197,42 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
|
||||
kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
|
||||
}
|
||||
|
||||
static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
{
|
||||
SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
|
||||
XivePresenter *xptr = XIVE_PRESENTER(spapr->xive);
|
||||
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
|
||||
int count;
|
||||
|
||||
/* This is a XIVE only operation */
|
||||
assert(spapr->active_intc == SPAPR_INTC(spapr->xive));
|
||||
|
||||
count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
|
||||
priority, logic_serv, match);
|
||||
if (count < 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we implement the save and restore of the thread interrupt
|
||||
* contexts in the enter/exit CPU handlers of the machine and the
|
||||
* escalations in QEMU, we should be able to handle non dispatched
|
||||
* vCPUs.
|
||||
*
|
||||
* Until this is done, the sPAPR machine should find at least one
|
||||
* matching context always.
|
||||
*/
|
||||
if (count == 0) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is not dispatched\n",
|
||||
nvt_blk, nvt_idx);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int spapr_get_vcpu_id(PowerPCCPU *cpu)
|
||||
{
|
||||
return cpu->vcpu_id;
|
||||
@@ -4371,6 +4329,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
|
||||
XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
|
||||
InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
|
||||
XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
|
||||
|
||||
mc->desc = "pSeries Logical Partition (PAPR compliant)";
|
||||
mc->ignore_boot_device_suffixes = true;
|
||||
@@ -4447,6 +4406,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
smc->linux_pci_probe = true;
|
||||
smc->smp_threads_vsmt = true;
|
||||
smc->nr_xirqs = SPAPR_NR_XIRQS;
|
||||
xfc->match_nvt = spapr_match_nvt;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_machine_info = {
|
||||
@@ -4465,6 +4425,7 @@ static const TypeInfo spapr_machine_info = {
|
||||
{ TYPE_PPC_VIRTUAL_HYPERVISOR },
|
||||
{ TYPE_XICS_FABRIC },
|
||||
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||
{ TYPE_XIVE_FABRIC },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user