ppc patch queue 2019-10-04

Here's the next batch of ppc and spapr patches.  Includes:
   * Fist part of a large cleanup to irq infrastructure
   * Recreate the full FDT at CAS time, instead of making a difficult
     to follow set of updates.  This will help us move towards
     eliminating CAS reboots altogether
   * No longer provide RTAS blob to SLOF - SLOF can include it just as
     well itself, since guests will generally need to relocate it with
     a call to instantiate-rtas
   * A number of DFP fixes and cleanups from Mark Cave-Ayland
   * Assorted bugfixes
   * Several new small devices for powernv
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAl2XEn0ACgkQbDjKyiDZ
 s5I6bA/7B5sjY/QxuE8axm5KupoAnE8zf205hN8mbYASwtDfFwgaeNreVaOSJUpr
 fgcx/g9G3rAryGZv3O6i02+wcRgNw1DnJ3ynCthIrExZEcfbTYJiS4s9apwPEQy8
 HFmBNdPDqrhFI0aFvXEUauiOp1aapPUUklm34eFscs94lJXxphRUEfa3XT5uEhUh
 xrIZwYq20A+ih4UHwk3Onyx/cvFpl6BRB2nVEllQFqzwF5eTTfz9t8+JGTebxD/7
 8qqt8ti0KM3wxSDTQnmyMUmpgy+C1iCvNYvv6nWFg+07QuGs48EHlQUUVVni4r9j
 kUrDwKS2eC+8e8gP/xdIXEq3R2DsAMq+wFIswXZ3X6x4DoUV0OAJSHc9iMD4l+pr
 LyWnVpDprc6XhJHWKpuHZ5w9EuBnZFbIXdlZGFno+8UvXtusnbbuwAZzHTrRJRqe
 /AWVpFwGAoOF4KxIOFlPVBI8m4vFad/soVojC0vzIbRqaogOFZAjiL/yD5GwLmMa
 tywOEMBUJ/j2lgudTCyKn5uCa/Ew3DS1TSdenJjyqRi/gZM0IaORIhJhyFYW/eO1
 U7Uh8BnbC+4J11wwvFR5+W789dgM2+EEtAX9uI08VcE/R2ASabZlN4Zwrl0w4cb/
 VRybMT4bgmjzHRpfrqYPxpn8wqPcIw0BCeipSOjY3QU1Q25TEYQ=
 =PXXe
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.2-20191004' into staging

ppc patch queue 2019-10-04

Here's the next batch of ppc and spapr patches.  Includes:
  * Fist part of a large cleanup to irq infrastructure
  * Recreate the full FDT at CAS time, instead of making a difficult
    to follow set of updates.  This will help us move towards
    eliminating CAS reboots altogether
  * No longer provide RTAS blob to SLOF - SLOF can include it just as
    well itself, since guests will generally need to relocate it with
    a call to instantiate-rtas
  * A number of DFP fixes and cleanups from Mark Cave-Ayland
  * Assorted bugfixes
  * Several new small devices for powernv

# gpg: Signature made Fri 04 Oct 2019 10:35:57 BST
# 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-4.2-20191004: (53 commits)
  ppc/pnv: Remove the XICSFabric Interface from the POWER9 machine
  spapr: Eliminate SpaprIrq::init hook
  spapr: Add return value to spapr_irq_check()
  spapr: Use less cryptic representation of which irq backends are supported
  xive: Improve irq claim/free path
  spapr, xics, xive: Better use of assert()s on irq claim/free paths
  spapr: Handle freeing of multiple irqs in frontend only
  spapr: Remove unhelpful tracepoints from spapr_irq_free_xics()
  spapr: Eliminate SpaprIrq:get_nodename method
  spapr: Simplify spapr_qirq() handling
  spapr: Fix indexing of XICS irqs
  spapr: Eliminate nr_irqs parameter to SpaprIrq::init
  spapr: Clarify and fix handling of nr_irqs
  spapr: Replace spapr_vio_qirq() helper with spapr_vio_irq_pulse() helper
  spapr: Fold spapr_phb_lsi_qirq() into its single caller
  xics: Create sPAPR specific ICS subtype
  xics: Merge TYPE_ICS_BASE and TYPE_ICS_SIMPLE classes
  xics: Eliminate reset hook
  xics: Rename misleading ics_simple_*() functions
  xics: Eliminate 'reject', 'resend' and 'eoi' class hooks
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-10-07 13:49:02 +01:00
commit 0f0b43868a
54 changed files with 1422 additions and 1094 deletions

View file

@ -5,7 +5,6 @@
#include "cpu.h"
#include "migration/vmstate.h"
#include "chardev/char-fe.h"
#include "hw/irq.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "hw/qdev-properties.h"
@ -37,7 +36,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
if ((dev->in == dev->out) && size) {
/* toggle line to simulate edge interrupt */
qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
spapr_vio_irq_pulse(&dev->sdev);
}
for (i = 0; i < size; i++) {
if (dev->in - dev->out >= VTERM_BUFSIZE) {

View file

@ -528,12 +528,15 @@ static void spapr_xive_register_types(void)
type_init(spapr_xive_register_types)
bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi)
int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp)
{
XiveSource *xsrc = &xive->source;
if (lisn >= xive->nr_irqs) {
return false;
assert(lisn < xive->nr_irqs);
if (xive_eas_is_valid(&xive->eat[lisn])) {
error_setg(errp, "IRQ %d is not free", lisn);
return -EBUSY;
}
/*
@ -545,26 +548,17 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi)
}
if (kvm_irqchip_in_kernel()) {
Error *local_err = NULL;
kvmppc_xive_source_reset_one(xsrc, lisn, &local_err);
if (local_err) {
error_report_err(local_err);
return false;
}
return kvmppc_xive_source_reset_one(xsrc, lisn, errp);
}
return true;
return 0;
}
bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn)
void spapr_xive_irq_free(SpaprXive *xive, int lisn)
{
if (lisn >= xive->nr_irqs) {
return false;
}
assert(lisn < xive->nr_irqs);
xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID);
return true;
}
/*

View file

@ -232,14 +232,14 @@ void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp)
* only need to inform the KVM XIVE device about their type: LSI or
* MSI.
*/
void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
{
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
uint64_t state = 0;
/* The KVM XIVE device is not in use */
if (xive->fd == -1) {
return;
return -ENODEV;
}
if (xive_source_irq_is_lsi(xsrc, srcno)) {
@ -249,17 +249,22 @@ void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
}
}
kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state,
true, errp);
return kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state,
true, errp);
}
static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp)
{
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
int i;
for (i = 0; i < xsrc->nr_irqs; i++) {
Error *local_err = NULL;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
kvmppc_xive_source_reset_one(xsrc, i, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@ -328,11 +333,18 @@ uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset,
static void kvmppc_xive_source_get_state(XiveSource *xsrc)
{
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
int i;
for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
/* Perform a load without side effect to retrieve the PQ bits */
uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
/* and save PQ locally */
xive_source_esb_set(xsrc, i, pq);
@ -521,9 +533,14 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
*/
if (running) {
for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq = xive_source_esb_get(xsrc, i);
uint8_t pq;
uint8_t old_pq;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
pq = xive_source_esb_get(xsrc, i);
old_pq = xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8));
/*
@ -545,7 +562,13 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
* migration is in progress.
*/
for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
uint8_t pq;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
/*
* PQ is set to PENDING to possibly catch a triggered
@ -655,6 +678,17 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
continue;
}
/*
* We can only restore the source config if the source has been
* previously set in KVM. Since we don't do that for all interrupts
* at reset time anymore, let's do it now.
*/
kvmppc_xive_source_reset_one(&xive->source, i, &local_err);
if (local_err) {
error_report_err(local_err);
return -1;
}
kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err);
if (local_err) {
error_report_err(local_err);

View file

@ -66,12 +66,12 @@ xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx
xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR 0x%"PRIx32" new XIRR 0x%"PRIx32
xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq 0x%"PRIx32" priority 0x%x"
xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=0x%x new pending priority=0x%x"
xics_ics_simple_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]"
xics_ics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]"
xics_masked_pending(void) "set_irq_msi: masked pending"
xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]"
xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x"
xics_ics_simple_reject(int nr, int srcno) "reject irq 0x%x [src %d]"
xics_ics_simple_eoi(int nr) "ics_eoi: irq 0x%x"
xics_ics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]"
xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x"
xics_ics_reject(int nr, int srcno) "reject irq 0x%x [src %d]"
xics_ics_eoi(int nr) "ics_eoi: irq 0x%x"
# s390_flic_kvm.c
flic_create_device(int err) "flic: create device failed %d"

View file

