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-2.7-20160701' into staging
ppc patch queue 2016-07-01
Here's the current ppc patch queue. This is a fairly large batch,
containing:
* A number of further preliminary patches towards full hypervisor
mode emulation
* Some further fixes / cleanups for the recently merged device_add
based CPU hotplug
* Preliminary patches towards supporting a native (rather than
paravirtualized) XICS device. This will be needed to emulate a
physical Power machine, including hypervisor capabilities
* Assorted bug fixes
# gpg: Signature made Fri 01 Jul 2016 06:56:35 BST
# gpg: using RSA key 0x6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg: It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-2.7-20160701: (23 commits)
qmp: fix spapr example of query-hotpluggable-cpus
spapr: drop duplicate variable in spapr_core_release()
spapr: do proper error propagation in spapr_cpu_core_realize_child()
spapr: drop reference on child object during core realization
spapr: Restore support for 970MP and POWER8NVL CPU cores
target-ppc: gen_pause for instructions: yield, mdoio, mdoom, miso
ppc/xics: Replace "icp" with "xics" in most places
ppc/xics: Implement H_IPOLL using an accessor
ppc/xics: Move SPAPR specific code to a separate file
ppc/xics: Rename existing xics to xics_spapr
ppc: Fix 64K pages support in full emulation
target-ppc: Eliminate redundant and incorrect function booke206_page_size_to_tlb
spapr: Restore support for older PowerPC CPU cores
spapr: fix write-past-end-of-array error in cpu core device init code
hw/ppc/spapr: Add some missing hcall function set strings
ppc: Print HSRR0/HSRR1 in "info registers"
ppc: LPCR is a HV resource
ppc: Initial HDEC support
ppc: Enforce setting MSR:EE,IR and DR when MSR:PR is set
ppc: Fix conditions for delivering external interrupts to a guest
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -49,6 +49,7 @@ CONFIG_ETSEC=y
|
||||
CONFIG_LIBDECNUMBER=y
|
||||
# For pSeries
|
||||
CONFIG_XICS=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||
# For PReP
|
||||
CONFIG_MC146818RTC=y
|
||||
|
||||
@@ -30,6 +30,7 @@ obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
|
||||
obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o
|
||||
obj-$(CONFIG_SH4) += sh_intc.o
|
||||
obj-$(CONFIG_XICS) += xics.o
|
||||
obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
|
||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||
|
||||
+73
-464
File diff suppressed because it is too large
Load Diff
+33
-30
@@ -145,7 +145,7 @@ static const TypeInfo icp_kvm_info = {
|
||||
*/
|
||||
static void ics_get_kvm_state(ICSState *ics)
|
||||
{
|
||||
KVMXICSState *icpkvm = KVM_XICS(ics->icp);
|
||||
KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics);
|
||||
uint64_t state;
|
||||
struct kvm_device_attr attr = {
|
||||
.flags = 0,
|
||||
@@ -160,7 +160,7 @@ static void ics_get_kvm_state(ICSState *ics)
|
||||
|
||||
attr.attr = i + ics->offset;
|
||||
|
||||
ret = ioctl(icpkvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||
ret = ioctl(xicskvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||
if (ret != 0) {
|
||||
error_report("Unable to retrieve KVM interrupt controller state"
|
||||
" for IRQ %d: %s", i + ics->offset, strerror(errno));
|
||||
@@ -204,7 +204,7 @@ static void ics_get_kvm_state(ICSState *ics)
|
||||
|
||||
static int ics_set_kvm_state(ICSState *ics, int version_id)
|
||||
{
|
||||
KVMXICSState *icpkvm = KVM_XICS(ics->icp);
|
||||
KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics);
|
||||
uint64_t state;
|
||||
struct kvm_device_attr attr = {
|
||||
.flags = 0,
|
||||
@@ -238,7 +238,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
|
||||
}
|
||||
}
|
||||
|
||||
ret = ioctl(icpkvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
ret = ioctl(xicskvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
if (ret != 0) {
|
||||
error_report("Unable to restore KVM interrupt controller state"
|
||||
" for IRQs %d: %s", i + ics->offset, strerror(errno));
|
||||
@@ -324,17 +324,17 @@ static const TypeInfo ics_kvm_info = {
|
||||
/*
|
||||
* XICS-KVM
|
||||
*/
|
||||
static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
||||
static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
|
||||
{
|
||||
CPUState *cs;
|
||||
ICPState *ss;
|
||||
KVMXICSState *icpkvm = KVM_XICS(icp);
|
||||
KVMXICSState *xicskvm = XICS_SPAPR_KVM(xics);
|
||||
|
||||
cs = CPU(cpu);
|
||||
ss = &icp->ss[cs->cpu_index];
|
||||
ss = &xics->ss[cs->cpu_index];
|
||||
|
||||
assert(cs->cpu_index < icp->nr_servers);
|
||||
if (icpkvm->kernel_xics_fd == -1) {
|
||||
assert(cs->cpu_index < xics->nr_servers);
|
||||
if (xicskvm->kernel_xics_fd == -1) {
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -347,11 +347,12 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
||||
return;
|
||||
}
|
||||
|
||||
if (icpkvm->kernel_xics_fd != -1) {
|
||||
if (xicskvm->kernel_xics_fd != -1) {
|
||||
int ret;
|
||||
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0,
|
||||
icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs));
|
||||
xicskvm->kernel_xics_fd,
|
||||
kvm_arch_vcpu_id(cs));
|
||||
if (ret < 0) {
|
||||
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
||||
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||
@@ -361,24 +362,25 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
||||
}
|
||||
}
|
||||
|
||||
static void xics_kvm_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp)
|
||||
static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
|
||||
Error **errp)
|
||||
{
|
||||
icp->nr_irqs = icp->ics->nr_irqs = nr_irqs;
|
||||
xics->nr_irqs = xics->ics->nr_irqs = nr_irqs;
|
||||
}
|
||||
|
||||
static void xics_kvm_set_nr_servers(XICSState *icp, uint32_t nr_servers,
|
||||
static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers,
|
||||
Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
icp->nr_servers = nr_servers;
|
||||
xics->nr_servers = nr_servers;
|
||||
|
||||
icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState));
|
||||
for (i = 0; i < icp->nr_servers; i++) {
|
||||
xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState));
|
||||
for (i = 0; i < xics->nr_servers; i++) {
|
||||
char buffer[32];
|
||||
object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_KVM_ICP);
|
||||
object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_KVM_ICP);
|
||||
snprintf(buffer, sizeof(buffer), "icp[%d]", i);
|
||||
object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]),
|
||||
object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]),
|
||||
errp);
|
||||
}
|
||||
}
|
||||
@@ -394,8 +396,8 @@ static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
|
||||
static void xics_kvm_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMXICSState *icpkvm = KVM_XICS(dev);
|
||||
XICSState *icp = XICS_COMMON(dev);
|
||||
KVMXICSState *xicskvm = XICS_SPAPR_KVM(dev);
|
||||
XICSState *xics = XICS_COMMON(dev);
|
||||
int i, rc;
|
||||
Error *error = NULL;
|
||||
struct kvm_create_device xics_create_device = {
|
||||
@@ -445,17 +447,18 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
icpkvm->kernel_xics_fd = xics_create_device.fd;
|
||||
xicskvm->kernel_xics_fd = xics_create_device.fd;
|
||||
|
||||
object_property_set_bool(OBJECT(icp->ics), true, "realized", &error);
|
||||
object_property_set_bool(OBJECT(xics->ics), true, "realized", &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
assert(icp->nr_servers);
|
||||
for (i = 0; i < icp->nr_servers; i++) {
|
||||
object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error);
|
||||
assert(xics->nr_servers);
|
||||
for (i = 0; i < xics->nr_servers; i++) {
|
||||
object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized",
|
||||
&error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto fail;
|
||||
@@ -481,7 +484,7 @@ static void xics_kvm_initfn(Object *obj)
|
||||
|
||||
xics->ics = ICS(object_new(TYPE_KVM_ICS));
|
||||
object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
|
||||
xics->ics->icp = xics;
|
||||
xics->ics->xics = xics;
|
||||
}
|
||||
|
||||
static void xics_kvm_class_init(ObjectClass *oc, void *data)
|
||||
@@ -495,8 +498,8 @@ static void xics_kvm_class_init(ObjectClass *oc, void *data)
|
||||
xsc->set_nr_servers = xics_kvm_set_nr_servers;
|
||||
}
|
||||
|
||||
static const TypeInfo xics_kvm_info = {
|
||||
.name = TYPE_KVM_XICS,
|
||||
static const TypeInfo xics_spapr_kvm_info = {
|
||||
.name = TYPE_XICS_SPAPR_KVM,
|
||||
.parent = TYPE_XICS_COMMON,
|
||||
.instance_size = sizeof(KVMXICSState),
|
||||
.class_init = xics_kvm_class_init,
|
||||
@@ -505,7 +508,7 @@ static const TypeInfo xics_kvm_info = {
|
||||
|
||||
static void xics_kvm_register_types(void)
|
||||
{
|
||||
type_register_static(&xics_kvm_info);
|
||||
type_register_static(&xics_spapr_kvm_info);
|
||||
type_register_static(&ics_kvm_info);
|
||||
type_register_static(&icp_kvm_info);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
|
||||
*
|
||||
* PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
|
||||
*
|
||||
* Copyright (c) 2010,2011 David Gibson, IBM Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/xics.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
/*
|
||||
* Guest interfaces
|
||||
*/
|
||||
|
||||
static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
target_ulong cppr = args[0];
|
||||
|
||||
icp_set_cppr(spapr->xics, cs->cpu_index, cppr);
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong server = xics_get_cpu_index_by_dt_id(args[0]);
|
||||
target_ulong mfrr = args[1];
|
||||
|
||||
if (server >= spapr->xics->nr_servers) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
icp_set_mfrr(spapr->xics, server, mfrr);
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
uint32_t xirr = icp_accept(spapr->xics->ss + cs->cpu_index);
|
||||
|
||||
args[0] = xirr;
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
ICPState *ss = &spapr->xics->ss[cs->cpu_index];
|
||||
uint32_t xirr = icp_accept(ss);
|
||||
|
||||
args[0] = xirr;
|
||||
args[1] = cpu_get_host_ticks();
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
target_ulong xirr = args[0];
|
||||
|
||||
icp_eoi(spapr->xics, cs->cpu_index, xirr);
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
uint32_t mfrr;
|
||||
uint32_t xirr = icp_ipoll(spapr->xics->ss + cs->cpu_index, &mfrr);
|
||||
|
||||
args[0] = xirr;
|
||||
args[1] = mfrr;
|
||||
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
uint32_t token,
|
||||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr, server, priority;
|
||||
|
||||
if ((nargs != 3) || (nret != 1)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1));
|
||||
priority = rtas_ld(args, 2);
|
||||
|
||||
if (!ics_valid_irq(ics, nr) || (server >= ics->xics->nr_servers)
|
||||
|| (priority > 0xff)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ics_write_xive(ics, nr, server, priority, priority);
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
}
|
||||
|
||||
static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
uint32_t token,
|
||||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr;
|
||||
|
||||
if ((nargs != 1) || (nret != 3)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
|
||||
if (!ics_valid_irq(ics, nr)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
|
||||
rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
|
||||
}
|
||||
|
||||
static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
uint32_t token,
|
||||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr;
|
||||
|
||||
if ((nargs != 1) || (nret != 1)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
|
||||
if (!ics_valid_irq(ics, nr)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
|
||||
ics->irqs[nr - ics->offset].priority);
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
}
|
||||
|
||||
static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
uint32_t token,
|
||||
uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
ICSState *ics = spapr->xics->ics;
|
||||
uint32_t nr;
|
||||
|
||||
if ((nargs != 1) || (nret != 1)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
|
||||
if (!ics_valid_irq(ics, nr)) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
|
||||
ics->irqs[nr - ics->offset].saved_priority,
|
||||
ics->irqs[nr - ics->offset].saved_priority);
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
}
|
||||
|
||||
static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
|
||||
Error **errp)
|
||||
{
|
||||
xics->nr_irqs = xics->ics->nr_irqs = nr_irqs;
|
||||
}
|
||||
|
||||
static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers,
|
||||
Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
xics->nr_servers = nr_servers;
|
||||
|
||||
xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState));
|
||||
for (i = 0; i < xics->nr_servers; i++) {
|
||||
char buffer[32];
|
||||
object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_ICP);
|
||||
snprintf(buffer, sizeof(buffer), "icp[%d]", i);
|
||||
object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]),
|
||||
errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void xics_spapr_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
XICSState *xics = XICS_SPAPR(dev);
|
||||
Error *error = NULL;
|
||||
int i;
|
||||
|
||||
if (!xics->nr_servers) {
|
||||
error_setg(errp, "Number of servers needs to be greater 0");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Registration of global state belongs into realize */
|
||||
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
|
||||
spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
|
||||
spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
|
||||
spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
|
||||
|
||||
spapr_register_hypercall(H_CPPR, h_cppr);
|
||||
spapr_register_hypercall(H_IPI, h_ipi);
|
||||
spapr_register_hypercall(H_XIRR, h_xirr);
|
||||
spapr_register_hypercall(H_XIRR_X, h_xirr_x);
|
||||
spapr_register_hypercall(H_EOI, h_eoi);
|
||||
spapr_register_hypercall(H_IPOLL, h_ipoll);
|
||||
|
||||
object_property_set_bool(OBJECT(xics->ics), true, "realized", &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < xics->nr_servers; i++) {
|
||||
object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized",
|
||||
&error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xics_spapr_initfn(Object *obj)
|
||||
{
|
||||
XICSState *xics = XICS_SPAPR(obj);
|
||||
|
||||
xics->ics = ICS(object_new(TYPE_ICS));
|
||||
object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
|
||||
xics->ics->xics = xics;
|
||||
}
|
||||
|
||||
static void xics_spapr_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
XICSStateClass *xsc = XICS_SPAPR_CLASS(oc);
|
||||
|
||||
dc->realize = xics_spapr_realize;
|
||||
xsc->set_nr_irqs = xics_spapr_set_nr_irqs;
|
||||
xsc->set_nr_servers = xics_spapr_set_nr_servers;
|
||||
}
|
||||
|
||||
static const TypeInfo xics_spapr_info = {
|
||||
.name = TYPE_XICS_SPAPR,
|
||||
.parent = TYPE_XICS_COMMON,
|
||||
.instance_size = sizeof(XICSState),
|
||||
.class_size = sizeof(XICSStateClass),
|
||||
.class_init = xics_spapr_class_init,
|
||||
.instance_init = xics_spapr_initfn,
|
||||
};
|
||||
|
||||
#define ICS_IRQ_FREE(ics, srcno) \
|
||||
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
|
||||
|
||||
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
|
||||
{
|
||||
int first, i;
|
||||
|
||||
for (first = 0; first < ics->nr_irqs; first += alignnum) {
|
||||
if (num > (ics->nr_irqs - first)) {
|
||||
return -1;
|
||||
}
|
||||
for (i = first; i < first + num; ++i) {
|
||||
if (!ICS_IRQ_FREE(ics, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == (first + num)) {
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi,
|
||||
Error **errp)
|
||||
{
|
||||
ICSState *ics = &xics->ics[src];
|
||||
int irq;
|
||||
|
||||
if (irq_hint) {
|
||||
assert(src == xics_find_source(xics, irq_hint));
|
||||
if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
|
||||
error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
|
||||
return -1;
|
||||
}
|
||||
irq = irq_hint;
|
||||
} else {
|
||||
irq = ics_find_free_block(ics, 1, 1);
|
||||
if (irq < 0) {
|
||||
error_setg(errp, "can't allocate IRQ: no IRQ left");
|
||||
return -1;
|
||||
}
|
||||
irq += ics->offset;
|
||||
}
|
||||
|
||||
ics_set_irq_type(ics, irq - ics->offset, lsi);
|
||||
trace_xics_alloc(src, irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate block of consecutive IRQs, and return the number of the first IRQ in
|
||||
* the block. If align==true, aligns the first IRQ number to num.
|
||||
*/
|
||||
int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi,
|
||||
bool align, Error **errp)
|
||||
{
|
||||
int i, first = -1;
|
||||
ICSState *ics = &xics->ics[src];
|
||||
|
||||
assert(src == 0);
|
||||
/*
|
||||
* MSIMesage::data is used for storing VIRQ so
|
||||
* it has to be aligned to num to support multiple
|
||||
* MSI vectors. MSI-X is not affected by this.
|
||||
* The hint is used for the first IRQ, the rest should
|
||||
* be allocated continuously.
|
||||
*/
|
||||
if (align) {
|
||||
assert((num == 1) || (num == 2) || (num == 4) ||
|
||||
(num == 8) || (num == 16) || (num == 32));
|
||||
first = ics_find_free_block(ics, num, num);
|
||||
} else {
|
||||
first = ics_find_free_block(ics, num, 1);
|
||||
}
|
||||
if (first < 0) {
|
||||
error_setg(errp, "can't find a free %d-IRQ block", num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (first >= 0) {
|
||||
for (i = first; i < first + num; ++i) {
|
||||
ics_set_irq_type(ics, i, lsi);
|
||||
}
|
||||
}
|
||||
first += ics->offset;
|
||||
|
||||
trace_xics_alloc_block(src, first, num, lsi, align);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
static void ics_free(ICSState *ics, int srcno, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = srcno; i < srcno + num; ++i) {
|
||||
if (ICS_IRQ_FREE(ics, i)) {
|
||||
trace_xics_ics_free_warn(ics - ics->xics->ics, i + ics->offset);
|
||||
}
|
||||
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
|
||||
}
|
||||
}
|
||||
|
||||
void xics_spapr_free(XICSState *xics, int irq, int num)
|
||||
{
|
||||
int src = xics_find_source(xics, irq);
|
||||
|
||||
if (src >= 0) {
|
||||
ICSState *ics = &xics->ics[src];
|
||||
|
||||
/* FIXME: implement multiple sources */
|
||||
assert(src == 0);
|
||||
|
||||
trace_xics_ics_free(ics - xics->ics, irq, num);
|
||||
ics_free(ics, irq - ics->offset, num);
|
||||
}
|
||||
}
|
||||
|
||||
static void xics_spapr_register_types(void)
|
||||
{
|
||||
type_register_static(&xics_spapr_info);
|
||||
}
|
||||
|
||||
type_init(xics_spapr_register_types)
|
||||
+1
-1
@@ -601,7 +601,7 @@ static int ppce500_prep_device_tree(MachineState *machine,
|
||||
}
|
||||
|
||||
/* Create -kernel TLB entries for BookE. */
|
||||
static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
|
||||
hwaddr booke206_page_size_to_tlb(uint64_t size)
|
||||
{
|
||||
return 63 - clz64(size >> 10);
|
||||
}
|
||||
|
||||
@@ -26,4 +26,6 @@ typedef struct PPCE500Params {
|
||||
|
||||
void ppce500_init(MachineState *machine, PPCE500Params *params);
|
||||
|
||||
hwaddr booke206_page_size_to_tlb(uint64_t size);
|
||||
|
||||
#endif
|
||||
|
||||
+12
-5
@@ -699,9 +699,18 @@ static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
|
||||
|
||||
static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
/* Raise it */
|
||||
LOG_TB("raise decrementer exception\n");
|
||||
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
|
||||
LOG_TB("raise hv decrementer exception\n");
|
||||
|
||||
/* The architecture specifies that we don't deliver HDEC
|
||||
* interrupts in a PM state. Not only they don't cause a
|
||||
* wakeup but they also get effectively discarded.
|
||||
*/
|
||||
if (!env->in_pm_state) {
|
||||
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
|
||||
@@ -928,9 +937,7 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
||||
}
|
||||
/* Create new timer */
|
||||
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
|
||||
if (0) {
|
||||
/* XXX: find a suitable condition to enable the hypervisor decrementer
|
||||
*/
|
||||
if (env->has_hv_mode) {
|
||||
tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb,
|
||||
cpu);
|
||||
} else {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "e500.h"
|
||||
|
||||
#define MAX_CPUS 32
|
||||
|
||||
@@ -72,12 +73,6 @@ static void spin_reset(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
|
||||
static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
|
||||
{
|
||||
return ctz32(size >> 10) >> 1;
|
||||
}
|
||||
|
||||
static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
||||
target_ulong va,
|
||||
hwaddr pa,
|
||||
|
||||
+13
-9
@@ -116,15 +116,16 @@ static XICSState *try_create_xics(const char *type, int nr_servers,
|
||||
static XICSState *xics_system_init(MachineState *machine,
|
||||
int nr_servers, int nr_irqs, Error **errp)
|
||||
{
|
||||
XICSState *icp = NULL;
|
||||
XICSState *xics = NULL;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
Error *err = NULL;
|
||||
|
||||
if (machine_kernel_irqchip_allowed(machine)) {
|
||||
icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs, &err);
|
||||
xics = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs,
|
||||
&err);
|
||||
}
|
||||
if (machine_kernel_irqchip_required(machine) && !icp) {
|
||||
if (machine_kernel_irqchip_required(machine) && !xics) {
|
||||
error_reportf_err(err,
|
||||
"kernel_irqchip requested but unavailable: ");
|
||||
} else {
|
||||
@@ -132,11 +133,11 @@ static XICSState *xics_system_init(MachineState *machine,
|
||||
}
|
||||
}
|
||||
|
||||
if (!icp) {
|
||||
icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs, errp);
|
||||
if (!xics) {
|
||||
xics = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp);
|
||||
}
|
||||
|
||||
return icp;
|
||||
return xics;
|
||||
}
|
||||
|
||||
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
|
||||
@@ -339,6 +340,9 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||
add_str(hypertas, "hcall-splpar");
|
||||
add_str(hypertas, "hcall-bulk");
|
||||
add_str(hypertas, "hcall-set-mode");
|
||||
add_str(hypertas, "hcall-sprg0");
|
||||
add_str(hypertas, "hcall-copy");
|
||||
add_str(hypertas, "hcall-debug");
|
||||
add_str(qemu_hypertas, "hcall-memop1");
|
||||
|
||||
fdt = g_malloc0(FDT_MAX_SIZE);
|
||||
@@ -1779,9 +1783,9 @@ static void ppc_spapr_init(MachineState *machine)
|
||||
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
|
||||
|
||||
/* Set up Interrupt Controller before we create the VCPUs */
|
||||
spapr->icp = xics_system_init(machine,
|
||||
DIV_ROUND_UP(max_cpus * smt, smp_threads),
|
||||
XICS_IRQS, &error_fatal);
|
||||
spapr->xics = xics_system_init(machine,
|
||||
DIV_ROUND_UP(max_cpus * smt, smp_threads),
|
||||
XICS_IRQS_SPAPR, &error_fatal);
|
||||
|
||||
if (smc->dr_lmb_enabled) {
|
||||
spapr_validate_node_memory(machine, &error_fatal);
|
||||
|
||||
+36
-12
@@ -42,7 +42,7 @@ static void spapr_cpu_destroy(PowerPCCPU *cpu)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
|
||||
xics_cpu_destroy(spapr->icp, cpu);
|
||||
xics_cpu_destroy(spapr->xics, cpu);
|
||||
qemu_unregister_reset(spapr_cpu_reset, cpu);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
xics_cpu_setup(spapr->icp, cpu);
|
||||
xics_cpu_setup(spapr->xics, cpu);
|
||||
|
||||
qemu_register_reset(spapr_cpu_reset, cpu);
|
||||
spapr_cpu_reset(cpu);
|
||||
@@ -102,7 +102,6 @@ static void spapr_core_release(DeviceState *dev, void *opaque)
|
||||
const char *typename = object_class_get_name(sc->cpu_class);
|
||||
size_t size = object_type_get_instance_size(typename);
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
|
||||
CPUCore *cc = CPU_CORE(dev);
|
||||
int smt = kvmppc_smt_threads();
|
||||
int i;
|
||||
@@ -120,7 +119,7 @@ static void spapr_core_release(DeviceState *dev, void *opaque)
|
||||
|
||||
spapr->cores[cc->core_id / smt] = NULL;
|
||||
|
||||
g_free(core->threads);
|
||||
g_free(sc->threads);
|
||||
object_unparent(OBJECT(dev));
|
||||
}
|
||||
|
||||
@@ -262,18 +261,20 @@ out:
|
||||
|
||||
static int spapr_cpu_core_realize_child(Object *child, void *opaque)
|
||||
{
|
||||
Error **errp = opaque;
|
||||
Error **errp = opaque, *local_err = NULL;
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
CPUState *cs = CPU(child);
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
object_property_set_bool(child, true, "realized", errp);
|
||||
if (*errp) {
|
||||
object_property_set_bool(child, true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
spapr_cpu_init(spapr, cpu, errp);
|
||||
if (*errp) {
|
||||
spapr_cpu_init(spapr, cpu, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -300,6 +301,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
|
||||
if (local_err) {
|
||||
goto err;
|
||||
}
|
||||
object_unref(obj);
|
||||
}
|
||||
object_child_foreach(OBJECT(dev), spapr_cpu_core_realize_child, &local_err);
|
||||
if (local_err) {
|
||||
@@ -309,10 +311,9 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
err:
|
||||
while (i >= 0) {
|
||||
while (--i >= 0) {
|
||||
obj = sc->threads + i * size;
|
||||
object_unparent(obj);
|
||||
i--;
|
||||
}
|
||||
g_free(sc->threads);
|
||||
error_propagate(errp, local_err);
|
||||
@@ -326,7 +327,6 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
/*
|
||||
* instance_init routines from different flavours of sPAPR CPU cores.
|
||||
* TODO: Add support for 'host' core type.
|
||||
*/
|
||||
#define SPAPR_CPU_CORE_INITFN(_type, _fname) \
|
||||
static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \
|
||||
@@ -339,10 +339,15 @@ static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \
|
||||
core->cpu_class = oc; \
|
||||
}
|
||||
|
||||
SPAPR_CPU_CORE_INITFN(970mp_v1.0, 970MP_v10);
|
||||
SPAPR_CPU_CORE_INITFN(970mp_v1.1, 970MP_v11);
|
||||
SPAPR_CPU_CORE_INITFN(970_v2.2, 970);
|
||||
SPAPR_CPU_CORE_INITFN(POWER5+_v2.1, POWER5plus);
|
||||
SPAPR_CPU_CORE_INITFN(POWER7_v2.3, POWER7);
|
||||
SPAPR_CPU_CORE_INITFN(POWER7+_v2.1, POWER7plus);
|
||||
SPAPR_CPU_CORE_INITFN(POWER8_v2.0, POWER8);
|
||||
SPAPR_CPU_CORE_INITFN(POWER8E_v2.1, POWER8E);
|
||||
SPAPR_CPU_CORE_INITFN(POWER8NVL_v1.0, POWER8NVL);
|
||||
|
||||
typedef struct SPAPRCoreInfo {
|
||||
const char *name;
|
||||
@@ -350,6 +355,21 @@ typedef struct SPAPRCoreInfo {
|
||||
} SPAPRCoreInfo;
|
||||
|
||||
static const SPAPRCoreInfo spapr_cores[] = {
|
||||
/* 970 and aliaes */
|
||||
{ .name = "970_v2.2", .initfn = spapr_cpu_core_970_initfn },
|
||||
{ .name = "970", .initfn = spapr_cpu_core_970_initfn },
|
||||
|
||||
/* 970MP variants and aliases */
|
||||
{ .name = "970MP_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn },
|
||||
{ .name = "970mp_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn },
|
||||
{ .name = "970MP_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn },
|
||||
{ .name = "970mp_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn },
|
||||
{ .name = "970mp", .initfn = spapr_cpu_core_970MP_v11_initfn },
|
||||
|
||||
/* POWER5 and aliases */
|
||||
{ .name = "POWER5+_v2.1", .initfn = spapr_cpu_core_POWER5plus_initfn },
|
||||
{ .name = "POWER5+", .initfn = spapr_cpu_core_POWER5plus_initfn },
|
||||
|
||||
/* POWER7 and aliases */
|
||||
{ .name = "POWER7_v2.3", .initfn = spapr_cpu_core_POWER7_initfn },
|
||||
{ .name = "POWER7", .initfn = spapr_cpu_core_POWER7_initfn },
|
||||
@@ -367,6 +387,10 @@ static const SPAPRCoreInfo spapr_cores[] = {
|
||||
{ .name = "POWER8E_v2.1", .initfn = spapr_cpu_core_POWER8E_initfn },
|
||||
{ .name = "POWER8E", .initfn = spapr_cpu_core_POWER8E_initfn },
|
||||
|
||||
/* POWER8NVL and aliases */
|
||||
{ .name = "POWER8NVL_v1.0", .initfn = spapr_cpu_core_POWER8NVL_initfn },
|
||||
{ .name = "POWER8NVL", .initfn = spapr_cpu_core_POWER8NVL_initfn },
|
||||
|
||||
{ .name = NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -386,7 +386,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
|
||||
|
||||
rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true);
|
||||
|
||||
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
|
||||
qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq));
|
||||
}
|
||||
|
||||
static void spapr_hotplug_set_signalled(uint32_t drc_index)
|
||||
@@ -468,7 +468,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
|
||||
|
||||
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->xics, spapr->check_exception_irq));
|
||||
}
|
||||
|
||||
void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
|
||||
@@ -551,7 +551,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
* interrupts.
|
||||
*/
|
||||
if (rtas_event_log_contains(mask, true)) {
|
||||
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
|
||||
qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq));
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -603,7 +603,7 @@ out_no_events:
|
||||
void spapr_events_init(sPAPRMachineState *spapr)
|
||||
{
|
||||
QTAILQ_INIT(&spapr->pending_events);
|
||||
spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false,
|
||||
spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, 0, false,
|
||||
&error_fatal);
|
||||
spapr->epow_notifier.notify = spapr_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&spapr->epow_notifier);
|
||||
|
||||
+7
-6
@@ -322,7 +322,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
return;
|
||||
}
|
||||
|
||||
xics_free(spapr->icp, msi->first_irq, msi->num);
|
||||
xics_spapr_free(spapr->xics, msi->first_irq, msi->num);
|
||||
if (msi_present(pdev)) {
|
||||
spapr_msi_setmsg(pdev, 0, false, 0, 0);
|
||||
}
|
||||
@@ -360,7 +360,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
}
|
||||
|
||||
/* Allocate MSIs */
|
||||
irq = xics_alloc_block(spapr->icp, 0, req_num, false,
|
||||
irq = xics_spapr_alloc_block(spapr->xics, 0, req_num, false,
|
||||
ret_intr_type == RTAS_TYPE_MSI, &err);
|
||||
if (err) {
|
||||
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
|
||||
@@ -371,7 +371,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
|
||||
/* Release previous MSIs */
|
||||
if (msi) {
|
||||
xics_free(spapr->icp, msi->first_irq, msi->num);
|
||||
xics_spapr_free(spapr->xics, msi->first_irq, msi->num);
|
||||
g_hash_table_remove(phb->msi, &config_addr);
|
||||
}
|
||||
|
||||
@@ -733,7 +733,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr,
|
||||
|
||||
trace_spapr_pci_msi_write(addr, data, irq);
|
||||
|
||||
qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
|
||||
qemu_irq_pulse(xics_get_qirq(spapr->xics, irq));
|
||||
}
|
||||
|
||||
static const MemoryRegionOps spapr_msi_ops = {
|
||||
@@ -1442,7 +1442,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
uint32_t irq;
|
||||
Error *local_err = NULL;
|
||||
|
||||
irq = xics_alloc_block(spapr->icp, 0, 1, true, false, &local_err);
|
||||
irq = xics_spapr_alloc_block(spapr->xics, 0, 1, true, false,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
error_prepend(errp, "can't allocate LSIs: ");
|
||||
@@ -1801,7 +1802,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
||||
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges));
|
||||
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
|
||||
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
|
||||
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS));
|
||||
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS_SPAPR));
|
||||
|
||||
/* Build the interrupt-map, this must matches what is done
|
||||
* in pci_spapr_map_irq
|
||||
|
||||
+1
-1
@@ -463,7 +463,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
|
||||
dev->qdev.id = id;
|
||||
}
|
||||
|
||||
dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false, &local_err);
|
||||
dev->irq = xics_spapr_alloc(spapr->xics, 0, dev->irq, false, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
|
||||
@@ -93,7 +93,7 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
|
||||
return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
|
||||
return xics_get_qirq(spapr->xics, phb->lsi_table[pin].irq);
|
||||
}
|
||||
|
||||
PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index);
|
||||
|
||||
@@ -52,7 +52,7 @@ struct sPAPRMachineState {
|
||||
struct VIOsPAPRBus *vio_bus;
|
||||
QLIST_HEAD(, sPAPRPHBState) phbs;
|
||||
struct sPAPRNVRAM *nvram;
|
||||
XICSState *icp;
|
||||
XICSState *xics;
|
||||
DeviceState *rtc;
|
||||
|
||||
void *htab;
|
||||
|
||||
@@ -90,7 +90,7 @@ static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
|
||||
return xics_get_qirq(spapr->icp, dev->irq);
|
||||
return xics_get_qirq(spapr->xics, dev->irq);
|
||||
}
|
||||
|
||||
static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
|
||||
|
||||
+41
-13
@@ -32,20 +32,25 @@
|
||||
#define TYPE_XICS_COMMON "xics-common"
|
||||
#define XICS_COMMON(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_COMMON)
|
||||
|
||||
#define TYPE_XICS "xics"
|
||||
#define XICS(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS)
|
||||
/*
|
||||
* Retain xics as the type name to be compatible for migration. Rest all the
|
||||
* functions, class and variables are renamed as xics_spapr.
|
||||
*/
|
||||
#define TYPE_XICS_SPAPR "xics"
|
||||
#define XICS_SPAPR(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_SPAPR)
|
||||
|
||||
#define TYPE_KVM_XICS "xics-kvm"
|
||||
#define KVM_XICS(obj) OBJECT_CHECK(KVMXICSState, (obj), TYPE_KVM_XICS)
|
||||
#define TYPE_XICS_SPAPR_KVM "xics-spapr-kvm"
|
||||
#define XICS_SPAPR_KVM(obj) \
|
||||
OBJECT_CHECK(KVMXICSState, (obj), TYPE_XICS_SPAPR_KVM)
|
||||
|
||||
#define XICS_COMMON_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_COMMON)
|
||||
#define XICS_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS)
|
||||
#define XICS_SPAPR_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_SPAPR)
|
||||
#define XICS_COMMON_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_COMMON)
|
||||
#define XICS_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS)
|
||||
#define XICS_SPAPR_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_SPAPR)
|
||||
|
||||
#define XICS_IPI 0x2
|
||||
#define XICS_BUID 0x1
|
||||
@@ -138,9 +143,15 @@ struct ICSState {
|
||||
uint32_t offset;
|
||||
qemu_irq *qirqs;
|
||||
ICSIRQState *irqs;
|
||||
XICSState *icp;
|
||||
XICSState *xics;
|
||||
};
|
||||
|
||||
static inline bool ics_valid_irq(ICSState *ics, uint32_t nr)
|
||||
{
|
||||
return (nr >= ics->offset)
|
||||
&& (nr < (ics->offset + ics->nr_irqs));
|
||||
}
|
||||
|
||||
struct ICSIRQState {
|
||||
uint32_t server;
|
||||
uint8_t priority;
|
||||
@@ -157,15 +168,32 @@ struct ICSIRQState {
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define XICS_IRQS 1024
|
||||
#define XICS_IRQS_SPAPR 1024
|
||||
|
||||
qemu_irq xics_get_qirq(XICSState *icp, int irq);
|
||||
int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi, Error **errp);
|
||||
int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align,
|
||||
int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi,
|
||||
Error **errp);
|
||||
void xics_free(XICSState *icp, int irq, int num);
|
||||
int xics_spapr_alloc_block(XICSState *icp, int src, int num, bool lsi,
|
||||
bool align, Error **errp);
|
||||
void xics_spapr_free(XICSState *icp, int irq, int num);
|
||||
|
||||
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu);
|
||||
void xics_cpu_destroy(XICSState *icp, PowerPCCPU *cpu);
|
||||
|
||||
/* Internal XICS interfaces */
|
||||
int xics_get_cpu_index_by_dt_id(int cpu_dt_id);
|
||||
|
||||
void icp_set_cppr(XICSState *icp, int server, uint8_t cppr);
|
||||
void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr);
|
||||
uint32_t icp_accept(ICPState *ss);
|
||||
uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr);
|
||||
void icp_eoi(XICSState *icp, int server, uint32_t xirr);
|
||||
|
||||
void ics_write_xive(ICSState *ics, int nr, int server,
|
||||
uint8_t priority, uint8_t saved_priority);
|
||||
|
||||
void ics_set_irq_type(ICSState *ics, int srcno, bool lsi);
|
||||
|
||||
int xics_find_source(XICSState *icp, int irq);
|
||||
|
||||
#endif /* __XICS_H__ */
|
||||
|
||||
+2
-2
@@ -4978,8 +4978,8 @@ Example for pseries machine type started with
|
||||
|
||||
-> { "execute": "query-hotpluggable-cpus" }
|
||||
<- {"return": [
|
||||
{ "props": { "core": 8 }, "type": "POWER8-spapr-cpu-core",
|
||||
{ "props": { "core-id": 8 }, "type": "POWER8-spapr-cpu-core",
|
||||
"vcpus-count": 1 },
|
||||
{ "props": { "core": 0 }, "type": "POWER8-spapr-cpu-core",
|
||||
{ "props": { "core-id": 0 }, "type": "POWER8-spapr-cpu-core",
|
||||
"vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
|
||||
]}'
|
||||
|
||||
@@ -70,18 +70,21 @@ enum powerpc_mmu_t {
|
||||
#define POWERPC_MMU_64 0x00010000
|
||||
#define POWERPC_MMU_1TSEG 0x00020000
|
||||
#define POWERPC_MMU_AMR 0x00040000
|
||||
#define POWERPC_MMU_64K 0x00080000
|
||||
/* 64 bits PowerPC MMU */
|
||||
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
|
||||
/* Architecture 2.03 and later (has LPCR) */
|
||||
POWERPC_MMU_2_03 = POWERPC_MMU_64 | 0x00000002,
|
||||
/* Architecture 2.06 variant */
|
||||
POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
|
||||
| POWERPC_MMU_64K
|
||||
| POWERPC_MMU_AMR | 0x00000003,
|
||||
/* Architecture 2.06 "degraded" (no 1T segments) */
|
||||
POWERPC_MMU_2_06a = POWERPC_MMU_64 | POWERPC_MMU_AMR
|
||||
| 0x00000003,
|
||||
/* Architecture 2.07 variant */
|
||||
POWERPC_MMU_2_07 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
|
||||
| POWERPC_MMU_64K
|
||||
| POWERPC_MMU_AMR | 0x00000004,
|
||||
/* Architecture 2.07 "degraded" (no 1T segments) */
|
||||
POWERPC_MMU_2_07a = POWERPC_MMU_64 | POWERPC_MMU_AMR
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user