2016-10-22 11:46:35 +02:00
|
|
|
/*
|
|
|
|
* QEMU PowerPC PowerNV machine model
|
|
|
|
*
|
|
|
|
* Copyright (c) 2016, 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 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "qemu/osdep.h"
|
2019-05-23 16:35:08 +02:00
|
|
|
#include "qemu-common.h"
|
2018-06-25 14:41:58 +02:00
|
|
|
#include "qemu/units.h"
|
2016-10-22 11:46:35 +02:00
|
|
|
#include "qapi/error.h"
|
|
|
|
#include "sysemu/sysemu.h"
|
|
|
|
#include "sysemu/numa.h"
|
2019-08-12 07:23:38 +02:00
|
|
|
#include "sysemu/reset.h"
|
2019-08-12 07:23:59 +02:00
|
|
|
#include "sysemu/runstate.h"
|
2017-03-03 12:01:16 +01:00
|
|
|
#include "sysemu/cpus.h"
|
2019-06-06 19:47:32 +02:00
|
|
|
#include "sysemu/device_tree.h"
|
2016-10-11 08:56:52 +02:00
|
|
|
#include "target/ppc/cpu.h"
|
2016-10-22 11:46:35 +02:00
|
|
|
#include "qemu/log.h"
|
|
|
|
#include "hw/ppc/fdt.h"
|
|
|
|
#include "hw/ppc/ppc.h"
|
|
|
|
#include "hw/ppc/pnv.h"
|
2016-10-22 11:46:39 +02:00
|
|
|
#include "hw/ppc/pnv_core.h"
|
2016-10-22 11:46:35 +02:00
|
|
|
#include "hw/loader.h"
|
|
|
|
#include "exec/address-spaces.h"
|
2016-10-22 11:46:36 +02:00
|
|
|
#include "qapi/visitor.h"
|
2017-04-03 09:46:02 +02:00
|
|
|
#include "monitor/monitor.h"
|
|
|
|
#include "hw/intc/intc.h"
|
2017-04-11 17:30:05 +02:00
|
|
|
#include "hw/ipmi/ipmi.h"
|
2018-03-23 04:11:07 +01:00
|
|
|
#include "target/ppc/mmu-hash64.h"
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
#include "hw/pci/msi.h"
|
2016-10-22 11:46:35 +02:00
|
|
|
|
2017-04-03 09:46:01 +02:00
|
|
|
#include "hw/ppc/xics.h"
|
2019-08-12 07:23:51 +02:00
|
|
|
#include "hw/qdev-properties.h"
|
ppc/pnv: add XSCOM infrastructure
On a real POWER8 system, the Pervasive Interconnect Bus (PIB) serves
as a backbone to connect different units of the system. The host
firmware connects to the PIB through a bridge unit, the
Alter-Display-Unit (ADU), which gives him access to all the chiplets
on the PCB network (Pervasive Connect Bus), the PIB acting as the root
of this network.
XSCOM (serial communication) is the interface to the sideband bus
provided by the POWER8 pervasive unit to read and write to chiplets
resources. This is needed by the host firmware, OPAL and to a lesser
extent, Linux. This is among others how the PCI Host bridges get
configured at boot or how the LPC bus is accessed.
To represent the ADU of a real system, we introduce a specific
AddressSpace to dispatch XSCOM accesses to the targeted chiplets. The
translation of an XSCOM address into a PCB register address is
slightly different between the P9 and the P8. This is handled before
the dispatch using a 8byte alignment for all.
To customize the device tree, a QOM InterfaceClass, PnvXScomInterface,
is provided with a populate() handler. The chip populates the device
tree by simply looping on its children. Therefore, each model needing
custom nodes should not forget to declare itself as a child at
instantiation time.
Based on previous work done by :
Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
[dwg: Added cpu parameter to xscom_complete()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2016-10-22 11:46:40 +02:00
|
|
|
#include "hw/ppc/pnv_xscom.h"
|
2019-10-21 15:12:11 +02:00
|
|
|
#include "hw/ppc/pnv_pnor.h"
|
ppc/pnv: add XSCOM infrastructure
On a real POWER8 system, the Pervasive Interconnect Bus (PIB) serves
as a backbone to connect different units of the system. The host
firmware connects to the PIB through a bridge unit, the
Alter-Display-Unit (ADU), which gives him access to all the chiplets
on the PCB network (Pervasive Connect Bus), the PIB acting as the root
of this network.
XSCOM (serial communication) is the interface to the sideband bus
provided by the POWER8 pervasive unit to read and write to chiplets
resources. This is needed by the host firmware, OPAL and to a lesser
extent, Linux. This is among others how the PCI Host bridges get
configured at boot or how the LPC bus is accessed.
To represent the ADU of a real system, we introduce a specific
AddressSpace to dispatch XSCOM accesses to the targeted chiplets. The
translation of an XSCOM address into a PCB register address is
slightly different between the P9 and the P8. This is handled before
the dispatch using a 8byte alignment for all.
To customize the device tree, a QOM InterfaceClass, PnvXScomInterface,
is provided with a populate() handler. The chip populates the device
tree by simply looping on its children. Therefore, each model needing
custom nodes should not forget to declare itself as a child at
instantiation time.
Based on previous work done by :
Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
[dwg: Added cpu parameter to xscom_complete()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2016-10-22 11:46:40 +02:00
|
|
|
|
2016-10-22 11:46:43 +02:00
|
|
|
#include "hw/isa/isa.h"
|
2019-08-12 07:23:52 +02:00
|
|
|
#include "hw/boards.h"
|
2016-10-22 11:46:43 +02:00
|
|
|
#include "hw/char/serial.h"
|
2019-10-04 01:03:53 +02:00
|
|
|
#include "hw/rtc/mc146818rtc.h"
|
2016-10-22 11:46:43 +02:00
|
|
|
|
2016-10-22 11:46:35 +02:00
|
|
|
#include <libfdt.h>
|
|
|
|
|
2019-02-25 18:01:55 +01:00
|
|
|
#define FDT_MAX_SIZE (1 * MiB)
|
2016-10-22 11:46:35 +02:00
|
|
|
|
|
|
|
#define FW_FILE_NAME "skiboot.lid"
|
|
|
|
#define FW_LOAD_ADDR 0x0
|
2019-02-25 18:01:55 +01:00
|
|
|
#define FW_MAX_SIZE (4 * MiB)
|
2016-10-22 11:46:35 +02:00
|
|
|
|
|
|
|
#define KERNEL_LOAD_ADDR 0x20000000
|
2019-02-25 18:01:53 +01:00
|
|
|
#define KERNEL_MAX_SIZE (256 * MiB)
|
2018-01-15 19:04:05 +01:00
|
|
|
#define INITRD_LOAD_ADDR 0x60000000
|
2019-02-25 18:01:54 +01:00
|
|
|
#define INITRD_MAX_SIZE (256 * MiB)
|
2016-10-22 11:46:35 +02:00
|
|
|
|
2017-10-09 21:51:10 +02:00
|
|
|
static const char *pnv_chip_core_typename(const PnvChip *o)
|
|
|
|
{
|
|
|
|
const char *chip_type = object_class_get_name(object_get_class(OBJECT(o)));
|
|
|
|
int len = strlen(chip_type) - strlen(PNV_CHIP_TYPE_SUFFIX);
|
|
|
|
char *s = g_strdup_printf(PNV_CORE_TYPE_NAME("%.*s"), len, chip_type);
|
|
|
|
const char *core_type = object_class_get_name(object_class_by_name(s));
|
|
|
|
g_free(s);
|
|
|
|
return core_type;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:35 +02:00
|
|
|
/*
|
|
|
|
* On Power Systems E880 (POWER8), the max cpus (threads) should be :
|
|
|
|
* 4 * 4 sockets * 12 cores * 8 threads = 1536
|
|
|
|
* Let's make it 2^11
|
|
|
|
*/
|
|
|
|
#define MAX_CPUS 2048
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Memory nodes are created by hostboot, one for each range of memory
|
|
|
|
* that has a different "affinity". In practice, it means one range
|
|
|
|
* per chip.
|
|
|
|
*/
|
2017-12-15 14:56:01 +01:00
|
|
|
static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
|
2016-10-22 11:46:35 +02:00
|
|
|
{
|
|
|
|
char *mem_name;
|
|
|
|
uint64_t mem_reg_property[2];
|
|
|
|
int off;
|
|
|
|
|
|
|
|
mem_reg_property[0] = cpu_to_be64(start);
|
|
|
|
mem_reg_property[1] = cpu_to_be64(size);
|
|
|
|
|
|
|
|
mem_name = g_strdup_printf("memory@%"HWADDR_PRIx, start);
|
|
|
|
off = fdt_add_subnode(fdt, 0, mem_name);
|
|
|
|
g_free(mem_name);
|
|
|
|
|
|
|
|
_FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
|
|
|
|
_FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
|
|
|
|
sizeof(mem_reg_property))));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, off, "ibm,chip-id", chip_id)));
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:39 +02:00
|
|
|
static int get_cpus_node(void *fdt)
|
|
|
|
{
|
|
|
|
int cpus_offset = fdt_path_offset(fdt, "/cpus");
|
|
|
|
|
|
|
|
if (cpus_offset < 0) {
|
2017-10-03 16:13:11 +02:00
|
|
|
cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
|
2016-10-22 11:46:39 +02:00
|
|
|
if (cpus_offset) {
|
|
|
|
_FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_FDT(cpus_offset);
|
|
|
|
return cpus_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The PowerNV cores (and threads) need to use real HW ids and not an
|
|
|
|
* incremental index like it has been done on other platforms. This HW
|
|
|
|
* id is stored in the CPU PIR, it is used to create cpu nodes in the
|
|
|
|
* device tree, used in XSCOM to address cores and in interrupt
|
|
|
|
* servers.
|
|
|
|
*/
|
2017-12-15 14:56:01 +01:00
|
|
|
static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
|
2016-10-22 11:46:39 +02:00
|
|
|
{
|
2018-06-13 03:57:37 +02:00
|
|
|
PowerPCCPU *cpu = pc->threads[0];
|
|
|
|
CPUState *cs = CPU(cpu);
|
2016-10-22 11:46:39 +02:00
|
|
|
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
2016-11-01 00:25:29 +01:00
|
|
|
int smt_threads = CPU_CORE(pc)->nr_threads;
|
2016-10-22 11:46:39 +02:00
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
|
|
|
uint32_t servers_prop[smt_threads];
|
|
|
|
int i;
|
|
|
|
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
|
|
|
0xffffffff, 0xffffffff};
|
|
|
|
uint32_t tbfreq = PNV_TIMEBASE_FREQ;
|
|
|
|
uint32_t cpufreq = 1000000000;
|
|
|
|
uint32_t page_sizes_prop[64];
|
|
|
|
size_t page_sizes_prop_size;
|
|
|
|
const uint8_t pa_features[] = { 24, 0,
|
|
|
|
0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xf0,
|
|
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
|
|
|
|
0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
|
|
|
|
int offset;
|
|
|
|
char *nodename;
|
|
|
|
int cpus_offset = get_cpus_node(fdt);
|
|
|
|
|
|
|
|
nodename = g_strdup_printf("%s@%x", dc->fw_name, pc->pir);
|
|
|
|
offset = fdt_add_subnode(fdt, cpus_offset, nodename);
|
|
|
|
_FDT(offset);
|
|
|
|
g_free(nodename);
|
|
|
|
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", chip->chip_id)));
|
|
|
|
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "reg", pc->pir)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,pir", pc->pir)));
|
|
|
|
_FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
|
|
|
|
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
|
|
|
|
env->dcache_line_size)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
|
|
|
|
env->dcache_line_size)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
|
|
|
|
env->icache_line_size)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
|
|
|
|
env->icache_line_size)));
|
|
|
|
|
|
|
|
if (pcc->l1_dcache_size) {
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
|
|
|
|
pcc->l1_dcache_size)));
|
|
|
|
} else {
|
2017-07-12 15:57:41 +02:00
|
|
|
warn_report("Unknown L1 dcache size for cpu");
|
2016-10-22 11:46:39 +02:00
|
|
|
}
|
|
|
|
if (pcc->l1_icache_size) {
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
|
|
|
|
pcc->l1_icache_size)));
|
|
|
|
} else {
|
2017-07-12 15:57:41 +02:00
|
|
|
warn_report("Unknown L1 icache size for cpu");
|
2016-10-22 11:46:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
|
2019-09-11 16:29:25 +02:00
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size",
|
|
|
|
cpu->hash64_opts->slb_size)));
|
2016-10-22 11:46:39 +02:00
|
|
|
_FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
|
|
|
|
|
|
|
|
if (env->spr_cb[SPR_PURR].oea_read) {
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
|
|
|
|
}
|
|
|
|
|
2018-03-23 04:11:07 +01:00
|
|
|
if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
|
2016-10-22 11:46:39 +02:00
|
|
|
_FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
|
|
|
|
segs, sizeof(segs))));
|
|
|
|
}
|
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* Advertise VMX/VSX (vector extensions) if available
|
2016-10-22 11:46:39 +02:00
|
|
|
* 0 / no property == no vector extensions
|
|
|
|
* 1 == VMX / Altivec available
|
2019-09-11 16:29:25 +02:00
|
|
|
* 2 == VSX available
|
|
|
|
*/
|
2016-10-22 11:46:39 +02:00
|
|
|
if (env->insns_flags & PPC_ALTIVEC) {
|
|
|
|
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
|
|
|
|
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
|
|
|
|
}
|
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* Advertise DFP (Decimal Floating Point) if available
|
2016-10-22 11:46:39 +02:00
|
|
|
* 0 / no property == no DFP
|
2019-09-11 16:29:25 +02:00
|
|
|
* 1 == DFP available
|
|
|
|
*/
|
2016-10-22 11:46:39 +02:00
|
|
|
if (env->insns_flags2 & PPC2_DFP) {
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
|
|
|
|
}
|
|
|
|
|
2018-03-22 06:18:40 +01:00
|
|
|
page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
|
|
|
|
sizeof(page_sizes_prop));
|
2016-10-22 11:46:39 +02:00
|
|
|
if (page_sizes_prop_size) {
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
|
|
|
|
page_sizes_prop, page_sizes_prop_size)));
|
|
|
|
}
|
|
|
|
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
|
|
|
pa_features, sizeof(pa_features))));
|
|
|
|
|
|
|
|
/* Build interrupt servers properties */
|
|
|
|
for (i = 0; i < smt_threads; i++) {
|
|
|
|
servers_prop[i] = cpu_to_be32(pc->pir + i);
|
|
|
|
}
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
|
|
|
|
servers_prop, sizeof(servers_prop))));
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
|
|
|
|
uint32_t nr_threads)
|
2017-04-03 09:46:05 +02:00
|
|
|
{
|
|
|
|
uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
|
|
|
|
char *name;
|
|
|
|
const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
|
|
|
|
uint32_t irange[2], i, rsize;
|
|
|
|
uint64_t *reg;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
irange[0] = cpu_to_be32(pir);
|
|
|
|
irange[1] = cpu_to_be32(nr_threads);
|
|
|
|
|
|
|
|
rsize = sizeof(uint64_t) * 2 * nr_threads;
|
|
|
|
reg = g_malloc(rsize);
|
|
|
|
for (i = 0; i < nr_threads; i++) {
|
|
|
|
reg[i * 2] = cpu_to_be64(addr | ((pir + i) * 0x1000));
|
|
|
|
reg[i * 2 + 1] = cpu_to_be64(0x1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
name = g_strdup_printf("interrupt-controller@%"PRIX64, addr);
|
|
|
|
offset = fdt_add_subnode(fdt, 0, name);
|
|
|
|
_FDT(offset);
|
|
|
|
g_free(name);
|
|
|
|
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "compatible", compat, sizeof(compat))));
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "reg", reg, rsize)));
|
|
|
|
_FDT((fdt_setprop_string(fdt, offset, "device_type",
|
|
|
|
"PowerPC-External-Interrupt-Presentation")));
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "interrupt-controller", NULL, 0)));
|
|
|
|
_FDT((fdt_setprop(fdt, offset, "ibm,interrupt-server-ranges",
|
|
|
|
irange, sizeof(irange))));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "#interrupt-cells", 1)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0)));
|
|
|
|
g_free(reg);
|
|
|
|
}
|
|
|
|
|
2019-03-06 09:50:12 +01:00
|
|
|
static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
|
2016-10-22 11:46:36 +02:00
|
|
|
{
|
2019-12-13 13:00:24 +01:00
|
|
|
static const char compat[] = "ibm,power8-xscom\0ibm,xscom";
|
2016-10-22 11:46:39 +02:00
|
|
|
int i;
|
|
|
|
|
2019-12-13 13:00:18 +01:00
|
|
|
pnv_dt_xscom(chip, fdt, 0,
|
|
|
|
cpu_to_be64(PNV_XSCOM_BASE(chip)),
|
2019-12-13 13:00:24 +01:00
|
|
|
cpu_to_be64(PNV_XSCOM_SIZE),
|
|
|
|
compat, sizeof(compat));
|
ppc/pnv: add XSCOM infrastructure
On a real POWER8 system, the Pervasive Interconnect Bus (PIB) serves
as a backbone to connect different units of the system. The host
firmware connects to the PIB through a bridge unit, the
Alter-Display-Unit (ADU), which gives him access to all the chiplets
on the PCB network (Pervasive Connect Bus), the PIB acting as the root
of this network.
XSCOM (serial communication) is the interface to the sideband bus
provided by the POWER8 pervasive unit to read and write to chiplets
resources. This is needed by the host firmware, OPAL and to a lesser
extent, Linux. This is among others how the PCI Host bridges get
configured at boot or how the LPC bus is accessed.
To represent the ADU of a real system, we introduce a specific
AddressSpace to dispatch XSCOM accesses to the targeted chiplets. The
translation of an XSCOM address into a PCB register address is
slightly different between the P9 and the P8. This is handled before
the dispatch using a 8byte alignment for all.
To customize the device tree, a QOM InterfaceClass, PnvXScomInterface,
is provided with a populate() handler. The chip populates the device
tree by simply looping on its children. Therefore, each model needing
custom nodes should not forget to declare itself as a child at
instantiation time.
Based on previous work done by :
Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
[dwg: Added cpu parameter to xscom_complete()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2016-10-22 11:46:40 +02:00
|
|
|
|
2016-10-22 11:46:39 +02:00
|
|
|
for (i = 0; i < chip->nr_cores; i++) {
|
2019-11-25 07:58:03 +01:00
|
|
|
PnvCore *pnv_core = chip->cores[i];
|
2016-10-22 11:46:39 +02:00
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
pnv_dt_core(chip, pnv_core, fdt);
|
2017-04-03 09:46:05 +02:00
|
|
|
|
|
|
|
/* Interrupt Control Presenters (ICP). One per core. */
|
2017-12-15 14:56:01 +01:00
|
|
|
pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
|
2016-10-22 11:46:39 +02:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:36 +02:00
|
|
|
if (chip->ram_size) {
|
2017-12-15 14:56:01 +01:00
|
|
|
pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-06 09:50:12 +01:00
|
|
|
static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
|
|
|
|
{
|
2019-12-13 13:00:24 +01:00
|
|
|
static const char compat[] = "ibm,power9-xscom\0ibm,xscom";
|
2019-03-06 09:50:12 +01:00
|
|
|
int i;
|
|
|
|
|
2019-12-13 13:00:18 +01:00
|
|
|
pnv_dt_xscom(chip, fdt, 0,
|
|
|
|
cpu_to_be64(PNV9_XSCOM_BASE(chip)),
|
2019-12-13 13:00:24 +01:00
|
|
|
cpu_to_be64(PNV9_XSCOM_SIZE),
|
|
|
|
compat, sizeof(compat));
|
2019-03-06 09:50:12 +01:00
|
|
|
|
|
|
|
for (i = 0; i < chip->nr_cores; i++) {
|
2019-11-25 07:58:03 +01:00
|
|
|
PnvCore *pnv_core = chip->cores[i];
|
2019-03-06 09:50:12 +01:00
|
|
|
|
|
|
|
pnv_dt_core(chip, pnv_core, fdt);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chip->ram_size) {
|
|
|
|
pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
|
|
|
|
}
|
2019-03-07 23:35:39 +01:00
|
|
|
|
2019-12-05 19:44:54 +01:00
|
|
|
pnv_dt_lpc(chip, fdt, 0, PNV9_LPCM_BASE(chip), PNV9_LPCM_SIZE);
|
2019-03-06 09:50:12 +01:00
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
|
|
|
|
{
|
2019-12-13 13:00:24 +01:00
|
|
|
static const char compat[] = "ibm,power10-xscom\0ibm,xscom";
|
2019-12-05 19:44:51 +01:00
|
|
|
int i;
|
|
|
|
|
2019-12-13 13:00:18 +01:00
|
|
|
pnv_dt_xscom(chip, fdt, 0,
|
|
|
|
cpu_to_be64(PNV10_XSCOM_BASE(chip)),
|
2019-12-13 13:00:24 +01:00
|
|
|
cpu_to_be64(PNV10_XSCOM_SIZE),
|
|
|
|
compat, sizeof(compat));
|
2019-12-05 19:44:51 +01:00
|
|
|
|
|
|
|
for (i = 0; i < chip->nr_cores; i++) {
|
|
|
|
PnvCore *pnv_core = chip->cores[i];
|
|
|
|
|
|
|
|
pnv_dt_core(chip, pnv_core, fdt);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chip->ram_size) {
|
|
|
|
pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
|
|
|
|
}
|
2019-12-05 19:44:54 +01:00
|
|
|
|
|
|
|
pnv_dt_lpc(chip, fdt, 0, PNV10_LPCM_BASE(chip), PNV10_LPCM_SIZE);
|
2019-12-05 19:44:51 +01:00
|
|
|
}
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
|
2017-04-11 17:30:02 +02:00
|
|
|
{
|
|
|
|
uint32_t io_base = d->ioport_id;
|
|
|
|
uint32_t io_regs[] = {
|
|
|
|
cpu_to_be32(1),
|
|
|
|
cpu_to_be32(io_base),
|
|
|
|
cpu_to_be32(2)
|
|
|
|
};
|
|
|
|
char *name;
|
|
|
|
int node;
|
|
|
|
|
|
|
|
name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
|
|
|
|
node = fdt_add_subnode(fdt, lpc_off, name);
|
|
|
|
_FDT(node);
|
|
|
|
g_free(name);
|
|
|
|
|
|
|
|
_FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
|
|
|
|
_FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
|
2017-04-11 17:30:03 +02:00
|
|
|
{
|
|
|
|
const char compatible[] = "ns16550\0pnpPNP,501";
|
|
|
|
uint32_t io_base = d->ioport_id;
|
|
|
|
uint32_t io_regs[] = {
|
|
|
|
cpu_to_be32(1),
|
|
|
|
cpu_to_be32(io_base),
|
|
|
|
cpu_to_be32(8)
|
|
|
|
};
|
|
|
|
char *name;
|
|
|
|
int node;
|
|
|
|
|
|
|
|
name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
|
|
|
|
node = fdt_add_subnode(fdt, lpc_off, name);
|
|
|
|
_FDT(node);
|
|
|
|
g_free(name);
|
|
|
|
|
|
|
|
_FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
|
|
|
|
_FDT((fdt_setprop(fdt, node, "compatible", compatible,
|
|
|
|
sizeof(compatible))));
|
|
|
|
|
|
|
|
_FDT((fdt_setprop_cell(fdt, node, "clock-frequency", 1843200)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, node, "current-speed", 115200)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, node, "interrupts", d->isairq[0])));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
|
|
|
|
fdt_get_phandle(fdt, lpc_off))));
|
|
|
|
|
|
|
|
/* This is needed by Linux */
|
|
|
|
_FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
|
2017-04-11 17:30:04 +02:00
|
|
|
{
|
|
|
|
const char compatible[] = "bt\0ipmi-bt";
|
|
|
|
uint32_t io_base;
|
|
|
|
uint32_t io_regs[] = {
|
|
|
|
cpu_to_be32(1),
|
|
|
|
0, /* 'io_base' retrieved from the 'ioport' property of 'isa-ipmi-bt' */
|
|
|
|
cpu_to_be32(3)
|
|
|
|
};
|
|
|
|
uint32_t irq;
|
|
|
|
char *name;
|
|
|
|
int node;
|
|
|
|
|
|
|
|
io_base = object_property_get_int(OBJECT(d), "ioport", &error_fatal);
|
|
|
|
io_regs[1] = cpu_to_be32(io_base);
|
|
|
|
|
|
|
|
irq = object_property_get_int(OBJECT(d), "irq", &error_fatal);
|
|
|
|
|
|
|
|
name = g_strdup_printf("%s@i%x", qdev_fw_name(DEVICE(d)), io_base);
|
|
|
|
node = fdt_add_subnode(fdt, lpc_off, name);
|
|
|
|
_FDT(node);
|
|
|
|
g_free(name);
|
|
|
|
|
2017-06-05 17:44:21 +02:00
|
|
|
_FDT((fdt_setprop(fdt, node, "reg", io_regs, sizeof(io_regs))));
|
|
|
|
_FDT((fdt_setprop(fdt, node, "compatible", compatible,
|
|
|
|
sizeof(compatible))));
|
2017-04-11 17:30:04 +02:00
|
|
|
|
|
|
|
/* Mark it as reserved to avoid Linux trying to claim it */
|
|
|
|
_FDT((fdt_setprop_string(fdt, node, "status", "reserved")));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, node, "interrupts", irq)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, node, "interrupt-parent",
|
|
|
|
fdt_get_phandle(fdt, lpc_off))));
|
|
|
|
}
|
|
|
|
|
2017-04-11 17:30:01 +02:00
|
|
|
typedef struct ForeachPopulateArgs {
|
|
|
|
void *fdt;
|
|
|
|
int offset;
|
|
|
|
} ForeachPopulateArgs;
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
|
2017-04-11 17:30:01 +02:00
|
|
|
{
|
2017-04-11 17:30:02 +02:00
|
|
|
ForeachPopulateArgs *args = opaque;
|
|
|
|
ISADevice *d = ISA_DEVICE(dev);
|
|
|
|
|
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
|
2017-12-15 14:56:01 +01:00
|
|
|
pnv_dt_rtc(d, args->fdt, args->offset);
|
2017-04-11 17:30:03 +02:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
|
2017-12-15 14:56:01 +01:00
|
|
|
pnv_dt_serial(d, args->fdt, args->offset);
|
2017-04-11 17:30:04 +02:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
|
2017-12-15 14:56:01 +01:00
|
|
|
pnv_dt_ipmi_bt(d, args->fdt, args->offset);
|
2017-04-11 17:30:02 +02:00
|
|
|
} else {
|
|
|
|
error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
|
|
|
|
d->ioport_id);
|
|
|
|
}
|
|
|
|
|
2017-04-11 17:30:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* The default LPC bus of a multichip system is on chip 0. It's
|
2018-06-18 19:05:40 +02:00
|
|
|
* recognized by the firmware (skiboot) using a "primary" property.
|
|
|
|
*/
|
|
|
|
static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
|
|
|
|
{
|
2019-03-07 23:35:38 +01:00
|
|
|
int isa_offset = fdt_path_offset(fdt, pnv->chips[0]->dt_isa_nodename);
|
2017-04-11 17:30:01 +02:00
|
|
|
ForeachPopulateArgs args = {
|
|
|
|
.fdt = fdt,
|
2018-06-18 19:05:40 +02:00
|
|
|
.offset = isa_offset,
|
2017-04-11 17:30:01 +02:00
|
|
|
};
|
2019-07-23 11:01:38 +02:00
|
|
|
uint32_t phandle;
|
2017-04-11 17:30:01 +02:00
|
|
|
|
2018-06-18 19:05:40 +02:00
|
|
|
_FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
|
|
|
|
|
2019-07-23 11:01:38 +02:00
|
|
|
phandle = qemu_fdt_alloc_phandle(fdt);
|
|
|
|
assert(phandle > 0);
|
|
|
|
_FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle)));
|
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* ISA devices are not necessarily parented to the ISA bus so we
|
|
|
|
* can not use object_child_foreach()
|
|
|
|
*/
|
2018-06-18 19:05:40 +02:00
|
|
|
qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
|
|
|
|
&args);
|
2017-04-11 17:30:01 +02:00
|
|
|
}
|
|
|
|
|
2019-12-13 12:59:56 +01:00
|
|
|
static void pnv_dt_power_mgt(PnvMachineState *pnv, void *fdt)
|
2019-03-07 23:35:47 +01:00
|
|
|
{
|
|
|
|
int off;
|
|
|
|
|
|
|
|
off = fdt_add_subnode(fdt, 0, "ibm,opal");
|
|
|
|
off = fdt_add_subnode(fdt, off, "power-mgt");
|
|
|
|
|
|
|
|
_FDT(fdt_setprop_cell(fdt, off, "ibm,enabled-stop-levels", 0xc0000000));
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
static void *pnv_dt_create(MachineState *machine)
|
2016-10-22 11:46:35 +02:00
|
|
|
{
|
2019-12-13 12:59:50 +01:00
|
|
|
PnvMachineClass *pmc = PNV_MACHINE_GET_CLASS(machine);
|
2017-12-15 14:56:01 +01:00
|
|
|
PnvMachineState *pnv = PNV_MACHINE(machine);
|
2016-10-22 11:46:35 +02:00
|
|
|
void *fdt;
|
|
|
|
char *buf;
|
|
|
|
int off;
|
2016-10-22 11:46:36 +02:00
|
|
|
int i;
|
2016-10-22 11:46:35 +02:00
|
|
|
|
|
|
|
fdt = g_malloc0(FDT_MAX_SIZE);
|
|
|
|
_FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
|
|
|
|
|
2019-11-06 15:21:29 +01:00
|
|
|
/* /qemu node */
|
|
|
|
_FDT((fdt_add_subnode(fdt, 0, "qemu")));
|
|
|
|
|
2016-10-22 11:46:35 +02:00
|
|
|
/* Root node */
|
|
|
|
_FDT((fdt_setprop_cell(fdt, 0, "#address-cells", 0x2)));
|
|
|
|
_FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
|
|
|
|
_FDT((fdt_setprop_string(fdt, 0, "model",
|
|
|
|
"IBM PowerNV (emulated by qemu)")));
|
2019-12-13 12:59:50 +01:00
|
|
|
_FDT((fdt_setprop(fdt, 0, "compatible", pmc->compat, pmc->compat_size)));
|
2016-10-22 11:46:35 +02:00
|
|
|
|
|
|
|
buf = qemu_uuid_unparse_strdup(&qemu_uuid);
|
|
|
|
_FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
|
|
|
|
if (qemu_uuid_set) {
|
|
|
|
_FDT((fdt_property_string(fdt, "system-id", buf)));
|
|
|
|
}
|
|
|
|
g_free(buf);
|
|
|
|
|
|
|
|
off = fdt_add_subnode(fdt, 0, "chosen");
|
|
|
|
if (machine->kernel_cmdline) {
|
|
|
|
_FDT((fdt_setprop_string(fdt, off, "bootargs",
|
|
|
|
machine->kernel_cmdline)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pnv->initrd_size) {
|
|
|
|
uint32_t start_prop = cpu_to_be32(pnv->initrd_base);
|
|
|
|
uint32_t end_prop = cpu_to_be32(pnv->initrd_base + pnv->initrd_size);
|
|
|
|
|
|
|
|
_FDT((fdt_setprop(fdt, off, "linux,initrd-start",
|
|
|
|
&start_prop, sizeof(start_prop))));
|
|
|
|
_FDT((fdt_setprop(fdt, off, "linux,initrd-end",
|
|
|
|
&end_prop, sizeof(end_prop))));
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:36 +02:00
|
|
|
/* Populate device tree for each chip */
|
|
|
|
for (i = 0; i < pnv->num_chips; i++) {
|
2019-03-06 09:50:12 +01:00
|
|
|
PNV_CHIP_GET_CLASS(pnv->chips[i])->dt_populate(pnv->chips[i], fdt);
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
2017-04-11 17:30:01 +02:00
|
|
|
|
|
|
|
/* Populate ISA devices on chip 0 */
|
2018-06-18 19:05:40 +02:00
|
|
|
pnv_dt_isa(pnv, fdt);
|
2017-04-11 17:30:05 +02:00
|
|
|
|
|
|
|
if (pnv->bmc) {
|
2017-12-15 14:56:01 +01:00
|
|
|
pnv_dt_bmc_sensors(pnv->bmc, fdt);
|
2017-04-11 17:30:05 +02:00
|
|
|
}
|
|
|
|
|
2019-12-13 12:59:56 +01:00
|
|
|
/* Create an extra node for power management on machines that support it */
|
|
|
|
if (pmc->dt_power_mgt) {
|
|
|
|
pmc->dt_power_mgt(pnv, fdt);
|
2019-03-07 23:35:47 +01:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:35 +02:00
|
|
|
return fdt;
|
|
|
|
}
|
|
|
|
|
2017-04-11 17:30:06 +02:00
|
|
|
static void pnv_powerdown_notify(Notifier *n, void *opaque)
|
|
|
|
{
|
2019-12-19 19:11:43 +01:00
|
|
|
PnvMachineState *pnv = container_of(n, PnvMachineState, powerdown_notifier);
|
2017-04-11 17:30:06 +02:00
|
|
|
|
|
|
|
if (pnv->bmc) {
|
|
|
|
pnv_bmc_powerdown(pnv->bmc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-18 22:54:20 +02:00
|
|
|
static void pnv_reset(MachineState *machine)
|
2016-10-22 11:46:35 +02:00
|
|
|
{
|
2020-04-04 17:36:55 +02:00
|
|
|
PnvMachineState *pnv = PNV_MACHINE(machine);
|
|
|
|
IPMIBmc *bmc;
|
2016-10-22 11:46:35 +02:00
|
|
|
void *fdt;
|
|
|
|
|
|
|
|
qemu_devices_reset();
|
|
|
|
|
2020-04-04 17:36:55 +02:00
|
|
|
/*
|
|
|
|
* The machine should provide by default an internal BMC simulator.
|
|
|
|
* If not, try to use the BMC device that was provided on the command
|
|
|
|
* line.
|
|
|
|
*/
|
|
|
|
bmc = pnv_bmc_find(&error_fatal);
|
|
|
|
if (!pnv->bmc) {
|
|
|
|
if (!bmc) {
|
|
|
|
warn_report("machine has no BMC device. Use '-device "
|
|
|
|
"ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' "
|
|
|
|
"to define one");
|
|
|
|
} else {
|
|
|
|
pnv_bmc_set_pnor(bmc, pnv->pnor);
|
|
|
|
pnv->bmc = bmc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
fdt = pnv_dt_create(machine);
|
2016-10-22 11:46:35 +02:00
|
|
|
|
|
|
|
/* Pack resulting tree */
|
|
|
|
_FDT((fdt_pack(fdt)));
|
|
|
|
|
2019-06-06 19:47:32 +02:00
|
|
|
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
|
2016-10-22 11:46:35 +02:00
|
|
|
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
|
2020-02-14 04:32:06 +01:00
|
|
|
|
|
|
|
g_free(fdt);
|
2016-10-22 11:46:35 +02:00
|
|
|
}
|
|
|
|
|
2018-06-15 17:25:34 +02:00
|
|
|
static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
|
2016-10-22 11:46:43 +02:00
|
|
|
{
|
2018-06-18 19:05:39 +02:00
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(chip);
|
|
|
|
return pnv_lpc_isa_create(&chip8->lpc, true, errp);
|
2018-06-15 17:25:34 +02:00
|
|
|
}
|
2016-10-22 11:46:43 +02:00
|
|
|
|
2018-06-15 17:25:34 +02:00
|
|
|
static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
|
|
|
|
{
|
2018-06-18 19:05:39 +02:00
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(chip);
|
|
|
|
return pnv_lpc_isa_create(&chip8->lpc, false, errp);
|
2018-06-15 17:25:34 +02:00
|
|
|
}
|
2016-10-22 11:46:43 +02:00
|
|
|
|
2018-06-15 17:25:34 +02:00
|
|
|
static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
|
|
|
|
{
|
2019-03-07 23:35:39 +01:00
|
|
|
Pnv9Chip *chip9 = PNV9_CHIP(chip);
|
|
|
|
return pnv_lpc_isa_create(&chip9->lpc, false, errp);
|
2018-06-15 17:25:34 +02:00
|
|
|
}
|
2016-10-22 11:46:43 +02:00
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp)
|
|
|
|
{
|
2019-12-05 19:44:54 +01:00
|
|
|
Pnv10Chip *chip10 = PNV10_CHIP(chip);
|
|
|
|
return pnv_lpc_isa_create(&chip10->lpc, false, errp);
|
2019-12-05 19:44:51 +01:00
|
|
|
}
|
|
|
|
|
2018-06-15 17:25:34 +02:00
|
|
|
static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
|
|
|
|
{
|
|
|
|
return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
|
2016-10-22 11:46:43 +02:00
|
|
|
}
|
|
|
|
|
2019-03-06 09:50:13 +01:00
|
|
|
static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
|
|
|
|
{
|
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(chip);
|
2020-01-27 15:45:06 +01:00
|
|
|
int i;
|
2019-03-06 09:50:13 +01:00
|
|
|
|
|
|
|
ics_pic_print_info(&chip8->psi.ics, mon);
|
2020-01-27 15:45:06 +01:00
|
|
|
for (i = 0; i < chip->num_phbs; i++) {
|
|
|
|
pnv_phb3_msi_pic_print_info(&chip8->phbs[i].msis, mon);
|
|
|
|
ics_pic_print_info(&chip8->phbs[i].lsis, mon);
|
|
|
|
}
|
2019-03-06 09:50:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
|
|
|
|
{
|
|
|
|
Pnv9Chip *chip9 = PNV9_CHIP(chip);
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
int i, j;
|
2019-03-06 09:50:13 +01:00
|
|
|
|
|
|
|
pnv_xive_pic_print_info(&chip9->xive, mon);
|
2019-03-07 23:35:35 +01:00
|
|
|
pnv_psi_pic_print_info(&chip9->psi, mon);
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
|
|
|
|
for (i = 0; i < PNV9_CHIP_MAX_PEC; i++) {
|
|
|
|
PnvPhb4PecState *pec = &chip9->pecs[i];
|
|
|
|
for (j = 0; j < pec->num_stacks; j++) {
|
|
|
|
pnv_phb4_pic_print_info(&pec->stacks[j].phb, mon);
|
|
|
|
}
|
|
|
|
}
|
2019-03-06 09:50:13 +01:00
|
|
|
}
|
|
|
|
|
2019-12-13 13:00:13 +01:00
|
|
|
static uint64_t pnv_chip_power8_xscom_core_base(PnvChip *chip,
|
|
|
|
uint32_t core_id)
|
|
|
|
{
|
|
|
|
return PNV_XSCOM_EX_BASE(core_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t pnv_chip_power9_xscom_core_base(PnvChip *chip,
|
|
|
|
uint32_t core_id)
|
|
|
|
{
|
|
|
|
return PNV9_XSCOM_EC_BASE(core_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t pnv_chip_power10_xscom_core_base(PnvChip *chip,
|
|
|
|
uint32_t core_id)
|
|
|
|
{
|
|
|
|
return PNV10_XSCOM_EC_BASE(core_id);
|
|
|
|
}
|
|
|
|
|
2019-07-31 16:12:16 +02:00
|
|
|
static bool pnv_match_cpu(const char *default_type, const char *cpu_type)
|
|
|
|
{
|
|
|
|
PowerPCCPUClass *ppc_default =
|
|
|
|
POWERPC_CPU_CLASS(object_class_by_name(default_type));
|
|
|
|
PowerPCCPUClass *ppc =
|
|
|
|
POWERPC_CPU_CLASS(object_class_by_name(cpu_type));
|
|
|
|
|
|
|
|
return ppc_default->pvr_match(ppc_default, ppc->pvr);
|
|
|
|
}
|
|
|
|
|
ppc/pnv: Create BMC devices at machine init
The BMC of the OpenPOWER systems monitors the machine state using
sensors, controls the power and controls the access to the PNOR flash
device containing the firmware image required to boot the host.
QEMU models the power cycle process, access to the sensors and access
to the PNOR device. But, for these features to be available, the QEMU
PowerNV machine needs two extras devices on the command line, an IPMI
BT device for communication and a BMC backend device:
-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10
The BMC properties are then defined accordingly in the device tree and
OPAL self adapts. If a BMC device and an IPMI BT device are not
available, OPAL does not try to communicate with the BMC in any
manner. This is not how real systems behave.
To be closer to the default behavior, create an IPMI BMC simulator
device and an IPMI BT device at machine initialization time. We loose
the ability to define an external BMC device but there are benefits:
- a better match with real systems,
- a better test coverage of the OPAL code,
- system powerdown and reset commands that work,
- a QEMU device tree compliant with the specifications (*).
(*) Still needs a MBOX device.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20191121162340.11049-1-clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2019-11-21 17:23:40 +01:00
|
|
|
static void pnv_ipmi_bt_init(ISABus *bus, IPMIBmc *bmc, uint32_t irq)
|
|
|
|
{
|
|
|
|
Object *obj;
|
|
|
|
|
|
|
|
obj = OBJECT(isa_create(bus, "isa-ipmi-bt"));
|
|
|
|
object_property_set_link(obj, OBJECT(bmc), "bmc", &error_fatal);
|
|
|
|
object_property_set_int(obj, irq, "irq", &error_fatal);
|
|
|
|
object_property_set_bool(obj, true, "realized", &error_fatal);
|
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static void pnv_chip_power10_pic_print_info(PnvChip *chip, Monitor *mon)
|
|
|
|
{
|
2019-12-05 19:44:53 +01:00
|
|
|
Pnv10Chip *chip10 = PNV10_CHIP(chip);
|
|
|
|
|
|
|
|
pnv_psi_pic_print_info(&chip10->psi, mon);
|
2019-12-05 19:44:51 +01:00
|
|
|
}
|
|
|
|
|
2017-12-15 14:56:01 +01:00
|
|
|
static void pnv_init(MachineState *machine)
|
2016-10-22 11:46:35 +02:00
|
|
|
{
|
2017-12-15 14:56:01 +01:00
|
|
|
PnvMachineState *pnv = PNV_MACHINE(machine);
|
2019-07-31 16:12:16 +02:00
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
2016-10-22 11:46:35 +02:00
|
|
|
char *fw_filename;
|
|
|
|
long fw_size;
|
2016-10-22 11:46:36 +02:00
|
|
|
int i;
|
|
|
|
char *chip_typename;
|
2019-10-21 15:12:11 +02:00
|
|
|
DriveInfo *pnor = drive_get(IF_MTD, 0, 0);
|
|
|
|
DeviceState *dev;
|
2016-10-22 11:46:35 +02:00
|
|
|
|
|
|
|
/* allocate RAM */
|
2018-06-25 14:41:57 +02:00
|
|
|
if (machine->ram_size < (1 * GiB)) {
|
2017-07-12 15:57:41 +02:00
|
|
|
warn_report("skiboot may not work with < 1GB of RAM");
|
2016-10-22 11:46:35 +02:00
|
|
|
}
|
2020-02-19 17:09:36 +01:00
|
|
|
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
|
2016-10-22 11:46:35 +02:00
|
|
|
|
2019-10-21 15:12:11 +02:00
|
|
|
/*
|
|
|
|
* Create our simple PNOR device
|
|
|
|
*/
|
|
|
|
dev = qdev_create(NULL, TYPE_PNV_PNOR);
|
|
|
|
if (pnor) {
|
|
|
|
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(pnor),
|
|
|
|
&error_abort);
|
|
|
|
}
|
|
|
|
qdev_init_nofail(dev);
|
|
|
|
pnv->pnor = PNV_PNOR(dev);
|
|
|
|
|
2016-10-22 11:46:35 +02:00
|
|
|
/* load skiboot firmware */
|
|
|
|
if (bios_name == NULL) {
|
|
|
|
bios_name = FW_FILE_NAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
2017-09-25 10:58:25 +02:00
|
|
|
if (!fw_filename) {
|
|
|
|
error_report("Could not find OPAL firmware '%s'", bios_name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2016-10-22 11:46:35 +02:00
|
|
|
|
2020-01-27 15:41:54 +01:00
|
|
|
fw_size = load_image_targphys(fw_filename, pnv->fw_load_addr, FW_MAX_SIZE);
|
2016-10-22 11:46:35 +02:00
|
|
|
if (fw_size < 0) {
|
2017-09-25 10:58:25 +02:00
|
|
|
error_report("Could not load OPAL firmware '%s'", fw_filename);
|
2016-10-22 11:46:35 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
g_free(fw_filename);
|
|
|
|
|
|
|
|
/* load kernel */
|
|
|
|
if (machine->kernel_filename) {
|
|
|
|
long kernel_size;
|
|
|
|
|
|
|
|
kernel_size = load_image_targphys(machine->kernel_filename,
|
2019-02-25 18:01:53 +01:00
|
|
|
KERNEL_LOAD_ADDR, KERNEL_MAX_SIZE);
|
2016-10-22 11:46:35 +02:00
|
|
|
if (kernel_size < 0) {
|
2017-02-08 19:31:57 +01:00
|
|
|
error_report("Could not load kernel '%s'",
|
2017-02-01 12:03:10 +01:00
|
|
|
machine->kernel_filename);
|
2016-10-22 11:46:35 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* load initrd */
|
|
|
|
if (machine->initrd_filename) {
|
|
|
|
pnv->initrd_base = INITRD_LOAD_ADDR;
|
|
|
|
pnv->initrd_size = load_image_targphys(machine->initrd_filename,
|
2019-02-25 18:01:54 +01:00
|
|
|
pnv->initrd_base, INITRD_MAX_SIZE);
|
2016-10-22 11:46:35 +02:00
|
|
|
if (pnv->initrd_size < 0) {
|
2017-02-08 19:31:57 +01:00
|
|
|
error_report("Could not load initial ram disk '%s'",
|
2016-10-22 11:46:35 +02:00
|
|
|
machine->initrd_filename);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
2016-10-22 11:46:36 +02:00
|
|
|
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
/* MSIs are supported on this platform */
|
|
|
|
msi_nonbroken = true;
|
|
|
|
|
2019-07-31 16:12:16 +02:00
|
|
|
/*
|
|
|
|
* Check compatibility of the specified CPU with the machine
|
|
|
|
* default.
|
|
|
|
*/
|
|
|
|
if (!pnv_match_cpu(mc->default_cpu_type, machine->cpu_type)) {
|
|
|
|
error_report("invalid CPU model '%s' for %s machine",
|
|
|
|
machine->cpu_type, mc->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:36 +02:00
|
|
|
/* Create the processor chips */
|
2017-10-09 21:51:06 +02:00
|
|
|
i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
|
2017-10-09 21:51:07 +02:00
|
|
|
chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
|
2017-10-09 21:51:06 +02:00
|
|
|
i, machine->cpu_type);
|
2016-10-22 11:46:36 +02:00
|
|
|
if (!object_class_by_name(chip_typename)) {
|
2019-07-31 16:12:16 +02:00
|
|
|
error_report("invalid chip model '%.*s' for %s machine",
|
|
|
|
i, machine->cpu_type, mc->name);
|
2016-10-22 11:46:36 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2020-01-06 11:29:42 +01:00
|
|
|
pnv->num_chips =
|
|
|
|
machine->smp.max_cpus / (machine->smp.cores * machine->smp.threads);
|
|
|
|
/*
|
|
|
|
* TODO: should we decide on how many chips we can create based
|
|
|
|
* on #cores and Venice vs. Murano vs. Naples chip type etc...,
|
|
|
|
*/
|
|
|
|
if (!is_power_of_2(pnv->num_chips) || pnv->num_chips > 4) {
|
|
|
|
error_report("invalid number of chips: '%d'", pnv->num_chips);
|
|
|
|
error_printf("Try '-smp sockets=N'. Valid values are : 1, 2 or 4.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:36 +02:00
|
|
|
pnv->chips = g_new0(PnvChip *, pnv->num_chips);
|
|
|
|
for (i = 0; i < pnv->num_chips; i++) {
|
|
|
|
char chip_name[32];
|
|
|
|
Object *chip = object_new(chip_typename);
|
|
|
|
|
|
|
|
pnv->chips[i] = PNV_CHIP(chip);
|
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* TODO: put all the memory in one node on chip 0 until we find a
|
2016-10-22 11:46:36 +02:00
|
|
|
* way to specify different ranges for each chip
|
|
|
|
*/
|
|
|
|
if (i == 0) {
|
|
|
|
object_property_set_int(chip, machine->ram_size, "ram-size",
|
|
|
|
&error_fatal);
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(chip_name, sizeof(chip_name), "chip[%d]", PNV_CHIP_HWID(i));
|
|
|
|
object_property_add_child(OBJECT(pnv), chip_name, chip, &error_fatal);
|
|
|
|
object_property_set_int(chip, PNV_CHIP_HWID(i), "chip-id",
|
|
|
|
&error_fatal);
|
2019-05-18 22:54:22 +02:00
|
|
|
object_property_set_int(chip, machine->smp.cores,
|
|
|
|
"nr-cores", &error_fatal);
|
2020-01-06 15:56:39 +01:00
|
|
|
object_property_set_int(chip, machine->smp.threads,
|
|
|
|
"nr-threads", &error_fatal);
|
2020-01-06 15:56:35 +01:00
|
|
|
/*
|
|
|
|
* The POWER8 machine use the XICS interrupt interface.
|
|
|
|
* Propagate the XICS fabric to the chip and its controllers.
|
|
|
|
*/
|
|
|
|
if (object_dynamic_cast(OBJECT(pnv), TYPE_XICS_FABRIC)) {
|
|
|
|
object_property_set_link(chip, OBJECT(pnv), "xics", &error_abort);
|
|
|
|
}
|
2020-01-06 15:56:37 +01:00
|
|
|
if (object_dynamic_cast(OBJECT(pnv), TYPE_XIVE_FABRIC)) {
|
|
|
|
object_property_set_link(chip, OBJECT(pnv), "xive-fabric",
|
|
|
|
&error_abort);
|
|
|
|
}
|
2016-10-22 11:46:36 +02:00
|
|
|
object_property_set_bool(chip, true, "realized", &error_fatal);
|
|
|
|
}
|
|
|
|
g_free(chip_typename);
|
2016-10-22 11:46:43 +02:00
|
|
|
|
|
|
|
/* Instantiate ISA bus on chip 0 */
|
2018-06-15 17:25:34 +02:00
|
|
|
pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
|
2016-10-22 11:46:43 +02:00
|
|
|
|
|
|
|
/* Create serial port */
|
2018-04-20 16:52:46 +02:00
|
|
|
serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
|
2016-10-22 11:46:43 +02:00
|
|
|
|
|
|
|
/* Create an RTC ISA device too */
|
2017-10-17 18:44:16 +02:00
|
|
|
mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
|
2017-04-11 17:30:06 +02:00
|
|
|
|
2020-04-04 17:36:55 +02:00
|
|
|
/*
|
|
|
|
* Create the machine BMC simulator and the IPMI BT device for
|
|
|
|
* communication with the BMC
|
|
|
|
*/
|
|
|
|
if (defaults_enabled()) {
|
|
|
|
pnv->bmc = pnv_bmc_create(pnv->pnor);
|
|
|
|
pnv_ipmi_bt_init(pnv->isa_bus, pnv->bmc, 10);
|
|
|
|
}
|
ppc/pnv: Create BMC devices at machine init
The BMC of the OpenPOWER systems monitors the machine state using
sensors, controls the power and controls the access to the PNOR flash
device containing the firmware image required to boot the host.
QEMU models the power cycle process, access to the sensors and access
to the PNOR device. But, for these features to be available, the QEMU
PowerNV machine needs two extras devices on the command line, an IPMI
BT device for communication and a BMC backend device:
-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10
The BMC properties are then defined accordingly in the device tree and
OPAL self adapts. If a BMC device and an IPMI BT device are not
available, OPAL does not try to communicate with the BMC in any
manner. This is not how real systems behave.
To be closer to the default behavior, create an IPMI BMC simulator
device and an IPMI BT device at machine initialization time. We loose
the ability to define an external BMC device but there are benefits:
- a better match with real systems,
- a better test coverage of the OPAL code,
- system powerdown and reset commands that work,
- a QEMU device tree compliant with the specifications (*).
(*) Still needs a MBOX device.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20191121162340.11049-1-clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2019-11-21 17:23:40 +01:00
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* OpenPOWER systems use a IPMI SEL Event message to notify the
|
|
|
|
* host to powerdown
|
|
|
|
*/
|
2017-04-11 17:30:06 +02:00
|
|
|
pnv->powerdown_notifier.notify = pnv_powerdown_notify;
|
|
|
|
qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:38 +02:00
|
|
|
/*
|
|
|
|
* 0:21 Reserved - Read as zeros
|
|
|
|
* 22:24 Chip ID
|
|
|
|
* 25:28 Core number
|
|
|
|
* 29:31 Thread ID
|
|
|
|
*/
|
|
|
|
static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
|
|
|
|
{
|
|
|
|
return (chip->chip_id << 7) | (core_id << 3);
|
|
|
|
}
|
|
|
|
|
2019-01-02 06:57:34 +01:00
|
|
|
static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
|
|
|
|
Error **errp)
|
2018-06-15 17:25:33 +02:00
|
|
|
{
|
2020-01-06 15:56:35 +01:00
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(chip);
|
2019-01-02 06:57:34 +01:00
|
|
|
Error *local_err = NULL;
|
|
|
|
Object *obj;
|
2019-01-17 08:53:25 +01:00
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
2019-01-02 06:57:34 +01:00
|
|
|
|
2020-01-06 15:56:35 +01:00
|
|
|
obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, chip8->xics, &local_err);
|
2019-01-02 06:57:34 +01:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 09:50:10 +01:00
|
|
|
pnv_cpu->intc = obj;
|
2018-06-15 17:25:33 +02:00
|
|
|
}
|
|
|
|
|
2019-10-24 16:27:22 +02:00
|
|
|
|
2019-10-22 18:38:10 +02:00
|
|
|
static void pnv_chip_power8_intc_reset(PnvChip *chip, PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
|
|
|
|
|
|
|
icp_reset(ICP(pnv_cpu->intc));
|
|
|
|
}
|
|
|
|
|
2019-10-24 16:27:22 +02:00
|
|
|
static void pnv_chip_power8_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
|
|
|
|
|
|
|
icp_destroy(ICP(pnv_cpu->intc));
|
|
|
|
pnv_cpu->intc = NULL;
|
|
|
|
}
|
|
|
|
|
2019-12-13 13:00:07 +01:00
|
|
|
static void pnv_chip_power8_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
|
|
|
|
Monitor *mon)
|
|
|
|
{
|
|
|
|
icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:38 +02:00
|
|
|
/*
|
|
|
|
* 0:48 Reserved - Read as zeroes
|
|
|
|
* 49:52 Node ID
|
|
|
|
* 53:55 Chip ID
|
|
|
|
* 56 Reserved - Read as zero
|
|
|
|
* 57:61 Core number
|
|
|
|
* 62:63 Thread ID
|
|
|
|
*
|
|
|
|
* We only care about the lower bits. uint32_t is fine for the moment.
|
|
|
|
*/
|
|
|
|
static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
|
|
|
|
{
|
|
|
|
return (chip->chip_id << 8) | (core_id << 2);
|
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static uint32_t pnv_chip_core_pir_p10(PnvChip *chip, uint32_t core_id)
|
|
|
|
{
|
|
|
|
return (chip->chip_id << 8) | (core_id << 2);
|
|
|
|
}
|
|
|
|
|
2019-01-02 06:57:34 +01:00
|
|
|
static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
|
|
|
|
Error **errp)
|
2018-06-15 17:25:33 +02:00
|
|
|
{
|
2019-03-06 09:50:11 +01:00
|
|
|
Pnv9Chip *chip9 = PNV9_CHIP(chip);
|
|
|
|
Error *local_err = NULL;
|
|
|
|
Object *obj;
|
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The core creates its interrupt presenter but the XIVE interrupt
|
|
|
|
* controller object is initialized afterwards. Hopefully, it's
|
|
|
|
* only used at runtime.
|
|
|
|
*/
|
2020-01-06 15:56:41 +01:00
|
|
|
obj = xive_tctx_create(OBJECT(cpu), XIVE_PRESENTER(&chip9->xive),
|
|
|
|
&local_err);
|
2019-03-06 09:50:11 +01:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pnv_cpu->intc = obj;
|
2018-06-15 17:25:33 +02:00
|
|
|
}
|
|
|
|
|
2019-10-22 18:38:10 +02:00
|
|
|
static void pnv_chip_power9_intc_reset(PnvChip *chip, PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
|
|
|
|
|
|
|
xive_tctx_reset(XIVE_TCTX(pnv_cpu->intc));
|
|
|
|
}
|
|
|
|
|
2019-10-24 16:27:22 +02:00
|
|
|
static void pnv_chip_power9_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
|
|
|
|
|
|
|
xive_tctx_destroy(XIVE_TCTX(pnv_cpu->intc));
|
|
|
|
pnv_cpu->intc = NULL;
|
|
|
|
}
|
|
|
|
|
2019-12-13 13:00:07 +01:00
|
|
|
static void pnv_chip_power9_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
|
|
|
|
Monitor *mon)
|
|
|
|
{
|
|
|
|
xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), mon);
|
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static void pnv_chip_power10_intc_create(PnvChip *chip, PowerPCCPU *cpu,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
|
|
|
|
|
|
|
/* Will be defined when the interrupt controller is */
|
|
|
|
pnv_cpu->intc = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power10_intc_reset(PnvChip *chip, PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power10_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
|
|
|
|
|
|
|
|
pnv_cpu->intc = NULL;
|
|
|
|
}
|
|
|
|
|
2019-12-13 13:00:07 +01:00
|
|
|
static void pnv_chip_power10_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
|
|
|
|
Monitor *mon)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* Allowed core identifiers on a POWER8 Processor Chip :
|
2016-10-22 11:46:37 +02:00
|
|
|
*
|
|
|
|
* <EX0 reserved>
|
|
|
|
* EX1 - Venice only
|
|
|
|
* EX2 - Venice only
|
|
|
|
* EX3 - Venice only
|
|
|
|
* EX4
|
|
|
|
* EX5
|
|
|
|
* EX6
|
|
|
|
* <EX7,8 reserved> <reserved>
|
|
|
|
* EX9 - Venice only
|
|
|
|
* EX10 - Venice only
|
|
|
|
* EX11 - Venice only
|
|
|
|
* EX12
|
|
|
|
* EX13
|
|
|
|
* EX14
|
|
|
|
* <EX15 reserved>
|
|
|
|
*/
|
|
|
|
#define POWER8E_CORE_MASK (0x7070ull)
|
|
|
|
#define POWER8_CORE_MASK (0x7e7eull)
|
|
|
|
|
|
|
|
/*
|
2018-01-15 19:04:02 +01:00
|
|
|
* POWER9 has 24 cores, ids starting at 0x0
|
2016-10-22 11:46:37 +02:00
|
|
|
*/
|
2018-01-15 19:04:02 +01:00
|
|
|
#define POWER9_CORE_MASK (0xffffffffffffffull)
|
2016-10-22 11:46:37 +02:00
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
|
|
|
|
#define POWER10_CORE_MASK (0xffffffffffffffull)
|
|
|
|
|
2018-06-18 19:05:39 +02:00
|
|
|
static void pnv_chip_power8_instance_init(Object *obj)
|
|
|
|
{
|
2020-01-27 15:45:06 +01:00
|
|
|
PnvChip *chip = PNV_CHIP(obj);
|
2018-06-18 19:05:39 +02:00
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(obj);
|
2020-01-27 15:45:06 +01:00
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
|
|
|
|
int i;
|
2018-06-18 19:05:39 +02:00
|
|
|
|
2020-01-06 15:56:35 +01:00
|
|
|
object_property_add_link(obj, "xics", TYPE_XICS_FABRIC,
|
|
|
|
(Object **)&chip8->xics,
|
|
|
|
object_property_allow_set_link,
|
|
|
|
OBJ_PROP_LINK_STRONG,
|
|
|
|
&error_abort);
|
|
|
|
|
2019-02-21 12:24:48 +01:00
|
|
|
object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi),
|
2019-03-07 23:35:34 +01:00
|
|
|
TYPE_PNV8_PSI, &error_abort, NULL);
|
2018-06-18 19:05:39 +02:00
|
|
|
|
2019-02-21 12:24:48 +01:00
|
|
|
object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc),
|
2019-03-07 23:35:37 +01:00
|
|
|
TYPE_PNV8_LPC, &error_abort, NULL);
|
2018-06-18 19:05:39 +02:00
|
|
|
|
2019-02-21 12:24:48 +01:00
|
|
|
object_initialize_child(obj, "occ", &chip8->occ, sizeof(chip8->occ),
|
2019-03-07 23:35:41 +01:00
|
|
|
TYPE_PNV8_OCC, &error_abort, NULL);
|
2019-09-12 11:30:54 +02:00
|
|
|
|
|
|
|
object_initialize_child(obj, "homer", &chip8->homer, sizeof(chip8->homer),
|
|
|
|
TYPE_PNV8_HOMER, &error_abort, NULL);
|
2020-01-27 15:45:06 +01:00
|
|
|
|
|
|
|
for (i = 0; i < pcc->num_phbs; i++) {
|
|
|
|
object_initialize_child(obj, "phb[*]", &chip8->phbs[i],
|
|
|
|
sizeof(chip8->phbs[i]), TYPE_PNV_PHB3,
|
|
|
|
&error_abort, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Number of PHBs is the chip default
|
|
|
|
*/
|
|
|
|
chip->num_phbs = pcc->num_phbs;
|
2018-06-18 19:05:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
|
|
|
|
{
|
|
|
|
PnvChip *chip = PNV_CHIP(chip8);
|
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
|
|
|
|
int i, j;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
name = g_strdup_printf("icp-%x", chip->chip_id);
|
|
|
|
memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
|
|
|
|
sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
|
|
|
|
g_free(name);
|
|
|
|
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
|
|
|
|
|
|
|
|
/* Map the ICP registers for each thread */
|
|
|
|
for (i = 0; i < chip->nr_cores; i++) {
|
2019-11-25 07:58:03 +01:00
|
|
|
PnvCore *pnv_core = chip->cores[i];
|
2018-06-18 19:05:39 +02:00
|
|
|
int core_hwid = CPU_CORE(pnv_core)->core_id;
|
|
|
|
|
|
|
|
for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
|
|
|
|
uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
|
2020-01-06 15:56:35 +01:00
|
|
|
PnvICPState *icp = PNV_ICP(xics_icp_get(chip8->xics, pir));
|
2018-06-18 19:05:39 +02:00
|
|
|
|
|
|
|
memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
|
|
|
|
&icp->mmio);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
|
|
|
|
PnvChip *chip = PNV_CHIP(dev);
|
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(dev);
|
2019-03-07 23:35:34 +01:00
|
|
|
Pnv8Psi *psi8 = &chip8->psi;
|
2018-06-18 19:05:39 +02:00
|
|
|
Error *local_err = NULL;
|
2020-01-27 15:45:06 +01:00
|
|
|
int i;
|
2018-06-18 19:05:39 +02:00
|
|
|
|
2020-01-06 15:56:35 +01:00
|
|
|
assert(chip8->xics);
|
|
|
|
|
2019-06-12 19:43:44 +02:00
|
|
|
/* XSCOM bridge is first */
|
|
|
|
pnv_xscom_realize(chip, PNV_XSCOM_SIZE, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
|
|
|
|
|
2018-06-18 19:05:39 +02:00
|
|
|
pcc->parent_realize(dev, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Processor Service Interface (PSI) Host Bridge */
|
|
|
|
object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
|
|
|
|
"bar", &error_fatal);
|
2020-01-06 15:56:35 +01:00
|
|
|
object_property_set_link(OBJECT(&chip8->psi), OBJECT(chip8->xics),
|
2020-01-06 15:56:34 +01:00
|
|
|
ICS_PROP_XICS, &error_abort);
|
2018-06-18 19:05:39 +02:00
|
|
|
object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2019-03-07 23:35:34 +01:00
|
|
|
pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE,
|
|
|
|
&PNV_PSI(psi8)->xscom_regs);
|
2018-06-18 19:05:39 +02:00
|
|
|
|
|
|
|
/* Create LPC controller */
|
2019-11-15 16:55:43 +01:00
|
|
|
object_property_set_link(OBJECT(&chip8->lpc), OBJECT(&chip8->psi), "psi",
|
|
|
|
&error_abort);
|
2018-06-18 19:05:39 +02:00
|
|
|
object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
|
|
|
|
&error_fatal);
|
|
|
|
pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
|
|
|
|
|
2019-03-07 23:35:38 +01:00
|
|
|
chip->dt_isa_nodename = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
|
|
|
|
(uint64_t) PNV_XSCOM_BASE(chip),
|
|
|
|
PNV_XSCOM_LPC_BASE);
|
|
|
|
|
2019-09-11 16:29:25 +02:00
|
|
|
/*
|
|
|
|
* Interrupt Management Area. This is the memory region holding
|
|
|
|
* all the Interrupt Control Presenter (ICP) registers
|
|
|
|
*/
|
2018-06-18 19:05:39 +02:00
|
|
|
pnv_chip_icp_realize(chip8, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the simplified OCC model */
|
2019-11-15 16:55:49 +01:00
|
|
|
object_property_set_link(OBJECT(&chip8->occ), OBJECT(&chip8->psi), "psi",
|
|
|
|
&error_abort);
|
2018-06-18 19:05:39 +02:00
|
|
|
object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
|
2019-09-12 11:30:53 +02:00
|
|
|
|
|
|
|
/* OCC SRAM model */
|
2019-12-11 09:29:12 +01:00
|
|
|
memory_region_add_subregion(get_system_memory(), PNV_OCC_SENSOR_BASE(chip),
|
2019-09-12 11:30:53 +02:00
|
|
|
&chip8->occ.sram_regs);
|
2019-09-12 11:30:54 +02:00
|
|
|
|
|
|
|
/* HOMER */
|
2019-11-15 16:55:54 +01:00
|
|
|
object_property_set_link(OBJECT(&chip8->homer), OBJECT(chip), "chip",
|
|
|
|
&error_abort);
|
2019-09-12 11:30:54 +02:00
|
|
|
object_property_set_bool(OBJECT(&chip8->homer), true, "realized",
|
|
|
|
&local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2019-12-11 09:29:11 +01:00
|
|
|
/* Homer Xscom region */
|
|
|
|
pnv_xscom_add_subregion(chip, PNV_XSCOM_PBA_BASE, &chip8->homer.pba_regs);
|
|
|
|
|
|
|
|
/* Homer mmio region */
|
2019-09-12 11:30:54 +02:00
|
|
|
memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip),
|
|
|
|
&chip8->homer.regs);
|
2020-01-27 15:45:06 +01:00
|
|
|
|
|
|
|
/* PHB3 controllers */
|
|
|
|
for (i = 0; i < chip->num_phbs; i++) {
|
|
|
|
PnvPHB3 *phb = &chip8->phbs[i];
|
|
|
|
PnvPBCQState *pbcq = &phb->pbcq;
|
|
|
|
|
|
|
|
object_property_set_int(OBJECT(phb), i, "index", &error_fatal);
|
|
|
|
object_property_set_int(OBJECT(phb), chip->chip_id, "chip-id",
|
|
|
|
&error_fatal);
|
|
|
|
object_property_set_bool(OBJECT(phb), true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qdev_set_parent_bus(DEVICE(phb), sysbus_get_default());
|
|
|
|
|
|
|
|
/* Populate the XSCOM address space. */
|
|
|
|
pnv_xscom_add_subregion(chip,
|
|
|
|
PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id,
|
|
|
|
&pbcq->xscom_nest_regs);
|
|
|
|
pnv_xscom_add_subregion(chip,
|
|
|
|
PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id,
|
|
|
|
&pbcq->xscom_pci_regs);
|
|
|
|
pnv_xscom_add_subregion(chip,
|
|
|
|
PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id,
|
|
|
|
&pbcq->xscom_spci_regs);
|
|
|
|
}
|
2018-06-18 19:05:39 +02:00
|
|
|
}
|
|
|
|
|
2019-12-13 13:00:35 +01:00
|
|
|
static uint32_t pnv_chip_power8_xscom_pcba(PnvChip *chip, uint64_t addr)
|
|
|
|
{
|
|
|
|
addr &= (PNV_XSCOM_SIZE - 1);
|
|
|
|
return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:36 +02:00
|
|
|
static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
PnvChipClass *k = PNV_CHIP_CLASS(klass);
|
|
|
|
|
|
|
|
k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */
|
2016-10-22 11:46:37 +02:00
|
|
|
k->cores_mask = POWER8E_CORE_MASK;
|
2020-01-27 15:45:06 +01:00
|
|
|
k->num_phbs = 3;
|
2016-10-22 11:46:38 +02:00
|
|
|
k->core_pir = pnv_chip_core_pir_p8;
|
2018-06-15 17:25:33 +02:00
|
|
|
k->intc_create = pnv_chip_power8_intc_create;
|
2019-10-22 18:38:10 +02:00
|
|
|
k->intc_reset = pnv_chip_power8_intc_reset;
|
2019-10-24 16:27:22 +02:00
|
|
|
k->intc_destroy = pnv_chip_power8_intc_destroy;
|
2019-12-13 13:00:07 +01:00
|
|
|
k->intc_print_info = pnv_chip_power8_intc_print_info;
|
2018-06-15 17:25:34 +02:00
|
|
|
k->isa_create = pnv_chip_power8_isa_create;
|
2019-03-06 09:50:12 +01:00
|
|
|
k->dt_populate = pnv_chip_power8_dt_populate;
|
2019-03-06 09:50:13 +01:00
|
|
|
k->pic_print_info = pnv_chip_power8_pic_print_info;
|
2019-12-13 13:00:13 +01:00
|
|
|
k->xscom_core_base = pnv_chip_power8_xscom_core_base;
|
2019-12-13 13:00:35 +01:00
|
|
|
k->xscom_pcba = pnv_chip_power8_xscom_pcba;
|
2016-10-22 11:46:36 +02:00
|
|
|
dc->desc = "PowerNV Chip POWER8E";
|
2018-06-18 19:05:39 +02:00
|
|
|
|
|
|
|
device_class_set_parent_realize(dc, pnv_chip_power8_realize,
|
|
|
|
&k->parent_realize);
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
PnvChipClass *k = PNV_CHIP_CLASS(klass);
|
|
|
|
|
|
|
|
k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
|
2016-10-22 11:46:37 +02:00
|
|
|
k->cores_mask = POWER8_CORE_MASK;
|
2020-01-27 15:45:06 +01:00
|
|
|
k->num_phbs = 3;
|
2016-10-22 11:46:38 +02:00
|
|
|
k->core_pir = pnv_chip_core_pir_p8;
|
2018-06-15 17:25:33 +02:00
|
|
|
k->intc_create = pnv_chip_power8_intc_create;
|
2019-10-22 18:38:10 +02:00
|
|
|
k->intc_reset = pnv_chip_power8_intc_reset;
|
2019-10-24 16:27:22 +02:00
|
|
|
k->intc_destroy = pnv_chip_power8_intc_destroy;
|
2019-12-13 13:00:07 +01:00
|
|
|
k->intc_print_info = pnv_chip_power8_intc_print_info;
|
2018-06-15 17:25:34 +02:00
|
|
|
k->isa_create = pnv_chip_power8_isa_create;
|
2019-03-06 09:50:12 +01:00
|
|
|
k->dt_populate = pnv_chip_power8_dt_populate;
|
2019-03-06 09:50:13 +01:00
|
|
|
k->pic_print_info = pnv_chip_power8_pic_print_info;
|
2019-12-13 13:00:13 +01:00
|
|
|
k->xscom_core_base = pnv_chip_power8_xscom_core_base;
|
2019-12-13 13:00:35 +01:00
|
|
|
k->xscom_pcba = pnv_chip_power8_xscom_pcba;
|
2016-10-22 11:46:36 +02:00
|
|
|
dc->desc = "PowerNV Chip POWER8";
|
2018-06-18 19:05:39 +02:00
|
|
|
|
|
|
|
device_class_set_parent_realize(dc, pnv_chip_power8_realize,
|
|
|
|
&k->parent_realize);
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
PnvChipClass *k = PNV_CHIP_CLASS(klass);
|
|
|
|
|
|
|
|
k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */
|
2016-10-22 11:46:37 +02:00
|
|
|
k->cores_mask = POWER8_CORE_MASK;
|
2020-01-27 15:45:06 +01:00
|
|
|
k->num_phbs = 3;
|
2016-10-22 11:46:38 +02:00
|
|
|
k->core_pir = pnv_chip_core_pir_p8;
|
2018-06-15 17:25:33 +02:00
|
|
|
k->intc_create = pnv_chip_power8_intc_create;
|
2019-10-22 18:38:10 +02:00
|
|
|
k->intc_reset = pnv_chip_power8_intc_reset;
|
2019-10-24 16:27:22 +02:00
|
|
|
k->intc_destroy = pnv_chip_power8_intc_destroy;
|
2019-12-13 13:00:07 +01:00
|
|
|
k->intc_print_info = pnv_chip_power8_intc_print_info;
|
2018-06-15 17:25:34 +02:00
|
|
|
k->isa_create = pnv_chip_power8nvl_isa_create;
|
2019-03-06 09:50:12 +01:00
|
|
|
k->dt_populate = pnv_chip_power8_dt_populate;
|
2019-03-06 09:50:13 +01:00
|
|
|
k->pic_print_info = pnv_chip_power8_pic_print_info;
|
2019-12-13 13:00:13 +01:00
|
|
|
k->xscom_core_base = pnv_chip_power8_xscom_core_base;
|
2019-12-13 13:00:35 +01:00
|
|
|
k->xscom_pcba = pnv_chip_power8_xscom_pcba;
|
2016-10-22 11:46:36 +02:00
|
|
|
dc->desc = "PowerNV Chip POWER8NVL";
|
2018-06-18 19:05:39 +02:00
|
|
|
|
|
|
|
device_class_set_parent_realize(dc, pnv_chip_power8_realize,
|
|
|
|
&k->parent_realize);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power9_instance_init(Object *obj)
|
|
|
|
{
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
PnvChip *chip = PNV_CHIP(obj);
|
2019-03-06 09:50:11 +01:00
|
|
|
Pnv9Chip *chip9 = PNV9_CHIP(obj);
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
|
|
|
|
int i;
|
2019-03-06 09:50:11 +01:00
|
|
|
|
|
|
|
object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive),
|
|
|
|
TYPE_PNV_XIVE, &error_abort, NULL);
|
2020-01-06 15:56:37 +01:00
|
|
|
object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive),
|
|
|
|
"xive-fabric", &error_abort);
|
2019-03-07 23:35:35 +01:00
|
|
|
|
|
|
|
object_initialize_child(obj, "psi", &chip9->psi, sizeof(chip9->psi),
|
|
|
|
TYPE_PNV9_PSI, &error_abort, NULL);
|
2019-03-07 23:35:39 +01:00
|
|
|
|
|
|
|
object_initialize_child(obj, "lpc", &chip9->lpc, sizeof(chip9->lpc),
|
|
|
|
TYPE_PNV9_LPC, &error_abort, NULL);
|
2019-03-07 23:35:42 +01:00
|
|
|
|
|
|
|
object_initialize_child(obj, "occ", &chip9->occ, sizeof(chip9->occ),
|
|
|
|
TYPE_PNV9_OCC, &error_abort, NULL);
|
2019-09-12 11:30:54 +02:00
|
|
|
|
|
|
|
object_initialize_child(obj, "homer", &chip9->homer, sizeof(chip9->homer),
|
|
|
|
TYPE_PNV9_HOMER, &error_abort, NULL);
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
|
|
|
|
for (i = 0; i < PNV9_CHIP_MAX_PEC; i++) {
|
|
|
|
object_initialize_child(obj, "pec[*]", &chip9->pecs[i],
|
|
|
|
sizeof(chip9->pecs[i]), TYPE_PNV_PHB4_PEC,
|
|
|
|
&error_abort, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Number of PHBs is the chip default
|
|
|
|
*/
|
|
|
|
chip->num_phbs = pcc->num_phbs;
|
2018-06-18 19:05:39 +02:00
|
|
|
}
|
|
|
|
|
2019-03-07 23:35:44 +01:00
|
|
|
static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
|
|
|
|
{
|
|
|
|
PnvChip *chip = PNV_CHIP(chip9);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
chip9->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4);
|
|
|
|
chip9->quads = g_new0(PnvQuad, chip9->nr_quads);
|
|
|
|
|
|
|
|
for (i = 0; i < chip9->nr_quads; i++) {
|
|
|
|
char eq_name[32];
|
|
|
|
PnvQuad *eq = &chip9->quads[i];
|
2019-11-25 07:58:03 +01:00
|
|
|
PnvCore *pnv_core = chip->cores[i * 4];
|
2019-03-07 23:35:44 +01:00
|
|
|
int core_id = CPU_CORE(pnv_core)->core_id;
|
|
|
|
|
|
|
|
snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id);
|
hw/ppc/pnv: Use object_initialize_child for correct reference counting
As explained in commit aff39be0ed97:
Both functions, object_initialize() and object_property_add_child()
increase the reference counter of the new object, so one of the
references has to be dropped afterwards to get the reference
counting right. Otherwise the child object will not be properly
cleaned up when the parent gets destroyed.
Thus let's use now object_initialize_child() instead to get the
reference counting here right.
This patch was generated using the following Coccinelle script
(with a bit of manual fix-up for overly long lines):
@use_object_initialize_child@
expression parent_obj;
expression child_ptr;
expression child_name;
expression child_type;
expression child_size;
expression errp;
@@
(
- object_initialize(child_ptr, child_size, child_type);
+ object_initialize_child(parent_obj, child_name, child_ptr, child_size,
+ child_type, &error_abort, NULL);
... when != parent_obj
- object_property_add_child(parent_obj, child_name, OBJECT(child_ptr), NULL);
...
?- object_unref(OBJECT(child_ptr));
|
- object_initialize(child_ptr, child_size, child_type);
+ object_initialize_child(parent_obj, child_name, child_ptr, child_size,
+ child_type, errp, NULL);
... when != parent_obj
- object_property_add_child(parent_obj, child_name, OBJECT(child_ptr), errp);
...
?- object_unref(OBJECT(child_ptr));
)
While the object_initialize() function doesn't take an
'Error *errp' argument, the object_initialize_child() does.
Since this code is used when a machine is created (and is not
yet running), we deliberately choose to use the &error_abort
argument instead of ignoring errors if an object creation failed.
Suggested-by: Eduardo Habkost <ehabkost@redhat.com>
Inspired-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20190507163416.24647-2-philmd@redhat.com>
Acked-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2019-05-07 18:34:01 +02:00
|
|
|
object_initialize_child(OBJECT(chip), eq_name, eq, sizeof(*eq),
|
|
|
|
TYPE_PNV_QUAD, &error_fatal, NULL);
|
2019-03-07 23:35:44 +01:00
|
|
|
|
|
|
|
object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal);
|
|
|
|
object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal);
|
|
|
|
|
|
|
|
pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id),
|
|
|
|
&eq->xscom_regs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp)
|
|
|
|
{
|
|
|
|
Pnv9Chip *chip9 = PNV9_CHIP(chip);
|
|
|
|
Error *local_err = NULL;
|
|
|
|
int i, j;
|
|
|
|
int phb_id = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < PNV9_CHIP_MAX_PEC; i++) {
|
|
|
|
PnvPhb4PecState *pec = &chip9->pecs[i];
|
|
|
|
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
|
|
|
|
uint32_t pec_nest_base;
|
|
|
|
uint32_t pec_pci_base;
|
|
|
|
|
|
|
|
object_property_set_int(OBJECT(pec), i, "index", &error_fatal);
|
|
|
|
/*
|
|
|
|
* PEC0 -> 1 stack
|
|
|
|
* PEC1 -> 2 stacks
|
|
|
|
* PEC2 -> 3 stacks
|
|
|
|
*/
|
|
|
|
object_property_set_int(OBJECT(pec), i + 1, "num-stacks",
|
|
|
|
&error_fatal);
|
|
|
|
object_property_set_int(OBJECT(pec), chip->chip_id, "chip-id",
|
|
|
|
&error_fatal);
|
|
|
|
object_property_set_link(OBJECT(pec), OBJECT(get_system_memory()),
|
|
|
|
"system-memory", &error_abort);
|
|
|
|
object_property_set_bool(OBJECT(pec), true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pec_nest_base = pecc->xscom_nest_base(pec);
|
|
|
|
pec_pci_base = pecc->xscom_pci_base(pec);
|
|
|
|
|
|
|
|
pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr);
|
|
|
|
pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr);
|
|
|
|
|
|
|
|
for (j = 0; j < pec->num_stacks && phb_id < chip->num_phbs;
|
|
|
|
j++, phb_id++) {
|
|
|
|
PnvPhb4PecStack *stack = &pec->stacks[j];
|
|
|
|
Object *obj = OBJECT(&stack->phb);
|
|
|
|
|
|
|
|
object_property_set_int(obj, phb_id, "index", &error_fatal);
|
|
|
|
object_property_set_int(obj, chip->chip_id, "chip-id",
|
|
|
|
&error_fatal);
|
|
|
|
object_property_set_int(obj, PNV_PHB4_VERSION, "version",
|
|
|
|
&error_fatal);
|
|
|
|
object_property_set_int(obj, PNV_PHB4_DEVICE_ID, "device-id",
|
|
|
|
&error_fatal);
|
|
|
|
object_property_set_link(obj, OBJECT(stack), "stack", &error_abort);
|
|
|
|
object_property_set_bool(obj, true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qdev_set_parent_bus(DEVICE(obj), sysbus_get_default());
|
|
|
|
|
|
|
|
/* Populate the XSCOM address space. */
|
|
|
|
pnv_xscom_add_subregion(chip,
|
|
|
|
pec_nest_base + 0x40 * (stack->stack_no + 1),
|
|
|
|
&stack->nest_regs_mr);
|
|
|
|
pnv_xscom_add_subregion(chip,
|
|
|
|
pec_pci_base + 0x40 * (stack->stack_no + 1),
|
|
|
|
&stack->pci_regs_mr);
|
|
|
|
pnv_xscom_add_subregion(chip,
|
|
|
|
pec_pci_base + PNV9_XSCOM_PEC_PCI_STK0 +
|
|
|
|
0x40 * stack->stack_no,
|
|
|
|
&stack->phb_regs_mr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-18 19:05:39 +02:00
|
|
|
static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
|
2019-03-06 09:50:11 +01:00
|
|
|
Pnv9Chip *chip9 = PNV9_CHIP(dev);
|
|
|
|
PnvChip *chip = PNV_CHIP(dev);
|
2019-03-07 23:35:35 +01:00
|
|
|
Pnv9Psi *psi9 = &chip9->psi;
|
2018-06-18 19:05:39 +02:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
2019-06-12 19:43:44 +02:00
|
|
|
/* XSCOM bridge is first */
|
|
|
|
pnv_xscom_realize(chip, PNV9_XSCOM_SIZE, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip));
|
|
|
|
|
2018-06-18 19:05:39 +02:00
|
|
|
pcc->parent_realize(dev, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2019-03-06 09:50:11 +01:00
|
|
|
|
2019-03-07 23:35:44 +01:00
|
|
|
pnv_chip_quad_realize(chip9, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-06 09:50:11 +01:00
|
|
|
/* XIVE interrupt controller (POWER9) */
|
|
|
|
object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
|
|
|
|
"ic-bar", &error_fatal);
|
|
|
|
object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_VC_BASE(chip),
|
|
|
|
"vc-bar", &error_fatal);
|
|
|
|
object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_PC_BASE(chip),
|
|
|
|
"pc-bar", &error_fatal);
|
|
|
|
object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_TM_BASE(chip),
|
|
|
|
"tm-bar", &error_fatal);
|
2019-11-15 16:56:05 +01:00
|
|
|
object_property_set_link(OBJECT(&chip9->xive), OBJECT(chip), "chip",
|
|
|
|
&error_abort);
|
2019-03-06 09:50:11 +01:00
|
|
|
object_property_set_bool(OBJECT(&chip9->xive), true, "realized",
|
|
|
|
&local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
|
|
|
|
&chip9->xive.xscom_regs);
|
2019-03-07 23:35:35 +01:00
|
|
|
|
|
|
|
/* Processor Service Interface (PSI) Host Bridge */
|
|
|
|
object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
|
|
|
|
"bar", &error_fatal);
|
|
|
|
object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
|
|
|
|
&PNV_PSI(psi9)->xscom_regs);
|
2019-03-07 23:35:39 +01:00
|
|
|
|
|
|
|
/* LPC */
|
2019-11-15 16:55:43 +01:00
|
|
|
object_property_set_link(OBJECT(&chip9->lpc), OBJECT(&chip9->psi), "psi",
|
|
|
|
&error_abort);
|
2019-03-07 23:35:39 +01:00
|
|
|
object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
|
|
|
|
&chip9->lpc.xscom_regs);
|
|
|
|
|
|
|
|
chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
|
|
|
|
(uint64_t) PNV9_LPCM_BASE(chip));
|
2019-03-07 23:35:42 +01:00
|
|
|
|
|
|
|
/* Create the simplified OCC model */
|
2019-11-15 16:55:49 +01:00
|
|
|
object_property_set_link(OBJECT(&chip9->occ), OBJECT(&chip9->psi), "psi",
|
|
|
|
&error_abort);
|
2019-03-07 23:35:42 +01:00
|
|
|
object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
|
2019-09-12 11:30:53 +02:00
|
|
|
|
|
|
|
/* OCC SRAM model */
|
2019-12-11 09:29:12 +01:00
|
|
|
memory_region_add_subregion(get_system_memory(), PNV9_OCC_SENSOR_BASE(chip),
|
2019-09-12 11:30:53 +02:00
|
|
|
&chip9->occ.sram_regs);
|
2019-09-12 11:30:54 +02:00
|
|
|
|
|
|
|
/* HOMER */
|
2019-11-15 16:55:54 +01:00
|
|
|
object_property_set_link(OBJECT(&chip9->homer), OBJECT(chip), "chip",
|
|
|
|
&error_abort);
|
2019-09-12 11:30:54 +02:00
|
|
|
object_property_set_bool(OBJECT(&chip9->homer), true, "realized",
|
|
|
|
&local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2019-12-11 09:29:11 +01:00
|
|
|
/* Homer Xscom region */
|
|
|
|
pnv_xscom_add_subregion(chip, PNV9_XSCOM_PBA_BASE, &chip9->homer.pba_regs);
|
|
|
|
|
|
|
|
/* Homer mmio region */
|
2019-09-12 11:30:54 +02:00
|
|
|
memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip),
|
|
|
|
&chip9->homer.regs);
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
|
|
|
|
/* PHBs */
|
|
|
|
pnv_chip_power9_phb_realize(chip, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
|
|
|
|
2019-12-13 13:00:35 +01:00
|
|
|
static uint32_t pnv_chip_power9_xscom_pcba(PnvChip *chip, uint64_t addr)
|
|
|
|
{
|
|
|
|
addr &= (PNV9_XSCOM_SIZE - 1);
|
|
|
|
return addr >> 3;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:36 +02:00
|
|
|
static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
PnvChipClass *k = PNV_CHIP_CLASS(klass);
|
|
|
|
|
2018-01-15 19:04:01 +01:00
|
|
|
k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
|
2016-10-22 11:46:37 +02:00
|
|
|
k->cores_mask = POWER9_CORE_MASK;
|
2016-10-22 11:46:38 +02:00
|
|
|
k->core_pir = pnv_chip_core_pir_p9;
|
2018-06-15 17:25:33 +02:00
|
|
|
k->intc_create = pnv_chip_power9_intc_create;
|
2019-10-22 18:38:10 +02:00
|
|
|
k->intc_reset = pnv_chip_power9_intc_reset;
|
2019-10-24 16:27:22 +02:00
|
|
|
k->intc_destroy = pnv_chip_power9_intc_destroy;
|
2019-12-13 13:00:07 +01:00
|
|
|
k->intc_print_info = pnv_chip_power9_intc_print_info;
|
2018-06-15 17:25:34 +02:00
|
|
|
k->isa_create = pnv_chip_power9_isa_create;
|
2019-03-06 09:50:12 +01:00
|
|
|
k->dt_populate = pnv_chip_power9_dt_populate;
|
2019-03-06 09:50:13 +01:00
|
|
|
k->pic_print_info = pnv_chip_power9_pic_print_info;
|
2019-12-13 13:00:13 +01:00
|
|
|
k->xscom_core_base = pnv_chip_power9_xscom_core_base;
|
2019-12-13 13:00:35 +01:00
|
|
|
k->xscom_pcba = pnv_chip_power9_xscom_pcba;
|
2016-10-22 11:46:36 +02:00
|
|
|
dc->desc = "PowerNV Chip POWER9";
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
k->num_phbs = 6;
|
2018-06-18 19:05:39 +02:00
|
|
|
|
|
|
|
device_class_set_parent_realize(dc, pnv_chip_power9_realize,
|
|
|
|
&k->parent_realize);
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static void pnv_chip_power10_instance_init(Object *obj)
|
|
|
|
{
|
2019-12-05 19:44:53 +01:00
|
|
|
Pnv10Chip *chip10 = PNV10_CHIP(obj);
|
|
|
|
|
|
|
|
object_initialize_child(obj, "psi", &chip10->psi, sizeof(chip10->psi),
|
|
|
|
TYPE_PNV10_PSI, &error_abort, NULL);
|
2019-12-05 19:44:54 +01:00
|
|
|
object_initialize_child(obj, "lpc", &chip10->lpc, sizeof(chip10->lpc),
|
|
|
|
TYPE_PNV10_LPC, &error_abort, NULL);
|
2019-12-05 19:44:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
|
|
|
|
PnvChip *chip = PNV_CHIP(dev);
|
2019-12-05 19:44:53 +01:00
|
|
|
Pnv10Chip *chip10 = PNV10_CHIP(dev);
|
2019-12-05 19:44:51 +01:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
/* XSCOM bridge is first */
|
|
|
|
pnv_xscom_realize(chip, PNV10_XSCOM_SIZE, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip));
|
|
|
|
|
|
|
|
pcc->parent_realize(dev, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2019-12-05 19:44:53 +01:00
|
|
|
|
|
|
|
/* Processor Service Interface (PSI) Host Bridge */
|
|
|
|
object_property_set_int(OBJECT(&chip10->psi), PNV10_PSIHB_BASE(chip),
|
|
|
|
"bar", &error_fatal);
|
|
|
|
object_property_set_bool(OBJECT(&chip10->psi), true, "realized",
|
|
|
|
&local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pnv_xscom_add_subregion(chip, PNV10_XSCOM_PSIHB_BASE,
|
|
|
|
&PNV_PSI(&chip10->psi)->xscom_regs);
|
2019-12-05 19:44:54 +01:00
|
|
|
|
|
|
|
/* LPC */
|
|
|
|
object_property_set_link(OBJECT(&chip10->lpc), OBJECT(&chip10->psi), "psi",
|
|
|
|
&error_abort);
|
|
|
|
object_property_set_bool(OBJECT(&chip10->lpc), true, "realized",
|
|
|
|
&local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memory_region_add_subregion(get_system_memory(), PNV10_LPCM_BASE(chip),
|
|
|
|
&chip10->lpc.xscom_regs);
|
|
|
|
|
|
|
|
chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
|
|
|
|
(uint64_t) PNV10_LPCM_BASE(chip));
|
2019-12-05 19:44:51 +01:00
|
|
|
}
|
|
|
|
|
2019-12-13 13:00:35 +01:00
|
|
|
static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
|
|
|
|
{
|
|
|
|
addr &= (PNV10_XSCOM_SIZE - 1);
|
|
|
|
return addr >> 3;
|
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
PnvChipClass *k = PNV_CHIP_CLASS(klass);
|
|
|
|
|
|
|
|
k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
|
|
|
|
k->cores_mask = POWER10_CORE_MASK;
|
|
|
|
k->core_pir = pnv_chip_core_pir_p10;
|
|
|
|
k->intc_create = pnv_chip_power10_intc_create;
|
|
|
|
k->intc_reset = pnv_chip_power10_intc_reset;
|
|
|
|
k->intc_destroy = pnv_chip_power10_intc_destroy;
|
2019-12-13 13:00:07 +01:00
|
|
|
k->intc_print_info = pnv_chip_power10_intc_print_info;
|
2019-12-05 19:44:51 +01:00
|
|
|
k->isa_create = pnv_chip_power10_isa_create;
|
|
|
|
k->dt_populate = pnv_chip_power10_dt_populate;
|
|
|
|
k->pic_print_info = pnv_chip_power10_pic_print_info;
|
2019-12-13 13:00:13 +01:00
|
|
|
k->xscom_core_base = pnv_chip_power10_xscom_core_base;
|
2019-12-13 13:00:35 +01:00
|
|
|
k->xscom_pcba = pnv_chip_power10_xscom_pcba;
|
2019-12-05 19:44:51 +01:00
|
|
|
dc->desc = "PowerNV Chip POWER10";
|
|
|
|
|
|
|
|
device_class_set_parent_realize(dc, pnv_chip_power10_realize,
|
|
|
|
&k->parent_realize);
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:46:37 +02:00
|
|
|
static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
|
|
|
|
{
|
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
|
|
|
|
int cores_max;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No custom mask for this chip, let's use the default one from *
|
|
|
|
* the chip class
|
|
|
|
*/
|
|
|
|
if (!chip->cores_mask) {
|
|
|
|
chip->cores_mask = pcc->cores_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* filter alien core ids ! some are reserved */
|
|
|
|
if ((chip->cores_mask & pcc->cores_mask) != chip->cores_mask) {
|
|
|
|
error_setg(errp, "warning: invalid core mask for chip Ox%"PRIx64" !",
|
|
|
|
chip->cores_mask);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
chip->cores_mask &= pcc->cores_mask;
|
|
|
|
|
|
|
|
/* now that we have a sane layout, let check the number of cores */
|
2016-11-14 10:12:57 +01:00
|
|
|
cores_max = ctpop64(chip->cores_mask);
|
2016-10-22 11:46:37 +02:00
|
|
|
if (chip->nr_cores > cores_max) {
|
|
|
|
error_setg(errp, "warning: too many cores for chip ! Limit is %d",
|
|
|
|
cores_max);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-14 16:00:41 +02:00
|
|
|
static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
|
2016-10-22 11:46:36 +02:00
|
|
|
{
|
2016-10-22 11:46:37 +02:00
|
|
|
Error *error = NULL;
|
2016-10-22 11:46:39 +02:00
|
|
|
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
|
2017-10-09 21:51:10 +02:00
|
|
|
const char *typename = pnv_chip_core_typename(chip);
|
2016-10-22 11:46:39 +02:00
|
|
|
int i, core_hwid;
|
2020-01-27 15:41:54 +01:00
|
|
|
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
|
2016-10-22 11:46:39 +02:00
|
|
|
|
|
|
|
if (!object_class_by_name(typename)) {
|
|
|
|
error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-22 11:46:37 +02:00
|
|
|
|
2016-10-22 11:46:39 +02:00
|
|
|
/* Cores */
|
2016-10-22 11:46:37 +02:00
|
|
|
pnv_chip_core_sanitize(chip, &error);
|
|
|
|
if (error) {
|
|
|
|
error_propagate(errp, error);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-22 11:46:39 +02:00
|
|
|
|
2019-11-25 07:58:03 +01:00
|
|
|
chip->cores = g_new0(PnvCore *, chip->nr_cores);
|
2016-10-22 11:46:39 +02:00
|
|
|
|
|
|
|
for (i = 0, core_hwid = 0; (core_hwid < sizeof(chip->cores_mask) * 8)
|
|
|
|
&& (i < chip->nr_cores); core_hwid++) {
|
|
|
|
char core_name[32];
|
2019-11-25 07:58:03 +01:00
|
|
|
PnvCore *pnv_core;
|
2018-01-15 19:04:04 +01:00
|
|
|
uint64_t xscom_core_base;
|
2016-10-22 11:46:39 +02:00
|
|
|
|
|
|
|
if (!(chip->cores_mask & (1ull << core_hwid))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-11-25 07:58:03 +01:00
|
|
|
pnv_core = PNV_CORE(object_new(typename));
|
|
|
|
|
2016-10-22 11:46:39 +02:00
|
|
|
snprintf(core_name, sizeof(core_name), "core[%d]", core_hwid);
|
2019-11-25 07:58:03 +01:00
|
|
|
object_property_add_child(OBJECT(chip), core_name, OBJECT(pnv_core),
|
|
|
|
&error_abort);
|
|
|
|
chip->cores[i] = pnv_core;
|
2020-01-06 15:56:39 +01:00
|
|
|
object_property_set_int(OBJECT(pnv_core), chip->nr_threads,
|
|
|
|
"nr-threads", &error_fatal);
|
2016-10-22 11:46:39 +02:00
|
|
|
object_property_set_int(OBJECT(pnv_core), core_hwid,
|
|
|
|
CPU_CORE_PROP_CORE_ID, &error_fatal);
|
|
|
|
object_property_set_int(OBJECT(pnv_core),
|
|
|
|
pcc->core_pir(chip, core_hwid),
|
|
|
|
"pir", &error_fatal);
|
2020-01-27 15:41:54 +01:00
|
|
|
object_property_set_int(OBJECT(pnv_core), pnv->fw_load_addr,
|
|
|
|
"hrmor", &error_fatal);
|
2019-11-15 16:56:00 +01:00
|
|
|
object_property_set_link(OBJECT(pnv_core), OBJECT(chip), "chip",
|
|
|
|
&error_abort);
|
2016-10-22 11:46:39 +02:00
|
|
|
object_property_set_bool(OBJECT(pnv_core), true, "realized",
|
|
|
|
&error_fatal);
|
2016-10-22 11:46:41 +02:00
|
|
|
|
|
|
|
/* Each core has an XSCOM MMIO region */
|
2019-12-13 13:00:13 +01:00
|
|
|
xscom_core_base = pcc->xscom_core_base(chip, core_hwid);
|
2018-01-15 19:04:04 +01:00
|
|
|
|
|
|
|
pnv_xscom_add_subregion(chip, xscom_core_base,
|
2019-11-25 07:58:03 +01:00
|
|
|
&pnv_core->xscom_regs);
|
2016-10-22 11:46:39 +02:00
|
|
|
i++;
|
|
|
|
}
|
2018-06-14 16:00:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_chip_realize(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
PnvChip *chip = PNV_CHIP(dev);
|
|
|
|
Error *error = NULL;
|
|
|
|
|
|
|
|
/* Cores */
|
|
|
|
pnv_chip_core_realize(chip, &error);
|
|
|
|
if (error) {
|
|
|
|
error_propagate(errp, error);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-22 11:46:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static Property pnv_chip_properties[] = {
|
|
|
|
DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
|
|
|
|
DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
|
|
|
|
DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
|
2016-10-22 11:46:37 +02:00
|
|
|
DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
|
|
|
|
DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
|
2020-01-06 15:56:39 +01:00
|
|
|
DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
|
ppc/pnv: Add models for POWER9 PHB4 PCIe Host bridge
These changes introduces models for the PCIe Host Bridge (PHB4) of the
POWER9 processor. It includes the PowerBus logic interface (PBCQ),
IOMMU support, a single PCIe Gen.4 Root Complex, and support for MSI
and LSI interrupt sources as found on a POWER9 system using the XIVE
interrupt controller.
POWER9 processor comes with 3 PHB4 PEC (PCI Express Controller) and
each PEC can have several PHBs. By default,
* PEC0 provides 1 PHB (PHB0)
* PEC1 provides 2 PHBs (PHB1 and PHB2)
* PEC2 provides 3 PHBs (PHB3, PHB4 and PHB5)
Each PEC has a set "global" registers and some "per-stack" (per-PHB)
registers. Those are organized in two XSCOM ranges, the "Nest" range
and the "PCI" range, each range contains both some "PEC" registers and
some "per-stack" registers.
No default device layout is provided and PCI devices can be added on
any of the available PCIe Root Port (pcie.0 .. 2 of a Power9 chip)
with address 0x0 as the firwware (skiboot) only accepts a single
device per root port. To run a simple system with a network and a
storage adapters, use a command line options such as :
-device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
-netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
-device megasas,id=scsi0,bus=pcie.1,addr=0x0
-drive file=$disk,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
-device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
If more are needed, include a bridge.
Multi chip is supported, each chip adding its set of PHB4 controllers
and its PCI busses. The model doesn't emulate the EEH error handling.
This model is not ready for hotplug yet.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[ clg: - numerous cleanups
- commit log
- fix for broken LSI support
- PHB pic printinfo
- large QOM rework ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200127144506.11132-2-clg@kaod.org>
[dwg: Use device_class_set_props()]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-01-27 15:45:05 +01:00
|
|
|
DEFINE_PROP_UINT32("num-phbs", PnvChip, num_phbs, 0),
|
2016-10-22 11:46:36 +02:00
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void pnv_chip_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
|
2017-03-09 19:37:53 +01:00
|
|
|
set_bit(DEVICE_CATEGORY_CPU, dc->categories);
|
2016-10-22 11:46:36 +02:00
|
|
|
dc->realize = pnv_chip_realize;
|
2020-01-10 16:30:32 +01:00
|
|
|
device_class_set_props(dc, pnv_chip_properties);
|
2016-10-22 11:46:36 +02:00
|
|
|
dc->desc = "PowerNV Chip";
|
|
|
|
}
|
|
|
|
|
2019-11-25 07:58:07 +01:00
|
|
|
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < chip->nr_cores; i++) {
|
|
|
|
PnvCore *pc = chip->cores[i];
|
|
|
|
CPUCore *cc = CPU_CORE(pc);
|
|
|
|
|
|
|
|
for (j = 0; j < cc->nr_threads; j++) {
|
|
|
|
if (ppc_cpu_pir(pc->threads[j]) == pir) {
|
|
|
|
return pc->threads[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-04-05 14:41:26 +02:00
|
|
|
static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
|
|
|
|
{
|
2017-12-15 14:56:01 +01:00
|
|
|
PnvMachineState *pnv = PNV_MACHINE(xi);
|
2020-01-27 15:45:06 +01:00
|
|
|
int i, j;
|
2017-04-05 14:41:26 +02:00
|
|
|
|
|
|
|
for (i = 0; i < pnv->num_chips; i++) {
|
2020-01-27 15:45:06 +01:00
|
|
|
PnvChip *chip = pnv->chips[i];
|
2018-06-18 19:05:39 +02:00
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
|
|
|
|
|
|
|
|
if (ics_valid_irq(&chip8->psi.ics, irq)) {
|
|
|
|
return &chip8->psi.ics;
|
2017-04-05 14:41:26 +02:00
|
|
|
}
|
2020-01-27 15:45:06 +01:00
|
|
|
for (j = 0; j < chip->num_phbs; j++) {
|
|
|
|
if (ics_valid_irq(&chip8->phbs[j].lsis, irq)) {
|
|
|
|
return &chip8->phbs[j].lsis;
|
|
|
|
}
|
|
|
|
if (ics_valid_irq(ICS(&chip8->phbs[j].msis), irq)) {
|
|
|
|
return ICS(&chip8->phbs[j].msis);
|
|
|
|
}
|
|
|
|
}
|
2017-04-05 14:41:26 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_ics_resend(XICSFabric *xi)
|
|
|
|
{
|
2017-12-15 14:56:01 +01:00
|
|
|
PnvMachineState *pnv = PNV_MACHINE(xi);
|
2020-01-27 15:45:06 +01:00
|
|
|
int i, j;
|
2017-04-05 14:41:26 +02:00
|
|
|
|
|
|
|
for (i = 0; i < pnv->num_chips; i++) {
|
2020-01-27 15:45:06 +01:00
|
|
|
PnvChip *chip = pnv->chips[i];
|
2018-06-18 19:05:39 +02:00
|
|
|
Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
|
2020-01-27 15:45:06 +01:00
|
|
|
|
2018-06-18 19:05:39 +02:00
|
|
|
ics_resend(&chip8->psi.ics);
|
2020-01-27 15:45:06 +01:00
|
|
|
for (j = 0; j < chip->num_phbs; j++) {
|
|
|
|
ics_resend(&chip8->phbs[j].lsis);
|
|
|
|
ics_resend(ICS(&chip8->phbs[j].msis));
|
|
|
|
}
|
2017-04-05 14:41:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-03 09:46:01 +02:00
|
|
|
static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
|
|
|
|
|
2019-03-06 09:50:10 +01:00
|
|
|
return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL;
|
2017-04-03 09:46:01 +02:00
|
|
|
}
|
|
|
|
|
2017-04-03 09:46:02 +02:00
|
|
|
static void pnv_pic_print_info(InterruptStatsProvider *obj,
|
|
|
|
Monitor *mon)
|
|
|
|
{
|
2017-12-15 14:56:01 +01:00
|
|
|
PnvMachineState *pnv = PNV_MACHINE(obj);
|
2017-04-05 14:41:26 +02:00
|
|
|
int i;
|
2017-04-03 09:46:02 +02:00
|
|
|
CPUState *cs;
|
|
|
|
|
|
|
|
CPU_FOREACH(cs) {
|
|
|
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
|
|
|
|
2019-12-13 13:00:07 +01:00
|
|
|
/* XXX: loop on each chip/core/thread instead of CPU_FOREACH() */
|
|
|
|
PNV_CHIP_GET_CLASS(pnv->chips[0])->intc_print_info(pnv->chips[0], cpu,
|
|
|
|
mon);
|
2017-04-03 09:46:02 +02:00
|
|
|
}
|
2017-04-05 14:41:26 +02:00
|
|
|
|
|
|
|
for (i = 0; i < pnv->num_chips; i++) {
|
2019-03-06 09:50:13 +01:00
|
|
|
PNV_CHIP_GET_CLASS(pnv->chips[i])->pic_print_info(pnv->chips[i], mon);
|
2017-04-05 14:41:26 +02:00
|
|
|
}
|
2017-04-03 09:46:02 +02:00
|
|
|
}
|
|
|
|
|
2019-11-25 07:58:09 +01:00
|
|
|
static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
|
|
|
|
uint8_t nvt_blk, uint32_t nvt_idx,
|
|
|
|
bool cam_ignore, uint8_t priority,
|
|
|
|
uint32_t logic_serv,
|
|
|
|
XiveTCTXMatch *match)
|
|
|
|
{
|
|
|
|
PnvMachineState *pnv = PNV_MACHINE(xfb);
|
|
|
|
int total_count = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pnv->num_chips; i++) {
|
|
|
|
Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
|
|
|
|
XivePresenter *xptr = XIVE_PRESENTER(&chip9->xive);
|
|
|
|
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
|
|
|
|
int count;
|
|
|
|
|
|
|
|
count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
|
|
|
|
priority, logic_serv, match);
|
|
|
|
|
|
|
|
if (count < 0) {
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_count += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return total_count;
|
|
|
|
}
|
|
|
|
|
2019-07-31 16:12:16 +02:00
|
|
|
static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
|
2016-10-22 11:46:35 +02:00
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
2017-04-03 09:46:01 +02:00
|
|
|
XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
|
2019-12-13 12:59:50 +01:00
|
|
|
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
|
|
|
|
static const char compat[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
|
2019-07-31 16:12:16 +02:00
|
|
|
|
|
|
|
mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
|
|
|
|
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
|
|
|
|
|
|
|
|
xic->icp_get = pnv_icp_get;
|
|
|
|
xic->ics_get = pnv_ics_get;
|
|
|
|
xic->ics_resend = pnv_ics_resend;
|
2019-12-13 12:59:50 +01:00
|
|
|
|
|
|
|
pmc->compat = compat;
|
|
|
|
pmc->compat_size = sizeof(compat);
|
2019-07-31 16:12:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
2019-11-25 07:58:09 +01:00
|
|
|
XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
|
2019-12-13 12:59:50 +01:00
|
|
|
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
|
|
|
|
static const char compat[] = "qemu,powernv9\0ibm,powernv";
|
2019-07-31 16:12:16 +02:00
|
|
|
|
|
|
|
mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
|
|
|
|
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
|
2019-11-25 07:58:09 +01:00
|
|
|
xfc->match_nvt = pnv_match_nvt;
|
2019-07-31 16:12:16 +02:00
|
|
|
|
|
|
|
mc->alias = "powernv";
|
2019-12-13 12:59:50 +01:00
|
|
|
|
|
|
|
pmc->compat = compat;
|
|
|
|
pmc->compat_size = sizeof(compat);
|
2019-12-13 12:59:56 +01:00
|
|
|
pmc->dt_power_mgt = pnv_dt_power_mgt;
|
2019-07-31 16:12:16 +02:00
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
2019-12-13 12:59:50 +01:00
|
|
|
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
|
|
|
|
static const char compat[] = "qemu,powernv10\0ibm,powernv";
|
2019-12-05 19:44:51 +01:00
|
|
|
|
|
|
|
mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
|
|
|
|
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v1.0");
|
2019-12-13 12:59:50 +01:00
|
|
|
|
|
|
|
pmc->compat = compat;
|
|
|
|
pmc->compat_size = sizeof(compat);
|
2019-12-13 12:59:56 +01:00
|
|
|
pmc->dt_power_mgt = pnv_dt_power_mgt;
|
2019-12-05 19:44:51 +01:00
|
|
|
}
|
|
|
|
|
2020-01-27 15:41:54 +01:00
|
|
|
static bool pnv_machine_get_hb(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
PnvMachineState *pnv = PNV_MACHINE(obj);
|
|
|
|
|
|
|
|
return !!pnv->fw_load_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
PnvMachineState *pnv = PNV_MACHINE(obj);
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
pnv->fw_load_addr = 0x8000000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-31 16:12:16 +02:00
|
|
|
static void pnv_machine_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
2017-04-03 09:46:02 +02:00
|
|
|
InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
|
2016-10-22 11:46:35 +02:00
|
|
|
|
|
|
|
mc->desc = "IBM PowerNV (Non-Virtualized)";
|
2017-12-15 14:56:01 +01:00
|
|
|
mc->init = pnv_init;
|
|
|
|
mc->reset = pnv_reset;
|
2016-10-22 11:46:35 +02:00
|
|
|
mc->max_cpus = MAX_CPUS;
|
2019-09-11 16:29:25 +02:00
|
|
|
/* Pnv provides a AHCI device for storage */
|
|
|
|
mc->block_default_type = IF_IDE;
|
2016-10-22 11:46:35 +02:00
|
|
|
mc->no_parallel = 1;
|
|
|
|
mc->default_boot_order = NULL;
|
2019-08-21 05:09:45 +02:00
|
|
|
/*
|
|
|
|
* RAM defaults to less than 2048 for 32-bit hosts, and large
|
|
|
|
* enough to fit the maximum initrd size at it's load address
|
|
|
|
*/
|
|
|
|
mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE;
|
2020-02-19 17:09:36 +01:00
|
|
|
mc->default_ram_id = "pnv.ram";
|
2017-04-03 09:46:02 +02:00
|
|
|
ispc->print_info = pnv_pic_print_info;
|
2020-01-27 15:41:54 +01:00
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "hb-mode",
|
|
|
|
pnv_machine_get_hb, pnv_machine_set_hb,
|
|
|
|
&error_abort);
|
|
|
|
object_class_property_set_description(oc, "hb-mode",
|
|
|
|
"Use a hostboot like boot loader",
|
|
|
|
NULL);
|
2016-10-22 11:46:35 +02:00
|
|
|
}
|
|
|
|
|
2018-06-18 19:05:39 +02:00
|
|
|
#define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
|
|
|
|
{ \
|
|
|
|
.name = type, \
|
|
|
|
.class_init = class_initfn, \
|
|
|
|
.parent = TYPE_PNV8_CHIP, \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
|
|
|
|
{ \
|
|
|
|
.name = type, \
|
|
|
|
.class_init = class_initfn, \
|
|
|
|
.parent = TYPE_PNV9_CHIP, \
|
2017-10-09 21:51:11 +02:00
|
|
|
}
|
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
#define DEFINE_PNV10_CHIP_TYPE(type, class_initfn) \
|
|
|
|
{ \
|
|
|
|
.name = type, \
|
|
|
|
.class_init = class_initfn, \
|
|
|
|
.parent = TYPE_PNV10_CHIP, \
|
|
|
|
}
|
|
|
|
|
2017-10-09 21:51:11 +02:00
|
|
|
static const TypeInfo types[] = {
|
2019-12-05 19:44:51 +01:00
|
|
|
{
|
|
|
|
.name = MACHINE_TYPE_NAME("powernv10"),
|
|
|
|
.parent = TYPE_PNV_MACHINE,
|
|
|
|
.class_init = pnv_machine_power10_class_init,
|
|
|
|
},
|
2019-10-03 16:36:17 +02:00
|
|
|
{
|
|
|
|
.name = MACHINE_TYPE_NAME("powernv9"),
|
|
|
|
.parent = TYPE_PNV_MACHINE,
|
|
|
|
.class_init = pnv_machine_power9_class_init,
|
2019-11-25 07:58:09 +01:00
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_XIVE_FABRIC },
|
|
|
|
{ },
|
|
|
|
},
|
2019-10-03 16:36:17 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = MACHINE_TYPE_NAME("powernv8"),
|
|
|
|
.parent = TYPE_PNV_MACHINE,
|
|
|
|
.class_init = pnv_machine_power8_class_init,
|
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_XICS_FABRIC },
|
|
|
|
{ },
|
|
|
|
},
|
|
|
|
},
|
2017-10-09 21:51:11 +02:00
|
|
|
{
|
2017-12-15 14:56:01 +01:00
|
|
|
.name = TYPE_PNV_MACHINE,
|
2017-10-09 21:51:11 +02:00
|
|
|
.parent = TYPE_MACHINE,
|
2019-07-31 16:12:16 +02:00
|
|
|
.abstract = true,
|
2017-10-09 21:51:11 +02:00
|
|
|
.instance_size = sizeof(PnvMachineState),
|
2017-12-15 14:56:01 +01:00
|
|
|
.class_init = pnv_machine_class_init,
|
2019-12-13 12:59:50 +01:00
|
|
|
.class_size = sizeof(PnvMachineClass),
|
2017-10-09 21:51:11 +02:00
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
|
|
|
{ },
|
|
|
|
},
|
2017-04-03 09:46:01 +02:00
|
|
|
},
|
2017-10-09 21:51:11 +02:00
|
|
|
{
|
|
|
|
.name = TYPE_PNV_CHIP,
|
|
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
|
|
|
.class_init = pnv_chip_class_init,
|
|
|
|
.instance_size = sizeof(PnvChip),
|
|
|
|
.class_size = sizeof(PnvChipClass),
|
|
|
|
.abstract = true,
|
|
|
|
},
|
2018-06-18 19:05:39 +02:00
|
|
|
|
2019-12-05 19:44:51 +01:00
|
|
|
/*
|
|
|
|
* P10 chip and variants
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
.name = TYPE_PNV10_CHIP,
|
|
|
|
.parent = TYPE_PNV_CHIP,
|
|
|
|
.instance_init = pnv_chip_power10_instance_init,
|
|
|
|
.instance_size = sizeof(Pnv10Chip),
|
|
|
|
},
|
|
|
|
DEFINE_PNV10_CHIP_TYPE(TYPE_PNV_CHIP_POWER10, pnv_chip_power10_class_init),
|
|
|
|
|
2018-06-18 19:05:39 +02:00
|
|
|
/*
|
|
|
|
* P9 chip and variants
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
.name = TYPE_PNV9_CHIP,
|
|
|
|
.parent = TYPE_PNV_CHIP,
|
|
|
|
.instance_init = pnv_chip_power9_instance_init,
|
|
|
|
.instance_size = sizeof(Pnv9Chip),
|
|
|
|
},
|
|
|
|
DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
|
|
|
|
|
|
|
|
/*
|
|
|
|
* P8 chip and variants
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
.name = TYPE_PNV8_CHIP,
|
|
|
|
.parent = TYPE_PNV_CHIP,
|
|
|
|
.instance_init = pnv_chip_power8_instance_init,
|
|
|
|
.instance_size = sizeof(Pnv8Chip),
|
|
|
|
},
|
|
|
|
DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
|
|
|
|
DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
|
|
|
|
DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
|
|
|
|
pnv_chip_power8nvl_class_init),
|
2016-10-22 11:46:35 +02:00
|
|
|
};
|
|
|
|
|
2017-10-09 21:51:11 +02:00
|
|
|
DEFINE_TYPES(types)
|