Merge tag 'pull-ppc-for-9.0-20240224' of https://gitlab.com/npiggin/qemu into staging

* Avocado tests for ppc64 to boot FreeBSD, run guests with emulated
  or nested hypervisor facilities, among other things.
* Update ppc64 CPU defaults to Power10.
* Add a new powernv10-rainier machine to better capture differences
  between the different Power10 systems.
* Implement more device models for powernv.
* 4xx TLB flushing performance and correctness improvements.
* Correct gdb implementation to access some important SPRs.
* Misc cleanups and bug fixes.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEETkN92lZhb0MpsKeVZ7MCdqhiHK4FAmXYuX0ACgkQZ7MCdqhi
# HK6t1Q/9Hxw+MseFUa/6sbWX6mhv/8emrFFOwI9qxapxDoMyic+SjIhR5PPCYh6t
# TLE1vJiV54XYB3286hz3eQfDxfHNjkgsF7PYp9SEd6D1rMT9ESxeu5NkifenEfP0
# UoTFXJyfg/OF1h+JQRrVv1m+D4mqGGNCQB4QiU3DYTmRhrhp7H3mKfUX/KvkEwiX
# EqZibmrqb9SVSjT66LBQzY328mEH4nipF33QtYKfYjb6kMe8ACSznL2VYP0NmacU
# T+3eHJeLtOLeRlHwYfADx2ekRHlsJuE9/fMMHJHb2qxJkHSQ7yGBqSLESAe6kNP8
# TnKJ9x4433K7IjFqaoiDONrMVJbVZDh/DUh1WWdY14iiUOYEy7uLkLtmThmNSyUB
# 622Rd5Ch09JWzA/tg1aC9mR2f9boe9/Z1VeHeN8j+sVj1e6MEh8un8SER3X+9TDz
# myGLsmPXQnu1yjebycuE+9RAPbR9npOAkQpE5ZfDwjUM7y4s4jzZUKUoIhtCXeEF
# eIykVnaGbPlEBGpuf+E+w2ZxhZUIfxRUhuunK8Ib4TE8khJn/Ir4BxoLweSnqtKM
# O4xiFvHm72RUVK232Kox5HWbFJ8XSLBUb3ABNGbXXynzAMD+THB4ImFBbysOmIkR
# xcF1tWQ+xoMMcCxbx73b0PhO5AR/PgYc2ctug9rAc9fh4ypJLEs=
# =LZzb
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 23 Feb 2024 15:27:57 GMT
# gpg:                using RSA key 4E437DDA56616F4329B0A79567B30276A8621CAE
# gpg: Good signature from "Nicholas Piggin <npiggin@gmail.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 4E43 7DDA 5661 6F43 29B0  A795 67B3 0276 A862 1CAE

