ppc patch queue for 2022-08-31:

In the first 7.2 queue we have changes in the powernv pnv-phb handling,
 the start of the QOMification of the ppc405 model, the removal of the
 taihu machine, a new SLOF image and others.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCYw/AFgAKCRA82cqW3gMx
 ZI6XAP0d8m6r1JqKXPSfCwVYy+AfrwY7oZWYbeTqdamK6xHcUQD+JyCcFcogY4Vz
 YwvHLd9W2cqvoWiZ4tmkK4Mb0Xt0Xg4=
 =0uL/
 -----END PGP SIGNATURE-----

Merge tag 'pull-ppc-20220831' of https://gitlab.com/danielhb/qemu into staging

ppc patch queue for 2022-08-31:

In the first 7.2 queue we have changes in the powernv pnv-phb handling,
the start of the QOMification of the ppc405 model, the removal of the
taihu machine, a new SLOF image and others.

# -----BEGIN PGP SIGNATURE-----
#
# iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCYw/AFgAKCRA82cqW3gMx
# ZI6XAP0d8m6r1JqKXPSfCwVYy+AfrwY7oZWYbeTqdamK6xHcUQD+JyCcFcogY4Vz
# YwvHLd9W2cqvoWiZ4tmkK4Mb0Xt0Xg4=
# =0uL/
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 31 Aug 2022 16:09:58 EDT
# gpg:                using EDDSA key 17EBFF9923D01800AF2838193CD9CA96DE033164
# gpg: Good signature from "Daniel Henrique Barboza <danielhb413@gmail.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 17EB FF99 23D0 1800 AF28  3819 3CD9 CA96 DE03 3164

* tag 'pull-ppc-20220831' of https://gitlab.com/danielhb/qemu: (60 commits)
  ppc4xx: Fix code style problems reported by checkpatch
  ppc/ppc4xx: Fix sdram trace events
  hw/ppc/Kconfig: Move imply before select
  hw/ppc/sam460ex: Remove PPC405 dependency from sam460ex
  ppc405: Move machine specific code to ppc405_boards.c
  ppc/ppc405: QOM'ify FPGA
  ppc/ppc405: Use an explicit I2C object
  hw/intc/ppc-uic: Convert ppc-uic to a PPC4xx DCR device
  ppc/ppc405: Use an embedded PPCUIC model in SoC state
  ppc4xx: Rename ppc405-ebc to ppc4xx-ebc
  ppc4xx: Move EBC model to ppc4xx_devs.c
  ppc4xx: Rename ppc405-plb to ppc4xx-plb
  ppc4xx: Move PLB model to ppc4xx_devs.c
  ppc/ppc405: QOM'ify MAL
  ppc/ppc405: QOM'ify PLB
  ppc/ppc405: QOM'ify POB
  ppc/ppc405: QOM'ify OPBA
  ppc/ppc405: QOM'ify EBC
  ppc/ppc405: QOM'ify DMA
  ppc/ppc405: QOM'ify GPIO
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-09-01 13:53:20 -04:00
commit 7dd9d7e0bd
45 changed files with 2750 additions and 1608 deletions

View File

@ -1282,7 +1282,7 @@ F: hw/openrisc/openrisc_sim.c
PowerPC Machines
----------------
405 (ref405ep and taihu)
405 (ref405ep)
L: qemu-ppc@nongnu.org
S: Orphan
F: hw/ppc/ppc405_boards.c

View File