@ -98,32 +98,8 @@ void ics_pic_print_info(ICSState *ics, Monitor *mon)
#define XISR(icp) (((icp)->xirr) & XISR_MASK)
#define CPPR(icp) (((icp)->xirr) >> 24)
static void ics_reject(ICSState *ics, uint32_t nr)
{
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
if (k->reject) {
k->reject(ics, nr);
}
}
void ics_resend(ICSState *ics)
{
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
if (k->resend) {
k->resend(ics);
}
}
static void ics_eoi(ICSState *ics, int nr)
{
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
if (k->eoi) {
k->eoi(ics, nr);
}
}
static void ics_reject(ICSState *ics, uint32_t nr);
static void ics_eoi(ICSState *ics, uint32_t nr);
static void icp_check_ipi(ICPState *icp)
{
@ -427,7 +403,7 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp)
/*
* ICS: Source layer
*/
static void ics_simple_resend_msi(ICSState *ics, int srcno)
static void ics_resend_msi(ICSState *ics, int srcno)
{
ICSIRQState *irq = ics->irqs + srcno;
@ -440,7 +416,7 @@ static void ics_simple_resend_msi(ICSState *ics, int srcno)
}
}
static void ics_simple_resend_lsi(ICSState *ics, int srcno)
static void ics_resend_lsi(ICSState *ics, int srcno)
{
ICSIRQState *irq = ics->irqs + srcno;
@ -452,11 +428,11 @@ static void ics_simple_resend_lsi(ICSState *ics, int srcno)
}
}
static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val)
static void ics_set_irq_msi(ICSState *ics, int srcno, int val)
{
ICSIRQState *irq = ics->irqs + srcno;
trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset);
trace_xics_ics_set_irq_msi(srcno, srcno + ics->offset);
if (val) {
if (irq->priority == 0xff) {
@ -468,20 +444,20 @@ static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val)
}
}
static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val)
static void ics_set_irq_lsi(ICSState *ics, int srcno, int val)
{
ICSIRQState *irq = ics->irqs + srcno;
trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset);
trace_xics_ics_set_irq_lsi(srcno, srcno + ics->offset);
if (val) {
irq->status |= XICS_STATUS_ASSERTED;
} else {
irq->status &= ~XICS_STATUS_ASSERTED;
}
ics_simple_resend_lsi(ics, srcno);
ics_resend_lsi(ics, srcno);
}
void ics_simple_set_irq(void *opaque, int srcno, int val)
void ics_set_irq(void *opaque, int srcno, int val)
{
ICSState *ics = (ICSState *)opaque;
@ -491,13 +467,13 @@ void ics_simple_set_irq(void *opaque, int srcno, int val)
}
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
ics_simple_set_irq_lsi(ics, srcno, val);
ics_set_irq_lsi(ics, srcno, val);
} else {
ics_simple_set_irq_msi(ics, srcno, val);
ics_set_irq_msi(ics, srcno, val);
}
}
static void ics_simple_write_xive_msi(ICSState *ics, int srcno)
static void ics_write_xive_msi(ICSState *ics, int srcno)
{
ICSIRQState *irq = ics->irqs + srcno;
@ -510,13 +486,13 @@ static void ics_simple_write_xive_msi(ICSState *ics, int srcno)
icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
}
static void ics_simple_write_xive_lsi(ICSState *ics, int srcno)
static void ics_write_xive_lsi(ICSState *ics, int srcno)
{
ics_simple_resend_lsi(ics, srcno);
ics_resend_lsi(ics, srcno);
}
void ics_simple_write_xive(ICSState *ics, int srcno, int server,
uint8_t priority, uint8_t saved_priority)
void ics_write_xive(ICSState *ics, int srcno, int server,
uint8_t priority, uint8_t saved_priority)
{
ICSIRQState *irq = ics->irqs + srcno;
@ -524,21 +500,20 @@ void ics_simple_write_xive(ICSState *ics, int srcno, int server,
irq->priority = priority;
irq->saved_priority = saved_priority;
trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server,
priority);
trace_xics_ics_write_xive(ics->offset + srcno, srcno, server, priority);
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
ics_simple_write_xive_lsi(ics, srcno);
ics_write_xive_lsi(ics, srcno);
} else {
ics_simple_write_xive_msi(ics, srcno);
ics_write_xive_msi(ics, srcno);
}
}
static void ics_simple_reject(ICSState *ics, uint32_t nr)
static void ics_reject(ICSState *ics, uint32_t nr)
{
ICSIRQState *irq = ics->irqs + nr - ics->offset;
trace_xics_ics_simple_reject(nr, nr - ics->offset);
trace_xics_ics_reject(nr, nr - ics->offset);
if (irq->flags & XICS_FLAGS_IRQ_MSI) {
irq->status |= XICS_STATUS_REJECTED;
} else if (irq->flags & XICS_FLAGS_IRQ_LSI) {
@ -546,100 +521,41 @@ static void ics_simple_reject(ICSState *ics, uint32_t nr)
}
}
static void ics_simple_resend(ICSState *ics)
void ics_resend(ICSState *ics)
{
int i;
for (i = 0; i < ics->nr_irqs; i++) {
/* FIXME: filter by server#? */
if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
ics_simple_resend_lsi(ics, i);
ics_resend_lsi(ics, i);
} else {
ics_simple_resend_msi(ics, i);
ics_resend_msi(ics, i);
}
}
}
static void ics_simple_eoi(ICSState *ics, uint32_t nr)
static void ics_eoi(ICSState *ics, uint32_t nr)
{
int srcno = nr - ics->offset;
ICSIRQState *irq = ics->irqs + srcno;
trace_xics_ics_simple_eoi(nr);
trace_xics_ics_eoi(nr);
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
irq->status &= ~XICS_STATUS_SENT;
}
}
static void ics_simple_reset(DeviceState *dev)
{
ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev);
icsc->parent_reset(dev);
if (kvm_irqchip_in_kernel()) {
Error *local_err = NULL;
ics_set_kvm_state(ICS_BASE(dev), &local_err);
if (local_err) {
error_report_err(local_err);
}
}
}
static void ics_simple_reset_handler(void *dev)
{
ics_simple_reset(dev);
}
static void ics_simple_realize(DeviceState *dev, Error **errp)
{
ICSState *ics = ICS_SIMPLE(dev);
ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics);
Error *local_err = NULL;
icsc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
qemu_register_reset(ics_simple_reset_handler, ics);
}
static void ics_simple_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_BASE_CLASS(klass);
device_class_set_parent_realize(dc, ics_simple_realize,
&isc->parent_realize);
device_class_set_parent_reset(dc, ics_simple_reset,
&isc->parent_reset);
isc->reject = ics_simple_reject;
isc->resend = ics_simple_resend;
isc->eoi = ics_simple_eoi;
}
static const TypeInfo ics_simple_info = {
.name = TYPE_ICS_SIMPLE,
.parent = TYPE_ICS_BASE,
.instance_size = sizeof(ICSState),
.class_init = ics_simple_class_init,
.class_size = sizeof(ICSStateClass),
};
static void ics_reset_irq(ICSIRQState *irq)
{
irq->priority = 0xff;
irq->saved_priority = 0xff;
}
static void ics_base_reset(DeviceState *dev)
static void ics_reset(DeviceState *dev)
{
ICSState *ics = ICS_BASE(dev);
ICSState *ics = ICS(dev);
int i;
uint8_t flags[ics->nr_irqs];
@ -653,17 +569,31 @@ static void ics_base_reset(DeviceState *dev)
ics_reset_irq(ics->irqs + i);
ics->irqs[i].flags = flags[i];
}
if (kvm_irqchip_in_kernel()) {
Error *local_err = NULL;
ics_set_kvm_state(ICS(dev), &local_err);
if (local_err) {
error_report_err(local_err);
}
}
}
static void ics_base_realize(DeviceState *dev, Error **errp)
static void ics_reset_handler(void *dev)
{
ICSState *ics = ICS_BASE(dev);
Object *obj;
Error *err = NULL;
ics_reset(dev);
}
obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err);
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, err,
error_propagate_prepend(errp, local_err,
"required link '" ICS_PROP_XICS
"' not found: ");
return;
@ -675,16 +605,18 @@ static void ics_base_realize(DeviceState *dev, Error **errp)
return;
}
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
qemu_register_reset(ics_reset_handler, ics);
}
static void ics_base_instance_init(Object *obj)
static void ics_instance_init(Object *obj)
{
ICSState *ics = ICS_BASE(obj);
ICSState *ics = ICS(obj);
ics->offset = XICS_IRQ_BASE;
}
static int ics_base_pre_save(void *opaque)
static int ics_pre_save(void *opaque)
{
ICSState *ics = opaque;
@ -695,7 +627,7 @@ static int ics_base_pre_save(void *opaque)
return 0;
}
static int ics_base_post_load(void *opaque, int version_id)
static int ics_post_load(void *opaque, int version_id)
{
ICSState *ics = opaque;
@ -713,7 +645,7 @@ static int ics_base_post_load(void *opaque, int version_id)
return 0;
}
static const VMStateDescription vmstate_ics_base_irq = {
static const VMStateDescription vmstate_ics_irq = {
.name = "ics/irq",
.version_id = 2,
.minimum_version_id = 1,
@ -727,45 +659,44 @@ static const VMStateDescription vmstate_ics_base_irq = {
},
};
static const VMStateDescription vmstate_ics_base = {
static const VMStateDescription vmstate_ics = {
.name = "ics",
.version_id = 1,
.minimum_version_id = 1,
.pre_save = ics_base_pre_save,
.post_load = ics_base_post_load,
.pre_save = ics_pre_save,
.post_load = ics_post_load,
.fields = (VMStateField[]) {
/* Sanity check */
VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
vmstate_ics_base_irq,
vmstate_ics_irq,
ICSIRQState),
VMSTATE_END_OF_LIST()
},
};
static Property ics_base_properties[] = {
static Property ics_properties[] = {
DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void ics_base_class_init(ObjectClass *klass, void *data)
static void ics_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ics_base_realize;
dc->props = ics_base_properties;
dc->reset = ics_base_reset;
dc->vmsd = &vmstate_ics_base;
dc->realize = ics_realize;
dc->props = ics_properties;
dc->reset = ics_reset;
dc->vmsd = &vmstate_ics;
}
static const TypeInfo ics_base_info = {
.name = TYPE_ICS_BASE,
static const TypeInfo ics_info = {
.name = TYPE_ICS,
.parent = TYPE_DEVICE,
.abstract = true,
.instance_size = sizeof(ICSState),
.instance_init = ics_base_instance_init,
.class_init = ics_base_class_init,
.instance_init = ics_instance_init,
.class_init = ics_class_init,
.class_size = sizeof(ICSStateClass),
};
@ -805,8 +736,7 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
static void xics_register_types(void)
{
type_register_static(&ics_simple_info);
type_register_static(&ics_base_info);
type_register_static(&ics_info);
type_register_static(&icp_info);
type_register_static(&xics_fabric_info);
}

View file

@ -190,6 +190,10 @@ void ics_get_kvm_state(ICSState *ics)
for (i = 0; i < ics->nr_irqs; i++) {
ICSIRQState *irq = &ics->irqs[i];
if (ics_irq_free(ics, i)) {
continue;
}
kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
i + ics->offset, &state, false, &error_fatal);
@ -301,6 +305,10 @@ int ics_set_kvm_state(ICSState *ics, Error **errp)
Error *local_err = NULL;
int ret;
if (ics_irq_free(ics, i)) {
continue;
}
ret = ics_set_kvm_state_one(ics, i, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);

View file

@ -179,7 +179,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr,
}
srcno = nr - ics->offset;
ics_simple_write_xive(ics, srcno, server, priority, priority);
ics_write_xive(ics, srcno, server, priority, priority);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
@ -243,8 +243,8 @@ static void rtas_int_off(PowerPCCPU *cpu, SpaprMachineState *spapr,
}
srcno = nr - ics->offset;
ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff,
ics->irqs[srcno].priority);
ics_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff,
ics->irqs[srcno].priority);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
@ -276,15 +276,25 @@ static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr,
}
srcno = nr - ics->offset;
ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server,
ics->irqs[srcno].saved_priority,
ics->irqs[srcno].saved_priority);
ics_write_xive(ics, srcno, ics->irqs[srcno].server,
ics->irqs[srcno].saved_priority,
ics->irqs[srcno].saved_priority);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
void xics_spapr_init(SpaprMachineState *spapr)
static void ics_spapr_realize(DeviceState *dev, Error **errp)
{
ICSState *ics = ICS_SPAPR(dev);
ICSStateClass *icsc = ICS_GET_CLASS(ics);
Error *local_err = NULL;
icsc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
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);
@ -306,7 +316,7 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
};
int node;
_FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME));
_FDT(node = fdt_add_subnode(fdt, 0, "interrupt-controller"));
_FDT(fdt_setprop_string(fdt, node, "device_type",
"PowerPC-External-Interrupt-Presentation"));
@ -319,3 +329,25 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
_FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle));
_FDT(fdt_setprop_cell(fdt, node, "phandle", phandle));
}
static void ics_spapr_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_CLASS(klass);
device_class_set_parent_realize(dc, ics_spapr_realize,
&isc->parent_realize);
}
static const TypeInfo ics_spapr_info = {
.name = TYPE_ICS_SPAPR,
.parent = TYPE_ICS,
.class_init = ics_spapr_class_init,
};
static void xics_spapr_register_types(void)
{
type_register_static(&ics_spapr_info);
}
type_init(xics_spapr_register_types)