* tag 'pull-ppc-for-9.0-20240224' of https://gitlab.com/npiggin/qemu: (47 commits)
  target/ppc: optimise ppcemb_tlb_t flushing
  target/ppc: 440 optimise tlbwe TLB flushing
  target/ppc: 4xx optimise tlbwe_lo TLB flushing
  target/ppc: 4xx don't flush TLB for a newly written software TLB entry
  target/ppc: Factor out 4xx ppcemb_tlb_t flushing
  target/ppc: Fix 440 tlbwe TLB invalidation gaps
  target/ppc: Add SMT support to time facilities
  target/ppc: Implement core timebase state machine and TFMR
  ppc/pnv: Implement the ChipTOD to Core transfer
  ppc/pnv: Wire ChipTOD model to powernv9 and powernv10 machines
  ppc/pnv: Add POWER9/10 chiptod model
  target/ppc: Fix move-to timebase SPR access permissions
  target/ppc: Improve timebase register defines naming
  target/ppc: Rename TBL to TB on 64-bit
  target/ppc: Update gdbstub to read SPR's CFAR, DEC, HDEC, TB-L/U
  hw/ppc: N1 chiplet wiring
  hw/ppc: Add N1 chiplet model
  hw/ppc: Add pnv nest pervasive common chiplet model
  ppc/pnv: Test pnv i2c master and connected devices
  ppc/pnv: Add a pca9554 I2C device to powernv10-rainier
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2024-02-23 18:59:11 +00:00
54 changed files with 3318 additions and 352 deletions
+9 -2
View File
@@ -1170,9 +1170,7 @@ R: Joel Stanley <joel@jms.id.au>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/*aspeed*
F: hw/misc/pca9552.c
F: include/hw/*/*aspeed*
F: include/hw/misc/pca9552*.h
F: hw/net/ftgmac100.c
F: include/hw/net/ftgmac100.h
F: docs/system/arm/aspeed.rst
@@ -1526,6 +1524,7 @@ F: tests/qtest/libqos/*spapr*
F: tests/qtest/rtas*
F: tests/qtest/libqos/rtas*
F: tests/avocado/ppc_pseries.py
F: tests/avocado/ppc_hv_tests.py
PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org>
@@ -1543,6 +1542,14 @@ F: include/hw/pci-host/pnv*
F: pc-bios/skiboot.lid
F: tests/qtest/pnv*
pca955x
M: Glenn Miles <milesg@linux.vnet.ibm.com>
L: qemu-ppc@nongnu.org
L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/misc/pca955*.c
F: include/hw/misc/pca955*.h
virtex_ml507
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
L: qemu-ppc@nongnu.org
+8
View File
@@ -229,6 +229,14 @@ The Nios II architecture is orphan.
The machine is no longer in existence and has been long unmaintained
in QEMU. This also holds for the TC51828 16MiB flash that it uses.
``pseries-2.1`` up to ``pseries-2.11`` (since 9.0)
''''''''''''''''''''''''''''''''''''''''''''''''''
Older pseries machines before version 2.12 have undergone many changes
to correct issues, mostly regarding migration compatibility. These are
no longer maintained and removing them will make the code easier to
read and maintain. Use versions 2.12 and above as a replacement.
Backend options
---------------
+11
View File
@@ -1346,6 +1346,17 @@ the environment.
The definition of *large* is a bit arbitrary here, but it usually means an
asset which occupies at least 1GB of size on disk when uncompressed.
SPEED
^^^^^
Tests which have a long runtime will not be run unless ``SPEED=slow`` is
exported on the environment.
The definition of *long* is a bit arbitrary here, and it depends on the
usefulness of the test too. A unique test is worth spending more time on,
small variations on existing tests perhaps less so. As a rough guide,
a test or set of similar tests which take more than 100 seconds to
complete.
AVOCADO_ALLOW_UNTRUSTED_CODE
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are tests which will boot a kernel image or firmware that can be
+4
View File
@@ -34,6 +34,10 @@ config PCA9552
bool
depends on I2C
config PCA9554
bool
depends on I2C
config I2C_ECHO
bool
default y if TEST_DEVICES
+1
View File
@@ -4,6 +4,7 @@ system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmcoreinfo.c'))
system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c'))
system_ss.add(when: 'CONFIG_ISA_TESTDEV', if_true: files('pc-testdev.c'))
system_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c'))
system_ss.add(when: 'CONFIG_PCA9554', if_true: files('pca9554.c'))
system_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c'))
system_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
system_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
+51 -7
View File
@@ -36,11 +36,16 @@ typedef struct PCA955xClass PCA955xClass;
DECLARE_CLASS_CHECKERS(PCA955xClass, PCA955X,
TYPE_PCA955X)
/*
* Note: The LED_ON and LED_OFF configuration values for the PCA955X
* chips are the reverse of the PCA953X family of chips.
*/
#define PCA9552_LED_ON 0x0
#define PCA9552_LED_OFF 0x1
#define PCA9552_LED_PWM0 0x2
#define PCA9552_LED_PWM1 0x3
#define PCA9552_PIN_LOW 0x0
#define PCA9552_PIN_HIZ 0x1
static const char *led_state[] = {"on", "off", "pwm0", "pwm1"};
@@ -107,17 +112,27 @@ static void pca955x_update_pin_input(PCA955xState *s)
for (i = 0; i < k->pin_count; i++) {
uint8_t input_reg = PCA9552_INPUT0 + (i / 8);
uint8_t input_shift = (i % 8);
uint8_t bit_mask = 1 << (i % 8);
uint8_t config = pca955x_pin_get_config(s, i);
uint8_t old_value = s->regs[input_reg] & bit_mask;
uint8_t new_value;
switch (config) {
case PCA9552_LED_ON:
qemu_set_irq(s->gpio[i], 1);
s->regs[input_reg] |= 1 << input_shift;
/* Pin is set to 0V to turn on LED */
s->regs[input_reg] &= ~bit_mask;
break;
case PCA9552_LED_OFF:
qemu_set_irq(s->gpio[i], 0);
s->regs[input_reg] &= ~(1 << input_shift);
/*
* Pin is set to Hi-Z to turn off LED and
* pullup sets it to a logical 1 unless
* external device drives it low.
*/
if (s->ext_state[i] == PCA9552_PIN_LOW) {
s->regs[input_reg] &= ~bit_mask;
} else {
s->regs[input_reg] |= bit_mask;
}
break;
case PCA9552_LED_PWM0:
case PCA9552_LED_PWM1:
@@ -125,6 +140,12 @@ static void pca955x_update_pin_input(PCA955xState *s)
default:
break;
}
/* update irq state only if pin state changed */
new_value = s->regs[input_reg] & bit_mask;
if (new_value != old_value) {
qemu_set_irq(s->gpio_out[i], !!new_value);
}
}
}
@@ -332,6 +353,7 @@ static const VMStateDescription pca9552_vmstate = {
VMSTATE_UINT8(len, PCA955xState),
VMSTATE_UINT8(pointer, PCA955xState),
VMSTATE_UINT8_ARRAY(regs, PCA955xState, PCA955X_NR_REGS),
VMSTATE_UINT8_ARRAY(ext_state, PCA955xState, PCA955X_PIN_COUNT_MAX),
VMSTATE_I2C_SLAVE(i2c, PCA955xState),
VMSTATE_END_OF_LIST()
}
@@ -350,6 +372,7 @@ static void pca9552_reset(DeviceState *dev)
s->regs[PCA9552_LS2] = 0x55;
s->regs[PCA9552_LS3] = 0x55;
memset(s->ext_state, PCA9552_PIN_HIZ, PCA955X_PIN_COUNT_MAX);
pca955x_update_pin_input(s);
s->pointer = 0xFF;
@@ -372,6 +395,26 @@ static void pca955x_initfn(Object *obj)
}
}
static void pca955x_set_ext_state(PCA955xState *s, int pin, int level)
{
if (s->ext_state[pin] != level) {
uint16_t pins_status = pca955x_pins_get_status(s);
s->ext_state[pin] = level;
pca955x_update_pin_input(s);
pca955x_display_pins_status(s, pins_status);
}
}
static void pca955x_gpio_in_handler(void *opaque, int pin, int level)
{
PCA955xState *s = PCA955X(opaque);
PCA955xClass *k = PCA955X_GET_CLASS(s);
assert((pin >= 0) && (pin < k->pin_count));
pca955x_set_ext_state(s, pin, level);
}
static void pca955x_realize(DeviceState *dev, Error **errp)
{
PCA955xClass *k = PCA955X_GET_CLASS(dev);
@@ -381,7 +424,8 @@ static void pca955x_realize(DeviceState *dev, Error **errp)
s->description = g_strdup("pca-unspecified");
}
qdev_init_gpio_out(dev, s->gpio, k->pin_count);
qdev_init_gpio_out(dev, s->gpio_out, k->pin_count);
qdev_init_gpio_in(dev, pca955x_gpio_in_handler, k->pin_count);
}
static Property pca955x_properties[] = {
+328
View File
@@ -0,0 +1,328 @@
/*
* PCA9554 I/O port
*
* Copyright (c) 2023, IBM Corporation.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/bitops.h"
#include "hw/qdev-properties.h"
#include "hw/misc/pca9554.h"
#include "hw/misc/pca9554_regs.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "trace.h"
#include "qom/object.h"
struct PCA9554Class {
/*< private >*/
I2CSlaveClass parent_class;
/*< public >*/
};
typedef struct PCA9554Class PCA9554Class;
DECLARE_CLASS_CHECKERS(PCA9554Class, PCA9554,
TYPE_PCA9554)
#define PCA9554_PIN_LOW 0x0
#define PCA9554_PIN_HIZ 0x1
static const char *pin_state[] = {"low", "high"};
static void pca9554_update_pin_input(PCA9554State *s)
{
int i;
uint8_t config = s->regs[PCA9554_CONFIG];
uint8_t output = s->regs[PCA9554_OUTPUT];
uint8_t internal_state = config | output;
for (i = 0; i < PCA9554_PIN_COUNT; i++) {
uint8_t bit_mask = 1 << i;
uint8_t internal_pin_state = (internal_state >> i) & 0x1;
uint8_t old_value = s->regs[PCA9554_INPUT] & bit_mask;
uint8_t new_value;
switch (internal_pin_state) {
case PCA9554_PIN_LOW:
s->regs[PCA9554_INPUT] &= ~bit_mask;
break;
case PCA9554_PIN_HIZ:
/*
* pullup sets it to a logical 1 unless
* external device drives it low.
*/
if (s->ext_state[i] == PCA9554_PIN_LOW) {
s->regs[PCA9554_INPUT] &= ~bit_mask;
} else {
s->regs[PCA9554_INPUT] |= bit_mask;
}
break;
default:
break;
}
/* update irq state only if pin state changed */
new_value = s->regs[PCA9554_INPUT] & bit_mask;
if (new_value != old_value) {
if (new_value) {
/* changed from 0 to 1 */
qemu_set_irq(s->gpio_out[i], 1);
} else {
/* changed from 1 to 0 */
qemu_set_irq(s->gpio_out[i], 0);
}
}
}
}
static uint8_t pca9554_read(PCA9554State *s, uint8_t reg)
{
switch (reg) {
case PCA9554_INPUT:
return s->regs[PCA9554_INPUT] ^ s->regs[PCA9554_POLARITY];
case PCA9554_OUTPUT:
case PCA9554_POLARITY:
case PCA9554_CONFIG:
return s->regs[reg];
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected read to register %d\n",
__func__, reg);
return 0xFF;
}
}
static void pca9554_write(PCA9554State *s, uint8_t reg, uint8_t data)
{
switch (reg) {
case PCA9554_OUTPUT:
case PCA9554_CONFIG:
s->regs[reg] = data;
pca9554_update_pin_input(s);
break;
case PCA9554_POLARITY:
s->regs[reg] = data;
break;
case PCA9554_INPUT:
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected write to register %d\n",
__func__, reg);
}
}
static uint8_t pca9554_recv(I2CSlave *i2c)
{
PCA9554State *s = PCA9554(i2c);
uint8_t ret;
ret = pca9554_read(s, s->pointer & 0x3);
return ret;
}
static int pca9554_send(I2CSlave *i2c, uint8_t data)
{
PCA9554State *s = PCA9554(i2c);
/* First byte sent by is the register address */
if (s->len == 0) {
s->pointer = data;
s->len++;
} else {
pca9554_write(s, s->pointer & 0x3, data);
}
return 0;
}
static int pca9554_event(I2CSlave *i2c, enum i2c_event event)
{
PCA9554State *s = PCA9554(i2c);
s->len = 0;
return 0;
}
static void pca9554_get_pin(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
PCA9554State *s = PCA9554(obj);
int pin, rc;
uint8_t state;
rc = sscanf(name, "pin%2d", &pin);
if (rc != 1) {
error_setg(errp, "%s: error reading %s", __func__, name);
return;
}
if (pin < 0 || pin > PCA9554_PIN_COUNT) {
error_setg(errp, "%s invalid pin %s", __func__, name);
return;
}
state = pca9554_read(s, PCA9554_CONFIG);
state |= pca9554_read(s, PCA9554_OUTPUT);
state = (state >> pin) & 0x1;
visit_type_str(v, name, (char **)&pin_state[state], errp);
}
static void pca9554_set_pin(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
PCA9554State *s = PCA9554(obj);
int pin, rc, val;
uint8_t state, mask;
char *state_str;
if (!visit_type_str(v, name, &state_str, errp)) {
return;
}
rc = sscanf(name, "pin%2d", &pin);
if (rc != 1) {
error_setg(errp, "%s: error reading %s", __func__, name);
return;
}
if (pin < 0 || pin > PCA9554_PIN_COUNT) {
error_setg(errp, "%s invalid pin %s", __func__, name);
return;
}
for (state = 0; state < ARRAY_SIZE(pin_state); state++) {
if (!strcmp(state_str, pin_state[state])) {
break;
}
}
if (state >= ARRAY_SIZE(pin_state)) {
error_setg(errp, "%s invalid pin state %s", __func__, state_str);
return;
}
/* First, modify the output register bit */
val = pca9554_read(s, PCA9554_OUTPUT);
mask = 0x1 << pin;
if (state == PCA9554_PIN_LOW) {
val &= ~(mask);
} else {
val |= mask;
}
pca9554_write(s, PCA9554_OUTPUT, val);
/* Then, clear the config register bit for output mode */
val = pca9554_read(s, PCA9554_CONFIG);
val &= ~mask;
pca9554_write(s, PCA9554_CONFIG, val);
}
static const VMStateDescription pca9554_vmstate = {
.name = "PCA9554",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT8(len, PCA9554State),
VMSTATE_UINT8(pointer, PCA9554State),
VMSTATE_UINT8_ARRAY(regs, PCA9554State, PCA9554_NR_REGS),
VMSTATE_UINT8_ARRAY(ext_state, PCA9554State, PCA9554_PIN_COUNT),
VMSTATE_I2C_SLAVE(i2c, PCA9554State),
VMSTATE_END_OF_LIST()
}
};
static void pca9554_reset(DeviceState *dev)
{
PCA9554State *s = PCA9554(dev);
s->regs[PCA9554_INPUT] = 0xFF;
s->regs[PCA9554_OUTPUT] = 0xFF;
s->regs[PCA9554_POLARITY] = 0x0; /* No pins are inverted */
s->regs[PCA9554_CONFIG] = 0xFF; /* All pins are inputs */
memset(s->ext_state, PCA9554_PIN_HIZ, PCA9554_PIN_COUNT);
pca9554_update_pin_input(s);
s->pointer = 0x0;
s->len = 0;
}
static void pca9554_initfn(Object *obj)
{
int pin;
for (pin = 0; pin < PCA9554_PIN_COUNT; pin++) {
char *name;
name = g_strdup_printf("pin%d", pin);
object_property_add(obj, name, "bool", pca9554_get_pin, pca9554_set_pin,
NULL, NULL);
g_free(name);
}
}
static void pca9554_set_ext_state(PCA9554State *s, int pin, int level)
{
if (s->ext_state[pin] != level) {
s->ext_state[pin] = level;
pca9554_update_pin_input(s);
}
}
static void pca9554_gpio_in_handler(void *opaque, int pin, int level)
{
PCA9554State *s = PCA9554(opaque);
assert((pin >= 0) && (pin < PCA9554_PIN_COUNT));
pca9554_set_ext_state(s, pin, level);
}
static void pca9554_realize(DeviceState *dev, Error **errp)
{
PCA9554State *s = PCA9554(dev);
if (!s->description) {
s->description = g_strdup("pca9554");
}
qdev_init_gpio_out(dev, s->gpio_out, PCA9554_PIN_COUNT);
qdev_init_gpio_in(dev, pca9554_gpio_in_handler, PCA9554_PIN_COUNT);
}
static Property pca9554_properties[] = {
DEFINE_PROP_STRING("description", PCA9554State, description),
DEFINE_PROP_END_OF_LIST(),
};
static void pca9554_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
k->event = pca9554_event;
k->recv = pca9554_recv;
k->send = pca9554_send;
dc->realize = pca9554_realize;
dc->reset = pca9554_reset;
dc->vmsd = &pca9554_vmstate;
device_class_set_props(dc, pca9554_properties);
}
static const TypeInfo pca9554_info = {
.name = TYPE_PCA9554,
.parent = TYPE_I2C_SLAVE,
.instance_init = pca9554_initfn,
.instance_size = sizeof(PCA9554State),
.class_init = pca9554_class_init,
.class_size = sizeof(PCA9554Class),
.abstract = false,
};
static void pca9554_register_types(void)
{
type_register_static(&pca9554_info);
}
type_init(pca9554_register_types)
+2
View File
@@ -32,6 +32,8 @@ config POWERNV
select XIVE
select FDT_PPC
select PCI_POWERNV
select PCA9552
select PCA9554
config PPC405
bool
+4 -1
View File
@@ -31,7 +31,7 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files(
'pef.c',
))
ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_TCG'], if_true: files(
'spapr_softmmu.c',
'spapr_vhyp_mmu.c',
))
ppc_ss.add(when: 'CONFIG_SPAPR_RNG', if_true: files('spapr_rng.c'))
if host_os == 'linux'
@@ -48,11 +48,14 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
'pnv_i2c.c',
'pnv_lpc.c',
'pnv_psi.c',
'pnv_chiptod.c',
'pnv_occ.c',
'pnv_sbe.c',
'pnv_bmc.c',
'pnv_homer.c',
'pnv_pnor.c',
'pnv_nest_pervasive.c',
'pnv_n1_chiplet.c',
))
# PowerPC 4xx boards
ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
+127 -4
View File
@@ -790,6 +790,7 @@ static void pnv_init(MachineState *machine)
const char *bios_name = machine->firmware ?: FW_FILE_NAME;
PnvMachineState *pnv = PNV_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
PnvMachineClass *pmc = PNV_MACHINE_GET_CLASS(machine);
char *fw_filename;
long fw_size;
uint64_t chip_ram_start = 0;
@@ -979,6 +980,13 @@ static void pnv_init(MachineState *machine)
*/
pnv->powerdown_notifier.notify = pnv_powerdown_notify;
qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
/*
* Create/Connect any machine-specific I2C devices
*/
if (pmc->i2c_init) {
pmc->i2c_init(pnv);
}
}
/*
@@ -1419,6 +1427,8 @@ static void pnv_chip_power9_instance_init(Object *obj)
object_initialize_child(obj, "lpc", &chip9->lpc, TYPE_PNV9_LPC);
object_initialize_child(obj, "chiptod", &chip9->chiptod, TYPE_PNV9_CHIPTOD);
object_initialize_child(obj, "occ", &chip9->occ, TYPE_PNV9_OCC);
object_initialize_child(obj, "sbe", &chip9->sbe, TYPE_PNV9_SBE);
@@ -1565,6 +1575,19 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
(uint64_t) PNV9_LPCM_BASE(chip));
/* ChipTOD */
object_property_set_bool(OBJECT(&chip9->chiptod), "primary",
chip->chip_id == 0, &error_abort);
object_property_set_bool(OBJECT(&chip9->chiptod), "secondary",
chip->chip_id == 1, &error_abort);
object_property_set_link(OBJECT(&chip9->chiptod), "chip", OBJECT(chip),
&error_abort);
if (!qdev_realize(DEVICE(&chip9->chiptod), NULL, errp)) {
return;
}
pnv_xscom_add_subregion(chip, PNV9_XSCOM_CHIPTOD_BASE,
&chip9->chiptod.xscom_regs);
/* Create the simplified OCC model */
if (!qdev_realize(DEVICE(&chip9->occ), NULL, errp)) {
return;
@@ -1677,9 +1700,13 @@ static void pnv_chip_power10_instance_init(Object *obj)
"xive-fabric");
object_initialize_child(obj, "psi", &chip10->psi, TYPE_PNV10_PSI);
object_initialize_child(obj, "lpc", &chip10->lpc, TYPE_PNV10_LPC);
object_initialize_child(obj, "chiptod", &chip10->chiptod,
TYPE_PNV10_CHIPTOD);
object_initialize_child(obj, "occ", &chip10->occ, TYPE_PNV10_OCC);
object_initialize_child(obj, "sbe", &chip10->sbe, TYPE_PNV10_SBE);
object_initialize_child(obj, "homer", &chip10->homer, TYPE_PNV10_HOMER);
object_initialize_child(obj, "n1-chiplet", &chip10->n1_chiplet,
TYPE_PNV_N1_CHIPLET);
chip->num_pecs = pcc->num_pecs;
@@ -1810,6 +1837,19 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
(uint64_t) PNV10_LPCM_BASE(chip));
/* ChipTOD */
object_property_set_bool(OBJECT(&chip10->chiptod), "primary",
chip->chip_id == 0, &error_abort);
object_property_set_bool(OBJECT(&chip10->chiptod), "secondary",
chip->chip_id == 1, &error_abort);
object_property_set_link(OBJECT(&chip10->chiptod), "chip", OBJECT(chip),
&error_abort);
if (!qdev_realize(DEVICE(&chip10->chiptod), NULL, errp)) {
return;
}
pnv_xscom_add_subregion(chip, PNV10_XSCOM_CHIPTOD_BASE,
&chip10->chiptod.xscom_regs);
/* Create the simplified OCC model */
if (!qdev_realize(DEVICE(&chip10->occ), NULL, errp)) {
return;
@@ -1849,6 +1889,19 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(), PNV10_HOMER_BASE(chip),
&chip10->homer.regs);
/* N1 chiplet */
if (!qdev_realize(DEVICE(&chip10->n1_chiplet), NULL, errp)) {
return;
}
pnv_xscom_add_subregion(chip, PNV10_XSCOM_N1_CHIPLET_CTRL_REGS_BASE,
&chip10->n1_chiplet.nest_pervasive.xscom_ctrl_regs_mr);
pnv_xscom_add_subregion(chip, PNV10_XSCOM_N1_PB_SCOM_EQ_BASE,
&chip10->n1_chiplet.xscom_pb_eq_mr);
pnv_xscom_add_subregion(chip, PNV10_XSCOM_N1_PB_SCOM_ES_BASE,
&chip10->n1_chiplet.xscom_pb_es_mr);
/* PHBs */
pnv_chip_power10_phb_realize(chip, &local_err);
if (local_err) {
@@ -1879,6 +1932,39 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(&chip10->psi),
PSIHB9_IRQ_SBE_I2C));
}
}
static void pnv_rainier_i2c_init(PnvMachineState *pnv)
{
int i;
for (i = 0; i < pnv->num_chips; i++) {
Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
/*
* Add a PCA9552 I2C device for PCIe hotplug control
* to engine 2, bus 1, address 0x63
*/
I2CSlave *dev = i2c_slave_create_simple(chip10->i2c[2].busses[1],
"pca9552", 0x63);
/*
* Connect PCA9552 GPIO pins 0-4 (SLOTx_EN) outputs to GPIO pins 5-9
* (SLOTx_PG) inputs in order to fake the pgood state of PCIe slots
* after hypervisor code sets a SLOTx_EN pin high.
*/
qdev_connect_gpio_out(DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(dev), 5));
qdev_connect_gpio_out(DEVICE(dev), 1, qdev_get_gpio_in(DEVICE(dev), 6));
qdev_connect_gpio_out(DEVICE(dev), 2, qdev_get_gpio_in(DEVICE(dev), 7));
qdev_connect_gpio_out(DEVICE(dev), 3, qdev_get_gpio_in(DEVICE(dev), 8));
qdev_connect_gpio_out(DEVICE(dev), 4, qdev_get_gpio_in(DEVICE(dev), 9));
/*
* Add a PCA9554 I2C device for cable card presence detection
* to engine 2, bus 1, address 0x25
*/
i2c_slave_create_simple(chip10->i2c[2].busses[1], "pca9554", 0x25);
}
}
static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
@@ -2035,6 +2121,21 @@ static void pnv_chip_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV Chip";
}
PnvCore *pnv_chip_find_core(PnvChip *chip, uint32_t core_id)
{
int i;
for (i = 0; i < chip->nr_cores; i++) {
PnvCore *pc = chip->cores[i];
CPUCore *cc = CPU_CORE(pc);
if (cc->core_id == core_id) {
return pc;
}
}
return NULL;
}
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir)
{
int i, j;
@@ -2242,8 +2343,6 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
xfc->match_nvt = pnv_match_nvt;
mc->alias = "powernv";
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->dt_power_mgt = pnv_dt_power_mgt;
@@ -2251,7 +2350,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
@@ -2263,10 +2362,11 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
{ TYPE_PNV_PHB_ROOT_PORT, "version", "5" },
};
mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v2.0");
compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat));
mc->alias = "powernv";
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->dt_power_mgt = pnv_dt_power_mgt;
@@ -2276,6 +2376,24 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
pnv_machine_p10_common_class_init(oc, data);
mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
}
static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
pnv_machine_p10_common_class_init(oc, data);
mc->desc = "IBM PowerNV (Non-Virtualized) POWER10 Rainier";
pmc->i2c_init = pnv_rainier_i2c_init;
}
static bool pnv_machine_get_hb(Object *obj, Error **errp)
{
PnvMachineState *pnv = PNV_MACHINE(obj);
@@ -2381,6 +2499,11 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
}
static const TypeInfo types[] = {
{
.name = MACHINE_TYPE_NAME("powernv10-rainier"),
.parent = MACHINE_TYPE_NAME("powernv10"),
.class_init = pnv_machine_p10_rainier_class_init,
},
{
.name = MACHINE_TYPE_NAME("powernv10"),
.parent = TYPE_PNV_MACHINE,
File diff suppressed because it is too large Load Diff
+15 -131
View File
@@ -22,136 +22,7 @@
#include <libfdt.h>
/* I2C FIFO register */
#define I2C_FIFO_REG 0x4
#define I2C_FIFO PPC_BITMASK(0, 7)
/* I2C command register */
#define I2C_CMD_REG 0x5
#define I2C_CMD_WITH_START PPC_BIT(0)
#define I2C_CMD_WITH_ADDR PPC_BIT(1)
#define I2C_CMD_READ_CONT PPC_BIT(2)
#define I2C_CMD_WITH_STOP PPC_BIT(3)
#define I2C_CMD_INTR_STEERING PPC_BITMASK(6, 7) /* P9 */
#define I2C_CMD_INTR_STEER_HOST 1
#define I2C_CMD_INTR_STEER_OCC 2
#define I2C_CMD_DEV_ADDR PPC_BITMASK(8, 14)
#define I2C_CMD_READ_NOT_WRITE PPC_BIT(15)
#define I2C_CMD_LEN_BYTES PPC_BITMASK(16, 31)
#define I2C_MAX_TFR_LEN 0xfff0ull
/* I2C mode register */
#define I2C_MODE_REG 0x6
#define I2C_MODE_BIT_RATE_DIV PPC_BITMASK(0, 15)
#define I2C_MODE_PORT_NUM PPC_BITMASK(16, 21)
#define I2C_MODE_ENHANCED PPC_BIT(28)
#define I2C_MODE_DIAGNOSTIC PPC_BIT(29)
#define I2C_MODE_PACING_ALLOW PPC_BIT(30)
#define I2C_MODE_WRAP PPC_BIT(31)
/* I2C watermark register */
#define I2C_WATERMARK_REG 0x7
#define I2C_WATERMARK_HIGH PPC_BITMASK(16, 19)
#define I2C_WATERMARK_LOW PPC_BITMASK(24, 27)
/*
* I2C interrupt mask and condition registers
*
* NB: The function of 0x9 and 0xa changes depending on whether you're reading
* or writing to them. When read they return the interrupt condition bits
* and on writes they update the interrupt mask register.
*
* The bit definitions are the same for all the interrupt registers.
*/
#define I2C_INTR_MASK_REG 0x8
#define I2C_INTR_RAW_COND_REG 0x9 /* read */
#define I2C_INTR_MASK_OR_REG 0x9 /* write*/
#define I2C_INTR_COND_REG 0xa /* read */
#define I2C_INTR_MASK_AND_REG 0xa /* write */
#define I2C_INTR_ALL PPC_BITMASK(16, 31)
#define I2C_INTR_INVALID_CMD PPC_BIT(16)
#define I2C_INTR_LBUS_PARITY_ERR PPC_BIT(17)
#define I2C_INTR_BKEND_OVERRUN_ERR PPC_BIT(18)
#define I2C_INTR_BKEND_ACCESS_ERR PPC_BIT(19)
#define I2C_INTR_ARBT_LOST_ERR PPC_BIT(20)
#define I2C_INTR_NACK_RCVD_ERR PPC_BIT(21)
#define I2C_INTR_DATA_REQ PPC_BIT(22)
#define I2C_INTR_CMD_COMP PPC_BIT(23)
#define I2C_INTR_STOP_ERR PPC_BIT(24)
#define I2C_INTR_I2C_BUSY PPC_BIT(25)
#define I2C_INTR_NOT_I2C_BUSY PPC_BIT(26)
#define I2C_INTR_SCL_EQ_1 PPC_BIT(28)
#define I2C_INTR_SCL_EQ_0 PPC_BIT(29)
#define I2C_INTR_SDA_EQ_1 PPC_BIT(30)
#define I2C_INTR_SDA_EQ_0 PPC_BIT(31)
/* I2C status register */
#define I2C_RESET_I2C_REG 0xb /* write */
#define I2C_RESET_ERRORS 0xc
#define I2C_STAT_REG 0xb /* read */
#define I2C_STAT_INVALID_CMD PPC_BIT(0)
#define I2C_STAT_LBUS_PARITY_ERR PPC_BIT(1)
#define I2C_STAT_BKEND_OVERRUN_ERR PPC_BIT(2)
#define I2C_STAT_BKEND_ACCESS_ERR PPC_BIT(3)
#define I2C_STAT_ARBT_LOST_ERR PPC_BIT(4)
#define I2C_STAT_NACK_RCVD_ERR PPC_BIT(5)
#define I2C_STAT_DATA_REQ PPC_BIT(6)
#define I2C_STAT_CMD_COMP PPC_BIT(7)
#define I2C_STAT_STOP_ERR PPC_BIT(8)
#define I2C_STAT_UPPER_THRS PPC_BITMASK(9, 15)
#define I2C_STAT_ANY_I2C_INTR PPC_BIT(16)
#define I2C_STAT_PORT_HISTORY_BUSY PPC_BIT(19)
#define I2C_STAT_SCL_INPUT_LEVEL PPC_BIT(20)
#define I2C_STAT_SDA_INPUT_LEVEL PPC_BIT(21)
#define I2C_STAT_PORT_BUSY PPC_BIT(22)
#define I2C_STAT_INTERFACE_BUSY PPC_BIT(23)
#define I2C_STAT_FIFO_ENTRY_COUNT PPC_BITMASK(24, 31)
#define I2C_STAT_ANY_ERR (I2C_STAT_INVALID_CMD | I2C_STAT_LBUS_PARITY_ERR | \
I2C_STAT_BKEND_OVERRUN_ERR | \
I2C_STAT_BKEND_ACCESS_ERR | I2C_STAT_ARBT_LOST_ERR | \
I2C_STAT_NACK_RCVD_ERR | I2C_STAT_STOP_ERR)
#define I2C_INTR_ACTIVE \
((I2C_STAT_ANY_ERR >> 16) | I2C_INTR_CMD_COMP | I2C_INTR_DATA_REQ)
/* Pseudo-status used for timeouts */
#define I2C_STAT_PSEUDO_TIMEOUT PPC_BIT(63)
/* I2C extended status register */
#define I2C_EXTD_STAT_REG 0xc
#define I2C_EXTD_STAT_FIFO_SIZE PPC_BITMASK(0, 7)
#define I2C_EXTD_STAT_MSM_CURSTATE PPC_BITMASK(11, 15)
#define I2C_EXTD_STAT_SCL_IN_SYNC PPC_BIT(16)
#define I2C_EXTD_STAT_SDA_IN_SYNC PPC_BIT(17)
#define I2C_EXTD_STAT_S_SCL PPC_BIT(18)
#define I2C_EXTD_STAT_S_SDA PPC_BIT(19)
#define I2C_EXTD_STAT_M_SCL PPC_BIT(20)
#define I2C_EXTD_STAT_M_SDA PPC_BIT(21)
#define I2C_EXTD_STAT_HIGH_WATER PPC_BIT(22)
#define I2C_EXTD_STAT_LOW_WATER PPC_BIT(23)
#define I2C_EXTD_STAT_I2C_BUSY PPC_BIT(24)
#define I2C_EXTD_STAT_SELF_BUSY PPC_BIT(25)
#define I2C_EXTD_STAT_I2C_VERSION PPC_BITMASK(27, 31)
/* I2C residual front end/back end length */
#define I2C_RESIDUAL_LEN_REG 0xd
#define I2C_RESIDUAL_FRONT_END PPC_BITMASK(0, 15)
#define I2C_RESIDUAL_BACK_END PPC_BITMASK(16, 31)
/* Port busy register */
#define I2C_PORT_BUSY_REG 0xe
#define I2C_SET_S_SCL_REG 0xd
#define I2C_RESET_S_SCL_REG 0xf
#define I2C_SET_S_SDA_REG 0x10
#define I2C_RESET_S_SDA_REG 0x11
#define PNV_I2C_FIFO_SIZE 8
#define PNV_I2C_MAX_BUSSES 64
#include "hw/i2c/pnv_i2c_regs.h"
static I2CBus *pnv_i2c_get_bus(PnvI2C *i2c)
{
@@ -629,6 +500,19 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
return 0;
}
static void pnv_i2c_sys_reset(void *dev)
{
int port;
PnvI2C *i2c = PNV_I2C(dev);
pnv_i2c_reset(dev);
/* reset all buses connected to this i2c controller */
for (port = 0; port < i2c->num_busses; port++) {
bus_cold_reset(BUS(i2c->busses[port]));
}
}
static void pnv_i2c_realize(DeviceState *dev, Error **errp)
{
PnvI2C *i2c = PNV_I2C(dev);
@@ -654,7 +538,7 @@ static void pnv_i2c_realize(DeviceState *dev, Error **errp)
fifo8_create(&i2c->fifo, PNV_I2C_FIFO_SIZE);
qemu_register_reset(pnv_i2c_reset, dev);
qemu_register_reset(pnv_i2c_sys_reset, dev);
qdev_init_gpio_out(DEVICE(dev), &i2c->psi_irq, 1);
}
+173
View File
@@ -0,0 +1,173 @@
/*
* QEMU PowerPC N1 chiplet model
*
* Copyright (c) 2023, IBM Corporation.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_xscom.h"
#include "hw/ppc/pnv_n1_chiplet.h"
#include "hw/ppc/pnv_nest_pervasive.h"
/*
* The n1 chiplet contains chiplet control unit,
* PowerBus/RaceTrack/Bridge logic, nest Memory Management Unit(nMMU)
* and more.
*
* In this model Nest1 chiplet control registers are modelled via common
* nest pervasive model and few PowerBus racetrack registers are modelled.
*/
#define PB_SCOM_EQ0_HP_MODE2_CURR 0xe
#define PB_SCOM_ES3_MODE 0x8a
static uint64_t pnv_n1_chiplet_pb_scom_eq_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque);
uint32_t reg = addr >> 3;
uint64_t val = ~0ull;
switch (reg) {
case PB_SCOM_EQ0_HP_MODE2_CURR:
val = n1_chiplet->eq[0].hp_mode2_curr;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom read at 0x%" PRIx32 "\n",
__func__, reg);
}
return val;
}
static void pnv_n1_chiplet_pb_scom_eq_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque);
uint32_t reg = addr >> 3;
switch (reg) {
case PB_SCOM_EQ0_HP_MODE2_CURR:
n1_chiplet->eq[0].hp_mode2_curr = val;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom write at 0x%" PRIx32 "\n",
__func__, reg);
}
}
static const MemoryRegionOps pnv_n1_chiplet_pb_scom_eq_ops = {
.read = pnv_n1_chiplet_pb_scom_eq_read,
.write = pnv_n1_chiplet_pb_scom_eq_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static uint64_t pnv_n1_chiplet_pb_scom_es_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque);
uint32_t reg = addr >> 3;
uint64_t val = ~0ull;
switch (reg) {
case PB_SCOM_ES3_MODE:
val = n1_chiplet->es[3].mode;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom read at 0x%" PRIx32 "\n",
__func__, reg);
}
return val;
}
static void pnv_n1_chiplet_pb_scom_es_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(opaque);
uint32_t reg = addr >> 3;
switch (reg) {
case PB_SCOM_ES3_MODE:
n1_chiplet->es[3].mode = val;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Invalid xscom write at 0x%" PRIx32 "\n",
__func__, reg);
}
}
static const MemoryRegionOps pnv_n1_chiplet_pb_scom_es_ops = {
.read = pnv_n1_chiplet_pb_scom_es_read,
.write = pnv_n1_chiplet_pb_scom_es_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static void pnv_n1_chiplet_realize(DeviceState *dev, Error **errp)
{
PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(dev);
/* Realize nest pervasive common chiplet model */
if (!qdev_realize(DEVICE(&n1_chiplet->nest_pervasive), NULL, errp)) {
return;
}
/* Nest1 chiplet power bus EQ xscom region */
pnv_xscom_region_init(&n1_chiplet->xscom_pb_eq_mr, OBJECT(n1_chiplet),
&pnv_n1_chiplet_pb_scom_eq_ops, n1_chiplet,
"xscom-n1-chiplet-pb-scom-eq",
PNV10_XSCOM_N1_PB_SCOM_EQ_SIZE);
/* Nest1 chiplet power bus ES xscom region */
pnv_xscom_region_init(&n1_chiplet->xscom_pb_es_mr, OBJECT(n1_chiplet),
&pnv_n1_chiplet_pb_scom_es_ops, n1_chiplet,
"xscom-n1-chiplet-pb-scom-es",
PNV10_XSCOM_N1_PB_SCOM_ES_SIZE);
}
static void pnv_n1_chiplet_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "PowerNV n1 chiplet";
dc->realize = pnv_n1_chiplet_realize;
}
static void pnv_n1_chiplet_instance_init(Object *obj)
{
PnvN1Chiplet *n1_chiplet = PNV_N1_CHIPLET(obj);
object_initialize_child(OBJECT(n1_chiplet), "nest-pervasive-common",
&n1_chiplet->nest_pervasive,
TYPE_PNV_NEST_CHIPLET_PERVASIVE);
}
static const TypeInfo pnv_n1_chiplet_info = {
.name = TYPE_PNV_N1_CHIPLET,
.parent = TYPE_DEVICE,
.instance_init = pnv_n1_chiplet_instance_init,
.instance_size = sizeof(PnvN1Chiplet),
.class_init = pnv_n1_chiplet_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
};
static void pnv_n1_chiplet_register_types(void)
{
type_register_static(&pnv_n1_chiplet_info);
}
type_init(pnv_n1_chiplet_register_types);
+208
View File
@@ -0,0 +1,208 @@
/*
* QEMU PowerPC nest pervasive common chiplet model
*
* Copyright (c) 2023, IBM Corporation.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_xscom.h"
#include "hw/ppc/pnv_nest_pervasive.h"
/*
* Status, configuration, and control units in POWER chips is provided
* by the pervasive subsystem, which connects registers to the SCOM bus,
* which can be programmed by processor cores, other units on the chip,
* BMCs, or other POWER chips.
*
* A POWER10 chip is divided into logical units called chiplets. Chiplets
* are broadly divided into "core chiplets" (with the processor cores) and
* "nest chiplets" (with everything else). Each chiplet has an attachment
* to the pervasive bus (PIB) and with chiplet-specific registers.
* All nest chiplets have a common basic set of registers.
*
* This model will provide the registers functionality for common registers of
* nest unit (PB Chiplet, PCI Chiplets, MC Chiplet, PAU Chiplets)
*
* Currently this model provide the read/write functionality of chiplet control
* scom registers.
*/
#define CPLT_CONF0 0x08
#define CPLT_CONF0_OR 0x18
#define CPLT_CONF0_CLEAR 0x28
#define CPLT_CONF1 0x09
#define CPLT_CONF1_OR 0x19
#define CPLT_CONF1_CLEAR 0x29
#define CPLT_STAT0 0x100
#define CPLT_MASK0 0x101
#define CPLT_PROTECT_MODE 0x3FE
#define CPLT_ATOMIC_CLOCK 0x3FF
static uint64_t pnv_chiplet_ctrl_read(void *opaque, hwaddr addr, unsigned size)
{
PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(
opaque);
uint32_t reg = addr >> 3;
uint64_t val = ~0ull;
/* CPLT_CTRL0 to CPLT_CTRL5 */
for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) {
if (reg == i) {
return nest_pervasive->control_regs.cplt_ctrl[i];
} else if ((reg == (i + 0x10)) || (reg == (i + 0x20))) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring "
"xscom read at 0x%" PRIx32 "\n",
__func__, reg);
return val;
}
}
switch (reg) {
case CPLT_CONF0:
val = nest_pervasive->control_regs.cplt_cfg0;
break;
case CPLT_CONF0_OR:
case CPLT_CONF0_CLEAR:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring "
"xscom read at 0x%" PRIx32 "\n",
__func__, reg);
break;
case CPLT_CONF1:
val = nest_pervasive->control_regs.cplt_cfg1;
break;
case CPLT_CONF1_OR:
case CPLT_CONF1_CLEAR:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Write only register, ignoring "
"xscom read at 0x%" PRIx32 "\n",
__func__, reg);
break;
case CPLT_STAT0:
val = nest_pervasive->control_regs.cplt_stat0;
break;
case CPLT_MASK0:
val = nest_pervasive->control_regs.cplt_mask0;
break;
case CPLT_PROTECT_MODE:
val = nest_pervasive->control_regs.ctrl_protect_mode;
break;
case CPLT_ATOMIC_CLOCK:
val = nest_pervasive->control_regs.ctrl_atomic_lock;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom "
"read at 0x%" PRIx32 "\n", __func__, reg);
}
return val;
}
static void pnv_chiplet_ctrl_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(
opaque);
uint32_t reg = addr >> 3;
/* CPLT_CTRL0 to CPLT_CTRL5 */
for (int i = 0; i < PNV_CPLT_CTRL_SIZE; i++) {
if (reg == i) {
nest_pervasive->control_regs.cplt_ctrl[i] = val;
return;
} else if (reg == (i + 0x10)) {
nest_pervasive->control_regs.cplt_ctrl[i] |= val;
return;
} else if (reg == (i + 0x20)) {
nest_pervasive->control_regs.cplt_ctrl[i] &= ~val;
return;
}
}
switch (reg) {
case CPLT_CONF0:
nest_pervasive->control_regs.cplt_cfg0 = val;
break;
case CPLT_CONF0_OR:
nest_pervasive->control_regs.cplt_cfg0 |= val;
break;
case CPLT_CONF0_CLEAR:
nest_pervasive->control_regs.cplt_cfg0 &= ~val;
break;
case CPLT_CONF1:
nest_pervasive->control_regs.cplt_cfg1 = val;
break;
case CPLT_CONF1_OR:
nest_pervasive->control_regs.cplt_cfg1 |= val;
break;
case CPLT_CONF1_CLEAR:
nest_pervasive->control_regs.cplt_cfg1 &= ~val;
break;
case CPLT_STAT0:
nest_pervasive->control_regs.cplt_stat0 = val;
break;
case CPLT_MASK0:
nest_pervasive->control_regs.cplt_mask0 = val;
break;
case CPLT_PROTECT_MODE:
nest_pervasive->control_regs.ctrl_protect_mode = val;
break;
case CPLT_ATOMIC_CLOCK:
nest_pervasive->control_regs.ctrl_atomic_lock = val;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Chiplet_control_regs: Invalid xscom "
"write at 0x%" PRIx32 "\n",
__func__, reg);
}
}
static const MemoryRegionOps pnv_nest_pervasive_control_xscom_ops = {
.read = pnv_chiplet_ctrl_read,
.write = pnv_chiplet_ctrl_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp)
{
PnvNestChipletPervasive *nest_pervasive = PNV_NEST_CHIPLET_PERVASIVE(dev);
/* Chiplet control scoms */
pnv_xscom_region_init(&nest_pervasive->xscom_ctrl_regs_mr,
OBJECT(nest_pervasive),
&pnv_nest_pervasive_control_xscom_ops,
nest_pervasive, "pervasive-control",
PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE);
}
static void pnv_nest_pervasive_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "PowerNV nest pervasive chiplet";
dc->realize = pnv_nest_pervasive_realize;
}
static const TypeInfo pnv_nest_pervasive_info = {
.name = TYPE_PNV_NEST_CHIPLET_PERVASIVE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvNestChipletPervasive),
.class_init = pnv_nest_pervasive_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
};
static void pnv_nest_pervasive_register_types(void)
{
type_register_static(&pnv_nest_pervasive_info);
}
type_init(pnv_nest_pervasive_register_types);
+5 -7
View File
@@ -4639,13 +4639,10 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_SCSI;
/*
* Setting max_cpus to INT32_MAX. Both KVM and TCG max_cpus values
* should be limited by the host capability instead of hardcoded.
* max_cpus for KVM guests will be checked in kvm_init(), and TCG
* guests are welcome to have as many CPUs as the host are capable
* of emulate.
* While KVM determines max cpus in kvm_init() using kvm_max_vcpus(),
* In TCG the limit is restricted by the range of CPU IPIs available.
*/
mc->max_cpus = INT32_MAX;
mc->max_cpus = SPAPR_IRQ_NR_IPIS;
mc->no_parallel = 1;
mc->default_boot_order = "";
@@ -4667,7 +4664,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
smc->dr_lmb_enabled = true;
smc->update_dt_enabled = true;
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.2");
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v2.0");
mc->has_hotpluggable_cpus = true;
mc->nvdimm_supported = true;
smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
@@ -5086,6 +5083,7 @@ static void spapr_machine_2_11_class_options(MachineClass *mc)
spapr_machine_2_12_class_options(mc);
smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
mc->deprecation_reason = "old and not maintained - use a 2.12+ version";
}
DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
+8 -4
View File
@@ -123,9 +123,11 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
if (kvm_enabled()) {
return H_HARDWARE;
} else if (tcg_enabled()) {
return vhyp_mmu_resize_hpt_prepare(cpu, spapr, shift);
} else {
g_assert_not_reached();
}
return softmmu_resize_hpt_prepare(cpu, spapr, shift);
}
static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data)
@@ -191,9 +193,11 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
if (kvm_enabled()) {
return H_HARDWARE;
} else if (tcg_enabled()) {
return vhyp_mmu_resize_hpt_commit(cpu, spapr, flags, shift);
} else {
g_assert_not_reached();
}
return softmmu_resize_hpt_commit(cpu, spapr, flags, shift);
}
+4 -2
View File
@@ -23,6 +23,8 @@
#include "trace.h"
QEMU_BUILD_BUG_ON(SPAPR_IRQ_NR_IPIS > SPAPR_XIRQ_BASE);
static const TypeInfo spapr_intc_info = {
.name = TYPE_SPAPR_INTC,
.parent = TYPE_INTERFACE,
@@ -329,7 +331,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
int i;
dev = qdev_new(TYPE_SPAPR_XIVE);
qdev_prop_set_uint32(dev, "nr-irqs", smc->nr_xirqs + SPAPR_XIRQ_BASE);
qdev_prop_set_uint32(dev, "nr-irqs", smc->nr_xirqs + SPAPR_IRQ_NR_IPIS);
/*
* 8 XIVE END structures per CPU. One for each available
* priority
@@ -356,7 +358,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
}
spapr->qirqs = qemu_allocate_irqs(spapr_set_irq, spapr,
smc->nr_xirqs + SPAPR_XIRQ_BASE);
smc->nr_xirqs + SPAPR_IRQ_NR_IPIS);
/*
* Mostly we don't actually need this until reset, except that not
@@ -1,3 +1,12 @@
/*
* MMU hypercalls for the sPAPR (pseries) vHyp hypervisor that is used by TCG
*
* Copyright (c) 2004-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
* Copyright (c) 2010 David Gibson, IBM Corporation.
*
* SPDX-License-Identifier: MIT
*/
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qemu/memalign.h"
@@ -369,7 +378,7 @@ static void cancel_hpt_prepare(SpaprMachineState *spapr)
free_pending_hpt(pending);
}
target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu,
target_ulong vhyp_mmu_resize_hpt_prepare(PowerPCCPU *cpu,
SpaprMachineState *spapr,
target_ulong shift)
{
@@ -553,7 +562,7 @@ static int rehash_hpt(PowerPCCPU *cpu,
return H_SUCCESS;
}
target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu,
target_ulong vhyp_mmu_resize_hpt_commit(PowerPCCPU *cpu,
SpaprMachineState *spapr,
target_ulong flags,
target_ulong shift)
+4
View File
@@ -95,6 +95,10 @@ vof_write(uint32_t ih, unsigned cb, const char *msg) "ih=0x%x [%u] \"%s\""
vof_avail(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64
vof_claimed(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64
# pnv_chiptod.c
pnv_chiptod_xscom_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
pnv_chiptod_xscom_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
# pnv_sbe.c
pnv_sbe_xscom_ctrl_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
pnv_sbe_xscom_ctrl_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
+143
View File
@@ -0,0 +1,143 @@
/*
* PowerNV I2C Controller Register Definitions
*
* Copyright (c) 2024, IBM Corporation.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef PNV_I2C_REGS_H
#define PNV_I2C_REGS_H
/* I2C FIFO register */
#define I2C_FIFO_REG 0x4
#define I2C_FIFO PPC_BITMASK(0, 7)
/* I2C command register */
#define I2C_CMD_REG 0x5
#define I2C_CMD_WITH_START PPC_BIT(0)
#define I2C_CMD_WITH_ADDR PPC_BIT(1)
#define I2C_CMD_READ_CONT PPC_BIT(2)
#define I2C_CMD_WITH_STOP PPC_BIT(3)
#define I2C_CMD_INTR_STEERING PPC_BITMASK(6, 7) /* P9 */
#define I2C_CMD_INTR_STEER_HOST 1
#define I2C_CMD_INTR_STEER_OCC 2
#define I2C_CMD_DEV_ADDR PPC_BITMASK(8, 14)
#define I2C_CMD_READ_NOT_WRITE PPC_BIT(15)
#define I2C_CMD_LEN_BYTES PPC_BITMASK(16, 31)
#define I2C_MAX_TFR_LEN 0xfff0ull
/* I2C mode register */
#define I2C_MODE_REG 0x6
#define I2C_MODE_BIT_RATE_DIV PPC_BITMASK(0, 15)
#define I2C_MODE_PORT_NUM PPC_BITMASK(16, 21)
#define I2C_MODE_ENHANCED PPC_BIT(28)
#define I2C_MODE_DIAGNOSTIC PPC_BIT(29)
#define I2C_MODE_PACING_ALLOW PPC_BIT(30)
#define I2C_MODE_WRAP PPC_BIT(31)
/* I2C watermark register */
#define I2C_WATERMARK_REG 0x7
#define I2C_WATERMARK_HIGH PPC_BITMASK(16, 19)
#define I2C_WATERMARK_LOW PPC_BITMASK(24, 27)
/*
* I2C interrupt mask and condition registers
*
* NB: The function of 0x9 and 0xa changes depending on whether you're reading
* or writing to them. When read they return the interrupt condition bits
* and on writes they update the interrupt mask register.
*
* The bit definitions are the same for all the interrupt registers.
*/
#define I2C_INTR_MASK_REG 0x8
#define I2C_INTR_RAW_COND_REG 0x9 /* read */
#define I2C_INTR_MASK_OR_REG 0x9 /* write*/
#define I2C_INTR_COND_REG 0xa /* read */
#define I2C_INTR_MASK_AND_REG 0xa /* write */
#define I2C_INTR_ALL PPC_BITMASK(16, 31)
#define I2C_INTR_INVALID_CMD PPC_BIT(16)
#define I2C_INTR_LBUS_PARITY_ERR PPC_BIT(17)
#define I2C_INTR_BKEND_OVERRUN_ERR PPC_BIT(18)
#define I2C_INTR_BKEND_ACCESS_ERR PPC_BIT(19)
#define I2C_INTR_ARBT_LOST_ERR PPC_BIT(20)
#define I2C_INTR_NACK_RCVD_ERR PPC_BIT(21)
#define I2C_INTR_DATA_REQ PPC_BIT(22)
#define I2C_INTR_CMD_COMP PPC_BIT(23)
#define I2C_INTR_STOP_ERR PPC_BIT(24)
#define I2C_INTR_I2C_BUSY PPC_BIT(25)
#define I2C_INTR_NOT_I2C_BUSY PPC_BIT(26)
#define I2C_INTR_SCL_EQ_1 PPC_BIT(28)
#define I2C_INTR_SCL_EQ_0 PPC_BIT(29)
#define I2C_INTR_SDA_EQ_1 PPC_BIT(30)
#define I2C_INTR_SDA_EQ_0 PPC_BIT(31)
/* I2C status register */
#define I2C_RESET_I2C_REG 0xb /* write */
#define I2C_RESET_ERRORS 0xc
#define I2C_STAT_REG 0xb /* read */
#define I2C_STAT_INVALID_CMD PPC_BIT(0)
#define I2C_STAT_LBUS_PARITY_ERR PPC_BIT(1)
#define I2C_STAT_BKEND_OVERRUN_ERR PPC_BIT(2)
#define I2C_STAT_BKEND_ACCESS_ERR PPC_BIT(3)
#define I2C_STAT_ARBT_LOST_ERR PPC_BIT(4)
#define I2C_STAT_NACK_RCVD_ERR PPC_BIT(5)
#define I2C_STAT_DATA_REQ PPC_BIT(6)
#define I2C_STAT_CMD_COMP PPC_BIT(7)
#define I2C_STAT_STOP_ERR PPC_BIT(8)
#define I2C_STAT_UPPER_THRS PPC_BITMASK(9, 15)
#define I2C_STAT_ANY_I2C_INTR PPC_BIT(16)
#define I2C_STAT_PORT_HISTORY_BUSY PPC_BIT(19)
#define I2C_STAT_SCL_INPUT_LEVEL PPC_BIT(20)
#define I2C_STAT_SDA_INPUT_LEVEL PPC_BIT(21)
#define I2C_STAT_PORT_BUSY PPC_BIT(22)
#define I2C_STAT_INTERFACE_BUSY PPC_BIT(23)
#define I2C_STAT_FIFO_ENTRY_COUNT PPC_BITMASK(24, 31)
#define I2C_STAT_ANY_ERR (I2C_STAT_INVALID_CMD | I2C_STAT_LBUS_PARITY_ERR | \
I2C_STAT_BKEND_OVERRUN_ERR | \
I2C_STAT_BKEND_ACCESS_ERR | I2C_STAT_ARBT_LOST_ERR | \
I2C_STAT_NACK_RCVD_ERR | I2C_STAT_STOP_ERR)
#define I2C_INTR_ACTIVE \
((I2C_STAT_ANY_ERR >> 16) | I2C_INTR_CMD_COMP | I2C_INTR_DATA_REQ)
/* Pseudo-status used for timeouts */
#define I2C_STAT_PSEUDO_TIMEOUT PPC_BIT(63)
/* I2C extended status register */
#define I2C_EXTD_STAT_REG 0xc
#define I2C_EXTD_STAT_FIFO_SIZE PPC_BITMASK(0, 7)
#define I2C_EXTD_STAT_MSM_CURSTATE PPC_BITMASK(11, 15)
#define I2C_EXTD_STAT_SCL_IN_SYNC PPC_BIT(16)
#define I2C_EXTD_STAT_SDA_IN_SYNC PPC_BIT(17)
#define I2C_EXTD_STAT_S_SCL PPC_BIT(18)
#define I2C_EXTD_STAT_S_SDA PPC_BIT(19)
#define I2C_EXTD_STAT_M_SCL PPC_BIT(20)
#define I2C_EXTD_STAT_M_SDA PPC_BIT(21)
#define I2C_EXTD_STAT_HIGH_WATER PPC_BIT(22)
#define I2C_EXTD_STAT_LOW_WATER PPC_BIT(23)
#define I2C_EXTD_STAT_I2C_BUSY PPC_BIT(24)
#define I2C_EXTD_STAT_SELF_BUSY PPC_BIT(25)
#define I2C_EXTD_STAT_I2C_VERSION PPC_BITMASK(27, 31)
/* I2C residual front end/back end length */
#define I2C_RESIDUAL_LEN_REG 0xd
#define I2C_RESIDUAL_FRONT_END PPC_BITMASK(0, 15)
#define I2C_RESIDUAL_BACK_END PPC_BITMASK(16, 31)
/* Port busy register */
#define I2C_PORT_BUSY_REG 0xe
#define I2C_SET_S_SCL_REG 0xd
#define I2C_RESET_S_SCL_REG 0xf
#define I2C_SET_S_SDA_REG 0x10
#define I2C_RESET_S_SDA_REG 0x11
#define PNV_I2C_FIFO_SIZE 8
#define PNV_I2C_MAX_BUSSES 64
#endif /* PNV_I2C_REGS_H */

Some files were not shown because too many files have changed in this diff Show More