@ -233,15 +233,6 @@ deprecated; use the new name ``dtb-randomness`` instead. The new name
better reflects the way this property affects all random data within
the device tree blob, not just the ``kaslr-seed`` node.
PPC 405 ``taihu`` machine (since 7.0)
'''''''''''''''''''''''''''''''''''''
The PPC 405 CPU is a system-on-a-chip, so all 405 machines are very similar,
except for some external periphery. However, the periphery of the ``taihu``
machine is hardly emulated at all (e.g. neither the LCD nor the USB part had
been implemented), so there is not much value added by this board. Use the
``ref405ep`` machine instead.
``pc-i440fx-1.4`` up to ``pc-i440fx-1.7`` (since 7.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''

View File

@ -668,6 +668,12 @@ Aspeed ``swift-bmc`` machine (removed in 7.0)
This machine was removed because it was unused. Alternative AST2500 based
OpenPOWER machines are ``witherspoon-bmc`` and ``romulus-bmc``.
ppc ``taihu`` machine (removed in 7.2)
'''''''''''''''''''''''''''''''''''''''''''''
This machine was removed because it was partially emulated and 405
machines are very similar. Use the ``ref405ep`` machine instead.
linux-user mode CPUs
--------------------

View File

@ -6,5 +6,4 @@ Embedded family boards
- ``ppce500`` generic paravirt e500 platform
- ``ref405ep`` ref405ep
- ``sam460ex`` aCube Sam460ex
- ``taihu`` taihu
- ``virtex-ml507`` Xilinx Virtex ML507 reference design

View File

@ -62,7 +62,7 @@ Booting via ``-kernel`` supports the following:
+-------------------+-------------------+------------------+
| vmlinux LE | ✓ | ✓ |
+-------------------+-------------------+------------------+
| zImage.pseries BE | x | ✓¹ |
| zImage.pseries BE | ✓¹ | ✓¹ |
+-------------------+-------------------+------------------+
| zImage.pseries LE | ✓ | ✓ |
+-------------------+-------------------+------------------+

View File

@ -214,18 +214,35 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
p->frac_lo &= ~round_mask;
}
} else if (unlikely(exp >= exp_max)) {
flags |= float_flag_overflow | float_flag_inexact;
if (overflow_norm) {
flags |= float_flag_overflow;
if (s->rebias_overflow) {
exp -= fmt->exp_re_bias;
} else if (overflow_norm) {
flags |= float_flag_inexact;
exp = exp_max - 1;
frac_allones(p);
p->frac_lo &= ~round_mask;
} else {
flags |= float_flag_inexact;
p->cls = float_class_inf;
exp = exp_max;
frac_clear(p);
}
}
frac_shr(p, frac_shift);
} else if (unlikely(s->rebias_underflow)) {
flags |= float_flag_underflow;
exp += fmt->exp_re_bias;
if (p->frac_lo & round_mask) {
flags |= float_flag_inexact;
if (frac_addi(p, p, inc)) {
frac_shr(p, 1);
p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
exp++;
}
p->frac_lo &= ~round_mask;
}
frac_shr(p, frac_shift);
} else if (s->flush_to_zero) {
flags |= float_flag_output_denormal;
p->cls = float_class_zero;

View File

@ -521,6 +521,7 @@ typedef struct {
typedef struct {
int exp_size;
int exp_bias;
int exp_re_bias;
int exp_max;
int frac_size;
int frac_shift;
@ -532,6 +533,7 @@ typedef struct {
#define FLOAT_PARAMS_(E) \
.exp_size = E, \
.exp_bias = ((1 << E) - 1) >> 1, \
.exp_re_bias = (1 << (E - 1)) + (1 << (E - 2)), \
.exp_max = (1 << E) - 1
#define FLOAT_PARAMS(E, F) \

View File

@ -25,11 +25,8 @@
#include "qemu/osdep.h"
#include "hw/intc/ppc-uic.h"
#include "hw/irq.h"
#include "cpu.h"
#include "hw/ppc/ppc.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
enum {
DCR_UICSR = 0x000,
@ -105,10 +102,9 @@ static void ppcuic_trigger_irq(PPCUIC *uic)
static void ppcuic_set_irq(void *opaque, int irq_num, int level)
{
PPCUIC *uic;
PPCUIC *uic = opaque;
uint32_t mask, sr;
uic = opaque;
mask = 1U << (31 - irq_num);
LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
" mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
@ -144,10 +140,9 @@ static void ppcuic_set_irq(void *opaque, int irq_num, int level)
static uint32_t dcr_read_uic(void *opaque, int dcrn)
{
PPCUIC *uic;
PPCUIC *uic = opaque;
uint32_t ret;
uic = opaque;
dcrn -= uic->dcr_base;
switch (dcrn) {
case DCR_UICSR:
@ -192,9 +187,8 @@ static uint32_t dcr_read_uic(void *opaque, int dcrn)
static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
{
PPCUIC *uic;
PPCUIC *uic = opaque;
uic = opaque;
dcrn -= uic->dcr_base;
LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
switch (dcrn) {
@ -251,19 +245,12 @@ static void ppc_uic_reset(DeviceState *dev)
static void ppc_uic_realize(DeviceState *dev, Error **errp)
{
PPCUIC *uic = PPC_UIC(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
PowerPCCPU *cpu;
int i;
if (!uic->cpu) {
/* This is a programming error in the code using this device */
error_setg(errp, "ppc-uic 'cpu' link property was not set");
return;
}
cpu = POWERPC_CPU(uic->cpu);
for (i = 0; i < DCR_UICMAX; i++) {
ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
ppc4xx_dcr_register(dcr, uic->dcr_base + i, uic,
&dcr_read_uic, &dcr_write_uic);
}
@ -273,7 +260,6 @@ static void ppc_uic_realize(DeviceState *dev, Error **errp)
}
static Property ppc_uic_properties[] = {
DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0xc0),
DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
DEFINE_PROP_END_OF_LIST()
@ -308,7 +294,7 @@ static void ppc_uic_class_init(ObjectClass *klass, void *data)
static const TypeInfo ppc_uic_info = {
.name = TYPE_PPC_UIC,
.parent = TYPE_SYS_BUS_DEVICE,
.parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(PPCUIC),
.class_init = ppc_uic_class_init,
};

View File

@ -35,5 +35,6 @@ specific_ss.add(when: 'CONFIG_PCI_POWERNV', if_true: files(
'pnv_phb3_msi.c',
'pnv_phb3_pbcq.c',
'pnv_phb4.c',
'pnv_phb4_pec.c'
'pnv_phb4_pec.c',
'pnv_phb.c',
))

337
hw/pci-host/pnv_phb.c Normal file
View File

@ -0,0 +1,337 @@
/*
* QEMU PowerPC PowerNV Proxy PHB model
*
* Copyright (c) 2022, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qapi/visitor.h"
#include "qapi/error.h"
#include "hw/pci-host/pnv_phb.h"
#include "hw/pci-host/pnv_phb3.h"
#include "hw/pci-host/pnv_phb4.h"
#include "hw/ppc/pnv.h"
#include "hw/qdev-properties.h"
#include "qom/object.h"
#include "sysemu/sysemu.h"
/*
* Set the QOM parent and parent bus of an object child. If the device
* state associated with the child has an id, use it as QOM id.
* Otherwise use object_typename[index] as QOM id.
*
* This helper does both operations at the same time because seting
* a new QOM child will erase the bus parent of the device. This happens
* because object_unparent() will call object_property_del_child(),
* which in turn calls the property release callback prop->release if
* it's defined. In our case this callback is set to
* object_finalize_child_property(), which was assigned during the
* first object_property_add_child() call. This callback will end up
* calling device_unparent(), and this function removes the device
* from its parent bus.
*
* The QOM and parent bus to be set aren´t necessarily related, so
* let's receive both as arguments.
*/
static bool pnv_parent_fixup(Object *parent, BusState *parent_bus,
Object *child, int index,
Error **errp)
{
g_autofree char *default_id =
g_strdup_printf("%s[%d]", object_get_typename(child), index);
const char *dev_id = DEVICE(child)->id;
if (child->parent == parent) {
return true;
}
object_ref(child);
object_unparent(child);
object_property_add_child(parent, dev_id ? dev_id : default_id, child);
object_unref(child);
if (!qdev_set_parent_bus(DEVICE(child), parent_bus, errp)) {
return false;
}
return true;
}
/*
* User created devices won't have the initial setup that default
* devices have. This setup consists of assigning a parent device
* (chip for PHB3, PEC for PHB4/5) that will be the QOM/bus parent
* of the PHB.
*/
static bool pnv_phb_user_device_init(PnvPHB *phb, Error **errp)
{
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
PnvChip *chip = pnv_get_chip(pnv, phb->chip_id);
Object *parent = NULL;
if (!chip) {
error_setg(errp, "invalid chip id: %d", phb->chip_id);
return false;
}
parent = pnv_chip_add_phb(chip, phb, errp);
if (!parent) {
return false;
}
/*
* Reparent user created devices to the chip to build
* correctly the device tree. pnv_xscom_dt() needs every
* PHB to be a child of the chip to build the DT correctly.
*/
if (!pnv_parent_fixup(parent, qdev_get_parent_bus(DEVICE(chip)),
OBJECT(phb), phb->phb_id, errp)) {
return false;
}
return true;
}
static void pnv_phb_realize(DeviceState *dev, Error **errp)
{
PnvPHB *phb = PNV_PHB(dev);
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
g_autofree char *phb_typename = NULL;
if (!phb->version) {
error_setg(errp, "version not specified");
return;
}
switch (phb->version) {
case 3:
phb_typename = g_strdup(TYPE_PNV_PHB3);
break;
case 4:
phb_typename = g_strdup(TYPE_PNV_PHB4);
break;
case 5:
phb_typename = g_strdup(TYPE_PNV_PHB5);
break;
default:
g_assert_not_reached();
}
phb->backend = object_new(phb_typename);
object_property_add_child(OBJECT(dev), "phb-backend", phb->backend);
/* Passthrough child device properties to the proxy device */
object_property_set_uint(phb->backend, "index", phb->phb_id, errp);
object_property_set_uint(phb->backend, "chip-id", phb->chip_id, errp);
object_property_set_link(phb->backend, "phb-base", OBJECT(phb), errp);
/*
* Handle user created devices. User devices will not have a
* pointer to a chip (PHB3) and a PEC (PHB4/5).
*/
if (!phb->chip && !phb->pec) {
if (!pnv_phb_user_device_init(phb, errp)) {
return;
}
}
if (phb->version == 3) {
object_property_set_link(phb->backend, "chip",
OBJECT(phb->chip), errp);
} else {
object_property_set_link(phb->backend, "pec", OBJECT(phb->pec), errp);
}
if (!qdev_realize(DEVICE(phb->backend), NULL, errp)) {
return;
}
if (phb->version == 3) {
pnv_phb3_bus_init(dev, PNV_PHB3(phb->backend));
} else {
pnv_phb4_bus_init(dev, PNV_PHB4(phb->backend));
}
if (defaults_enabled()) {
PCIDevice *root = pci_new(PCI_DEVFN(0, 0), TYPE_PNV_PHB_ROOT_PORT);
pci_realize_and_unref(root, pci->bus, errp);
}
}
static const char *pnv_phb_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
PnvPHB *phb = PNV_PHB(host_bridge);
snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x",
phb->chip_id, phb->phb_id);
return phb->bus_path;
}
static Property pnv_phb_properties[] = {
DEFINE_PROP_UINT32("index", PnvPHB, phb_id, 0),
DEFINE_PROP_UINT32("chip-id", PnvPHB, chip_id, 0),
DEFINE_PROP_UINT32("version", PnvPHB, version, 0),
DEFINE_PROP_LINK("chip", PnvPHB, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_LINK("pec", PnvPHB, pec, TYPE_PNV_PHB4_PEC,
PnvPhb4PecState *),
DEFINE_PROP_END_OF_LIST(),
};
static void pnv_phb_class_init(ObjectClass *klass, void *data)
{
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
hc->root_bus_path = pnv_phb_root_bus_path;
dc->realize = pnv_phb_realize;
device_class_set_props(dc, pnv_phb_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->user_creatable = true;
}
static void pnv_phb_root_port_reset(DeviceState *dev)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
PCIDevice *d = PCI_DEVICE(dev);
uint8_t *conf = d->config;
rpc->parent_reset(dev);
if (phb_rp->version == 3) {
return;
}
/* PHB4 and later requires these extra reset steps */
pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
PCI_IO_RANGE_MASK & 0xff);
pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
PCI_IO_RANGE_MASK & 0xff);
pci_set_word(conf + PCI_MEMORY_BASE, 0);
pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
pci_config_set_interrupt_pin(conf, 0);
}
static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev);
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(dev));
PCIDevice *pci = PCI_DEVICE(dev);
uint16_t device_id = 0;
Error *local_err = NULL;
int chip_id, index;
/*
* 'index' will be used both as a PCIE slot value and to calculate
* QOM id. 'chip_id' is going to be used as PCIE chassis for the
* root port.
*/
chip_id = object_property_get_int(OBJECT(bus), "chip-id", &error_fatal);
index = object_property_get_int(OBJECT(bus), "phb-id", &error_fatal);
/* Set unique chassis/slot values for the root port */
qdev_prop_set_uint8(dev, "chassis", chip_id);
qdev_prop_set_uint16(dev, "slot", index);
/*
* User created root ports are QOM parented to one of
* the peripheral containers but it's already at the right
* parent bus. Change the QOM parent to be the same as the
* parent bus it's already assigned to.
*/
if (!pnv_parent_fixup(OBJECT(bus), BUS(bus), OBJECT(dev),
index, errp)) {
return;
}
rpc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
switch (phb_rp->version) {
case 3:
device_id = PNV_PHB3_DEVICE_ID;
break;
case 4:
device_id = PNV_PHB4_DEVICE_ID;
break;
case 5:
device_id = PNV_PHB5_DEVICE_ID;
break;
default:
g_assert_not_reached();
}
pci_config_set_device_id(pci->config, device_id);
pci_config_set_interrupt_pin(pci->config, 0);
}
static Property pnv_phb_root_port_properties[] = {
DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
dc->desc = "IBM PHB PCIE Root Port";
device_class_set_props(dc, pnv_phb_root_port_properties);
device_class_set_parent_realize(dc, pnv_phb_root_port_realize,
&rpc->parent_realize);
device_class_set_parent_reset(dc, pnv_phb_root_port_reset,
&rpc->parent_reset);
dc->reset = &pnv_phb_root_port_reset;
dc->user_creatable = true;
k->vendor_id = PCI_VENDOR_ID_IBM;
/* device_id will be written during realize() */
k->device_id = 0;
k->revision = 0;
rpc->exp_offset = 0x48;
rpc->aer_offset = 0x100;
}
static const TypeInfo pnv_phb_type_info = {
.name = TYPE_PNV_PHB,
.parent = TYPE_PCIE_HOST_BRIDGE,
.instance_size = sizeof(PnvPHB),
.class_init = pnv_phb_class_init,
};
static const TypeInfo pnv_phb_root_port_info = {
.name = TYPE_PNV_PHB_ROOT_PORT,
.parent = TYPE_PCIE_ROOT_PORT,
.instance_size = sizeof(PnvPHBRootPort),
.class_init = pnv_phb_root_port_class_init,
};
static void pnv_phb_register_types(void)
{
type_register_static(&pnv_phb_type_info);
type_register_static(&pnv_phb_root_port_info);
}
type_init(pnv_phb_register_types)

55
hw/pci-host/pnv_phb.h Normal file
View File

@ -0,0 +1,55 @@
/*
* QEMU PowerPC PowerNV Proxy PHB model
*
* Copyright (c) 2022, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
*/
#ifndef PCI_HOST_PNV_PHB_H
#define PCI_HOST_PNV_PHB_H
#include "hw/pci/pcie_host.h"
#include "hw/pci/pcie_port.h"
#include "qom/object.h"
typedef struct PnvChip PnvChip;
typedef struct PnvPhb4PecState PnvPhb4PecState;
struct PnvPHB {
PCIExpressHost parent_obj;
uint32_t chip_id;
uint32_t phb_id;
uint32_t version;
char bus_path[8];
PnvChip *chip;
PnvPhb4PecState *pec;
/* The PHB backend (PnvPHB3, PnvPHB4 ...) being used */
Object *backend;
};
#define TYPE_PNV_PHB "pnv-phb"
OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB)
/*
* PHB PCIe Root port
*/
#define PNV_PHB3_DEVICE_ID 0x03dc
#define PNV_PHB4_DEVICE_ID 0x04c1
#define PNV_PHB5_DEVICE_ID 0x0652
typedef struct PnvPHBRootPort {
PCIESlot parent_obj;
uint32_t version;
} PnvPHBRootPort;
#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port"
OBJECT_DECLARE_SIMPLE_TYPE(PnvPHBRootPort, PNV_PHB_ROOT_PORT)
#endif /* PCI_HOST_PNV_PHB_H */

View File

@ -11,6 +11,7 @@
#include "qapi/visitor.h"
#include "qapi/error.h"
#include "hw/pci-host/pnv_phb3_regs.h"
#include "hw/pci-host/pnv_phb.h"
#include "hw/pci-host/pnv_phb3.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pcie_port.h"
@ -26,7 +27,7 @@
static PCIDevice *pnv_phb3_find_cfg_dev(PnvPHB3 *phb)
{
PCIHostState *pci = PCI_HOST_BRIDGE(phb);
PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
uint64_t addr = phb->regs[PHB_CONFIG_ADDRESS >> 3];
uint8_t bus, devfn;
@ -590,7 +591,7 @@ void pnv_phb3_reg_write(void *opaque, hwaddr off, uint64_t val, unsigned size)
uint64_t pnv_phb3_reg_read(void *opaque, hwaddr off, unsigned size)
{
PnvPHB3 *phb = opaque;
PCIHostState *pci = PCI_HOST_BRIDGE(phb);
PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
uint64_t val;
if ((off & 0xfffc) == PHB_CONFIG_DATA) {
@ -986,10 +987,36 @@ static void pnv_phb3_instance_init(Object *obj)
}
void pnv_phb3_bus_init(DeviceState *dev, PnvPHB3 *phb)
{
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
/*
* PHB3 doesn't support IO space. However, qemu gets very upset if
* we don't have an IO region to anchor IO BARs onto so we just
* initialize one which we never hook up to anything
*/
memory_region_init(&phb->pci_io, OBJECT(phb), "pci-io", 0x10000);
memory_region_init(&phb->pci_mmio, OBJECT(phb), "pci-mmio",
PCI_MMIO_TOTAL_SIZE);
pci->bus = pci_register_root_bus(dev,
dev->id ? dev->id : NULL,
pnv_phb3_set_irq, pnv_phb3_map_irq, phb,
&phb->pci_mmio, &phb->pci_io,
0, 4, TYPE_PNV_PHB3_ROOT_BUS);
object_property_set_int(OBJECT(pci->bus), "phb-id", phb->phb_id,
&error_abort);
object_property_set_int(OBJECT(pci->bus), "chip-id", phb->chip_id,
&error_abort);
pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb);
}
static void pnv_phb3_realize(DeviceState *dev, Error **errp)
{
PnvPHB3 *phb = PNV_PHB3(dev);
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
int i;
@ -1034,26 +1061,6 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
/* Controller Registers */
memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb3_reg_ops, phb,
"phb3-regs", 0x1000);
/*
* PHB3 doesn't support IO space. However, qemu gets very upset if
* we don't have an IO region to anchor IO BARs onto so we just
* initialize one which we never hook up to anything
*/
memory_region_init(&phb->pci_io, OBJECT(phb), "pci-io", 0x10000);
memory_region_init(&phb->pci_mmio, OBJECT(phb), "pci-mmio",
PCI_MMIO_TOTAL_SIZE);
pci->bus = pci_register_root_bus(dev,
dev->id ? dev->id : NULL,
pnv_phb3_set_irq, pnv_phb3_map_irq, phb,
&phb->pci_mmio, &phb->pci_io,
0, 4, TYPE_PNV_PHB3_ROOT_BUS);
pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb);
pnv_phb_attach_root_port(pci, TYPE_PNV_PHB3_ROOT_PORT,
phb->phb_id, phb->chip_id);
}
void pnv_phb3_update_regions(PnvPHB3 *phb)
@ -1078,47 +1085,80 @@ void pnv_phb3_update_regions(PnvPHB3 *phb)
pnv_phb3_check_all_m64s(phb);
}
static const char *pnv_phb3_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
PnvPHB3 *phb = PNV_PHB3(host_bridge);
snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x",
phb->chip_id, phb->phb_id);
return phb->bus_path;
}
static Property pnv_phb3_properties[] = {
DEFINE_PROP_UINT32("index", PnvPHB3, phb_id, 0),
DEFINE_PROP_UINT32("chip-id", PnvPHB3, chip_id, 0),
DEFINE_PROP_LINK("chip", PnvPHB3, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_LINK("phb-base", PnvPHB3, phb_base, TYPE_PNV_PHB, PnvPHB *),
DEFINE_PROP_END_OF_LIST(),
};
static void pnv_phb3_class_init(ObjectClass *klass, void *data)
{
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
hc->root_bus_path = pnv_phb3_root_bus_path;
dc->realize = pnv_phb3_realize;
device_class_set_props(dc, pnv_phb3_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->user_creatable = false;
}
static const TypeInfo pnv_phb3_type_info = {
.name = TYPE_PNV_PHB3,
.parent = TYPE_PCIE_HOST_BRIDGE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvPHB3),
.class_init = pnv_phb3_class_init,
.instance_init = pnv_phb3_instance_init,
};
static void pnv_phb3_root_bus_get_prop(Object *obj, Visitor *v,
const char *name,
void *opaque, Error **errp)
{
PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj);
uint64_t value = 0;
if (strcmp(name, "phb-id") == 0) {
value = bus->phb_id;
} else {
value = bus->chip_id;
}
visit_type_size(v, name, &value, errp);
}
static void pnv_phb3_root_bus_set_prop(Object *obj, Visitor *v,
const char *name,
void *opaque, Error **errp)
{
PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj);
uint64_t value;
if (!visit_type_size(v, name, &value, errp)) {
return;
}
if (strcmp(name, "phb-id") == 0) {
bus->phb_id = value;
} else {
bus->chip_id = value;
}
}
static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
object_class_property_add(klass, "phb-id", "int",
pnv_phb3_root_bus_get_prop,
pnv_phb3_root_bus_set_prop,
NULL, NULL);
object_class_property_add(klass, "chip-id", "int",
pnv_phb3_root_bus_get_prop,
pnv_phb3_root_bus_set_prop,
NULL, NULL);
/*
* PHB3 has only a single root complex. Enforce the limit on the
* parent bus
@ -1132,51 +1172,9 @@ static const TypeInfo pnv_phb3_root_bus_info = {
.class_init = pnv_phb3_root_bus_class_init,
};
static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
PCIDevice *pci = PCI_DEVICE(dev);
Error *local_err = NULL;
rpc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
pci_config_set_interrupt_pin(pci->config, 0);
}
static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
dc->desc = "IBM PHB3 PCIE Root Port";
device_class_set_parent_realize(dc, pnv_phb3_root_port_realize,
&rpc->parent_realize);
dc->user_creatable = false;
k->vendor_id = PCI_VENDOR_ID_IBM;
k->device_id = 0x03dc;
k->revision = 0;
rpc->exp_offset = 0x48;
rpc->aer_offset = 0x100;
}
static const TypeInfo pnv_phb3_root_port_info = {
.name = TYPE_PNV_PHB3_ROOT_PORT,
.parent = TYPE_PCIE_ROOT_PORT,
.instance_size = sizeof(PnvPHB3RootPort),
.class_init = pnv_phb3_root_port_class_init,
};
static void pnv_phb3_register_types(void)
{
type_register_static(&pnv_phb3_root_bus_info);
type_register_static(&pnv_phb3_root_port_info);
type_register_static(&pnv_phb3_type_info);
type_register_static(&pnv_phb3_iommu_memory_region_info);
}

View File

@ -33,7 +33,7 @@
static PCIDevice *pnv_phb4_find_cfg_dev(PnvPHB4 *phb)
{
PCIHostState *pci = PCI_HOST_BRIDGE(phb);
PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
uint64_t addr = phb->regs[PHB_CONFIG_ADDRESS >> 3];
uint8_t bus, devfn;
@ -129,7 +129,7 @@ static uint64_t pnv_phb4_config_read(PnvPHB4 *phb, unsigned off,
static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off,
unsigned size, uint64_t val)
{
PCIHostState *pci = PCI_HOST_BRIDGE(phb);
PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
PCIDevice *pdev;
if (size != 4) {
@ -150,7 +150,7 @@ static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off,
static uint64_t pnv_phb4_rc_config_read(PnvPHB4 *phb, unsigned off,
unsigned size)
{
PCIHostState *pci = PCI_HOST_BRIDGE(phb);
PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
PCIDevice *pdev;
uint64_t val;
@ -1528,11 +1528,42 @@ static void pnv_phb4_instance_init(Object *obj)
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
}
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
{
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
char name[32];
/*
* PHB4 doesn't support IO space. However, qemu gets very upset if
* we don't have an IO region to anchor IO BARs onto so we just
* initialize one which we never hook up to anything
*/
snprintf(name, sizeof(name), "phb4-%d.%d-pci-io", phb->chip_id,
phb->phb_id);
memory_region_init(&phb->pci_io, OBJECT(phb), name, 0x10000);
snprintf(name, sizeof(name), "phb4-%d.%d-pci-mmio", phb->chip_id,
phb->phb_id);
memory_region_init(&phb->pci_mmio, OBJECT(phb), name,
PCI_MMIO_TOTAL_SIZE);
pci->bus = pci_register_root_bus(dev, dev->id ? dev->id : NULL,
pnv_phb4_set_irq, pnv_phb4_map_irq, phb,
&phb->pci_mmio, &phb->pci_io,
0, 4, TYPE_PNV_PHB4_ROOT_BUS);
object_property_set_int(OBJECT(pci->bus), "phb-id", phb->phb_id,
&error_abort);
object_property_set_int(OBJECT(pci->bus), "chip-id", phb->chip_id,
&error_abort);
pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
}
static void pnv_phb4_realize(DeviceState *dev, Error **errp)
{
PnvPHB4 *phb = PNV_PHB4(dev);
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(phb->pec);
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
XiveSource *xsrc = &phb->xsrc;
int nr_irqs;
char name[32];
@ -1546,32 +1577,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb4_reg_ops, phb,
name, 0x2000);
/*
* PHB4 doesn't support IO space. However, qemu gets very upset if
* we don't have an IO region to anchor IO BARs onto so we just
* initialize one which we never hook up to anything
*/
snprintf(name, sizeof(name), "phb4-%d.%d-pci-io", phb->chip_id,
phb->phb_id);
memory_region_init(&phb->pci_io, OBJECT(phb), name, 0x10000);
snprintf(name, sizeof(name), "phb4-%d.%d-pci-mmio", phb->chip_id,
phb->phb_id);
memory_region_init(&phb->pci_mmio, OBJECT(phb), name,
PCI_MMIO_TOTAL_SIZE);
pci->bus = pci_register_root_bus(dev, dev->id,
pnv_phb4_set_irq, pnv_phb4_map_irq, phb,
&phb->pci_mmio, &phb->pci_io,
0, 4, TYPE_PNV_PHB4_ROOT_BUS);
pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
/* Add a single Root port if running with defaults */
pnv_phb_attach_root_port(pci, pecc->rp_model,
phb->phb_id, phb->chip_id);
/* Setup XIVE Source */
if (phb->big_phb) {
nr_irqs = PNV_PHB4_MAX_INTs;
@ -1591,16 +1596,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
pnv_phb4_xscom_realize(phb);
}
static const char *pnv_phb4_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
PnvPHB4 *phb = PNV_PHB4(host_bridge);
snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x",
phb->chip_id, phb->phb_id);
return phb->bus_path;
}
/*
* Address base trigger mode (POWER10)
*
@ -1685,19 +1680,17 @@ static Property pnv_phb4_properties[] = {
DEFINE_PROP_UINT32("chip-id", PnvPHB4, chip_id, 0),
DEFINE_PROP_LINK("pec", PnvPHB4, pec, TYPE_PNV_PHB4_PEC,
PnvPhb4PecState *),
DEFINE_PROP_LINK("phb-base", PnvPHB4, phb_base, TYPE_PNV_PHB, PnvPHB *),
DEFINE_PROP_END_OF_LIST(),
};
static void pnv_phb4_class_init(ObjectClass *klass, void *data)
{
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
hc->root_bus_path = pnv_phb4_root_bus_path;
dc->realize = pnv_phb4_realize;
device_class_set_props(dc, pnv_phb4_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->user_creatable = false;
xfc->notify = pnv_phb4_xive_notify;
@ -1705,7 +1698,7 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data)
static const TypeInfo pnv_phb4_type_info = {
.name = TYPE_PNV_PHB4,
.parent = TYPE_PCIE_HOST_BRIDGE,
.parent = TYPE_DEVICE,
.instance_init = pnv_phb4_instance_init,
.instance_size = sizeof(PnvPHB4),
.class_init = pnv_phb4_class_init,
@ -1721,10 +1714,55 @@ static const TypeInfo pnv_phb5_type_info = {
.instance_size = sizeof(PnvPHB4),
};
static void pnv_phb4_root_bus_get_prop(Object *obj, Visitor *v,
const char *name,
void *opaque, Error **errp)
{
PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj);
uint64_t value = 0;
if (strcmp(name, "phb-id") == 0) {
value = bus->phb_id;
} else {
value = bus->chip_id;
}
visit_type_size(v, name, &value, errp);
}
static void pnv_phb4_root_bus_set_prop(Object *obj, Visitor *v,
const char *name,
void *opaque, Error **errp)
{
PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj);
uint64_t value;
if (!visit_type_size(v, name, &value, errp)) {
return;
}
if (strcmp(name, "phb-id") == 0) {
bus->phb_id = value;
} else {
bus->chip_id = value;
}
}
static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
object_class_property_add(klass, "phb-id", "int",
pnv_phb4_root_bus_get_prop,
pnv_phb4_root_bus_set_prop,
NULL, NULL);
object_class_property_add(klass, "chip-id", "int",
pnv_phb4_root_bus_get_prop,
pnv_phb4_root_bus_set_prop,
NULL, NULL);
/*
* PHB4 has only a single root complex. Enforce the limit on the
* parent bus
@ -1738,94 +1776,9 @@ static const TypeInfo pnv_phb4_root_bus_info = {
.class_init = pnv_phb4_root_bus_class_init,
};
static void pnv_phb4_root_port_reset(DeviceState *dev)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
PCIDevice *d = PCI_DEVICE(dev);
uint8_t *conf = d->config;
rpc->parent_reset(dev);
pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
PCI_IO_RANGE_MASK & 0xff);
pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
PCI_IO_RANGE_MASK & 0xff);
pci_set_word(conf + PCI_MEMORY_BASE, 0);
pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0);
pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1);
pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1);
pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
pci_config_set_interrupt_pin(conf, 0);
}
static void pnv_phb4_root_port_realize(DeviceState *dev, Error **errp)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
Error *local_err = NULL;
rpc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
dc->desc = "IBM PHB4 PCIE Root Port";
dc->user_creatable = false;
device_class_set_parent_realize(dc, pnv_phb4_root_port_realize,
&rpc->parent_realize);
device_class_set_parent_reset(dc, pnv_phb4_root_port_reset,
&rpc->parent_reset);
k->vendor_id = PCI_VENDOR_ID_IBM;
k->device_id = PNV_PHB4_DEVICE_ID;
k->revision = 0;
rpc->exp_offset = 0x48;
rpc->aer_offset = 0x100;
dc->reset = &pnv_phb4_root_port_reset;
}
static const TypeInfo pnv_phb4_root_port_info = {
.name = TYPE_PNV_PHB4_ROOT_PORT,
.parent = TYPE_PCIE_ROOT_PORT,
.instance_size = sizeof(PnvPHB4RootPort),
.class_init = pnv_phb4_root_port_class_init,
};
static void pnv_phb5_root_port_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
dc->desc = "IBM PHB5 PCIE Root Port";
dc->user_creatable = false;
k->vendor_id = PCI_VENDOR_ID_IBM;
k->device_id = PNV_PHB5_DEVICE_ID;
}
static const TypeInfo pnv_phb5_root_port_info = {
.name = TYPE_PNV_PHB5_ROOT_PORT,
.parent = TYPE_PNV_PHB4_ROOT_PORT,
.instance_size = sizeof(PnvPHB4RootPort),
.class_init = pnv_phb5_root_port_class_init,
};
static void pnv_phb4_register_types(void)
{
type_register_static(&pnv_phb4_root_bus_info);
type_register_static(&pnv_phb5_root_port_info);
type_register_static(&pnv_phb4_root_port_info);
type_register_static(&pnv_phb4_type_info);
type_register_static(&pnv_phb5_type_info);
type_register_static(&pnv_phb4_iommu_memory_region_info);

View File

@ -115,8 +115,7 @@ static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec,
int stack_no,
Error **errp)
{
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
PnvPHB4 *phb = PNV_PHB4(qdev_new(pecc->phb_type));
PnvPHB *phb = PNV_PHB(qdev_new(TYPE_PNV_PHB));
int phb_id = pnv_phb4_pec_get_phb_id(pec, stack_no);
object_property_add_child(OBJECT(pec), "phb[*]", OBJECT(phb));
@ -147,8 +146,10 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp)
pec->num_phbs = pecc->num_phbs[pec->index];
/* Create PHBs if running with defaults */
for (i = 0; i < pec->num_phbs; i++) {
pnv_pec_default_phb_realize(pec, i, errp);
if (defaults_enabled()) {
for (i = 0; i < pec->num_phbs; i++) {
pnv_pec_default_phb_realize(pec, i, errp);
}
}
/* Initialize the XSCOM regions for the PEC registers */
@ -261,7 +262,6 @@ static void pnv_pec_class_init(ObjectClass *klass, void *data)
pecc->version = PNV_PHB4_VERSION;
pecc->phb_type = TYPE_PNV_PHB4;
pecc->num_phbs = pnv_pec_num_phbs;
pecc->rp_model = TYPE_PNV_PHB4_ROOT_PORT;
}
static const TypeInfo pnv_pec_type_info = {
@ -314,7 +314,6 @@ static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data)
pecc->version = PNV_PHB5_VERSION;
pecc->phb_type = TYPE_PNV_PHB5;
pecc->num_phbs = pnv_phb5_pec_num_stacks;
pecc->rp_model = TYPE_PNV_PHB5_ROOT_PORT;
}
static const TypeInfo pnv_phb5_pec_type_info = {

View File

@ -58,7 +58,6 @@ config PPC4XX
config SAM460EX
bool
select PPC405
select PFLASH_CFI01
select IDE_SII3112
select M41T80
@ -72,6 +71,7 @@ config SAM460EX
config PEGASOS2
bool
imply ATI_VGA
select MV64361
select VT82C686
select IDE_VIA
@ -79,7 +79,6 @@ config PEGASOS2
select VOF
# This should come with VT82C686
select ACPI_X86
imply ATI_VGA
config PREP
bool

View File

@ -46,6 +46,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
'pnv_lpc.c',
'pnv_psi.c',
'pnv_occ.c',
'pnv_sbe.c',
'pnv_bmc.c',
'pnv_homer.c',
'pnv_pnor.c',

View File

@ -43,6 +43,7 @@
#include "hw/ipmi/ipmi.h"
#include "target/ppc/mmu-hash64.h"
#include "hw/pci/msi.h"
#include "hw/pci-host/pnv_phb.h"
#include "hw/ppc/xics.h"
#include "hw/qdev-properties.h"
@ -280,6 +281,75 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
g_free(reg);
}
static PnvPhb4PecState *pnv_phb4_get_pec(PnvChip *chip, PnvPHB4 *phb,
Error **errp)
{
PnvPHB *phb_base = phb->phb_base;
PnvPhb4PecState *pecs = NULL;
int chip_id = phb->chip_id;
int index = phb->phb_id;
int i, j;
if (phb_base->version == 4) {
Pnv9Chip *chip9 = PNV9_CHIP(chip);
pecs = chip9->pecs;
} else if (phb_base->version == 5) {
Pnv10Chip *chip10 = PNV10_CHIP(chip);
pecs = chip10->pecs;
} else {
g_assert_not_reached();
}
for (i = 0; i < chip->num_pecs; i++) {
/*
* For each PEC, check the amount of phbs it supports
* and see if the given phb4 index matches an index.
*/
PnvPhb4PecState *pec = &pecs[i];
for (j = 0; j < pec->num_phbs; j++) {
if (index == pnv_phb4_pec_get_phb_id(pec, j)) {
return pec;
}
}
}
error_setg(errp,
"pnv-phb4 chip-id %d index %d didn't match any existing PEC",
chip_id, index);
return NULL;
}
/*
* Adds a PnvPHB to the chip. Returns the parent obj of the
* PHB which varies with each version (phb version 3 is parented
* by the chip, version 4 and 5 are parented by the PEC
* device).
*
* TODO: for version 3 we're still parenting the PHB with the
* chip. We should parent with a (so far not implemented)
* PHB3 PEC device.
*/
Object *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp)
{
if (phb->version == 3) {
Pnv8Chip *chip8 = PNV8_CHIP(chip);
phb->chip = chip;
chip8->phbs[chip8->num_phbs] = phb;
chip8->num_phbs++;
return OBJECT(chip);
}
phb->pec = pnv_phb4_get_pec(chip, PNV_PHB4(phb->backend), errp);
return OBJECT(phb->pec);
}
static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
{
static const char compat[] = "ibm,power8-xscom\0ibm,xscom";
@ -660,7 +730,8 @@ static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
ics_pic_print_info(&chip8->psi.ics, mon);
for (i = 0; i < chip8->num_phbs; i++) {
PnvPHB3 *phb3 = &chip8->phbs[i];
PnvPHB *phb = chip8->phbs[i];
PnvPHB3 *phb3 = PNV_PHB3(phb->backend);
pnv_phb3_msi_pic_print_info(&phb3->msis, mon);
ics_pic_print_info(&phb3->lsis, mon);
@ -670,11 +741,14 @@ static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
static int pnv_chip_power9_pic_print_info_child(Object *child, void *opaque)
{
Monitor *mon = opaque;
PnvPHB4 *phb4 = (PnvPHB4 *) object_dynamic_cast(child, TYPE_PNV_PHB4);
PnvPHB *phb = (PnvPHB *) object_dynamic_cast(child, TYPE_PNV_PHB);
if (phb4) {
pnv_phb4_pic_print_info(phb4, mon);
if (!phb) {
return 0;
}
pnv_phb4_pic_print_info(PNV_PHB4(phb->backend), mon);
return 0;
}
@ -714,7 +788,7 @@ static bool pnv_match_cpu(const char *default_type, const char *cpu_type)
PowerPCCPUClass *ppc =
POWERPC_CPU_CLASS(object_class_by_name(cpu_type));
return ppc_default->pvr_match(ppc_default, ppc->pvr);
return ppc_default->pvr_match(ppc_default, ppc->pvr, false);
}
static void pnv_ipmi_bt_init(ISABus *bus, IPMIBmc *bmc, uint32_t irq)
@ -1146,10 +1220,22 @@ static void pnv_chip_power8_instance_init(Object *obj)
object_initialize_child(obj, "homer", &chip8->homer, TYPE_PNV8_HOMER);
chip8->num_phbs = pcc->num_phbs;
if (defaults_enabled()) {
chip8->num_phbs = pcc->num_phbs;
for (i = 0; i < chip8->num_phbs; i++) {
object_initialize_child(obj, "phb[*]", &chip8->phbs[i], TYPE_PNV_PHB3);
for (i = 0; i < chip8->num_phbs; i++) {
Object *phb = object_new(TYPE_PNV_PHB);
/*
* We need the chip to parent the PHB to allow the DT
* to build correctly (via pnv_xscom_dt()).
*
* TODO: the PHB should be parented by a PEC device that, at
* this moment, is not modelled powernv8/phb3.
*/
object_property_add_child(obj, "phb[*]", phb);
chip8->phbs[i] = PNV_PHB(phb);
}
}
}
@ -1183,30 +1269,6 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
}
}
/*
* Attach a root port device.
*
* 'index' will be used both as a PCIE slot value and to calculate
* QOM id. 'chip_id' is going to be used as PCIE chassis for the
* root port.
*/
void pnv_phb_attach_root_port(PCIHostState *pci, const char *name,
int index, int chip_id)
{
PCIDevice *root = pci_new(PCI_DEVFN(0, 0), name);
g_autofree char *default_id = g_strdup_printf("%s[%d]", name, index);
const char *dev_id = DEVICE(root)->id;
object_property_add_child(OBJECT(pci->bus), dev_id ? dev_id : default_id,
OBJECT(root));
/* Set unique chassis/slot values for the root port */
qdev_prop_set_uint8(DEVICE(root), "chassis", chip_id);
qdev_prop_set_uint16(DEVICE(root), "slot", index);
pci_realize_and_unref(root, pci->bus, &error_fatal);
}
static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
@ -1287,9 +1349,9 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip),
&chip8->homer.regs);
/* PHB3 controllers */
/* PHB controllers */
for (i = 0; i < chip8->num_phbs; i++) {
PnvPHB3 *phb = &chip8->phbs[i];
PnvPHB *phb = chip8->phbs[i];
object_property_set_int(OBJECT(phb), "index", i, &error_fatal);
object_property_set_int(OBJECT(phb), "chip-id", chip->chip_id,
@ -1397,6 +1459,8 @@ static void pnv_chip_power9_instance_init(Object *obj)
object_initialize_child(obj, "occ", &chip9->occ, TYPE_PNV9_OCC);
object_initialize_child(obj, "sbe", &chip9->sbe, TYPE_PNV9_SBE);
object_initialize_child(obj, "homer", &chip9->homer, TYPE_PNV9_HOMER);
/* Number of PECs is the chip default */
@ -1549,6 +1613,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(), PNV9_OCC_SENSOR_BASE(chip),
&chip9->occ.sram_regs);
/* SBE */
if (!qdev_realize(DEVICE(&chip9->sbe), NULL, errp)) {
return;
}
pnv_xscom_add_subregion(chip, PNV9_XSCOM_SBE_CTRL_BASE,
&chip9->sbe.xscom_ctrl_regs);
pnv_xscom_add_subregion(chip, PNV9_XSCOM_SBE_MBOX_BASE,
&chip9->sbe.xscom_mbox_regs);
qdev_connect_gpio_out(DEVICE(&chip9->sbe), 0, qdev_get_gpio_in(
DEVICE(&chip9->psi), PSIHB9_IRQ_PSU));
/* HOMER */
object_property_set_link(OBJECT(&chip9->homer), "chip", OBJECT(chip),
&error_abort);
@ -1613,6 +1688,7 @@ static void pnv_chip_power10_instance_init(Object *obj)
object_initialize_child(obj, "psi", &chip10->psi, TYPE_PNV10_PSI);
object_initialize_child(obj, "lpc", &chip10->lpc, TYPE_PNV10_LPC);
object_initialize_child(obj, "occ", &chip10->occ, TYPE_PNV10_OCC);
object_initialize_child(obj, "sbe", &chip10->sbe, TYPE_PNV10_SBE);
object_initialize_child(obj, "homer", &chip10->homer, TYPE_PNV10_HOMER);
chip->num_pecs = pcc->num_pecs;
@ -1754,6 +1830,17 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
PNV10_OCC_SENSOR_BASE(chip),
&chip10->occ.sram_regs);
/* SBE */
if (!qdev_realize(DEVICE(&chip10->sbe), NULL, errp)) {
return;
}
pnv_xscom_add_subregion(chip, PNV10_XSCOM_SBE_CTRL_BASE,
&chip10->sbe.xscom_ctrl_regs);
pnv_xscom_add_subregion(chip, PNV10_XSCOM_SBE_MBOX_BASE,
&chip10->sbe.xscom_mbox_regs);
qdev_connect_gpio_out(DEVICE(&chip10->sbe), 0, qdev_get_gpio_in(
DEVICE(&chip10->psi), PSIHB9_IRQ_PSU));
/* HOMER */
object_property_set_link(OBJECT(&chip10->homer), "chip", OBJECT(chip),
&error_abort);
@ -1957,7 +2044,8 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
}
for (j = 0; j < chip8->num_phbs; j++) {
PnvPHB3 *phb3 = &chip8->phbs[j];
PnvPHB *phb = chip8->phbs[j];
PnvPHB3 *phb3 = PNV_PHB3(phb->backend);
if (ics_valid_irq(&phb3->lsis, irq)) {
return &phb3->lsis;
@ -1995,7 +2083,8 @@ static void pnv_ics_resend(XICSFabric *xi)
ics_resend(&chip8->psi.ics);
for (j = 0; j < chip8->num_phbs; j++) {
PnvPHB3 *phb3 = &chip8->phbs[j];
PnvPHB *phb = chip8->phbs[j];
PnvPHB3 *phb3 = PNV_PHB3(phb->backend);
ics_resend(&phb3->lsis);
ics_resend(ICS(&phb3->msis));
@ -2095,8 +2184,14 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
static const char compat[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
static GlobalProperty phb_compat[] = {
{ TYPE_PNV_PHB, "version", "3" },
{ TYPE_PNV_PHB_ROOT_PORT, "version", "3" },
};
mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat));
xic->icp_get = pnv_icp_get;
xic->ics_get = pnv_ics_get;
@ -2104,6 +2199,8 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
@ -2113,8 +2210,15 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
static const char compat[] = "qemu,powernv9\0ibm,powernv";
static GlobalProperty phb_compat[] = {
{ TYPE_PNV_PHB, "version", "4" },
{ TYPE_PNV_PHB_ROOT_PORT, "version", "4" },
};
mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat));
xfc->match_nvt = pnv_match_nvt;
mc->alias = "powernv";
@ -2122,6 +2226,8 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->dt_power_mgt = pnv_dt_power_mgt;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
@ -2131,14 +2237,22 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
static const char compat[] = "qemu,powernv10\0ibm,powernv";
static GlobalProperty phb_compat[] = {
{ TYPE_PNV_PHB, "version", "5" },
{ TYPE_PNV_PHB_ROOT_PORT, "version", "5" },
};
mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v2.0");
compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat));
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->dt_power_mgt = pnv_dt_power_mgt;
xfc->match_nvt = pnv10_xive_match_nvt;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
static bool pnv_machine_get_hb(Object *obj, Error **errp)

414
hw/ppc/pnv_sbe.c Normal file
View File

@ -0,0 +1,414 @@
/*
* QEMU PowerPC PowerNV Emulation of some SBE behaviour
*
* Copyright (c) 2022, 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 "target/ppc/cpu.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_xscom.h"
#include "hw/ppc/pnv_sbe.h"
#include "trace.h"
/*
* Most register and command definitions come from skiboot.
*
* xscom addresses are adjusted to be relative to xscom subregion bases
*/
/*
* SBE MBOX register address
* Reg 0 - 3 : Host to send command packets to SBE
* Reg 4 - 7 : SBE to send response packets to Host
*/
#define PSU_HOST_SBE_MBOX_REG0 0x00000000
#define PSU_HOST_SBE_MBOX_REG1 0x00000001
#define PSU_HOST_SBE_MBOX_REG2 0x00000002
#define PSU_HOST_SBE_MBOX_REG3 0x00000003
#define PSU_HOST_SBE_MBOX_REG4 0x00000004
#define PSU_HOST_SBE_MBOX_REG5 0x00000005
#define PSU_HOST_SBE_MBOX_REG6 0x00000006
#define PSU_HOST_SBE_MBOX_REG7 0x00000007
#define PSU_SBE_DOORBELL_REG_RW 0x00000010
#define PSU_SBE_DOORBELL_REG_AND 0x00000011
#define PSU_SBE_DOORBELL_REG_OR 0x00000012
#define PSU_HOST_DOORBELL_REG_RW 0x00000013
#define PSU_HOST_DOORBELL_REG_AND 0x00000014
#define PSU_HOST_DOORBELL_REG_OR 0x00000015
/*
* Doorbell register to trigger SBE interrupt. Set by OPAL to inform
* the SBE about a waiting message in the Host/SBE mailbox registers
*/
#define HOST_SBE_MSG_WAITING PPC_BIT(0)
/*
* Doorbell register for host bridge interrupt. Set by the SBE to inform
* host about a response message in the Host/SBE mailbox registers
*/
#define SBE_HOST_RESPONSE_WAITING PPC_BIT(0)
#define SBE_HOST_MSG_READ PPC_BIT(1)
#define SBE_HOST_STOP15_EXIT PPC_BIT(2)
#define SBE_HOST_RESET PPC_BIT(3)
#define SBE_HOST_PASSTHROUGH PPC_BIT(4)
#define SBE_HOST_TIMER_EXPIRY PPC_BIT(14)
#define SBE_HOST_RESPONSE_MASK (PPC_BITMASK(0, 4) | \
SBE_HOST_TIMER_EXPIRY)
/* SBE Control Register */
#define SBE_CONTROL_REG_RW 0x00000000
/* SBE interrupt s0/s1 bits */
#define SBE_CONTROL_REG_S0 PPC_BIT(14)
#define SBE_CONTROL_REG_S1 PPC_BIT(15)
struct sbe_msg {
uint64_t reg[4];
};
static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque, hwaddr addr,
unsigned size)
{
uint32_t offset = addr >> 3;
uint64_t val = 0;
switch (offset) {
default:
qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
HWADDR_PRIx "\n", addr >> 3);
}
trace_pnv_sbe_xscom_ctrl_read(addr, val);
return val;
}
static void pnv_sbe_power9_xscom_ctrl_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
uint32_t offset = addr >> 3;
trace_pnv_sbe_xscom_ctrl_write(addr, val);
switch (offset) {
default:
qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
HWADDR_PRIx "\n", addr >> 3);
}
}
static const MemoryRegionOps pnv_sbe_power9_xscom_ctrl_ops = {
.read = pnv_sbe_power9_xscom_ctrl_read,
.write = pnv_sbe_power9_xscom_ctrl_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static void pnv_sbe_set_host_doorbell(PnvSBE *sbe, uint64_t val)
{
val &= SBE_HOST_RESPONSE_MASK; /* Is this right? What does HW do? */
sbe->host_doorbell = val;
trace_pnv_sbe_reg_set_host_doorbell(val);
qemu_set_irq(sbe->psi_irq, !!val);
}
/* SBE Target Type */
#define SBE_TARGET_TYPE_PROC 0x00
#define SBE_TARGET_TYPE_EX 0x01
#define SBE_TARGET_TYPE_PERV 0x02
#define SBE_TARGET_TYPE_MCS 0x03
#define SBE_TARGET_TYPE_EQ 0x04
#define SBE_TARGET_TYPE_CORE 0x05
/* SBE MBOX command class */
#define SBE_MCLASS_FIRST 0xD1
#define SBE_MCLASS_CORE_STATE 0xD1
#define SBE_MCLASS_SCOM 0xD2
#define SBE_MCLASS_RING 0xD3
#define SBE_MCLASS_TIMER 0xD4
#define SBE_MCLASS_MPIPL 0xD5
#define SBE_MCLASS_SECURITY 0xD6
#define SBE_MCLASS_GENERIC 0xD7
#define SBE_MCLASS_LAST 0xD7
/*
* Commands are provided in xxyy form where:
* - xx : command class
* - yy : command
*
* Both request and response message uses same seq ID,
* command class and command.
*/
#define SBE_CMD_CTRL_DEADMAN_LOOP 0xD101
#define SBE_CMD_MULTI_SCOM 0xD201
#define SBE_CMD_PUT_RING_FORM_IMAGE 0xD301
#define SBE_CMD_CONTROL_TIMER 0xD401
#define SBE_CMD_GET_ARCHITECTED_REG 0xD501
#define SBE_CMD_CLR_ARCHITECTED_REG 0xD502
#define SBE_CMD_SET_UNSEC_MEM_WINDOW 0xD601
#define SBE_CMD_GET_SBE_FFDC 0xD701
#define SBE_CMD_GET_CAPABILITY 0xD702
#define SBE_CMD_READ_SBE_SEEPROM 0xD703
#define SBE_CMD_SET_FFDC_ADDR 0xD704
#define SBE_CMD_QUIESCE_SBE 0xD705
#define SBE_CMD_SET_FABRIC_ID_MAP 0xD706
#define SBE_CMD_STASH_MPIPL_CONFIG 0xD707
/* SBE MBOX control flags */
/* Generic flags */
#define SBE_CMD_CTRL_RESP_REQ 0x0100
#define SBE_CMD_CTRL_ACK_REQ 0x0200
/* Deadman loop */
#define CTRL_DEADMAN_LOOP_START 0x0001
#define CTRL_DEADMAN_LOOP_STOP 0x0002
/* Control timer */
#define CONTROL_TIMER_START 0x0001
#define CONTROL_TIMER_STOP 0x0002
/* Stash MPIPL config */
#define SBE_STASH_KEY_SKIBOOT_BASE 0x03
static void sbe_timer(void *opaque)
{
PnvSBE *sbe = opaque;
trace_pnv_sbe_cmd_timer_expired();
pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_TIMER_EXPIRY);
}
static void do_sbe_msg(PnvSBE *sbe)
{
struct sbe_msg msg;
uint16_t cmd, ctrl_flags, seq_id;
int i;
memset(&msg, 0, sizeof(msg));
for (i = 0; i < 4; i++) {
msg.reg[i] = sbe->mbox[i];
}
cmd = msg.reg[0];
seq_id = msg.reg[0] >> 16;
ctrl_flags = msg.reg[0] >> 32;
trace_pnv_sbe_msg_recv(cmd, seq_id, ctrl_flags);
if (ctrl_flags & SBE_CMD_CTRL_ACK_REQ) {
pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_MSG_READ);
}
switch (cmd) {
case SBE_CMD_CONTROL_TIMER:
if (ctrl_flags & CONTROL_TIMER_START) {
uint64_t us = msg.reg[1];
trace_pnv_sbe_cmd_timer_start(us);
timer_mod(sbe->timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + us);
}
if (ctrl_flags & CONTROL_TIMER_STOP) {
trace_pnv_sbe_cmd_timer_stop();
timer_del(sbe->timer);
}
break;
default:
qemu_log_mask(LOG_UNIMP, "SBE Unimplemented command: 0x%x\n", cmd);
}
}
static void pnv_sbe_set_sbe_doorbell(PnvSBE *sbe, uint64_t val)
{
val &= HOST_SBE_MSG_WAITING;
sbe->sbe_doorbell = val;
if (val & HOST_SBE_MSG_WAITING) {
sbe->sbe_doorbell &= ~HOST_SBE_MSG_WAITING;
do_sbe_msg(sbe);
}
}
static uint64_t pnv_sbe_power9_xscom_mbox_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvSBE *sbe = PNV_SBE(opaque);
uint32_t offset = addr >> 3;
uint64_t val = 0;
if (offset <= PSU_HOST_SBE_MBOX_REG7) {
uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
val = sbe->mbox[idx];
} else {
switch (offset) {
case PSU_SBE_DOORBELL_REG_RW:
val = sbe->sbe_doorbell;
break;
case PSU_HOST_DOORBELL_REG_RW:
val = sbe->host_doorbell;
break;
default:
qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
HWADDR_PRIx "\n", addr >> 3);
}
}
trace_pnv_sbe_xscom_mbox_read(addr, val);
return val;
}
static void pnv_sbe_power9_xscom_mbox_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
PnvSBE *sbe = PNV_SBE(opaque);
uint32_t offset = addr >> 3;
trace_pnv_sbe_xscom_mbox_write(addr, val);
if (offset <= PSU_HOST_SBE_MBOX_REG7) {
uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
sbe->mbox[idx] = val;
} else {
switch (offset) {
case PSU_SBE_DOORBELL_REG_RW:
pnv_sbe_set_sbe_doorbell(sbe, val);
break;
case PSU_SBE_DOORBELL_REG_AND:
pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell & val);
break;
case PSU_SBE_DOORBELL_REG_OR:
pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell | val);
break;
case PSU_HOST_DOORBELL_REG_RW:
pnv_sbe_set_host_doorbell(sbe, val);
break;
case PSU_HOST_DOORBELL_REG_AND:
pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell & val);
break;
case PSU_HOST_DOORBELL_REG_OR:
pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | val);
break;
default:
qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
HWADDR_PRIx "\n", addr >> 3);
}
}
}
static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops = {
.read = pnv_sbe_power9_xscom_mbox_read,
.write = pnv_sbe_power9_xscom_mbox_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static void pnv_sbe_power9_class_init(ObjectClass *klass, void *data)
{
PnvSBEClass *psc = PNV_SBE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "PowerNV SBE Controller (POWER9)";
psc->xscom_ctrl_size = PNV9_XSCOM_SBE_CTRL_SIZE;
psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
psc->xscom_mbox_size = PNV9_XSCOM_SBE_MBOX_SIZE;
psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
}
static const TypeInfo pnv_sbe_power9_type_info = {
.name = TYPE_PNV9_SBE,
.parent = TYPE_PNV_SBE,
.instance_size = sizeof(PnvSBE),
.class_init = pnv_sbe_power9_class_init,
};
static void pnv_sbe_power10_class_init(ObjectClass *klass, void *data)
{
PnvSBEClass *psc = PNV_SBE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "PowerNV SBE Controller (POWER10)";
psc->xscom_ctrl_size = PNV10_XSCOM_SBE_CTRL_SIZE;
psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
psc->xscom_mbox_size = PNV10_XSCOM_SBE_MBOX_SIZE;
psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
}
static const TypeInfo pnv_sbe_power10_type_info = {
.name = TYPE_PNV10_SBE,
.parent = TYPE_PNV9_SBE,
.class_init = pnv_sbe_power10_class_init,
};
static void pnv_sbe_realize(DeviceState *dev, Error **errp)
{
PnvSBE *sbe = PNV_SBE(dev);
PnvSBEClass *psc = PNV_SBE_GET_CLASS(sbe);
/* XScom regions for SBE registers */
pnv_xscom_region_init(&sbe->xscom_ctrl_regs, OBJECT(dev),
psc->xscom_ctrl_ops, sbe, "xscom-sbe-ctrl",
psc->xscom_ctrl_size);
pnv_xscom_region_init(&sbe->xscom_mbox_regs, OBJECT(dev),
psc->xscom_mbox_ops, sbe, "xscom-sbe-mbox",
psc->xscom_mbox_size);
qdev_init_gpio_out(DEVICE(dev), &sbe->psi_irq, 1);
sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe);
}
static void pnv_sbe_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pnv_sbe_realize;
dc->desc = "PowerNV SBE Controller";
dc->user_creatable = false;
}
static const TypeInfo pnv_sbe_type_info = {
.name = TYPE_PNV_SBE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvSBE),
.class_init = pnv_sbe_class_init,
.class_size = sizeof(PnvSBEClass),
.abstract = true,
};
static void pnv_sbe_register_types(void)
{
type_register_static(&pnv_sbe_type_info);
type_register_static(&pnv_sbe_power9_type_info);
type_register_static(&pnv_sbe_power10_type_info);
}
type_init(pnv_sbe_register_types);

View File

@ -295,6 +295,9 @@ int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset,
_FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
_FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat, compat_size)));
_FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0)));
if (chip->chip_id == 0) {
_FDT((fdt_setprop(fdt, xscom_offset, "primary", NULL, 0)));
}
args.fdt = fdt;
args.xscom_offset = xscom_offset;

View File

@ -25,54 +25,168 @@
#ifndef PPC405_H
#define PPC405_H
#include "qom/object.h"
#include "hw/ppc/ppc4xx.h"
#include "hw/intc/ppc-uic.h"
#include "hw/i2c/ppc4xx_i2c.h"
#define PPC405EP_SDRAM_BASE 0x00000000
#define PPC405EP_NVRAM_BASE 0xF0000000
#define PPC405EP_FPGA_BASE 0xF0300000
#define PPC405EP_SRAM_BASE 0xFFF00000
#define PPC405EP_SRAM_SIZE (512 * KiB)
#define PPC405EP_FLASH_BASE 0xFFF80000
/* PLB to OPB bridge */
#define TYPE_PPC405_POB "ppc405-pob"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405PobState, PPC405_POB);
struct Ppc405PobState {
Ppc4xxDcrDeviceState parent_obj;
/* Bootinfo as set-up by u-boot */
typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
struct ppc4xx_bd_info_t {
uint32_t bi_memstart;
uint32_t bi_memsize;
uint32_t bi_flashstart;
uint32_t bi_flashsize;
uint32_t bi_flashoffset; /* 0x10 */
uint32_t bi_sramstart;
uint32_t bi_sramsize;
uint32_t bi_bootflags;
uint32_t bi_ipaddr; /* 0x20 */
uint8_t bi_enetaddr[6];
uint16_t bi_ethspeed;
uint32_t bi_intfreq;
uint32_t bi_busfreq; /* 0x30 */
uint32_t bi_baudrate;
uint8_t bi_s_version[4];
uint8_t bi_r_version[32];
uint32_t bi_procfreq;
uint32_t bi_plb_busfreq;
uint32_t bi_pci_busfreq;
uint8_t bi_pci_enetaddr[6];
uint8_t bi_pci_enetaddr2[6]; /* PPC405EP specific */
uint32_t bi_opbfreq;
uint32_t bi_iic_fast[2];
uint32_t bear;
uint32_t besr0;
uint32_t besr1;
};
/* PowerPC 405 core */
ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size);
/* OPB arbitrer */
#define TYPE_PPC405_OPBA "ppc405-opba"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405OpbaState, PPC405_OPBA);
struct Ppc405OpbaState {
SysBusDevice parent_obj;
void ppc4xx_plb_init(CPUPPCState *env);
void ppc405_ebc_init(CPUPPCState *env);
MemoryRegion io;
uint8_t cr;
uint8_t pr;
};
PowerPCCPU *ppc405ep_init(MemoryRegion *address_space_mem,
MemoryRegion ram_memories[2],
hwaddr ram_bases[2],
hwaddr ram_sizes[2],
uint32_t sysclk, DeviceState **uicdev,
int do_init);
/* DMA controller */
#define TYPE_PPC405_DMA "ppc405-dma"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405DmaState, PPC405_DMA);
struct Ppc405DmaState {
Ppc4xxDcrDeviceState parent_obj;
qemu_irq irqs[4];
uint32_t cr[4];
uint32_t ct[4];
uint32_t da[4];
uint32_t sa[4];
uint32_t sg[4];
uint32_t sr;
uint32_t sgc;
uint32_t slp;
uint32_t pol;
};
/* GPIO */
#define TYPE_PPC405_GPIO "ppc405-gpio"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405GpioState, PPC405_GPIO);
struct Ppc405GpioState {
SysBusDevice parent_obj;
MemoryRegion io;
uint32_t or;
uint32_t tcr;
uint32_t osrh;
uint32_t osrl;
uint32_t tsrh;
uint32_t tsrl;
uint32_t odr;
uint32_t ir;
uint32_t rr1;
uint32_t isr1h;
uint32_t isr1l;
};
/* On Chip Memory */
#define TYPE_PPC405_OCM "ppc405-ocm"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405OcmState, PPC405_OCM);
struct Ppc405OcmState {
Ppc4xxDcrDeviceState parent_obj;
MemoryRegion ram;
MemoryRegion isarc_ram;
MemoryRegion dsarc_ram;
uint32_t isarc;
uint32_t isacntl;
uint32_t dsarc;
uint32_t dsacntl;
};
/* General purpose timers */
#define TYPE_PPC405_GPT "ppc405-gpt"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405GptState, PPC405_GPT);
struct Ppc405GptState {
SysBusDevice parent_obj;
MemoryRegion iomem;
int64_t tb_offset;
uint32_t tb_freq;
QEMUTimer *timer;
qemu_irq irqs[5];
uint32_t oe;
uint32_t ol;
uint32_t im;
uint32_t is;
uint32_t ie;
uint32_t comp[5];
uint32_t mask[5];
};
#define TYPE_PPC405_CPC "ppc405-cpc"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405CpcState, PPC405_CPC);
enum {
PPC405EP_CPU_CLK = 0,
PPC405EP_PLB_CLK = 1,
PPC405EP_OPB_CLK = 2,
PPC405EP_EBC_CLK = 3,
PPC405EP_MAL_CLK = 4,
PPC405EP_PCI_CLK = 5,
PPC405EP_UART0_CLK = 6,
PPC405EP_UART1_CLK = 7,
PPC405EP_CLK_NB = 8,
};
struct Ppc405CpcState {
Ppc4xxDcrDeviceState parent_obj;
uint32_t sysclk;
clk_setup_t clk_setup[PPC405EP_CLK_NB];
uint32_t boot;
uint32_t epctl;
uint32_t pllmr[2];
uint32_t ucr;
uint32_t srr;
uint32_t jtagid;
uint32_t pci;
/* Clock and power management */
uint32_t er;
uint32_t fr;
uint32_t sr;
};
#define TYPE_PPC405_SOC "ppc405-soc"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405SoCState, PPC405_SOC);
struct Ppc405SoCState {
/* Private */
DeviceState parent_obj;
/* Public */
MemoryRegion ram_banks[2];
hwaddr ram_bases[2], ram_sizes[2];
bool do_dram_init;
MemoryRegion *dram_mr;
hwaddr ram_size;
PowerPCCPU cpu;
PPCUIC uic;
Ppc405CpcState cpc;
Ppc405GptState gpt;
Ppc405OcmState ocm;
Ppc405GpioState gpio;
Ppc405DmaState dma;
PPC4xxI2CState i2c;
Ppc4xxEbcState ebc;
Ppc405OpbaState opba;
Ppc405PobState pob;
Ppc4xxPlbState plb;
Ppc4xxMalState mal;
};
#endif /* PPC405_H */

View File

@ -48,97 +48,24 @@
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
#define PPC405EP_SDRAM_BASE 0x00000000
#define PPC405EP_SRAM_BASE 0xFFF00000
#define PPC405EP_SRAM_SIZE (512 * KiB)
#define USE_FLASH_BIOS
/*****************************************************************************/
/* PPC405EP reference board (IBM) */
/* Standalone board with:
* - PowerPC 405EP CPU
* - SDRAM (0x00000000)
* - Flash (0xFFF80000)
* - SRAM (0xFFF00000)
* - NVRAM (0xF0000000)
* - FPGA (0xF0300000)
*/
typedef struct ref405ep_fpga_t ref405ep_fpga_t;
struct ref405ep_fpga_t {
uint8_t reg0;
uint8_t reg1;
#define TYPE_PPC405_MACHINE MACHINE_TYPE_NAME("ppc405")
OBJECT_DECLARE_SIMPLE_TYPE(Ppc405MachineState, PPC405_MACHINE);
struct Ppc405MachineState {
/* Private */
MachineState parent_obj;
/* Public */
Ppc405SoCState soc;
};
static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size)
{
ref405ep_fpga_t *fpga;
uint32_t ret;
fpga = opaque;
switch (addr) {
case 0x0:
ret = fpga->reg0;
break;
case 0x1:
ret = fpga->reg1;
break;
default:
ret = 0;
break;
}
return ret;
}
static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
ref405ep_fpga_t *fpga;
fpga = opaque;
switch (addr) {
case 0x0:
/* Read only */
break;
case 0x1:
fpga->reg1 = value;
break;
default:
break;
}
}
static const MemoryRegionOps ref405ep_fpga_ops = {
.read = ref405ep_fpga_readb,
.write = ref405ep_fpga_writeb,
.impl.min_access_size = 1,
.impl.max_access_size = 1,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.endianness = DEVICE_BIG_ENDIAN,
};
static void ref405ep_fpga_reset (void *opaque)
{
ref405ep_fpga_t *fpga;
fpga = opaque;
fpga->reg0 = 0x00;
fpga->reg1 = 0x0F;
}
static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base)
{
ref405ep_fpga_t *fpga;
MemoryRegion *fpga_memory = g_new(MemoryRegion, 1);
fpga = g_new0(ref405ep_fpga_t, 1);
memory_region_init_io(fpga_memory, NULL, &ref405ep_fpga_ops, fpga,
"fpga", 0x00000100);
memory_region_add_subregion(sysmem, base, fpga_memory);
qemu_register_reset(&ref405ep_fpga_reset, fpga);
}
/*
* CPU reset handler when booting directly from a loaded kernel
*/
/* CPU reset handler when booting directly from a loaded kernel */
static struct boot_info {
uint32_t entry;
uint32_t bdloc;
@ -169,6 +96,126 @@ static void main_cpu_reset(void *opaque)
env->nip = bi->entry;
}
/* Bootinfo as set-up by u-boot */
typedef struct {
uint32_t bi_memstart;
uint32_t bi_memsize;
uint32_t bi_flashstart;
uint32_t bi_flashsize;
uint32_t bi_flashoffset; /* 0x10 */
uint32_t bi_sramstart;
uint32_t bi_sramsize;
uint32_t bi_bootflags;
uint32_t bi_ipaddr; /* 0x20 */
uint8_t bi_enetaddr[6];
uint16_t bi_ethspeed;
uint32_t bi_intfreq;
uint32_t bi_busfreq; /* 0x30 */
uint32_t bi_baudrate;
uint8_t bi_s_version[4];
uint8_t bi_r_version[32];
uint32_t bi_procfreq;
uint32_t bi_plb_busfreq;
uint32_t bi_pci_busfreq;
uint8_t bi_pci_enetaddr[6];
uint8_t bi_pci_enetaddr2[6]; /* PPC405EP specific */
uint32_t bi_opbfreq;
uint32_t bi_iic_fast[2];
} ppc4xx_bd_info_t;
static void ppc405_set_default_bootinfo(ppc4xx_bd_info_t *bd,
ram_addr_t ram_size)
{
memset(bd, 0, sizeof(*bd));
bd->bi_memstart = PPC405EP_SDRAM_BASE;
bd->bi_memsize = ram_size;
bd->bi_sramstart = PPC405EP_SRAM_BASE;
bd->bi_sramsize = PPC405EP_SRAM_SIZE;
bd->bi_bootflags = 0;
bd->bi_intfreq = 133333333;
bd->bi_busfreq = 33333333;
bd->bi_baudrate = 115200;
bd->bi_s_version[0] = 'Q';
bd->bi_s_version[1] = 'M';
bd->bi_s_version[2] = 'U';
bd->bi_s_version[3] = '\0';
bd->bi_r_version[0] = 'Q';
bd->bi_r_version[1] = 'E';
bd->bi_r_version[2] = 'M';
bd->bi_r_version[3] = 'U';
bd->bi_r_version[4] = '\0';
bd->bi_procfreq = 133333333;
bd->bi_plb_busfreq = 33333333;
bd->bi_pci_busfreq = 33333333;
bd->bi_opbfreq = 33333333;
}
static ram_addr_t __ppc405_set_bootinfo(CPUPPCState *env, ppc4xx_bd_info_t *bd)
{
CPUState *cs = env_cpu(env);
ram_addr_t bdloc;
int i, n;
/* We put the bd structure at the top of memory */
if (bd->bi_memsize >= 0x01000000UL) {
bdloc = 0x01000000UL - sizeof(ppc4xx_bd_info_t);
} else {
bdloc = bd->bi_memsize - sizeof(ppc4xx_bd_info_t);
}
stl_be_phys(cs->as, bdloc + 0x00, bd->bi_memstart);
stl_be_phys(cs->as, bdloc + 0x04, bd->bi_memsize);
stl_be_phys(cs->as, bdloc + 0x08, bd->bi_flashstart);
stl_be_phys(cs->as, bdloc + 0x0C, bd->bi_flashsize);
stl_be_phys(cs->as, bdloc + 0x10, bd->bi_flashoffset);
stl_be_phys(cs->as, bdloc + 0x14, bd->bi_sramstart);
stl_be_phys(cs->as, bdloc + 0x18, bd->bi_sramsize);
stl_be_phys(cs->as, bdloc + 0x1C, bd->bi_bootflags);
stl_be_phys(cs->as, bdloc + 0x20, bd->bi_ipaddr);
for (i = 0; i < 6; i++) {
stb_phys(cs->as, bdloc + 0x24 + i, bd->bi_enetaddr[i]);
}
stw_be_phys(cs->as, bdloc + 0x2A, bd->bi_ethspeed);
stl_be_phys(cs->as, bdloc + 0x2C, bd->bi_intfreq);
stl_be_phys(cs->as, bdloc + 0x30, bd->bi_busfreq);
stl_be_phys(cs->as, bdloc + 0x34, bd->bi_baudrate);
for (i = 0; i < 4; i++) {
stb_phys(cs->as, bdloc + 0x38 + i, bd->bi_s_version[i]);
}
for (i = 0; i < 32; i++) {
stb_phys(cs->as, bdloc + 0x3C + i, bd->bi_r_version[i]);
}
stl_be_phys(cs->as, bdloc + 0x5C, bd->bi_procfreq);
stl_be_phys(cs->as, bdloc + 0x60, bd->bi_plb_busfreq);
stl_be_phys(cs->as, bdloc + 0x64, bd->bi_pci_busfreq);
for (i = 0; i < 6; i++) {
stb_phys(cs->as, bdloc + 0x68 + i, bd->bi_pci_enetaddr[i]);
}
n = 0x70; /* includes 2 bytes hole */
for (i = 0; i < 6; i++) {
stb_phys(cs->as, bdloc + n++, bd->bi_pci_enetaddr2[i]);
}
stl_be_phys(cs->as, bdloc + n, bd->bi_opbfreq);
n += 4;
for (i = 0; i < 2; i++) {
stl_be_phys(cs->as, bdloc + n, bd->bi_iic_fast[i]);
n += 4;
}
return bdloc;
}
static ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size)
{
ppc4xx_bd_info_t bd;
memset(&bd, 0, sizeof(bd));
ppc405_set_default_bootinfo(&bd, ram_size);
return __ppc405_set_bootinfo(env, &bd);
}
static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
@ -221,18 +268,12 @@ static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu)
env->load_info = &boot_info;
}
static void ref405ep_init(MachineState *machine)
static void ppc405_init(MachineState *machine)
{
Ppc405MachineState *ppc405 = PPC405_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const char *kernel_filename = machine->kernel_filename;
PowerPCCPU *cpu;
DeviceState *dev;
SysBusDevice *s;
MemoryRegion *sram = g_new(MemoryRegion, 1);
MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
hwaddr ram_bases[2], ram_sizes[2];
MemoryRegion *sysmem = get_system_memory();
DeviceState *uicdev;
if (machine->ram_size != mc->default_ram_size) {
char *sz = size_to_str(mc->default_ram_size);
@ -241,22 +282,17 @@ static void ref405ep_init(MachineState *machine)
exit(EXIT_FAILURE);
}
/* XXX: fix this */
memory_region_init_alias(&ram_memories[0], NULL, "ef405ep.ram.alias",
machine->ram, 0, machine->ram_size);
ram_bases[0] = 0;
ram_sizes[0] = machine->ram_size;
memory_region_init(&ram_memories[1], NULL, "ef405ep.ram1", 0);
ram_bases[1] = 0x00000000;
ram_sizes[1] = 0x00000000;
cpu = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
33333333, &uicdev, kernel_filename == NULL ? 0 : 1);
/* allocate SRAM */
memory_region_init_ram(sram, NULL, "ef405ep.sram", PPC405EP_SRAM_SIZE,
&error_fatal);
memory_region_add_subregion(sysmem, PPC405EP_SRAM_BASE, sram);
object_initialize_child(OBJECT(machine), "soc", &ppc405->soc,
TYPE_PPC405_SOC);
object_property_set_uint(OBJECT(&ppc405->soc), "ram-size",
machine->ram_size, &error_fatal);
object_property_set_link(OBJECT(&ppc405->soc), "dram",
OBJECT(machine->ram), &error_abort);
object_property_set_bool(OBJECT(&ppc405->soc), "dram-init",
kernel_filename != NULL, &error_abort);
object_property_set_uint(OBJECT(&ppc405->soc), "sys-clk", 33333333,
&error_abort);
qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal);
/* allocate and load BIOS */
if (machine->firmware) {
@ -285,15 +321,6 @@ static void ref405ep_init(MachineState *machine)
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
}
/* Register FPGA */
ref405ep_fpga_init(sysmem, PPC405EP_FPGA_BASE);
/* Register NVRAM */
dev = qdev_new("sysbus-m48t08");
qdev_prop_set_int32(dev, "base-year", 1968);
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_mmio_map(s, 0, PPC405EP_NVRAM_BASE);
/* Load kernel and initrd using U-Boot images */
if (kernel_filename && machine->firmware) {
target_ulong kernel_base, initrd_base;
@ -322,63 +349,66 @@ static void ref405ep_init(MachineState *machine)
/* Load ELF kernel and rootfs.cpio */
} else if (kernel_filename && !machine->firmware) {
boot_from_kernel(machine, cpu);
boot_from_kernel(machine, &ppc405->soc.cpu);
}
}
static void ref405ep_class_init(ObjectClass *oc, void *data)
static void ppc405_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "ref405ep";
mc->init = ref405ep_init;
mc->default_ram_size = 0x08000000;
mc->default_ram_id = "ef405ep.ram";
mc->desc = "PPC405 generic machine";
mc->init = ppc405_init;
mc->default_ram_size = 128 * MiB;
mc->default_ram_id = "ppc405.ram";
}
static const TypeInfo ref405ep_type = {
.name = MACHINE_TYPE_NAME("ref405ep"),
static const TypeInfo ppc405_machine_type = {
.name = TYPE_PPC405_MACHINE,
.parent = TYPE_MACHINE,
.class_init = ref405ep_class_init,
.instance_size = sizeof(Ppc405MachineState),
.class_init = ppc405_machine_class_init,
.abstract = true,
};
/*****************************************************************************/
/* AMCC Taihu evaluation board */
/* - PowerPC 405EP processor
* - SDRAM 128 MB at 0x00000000
* - Boot flash 2 MB at 0xFFE00000
* - Application flash 32 MB at 0xFC000000
* - 2 serial ports
* - 2 ethernet PHY
* - 1 USB 1.1 device 0x50000000
* - 1 LCD display 0x50100000
* - 1 CPLD 0x50100000
* - 1 I2C EEPROM
* - 1 I2C thermal sensor
* - a set of LEDs
* - bit-bang SPI port using GPIOs
* - 1 EBC interface connector 0 0x50200000
* - 1 cardbus controller + expansion slot.
* - 1 PCI expansion slot.
/* PPC405EP reference board (IBM) */
/*
* Standalone board with:
* - PowerPC 405EP CPU
* - SDRAM (0x00000000)
* - Flash (0xFFF80000)
* - SRAM (0xFFF00000)
* - NVRAM (0xF0000000)
* - FPGA (0xF0300000)
*/
typedef struct taihu_cpld_t taihu_cpld_t;
struct taihu_cpld_t {
#define PPC405EP_NVRAM_BASE 0xF0000000
#define PPC405EP_FPGA_BASE 0xF0300000
#define PPC405EP_FLASH_BASE 0xFFF80000
#define TYPE_REF405EP_FPGA "ref405ep-fpga"
OBJECT_DECLARE_SIMPLE_TYPE(Ref405epFpgaState, REF405EP_FPGA);
struct Ref405epFpgaState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint8_t reg0;
uint8_t reg1;
};
static uint64_t taihu_cpld_read(void *opaque, hwaddr addr, unsigned size)
static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size)
{
taihu_cpld_t *cpld;
Ref405epFpgaState *fpga = opaque;
uint32_t ret;
cpld = opaque;
switch (addr) {
case 0x0:
ret = cpld->reg0;
ret = fpga->reg0;
break;
case 0x1:
ret = cpld->reg1;
ret = fpga->reg1;
break;
default:
ret = 0;
@ -388,195 +418,113 @@ static uint64_t taihu_cpld_read(void *opaque, hwaddr addr, unsigned size)
return ret;
}
static void taihu_cpld_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
taihu_cpld_t *cpld;
Ref405epFpgaState *fpga = opaque;
cpld = opaque;
switch (addr) {
case 0x0:
/* Read only */
break;
case 0x1:
cpld->reg1 = value;
fpga->reg1 = value;
break;
default:
break;
}
}
static const MemoryRegionOps taihu_cpld_ops = {
.read = taihu_cpld_read,
.write = taihu_cpld_write,
.impl = {
.min_access_size = 1,
.max_access_size = 1,
},
.endianness = DEVICE_NATIVE_ENDIAN,
static const MemoryRegionOps ref405ep_fpga_ops = {
.read = ref405ep_fpga_readb,
.write = ref405ep_fpga_writeb,
.impl.min_access_size = 1,
.impl.max_access_size = 1,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.endianness = DEVICE_BIG_ENDIAN,
};
static void taihu_cpld_reset (void *opaque)
static void ref405ep_fpga_reset(DeviceState *dev)
{
taihu_cpld_t *cpld;
Ref405epFpgaState *fpga = REF405EP_FPGA(dev);
cpld = opaque;
cpld->reg0 = 0x01;
cpld->reg1 = 0x80;
fpga->reg0 = 0x00;
fpga->reg1 = 0x0F;
}
static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base)
static void ref405ep_fpga_realize(DeviceState *dev, Error **errp)
{
taihu_cpld_t *cpld;
MemoryRegion *cpld_memory = g_new(MemoryRegion, 1);
Ref405epFpgaState *s = REF405EP_FPGA(dev);
cpld = g_new0(taihu_cpld_t, 1);
memory_region_init_io(cpld_memory, NULL, &taihu_cpld_ops, cpld, "cpld", 0x100);
memory_region_add_subregion(sysmem, base, cpld_memory);
qemu_register_reset(&taihu_cpld_reset, cpld);
memory_region_init_io(&s->iomem, OBJECT(s), &ref405ep_fpga_ops, s,
"fpga", 0x00000100);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
static void taihu_405ep_init(MachineState *machine)
static void ref405ep_fpga_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
const char *bios_name = machine->firmware ?: BIOS_FILENAME;
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
char *filename;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *bios;
MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
hwaddr ram_bases[2], ram_sizes[2];
long bios_size;
target_ulong kernel_base, initrd_base;
long kernel_size, initrd_size;
int linux_boot;
int fl_idx;
DriveInfo *dinfo;
DeviceState *uicdev;
DeviceClass *dc = DEVICE_CLASS(oc);
if (machine->ram_size != mc->default_ram_size) {
char *sz = size_to_str(mc->default_ram_size);
error_report("Invalid RAM size, should be %s", sz);
g_free(sz);
exit(EXIT_FAILURE);
}
ram_bases[0] = 0;
ram_sizes[0] = 0x04000000;
memory_region_init_alias(&ram_memories[0], NULL,
"taihu_405ep.ram-0", machine->ram, ram_bases[0],
ram_sizes[0]);
ram_bases[1] = 0x04000000;
ram_sizes[1] = 0x04000000;
memory_region_init_alias(&ram_memories[1], NULL,
"taihu_405ep.ram-1", machine->ram, ram_bases[1],
ram_sizes[1]);
ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
33333333, &uicdev, kernel_filename == NULL ? 0 : 1);
/* allocate and load BIOS */
fl_idx = 0;
#if defined(USE_FLASH_BIOS)
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
if (dinfo) {
bios_size = 2 * MiB;
pflash_cfi02_register(0xFFE00000,
"taihu_405ep.bios", bios_size,
blk_by_legacy_dinfo(dinfo),
64 * KiB, 1,
4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
1);
fl_idx++;
} else
#endif
{
bios = g_new(MemoryRegion, 1);
memory_region_init_rom(bios, NULL, "taihu_405ep.bios", BIOS_SIZE,
&error_fatal);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
bios_size = load_image_size(filename,
memory_region_get_ram_ptr(bios),
BIOS_SIZE);
g_free(filename);
if (bios_size < 0) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
} else if (!qtest_enabled()) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
}
/* Register Linux flash */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
if (dinfo) {
bios_size = 32 * MiB;
pflash_cfi02_register(0xfc000000, "taihu_405ep.flash", bios_size,
blk_by_legacy_dinfo(dinfo),
64 * KiB, 1,
4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
1);
fl_idx++;
}
/* Register CLPD & LCD display */
taihu_cpld_init(sysmem, 0x50100000);
/* Load kernel */
linux_boot = (kernel_filename != NULL);
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image_targphys(kernel_filename, kernel_base,
machine->ram_size - kernel_base);
if (kernel_size < 0) {
error_report("could not load kernel '%s'", kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image_targphys(initrd_filename, initrd_base,
machine->ram_size - initrd_base);
if (initrd_size < 0) {
error_report("could not load initial ram disk '%s'",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
dc->realize = ref405ep_fpga_realize;
dc->reset = ref405ep_fpga_reset;
/* Reason: only works as part of a ppc405 board */
dc->user_creatable = false;
}
static void taihu_class_init(ObjectClass *oc, void *data)
static const TypeInfo ref405ep_fpga_type = {
.name = TYPE_REF405EP_FPGA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Ref405epFpgaState),
.class_init = ref405ep_fpga_class_init,
};
static void ref405ep_init(MachineState *machine)
{
DeviceState *dev;
SysBusDevice *s;
MemoryRegion *sram = g_new(MemoryRegion, 1);
ppc405_init(machine);
/* allocate SRAM */
memory_region_init_ram(sram, NULL, "ref405ep.sram", PPC405EP_SRAM_SIZE,
&error_fatal);
memory_region_add_subregion(get_system_memory(), PPC405EP_SRAM_BASE, sram);
/* Register FPGA */
dev = qdev_new(TYPE_REF405EP_FPGA);
object_property_add_child(OBJECT(machine), "fpga", OBJECT(dev));
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, PPC405EP_FPGA_BASE);
/* Register NVRAM */
dev = qdev_new("sysbus-m48t08");
qdev_prop_set_int32(dev, "base-year", 1968);
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_mmio_map(s, 0, PPC405EP_NVRAM_BASE);
}
static void ref405ep_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "taihu";
mc->init = taihu_405ep_init;
mc->default_ram_size = 0x08000000;
mc->default_ram_id = "taihu_405ep.ram";
mc->deprecation_reason = "incomplete, use 'ref405ep' instead";
mc->desc = "ref405ep";
mc->init = ref405ep_init;
}
static const TypeInfo taihu_type = {
.name = MACHINE_TYPE_NAME("taihu"),
.parent = TYPE_MACHINE,
.class_init = taihu_class_init,
static const TypeInfo ref405ep_type = {
.name = MACHINE_TYPE_NAME("ref405ep"),
.parent = TYPE_PPC405_MACHINE,
.class_init = ref405ep_class_init,
};
static void ppc405_machine_init(void)
{
type_register_static(&ppc405_machine_type);
type_register_static(&ref405ep_type);
type_register_static(&taihu_type);
type_register_static(&ref405ep_fpga_type);
}
type_init(ppc405_machine_init)

File diff suppressed because it is too large Load Diff

View File

@ -84,27 +84,30 @@ static int bamboo_load_device_tree(hwaddr addr,
ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
sizeof(mem_reg_property));
if (ret < 0)
if (ret < 0) {
fprintf(stderr, "couldn't set /memory/reg\n");
}
ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
initrd_base);
if (ret < 0)
if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
}
ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
(initrd_base + initrd_size));
if (ret < 0)
if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
}
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
kernel_cmdline);
if (ret < 0)
if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/bootargs\n");
}
/* Copy data from the host device tree into the guest. Since the guest can
/*
* Copy data from the host device tree into the guest. Since the guest can
* directly access the timebase without host involvement, we must expose
* the correct frequencies. */
* the correct frequencies.
*/
if (kvm_enabled()) {
tb_freq = kvmppc_get_tbfreq();
clock_freq = kvmppc_get_clockfreq();
@ -193,12 +196,9 @@ static void bamboo_init(MachineState *machine)
/* interrupt controller */
uicdev = qdev_new(TYPE_PPC_UIC);
ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal);
object_unref(OBJECT(uicdev));
uicsbd = SYS_BUS_DEVICE(uicdev);
object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
&error_fatal);
sysbus_realize_and_unref(uicsbd, &error_fatal);
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
@ -249,8 +249,10 @@ static void bamboo_init(MachineState *machine)
if (pcibus) {
/* Register network interfaces. */
for (i = 0; i < nb_nics; i++) {
/* There are no PCI NICs on the Bamboo board, but there are
* PCI slots, so we can pick whatever default model we want. */
/*
* There are no PCI NICs on the Bamboo board, but there are
* PCI slots, so we can pick whatever default model we want.
*/
pci_nic_init_nofail(&nd_table[i], pcibus, "e1000", NULL);
}
}

View File

@ -1028,7 +1028,8 @@ void ppc4xx_dma_init(CPUPPCState *env, int dcr_base)
/*****************************************************************************/
/* PCI Express controller */
/* FIXME: This is not complete and does not work, only implemented partially
/*
* FIXME: This is not complete and does not work, only implemented partially
* to allow firmware and guests to find an empty bus. Cards should use PCI.
*/
#include "hw/pci/pcie_host.h"

View File

@ -29,7 +29,6 @@
#include "hw/irq.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc4xx.h"
#include "hw/intc/ppc-uic.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
#include "exec/address-spaces.h"
@ -37,38 +36,6 @@
#include "qapi/error.h"
#include "trace.h"
static void ppc4xx_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
cpu_reset(CPU(cpu));
}
/*****************************************************************************/
/* Generic PowerPC 4xx processor instantiation */
PowerPCCPU *ppc4xx_init(const char *cpu_type,
clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
uint32_t sysclk)
{
PowerPCCPU *cpu;
CPUPPCState *env;
/* init CPUs */
cpu = POWERPC_CPU(cpu_create(cpu_type));
env = &cpu->env;
cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
cpu_clk->opaque = env;
/* Set time-base frequency to sysclk */
tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
tb_clk->opaque = env;
ppc_dcr_init(env, NULL, NULL);
/* Register qemu callbacks */
qemu_register_reset(ppc4xx_reset, cpu);
return cpu;
}
/*****************************************************************************/
/* SDRAM controller */
typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
@ -98,12 +65,12 @@ enum {
SDRAM0_CFGDATA = 0x011,
};
/* XXX: TOFIX: some patches have made this code become inconsistent:
/*
* XXX: TOFIX: some patches have made this code become inconsistent:
* there are type inconsistencies, mixing hwaddr, target_ulong
* and uint32_t
*/
static uint32_t sdram_bcr (hwaddr ram_base,
hwaddr ram_size)
static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
{
uint32_t bcr;
@ -146,16 +113,17 @@ static inline hwaddr sdram_base(uint32_t bcr)
return bcr & 0xFF800000;
}
static target_ulong sdram_size (uint32_t bcr)
static target_ulong sdram_size(uint32_t bcr)
{
target_ulong size;
int sh;
sh = (bcr >> 17) & 0x7;
if (sh == 7)
if (sh == 7) {
size = -1;
else
} else {
size = (4 * MiB) << sh;
}
return size;
}
@ -175,7 +143,7 @@ static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
}
sdram->bcr[i] = bcr & 0xFFDEE001;
if (enabled && (bcr & 0x00000001)) {
trace_ppc4xx_sdram_unmap(sdram_base(bcr), sdram_size(bcr));
trace_ppc4xx_sdram_map(sdram_base(bcr), sdram_size(bcr));
memory_region_init(&sdram->containers[i], NULL, "sdram-containers",
sdram_size(bcr));
memory_region_add_subregion(&sdram->containers[i], 0,
@ -186,7 +154,7 @@ static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
}
}
static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
static void sdram_map_bcr(ppc4xx_sdram_t *sdram)
{
int i;
@ -200,7 +168,7 @@ static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
}
}
static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
static void sdram_unmap_bcr(ppc4xx_sdram_t *sdram)
{
int i;
@ -212,7 +180,7 @@ static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
}
}
static uint32_t dcr_read_sdram (void *opaque, int dcrn)
static uint32_t dcr_read_sdram(void *opaque, int dcrn)
{
ppc4xx_sdram_t *sdram;
uint32_t ret;
@ -280,7 +248,7 @@ static uint32_t dcr_read_sdram (void *opaque, int dcrn)
return ret;
}
static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
{
ppc4xx_sdram_t *sdram;
@ -313,10 +281,11 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
sdram_unmap_bcr(sdram);
sdram->status |= 0x80000000;
}
if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) {
sdram->status |= 0x40000000;
else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
} else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) {
sdram->status &= ~0x40000000;
}
sdram->cfg = val;
break;
case 0x24: /* SDRAM_STATUS */
@ -348,10 +317,11 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
break;
case 0x98: /* SDRAM_ECCESR */
val &= 0xFFF0F000;
if (sdram->eccesr == 0 && val != 0)
if (sdram->eccesr == 0 && val != 0) {
qemu_irq_raise(sdram->irq);
else if (sdram->eccesr != 0 && val == 0)
} else if (sdram->eccesr != 0 && val == 0) {
qemu_irq_lower(sdram->irq);
}
sdram->eccesr = val;
break;
default: /* Error */
@ -361,7 +331,7 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
}
}
static void sdram_reset (void *opaque)
static void sdram_reset(void *opaque)
{
ppc4xx_sdram_t *sdram;
@ -381,11 +351,11 @@ static void sdram_reset (void *opaque)
sdram->cfg = 0x00800000;
}
void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
MemoryRegion *ram_memories,
hwaddr *ram_bases,
hwaddr *ram_sizes,
int do_init)
void ppc4xx_sdram_init(CPUPPCState *env, qemu_irq irq, int nbanks,
MemoryRegion *ram_memories,
hwaddr *ram_bases,
hwaddr *ram_sizes,
int do_init)
{
ppc4xx_sdram_t *sdram;
@ -404,8 +374,9 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
sdram, &dcr_read_sdram, &dcr_write_sdram);
ppc_dcr_register(env, SDRAM0_CFGDATA,
sdram, &dcr_read_sdram, &dcr_write_sdram);
if (do_init)
if (do_init) {
sdram_map_bcr(sdram);
}
}
/*
@ -462,7 +433,7 @@ void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
}
error_report("at most %d bank%s of %s MiB each supported",
nr_banks, nr_banks == 1 ? "" : "s", s->str);
error_printf("Possible valid RAM size: %" PRIi64 " MiB \n",
error_printf("Possible valid RAM size: %" PRIi64 " MiB\n",
used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB);
g_string_free(s, true);
@ -491,32 +462,10 @@ enum {
MAL0_RCBS1 = 0x1E1,
};
typedef struct ppc4xx_mal_t ppc4xx_mal_t;
struct ppc4xx_mal_t {
qemu_irq irqs[4];
uint32_t cfg;
uint32_t esr;
uint32_t ier;
uint32_t txcasr;
uint32_t txcarr;
uint32_t txeobisr;
uint32_t txdeir;
uint32_t rxcasr;
uint32_t rxcarr;
uint32_t rxeobisr;
uint32_t rxdeir;
uint32_t *txctpr;
uint32_t *rxctpr;
uint32_t *rcbs;
uint8_t txcnum;
uint8_t rxcnum;
};
static void ppc4xx_mal_reset(void *opaque)
static void ppc4xx_mal_reset(DeviceState *dev)
{
ppc4xx_mal_t *mal;
Ppc4xxMalState *mal = PPC4xx_MAL(dev);
mal = opaque;
mal->cfg = 0x0007C000;
mal->esr = 0x00000000;
mal->ier = 0x00000000;
@ -530,10 +479,9 @@ static void ppc4xx_mal_reset(void *opaque)
static uint32_t dcr_read_mal(void *opaque, int dcrn)
{
ppc4xx_mal_t *mal;
Ppc4xxMalState *mal = opaque;
uint32_t ret;
mal = opaque;
switch (dcrn) {
case MAL0_CFG:
ret = mal->cfg;
@ -587,13 +535,12 @@ static uint32_t dcr_read_mal(void *opaque, int dcrn)
static void dcr_write_mal(void *opaque, int dcrn, uint32_t val)
{
ppc4xx_mal_t *mal;
Ppc4xxMalState *mal = opaque;
mal = opaque;
switch (dcrn) {
case MAL0_CFG:
if (val & 0x80000000) {
ppc4xx_mal_reset(mal);
ppc4xx_mal_reset(DEVICE(mal));
}
mal->cfg = val & 0x00FFC087;
break;
@ -644,55 +591,404 @@ static void dcr_write_mal(void *opaque, int dcrn, uint32_t val)
}
}
void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum,
qemu_irq irqs[4])
static void ppc4xx_mal_realize(DeviceState *dev, Error **errp)
{
ppc4xx_mal_t *mal;
Ppc4xxMalState *mal = PPC4xx_MAL(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
int i;
assert(txcnum <= 32 && rxcnum <= 32);
mal = g_malloc0(sizeof(*mal));
mal->txcnum = txcnum;
mal->rxcnum = rxcnum;
mal->txctpr = g_new0(uint32_t, txcnum);
mal->rxctpr = g_new0(uint32_t, rxcnum);
mal->rcbs = g_new0(uint32_t, rxcnum);
for (i = 0; i < 4; i++) {
mal->irqs[i] = irqs[i];
if (mal->txcnum > 32 || mal->rxcnum > 32) {
error_setg(errp, "invalid TXC/RXC number");
return;
}
qemu_register_reset(&ppc4xx_mal_reset, mal);
ppc_dcr_register(env, MAL0_CFG,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_ESR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_IER,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_TXCASR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_TXCARR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_TXEOBISR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_TXDEIR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_RXCASR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_RXCARR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_RXEOBISR,
mal, &dcr_read_mal, &dcr_write_mal);
ppc_dcr_register(env, MAL0_RXDEIR,
mal, &dcr_read_mal, &dcr_write_mal);
for (i = 0; i < txcnum; i++) {
ppc_dcr_register(env, MAL0_TXCTP0R + i,
mal, &dcr_read_mal, &dcr_write_mal);
mal->txctpr = g_new0(uint32_t, mal->txcnum);
mal->rxctpr = g_new0(uint32_t, mal->rxcnum);
mal->rcbs = g_new0(uint32_t, mal->rxcnum);
for (i = 0; i < ARRAY_SIZE(mal->irqs); i++) {
sysbus_init_irq(SYS_BUS_DEVICE(dev), &mal->irqs[i]);
}
for (i = 0; i < rxcnum; i++) {
ppc_dcr_register(env, MAL0_RXCTP0R + i,
mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_CFG, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_ESR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_IER, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_TXCASR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_TXCARR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_TXEOBISR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_TXDEIR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_RXCASR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_RXCARR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_RXEOBISR, mal, &dcr_read_mal, &dcr_write_mal);
ppc4xx_dcr_register(dcr, MAL0_RXDEIR, mal, &dcr_read_mal, &dcr_write_mal);
for (i = 0; i < mal->txcnum; i++) {
ppc4xx_dcr_register(dcr, MAL0_TXCTP0R + i,
mal, &dcr_read_mal, &dcr_write_mal);
}
for (i = 0; i < rxcnum; i++) {
ppc_dcr_register(env, MAL0_RCBS0 + i,
mal, &dcr_read_mal, &dcr_write_mal);
for (i = 0; i < mal->rxcnum; i++) {
ppc4xx_dcr_register(dcr, MAL0_RXCTP0R + i,
mal, &dcr_read_mal, &dcr_write_mal);
}
for (i = 0; i < mal->rxcnum; i++) {
ppc4xx_dcr_register(dcr, MAL0_RCBS0 + i,
mal, &dcr_read_mal, &dcr_write_mal);
}
}
static void ppc4xx_mal_finalize(Object *obj)
{
Ppc4xxMalState *mal = PPC4xx_MAL(obj);
g_free(mal->rcbs);
g_free(mal->rxctpr);
g_free(mal->txctpr);
}
static Property ppc4xx_mal_properties[] = {
DEFINE_PROP_UINT8("txc-num", Ppc4xxMalState, txcnum, 0),
DEFINE_PROP_UINT8("rxc-num", Ppc4xxMalState, rxcnum, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void ppc4xx_mal_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_mal_realize;
dc->reset = ppc4xx_mal_reset;
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_mal_properties);
}
/*****************************************************************************/
/* Peripheral local bus arbitrer */
enum {
PLB3A0_ACR = 0x077,
PLB4A0_ACR = 0x081,
PLB0_BESR = 0x084,
PLB0_BEAR = 0x086,
PLB0_ACR = 0x087,
PLB4A1_ACR = 0x089,
};
static uint32_t dcr_read_plb(void *opaque, int dcrn)
{
Ppc4xxPlbState *plb = opaque;
uint32_t ret;
switch (dcrn) {
case PLB0_ACR:
ret = plb->acr;
break;
case PLB0_BEAR:
ret = plb->bear;
break;
case PLB0_BESR:
ret = plb->besr;
break;
default:
/* Avoid gcc warning */
ret = 0;
break;
}
return ret;
}
static void dcr_write_plb(void *opaque, int dcrn, uint32_t val)
{
Ppc4xxPlbState *plb = opaque;
switch (dcrn) {
case PLB0_ACR:
/*
* We don't care about the actual parameters written as
* we don't manage any priorities on the bus
*/
plb->acr = val & 0xF8000000;
break;
case PLB0_BEAR:
/* Read only */
break;
case PLB0_BESR:
/* Write-clear */
plb->besr &= ~val;
break;
}
}
static void ppc405_plb_reset(DeviceState *dev)
{
Ppc4xxPlbState *plb = PPC4xx_PLB(dev);
plb->acr = 0x00000000;
plb->bear = 0x00000000;
plb->besr = 0x00000000;
}
static void ppc405_plb_realize(DeviceState *dev, Error **errp)
{
Ppc4xxPlbState *plb = PPC4xx_PLB(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
ppc4xx_dcr_register(dcr, PLB3A0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
ppc4xx_dcr_register(dcr, PLB4A0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
ppc4xx_dcr_register(dcr, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
ppc4xx_dcr_register(dcr, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
ppc4xx_dcr_register(dcr, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
ppc4xx_dcr_register(dcr, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb);
}
static void ppc405_plb_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_plb_realize;
dc->reset = ppc405_plb_reset;
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
/*****************************************************************************/
/* Peripheral controller */
enum {
EBC0_CFGADDR = 0x012,
EBC0_CFGDATA = 0x013,
};
static uint32_t dcr_read_ebc(void *opaque, int dcrn)
{
Ppc4xxEbcState *ebc = opaque;
uint32_t ret;
switch (dcrn) {
case EBC0_CFGADDR:
ret = ebc->addr;
break;
case EBC0_CFGDATA:
switch (ebc->addr) {
case 0x00: /* B0CR */
ret = ebc->bcr[0];
break;
case 0x01: /* B1CR */
ret = ebc->bcr[1];
break;
case 0x02: /* B2CR */
ret = ebc->bcr[2];
break;
case 0x03: /* B3CR */
ret = ebc->bcr[3];
break;
case 0x04: /* B4CR */
ret = ebc->bcr[4];
break;
case 0x05: /* B5CR */
ret = ebc->bcr[5];
break;
case 0x06: /* B6CR */
ret = ebc->bcr[6];
break;
case 0x07: /* B7CR */
ret = ebc->bcr[7];
break;
case 0x10: /* B0AP */
ret = ebc->bap[0];
break;
case 0x11: /* B1AP */
ret = ebc->bap[1];
break;
case 0x12: /* B2AP */
ret = ebc->bap[2];
break;
case 0x13: /* B3AP */
ret = ebc->bap[3];
break;
case 0x14: /* B4AP */
ret = ebc->bap[4];
break;
case 0x15: /* B5AP */
ret = ebc->bap[5];
break;
case 0x16: /* B6AP */
ret = ebc->bap[6];
break;
case 0x17: /* B7AP */
ret = ebc->bap[7];
break;
case 0x20: /* BEAR */
ret = ebc->bear;
break;
case 0x21: /* BESR0 */
ret = ebc->besr0;
break;
case 0x22: /* BESR1 */
ret = ebc->besr1;
break;
case 0x23: /* CFG */
ret = ebc->cfg;
break;
default:
ret = 0x00000000;
break;
}
break;
default:
ret = 0x00000000;
break;
}
return ret;
}
static void dcr_write_ebc(void *opaque, int dcrn, uint32_t val)
{
Ppc4xxEbcState *ebc = opaque;
switch (dcrn) {
case EBC0_CFGADDR:
ebc->addr = val;
break;
case EBC0_CFGDATA:
switch (ebc->addr) {
case 0x00: /* B0CR */
break;
case 0x01: /* B1CR */
break;
case 0x02: /* B2CR */
break;
case 0x03: /* B3CR */
break;
case 0x04: /* B4CR */
break;
case 0x05: /* B5CR */
break;
case 0x06: /* B6CR */
break;
case 0x07: /* B7CR */
break;
case 0x10: /* B0AP */
break;
case 0x11: /* B1AP */
break;
case 0x12: /* B2AP */
break;
case 0x13: /* B3AP */
break;
case 0x14: /* B4AP */
break;
case 0x15: /* B5AP */
break;
case 0x16: /* B6AP */
break;
case 0x17: /* B7AP */
break;
case 0x20: /* BEAR */
break;
case 0x21: /* BESR0 */
break;
case 0x22: /* BESR1 */
break;
case 0x23: /* CFG */
break;
default:
break;
}
break;
default:
break;
}
}
static void ppc405_ebc_reset(DeviceState *dev)
{
Ppc4xxEbcState *ebc = PPC4xx_EBC(dev);
int i;
ebc->addr = 0x00000000;
ebc->bap[0] = 0x7F8FFE80;
ebc->bcr[0] = 0xFFE28000;
for (i = 0; i < 8; i++) {
ebc->bap[i] = 0x00000000;
ebc->bcr[i] = 0x00000000;
}
ebc->besr0 = 0x00000000;
ebc->besr1 = 0x00000000;
ebc->cfg = 0x80400000;
}
static void ppc405_ebc_realize(DeviceState *dev, Error **errp)
{
Ppc4xxEbcState *ebc = PPC4xx_EBC(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
ppc4xx_dcr_register(dcr, EBC0_CFGADDR, ebc, &dcr_read_ebc, &dcr_write_ebc);
ppc4xx_dcr_register(dcr, EBC0_CFGDATA, ebc, &dcr_read_ebc, &dcr_write_ebc);
}
static void ppc405_ebc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_ebc_realize;
dc->reset = ppc405_ebc_reset;
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
/* PPC4xx_DCR_DEVICE */
void ppc4xx_dcr_register(Ppc4xxDcrDeviceState *dev, int dcrn, void *opaque,
dcr_read_cb dcr_read, dcr_write_cb dcr_write)
{
assert(dev->cpu);
ppc_dcr_register(&dev->cpu->env, dcrn, opaque, dcr_read, dcr_write);
}
bool ppc4xx_dcr_realize(Ppc4xxDcrDeviceState *dev, PowerPCCPU *cpu,
Error **errp)
{
object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort);
return sysbus_realize(SYS_BUS_DEVICE(dev), errp);
}
static Property ppc4xx_dcr_properties[] = {
DEFINE_PROP_LINK("cpu", Ppc4xxDcrDeviceState, cpu, TYPE_POWERPC_CPU,
PowerPCCPU *),
DEFINE_PROP_END_OF_LIST(),
};
static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, ppc4xx_dcr_properties);
}
static const TypeInfo ppc4xx_types[] = {
{
.name = TYPE_PPC4xx_MAL,
.parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(Ppc4xxMalState),
.instance_finalize = ppc4xx_mal_finalize,
.class_init = ppc4xx_mal_class_init,
}, {
.name = TYPE_PPC4xx_PLB,
.parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(Ppc4xxPlbState),
.class_init = ppc405_plb_class_init,
}, {
.name = TYPE_PPC4xx_EBC,
.parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(Ppc4xxEbcState),
.class_init = ppc405_ebc_class_init,
}, {
.name = TYPE_PPC4xx_DCR_DEVICE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Ppc4xxDcrDeviceState),
.class_init = ppc4xx_dcr_class_init,
.abstract = true,
}
};
DEFINE_TYPES(ppc4xx_types)

View File

@ -16,8 +16,10 @@
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
/* This file implements emulation of the 32-bit PCI controller found in some
* 4xx SoCs, such as the 440EP. */
/*
* This file implements emulation of the 32-bit PCI controller found in some
* 4xx SoCs, such as the 440EP.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
@ -65,8 +67,10 @@ struct PPC4xxPCIState {
#define PCIC0_CFGADDR 0x0
#define PCIC0_CFGDATA 0x4
/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
* PCI accesses. */
/*
* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
* PCI accesses.
*/
#define PCIL0_PMM0LA 0x0
#define PCIL0_PMM0MA 0x4
#define PCIL0_PMM0PCILA 0x8
@ -80,8 +84,10 @@ struct PPC4xxPCIState {
#define PCIL0_PMM2PCILA 0x28
#define PCIL0_PMM2PCIHA 0x2c
/* PCI Target Map (PTM) registers specify which PCI addresses are translated to
* PLB accesses. */
/*
* PCI Target Map (PTM) registers specify which PCI addresses are translated to
* PLB accesses.
*/
#define PCIL0_PTM1MS 0x30
#define PCIL0_PTM1LA 0x34
#define PCIL0_PTM2MS 0x38
@ -96,9 +102,10 @@ static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset,
{
struct PPC4xxPCIState *pci = opaque;
/* We ignore all target attempts at PCI configuration, effectively
* assuming a bidirectional 1:1 mapping of PLB and PCI space. */
/*
* We ignore all target attempts at PCI configuration, effectively
* assuming a bidirectional 1:1 mapping of PLB and PCI space.
*/
switch (offset) {
case PCIL0_PMM0LA:
pci->pmm[0].la = value;
@ -243,8 +250,10 @@ static void ppc4xx_pci_reset(void *opaque)
memset(pci->ptm, 0, sizeof(pci->ptm));
}
/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
* may need further refactoring for other boards. */
/*
* On Bamboo, all pins from each slot are tied to a single board IRQ.
* This may need further refactoring for other boards.
*/
static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
{
int slot = PCI_SLOT(pci_dev->devfn);

View File

@ -25,7 +25,6 @@
#include "elf.h"
#include "exec/memory.h"
#include "ppc440.h"
#include "ppc405.h"
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
#include "sysemu/reset.h"
@ -280,7 +279,6 @@ static void sam460ex_init(MachineState *machine)
hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
DeviceState *uic[4];
qemu_irq mal_irqs[4];
int i;
PCIBus *pci_bus;
PowerPCCPU *cpu;
@ -309,11 +307,12 @@ static void sam460ex_init(MachineState *machine)
ppc_dcr_init(env, NULL, NULL);
/* PLB arbitrer */
ppc4xx_plb_init(env);
dev = qdev_new(TYPE_PPC4xx_PLB);
ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
object_unref(OBJECT(dev));
/* interrupt controllers */
for (i = 0; i < ARRAY_SIZE(uic); i++) {
SysBusDevice *sbd;
/*
* UICs 1, 2 and 3 are cascaded through UIC 0.
* input_ints[n] is the interrupt number on UIC 0 which
@ -325,22 +324,20 @@ static void sam460ex_init(MachineState *machine)
const int input_ints[] = { -1, 30, 10, 16 };
uic[i] = qdev_new(TYPE_PPC_UIC);
sbd = SYS_BUS_DEVICE(uic[i]);
qdev_prop_set_uint32(uic[i], "dcr-base", 0xc0 + i * 0x10);
object_property_set_link(OBJECT(uic[i]), "cpu", OBJECT(cpu),
&error_fatal);
sysbus_realize_and_unref(sbd, &error_fatal);
ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uic[i]), cpu, &error_fatal);
object_unref(OBJECT(uic[i]));
sbdev = SYS_BUS_DEVICE(uic[i]);
if (i == 0) {
sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_INT,
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_CINT,
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
} else {
sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_INT,
qdev_get_gpio_in(uic[0], input_ints[i]));
sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_CINT,
qdev_get_gpio_in(uic[0], input_ints[i] + 1));
}
}
@ -371,7 +368,9 @@ static void sam460ex_init(MachineState *machine)
qdev_get_gpio_in(uic[0], 3));
/* External bus controller */
ppc405_ebc_init(env);
dev = qdev_new(TYPE_PPC4xx_EBC);
ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
object_unref(OBJECT(dev));
/* CPR */
ppc4xx_cpr_init(env);
@ -383,10 +382,15 @@ static void sam460ex_init(MachineState *machine)
ppc4xx_sdr_init(env);
/* MAL */
for (i = 0; i < ARRAY_SIZE(mal_irqs); i++) {
mal_irqs[i] = qdev_get_gpio_in(uic[2], 3 + i);
dev = qdev_new(TYPE_PPC4xx_MAL);
qdev_prop_set_uint32(dev, "txc-num", 4);
qdev_prop_set_uint32(dev, "rxc-num", 16);
ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
object_unref(OBJECT(dev));
sbdev = SYS_BUS_DEVICE(dev);
for (i = 0; i < ARRAY_SIZE(PPC4xx_MAL(dev)->irqs); i++) {
sysbus_connect_irq(sbdev, i, qdev_get_gpio_in(uic[2], 3 + i));
}
ppc4xx_mal_init(env, 4, 16, mal_irqs);
/* DMA */
ppc4xx_dma_init(env, 0x200);

View File

@ -95,6 +95,17 @@ vof_write(uint32_t ih, unsigned cb, const char *msg) "ih=0x%x [%u] \"%s\""
vof_avail(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64
vof_claimed(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64
# pnv_sbe.c
pnv_sbe_xscom_ctrl_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
pnv_sbe_xscom_ctrl_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
pnv_sbe_xscom_mbox_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
pnv_sbe_xscom_mbox_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
pnv_sbe_reg_set_host_doorbell(uint64_t val) "val 0x%" PRIx64
pnv_sbe_cmd_timer_start(uint64_t ns) "ns 0x%" PRIu64
pnv_sbe_cmd_timer_stop(void) ""
pnv_sbe_cmd_timer_expired(void) ""
pnv_sbe_msg_recv(uint16_t cmd, uint16_t seq, uint16_t ctrl_flags) "cmd 0x%" PRIx16 " seq %"PRIu16 " ctrl_flags 0x%" PRIx16
# ppc.c
ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)"
ppc_tb_load(uint64_t tb) "tb 0x%016" PRIx64
@ -150,11 +161,9 @@ ppc440_pcix_reg_write(uint64_t addr, uint32_t val, uint32_t size) "addr 0x%" PRI
# ppc405_boards.c
opba_readb(uint64_t addr, uint32_t val) "addr 0x%" PRIx64 " = 0x%" PRIx32
opba_writeb(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " = 0x%" PRIx64
opba_init(uint64_t addr) "offet 0x%" PRIx64
ppc405_gpio_read(uint64_t addr, uint32_t size) "addr 0x%" PRIx64 " size %d"
ppc405_gpio_write(uint64_t addr, uint32_t size, uint64_t val) "addr 0x%" PRIx64 " size %d = 0x%" PRIx64
ppc405_gpio_init(uint64_t addr) "offet 0x%" PRIx64
ocm_update_mappings(uint32_t isarc, uint32_t isacntl, uint32_t dsarc, uint32_t dsacntl, uint32_t ocm_isarc, uint32_t ocm_isacntl, uint32_t ocm_dsarc, uint32_t ocm_dsacntl) "OCM update ISA 0x%08" PRIx32 " 0x%08" PRIx32 " (0x%08" PRIx32" 0x%08" PRIx32 ") DSA 0x%08" PRIx32 " 0x%08" PRIx32" (0x%08" PRIx32 " 0x%08" PRIx32 ")"
ocm_map(const char* prefix, uint32_t isarc) "OCM map %s 0x%08" PRIx32
@ -162,7 +171,6 @@ ocm_unmap(const char* prefix, uint32_t isarc) "OCM unmap %s 0x%08" PRIx32
ppc4xx_gpt_read(uint64_t addr, uint32_t size) "addr 0x%" PRIx64 " size %d"
ppc4xx_gpt_write(uint64_t addr, uint32_t size, uint64_t val) "addr 0x%" PRIx64 " size %d = 0x%" PRIx64
ppc4xx_gpt_init(uint64_t addr) "offet 0x%" PRIx64
ppc405ep_clocks_compute(const char *param, uint32_t param2, uint32_t val) "%s 0x%1" PRIx32 " %d"
ppc405ep_clocks_setup(const char *trace) "%s"

View File

@ -104,12 +104,9 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
/* interrupt controller */
uicdev = qdev_new(TYPE_PPC_UIC);
ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal);
object_unref(OBJECT(uicdev));
uicsbd = SYS_BUS_DEVICE(uicdev);
object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
&error_fatal);
sysbus_realize_and_unref(uicsbd, &error_fatal);
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,

View File

@ -195,6 +195,10 @@ typedef struct float_status {
bool snan_bit_is_one;
bool use_first_nan;
bool no_signaling_nans;
/* should overflowed results subtract re_bias to its exponent? */
bool rebias_overflow;
/* should underflowed results add re_bias to its exponent? */
bool rebias_underflow;
} float_status;
#endif /* SOFTFLOAT_TYPES_H */

View File

@ -25,8 +25,7 @@
#ifndef HW_INTC_PPC_UIC_H
#define HW_INTC_PPC_UIC_H
#include "hw/sysbus.h"
#include "qom/object.h"
#include "hw/ppc/ppc4xx.h"
#define TYPE_PPC_UIC "ppc-uic"
OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
@ -56,14 +55,13 @@ enum {
struct PPCUIC {
/*< private >*/
SysBusDevice parent_obj;
Ppc4xxDcrDeviceState parent_obj;
/*< public >*/
qemu_irq output_int;
qemu_irq output_cint;
/* properties */
CPUState *cpu;
uint32_t dcr_base;
bool use_vectors;

View File

@ -14,6 +14,7 @@
#include "hw/pci/pcie_port.h"
#include "hw/ppc/xics.h"
#include "qom/object.h"
#include "hw/pci-host/pnv_phb.h"
typedef struct PnvPHB3 PnvPHB3;
typedef struct PnvChip PnvChip;
@ -103,15 +104,16 @@ struct PnvPBCQState {
};
/*
* PHB3 PCIe Root port
* PHB3 PCIe Root Bus
*/
#define TYPE_PNV_PHB3_ROOT_BUS "pnv-phb3-root"
struct PnvPHB3RootBus {
PCIBus parent;
#define TYPE_PNV_PHB3_ROOT_PORT "pnv-phb3-root-port"
typedef struct PnvPHB3RootPort {
PCIESlot parent_obj;
} PnvPHB3RootPort;
uint32_t chip_id;
uint32_t phb_id;
};
OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB3RootBus, PNV_PHB3_ROOT_BUS)
/*
* PHB3 PCIe Host Bridge for PowerNV machines (POWER8)
@ -127,7 +129,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB3, PNV_PHB3)
#define PCI_MMIO_TOTAL_SIZE (0x1ull << 60)
struct PnvPHB3 {
PCIExpressHost parent_obj;
DeviceState parent;
PnvPHB *phb_base;
uint32_t chip_id;
uint32_t phb_id;
@ -164,5 +168,6 @@ uint64_t pnv_phb3_reg_read(void *opaque, hwaddr off, unsigned size);
void pnv_phb3_reg_write(void *opaque, hwaddr off, uint64_t val, unsigned size);
void pnv_phb3_update_regions(PnvPHB3 *phb);
void pnv_phb3_remap_irqs(PnvPHB3 *phb);
void pnv_phb3_bus_init(DeviceState *dev, PnvPHB3 *phb);
#endif /* PCI_HOST_PNV_PHB3_H */

View File

@ -18,6 +18,7 @@
typedef struct PnvPhb4PecState PnvPhb4PecState;
typedef struct PnvPhb4PecStack PnvPhb4PecStack;
typedef struct PnvPHB4 PnvPHB4;
typedef struct PnvPHB PnvPHB;
typedef struct PnvChip PnvChip;
/*
@ -45,15 +46,16 @@ typedef struct PnvPhb4DMASpace {
} PnvPhb4DMASpace;
/*
* PHB4 PCIe Root port
* PHB4 PCIe Root Bus
*/
#define TYPE_PNV_PHB4_ROOT_BUS "pnv-phb4-root"
#define TYPE_PNV_PHB4_ROOT_PORT "pnv-phb4-root-port"
#define TYPE_PNV_PHB5_ROOT_PORT "pnv-phb5-root-port"
struct PnvPHB4RootBus {
PCIBus parent;
typedef struct PnvPHB4RootPort {
PCIESlot parent_obj;
} PnvPHB4RootPort;
uint32_t chip_id;
uint32_t phb_id;
};
OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4RootBus, PNV_PHB4_ROOT_BUS)
/*
* PHB4 PCIe Host Bridge for PowerNV machines (POWER9)
@ -78,13 +80,13 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
#define PCI_MMIO_TOTAL_SIZE (0x1ull << 60)
struct PnvPHB4 {
PCIExpressHost parent_obj;
DeviceState parent;
PnvPHB *phb_base;
uint32_t chip_id;
uint32_t phb_id;
uint64_t version;
/* The owner PEC */
PnvPhb4PecState *pec;
@ -157,6 +159,7 @@ struct PnvPHB4 {
void pnv_phb4_pic_print_info(PnvPHB4 *phb, Monitor *mon);
int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb);
extern const MemoryRegionOps pnv_phb4_xscom_ops;
/*
@ -205,7 +208,6 @@ struct PnvPhb4PecClass {
uint64_t version;
const char *phb_type;
const uint32_t *num_phbs;
const char *rp_model;
};
/*

View File

@ -27,11 +27,13 @@
#include "hw/ppc/pnv_pnor.h"
#include "hw/ppc/pnv_psi.h"
#include "hw/ppc/pnv_occ.h"
#include "hw/ppc/pnv_sbe.h"
#include "hw/ppc/pnv_homer.h"
#include "hw/ppc/pnv_xive.h"
#include "hw/ppc/pnv_core.h"
#include "hw/pci-host/pnv_phb3.h"
#include "hw/pci-host/pnv_phb4.h"
#include "hw/pci-host/pnv_phb.h"
#include "qom/object.h"
#define TYPE_PNV_CHIP "pnv-chip"
@ -80,7 +82,11 @@ struct Pnv8Chip {
PnvHomer homer;
#define PNV8_CHIP_PHB3_MAX 4
PnvPHB3 phbs[PNV8_CHIP_PHB3_MAX];
/*
* The array is used to allow quick access to the phbs by
* pnv_ics_get_child() and pnv_ics_resend_child().
*/
PnvPHB *phbs[PNV8_CHIP_PHB3_MAX];
uint32_t num_phbs;
XICSFabric *xics;
@ -100,6 +106,7 @@ struct Pnv9Chip {
Pnv9Psi psi;
PnvLpcController lpc;
PnvOCC occ;
PnvSBE sbe;
PnvHomer homer;
uint32_t nr_quads;
@ -129,6 +136,7 @@ struct Pnv10Chip {
Pnv9Psi psi;
PnvLpcController lpc;
PnvOCC occ;
PnvSBE sbe;
PnvHomer homer;
uint32_t nr_quads;
@ -189,8 +197,6 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10,
TYPE_PNV_CHIP_POWER10)
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
void pnv_phb_attach_root_port(PCIHostState *pci, const char *name,
int index, int chip_id);
#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv")
typedef struct PnvMachineClass PnvMachineClass;
@ -232,6 +238,7 @@ struct PnvMachineState {
};
PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id);
Object *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
#define PNV_FDT_ADDR 0x01000000
#define PNV_TIMEBASE_FREQ 512000000ULL

55
include/hw/ppc/pnv_sbe.h Normal file
View File

@ -0,0 +1,55 @@
/*
* QEMU PowerPC PowerNV Emulation of some SBE behaviour
*
* Copyright (c) 2022, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PPC_PNV_SBE_H
#define PPC_PNV_SBE_H
#include "qom/object.h"
#define TYPE_PNV_SBE "pnv-sbe"
OBJECT_DECLARE_TYPE(PnvSBE, PnvSBEClass, PNV_SBE)
#define TYPE_PNV9_SBE TYPE_PNV_SBE "-POWER9"
DECLARE_INSTANCE_CHECKER(PnvSBE, PNV9_SBE, TYPE_PNV9_SBE)
#define TYPE_PNV10_SBE TYPE_PNV_SBE "-POWER10"
DECLARE_INSTANCE_CHECKER(PnvSBE, PNV10_SBE, TYPE_PNV10_SBE)
struct PnvSBE {
DeviceState xd;
uint64_t mbox[8];
uint64_t sbe_doorbell;
uint64_t host_doorbell;
qemu_irq psi_irq;
QEMUTimer *timer;
MemoryRegion xscom_mbox_regs;
MemoryRegion xscom_ctrl_regs;
};
struct PnvSBEClass {
DeviceClass parent_class;
int xscom_ctrl_size;
int xscom_mbox_size;
const MemoryRegionOps *xscom_ctrl_ops;
const MemoryRegionOps *xscom_mbox_ops;
};
#endif /* PPC_PNV_SBE_H */

View File

@ -92,6 +92,12 @@ struct PnvXScomInterfaceClass {
#define PNV9_XSCOM_OCC_BASE PNV_XSCOM_OCC_BASE
#define PNV9_XSCOM_OCC_SIZE 0x8000
#define PNV9_XSCOM_SBE_CTRL_BASE 0x00050008
#define PNV9_XSCOM_SBE_CTRL_SIZE 0x1
#define PNV9_XSCOM_SBE_MBOX_BASE 0x000D0050
#define PNV9_XSCOM_SBE_MBOX_SIZE 0x16
#define PNV9_XSCOM_PBA_BASE 0x5012b00
#define PNV9_XSCOM_PBA_SIZE 0x40
@ -134,6 +140,12 @@ struct PnvXScomInterfaceClass {
#define PNV10_XSCOM_OCC_BASE PNV9_XSCOM_OCC_BASE
#define PNV10_XSCOM_OCC_SIZE PNV9_XSCOM_OCC_SIZE
#define PNV10_XSCOM_SBE_CTRL_BASE PNV9_XSCOM_SBE_CTRL_BASE
#define PNV10_XSCOM_SBE_CTRL_SIZE PNV9_XSCOM_SBE_CTRL_SIZE
#define PNV10_XSCOM_SBE_MBOX_BASE PNV9_XSCOM_SBE_MBOX_BASE
#define PNV10_XSCOM_SBE_MBOX_SIZE PNV9_XSCOM_SBE_MBOX_SIZE
#define PNV10_XSCOM_PBA_BASE 0x01010CDA
#define PNV10_XSCOM_PBA_SIZE 0x40

View File

@ -27,11 +27,7 @@
#include "hw/ppc/ppc.h"
#include "exec/memory.h"
/* PowerPC 4xx core initialization */
PowerPCCPU *ppc4xx_init(const char *cpu_model,
clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
uint32_t sysclk);
#include "hw/sysbus.h"
void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
MemoryRegion ram_memories[],
@ -44,9 +40,73 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
hwaddr *ram_sizes,
int do_init);
void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum,
qemu_irq irqs[4]);
#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
/*
* Generic DCR device
*/
#define TYPE_PPC4xx_DCR_DEVICE "ppc4xx-dcr-device"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxDcrDeviceState, PPC4xx_DCR_DEVICE);
struct Ppc4xxDcrDeviceState {
SysBusDevice parent_obj;
PowerPCCPU *cpu;
};
void ppc4xx_dcr_register(Ppc4xxDcrDeviceState *dev, int dcrn, void *opaque,
dcr_read_cb dcr_read, dcr_write_cb dcr_write);
bool ppc4xx_dcr_realize(Ppc4xxDcrDeviceState *dev, PowerPCCPU *cpu,
Error **errp);
/* Memory Access Layer (MAL) */
#define TYPE_PPC4xx_MAL "ppc4xx-mal"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxMalState, PPC4xx_MAL);
struct Ppc4xxMalState {
Ppc4xxDcrDeviceState parent_obj;
qemu_irq irqs[4];
uint32_t cfg;
uint32_t esr;
uint32_t ier;
uint32_t txcasr;
uint32_t txcarr;
uint32_t txeobisr;
uint32_t txdeir;
uint32_t rxcasr;
uint32_t rxcarr;
uint32_t rxeobisr;
uint32_t rxdeir;
uint32_t *txctpr;
uint32_t *rxctpr;
uint32_t *rcbs;
uint8_t txcnum;
uint8_t rxcnum;
};
/* Peripheral local bus arbitrer */
#define TYPE_PPC4xx_PLB "ppc4xx-plb"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxPlbState, PPC4xx_PLB);
struct Ppc4xxPlbState {
Ppc4xxDcrDeviceState parent_obj;
uint32_t acr;
uint32_t bear;
uint32_t besr;
};
/* Peripheral controller */
#define TYPE_PPC4xx_EBC "ppc4xx-ebc"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxEbcState, PPC4xx_EBC);
struct Ppc4xxEbcState {
Ppc4xxDcrDeviceState parent_obj;
uint32_t addr;
uint32_t bcr[8];
uint32_t bap[8];
uint32_t bear;
uint32_t besr0;
uint32_t besr1;
uint32_t cfg;
};
#endif /* PPC4XX_H */

View File

@ -14,7 +14,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
built from git tag qemu-slof-20220110.
built from git tag qemu-slof-20220719.
- VOF (Virtual Open Firmware) is a minimalistic firmware to work with
-machine pseries,x-vof=on. When enabled, the firmware acts as a slim shim and

Binary file not shown.

@ -1 +1 @@
Subproject commit 5b4c5acdcd552a4e1796aeca6bb700f6cbb0282d
Subproject commit 6b6c16b4b40763507cf1f518096f3c3883c5cf2d

View File

@ -158,7 +158,11 @@ struct PowerPCCPUClass {
void (*parent_parse_features)(const char *type, char *str, Error **errp);
uint32_t pvr;
bool (*pvr_match)(struct PowerPCCPUClass *pcc, uint32_t pvr);
/*
* If @best is false, match if pcc is in the family of pvr
* Else match only if pcc is the best match for pvr in this family.
*/
bool (*pvr_match)(struct PowerPCCPUClass *pcc, uint32_t pvr, bool best);
uint64_t pcr_mask; /* Available bits in PCR register */
uint64_t pcr_supported; /* Bits for supported PowerISA versions */
uint32_t svr;

View File

@ -120,6 +120,8 @@ void ppc_store_fpscr(CPUPPCState *env, target_ulong val)
val |= FP_FEX;
}
env->fpscr = val;
env->fp_status.rebias_overflow = (FP_OE & env->fpscr) ? true : false;
env->fp_status.rebias_underflow = (FP_UE & env->fpscr) ? true : false;
if (tcg_enabled()) {
fpscr_set_rounding_mode(env);
}

View File

@ -5912,15 +5912,25 @@ static void init_proc_POWER7(CPUPPCState *env)
ppcPOWER7_irq_init(env_archcpu(env));
}
static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr)
static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
{
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7P_BASE) {
return true;
uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK;
uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK;
if (!best) {
if (base == CPU_POWERPC_POWER7_BASE) {
return true;
}
if (base == CPU_POWERPC_POWER7P_BASE) {
return true;
}
}
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7_BASE) {
return true;
if (base != pcc_base) {
return false;
}
return false;
return true;
}
static bool cpu_has_work_POWER7(CPUState *cs)
@ -6073,18 +6083,27 @@ static void init_proc_POWER8(CPUPPCState *env)
ppcPOWER7_irq_init(env_archcpu(env));
}
static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)
static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
{
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8NVL_BASE) {
return true;
uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK;
uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK;
if (!best) {
if (base == CPU_POWERPC_POWER8_BASE) {
return true;
}
if (base == CPU_POWERPC_POWER8E_BASE) {
return true;
}
if (base == CPU_POWERPC_POWER8NVL_BASE) {
return true;
}
}
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8E_BASE) {
return true;
if (base != pcc_base) {
return false;
}
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8_BASE) {
return true;
}
return false;
return true;
}
static bool cpu_has_work_POWER8(CPUState *cs)
@ -6282,11 +6301,26 @@ static void init_proc_POWER9(CPUPPCState *env)
ppcPOWER9_irq_init(env_archcpu(env));
}
static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr)
static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
{
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER9_BASE) {
uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK;
uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK;
if (!best) {
if (base == CPU_POWERPC_POWER9_BASE) {
return true;
}
}
if (base != pcc_base) {
return false;
}
if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) {
/* Major DD version matches to power9_v1.0 and power9_v2.0 */
return true;
}
return false;
}
@ -6499,11 +6533,26 @@ static void init_proc_POWER10(CPUPPCState *env)
ppcPOWER9_irq_init(env_archcpu(env));
}
static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr)
static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
{
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER10_BASE) {
uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK;
uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK;
if (!best) {
if (base == CPU_POWERPC_POWER10_BASE) {
return true;
}
}
if (base != pcc_base) {
return false;
}
if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) {
/* Major DD version matches to power10_v1.0 and power10_v2.0 */
return true;
}
return false;
}
@ -6910,7 +6959,7 @@ static gint ppc_cpu_compare_class_pvr_mask(gconstpointer a, gconstpointer b)
return -1;
}
if (pcc->pvr_match(pcc, pvr)) {
if (pcc->pvr_match(pcc, pvr, true)) {
return 0;
}
@ -7308,7 +7357,7 @@ static void ppc_cpu_instance_finalize(Object *obj)
ppc_hash64_finalize(cpu);
}
static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr)
static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
{
return pcc->pvr == pvr;
}

View File

@ -348,7 +348,6 @@ static inline int float_overflow_excp(CPUPPCState *env)
bool overflow_enabled = !!(env->fpscr & FP_OE);
if (overflow_enabled) {
/* XXX: should adjust the result */
/* Update the floating-point enabled exception summary */
env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */
@ -367,7 +366,6 @@ static inline void float_underflow_excp(CPUPPCState *env)
/* Update the floating-point exception summary */
env->fpscr |= FP_FX;
if (env->fpscr & FP_UE) {
/* XXX: should adjust the result */
/* Update the floating-point enabled exception summary */
env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */

View File

@ -234,7 +234,7 @@ static bool pvr_match(PowerPCCPU *cpu, uint32_t pvr)
if (pvr == pcc->pvr) {
return true;
}
return pcc->pvr_match(pcc, pvr);
return pcc->pvr_match(pcc, pvr, true);
}
static int cpu_post_load(void *opaque, int version_id)