View file

@ -1396,6 +1396,14 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format,
XiveTCTX *tctx = xive_router_get_tctx(xrtr, cs);
int ring;
/*
* Skip partially initialized vCPUs. This can happen when
* vCPUs are hotplugged.
*/
if (!tctx) {
continue;
}
/*
* HW checks that the CPU is enabled in the Physical Thread
* Enable Register (PTER).

View file

@ -27,7 +27,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "hw/irq.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "net/net.h"
@ -267,7 +266,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
}
if (sdev->signal_state & 1) {
qemu_irq_pulse(spapr_vio_qirq(sdev));
spapr_vio_irq_pulse(sdev);
}
return size;

View file

@ -9,6 +9,7 @@ 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
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
obj-y += spapr_pci_vfio.o spapr_pci_nvlink2.o
endif

View file

@ -187,7 +187,8 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
_FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
_FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
_FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size",
cpu->hash64_opts->slb_size)));
_FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
@ -200,19 +201,23 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
segs, sizeof(segs))));
}
/* Advertise VMX/VSX (vector extensions) if available
/*
* Advertise VMX/VSX (vector extensions) if available
* 0 / no property == no vector extensions
* 1 == VMX / Altivec available
* 2 == VSX available */
* 2 == VSX available
*/
if (env->insns_flags & PPC_ALTIVEC) {
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
_FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
}
/* Advertise DFP (Decimal Floating Point) if available
/*
* Advertise DFP (Decimal Floating Point) if available
* 0 / no property == no DFP
* 1 == DFP available */
* 1 == DFP available
*/
if (env->insns_flags2 & PPC2_DFP) {
_FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
}
@ -424,7 +429,8 @@ static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
return 0;
}
/* The default LPC bus of a multichip system is on chip 0. It's
/*
* The default LPC bus of a multichip system is on chip 0. It's
* recognized by the firmware (skiboot) using a "primary" property.
*/
static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
@ -442,8 +448,10 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
assert(phandle > 0);
_FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle)));
/* ISA devices are not necessarily parented to the ISA bus so we
* can not use object_child_foreach() */
/*
* ISA devices are not necessarily parented to the ISA bus so we
* can not use object_child_foreach()
*/
qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
&args);
}
@ -545,7 +553,8 @@ static void pnv_reset(MachineState *machine)
qemu_devices_reset();
/* OpenPOWER systems have a BMC, which can be defined on the
/*
* OpenPOWER systems have a BMC, which can be defined on the
* command line with:
*
* -device ipmi-bmc-sim,id=bmc0
@ -705,7 +714,8 @@ static void pnv_init(MachineState *machine)
pnv->chips[i] = PNV_CHIP(chip);
/* TODO: put all the memory in one node on chip 0 until we find a
/*
* TODO: put all the memory in one node on chip 0 until we find a
* way to specify different ranges for each chip
*/
if (i == 0) {
@ -732,8 +742,10 @@ static void pnv_init(MachineState *machine)
/* Create an RTC ISA device too */
mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
/* OpenPOWER systems use a IPMI SEL Event message to notify the
* host to powerdown */
/*
* OpenPOWER systems use a IPMI SEL Event message to notify the
* host to powerdown
*/
pnv->powerdown_notifier.notify = pnv_powerdown_notify;
qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
}
@ -803,7 +815,8 @@ static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
pnv_cpu->intc = obj;
}
/* Allowed core identifiers on a POWER8 Processor Chip :
/*
* Allowed core identifiers on a POWER8 Processor Chip :
*
* <EX0 reserved>
* EX1 - Venice only
@ -847,6 +860,11 @@ static void pnv_chip_power8_instance_init(Object *obj)
TYPE_PNV8_OCC, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip8->occ), "psi",
OBJECT(&chip8->psi), &error_abort);
object_initialize_child(obj, "homer", &chip8->homer, sizeof(chip8->homer),
TYPE_PNV8_HOMER, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip8->homer), "chip", obj,
&error_abort);
}
static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
@ -923,8 +941,10 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
(uint64_t) PNV_XSCOM_BASE(chip),
PNV_XSCOM_LPC_BASE);
/* Interrupt Management Area. This is the memory region holding
* all the Interrupt Control Presenter (ICP) registers */
/*
* Interrupt Management Area. This is the memory region holding
* all the Interrupt Control Presenter (ICP) registers
*/
pnv_chip_icp_realize(chip8, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@ -938,6 +958,20 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
return;
}
pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
/* OCC SRAM model */
memory_region_add_subregion(get_system_memory(), PNV_OCC_COMMON_AREA(chip),
&chip8->occ.sram_regs);
/* HOMER */
object_property_set_bool(OBJECT(&chip8->homer), true, "realized",
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip),
&chip8->homer.regs);
}
static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
@ -1020,6 +1054,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
TYPE_PNV9_OCC, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip9->occ), "psi",
OBJECT(&chip9->psi), &error_abort);
object_initialize_child(obj, "homer", &chip9->homer, sizeof(chip9->homer),
TYPE_PNV9_HOMER, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip9->homer), "chip", obj,
&error_abort);
}
static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
@ -1126,6 +1165,20 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
return;
}
pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
/* OCC SRAM model */
memory_region_add_subregion(get_system_memory(), PNV9_OCC_COMMON_AREA(chip),
&chip9->occ.sram_regs);
/* HOMER */
object_property_set_bool(OBJECT(&chip9->homer), true, "realized",
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip),
&chip9->homer.regs);
}
static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
@ -1404,8 +1457,8 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
mc->init = pnv_init;
mc->reset = pnv_reset;
mc->max_cpus = MAX_CPUS;
mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
* storage */
/* Pnv provides a AHCI device for storage */
mc->block_default_type = IF_IDE;
mc->no_parallel = 1;
mc->default_boot_order = NULL;
/*
@ -1432,23 +1485,21 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
.parent = TYPE_PNV9_CHIP, \
}
#define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn) \
{ \
.name = MACHINE_TYPE_NAME(cpu), \
.parent = TYPE_PNV_MACHINE, \
.instance_size = sizeof(PnvMachineState), \
.instance_init = pnv_machine_instance_init, \
.class_init = class_initfn, \
.interfaces = (InterfaceInfo[]) { \
{ TYPE_XICS_FABRIC }, \
{ TYPE_INTERRUPT_STATS_PROVIDER }, \
{ }, \
}, \
}
static const TypeInfo types[] = {
DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init),
DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init),
{
.name = MACHINE_TYPE_NAME("powernv9"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power9_class_init,
},
{
.name = MACHINE_TYPE_NAME("powernv8"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power8_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
{ },
},
},
{
.name = TYPE_PNV_MACHINE,
.parent = TYPE_MACHINE,
@ -1457,7 +1508,6 @@ static const TypeInfo types[] = {
.instance_init = pnv_machine_instance_init,
.class_init = pnv_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ },
},

View file

@ -77,13 +77,10 @@ void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt)
const struct ipmi_sdr_compact *sdr;
uint16_t nextrec;
offset = fdt_add_subnode(fdt, 0, "/bmc");
offset = fdt_add_subnode(fdt, 0, "bmc");
_FDT(offset);
_FDT((fdt_setprop_string(fdt, offset, "name", "bmc")));
_FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1)));
_FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0)));
offset = fdt_add_subnode(fdt, offset, "sensors");
_FDT(offset);

272
hw/ppc/pnv_homer.c Normal file
View file

@ -0,0 +1,272 @@
/*
* QEMU PowerPC PowerNV Emulation of a few HOMER related registers
*
* Copyright (c) 2019, IBM Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "exec/hwaddr.h"
#include "exec/memory.h"
#include "sysemu/cpus.h"
#include "hw/qdev-core.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_homer.h"
static bool core_max_array(PnvHomer *homer, hwaddr addr)
{
int i;
PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
for (i = 0; i <= homer->chip->nr_cores; i++) {
if (addr == (hmrc->core_max_base + i)) {
return true;
}
}
return false;
}
/* P8 Pstate table */
#define PNV8_OCC_PSTATE_VERSION 0x1f8001
#define PNV8_OCC_PSTATE_MIN 0x1f8003
#define PNV8_OCC_PSTATE_VALID 0x1f8000
#define PNV8_OCC_PSTATE_THROTTLE 0x1f8002
#define PNV8_OCC_PSTATE_NOM 0x1f8004
#define PNV8_OCC_PSTATE_TURBO 0x1f8005
#define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006
#define PNV8_OCC_PSTATE_DATA 0x1f8008
#define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010
#define PNV8_OCC_PSTATE_ID_ONE 0x1f8018
#define PNV8_OCC_PSTATE_ID_TWO 0x1f8020
#define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012
#define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013
#define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014
#define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c
#define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024
#define PNV8_CORE_MAX_BASE 0x1f8810
static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvHomer *homer = PNV_HOMER(opaque);
switch (addr) {
case PNV8_OCC_PSTATE_VERSION:
case PNV8_OCC_PSTATE_MIN:
case PNV8_OCC_PSTATE_ID_ZERO:
return 0;
case PNV8_OCC_PSTATE_VALID:
case PNV8_OCC_PSTATE_THROTTLE:
case PNV8_OCC_PSTATE_NOM:
case PNV8_OCC_PSTATE_TURBO:
case PNV8_OCC_PSTATE_ID_ONE:
case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER:
case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER:
return 1;
case PNV8_OCC_PSTATE_ULTRA_TURBO:
case PNV8_OCC_PSTATE_ID_TWO:
return 2;
case PNV8_OCC_PSTATE_DATA:
return 0x1000000000000000;
/* P8 frequency for 0, 1, and 2 pstates */
case PNV8_OCC_PSTATE_ZERO_FREQUENCY:
case PNV8_OCC_PSTATE_ONE_FREQUENCY:
case PNV8_OCC_PSTATE_TWO_FREQUENCY:
return 3000;
}
/* pstate table core max array */
if (core_max_array(homer, addr)) {
return 1;
}
return 0;
}
static void pnv_power8_homer_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
/* callback function defined to homer write */
return;
}
static const MemoryRegionOps pnv_power8_homer_ops = {
.read = pnv_power8_homer_read,
.write = pnv_power8_homer_write,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.impl.min_access_size = 1,
.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->homer_size = PNV_HOMER_SIZE;
homer->homer_ops = &pnv_power8_homer_ops;
homer->core_max_base = PNV8_CORE_MAX_BASE;
}
static const TypeInfo pnv_homer_power8_type_info = {
.name = TYPE_PNV8_HOMER,
.parent = TYPE_PNV_HOMER,
.instance_size = sizeof(PnvHomer),
.class_init = pnv_homer_power8_class_init,
};
/* P9 Pstate table */
#define PNV9_OCC_PSTATE_ID_ZERO 0xe2018
#define PNV9_OCC_PSTATE_ID_ONE 0xe2020
#define PNV9_OCC_PSTATE_ID_TWO 0xe2028
#define PNV9_OCC_PSTATE_DATA 0xe2000
#define PNV9_OCC_PSTATE_DATA_AREA 0xe2008
#define PNV9_OCC_PSTATE_MIN 0xe2003
#define PNV9_OCC_PSTATE_NOM 0xe2004
#define PNV9_OCC_PSTATE_TURBO 0xe2005
#define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818
#define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006
#define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001
#define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85
#define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008
#define PNV9_CHIP_HOMER_BASE 0x0
#define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c
#define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024
#define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c
#define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002
#define PNV9_CORE_MAX_BASE 0xe2819
static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvHomer *homer = PNV_HOMER(opaque);
switch (addr) {
case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO:
case PNV9_OCC_PSTATE_ID_ZERO:
return 0;
case PNV9_OCC_PSTATE_DATA:
case PNV9_OCC_ROLE_MASTER_OR_SLAVE:
case PNV9_OCC_PSTATE_NOM:
case PNV9_OCC_PSTATE_TURBO:
case PNV9_OCC_PSTATE_ID_ONE:
case PNV9_OCC_PSTATE_ULTRA_TURBO:
case PNV9_OCC_OPAL_RUNTIME_DATA:
return 1;
case PNV9_OCC_PSTATE_MIN:
case PNV9_OCC_PSTATE_ID_TWO:
return 2;
/* 3000 khz frequency for 0, 1, and 2 pstates */
case PNV9_OCC_PSTATE_ZERO_FREQUENCY:
case PNV9_OCC_PSTATE_ONE_FREQUENCY:
case PNV9_OCC_PSTATE_TWO_FREQUENCY:
return 3000;
case PNV9_OCC_PSTATE_MAJOR_VERSION:
return 0x90;
case PNV9_CHIP_HOMER_BASE:
case PNV9_OCC_PSTATE_DATA_AREA:
case PNV9_CHIP_HOMER_IMAGE_POINTER:
return 0x1000000000000000;
}
/* pstate table core max array */
if (core_max_array(homer, addr)) {
return 1;
}
return 0;
}
static void pnv_power9_homer_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
/* callback function defined to homer write */
return;
}
static const MemoryRegionOps pnv_power9_homer_ops = {
.read = pnv_power9_homer_read,
.write = pnv_power9_homer_write,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.impl.min_access_size = 1,
.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->homer_size = PNV9_HOMER_SIZE;
homer->homer_ops = &pnv_power9_homer_ops;
homer->core_max_base = PNV9_CORE_MAX_BASE;
}
static const TypeInfo pnv_homer_power9_type_info = {
.name = TYPE_PNV9_HOMER,
.parent = TYPE_PNV_HOMER,
.instance_size = sizeof(PnvHomer),
.class_init = pnv_homer_power9_class_init,
};
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);
/* homer region */
memory_region_init_io(&homer->regs, OBJECT(dev),
hmrc->homer_ops, homer, "homer-main-memory",
hmrc->homer_size);
}
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";
}
static const TypeInfo pnv_homer_type_info = {
.name = TYPE_PNV_HOMER,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvHomer),
.class_init = pnv_homer_class_init,
.class_size = sizeof(PnvHomerClass),
.abstract = true,
};
static void pnv_homer_register_types(void)
{
type_register_static(&pnv_homer_type_info);
type_register_static(&pnv_homer_power8_type_info);
type_register_static(&pnv_homer_power9_type_info);
}
type_init(pnv_homer_register_types);

View file

@ -30,6 +30,24 @@
#define OCB_OCI_OCCMISC_AND 0x4021
#define OCB_OCI_OCCMISC_OR 0x4022
/* OCC sensors */
#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000
#define OCC_SENSOR_DATA_VALID 0x580001
#define OCC_SENSOR_DATA_VERSION 0x580002
#define OCC_SENSOR_DATA_READING_VERSION 0x580004
#define OCC_SENSOR_DATA_NR_SENSORS 0x580008
#define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010
#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014
#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c
#define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d
#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023
#define OCC_SENSOR_LOC_CORE 0x580022
#define OCC_SENSOR_LOC_GPU 0x580020
#define OCC_SENSOR_TYPE_POWER 0x580003
#define OCC_SENSOR_NAME 0x580005
#define HWMON_SENSORS_MASK 0x58001e
#define SLW_IMAGE_BASE 0x0
static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
{
bool irq_state;
@ -82,6 +100,48 @@ static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr,
}
}
static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
unsigned width)
{
switch (addr) {
/*
* occ-sensor sanity check that asserts the sensor
* header block
*/
case OCC_SENSOR_DATA_BLOCK_OFFSET:
case OCC_SENSOR_DATA_VALID:
case OCC_SENSOR_DATA_VERSION:
case OCC_SENSOR_DATA_READING_VERSION:
case OCC_SENSOR_DATA_NR_SENSORS:
case OCC_SENSOR_DATA_NAMES_OFFSET:
case OCC_SENSOR_DATA_READING_PING_OFFSET:
case OCC_SENSOR_DATA_READING_PONG_OFFSET:
case OCC_SENSOR_NAME_STRUCTURE_TYPE:
return 1;
case OCC_SENSOR_DATA_NAME_LENGTH:
return 0x30;
case OCC_SENSOR_LOC_CORE:
return 0x0040;
case OCC_SENSOR_TYPE_POWER:
return 0x0080;
case OCC_SENSOR_NAME:
return 0x1000;
case HWMON_SENSORS_MASK:
case OCC_SENSOR_LOC_GPU:
return 0x8e00;
case SLW_IMAGE_BASE:
return 0x1000000000000000;
}
return 0;
}
static void pnv_occ_common_area_write(void *opaque, hwaddr addr,
uint64_t val, unsigned width)
{
/* callback function defined to occ common area write */
return;
}
static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
.read = pnv_occ_power8_xscom_read,
.write = pnv_occ_power8_xscom_write,
@ -92,12 +152,24 @@ static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
const MemoryRegionOps pnv_occ_sram_ops = {
.read = pnv_occ_common_area_read,
.write = pnv_occ_common_area_write,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.impl.min_access_size = 1,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
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;
}
@ -168,7 +240,9 @@ 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;
}
@ -199,6 +273,10 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
/* 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);
}
static void pnv_occ_class_init(ObjectClass *klass, void *data)

View file

@ -311,7 +311,7 @@ static void pnv_psi_set_xivr(PnvPsi *psi, uint32_t reg, uint64_t val)
* do for now but a more accurate implementation would instead
* use a fixed server/prio and a remapper of the generated irq.
*/
ics_simple_write_xive(ics, src, server, prio, prio);
ics_write_xive(ics, src, server, prio, prio);
}
static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio)
@ -469,7 +469,7 @@ static void pnv_psi_power8_instance_init(Object *obj)
Pnv8Psi *psi8 = PNV8_PSI(obj);
object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics),
TYPE_ICS_SIMPLE, &error_abort, NULL);
TYPE_ICS, &error_abort, NULL);
}
static const uint8_t irq_to_xivr[] = {
@ -514,7 +514,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
ics_set_irq_type(ics, i, true);
}
psi->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
psi->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
/* XSCOM region for PSI registers */
pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops,

View file

@ -36,6 +36,16 @@
#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)
{
/*
@ -74,6 +84,26 @@ 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 */
@ -93,13 +123,9 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
case 0x2020009: /* ADU stuff, error register */
case 0x202000f: /* ADU stuff, receive status register*/
return 0;
case 0x2013f00: /* PBA stuff */
case 0x2013f01: /* PBA stuff */
case 0x2013f02: /* PBA stuff */
case 0x2013f03: /* PBA stuff */
case 0x2013f04: /* PBA stuff */
case 0x2013f05: /* PBA stuff */
case 0x2013f06: /* PBA stuff */
case 0x2013f07: /* PBA stuff */
return 0;
case 0x2013028: /* CAPP stuff */

View file

@ -81,6 +81,8 @@
#include "hw/mem/memory-device.h"
#include "hw/ppc/spapr_tpm_proxy.h"
#include "monitor/monitor.h"
#include <libfdt.h>
/* SLOF memory layout:
@ -94,7 +96,6 @@
* We load our kernel at 4M, leaving space for SLOF initial image
*/
#define FDT_MAX_SIZE 0x100000
#define RTAS_MAX_SIZE 0x10000
#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */
#define FW_MAX_SIZE 0x400000
#define FW_FILE_NAME "slof.bin"
@ -218,8 +219,7 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
/* Populate the "ibm,pa-features" property */
static void spapr_populate_pa_features(SpaprMachineState *spapr,
PowerPCCPU *cpu,
void *fdt, int offset,
bool legacy_guest)
void *fdt, int offset)
{
uint8_t pa_features_206[] = { 6, 0,
0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
@ -285,7 +285,7 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr,
if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
pa_features[24] |= 0x80; /* Transactional memory support */
}
if (legacy_guest && pa_size > 40) {
if (spapr->cas_pre_isa3_guest && pa_size > 40) {
/* Workaround for broken kernels that attempt (guest) radix
* mode when they can't handle it, if they see the radix bit set
* in pa-features. So hide it from them. */
@ -295,65 +295,6 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr,
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
}
static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr)
{
MachineState *ms = MACHINE(spapr);
int ret = 0, offset, cpus_offset;
CPUState *cs;
char cpu_model[32];
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
DeviceClass *dc = DEVICE_GET_CLASS(cs);
int index = spapr_get_vcpu_id(cpu);
int compat_smt = MIN(ms->smp.threads, ppc_compat_max_vthreads(cpu));
if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
continue;
}
snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0) {
cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
if (cpus_offset < 0) {
return cpus_offset;
}
}
offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
if (offset < 0) {
offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
if (offset < 0) {
return offset;
}
}
ret = fdt_setprop(fdt, offset, "ibm,pft-size",
pft_size_prop, sizeof(pft_size_prop));
if (ret < 0) {
return ret;
}
if (ms->numa_state->num_nodes > 1) {
ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu);
if (ret < 0) {
return ret;
}
}
ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
if (ret < 0) {
return ret;
}
spapr_populate_pa_features(spapr, cpu, fdt, offset,
spapr->cas_legacy_guest_workaround);
}
return ret;
}
static hwaddr spapr_node0_size(MachineState *machine)
{
if (machine->numa_state->num_nodes) {
@ -388,7 +329,7 @@ static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
mem_reg_property[0] = cpu_to_be64(start);
mem_reg_property[1] = cpu_to_be64(size);
sprintf(mem_name, "memory@" TARGET_FMT_lx, start);
sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
off = fdt_add_subnode(fdt, 0, mem_name);
_FDT(off);
_FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
@ -551,7 +492,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
page_sizes_prop, page_sizes_prop_size)));
}
spapr_populate_pa_features(spapr, cpu, fdt, offset, false);
spapr_populate_pa_features(spapr, cpu, fdt, offset);
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
cs->cpu_index / vcpus_per_socket)));
@ -984,11 +925,13 @@ static bool spapr_hotplugged_dev_before_cas(void)
return false;
}
static void *spapr_build_fdt(SpaprMachineState *spapr);
int spapr_h_cas_compose_response(SpaprMachineState *spapr,
target_ulong addr, target_ulong size,
SpaprOptionVector *ov5_updates)
{
void *fdt, *fdt_skel;
void *fdt;
SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
if (spapr_hotplugged_dev_before_cas()) {
@ -1004,28 +947,11 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr,
size -= sizeof(hdr);
/* Create skeleton */
fdt_skel = g_malloc0(size);
_FDT((fdt_create(fdt_skel, size)));
_FDT((fdt_finish_reservemap(fdt_skel)));
_FDT((fdt_begin_node(fdt_skel, "")));
_FDT((fdt_end_node(fdt_skel)));
_FDT((fdt_finish(fdt_skel)));
fdt = g_malloc0(size);
_FDT((fdt_open_into(fdt_skel, fdt, size)));
g_free(fdt_skel);
/* Fixup cpu nodes */
_FDT((spapr_fixup_cpu_dt(fdt, spapr)));
if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
return -1;
}
/* Pack resulting tree */
fdt = spapr_build_fdt(spapr);
_FDT((fdt_pack(fdt)));
if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
g_free(fdt);
trace_spapr_cas_failed(size);
return -1;
}
@ -1033,7 +959,11 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr,
cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
g_free(fdt);
g_free(spapr->fdt_blob);
spapr->fdt_size = fdt_totalsize(fdt);
spapr->fdt_initial_size = spapr->fdt_size;
spapr->fdt_blob = fdt;
return 0;
}
@ -1136,19 +1066,28 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
char val[2 * 4] = {
23, spapr->irq->ov5, /* Xive mode. */
23, 0x00, /* XICS / XIVE mode */
24, 0x00, /* Hash/Radix, filled in below. */
25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
26, 0x40, /* Radix options: GTSE == yes. */
};
if (spapr->irq->xics && spapr->irq->xive) {
val[1] = SPAPR_OV5_XIVE_BOTH;
} else if (spapr->irq->xive) {
val[1] = SPAPR_OV5_XIVE_EXPLOIT;
} else {
assert(spapr->irq->xics);
val[1] = SPAPR_OV5_XIVE_LEGACY;
}
if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
first_ppc_cpu->compat_pvr)) {
/*
* If we're in a pre POWER9 compat mode then the guest should
* do hash and use the legacy interrupt mode
*/
val[1] = 0x00; /* XICS */
val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
val[3] = 0x00; /* Hash */
} else if (kvm_enabled()) {
if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
@ -1178,11 +1117,16 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
_FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
_FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline));
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
spapr->initrd_base));
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
spapr->initrd_base + spapr->initrd_size));
if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
_FDT(fdt_setprop_string(fdt, chosen, "bootargs",
machine->kernel_cmdline));
}
if (spapr->initrd_size) {
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
spapr->initrd_base));
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
spapr->initrd_base + spapr->initrd_size));
}
if (spapr->kernel_size) {
uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
@ -1717,8 +1661,7 @@ static void spapr_machine_reset(MachineState *machine)
{
SpaprMachineState *spapr = SPAPR_MACHINE(machine);
PowerPCCPU *first_ppc_cpu;
uint32_t rtas_limit;
hwaddr rtas_addr, fdt_addr;
hwaddr fdt_addr;
void *fdt;
int rc;
@ -1739,16 +1682,6 @@ static void spapr_machine_reset(MachineState *machine)
spapr_setup_hpt_and_vrma(spapr);
}
/*
* NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
* We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
* called from vPHB reset handler so we initialize the counter here.
* If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
* must be equally distant from any other node.
* The final value of spapr->gpu_numa_id is going to be written to
* max-associativity-domains in spapr_build_fdt().
*/
spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
qemu_devices_reset();
/*
@ -1792,14 +1725,10 @@ static void spapr_machine_reset(MachineState *machine)
* or just below 2GB, whichever is lower, so that it can be
* processed with 32-bit real mode code if necessary
*/
rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
rtas_addr = rtas_limit - RTAS_MAX_SIZE;
fdt_addr = rtas_addr - FDT_MAX_SIZE;
fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
fdt = spapr_build_fdt(spapr);
spapr_load_rtas(spapr, fdt, rtas_addr);
rc = fdt_pack(fdt);
/* Should only fail if we've built a corrupted tree */
@ -2847,13 +2776,57 @@ static void spapr_machine_init(MachineState *machine)
spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
/* advertise XIVE on POWER9 machines */
if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) {
if (spapr->irq->xive) {
spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
}
/* init CPUs */
spapr_init_cpus(spapr);
/*
* check we don't have a memory-less/cpu-less NUMA node
* Firmware relies on the existing memory/cpu topology to provide the
* NUMA topology to the kernel.
* And the linux kernel needs to know the NUMA topology at start
* to be able to hotplug CPUs later.
*/
if (machine->numa_state->num_nodes) {
for (i = 0; i < machine->numa_state->num_nodes; ++i) {
/* check for memory-less node */
if (machine->numa_state->nodes[i].node_mem == 0) {
CPUState *cs;
int found = 0;
/* check for cpu-less node */
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
if (cpu->node_id == i) {
found = 1;
break;
}
}
/* memory-less and cpu-less node */
if (!found) {
error_report(
"Memory-less/cpu-less nodes are not supported (node %d)",
i);
exit(1);
}
}
}
}
/*
* NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
* We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
* called from vPHB reset handler so we initialize the counter here.
* If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
* must be equally distant from any other node.
* The final value of spapr->gpu_numa_id is going to be written to
* max-associativity-domains in spapr_build_fdt().
*/
spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
spapr->max_compat_pvr)) {
@ -2915,28 +2888,6 @@ static void spapr_machine_init(MachineState *machine)
spapr_create_lmb_dr_connectors(spapr);
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
if (!filename) {
error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
exit(1);
}
spapr->rtas_size = get_image_size(filename);
if (spapr->rtas_size < 0) {
error_report("Could not get size of LPAR rtas '%s'", filename);
exit(1);
}
spapr->rtas_blob = g_malloc(spapr->rtas_size);
if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
error_report("Could not load LPAR rtas '%s'", filename);
exit(1);
}
if (spapr->rtas_size > RTAS_MAX_SIZE) {
error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
(size_t)spapr->rtas_size, RTAS_MAX_SIZE);
exit(1);
}
g_free(filename);
/* Set up RTAS event infrastructure */
spapr_events_init(spapr);
@ -4321,6 +4272,8 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
SpaprMachineState *spapr = SPAPR_MACHINE(obj);
spapr->irq->print_info(spapr, mon);
monitor_printf(mon, "irqchip: %s\n",
kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
}
int spapr_get_vcpu_id(PowerPCCPU *cpu)

View file

@ -1765,8 +1765,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
exit(EXIT_FAILURE);
}
}
spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest,
OV1_PPC_3_00);
spapr->cas_pre_isa3_guest = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00);
spapr_ovec_cleanup(ov1_guest);
if (!spapr->cas_reboot) {
/* If spapr_machine_reset() did not set up a HPT but one is necessary
@ -1785,13 +1784,13 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
* terminate the boot.
*/
if (guest_xive) {
if (spapr->irq->ov5 == SPAPR_OV5_XIVE_LEGACY) {
if (!spapr->irq->xive) {
error_report(
"Guest requested unavailable interrupt mode (XIVE), try the ic-mode=xive or ic-mode=dual machine property");
exit(EXIT_FAILURE);
}
} else {
if (spapr->irq->ov5 == SPAPR_OV5_XIVE_EXPLOIT) {
if (!spapr->irq->xics) {
error_report(
"Guest requested unavailable interrupt mode (XICS), either don't set the ic-mode machine property or try ic-mode=xics or ic-mode=dual");
exit(EXIT_FAILURE);
@ -1805,7 +1804,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
*/
if (!spapr->cas_reboot) {
spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT)
&& spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH;
&& spapr->irq->xics && spapr->irq->xive;
}
spapr_ovec_cleanup(ov5_updates);

View file

@ -92,44 +92,15 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr,
* XICS IRQ backend.
*/
static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
Object *obj;
Error *local_err = NULL;
obj = object_new(TYPE_ICS_SIMPLE);
object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
&error_fatal);
object_property_set_int(obj, nr_irqs, "nr-irqs", &error_fatal);
object_property_set_bool(obj, true, "realized", &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
spapr->ics = ICS_BASE(obj);
xics_spapr_init(spapr);
}
#define ICS_IRQ_FREE(ics, srcno) \
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
ICSState *ics = spapr->ics;
assert(ics);
assert(ics_valid_irq(ics, irq));
if (!ics_valid_irq(ics, irq)) {
error_setg(errp, "IRQ %d is invalid", irq);
return -1;
}
if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
if (!ics_irq_free(ics, irq - ics->offset)) {
error_setg(errp, "IRQ %d is not free", irq);
return -1;
}
@ -138,33 +109,14 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi,
return 0;
}
static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num)
{
ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset;
int i;
if (ics_valid_irq(ics, irq)) {
trace_spapr_irq_free(0, irq, num);
for (i = srcno; i < srcno + num; ++i) {
if (ICS_IRQ_FREE(ics, i)) {
trace_spapr_irq_free_warn(0, i);
}
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
}
}
}
static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq)
static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq)
{
ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset;
if (ics_valid_irq(ics, irq)) {
return spapr->qirqs[srcno];
}
assert(ics_valid_irq(ics, irq));
return NULL;
memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState));
}
static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon)
@ -209,11 +161,12 @@ static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id)
return 0;
}
static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val)
static void spapr_irq_set_irq_xics(void *opaque, int irq, int val)
{
SpaprMachineState *spapr = opaque;
uint32_t srcno = irq - spapr->ics->offset;
ics_simple_set_irq(spapr->ics, srcno, val);
ics_set_irq(spapr->ics, srcno, val);
}
static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp)
@ -227,11 +180,6 @@ static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp)
}
}
static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr)
{
return XICS_NODENAME;
}
static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp)
{
if (kvm_enabled()) {
@ -239,88 +187,36 @@ static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp)
}
}
#define SPAPR_IRQ_XICS_NR_IRQS 0x1000
#define SPAPR_IRQ_XICS_NR_MSIS \
(XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI)
SpaprIrq spapr_irq_xics = {
.nr_irqs = SPAPR_IRQ_XICS_NR_IRQS,
.nr_msis = SPAPR_IRQ_XICS_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_LEGACY,
.nr_xirqs = SPAPR_NR_XIRQS,
.nr_msis = SPAPR_NR_MSIS,
.xics = true,
.xive = false,
.init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics,
.qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics,
.dt_populate = spapr_dt_xics,
.cpu_intc_create = spapr_irq_cpu_intc_create_xics,
.post_load = spapr_irq_post_load_xics,
.reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics,
.get_nodename = spapr_irq_get_nodename_xics,
.init_kvm = spapr_irq_init_kvm_xics,
};
/*
* XIVE IRQ backend.
*/
static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
uint32_t nr_servers = spapr_max_server_number(spapr);
DeviceState *dev;
int i;
dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
qdev_prop_set_uint32(dev, "nr-irqs", nr_irqs);
/*
* 8 XIVE END structures per CPU. One for each available priority
*/
qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
qdev_init_nofail(dev);
spapr->xive = SPAPR_XIVE(dev);
/* Enable the CPU IPIs */
for (i = 0; i < nr_servers; ++i) {
spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false);
}
spapr_xive_hcall_init(spapr);
}
static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) {
error_setg(errp, "IRQ %d is invalid", irq);
return -1;
}
return 0;
return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp);
}
static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num)
static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq)
{
int i;
for (i = irq; i < irq + num; ++i) {
spapr_xive_irq_free(spapr->xive, i);
}
}
static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq)
{
SpaprXive *xive = spapr->xive;
if (irq >= xive->nr_irqs) {
return NULL;
}
/* The sPAPR machine/device should have claimed the IRQ before */
assert(xive_eas_is_valid(&xive->eat[irq]));
return spapr->qirqs[irq];
spapr_xive_irq_free(spapr->xive, irq);
}
static void spapr_irq_print_info_xive(SpaprMachineState *spapr,
@ -386,22 +282,17 @@ static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp)
spapr_xive_mmio_set_enabled(spapr->xive, true);
}
static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val)
static void spapr_irq_set_irq_xive(void *opaque, int irq, int val)
{
SpaprMachineState *spapr = opaque;
if (kvm_irqchip_in_kernel()) {
kvmppc_xive_source_set_irq(&spapr->xive->source, srcno, val);
kvmppc_xive_source_set_irq(&spapr->xive->source, irq, val);
} else {
xive_source_set_irq(&spapr->xive->source, srcno, val);
xive_source_set_irq(&spapr->xive->source, irq, val);
}
}
static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr)
{
return spapr->xive->nodename;
}
static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp)
{
if (kvm_enabled()) {
@ -409,30 +300,20 @@ static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp)
}
}
/*
* XIVE uses the full IRQ number space. Set it to 8K to be compatible
* with XICS.
*/
#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000
#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI)
SpaprIrq spapr_irq_xive = {
.nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS,
.nr_msis = SPAPR_IRQ_XIVE_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_EXPLOIT,
.nr_xirqs = SPAPR_NR_XIRQS,
.nr_msis = SPAPR_NR_MSIS,
.xics = false,
.xive = true,
.init = spapr_irq_init_xive,
.claim = spapr_irq_claim_xive,
.free = spapr_irq_free_xive,
.qirq = spapr_qirq_xive,
.print_info = spapr_irq_print_info_xive,
.dt_populate = spapr_dt_xive,
.cpu_intc_create = spapr_irq_cpu_intc_create_xive,
.post_load = spapr_irq_post_load_xive,
.reset = spapr_irq_reset_xive,
.set_irq = spapr_irq_set_irq_xive,
.get_nodename = spapr_irq_get_nodename_xive,
.init_kvm = spapr_irq_init_kvm_xive,
};
@ -455,24 +336,6 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr)
&spapr_irq_xive : &spapr_irq_xics;
}
static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
Error *local_err = NULL;
spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
@ -494,15 +357,10 @@ static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi,
return ret;
}
static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num)
static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq)
{
spapr_irq_xics.free(spapr, irq, num);
spapr_irq_xive.free(spapr, irq, num);
}
static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq)
{
return spapr_irq_current(spapr)->qirq(spapr, irq);
spapr_irq_xics.free(spapr, irq);
spapr_irq_xive.free(spapr, irq);
}
static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon)
@ -576,45 +434,35 @@ static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp)
spapr_irq_current(spapr)->reset(spapr, errp);
}
static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val)
static void spapr_irq_set_irq_dual(void *opaque, int irq, int val)
{
SpaprMachineState *spapr = opaque;
spapr_irq_current(spapr)->set_irq(spapr, srcno, val);
}
static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr)
{
return spapr_irq_current(spapr)->get_nodename(spapr);
spapr_irq_current(spapr)->set_irq(spapr, irq, val);
}
/*
* Define values in sync with the XIVE and XICS backend
*/
#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000
#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI)
SpaprIrq spapr_irq_dual = {
.nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS,
.nr_msis = SPAPR_IRQ_DUAL_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_BOTH,
.nr_xirqs = SPAPR_NR_XIRQS,
.nr_msis = SPAPR_NR_MSIS,
.xics = true,
.xive = true,
.init = spapr_irq_init_dual,
.claim = spapr_irq_claim_dual,
.free = spapr_irq_free_dual,
.qirq = spapr_qirq_dual,
.print_info = spapr_irq_print_info_dual,
.dt_populate = spapr_irq_dt_populate_dual,
.cpu_intc_create = spapr_irq_cpu_intc_create_dual,
.post_load = spapr_irq_post_load_dual,
.reset = spapr_irq_reset_dual,
.set_irq = spapr_irq_set_irq_dual,
.get_nodename = spapr_irq_get_nodename_dual,
.init_kvm = NULL, /* should not be used */
};
static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
static int spapr_irq_check(SpaprMachineState *spapr, Error **errp)
{
MachineState *machine = MACHINE(spapr);
@ -630,7 +478,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
*/
if (spapr->irq == &spapr_irq_dual) {
spapr->irq = &spapr_irq_xics;
return;
return 0;
}
/*
@ -650,7 +498,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
*/
if (spapr->irq == &spapr_irq_xive) {
error_setg(errp, "XIVE-only machines require a POWER9 CPU");
return;
return -1;
}
}
@ -664,8 +512,10 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
machine_kernel_irqchip_required(machine) &&
xics_kvm_has_broken_disconnect(spapr)) {
error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on");
return;
return -1;
}
return 0;
}
/*
@ -674,7 +524,6 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
{
MachineState *machine = MACHINE(spapr);
Error *local_err = NULL;
if (machine_kernel_irqchip_split(machine)) {
error_setg(errp, "kernel_irqchip split mode not supported on pseries");
@ -687,9 +536,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
return;
}
spapr_irq_check(spapr, &local_err);
if (local_err) {
error_propagate(errp, local_err);
if (spapr_irq_check(spapr, errp) < 0) {
return;
}
@ -698,25 +545,113 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
spapr_irq_msi_init(spapr, spapr->irq->nr_msis);
}
spapr->irq->init(spapr, spapr->irq->nr_irqs, errp);
if (spapr->irq->xics) {
Error *local_err = NULL;
Object *obj;
obj = object_new(TYPE_ICS_SPAPR);
object_property_add_child(OBJECT(spapr), "ics", obj, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs",
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
object_property_set_bool(obj, true, "realized", &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
spapr->ics = ICS_SPAPR(obj);
}
if (spapr->irq->xive) {
uint32_t nr_servers = spapr_max_server_number(spapr);
DeviceState *dev;
int i;
dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
qdev_prop_set_uint32(dev, "nr-irqs",
spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE);
/*
* 8 XIVE END structures per CPU. One for each available
* priority
*/
qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
qdev_init_nofail(dev);
spapr->xive = SPAPR_XIVE(dev);
/* Enable the CPU IPIs */
for (i = 0; i < nr_servers; ++i) {
if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i,
false, errp) < 0) {
return;
}
}
spapr_xive_hcall_init(spapr);
}
spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr,
spapr->irq->nr_irqs);
spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE);
}
int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp)
{
assert(irq >= SPAPR_XIRQ_BASE);
assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
return spapr->irq->claim(spapr, irq, lsi, errp);
}
void spapr_irq_free(SpaprMachineState *spapr, int irq, int num)
{
spapr->irq->free(spapr, irq, num);
int i;
assert(irq >= SPAPR_XIRQ_BASE);
assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
for (i = irq; i < (irq + num); i++) {
spapr->irq->free(spapr, i);
}
}
qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq)
{
return spapr->irq->qirq(spapr, irq);
/*
* This interface is basically for VIO and PHB devices to find the
* right qemu_irq to manipulate, so we only allow access to the
* external irqs for now. Currently anything which needs to
* access the IPIs most naturally gets there via the guest side
* interfaces, we can change this if we need to in future.
*/
assert(irq >= SPAPR_XIRQ_BASE);
assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
if (spapr->ics) {
assert(ics_valid_irq(spapr->ics, irq));
}
if (spapr->xive) {
assert(irq < spapr->xive->nr_irqs);
assert(xive_eas_is_valid(&spapr->xive->eat[irq]));
}
return spapr->qirqs[irq];
}
int spapr_irq_post_load(SpaprMachineState *spapr, int version_id)
@ -735,13 +670,13 @@ void spapr_irq_reset(SpaprMachineState *spapr, Error **errp)
int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp)
{
const char *nodename = spapr->irq->get_nodename(spapr);
const char *nodename = "interrupt-controller";
int offset, phandle;
offset = fdt_subnode_offset(fdt, 0, nodename);
if (offset < 0) {
error_setg(errp, "Can't find node \"%s\": %s", nodename,
fdt_strerror(offset));
error_setg(errp, "Can't find node \"%s\": %s",
nodename, fdt_strerror(offset));
return -1;
}
@ -767,7 +702,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)
return -1;
}
for (i = first; i < first + num; ++i) {
if (!ICS_IRQ_FREE(ics, i)) {
if (!ics_irq_free(ics, i)) {
break;
}
}
@ -809,23 +744,21 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp)
return first + ics->offset;
}
#define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400
#define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400
SpaprIrq spapr_irq_xics_legacy = {
.nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
.nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
.ov5 = SPAPR_OV5_XIVE_LEGACY,
.nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS,
.nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS,
.xics = true,
.xive = false,
.init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics,
.qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics,
.dt_populate = spapr_dt_xics,
.cpu_intc_create = spapr_irq_cpu_intc_create_xics,
.post_load = spapr_irq_post_load_xics,
.reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics,
.get_nodename = spapr_irq_get_nodename_xics,
.init_kvm = spapr_irq_init_kvm_xics,
};

View file

@ -721,9 +721,10 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
* corresponding qemu_irq.
*/
SpaprPhbState *phb = opaque;
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq);
qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
qemu_set_irq(spapr_qirq(spapr, phb->lsi_table[irq_num].irq), level);
}
static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin)
@ -835,7 +836,7 @@ static char *spapr_phb_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev)
#define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
/* for 'reg'/'assigned-addresses' OF properties */
/* for 'reg' OF properties */
#define RESOURCE_CELLS_SIZE 2
#define RESOURCE_CELLS_ADDRESS 3
@ -849,17 +850,14 @@ typedef struct ResourceFields {
typedef struct ResourceProps {
ResourceFields reg[8];
ResourceFields assigned[7];
uint32_t reg_len;
uint32_t assigned_len;
} ResourceProps;
/* fill in the 'reg'/'assigned-resources' OF properties for
/* fill in the 'reg' OF properties for
* a PCI device. 'reg' describes resource requirements for a
* device's IO/MEM regions, 'assigned-addresses' describes the
* actual resource assignments.
* device's IO/MEM regions.
*
* the properties are arrays of ('phys-addr', 'size') pairs describing
* the property is an array of ('phys-addr', 'size') pairs describing
* the addressable regions of the PCI device, where 'phys-addr' is a
* RESOURCE_CELLS_ADDRESS-tuple of 32-bit integers corresponding to
* (phys.hi, phys.mid, phys.lo), and 'size' is a
@ -888,18 +886,7 @@ typedef struct ResourceProps {
* phys.mid and phys.lo correspond respectively to the hi/lo portions
* of the actual address of the region.
*
* how the phys-addr/size values are used differ slightly between
* 'reg' and 'assigned-addresses' properties. namely, 'reg' has
* an additional description for the config space region of the
* device, and in the case of QEMU has n=0 and phys.mid=phys.lo=0
* to describe the region as relocatable, with an address-mapping
* that corresponds directly to the PHB's address space for the
* resource. 'assigned-addresses' always has n=1 set with an absolute
* address assigned for the resource. in general, 'assigned-addresses'
* won't be populated, since addresses for PCI devices are generally
* unmapped initially and left to the guest to assign.
*
* note also that addresses defined in these properties are, at least
* note also that addresses defined in this property are, at least
* for PAPR guests, relative to the PHBs IO/MEM windows, and
* correspond directly to the addresses in the BARs.
*
@ -913,8 +900,8 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
uint32_t dev_id = (b_bbbbbbbb(bus_num) |
b_ddddd(PCI_SLOT(d->devfn)) |
b_fff(PCI_FUNC(d->devfn)));
ResourceFields *reg, *assigned;
int i, reg_idx = 0, assigned_idx = 0;
ResourceFields *reg;
int i, reg_idx = 0;
/* config space region */
reg = &rp->reg[reg_idx++];
@ -943,21 +930,9 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
reg->phys_lo = 0;
reg->size_hi = cpu_to_be32(d->io_regions[i].size >> 32);
reg->size_lo = cpu_to_be32(d->io_regions[i].size);
if (d->io_regions[i].addr == PCI_BAR_UNMAPPED) {
continue;
}
assigned = &rp->assigned[assigned_idx++];
assigned->phys_hi = cpu_to_be32(be32_to_cpu(reg->phys_hi) | b_n(1));
assigned->phys_mid = cpu_to_be32(d->io_regions[i].addr >> 32);
assigned->phys_lo = cpu_to_be32(d->io_regions[i].addr);
assigned->size_hi = reg->size_hi;
assigned->size_lo = reg->size_lo;
}
rp->reg_len = reg_idx * sizeof(ResourceFields);
rp->assigned_len = assigned_idx * sizeof(ResourceFields);
}
typedef struct PCIClass PCIClass;
@ -1471,8 +1446,6 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
populate_resource_props(dev, &rp);
_FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len));
_FDT(fdt_setprop(fdt, offset, "assigned-addresses",
(uint8_t *)rp.assigned, rp.assigned_len));
if (sphb->pcie_ecs && pci_is_express(dev)) {
_FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1));

View file

@ -477,47 +477,6 @@ void spapr_dt_rtas_tokens(void *fdt, int rtas)
}
}
void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr)
{
int rtas_node;
int ret;
/* Copy RTAS blob into guest RAM */
cpu_physical_memory_write(addr, spapr->rtas_blob, spapr->rtas_size);
ret = fdt_add_mem_rsv(fdt, addr, spapr->rtas_size);
if (ret < 0) {
error_report("Couldn't add RTAS reserve entry: %s",
fdt_strerror(ret));
exit(1);
}
/* Update the device tree with the blob's location */
rtas_node = fdt_path_offset(fdt, "/rtas");
assert(rtas_node >= 0);
ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-base", addr);
if (ret < 0) {
error_report("Couldn't add linux,rtas-base property: %s",
fdt_strerror(ret));
exit(1);
}
ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-entry", addr);
if (ret < 0) {
error_report("Couldn't add linux,rtas-entry property: %s",
fdt_strerror(ret));
exit(1);
}
ret = fdt_setprop_cell(fdt, rtas_node, "rtas-size", spapr->rtas_size);
if (ret < 0) {
error_report("Couldn't add rtas-size property: %s",
fdt_strerror(ret));
exit(1);
}
}
static void core_rtas_register_types(void)
{
spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",

View file

@ -114,7 +114,7 @@ static target_ulong h_tpm_comm(PowerPCCPU *cpu,
return H_FUNCTION;
}
trace_spapr_h_tpm_comm(tpm_proxy->host_path ?: "null", op);
trace_spapr_h_tpm_comm(tpm_proxy->host_path, op);
switch (op) {
case TPM_COMM_OP_EXECUTE:

View file

@ -23,7 +23,6 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "hw/irq.h"
#include "qemu/log.h"
#include "hw/loader.h"
#include "elf.h"
@ -294,7 +293,7 @@ int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq)
dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
if (dev->signal_state & 1) {
qemu_irq_pulse(spapr_vio_qirq(dev));
spapr_vio_irq_pulse(dev);
}
return 0;

View file

@ -13,10 +13,6 @@ spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) "
spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes"
spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
# spapr_irq.c
spapr_irq_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
spapr_irq_free_warn(int src, int irq) "Source#%d, irq %d is already free"
# spapr_hcall.c
spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x"
spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64