* [RFC PATCH 1/3] hw/peci: add initial support for PECI
2022-09-06 22:05 [RFC PATCH 0/3] Initial PECI bus support Titus Rwantare
@ 2022-09-06 22:05 ` Titus Rwantare
2022-09-09 19:58 ` Peter Delevoryas
2022-09-06 22:05 ` [RFC PATCH 2/3] hw/peci: add PECI support for NPCM7xx BMCs Titus Rwantare
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Titus Rwantare @ 2022-09-06 22:05 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-arm, peter, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Titus Rwantare, Hao Wu, Patrick Venture
PECI - Platform Environment Control Interface
This commit adds support for reading basic sensor values from a client
on the PECI bus.
BMCs can use the PECI wire to get thermal information out of an Intel
cpu. Additionally, on hardware, various MSRs are exposed over the
PECI bus. Part of PCI config space is exposed due to Intel posting
various platform configuration in PCI config space.
Commands implemented:
- Ping
- GetDIB
- GetTemp
- GetPkgConfig (partial)
Commands not implemented:
- RdIAMSR
- RdPCIConfig
- RdPCIConfigLocal
Signed-off-by: Titus Rwantare <titusr@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Reviewed-by: Patrick Venture <venture@google.com>
---
MAINTAINERS | 7 ++
hw/Kconfig | 1 +
hw/meson.build | 1 +
hw/peci/Kconfig | 2 +
hw/peci/meson.build | 1 +
hw/peci/peci-client.c | 230 +++++++++++++++++++++++++++++++++++++++++
hw/peci/peci-core.c | 182 ++++++++++++++++++++++++++++++++
hw/peci/trace-events | 5 +
hw/peci/trace.h | 1 +
include/hw/peci/peci.h | 194 ++++++++++++++++++++++++++++++++++
meson.build | 1 +
11 files changed, 625 insertions(+)
create mode 100644 hw/peci/Kconfig
create mode 100644 hw/peci/meson.build
create mode 100644 hw/peci/peci-client.c
create mode 100644 hw/peci/peci-core.c
create mode 100644 hw/peci/trace-events
create mode 100644 hw/peci/trace.h
create mode 100644 include/hw/peci/peci.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 5ce4227ff6..14ab29679d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3212,6 +3212,13 @@ F: tests/qtest/adm1272-test.c
F: tests/qtest/max34451-test.c
F: tests/qtest/isl_pmbus_vr-test.c
+PECI
+M: Titus Rwantare <titusr@google.com>
+S: Maintained
+F: hw/peci/peci-core.c
+F: hw/peci/peci-client.c
+F: include/hw/peci/peci.h
+
Firmware schema specifications
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Daniel P. Berrange <berrange@redhat.com>
diff --git a/hw/Kconfig b/hw/Kconfig
index 38233bbb0f..300ab48127 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -24,6 +24,7 @@ source net/Kconfig
source nubus/Kconfig
source nvme/Kconfig
source nvram/Kconfig
+source peci/Kconfig
source pci-bridge/Kconfig
source pci-host/Kconfig
source pcmcia/Kconfig
diff --git a/hw/meson.build b/hw/meson.build
index c7ac7d3d75..340cc88a52 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -28,6 +28,7 @@ subdir('pci')
subdir('pci-bridge')
subdir('pci-host')
subdir('pcmcia')
+subdir('peci')
subdir('rdma')
subdir('rtc')
subdir('scsi')
diff --git a/hw/peci/Kconfig b/hw/peci/Kconfig
new file mode 100644
index 0000000000..fe4f665d21
--- /dev/null
+++ b/hw/peci/Kconfig
@@ -0,0 +1,2 @@
+config PECI
+ bool
diff --git a/hw/peci/meson.build b/hw/peci/meson.build
new file mode 100644
index 0000000000..01cfa95abe
--- /dev/null
+++ b/hw/peci/meson.build
@@ -0,0 +1 @@
+softmmu_ss.add(when: 'CONFIG_PECI', if_true: files('peci-core.c', 'peci-client.c'))
diff --git a/hw/peci/peci-client.c b/hw/peci/peci-client.c
new file mode 100644
index 0000000000..2aa797b5f6
--- /dev/null
+++ b/hw/peci/peci-client.c
@@ -0,0 +1,230 @@
+/*
+ * PECI Client device
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/peci/peci.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "qom/object.h"
+
+/*
+ * A PECI client represents an Intel socket and the peripherals attached to it
+ * that are accessible over the PECI bus.
+ */
+
+#define PECI_CLIENT_DEFAULT_TEMP 30
+
+static void peci_client_update_temps(PECIClientDevice *client)
+{
+ uint8_t temp_cpu = 0;
+ for (size_t i = 0; i < client->cpu_cores; i++) {
+ if (temp_cpu < client->core_temp[i]) {
+ temp_cpu = client->core_temp[i];
+ }
+ }
+ client->core_temp_max = -1 * (client->tjmax - temp_cpu);
+
+ uint8_t temp_dimm = 0;
+ for (size_t i = 0; i < client->dimms; i++) {
+ if (temp_dimm < client->dimm_temp[i]) {
+ temp_dimm = client->dimm_temp[i];
+ }
+ }
+ client->dimm_temp_max = temp_dimm;
+}
+
+PECIClientDevice *peci_get_client(PECIBus *bus, uint8_t addr)
+{
+ PECIClientDevice *client;
+ BusChild *var;
+
+ QTAILQ_FOREACH(var, &bus->qbus.children, sibling) {
+ DeviceState *dev = var->child;
+ client = PECI_CLIENT(dev);
+
+ if (client->address == addr) {
+ return client;
+ }
+ }
+ return 0;
+}
+
+
+PECIClientDevice *peci_add_client(PECIBus *bus,
+ uint8_t address,
+ PECIClientProperties *props)
+{
+ DeviceState *dev = qdev_new("peci-client");
+ PECIClientDevice *client;
+
+ /* Only 8 addresses supported as of rev 4.1, 0x30 to 0x37 */
+ if (address < PECI_BASE_ADDR || address > PECI_BASE_ADDR + 7) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to add client at 0x%02x",
+ __func__, address);
+ return 0;
+ }
+
+ client = PECI_CLIENT(dev);
+ client->address = address;
+
+ /* these fields are optional, get set to max if unset or invalid */
+ if (!props->cpu_cores || props->cpu_cores > PECI_NUM_CPUS_MAX) {
+ props->cpu_cores = PECI_NUM_CPUS_MAX;
+ }
+ if (!props->dimms || props->dimms > PECI_NUM_DIMMS_MAX) {
+ props->dimms = PECI_NUM_DIMMS_MAX;
+ }
+ if (!props->cpu_family) {
+ props->cpu_family = FAM6_ICELAKE_X;
+ }
+ if (!props->dimms_per_channel ||
+ props->dimms_per_channel > PECI_DIMMS_PER_CHANNEL_MAX) {
+ props->dimms_per_channel = 2;
+ }
+
+ client->cpu_id = props->cpu_family;
+ client->cpu_cores = props->cpu_cores;
+ client->dimms = props->dimms;
+ client->dimms_per_channel = props->dimms_per_channel;
+
+ /* TODO: find real revisions and TJ max for supported families */
+ client->tjmax = 90;
+ client->tcontrol = -5;
+
+ switch (props->cpu_family) {
+ case FAM6_HASWELL_X:
+ client->revision = 0x31;
+ break;
+
+ case FAM6_BROADWELL_X:
+ client->revision = 0x32;
+ break;
+
+ case FAM6_SKYLAKE_X:
+ case FAM6_SKYLAKE_XD:
+ client->revision = 0x36;
+ break;
+
+ case FAM6_ICELAKE_X:
+ case FAM6_SAPPHIRE_RAPIDS_X:
+ client->revision = 0x40;
+ client->ucode = 0x8c0004a0;
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unsupported cpu: 0x%x\n",
+ __func__, props->cpu_family);
+ client->revision = 0x31;
+ break;
+ }
+
+ qdev_realize_and_unref(&client->qdev, &bus->qbus, &error_abort);
+ bus->num_clients += 1;
+ return client;
+}
+
+static void peci_client_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ /* use millidegrees convention */
+ uint32_t value = *(uint8_t *)opaque * 1000;
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void peci_client_set(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PECIClientDevice *client = PECI_CLIENT(obj);
+ uint8_t *internal = opaque;
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ g_assert(value <= 255000);
+
+ *internal = value / 1000;
+ peci_client_update_temps(client);
+}
+
+static void peci_client_reset(Object *obj, ResetType type)
+{
+ PECIClientDevice *client = PECI_CLIENT(obj);
+ client->core_temp_max = 0;
+ client->dimm_temp_max = 0;
+}
+
+static const VMStateDescription vmstate_peci_client = {
+ .name = TYPE_PECI_CLIENT,
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(address, PECIClientDevice),
+ VMSTATE_UINT8(device_info, PECIClientDevice),
+ VMSTATE_UINT8(revision, PECIClientDevice),
+ VMSTATE_UINT32(cpu_id, PECIClientDevice),
+ VMSTATE_UINT8(cpu_cores, PECIClientDevice),
+ VMSTATE_UINT8(tjmax, PECIClientDevice),
+ VMSTATE_INT8(tcontrol, PECIClientDevice),
+ VMSTATE_UINT8_ARRAY(core_temp, PECIClientDevice, PECI_NUM_CPUS_MAX),
+ VMSTATE_UINT8(dimms, PECIClientDevice),
+ VMSTATE_UINT8(dimms_per_channel, PECIClientDevice),
+ VMSTATE_UINT8_ARRAY(dimm_temp, PECIClientDevice , PECI_NUM_DIMMS_MAX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void peci_client_realize(DeviceState *dev, Error **errp)
+{
+ PECIClientDevice *client = PECI_CLIENT(dev);
+ for (size_t i = 0; i < client->cpu_cores; i++) {
+ client->core_temp[i] = PECI_CLIENT_DEFAULT_TEMP;
+ object_property_add(OBJECT(client), "cpu_temp[*]", "uint8",
+ peci_client_get,
+ peci_client_set, NULL, &client->core_temp[i]);
+ }
+
+ for (size_t i = 0; i < client->dimms; i++) {
+ client->dimm_temp[i] = PECI_CLIENT_DEFAULT_TEMP;
+ object_property_add(OBJECT(client), "dimm_temp[*]", "uint8",
+ peci_client_get,
+ peci_client_set, NULL, &client->dimm_temp[i]);
+ }
+}
+
+static void peci_client_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->desc = "PECI Client Device";
+ dc->bus_type = TYPE_PECI_BUS;
+ dc->realize = peci_client_realize;
+ dc->vmsd = &vmstate_peci_client;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ rc->phases.enter = peci_client_reset;
+}
+
+static const TypeInfo peci_client_info = {
+ .name = TYPE_PECI_CLIENT,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PECIClientDevice),
+ .class_init = peci_client_class_init,
+};
+
+static void peci_client_register_types(void)
+{
+ type_register_static(&peci_client_info);
+}
+
+type_init(peci_client_register_types)
diff --git a/hw/peci/peci-core.c b/hw/peci/peci-core.c
new file mode 100644
index 0000000000..8210bfa198
--- /dev/null
+++ b/hw/peci/peci-core.c
@@ -0,0 +1,182 @@
+/*
+ * PECI - Platform Environment Control Interface
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * This PECI implementation aims to simulate a host with peci as viewed by a
+ * BMC. This is developed with OpenBMC firmware running in QEMU.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/peci/peci.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+#define PECI_FCS_OK 0
+#define PECI_FCS_ERR 1
+
+static void peci_rd_pkg_cfg(PECIClientDevice *client, PECICmd *pcmd)
+{
+ PECIPkgCfg *resp = (PECIPkgCfg *)pcmd->tx;
+ uint8_t index = pcmd->rx[1];
+ uint16_t param = pcmd->rx[3] | pcmd->rx[2];
+
+ switch (index) {
+ case PECI_MBX_CPU_ID: /* CPU Family ID*/
+ trace_peci_rd_pkg_cfg("CPU ID");
+ switch (param) {
+ case PECI_PKG_ID_CPU_ID:
+ resp->data = client->cpu_id;
+ break;
+
+ case PECI_PKG_ID_MICROCODE_REV:
+ resp->data = client->ucode;
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: CPU ID param %u\n", __func__, param);
+ break;
+ }
+ break;
+
+ case PECI_MBX_DTS_MARGIN:
+ trace_peci_rd_pkg_cfg("DTS MARGIN");
+ /*
+ * Processors return a value of DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ */
+ resp->data = (-1 * client->core_temp_max) << 6;
+ break;
+
+ case PECI_MBX_DDR_DIMM_TEMP:
+ trace_peci_rd_pkg_cfg("DDR DIMM TEMP");
+ if (param > PECI_NUM_CHANNELS_MAX) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: DDR_DIMM_TEMP unsupported channel index %d",
+ __func__, param);
+ param = PECI_NUM_CHANNELS_MAX;
+ }
+ uint8_t channel_index = param * client->dimms_per_channel;
+ memcpy(&resp->data,
+ &client->dimm_temp[channel_index],
+ sizeof(client->dimm_temp[0]) * client->dimms_per_channel);
+ break;
+
+ case PECI_MBX_TEMP_TARGET:
+ trace_peci_rd_pkg_cfg("TEMP TARGET");
+ PECITempTarget target = {
+ .tcontrol = client->tcontrol,
+ .tjmax = client->tjmax,
+ };
+ memcpy(&resp->data, &target, sizeof(target));
+ break;
+
+ case PECI_MBX_PPIN:
+ trace_peci_rd_pkg_cfg("PPIN");
+ resp->data = 0xdeadbeef;
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented PkgCfg Index: %u\n",
+ __func__, index);
+ resp->cc = PECI_DEV_CC_INVALID_REQ;
+ return;
+ }
+
+ resp->cc = PECI_DEV_CC_SUCCESS;
+}
+
+int peci_handle_cmd(PECIBus *bus, PECICmd *pcmd)
+{
+ PECIClientDevice *client = peci_get_client(bus, pcmd->addr);
+
+ if (!client) { /* ignore commands if clients aren't found */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: no peci client at address: 0x%02x\n",
+ __func__, pcmd->addr);
+ return PECI_FCS_ERR;
+ }
+
+ /* clear output buffer before handling command */
+ for (size_t i = 0; i < pcmd->rd_length; i++) {
+ pcmd->tx[i] = 0;
+ }
+
+ switch (pcmd->cmd) {
+ case PECI_CMD_PING:
+ trace_peci_handle_cmd("PING!", pcmd->addr);
+ break;
+
+ case PECI_CMD_GET_DIB: /* Device Info Byte */
+ trace_peci_handle_cmd("GetDIB", pcmd->addr);
+ PECIDIB dib = {
+ .device_info = client->device_info,
+ .revision = client->revision,
+ };
+ memcpy(pcmd->tx, &dib, sizeof(PECIDIB));
+ break;
+
+ case PECI_CMD_GET_TEMP: /* maximum die temp in socket */
+ trace_peci_handle_cmd("GetTemp", pcmd->addr);
+ /*
+ * The data is returned as a negative value representing the number of
+ * degrees centigrade below the maximum processor junction temperature
+ */
+ memcpy(pcmd->tx, &client->core_temp_max, sizeof(client->core_temp_max));
+ break;
+
+ case PECI_CMD_RD_PKG_CFG:
+ trace_peci_handle_cmd("RdPkgConfig", pcmd->addr);
+ peci_rd_pkg_cfg(client, pcmd);
+ break;
+
+ case PECI_CMD_RD_IA_MSR:
+ trace_peci_handle_cmd("RdIAMSR", pcmd->addr);
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented RD_IA_MSR\n", __func__);
+ break;
+
+ case PECI_CMD_RD_PCI_CFG:
+ trace_peci_handle_cmd("RdPCIConfig", pcmd->addr);
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented PCI_CFG\n", __func__);
+ break;
+
+ case PECI_CMD_RD_PCI_CFG_LOCAL:
+ trace_peci_handle_cmd("RdPCIConfigLocal", pcmd->addr);
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented PCI_CFG_LOCAL\n", __func__);
+ break;
+
+ case PECI_CMD_RD_END_PT_CFG:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented CMD_RD_END_PT_CFG\n",
+ __func__);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown cmd: %x\n",
+ __func__, pcmd->cmd);
+ break;
+ }
+
+ return PECI_FCS_OK;
+}
+
+PECIBus *peci_bus_create(DeviceState *parent)
+{
+ return PECI_BUS(qbus_new(TYPE_PECI_BUS, parent, "peci-bus"));
+};
+
+static const TypeInfo peci_types[] = {
+ {
+ .name = TYPE_PECI_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(PECIBus),
+ },
+};
+
+DEFINE_TYPES(peci_types);
diff --git a/hw/peci/trace-events b/hw/peci/trace-events
new file mode 100644
index 0000000000..f90c998dd9
--- /dev/null
+++ b/hw/peci/trace-events
@@ -0,0 +1,5 @@
+# See docs/devel/tracing.rst for syntax documentation.
+
+# peci-core.c
+peci_handle_cmd(const char* s, uint8_t addr) "%s @ 0x%02" PRIx8
+peci_rd_pkg_cfg(const char* s) "%s"
diff --git a/hw/peci/trace.h b/hw/peci/trace.h
new file mode 100644
index 0000000000..4283e3bfc5
--- /dev/null
+++ b/hw/peci/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-hw_peci.h"
diff --git a/include/hw/peci/peci.h b/include/hw/peci/peci.h
new file mode 100644
index 0000000000..1a0abe65cd
--- /dev/null
+++ b/include/hw/peci/peci.h
@@ -0,0 +1,194 @@
+/*
+ * PECI - Platform Environment Control Interface
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef PECI_H
+#define PECI_H
+
+#include "hw/qdev-core.h"
+#include "qom/object.h"
+
+#define PECI_CMD_PING 0x0
+#define PECI_CMD_GET_DIB 0xF7
+#define PECI_CMD_GET_TEMP 0x01
+#define PECI_CMD_RD_PKG_CFG 0xA1
+#define PECI_CMD_WR_PKG_CFG 0xA5
+#define PECI_MBX_CPU_ID 0 /* Package Identifier Read */
+#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */
+#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */
+#define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */
+#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
+#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Revision */
+#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
+#define PECI_MBX_VR_DEBUG 1 /* VR Debug */
+#define PECI_MBX_PKG_TEMP_READ 2 /* Package Temperature Read */
+#define PECI_MBX_ENERGY_COUNTER 3 /* Energy counter */
+#define PECI_MBX_ENERGY_STATUS 4 /* DDR Energy Status */
+#define PECI_MBX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */
+#define PECI_MBX_EPI 6 /* Efficient Performance Indication */
+#define PECI_MBX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */
+#define PECI_MBX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */
+#define PECI_MBX_DTS_MARGIN 10 /* DTS thermal margin */
+#define PECI_MBX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */
+#define PECI_MBX_CFG_TDP_CONTROL 12 /* TDP Config Control */
+#define PECI_MBX_CFG_TDP_LEVELS 13 /* TDP Config Levels */
+#define PECI_MBX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */
+#define PECI_MBX_CFG_ICCMAX 15 /* Configurable ICCMAX */
+#define PECI_MBX_TEMP_TARGET 16 /* Temperature Target Read */
+#define PECI_MBX_CURR_CFG_LIMIT 17 /* Current Config Limit */
+#define PECI_MBX_PPIN 19 /* Processor Inventory Number */
+#define PECI_MBX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */
+#define PECI_MBX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */
+#define PECI_MBX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */
+#define PECI_MBX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */
+#define PECI_MBX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */
+#define PECI_MBX_TDP 28 /* Thermal design power minimum */
+#define PECI_MBX_TDP_HIGH 29 /* Thermal design power maximum */
+#define PECI_MBX_TDP_UNITS 30 /* Units for power/energy registers */
+#define PECI_MBX_RUN_TIME 31 /* Accumulated Run Time */
+#define PECI_MBX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */
+#define PECI_MBX_TURBO_RATIO 33 /* Turbo Activation Ratio */
+#define PECI_MBX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */
+#define PECI_MBX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */
+#define PECI_MBX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */
+#define PECI_MBX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */
+#define PECI_MBX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */
+#define PECI_MBX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */
+#define PECI_MBX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */
+#define PECI_MBX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */
+#define PECI_MBX_DDR_THERM_STATUS 46 /* DDR Thermal Status */
+#define PECI_MBX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */
+#define PECI_MBX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */
+#define PECI_MBX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */
+#define PECI_MBX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */
+#define PECI_MBX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */
+#define PECI_MBX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */
+#define PECI_MBX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */
+#define PECI_MBX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */
+#define PECI_MBX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */
+#define PECI_MBX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */
+#define PECI_CMD_RD_IA_MSR 0xB1
+#define PECI_CMD_WR_IA_MSR 0xB5
+#define PECI_CMD_RD_IA_MSREX 0xD1
+#define PECI_CMD_RD_PCI_CFG 0x61
+#define PECI_CMD_WR_PCI_CFG 0x65
+#define PECI_CMD_RD_PCI_CFG_LOCAL 0xE1
+#define PECI_CMD_WR_PCI_CFG_LOCAL 0xE5
+#define PECI_CMD_RD_END_PT_CFG 0xC1
+#define PECI_CMD_WR_END_PT_CFG 0xC5
+#define PECI_CMD_CRASHDUMP_GET_FRAME 0x71
+
+/* Device Specific Completion Code (CC) Definition */
+#define PECI_DEV_CC_SUCCESS 0x40
+#define PECI_DEV_CC_NEED_RETRY 0x80
+#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81
+#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82
+#define PECI_DEV_CC_INVALID_REQ 0x90
+#define PECI_DEV_CC_MCA_ERROR 0x91
+#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93
+#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94
+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98
+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B
+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C
+
+
+typedef struct PECIDIB { /* DIB - Device Info Byte(s) */
+ uint8_t device_info; /* bit 2 - num of domains */
+ uint8_t revision;
+} PECIDIB;
+
+typedef struct __attribute__ ((__packed__)) {
+ uint8_t cc; /* completion code */
+ uint32_t data;
+} PECIPkgCfg;
+
+typedef struct PECITempTarget {
+ uint8_t reserved;
+ int8_t tcontrol;
+ uint8_t tjmax;
+} PECITempTarget;
+
+#define PECI_BASE_ADDR 0x30
+#define PECI_BUFFER_SIZE 0x100
+#define PECI_NUM_CPUS_MAX 56
+#define PECI_DIMMS_PER_CHANNEL_MAX 3
+#define PECI_NUM_CHANNELS_MAX 8
+#define PECI_NUM_DIMMS_MAX (PECI_NUM_CHANNELS_MAX * PECI_DIMMS_PER_CHANNEL_MAX)
+
+typedef struct PECIClientDevice {
+ DeviceState qdev;
+ uint8_t address;
+ uint8_t device_info;
+ uint8_t revision;
+
+ /* CPU */
+ uint32_t cpu_id;
+ uint8_t cpu_cores;
+ uint32_t ucode;
+ uint8_t tjmax;
+ int8_t tcontrol;
+ int8_t core_temp_max; /* absolute temp - tjmax */
+ uint8_t core_temp[PECI_NUM_CPUS_MAX];
+
+ /* DIMMS */
+ uint8_t dimms;
+ uint8_t dimms_per_channel;
+ uint8_t dimm_temp_max;
+ uint8_t dimm_temp[PECI_NUM_DIMMS_MAX];
+
+} PECIClientDevice;
+
+#define TYPE_PECI_CLIENT "peci-client"
+OBJECT_DECLARE_SIMPLE_TYPE(PECIClientDevice, PECI_CLIENT)
+
+typedef struct PECIBus {
+ BusState qbus;
+ uint8_t num_clients;
+} PECIBus;
+
+#define TYPE_PECI_BUS "peci-bus"
+OBJECT_DECLARE_SIMPLE_TYPE(PECIBus, PECI_BUS)
+
+/* Creates a basic qemu bus onto which PECI clients will be attached */
+PECIBus *peci_bus_create(DeviceState *parent);
+
+enum {
+ FAM6_HASWELL_X = 0x306F0,
+ FAM6_BROADWELL_X = 0x406F0,
+ FAM6_SKYLAKE_X = 0x50650,
+ FAM6_SKYLAKE_XD = 0x50660,
+ FAM6_ICELAKE_X = 0x606A0,
+ FAM6_SAPPHIRE_RAPIDS_X = 0x806F3,
+};
+
+typedef struct PECIClientProperties {
+ uint32_t cpu_family;
+ uint8_t cpu_cores;
+ uint8_t dimms;
+ uint8_t dimms_per_channel;
+} PECIClientProperties;
+
+/* Creates a PECI client with the specified cpu and dimm count */
+PECIClientDevice *peci_add_client(PECIBus *bus,
+ uint8_t address,
+ PECIClientProperties *props);
+PECIClientDevice *peci_get_client(PECIBus *bus, uint8_t addr);
+
+typedef struct PECICmd {
+ uint8_t addr;
+ uint8_t cmd;
+
+ size_t wr_length;
+ uint8_t rx[PECI_BUFFER_SIZE];
+
+ size_t rd_length;
+ uint8_t tx[PECI_BUFFER_SIZE];
+} PECICmd;
+
+int peci_handle_cmd(PECIBus *bus, PECICmd *pcmd);
+
+#endif
diff --git a/meson.build b/meson.build
index 20fddbd707..55594702c3 100644
--- a/meson.build
+++ b/meson.build
@@ -2965,6 +2965,7 @@ if have_system
'hw/nvram',
'hw/pci',
'hw/pci-host',
+ 'hw/peci',
'hw/ppc',
'hw/rdma',
'hw/rdma/vmw',
--
2.37.2.789.g6183377224-goog
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 1/3] hw/peci: add initial support for PECI
2022-09-06 22:05 ` [RFC PATCH 1/3] hw/peci: add initial support for PECI Titus Rwantare
@ 2022-09-09 19:58 ` Peter Delevoryas
2022-09-13 18:21 ` Titus Rwantare
0 siblings, 1 reply; 13+ messages in thread
From: Peter Delevoryas @ 2022-09-09 19:58 UTC (permalink / raw)
To: Titus Rwantare
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Hao Wu, Patrick Venture
On Tue, Sep 06, 2022 at 10:05:50PM +0000, Titus Rwantare wrote:
> PECI - Platform Environment Control Interface
>
> This commit adds support for reading basic sensor values from a client
> on the PECI bus.
> BMCs can use the PECI wire to get thermal information out of an Intel
> cpu. Additionally, on hardware, various MSRs are exposed over the
> PECI bus. Part of PCI config space is exposed due to Intel posting
> various platform configuration in PCI config space.
>
> Commands implemented:
> - Ping
> - GetDIB
> - GetTemp
> - GetPkgConfig (partial)
>
> Commands not implemented:
> - RdIAMSR
> - RdPCIConfig
> - RdPCIConfigLocal
>
> Signed-off-by: Titus Rwantare <titusr@google.com>
> Reviewed-by: Hao Wu <wuhaotsh@google.com>
> Reviewed-by: Patrick Venture <venture@google.com>
> ---
> MAINTAINERS | 7 ++
> hw/Kconfig | 1 +
> hw/meson.build | 1 +
> hw/peci/Kconfig | 2 +
> hw/peci/meson.build | 1 +
> hw/peci/peci-client.c | 230 +++++++++++++++++++++++++++++++++++++++++
> hw/peci/peci-core.c | 182 ++++++++++++++++++++++++++++++++
> hw/peci/trace-events | 5 +
> hw/peci/trace.h | 1 +
> include/hw/peci/peci.h | 194 ++++++++++++++++++++++++++++++++++
> meson.build | 1 +
> 11 files changed, 625 insertions(+)
> create mode 100644 hw/peci/Kconfig
> create mode 100644 hw/peci/meson.build
> create mode 100644 hw/peci/peci-client.c
> create mode 100644 hw/peci/peci-core.c
> create mode 100644 hw/peci/trace-events
> create mode 100644 hw/peci/trace.h
> create mode 100644 include/hw/peci/peci.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 5ce4227ff6..14ab29679d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3212,6 +3212,13 @@ F: tests/qtest/adm1272-test.c
> F: tests/qtest/max34451-test.c
> F: tests/qtest/isl_pmbus_vr-test.c
>
> +PECI
> +M: Titus Rwantare <titusr@google.com>
> +S: Maintained
> +F: hw/peci/peci-core.c
> +F: hw/peci/peci-client.c
> +F: include/hw/peci/peci.h
> +
> Firmware schema specifications
> M: Philippe Mathieu-Daudé <f4bug@amsat.org>
> R: Daniel P. Berrange <berrange@redhat.com>
> diff --git a/hw/Kconfig b/hw/Kconfig
> index 38233bbb0f..300ab48127 100644
> --- a/hw/Kconfig
> +++ b/hw/Kconfig
> @@ -24,6 +24,7 @@ source net/Kconfig
> source nubus/Kconfig
> source nvme/Kconfig
> source nvram/Kconfig
> +source peci/Kconfig
> source pci-bridge/Kconfig
> source pci-host/Kconfig
> source pcmcia/Kconfig
> diff --git a/hw/meson.build b/hw/meson.build
> index c7ac7d3d75..340cc88a52 100644
> --- a/hw/meson.build
> +++ b/hw/meson.build
> @@ -28,6 +28,7 @@ subdir('pci')
> subdir('pci-bridge')
> subdir('pci-host')
> subdir('pcmcia')
> +subdir('peci')
> subdir('rdma')
> subdir('rtc')
> subdir('scsi')
> diff --git a/hw/peci/Kconfig b/hw/peci/Kconfig
> new file mode 100644
> index 0000000000..fe4f665d21
> --- /dev/null
> +++ b/hw/peci/Kconfig
> @@ -0,0 +1,2 @@
> +config PECI
> + bool
> diff --git a/hw/peci/meson.build b/hw/peci/meson.build
> new file mode 100644
> index 0000000000..01cfa95abe
> --- /dev/null
> +++ b/hw/peci/meson.build
> @@ -0,0 +1 @@
> +softmmu_ss.add(when: 'CONFIG_PECI', if_true: files('peci-core.c', 'peci-client.c'))
> diff --git a/hw/peci/peci-client.c b/hw/peci/peci-client.c
> new file mode 100644
> index 0000000000..2aa797b5f6
> --- /dev/null
> +++ b/hw/peci/peci-client.c
> @@ -0,0 +1,230 @@
> +/*
> + * PECI Client device
> + * Copyright 2021 Google LLC
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
Not sure, but I think the SPDX license identifier is supposed to be in
the first line? Maybe not though. I would have expected:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* PECI Client device
*
* Copyright 2021 Google LLC
*/
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/peci/peci.h"
> +#include "hw/qdev-core.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +#include "qapi/visitor.h"
> +#include "qemu/module.h"
> +#include "qemu/log.h"
> +#include "qom/object.h"
> +
> +/*
> + * A PECI client represents an Intel socket and the peripherals attached to it
> + * that are accessible over the PECI bus.
> + */
> +
> +#define PECI_CLIENT_DEFAULT_TEMP 30
> +
> +static void peci_client_update_temps(PECIClientDevice *client)
> +{
> + uint8_t temp_cpu = 0;
> + for (size_t i = 0; i < client->cpu_cores; i++) {
> + if (temp_cpu < client->core_temp[i]) {
> + temp_cpu = client->core_temp[i];
> + }
> + }
> + client->core_temp_max = -1 * (client->tjmax - temp_cpu);
> +
> + uint8_t temp_dimm = 0;
> + for (size_t i = 0; i < client->dimms; i++) {
> + if (temp_dimm < client->dimm_temp[i]) {
> + temp_dimm = client->dimm_temp[i];
> + }
> + }
> + client->dimm_temp_max = temp_dimm;
> +}
> +
> +PECIClientDevice *peci_get_client(PECIBus *bus, uint8_t addr)
> +{
> + PECIClientDevice *client;
> + BusChild *var;
> +
> + QTAILQ_FOREACH(var, &bus->qbus.children, sibling) {
> + DeviceState *dev = var->child;
> + client = PECI_CLIENT(dev);
> +
> + if (client->address == addr) {
> + return client;
> + }
> + }
> + return 0;
> +}
> +
> +
> +PECIClientDevice *peci_add_client(PECIBus *bus,
> + uint8_t address,
> + PECIClientProperties *props)
> +{
> + DeviceState *dev = qdev_new("peci-client");
> + PECIClientDevice *client;
> +
> + /* Only 8 addresses supported as of rev 4.1, 0x30 to 0x37 */
> + if (address < PECI_BASE_ADDR || address > PECI_BASE_ADDR + 7) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to add client at 0x%02x",
> + __func__, address);
> + return 0;
> + }
> +
> + client = PECI_CLIENT(dev);
> + client->address = address;
> +
> + /* these fields are optional, get set to max if unset or invalid */
> + if (!props->cpu_cores || props->cpu_cores > PECI_NUM_CPUS_MAX) {
> + props->cpu_cores = PECI_NUM_CPUS_MAX;
> + }
> + if (!props->dimms || props->dimms > PECI_NUM_DIMMS_MAX) {
> + props->dimms = PECI_NUM_DIMMS_MAX;
> + }
> + if (!props->cpu_family) {
> + props->cpu_family = FAM6_ICELAKE_X;
> + }
> + if (!props->dimms_per_channel ||
> + props->dimms_per_channel > PECI_DIMMS_PER_CHANNEL_MAX) {
> + props->dimms_per_channel = 2;
> + }
> +
> + client->cpu_id = props->cpu_family;
> + client->cpu_cores = props->cpu_cores;
> + client->dimms = props->dimms;
> + client->dimms_per_channel = props->dimms_per_channel;
> +
> + /* TODO: find real revisions and TJ max for supported families */
> + client->tjmax = 90;
> + client->tcontrol = -5;
> +
> + switch (props->cpu_family) {
> + case FAM6_HASWELL_X:
> + client->revision = 0x31;
> + break;
> +
> + case FAM6_BROADWELL_X:
> + client->revision = 0x32;
> + break;
> +
> + case FAM6_SKYLAKE_X:
> + case FAM6_SKYLAKE_XD:
> + client->revision = 0x36;
> + break;
> +
> + case FAM6_ICELAKE_X:
> + case FAM6_SAPPHIRE_RAPIDS_X:
> + client->revision = 0x40;
> + client->ucode = 0x8c0004a0;
> + break;
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "%s: unsupported cpu: 0x%x\n",
> + __func__, props->cpu_family);
> + client->revision = 0x31;
> + break;
> + }
> +
> + qdev_realize_and_unref(&client->qdev, &bus->qbus, &error_abort);
> + bus->num_clients += 1;
> + return client;
> +}
> +
> +static void peci_client_get(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + /* use millidegrees convention */
> + uint32_t value = *(uint8_t *)opaque * 1000;
> + visit_type_uint32(v, name, &value, errp);
> +}
> +
> +static void peci_client_set(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + PECIClientDevice *client = PECI_CLIENT(obj);
> + uint8_t *internal = opaque;
> + uint32_t value;
> +
> + if (!visit_type_uint32(v, name, &value, errp)) {
> + return;
> + }
> +
> + g_assert(value <= 255000);
> +
> + *internal = value / 1000;
> + peci_client_update_temps(client);
> +}
> +
> +static void peci_client_reset(Object *obj, ResetType type)
> +{
> + PECIClientDevice *client = PECI_CLIENT(obj);
> + client->core_temp_max = 0;
> + client->dimm_temp_max = 0;
> +}
> +
> +static const VMStateDescription vmstate_peci_client = {
> + .name = TYPE_PECI_CLIENT,
> + .version_id = 0,
> + .minimum_version_id = 0,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT8(address, PECIClientDevice),
> + VMSTATE_UINT8(device_info, PECIClientDevice),
> + VMSTATE_UINT8(revision, PECIClientDevice),
> + VMSTATE_UINT32(cpu_id, PECIClientDevice),
> + VMSTATE_UINT8(cpu_cores, PECIClientDevice),
> + VMSTATE_UINT8(tjmax, PECIClientDevice),
> + VMSTATE_INT8(tcontrol, PECIClientDevice),
> + VMSTATE_UINT8_ARRAY(core_temp, PECIClientDevice, PECI_NUM_CPUS_MAX),
> + VMSTATE_UINT8(dimms, PECIClientDevice),
> + VMSTATE_UINT8(dimms_per_channel, PECIClientDevice),
> + VMSTATE_UINT8_ARRAY(dimm_temp, PECIClientDevice , PECI_NUM_DIMMS_MAX),
> + VMSTATE_END_OF_LIST()
> + },
> +};
> +
> +static void peci_client_realize(DeviceState *dev, Error **errp)
> +{
> + PECIClientDevice *client = PECI_CLIENT(dev);
> + for (size_t i = 0; i < client->cpu_cores; i++) {
> + client->core_temp[i] = PECI_CLIENT_DEFAULT_TEMP;
> + object_property_add(OBJECT(client), "cpu_temp[*]", "uint8",
> + peci_client_get,
> + peci_client_set, NULL, &client->core_temp[i]);
> + }
> +
> + for (size_t i = 0; i < client->dimms; i++) {
> + client->dimm_temp[i] = PECI_CLIENT_DEFAULT_TEMP;
> + object_property_add(OBJECT(client), "dimm_temp[*]", "uint8",
> + peci_client_get,
> + peci_client_set, NULL, &client->dimm_temp[i]);
> + }
> +}
> +
> +static void peci_client_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
> +
> + dc->desc = "PECI Client Device";
> + dc->bus_type = TYPE_PECI_BUS;
> + dc->realize = peci_client_realize;
> + dc->vmsd = &vmstate_peci_client;
> + set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> + rc->phases.enter = peci_client_reset;
> +}
> +
> +static const TypeInfo peci_client_info = {
> + .name = TYPE_PECI_CLIENT,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(PECIClientDevice),
> + .class_init = peci_client_class_init,
> +};
> +
> +static void peci_client_register_types(void)
> +{
> + type_register_static(&peci_client_info);
> +}
> +
> +type_init(peci_client_register_types)
> diff --git a/hw/peci/peci-core.c b/hw/peci/peci-core.c
> new file mode 100644
> index 0000000000..8210bfa198
> --- /dev/null
> +++ b/hw/peci/peci-core.c
> @@ -0,0 +1,182 @@
> +/*
> + * PECI - Platform Environment Control Interface
> + * Copyright 2021 Google LLC
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +/*
> + * This PECI implementation aims to simulate a host with peci as viewed by a
> + * BMC. This is developed with OpenBMC firmware running in QEMU.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/peci/peci.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qemu/module.h"
> +#include "qemu/log.h"
> +#include "trace.h"
> +
> +#define PECI_FCS_OK 0
> +#define PECI_FCS_ERR 1
> +
> +static void peci_rd_pkg_cfg(PECIClientDevice *client, PECICmd *pcmd)
> +{
> + PECIPkgCfg *resp = (PECIPkgCfg *)pcmd->tx;
> + uint8_t index = pcmd->rx[1];
> + uint16_t param = pcmd->rx[3] | pcmd->rx[2];
> +
> + switch (index) {
> + case PECI_MBX_CPU_ID: /* CPU Family ID*/
> + trace_peci_rd_pkg_cfg("CPU ID");
> + switch (param) {
> + case PECI_PKG_ID_CPU_ID:
> + resp->data = client->cpu_id;
> + break;
> +
> + case PECI_PKG_ID_MICROCODE_REV:
> + resp->data = client->ucode;
> + break;
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "%s: CPU ID param %u\n", __func__, param);
> + break;
> + }
> + break;
> +
> + case PECI_MBX_DTS_MARGIN:
> + trace_peci_rd_pkg_cfg("DTS MARGIN");
> + /*
> + * Processors return a value of DTS reading in 10.6 format
> + * (10 bits signed decimal, 6 bits fractional).
> + */
> + resp->data = (-1 * client->core_temp_max) << 6;
> + break;
> +
> + case PECI_MBX_DDR_DIMM_TEMP:
> + trace_peci_rd_pkg_cfg("DDR DIMM TEMP");
> + if (param > PECI_NUM_CHANNELS_MAX) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: DDR_DIMM_TEMP unsupported channel index %d",
> + __func__, param);
> + param = PECI_NUM_CHANNELS_MAX;
> + }
> + uint8_t channel_index = param * client->dimms_per_channel;
> + memcpy(&resp->data,
> + &client->dimm_temp[channel_index],
> + sizeof(client->dimm_temp[0]) * client->dimms_per_channel);
> + break;
> +
> + case PECI_MBX_TEMP_TARGET:
> + trace_peci_rd_pkg_cfg("TEMP TARGET");
> + PECITempTarget target = {
> + .tcontrol = client->tcontrol,
> + .tjmax = client->tjmax,
> + };
> + memcpy(&resp->data, &target, sizeof(target));
> + break;
> +
> + case PECI_MBX_PPIN:
> + trace_peci_rd_pkg_cfg("PPIN");
> + resp->data = 0xdeadbeef;
> + break;
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "%s: unimplemented PkgCfg Index: %u\n",
> + __func__, index);
> + resp->cc = PECI_DEV_CC_INVALID_REQ;
> + return;
> + }
> +
> + resp->cc = PECI_DEV_CC_SUCCESS;
> +}
> +
> +int peci_handle_cmd(PECIBus *bus, PECICmd *pcmd)
> +{
> + PECIClientDevice *client = peci_get_client(bus, pcmd->addr);
> +
> + if (!client) { /* ignore commands if clients aren't found */
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: no peci client at address: 0x%02x\n",
> + __func__, pcmd->addr);
> + return PECI_FCS_ERR;
> + }
> +
> + /* clear output buffer before handling command */
> + for (size_t i = 0; i < pcmd->rd_length; i++) {
> + pcmd->tx[i] = 0;
> + }
> +
> + switch (pcmd->cmd) {
> + case PECI_CMD_PING:
> + trace_peci_handle_cmd("PING!", pcmd->addr);
> + break;
> +
> + case PECI_CMD_GET_DIB: /* Device Info Byte */
> + trace_peci_handle_cmd("GetDIB", pcmd->addr);
> + PECIDIB dib = {
> + .device_info = client->device_info,
> + .revision = client->revision,
> + };
> + memcpy(pcmd->tx, &dib, sizeof(PECIDIB));
> + break;
> +
> + case PECI_CMD_GET_TEMP: /* maximum die temp in socket */
> + trace_peci_handle_cmd("GetTemp", pcmd->addr);
> + /*
> + * The data is returned as a negative value representing the number of
> + * degrees centigrade below the maximum processor junction temperature
> + */
> + memcpy(pcmd->tx, &client->core_temp_max, sizeof(client->core_temp_max));
> + break;
> +
> + case PECI_CMD_RD_PKG_CFG:
> + trace_peci_handle_cmd("RdPkgConfig", pcmd->addr);
> + peci_rd_pkg_cfg(client, pcmd);
> + break;
> +
> + case PECI_CMD_RD_IA_MSR:
> + trace_peci_handle_cmd("RdIAMSR", pcmd->addr);
> + qemu_log_mask(LOG_UNIMP, "%s: unimplemented RD_IA_MSR\n", __func__);
> + break;
> +
> + case PECI_CMD_RD_PCI_CFG:
> + trace_peci_handle_cmd("RdPCIConfig", pcmd->addr);
> + qemu_log_mask(LOG_UNIMP, "%s: unimplemented PCI_CFG\n", __func__);
> + break;
> +
> + case PECI_CMD_RD_PCI_CFG_LOCAL:
> + trace_peci_handle_cmd("RdPCIConfigLocal", pcmd->addr);
> + qemu_log_mask(LOG_UNIMP, "%s: unimplemented PCI_CFG_LOCAL\n", __func__);
> + break;
> +
> + case PECI_CMD_RD_END_PT_CFG:
> + qemu_log_mask(LOG_UNIMP, "%s: unimplemented CMD_RD_END_PT_CFG\n",
> + __func__);
> + break;
> +
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown cmd: %x\n",
> + __func__, pcmd->cmd);
> + break;
> + }
> +
> + return PECI_FCS_OK;
> +}
> +
> +PECIBus *peci_bus_create(DeviceState *parent)
> +{
> + return PECI_BUS(qbus_new(TYPE_PECI_BUS, parent, "peci-bus"));
> +};
> +
> +static const TypeInfo peci_types[] = {
> + {
> + .name = TYPE_PECI_BUS,
> + .parent = TYPE_BUS,
> + .instance_size = sizeof(PECIBus),
> + },
> +};
> +
> +DEFINE_TYPES(peci_types);
> diff --git a/hw/peci/trace-events b/hw/peci/trace-events
> new file mode 100644
> index 0000000000..f90c998dd9
> --- /dev/null
> +++ b/hw/peci/trace-events
> @@ -0,0 +1,5 @@
> +# See docs/devel/tracing.rst for syntax documentation.
> +
> +# peci-core.c
> +peci_handle_cmd(const char* s, uint8_t addr) "%s @ 0x%02" PRIx8
> +peci_rd_pkg_cfg(const char* s) "%s"
> diff --git a/hw/peci/trace.h b/hw/peci/trace.h
> new file mode 100644
> index 0000000000..4283e3bfc5
> --- /dev/null
> +++ b/hw/peci/trace.h
> @@ -0,0 +1 @@
> +#include "trace/trace-hw_peci.h"
> diff --git a/include/hw/peci/peci.h b/include/hw/peci/peci.h
> new file mode 100644
> index 0000000000..1a0abe65cd
> --- /dev/null
> +++ b/include/hw/peci/peci.h
> @@ -0,0 +1,194 @@
> +/*
> + * PECI - Platform Environment Control Interface
> + *
> + * Copyright 2021 Google LLC
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef PECI_H
> +#define PECI_H
> +
> +#include "hw/qdev-core.h"
> +#include "qom/object.h"
> +
> +#define PECI_CMD_PING 0x0
> +#define PECI_CMD_GET_DIB 0xF7
> +#define PECI_CMD_GET_TEMP 0x01
> +#define PECI_CMD_RD_PKG_CFG 0xA1
> +#define PECI_CMD_WR_PKG_CFG 0xA5
> +#define PECI_MBX_CPU_ID 0 /* Package Identifier Read */
> +#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */
> +#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */
> +#define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */
> +#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
> +#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Revision */
> +#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
> +#define PECI_MBX_VR_DEBUG 1 /* VR Debug */
> +#define PECI_MBX_PKG_TEMP_READ 2 /* Package Temperature Read */
> +#define PECI_MBX_ENERGY_COUNTER 3 /* Energy counter */
> +#define PECI_MBX_ENERGY_STATUS 4 /* DDR Energy Status */
> +#define PECI_MBX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */
> +#define PECI_MBX_EPI 6 /* Efficient Performance Indication */
> +#define PECI_MBX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */
> +#define PECI_MBX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */
> +#define PECI_MBX_DTS_MARGIN 10 /* DTS thermal margin */
> +#define PECI_MBX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */
> +#define PECI_MBX_CFG_TDP_CONTROL 12 /* TDP Config Control */
> +#define PECI_MBX_CFG_TDP_LEVELS 13 /* TDP Config Levels */
> +#define PECI_MBX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */
> +#define PECI_MBX_CFG_ICCMAX 15 /* Configurable ICCMAX */
> +#define PECI_MBX_TEMP_TARGET 16 /* Temperature Target Read */
> +#define PECI_MBX_CURR_CFG_LIMIT 17 /* Current Config Limit */
> +#define PECI_MBX_PPIN 19 /* Processor Inventory Number */
> +#define PECI_MBX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */
> +#define PECI_MBX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */
> +#define PECI_MBX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */
> +#define PECI_MBX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */
> +#define PECI_MBX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */
> +#define PECI_MBX_TDP 28 /* Thermal design power minimum */
> +#define PECI_MBX_TDP_HIGH 29 /* Thermal design power maximum */
> +#define PECI_MBX_TDP_UNITS 30 /* Units for power/energy registers */
> +#define PECI_MBX_RUN_TIME 31 /* Accumulated Run Time */
> +#define PECI_MBX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */
> +#define PECI_MBX_TURBO_RATIO 33 /* Turbo Activation Ratio */
> +#define PECI_MBX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */
> +#define PECI_MBX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */
> +#define PECI_MBX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */
> +#define PECI_MBX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */
> +#define PECI_MBX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */
> +#define PECI_MBX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */
> +#define PECI_MBX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */
> +#define PECI_MBX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */
> +#define PECI_MBX_DDR_THERM_STATUS 46 /* DDR Thermal Status */
> +#define PECI_MBX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */
> +#define PECI_MBX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */
> +#define PECI_MBX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */
> +#define PECI_MBX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */
> +#define PECI_MBX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */
> +#define PECI_MBX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */
> +#define PECI_MBX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */
> +#define PECI_MBX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */
> +#define PECI_MBX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */
> +#define PECI_MBX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */
> +#define PECI_CMD_RD_IA_MSR 0xB1
> +#define PECI_CMD_WR_IA_MSR 0xB5
> +#define PECI_CMD_RD_IA_MSREX 0xD1
> +#define PECI_CMD_RD_PCI_CFG 0x61
> +#define PECI_CMD_WR_PCI_CFG 0x65
> +#define PECI_CMD_RD_PCI_CFG_LOCAL 0xE1
> +#define PECI_CMD_WR_PCI_CFG_LOCAL 0xE5
> +#define PECI_CMD_RD_END_PT_CFG 0xC1
> +#define PECI_CMD_WR_END_PT_CFG 0xC5
> +#define PECI_CMD_CRASHDUMP_GET_FRAME 0x71
> +
> +/* Device Specific Completion Code (CC) Definition */
> +#define PECI_DEV_CC_SUCCESS 0x40
> +#define PECI_DEV_CC_NEED_RETRY 0x80
> +#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81
> +#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82
> +#define PECI_DEV_CC_INVALID_REQ 0x90
> +#define PECI_DEV_CC_MCA_ERROR 0x91
> +#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93
> +#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94
> +#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98
> +#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B
> +#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C
> +
> +
> +typedef struct PECIDIB { /* DIB - Device Info Byte(s) */
> + uint8_t device_info; /* bit 2 - num of domains */
> + uint8_t revision;
> +} PECIDIB;
> +
> +typedef struct __attribute__ ((__packed__)) {
> + uint8_t cc; /* completion code */
> + uint32_t data;
> +} PECIPkgCfg;
> +
> +typedef struct PECITempTarget {
> + uint8_t reserved;
> + int8_t tcontrol;
> + uint8_t tjmax;
> +} PECITempTarget;
> +
> +#define PECI_BASE_ADDR 0x30
> +#define PECI_BUFFER_SIZE 0x100
> +#define PECI_NUM_CPUS_MAX 56
> +#define PECI_DIMMS_PER_CHANNEL_MAX 3
> +#define PECI_NUM_CHANNELS_MAX 8
> +#define PECI_NUM_DIMMS_MAX (PECI_NUM_CHANNELS_MAX * PECI_DIMMS_PER_CHANNEL_MAX)
> +
> +typedef struct PECIClientDevice {
> + DeviceState qdev;
> + uint8_t address;
> + uint8_t device_info;
> + uint8_t revision;
> +
> + /* CPU */
> + uint32_t cpu_id;
> + uint8_t cpu_cores;
> + uint32_t ucode;
> + uint8_t tjmax;
> + int8_t tcontrol;
> + int8_t core_temp_max; /* absolute temp - tjmax */
> + uint8_t core_temp[PECI_NUM_CPUS_MAX];
> +
> + /* DIMMS */
> + uint8_t dimms;
> + uint8_t dimms_per_channel;
> + uint8_t dimm_temp_max;
> + uint8_t dimm_temp[PECI_NUM_DIMMS_MAX];
> +
> +} PECIClientDevice;
> +
> +#define TYPE_PECI_CLIENT "peci-client"
> +OBJECT_DECLARE_SIMPLE_TYPE(PECIClientDevice, PECI_CLIENT)
> +
> +typedef struct PECIBus {
> + BusState qbus;
> + uint8_t num_clients;
> +} PECIBus;
> +
> +#define TYPE_PECI_BUS "peci-bus"
> +OBJECT_DECLARE_SIMPLE_TYPE(PECIBus, PECI_BUS)
> +
> +/* Creates a basic qemu bus onto which PECI clients will be attached */
> +PECIBus *peci_bus_create(DeviceState *parent);
> +
> +enum {
> + FAM6_HASWELL_X = 0x306F0,
> + FAM6_BROADWELL_X = 0x406F0,
> + FAM6_SKYLAKE_X = 0x50650,
> + FAM6_SKYLAKE_XD = 0x50660,
> + FAM6_ICELAKE_X = 0x606A0,
> + FAM6_SAPPHIRE_RAPIDS_X = 0x806F3,
> +};
I'm curious if we really need the CPU family here, or if we could just
base everything off the PECI version.
The PECI specification doesn't mention the CPU family, does it? Or maybe
it does.
> +
> +typedef struct PECIClientProperties {
> + uint32_t cpu_family;
> + uint8_t cpu_cores;
> + uint8_t dimms;
> + uint8_t dimms_per_channel;
> +} PECIClientProperties;
> +
> +/* Creates a PECI client with the specified cpu and dimm count */
> +PECIClientDevice *peci_add_client(PECIBus *bus,
> + uint8_t address,
> + PECIClientProperties *props);
> +PECIClientDevice *peci_get_client(PECIBus *bus, uint8_t addr);
> +
> +typedef struct PECICmd {
> + uint8_t addr;
> + uint8_t cmd;
> +
> + size_t wr_length;
> + uint8_t rx[PECI_BUFFER_SIZE];
> +
> + size_t rd_length;
> + uint8_t tx[PECI_BUFFER_SIZE];
> +} PECICmd;
> +
> +int peci_handle_cmd(PECIBus *bus, PECICmd *pcmd);
> +
> +#endif
> diff --git a/meson.build b/meson.build
> index 20fddbd707..55594702c3 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -2965,6 +2965,7 @@ if have_system
> 'hw/nvram',
> 'hw/pci',
> 'hw/pci-host',
> + 'hw/peci',
> 'hw/ppc',
> 'hw/rdma',
> 'hw/rdma/vmw',
> --
> 2.37.2.789.g6183377224-goog
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 1/3] hw/peci: add initial support for PECI
2022-09-09 19:58 ` Peter Delevoryas
@ 2022-09-13 18:21 ` Titus Rwantare
2022-09-13 18:28 ` Peter Delevoryas
0 siblings, 1 reply; 13+ messages in thread
From: Titus Rwantare @ 2022-09-13 18:21 UTC (permalink / raw)
To: Peter Delevoryas
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Hao Wu, Patrick Venture
On Fri, 9 Sept 2022 at 12:58, Peter Delevoryas <peter@pjd.dev> wrote:
> > +/*
> > + * PECI Client device
> > + * Copyright 2021 Google LLC
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
>
> Not sure, but I think the SPDX license identifier is supposed to be in
> the first line? Maybe not though. I would have expected:
>
That's a Linux thing as far as I can tell. QEMU has it in the top comment.
>
> I'm curious if we really need the CPU family here, or if we could just
> base everything off the PECI version.
>
> The PECI specification doesn't mention the CPU family, does it? Or maybe
> it does.
>
I needed the family info anyway for RdPkgConfig() CPU ID, and thought it
would be more readable to specify that in the board file than the PECI version.
We tend to add new machines to QEMU by copying the config of an existing
machine, I think this way makes it more obvious that this is a field
that is changing.
Titus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 1/3] hw/peci: add initial support for PECI
2022-09-13 18:21 ` Titus Rwantare
@ 2022-09-13 18:28 ` Peter Delevoryas
0 siblings, 0 replies; 13+ messages in thread
From: Peter Delevoryas @ 2022-09-13 18:28 UTC (permalink / raw)
To: Titus Rwantare
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Hao Wu, Patrick Venture
On Tue, Sep 13, 2022 at 11:21:16AM -0700, Titus Rwantare wrote:
> On Fri, 9 Sept 2022 at 12:58, Peter Delevoryas <peter@pjd.dev> wrote:
>
> > > +/*
> > > + * PECI Client device
> > > + * Copyright 2021 Google LLC
> > > + *
> > > + * SPDX-License-Identifier: GPL-2.0-or-later
> >
> > Not sure, but I think the SPDX license identifier is supposed to be in
> > the first line? Maybe not though. I would have expected:
> >
>
> That's a Linux thing as far as I can tell. QEMU has it in the top comment.
Oh ok, nevermind then.
>
> >
> > I'm curious if we really need the CPU family here, or if we could just
> > base everything off the PECI version.
> >
> > The PECI specification doesn't mention the CPU family, does it? Or maybe
> > it does.
> >
>
> I needed the family info anyway for RdPkgConfig() CPU ID, and thought it
> would be more readable to specify that in the board file than the PECI version.
> We tend to add new machines to QEMU by copying the config of an existing
> machine, I think this way makes it more obvious that this is a field
> that is changing.
Yeah, I think you're right. And looking at the PECI spec, they refer to
families directly when describing new features, so this seems
appropriate.
Reviewed-by: Peter Delevoryas <peter@pjd.dev>
>
>
> Titus
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH 2/3] hw/peci: add PECI support for NPCM7xx BMCs
2022-09-06 22:05 [RFC PATCH 0/3] Initial PECI bus support Titus Rwantare
2022-09-06 22:05 ` [RFC PATCH 1/3] hw/peci: add initial support for PECI Titus Rwantare
@ 2022-09-06 22:05 ` Titus Rwantare
2022-09-09 20:10 ` Peter Delevoryas
2022-09-06 22:05 ` [RFC PATCH 3/3] hw/peci: add support for EndPointConfig reads Titus Rwantare
2022-09-09 19:54 ` [RFC PATCH 0/3] Initial PECI bus support Peter Delevoryas
3 siblings, 1 reply; 13+ messages in thread
From: Titus Rwantare @ 2022-09-06 22:05 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-arm, peter, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Titus Rwantare, Patrick Venture
This allows BMC firmware for npcm7xx BMCs to talk to a PECI client
in qemu.
Signed-off-by: Titus Rwantare <titusr@google.com>
Reviewed-by: Patrick Venture <venture@google.com>
---
MAINTAINERS | 3 +-
hw/arm/Kconfig | 1 +
hw/arm/npcm7xx.c | 9 ++
hw/peci/meson.build | 1 +
hw/peci/npcm7xx_peci.c | 204 +++++++++++++++++++++++++++++++++
hw/peci/trace-events | 5 +
include/hw/arm/npcm7xx.h | 2 +
include/hw/peci/npcm7xx_peci.h | 37 ++++++
8 files changed, 261 insertions(+), 1 deletion(-)
create mode 100644 hw/peci/npcm7xx_peci.c
create mode 100644 include/hw/peci/npcm7xx_peci.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 14ab29679d..f87dfe5bfa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2959,7 +2959,7 @@ R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
R: Thomas Huth <thuth@redhat.com>
-R: Darren Kenny <darren.kenny@oracle.com>
+R: Darren Kenny <darren.kenny@oracle.com>
R: Qiuhao Li <Qiuhao.Li@outlook.com>
S: Maintained
F: tests/qtest/fuzz/
@@ -3218,6 +3218,7 @@ S: Maintained
F: hw/peci/peci-core.c
F: hw/peci/peci-client.c
F: include/hw/peci/peci.h
+F: hw/peci/npcm7xx_peci.c
Firmware schema specifications
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 15fa79afd3..cb38c6c88f 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -408,6 +408,7 @@ config NPCM7XX
select SSI
select UNIMP
select PCA954X
+ select PECI
config FSL_IMX25
bool
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index d85cc02765..d408dd7eb4 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -45,6 +45,7 @@
#define NPCM7XX_CLK_BA (0xf0801000)
#define NPCM7XX_MC_BA (0xf0824000)
#define NPCM7XX_RNG_BA (0xf000b000)
+#define NPCM7XX_PECI_BA (0xf0100000)
/* USB Host modules */
#define NPCM7XX_EHCI_BA (0xf0806000)
@@ -83,6 +84,7 @@ enum NPCM7xxInterrupt {
NPCM7XX_UART1_IRQ,
NPCM7XX_UART2_IRQ,
NPCM7XX_UART3_IRQ,
+ NPCM7XX_PECI_IRQ = 6,
NPCM7XX_EMC1RX_IRQ = 15,
NPCM7XX_EMC1TX_IRQ,
NPCM7XX_MMC_IRQ = 26,
@@ -445,6 +447,7 @@ static void npcm7xx_init(Object *obj)
}
object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
+ object_initialize_child(obj, "peci", &s->peci, TYPE_NPCM7XX_PECI);
}
static void npcm7xx_realize(DeviceState *dev, Error **errp)
@@ -715,6 +718,12 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
+ /* PECI */
+ sysbus_realize(SYS_BUS_DEVICE(&s->peci), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->peci), 0, NPCM7XX_PECI_BA);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
+ npcm7xx_irq(s, NPCM7XX_PECI_IRQ));
+
create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
diff --git a/hw/peci/meson.build b/hw/peci/meson.build
index 01cfa95abe..ee033eb915 100644
--- a/hw/peci/meson.build
+++ b/hw/peci/meson.build
@@ -1 +1,2 @@
softmmu_ss.add(when: 'CONFIG_PECI', if_true: files('peci-core.c', 'peci-client.c'))
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_peci.c'))
diff --git a/hw/peci/npcm7xx_peci.c b/hw/peci/npcm7xx_peci.c
new file mode 100644
index 0000000000..17a2642898
--- /dev/null
+++ b/hw/peci/npcm7xx_peci.c
@@ -0,0 +1,204 @@
+/*
+ * Nuvoton NPCM7xx PECI Module
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/peci/npcm7xx_peci.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qemu/units.h"
+#include "trace.h"
+
+#define PECI_CTL_STS 0
+#define PECI_CTL_STS_DONE_EN BIT(6)
+#define PECI_CTL_STS_ABRT_ERR BIT(4)
+#define PECI_CTL_STS_CRC_ERR BIT(3)
+#define PECI_CTL_STS_DONE BIT(1)
+#define PECI_CTL_STS_START_BUSY BIT(0)
+#define PECI_RD_LENGTH 0x4
+#define PECI_ADDR 0x8
+#define PECI_CMD 0xC
+#define PECI_CTL2 0x10
+#define PECI_WR_LENGTH 0x1C
+#define PECI_PDDR 0x2C
+#define PECI_DAT_INOUT(reg) (0x100 + (reg) * 4)
+
+static uint64_t npcm7xx_peci_read(void *opaque, hwaddr offset, unsigned size)
+{
+ NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque);
+ uint8_t ret = 0;
+
+ if (!ps->bus->num_clients) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to board\n",
+ __func__);
+ return 0;
+ }
+
+ qemu_irq_lower(ps->irq);
+
+ switch (offset) {
+ case PECI_CTL_STS:
+ ret = ps->status;
+ break;
+
+ case PECI_RD_LENGTH:
+ ret = ps->pcmd.rd_length;
+ break;
+
+ case PECI_ADDR:
+ ret = ps->pcmd.addr;
+ break;
+
+ case PECI_CMD:
+ ret = ps->pcmd.cmd;
+ break;
+
+ case PECI_CTL2:
+ ret = ps->ctl2;
+ break;
+
+ case PECI_WR_LENGTH:
+ ret = ps->pcmd.wr_length;
+ break;
+
+ case PECI_PDDR:
+ qemu_log_mask(LOG_UNIMP, "%s: PECI PDDR is unimplemented.\n", __func__);
+ ret = ps->pddr; /* undoc register */
+ break;
+
+ case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63):
+ ret = ps->pcmd.tx[(offset - PECI_DAT_INOUT(0)) / 4];
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register 0x%lx\n",
+ __func__, offset);
+ ret = 0xff;
+ break;
+ }
+ trace_npcm7xx_peci_read(offset, ret);
+ return ret;
+}
+
+static void npcm7xx_peci_write(void *opaque, hwaddr offset, uint64_t input,
+ unsigned size)
+{
+ NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque);
+ uint8_t data = input & 0xff;
+
+ trace_npcm7xx_peci_write(offset, input);
+
+ /* ignore writes if the bus has not been populated */
+ if (!ps->bus->num_clients) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to board\n",
+ __func__);
+ return;
+ }
+
+ switch (offset) {
+ case PECI_CTL_STS:
+ ps->status = data;
+ /* STS_START busy is set by the bmc when the request is written */
+ if (data & PECI_CTL_STS_START_BUSY) {
+ if (!peci_handle_cmd(ps->bus, &(ps->pcmd))) {
+ ps->status |= PECI_CTL_STS_ABRT_ERR;
+ }
+ ps->status |= PECI_CTL_STS_DONE;
+ ps->status &= ~PECI_CTL_STS_START_BUSY;
+ qemu_irq_raise(ps->irq);
+ }
+ break;
+
+ case PECI_RD_LENGTH:
+ ps->pcmd.rd_length = data;
+ break;
+
+ case PECI_ADDR:
+ ps->pcmd.addr = data;
+ break;
+
+ case PECI_CMD:
+ ps->pcmd.cmd = data;
+ break;
+
+ case PECI_CTL2:
+ ps->ctl2 = data;
+ break;
+
+ case PECI_WR_LENGTH:
+ ps->pcmd.wr_length = data;
+ break;
+
+ case PECI_PDDR:
+ ps->pddr = data;
+ break;
+
+ case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63):
+ ps->pcmd.rx[(offset - PECI_DAT_INOUT(0)) / 4] = data;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: to unknown register 0x%lx : 0x%lx\n",
+ __func__, offset, input);
+ return;
+ }
+
+}
+
+static void npcm7xx_peci_reset(Object *obj, ResetType type)
+{
+ NPCM7xxPECIState *ps = NPCM7XX_PECI(obj);
+
+ ps->status = PECI_CTL_STS_DONE_EN;
+}
+
+static const MemoryRegionOps npcm7xx_peci_ops = {
+ .read = npcm7xx_peci_read,
+ .write = npcm7xx_peci_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .min_access_size = 1,
+ .unaligned = false,
+ },
+};
+
+static void npcm7xx_peci_realize(DeviceState *dev, Error **errp)
+{
+ NPCM7xxPECIState *ps = NPCM7XX_PECI(dev);
+ SysBusDevice *sbd = &ps->parent;
+
+ memory_region_init_io(&ps->iomem, OBJECT(ps), &npcm7xx_peci_ops, ps,
+ TYPE_NPCM7XX_PECI, 4 * KiB);
+
+ sysbus_init_mmio(sbd, &ps->iomem);
+ sysbus_init_irq(sbd, &ps->irq);
+
+ ps->bus = peci_bus_create(DEVICE(ps));
+}
+
+static void npcm7xx_peci_class_init(ObjectClass *klass, void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "NPCM7xx PECI Module";
+ dc->realize = npcm7xx_peci_realize;
+ rc->phases.enter = npcm7xx_peci_reset;
+}
+
+static const TypeInfo npcm7xx_peci_types[] = {
+ {
+ .name = TYPE_NPCM7XX_PECI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCM7xxPECIState),
+ .class_init = npcm7xx_peci_class_init,
+ },
+};
+
+DEFINE_TYPES(npcm7xx_peci_types)
diff --git a/hw/peci/trace-events b/hw/peci/trace-events
index f90c998dd9..a895b21f7b 100644
--- a/hw/peci/trace-events
+++ b/hw/peci/trace-events
@@ -3,3 +3,8 @@
# peci-core.c
peci_handle_cmd(const char* s, uint8_t addr) "%s @ 0x%02" PRIx8
peci_rd_pkg_cfg(const char* s) "%s"
+
+# npcm7xx_peci.c
+npcm7xx_peci_cmd(uint64_t cmd) "cmd: 0x%04" PRIx64
+npcm7xx_peci_read(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
+npcm7xx_peci_write(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
index ce593235d9..9e7cf8b774 100644
--- a/include/hw/arm/npcm7xx.h
+++ b/include/hw/arm/npcm7xx.h
@@ -30,6 +30,7 @@
#include "hw/misc/npcm7xx_rng.h"
#include "hw/net/npcm7xx_emc.h"
#include "hw/nvram/npcm7xx_otp.h"
+#include "hw/peci/npcm7xx_peci.h"
#include "hw/timer/npcm7xx_timer.h"
#include "hw/ssi/npcm7xx_fiu.h"
#include "hw/usb/hcd-ehci.h"
@@ -105,6 +106,7 @@ typedef struct NPCM7xxState {
NPCM7xxFIUState fiu[2];
NPCM7xxEMCState emc[2];
NPCM7xxSDHCIState mmc;
+ NPCM7xxPECIState peci;
} NPCM7xxState;
#define TYPE_NPCM7XX "npcm7xx"
diff --git a/include/hw/peci/npcm7xx_peci.h b/include/hw/peci/npcm7xx_peci.h
new file mode 100644
index 0000000000..421f445041
--- /dev/null
+++ b/include/hw/peci/npcm7xx_peci.h
@@ -0,0 +1,37 @@
+/*
+ * Nuvoton NPCM7xx PECI Module
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef NPCM7XX_PECI_H
+#define NPCM7XX_PECI_H
+
+#include "exec/memory.h"
+#include "hw/irq.h"
+#include "hw/peci/peci.h"
+#include "hw/sysbus.h"
+
+typedef struct NPCM7xxPECIState {
+ SysBusDevice parent;
+
+ MemoryRegion iomem;
+
+ PECIBus *bus;
+ qemu_irq irq;
+
+ PECICmd pcmd;
+
+ /* Registers */
+ uint8_t status;
+ uint8_t ctl2;
+ uint8_t pddr;
+} NPCM7xxPECIState;
+
+#define TYPE_NPCM7XX_PECI "npcm7xx-peci"
+#define NPCM7XX_PECI(obj) \
+ OBJECT_CHECK(NPCM7xxPECIState, (obj), TYPE_NPCM7XX_PECI)
+
+#endif /* NPCM7XX_PECI_H */
--
2.37.2.789.g6183377224-goog
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 2/3] hw/peci: add PECI support for NPCM7xx BMCs
2022-09-06 22:05 ` [RFC PATCH 2/3] hw/peci: add PECI support for NPCM7xx BMCs Titus Rwantare
@ 2022-09-09 20:10 ` Peter Delevoryas
0 siblings, 0 replies; 13+ messages in thread
From: Peter Delevoryas @ 2022-09-09 20:10 UTC (permalink / raw)
To: Titus Rwantare
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Patrick Venture
On Tue, Sep 06, 2022 at 10:05:51PM +0000, Titus Rwantare wrote:
> This allows BMC firmware for npcm7xx BMCs to talk to a PECI client
> in qemu.
>
> Signed-off-by: Titus Rwantare <titusr@google.com>
> Reviewed-by: Patrick Venture <venture@google.com>
Looks good to me!
Reviewed-by: Peter Delevoryas <peter@pjd.dev>
> ---
> MAINTAINERS | 3 +-
> hw/arm/Kconfig | 1 +
> hw/arm/npcm7xx.c | 9 ++
> hw/peci/meson.build | 1 +
> hw/peci/npcm7xx_peci.c | 204 +++++++++++++++++++++++++++++++++
> hw/peci/trace-events | 5 +
> include/hw/arm/npcm7xx.h | 2 +
> include/hw/peci/npcm7xx_peci.h | 37 ++++++
> 8 files changed, 261 insertions(+), 1 deletion(-)
> create mode 100644 hw/peci/npcm7xx_peci.c
> create mode 100644 include/hw/peci/npcm7xx_peci.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 14ab29679d..f87dfe5bfa 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2959,7 +2959,7 @@ R: Paolo Bonzini <pbonzini@redhat.com>
> R: Bandan Das <bsd@redhat.com>
> R: Stefan Hajnoczi <stefanha@redhat.com>
> R: Thomas Huth <thuth@redhat.com>
> -R: Darren Kenny <darren.kenny@oracle.com>
> +R: Darren Kenny <darren.kenny@oracle.com>
> R: Qiuhao Li <Qiuhao.Li@outlook.com>
> S: Maintained
> F: tests/qtest/fuzz/
> @@ -3218,6 +3218,7 @@ S: Maintained
> F: hw/peci/peci-core.c
> F: hw/peci/peci-client.c
> F: include/hw/peci/peci.h
> +F: hw/peci/npcm7xx_peci.c
>
> Firmware schema specifications
> M: Philippe Mathieu-Daudé <f4bug@amsat.org>
> diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
> index 15fa79afd3..cb38c6c88f 100644
> --- a/hw/arm/Kconfig
> +++ b/hw/arm/Kconfig
> @@ -408,6 +408,7 @@ config NPCM7XX
> select SSI
> select UNIMP
> select PCA954X
> + select PECI
>
> config FSL_IMX25
> bool
> diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
> index d85cc02765..d408dd7eb4 100644
> --- a/hw/arm/npcm7xx.c
> +++ b/hw/arm/npcm7xx.c
> @@ -45,6 +45,7 @@
> #define NPCM7XX_CLK_BA (0xf0801000)
> #define NPCM7XX_MC_BA (0xf0824000)
> #define NPCM7XX_RNG_BA (0xf000b000)
> +#define NPCM7XX_PECI_BA (0xf0100000)
>
> /* USB Host modules */
> #define NPCM7XX_EHCI_BA (0xf0806000)
> @@ -83,6 +84,7 @@ enum NPCM7xxInterrupt {
> NPCM7XX_UART1_IRQ,
> NPCM7XX_UART2_IRQ,
> NPCM7XX_UART3_IRQ,
> + NPCM7XX_PECI_IRQ = 6,
> NPCM7XX_EMC1RX_IRQ = 15,
> NPCM7XX_EMC1TX_IRQ,
> NPCM7XX_MMC_IRQ = 26,
> @@ -445,6 +447,7 @@ static void npcm7xx_init(Object *obj)
> }
>
> object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
> + object_initialize_child(obj, "peci", &s->peci, TYPE_NPCM7XX_PECI);
> }
>
> static void npcm7xx_realize(DeviceState *dev, Error **errp)
> @@ -715,6 +718,12 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
> sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
> npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
>
> + /* PECI */
> + sysbus_realize(SYS_BUS_DEVICE(&s->peci), &error_abort);
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->peci), 0, NPCM7XX_PECI_BA);
> + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
> + npcm7xx_irq(s, NPCM7XX_PECI_IRQ));
> +
> create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
> create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
> create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
> diff --git a/hw/peci/meson.build b/hw/peci/meson.build
> index 01cfa95abe..ee033eb915 100644
> --- a/hw/peci/meson.build
> +++ b/hw/peci/meson.build
> @@ -1 +1,2 @@
> softmmu_ss.add(when: 'CONFIG_PECI', if_true: files('peci-core.c', 'peci-client.c'))
> +softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_peci.c'))
> diff --git a/hw/peci/npcm7xx_peci.c b/hw/peci/npcm7xx_peci.c
> new file mode 100644
> index 0000000000..17a2642898
> --- /dev/null
> +++ b/hw/peci/npcm7xx_peci.c
> @@ -0,0 +1,204 @@
> +/*
> + * Nuvoton NPCM7xx PECI Module
> + *
> + * Copyright 2021 Google LLC
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/peci/npcm7xx_peci.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qemu/units.h"
> +#include "trace.h"
> +
> +#define PECI_CTL_STS 0
> +#define PECI_CTL_STS_DONE_EN BIT(6)
> +#define PECI_CTL_STS_ABRT_ERR BIT(4)
> +#define PECI_CTL_STS_CRC_ERR BIT(3)
> +#define PECI_CTL_STS_DONE BIT(1)
> +#define PECI_CTL_STS_START_BUSY BIT(0)
> +#define PECI_RD_LENGTH 0x4
> +#define PECI_ADDR 0x8
> +#define PECI_CMD 0xC
> +#define PECI_CTL2 0x10
> +#define PECI_WR_LENGTH 0x1C
> +#define PECI_PDDR 0x2C
> +#define PECI_DAT_INOUT(reg) (0x100 + (reg) * 4)
> +
> +static uint64_t npcm7xx_peci_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque);
> + uint8_t ret = 0;
> +
> + if (!ps->bus->num_clients) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to board\n",
> + __func__);
> + return 0;
> + }
> +
> + qemu_irq_lower(ps->irq);
> +
> + switch (offset) {
> + case PECI_CTL_STS:
> + ret = ps->status;
> + break;
> +
> + case PECI_RD_LENGTH:
> + ret = ps->pcmd.rd_length;
> + break;
> +
> + case PECI_ADDR:
> + ret = ps->pcmd.addr;
> + break;
> +
> + case PECI_CMD:
> + ret = ps->pcmd.cmd;
> + break;
> +
> + case PECI_CTL2:
> + ret = ps->ctl2;
> + break;
> +
> + case PECI_WR_LENGTH:
> + ret = ps->pcmd.wr_length;
> + break;
> +
> + case PECI_PDDR:
> + qemu_log_mask(LOG_UNIMP, "%s: PECI PDDR is unimplemented.\n", __func__);
> + ret = ps->pddr; /* undoc register */
> + break;
> +
> + case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63):
> + ret = ps->pcmd.tx[(offset - PECI_DAT_INOUT(0)) / 4];
> + break;
> +
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register 0x%lx\n",
> + __func__, offset);
> + ret = 0xff;
> + break;
> + }
> + trace_npcm7xx_peci_read(offset, ret);
> + return ret;
> +}
> +
> +static void npcm7xx_peci_write(void *opaque, hwaddr offset, uint64_t input,
> + unsigned size)
> +{
> + NPCM7xxPECIState *ps = NPCM7XX_PECI(opaque);
> + uint8_t data = input & 0xff;
> +
> + trace_npcm7xx_peci_write(offset, input);
> +
> + /* ignore writes if the bus has not been populated */
> + if (!ps->bus->num_clients) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: no peci clients added to board\n",
> + __func__);
> + return;
> + }
> +
> + switch (offset) {
> + case PECI_CTL_STS:
> + ps->status = data;
> + /* STS_START busy is set by the bmc when the request is written */
> + if (data & PECI_CTL_STS_START_BUSY) {
> + if (!peci_handle_cmd(ps->bus, &(ps->pcmd))) {
> + ps->status |= PECI_CTL_STS_ABRT_ERR;
> + }
> + ps->status |= PECI_CTL_STS_DONE;
> + ps->status &= ~PECI_CTL_STS_START_BUSY;
> + qemu_irq_raise(ps->irq);
> + }
> + break;
> +
> + case PECI_RD_LENGTH:
> + ps->pcmd.rd_length = data;
> + break;
> +
> + case PECI_ADDR:
> + ps->pcmd.addr = data;
> + break;
> +
> + case PECI_CMD:
> + ps->pcmd.cmd = data;
> + break;
> +
> + case PECI_CTL2:
> + ps->ctl2 = data;
> + break;
> +
> + case PECI_WR_LENGTH:
> + ps->pcmd.wr_length = data;
> + break;
> +
> + case PECI_PDDR:
> + ps->pddr = data;
> + break;
> +
> + case PECI_DAT_INOUT(0) ... PECI_DAT_INOUT(63):
> + ps->pcmd.rx[(offset - PECI_DAT_INOUT(0)) / 4] = data;
> + break;
> +
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: to unknown register 0x%lx : 0x%lx\n",
> + __func__, offset, input);
> + return;
> + }
> +
> +}
> +
> +static void npcm7xx_peci_reset(Object *obj, ResetType type)
> +{
> + NPCM7xxPECIState *ps = NPCM7XX_PECI(obj);
> +
> + ps->status = PECI_CTL_STS_DONE_EN;
> +}
> +
> +static const MemoryRegionOps npcm7xx_peci_ops = {
> + .read = npcm7xx_peci_read,
> + .write = npcm7xx_peci_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> + .valid = {
> + .min_access_size = 1,
> + .min_access_size = 1,
> + .unaligned = false,
> + },
> +};
> +
> +static void npcm7xx_peci_realize(DeviceState *dev, Error **errp)
> +{
> + NPCM7xxPECIState *ps = NPCM7XX_PECI(dev);
> + SysBusDevice *sbd = &ps->parent;
> +
> + memory_region_init_io(&ps->iomem, OBJECT(ps), &npcm7xx_peci_ops, ps,
> + TYPE_NPCM7XX_PECI, 4 * KiB);
> +
> + sysbus_init_mmio(sbd, &ps->iomem);
> + sysbus_init_irq(sbd, &ps->irq);
> +
> + ps->bus = peci_bus_create(DEVICE(ps));
> +}
> +
> +static void npcm7xx_peci_class_init(ObjectClass *klass, void *data)
> +{
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->desc = "NPCM7xx PECI Module";
> + dc->realize = npcm7xx_peci_realize;
> + rc->phases.enter = npcm7xx_peci_reset;
> +}
> +
> +static const TypeInfo npcm7xx_peci_types[] = {
> + {
> + .name = TYPE_NPCM7XX_PECI,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(NPCM7xxPECIState),
> + .class_init = npcm7xx_peci_class_init,
> + },
> +};
> +
> +DEFINE_TYPES(npcm7xx_peci_types)
> diff --git a/hw/peci/trace-events b/hw/peci/trace-events
> index f90c998dd9..a895b21f7b 100644
> --- a/hw/peci/trace-events
> +++ b/hw/peci/trace-events
> @@ -3,3 +3,8 @@
> # peci-core.c
> peci_handle_cmd(const char* s, uint8_t addr) "%s @ 0x%02" PRIx8
> peci_rd_pkg_cfg(const char* s) "%s"
> +
> +# npcm7xx_peci.c
> +npcm7xx_peci_cmd(uint64_t cmd) "cmd: 0x%04" PRIx64
> +npcm7xx_peci_read(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
> +npcm7xx_peci_write(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
> diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
> index ce593235d9..9e7cf8b774 100644
> --- a/include/hw/arm/npcm7xx.h
> +++ b/include/hw/arm/npcm7xx.h
> @@ -30,6 +30,7 @@
> #include "hw/misc/npcm7xx_rng.h"
> #include "hw/net/npcm7xx_emc.h"
> #include "hw/nvram/npcm7xx_otp.h"
> +#include "hw/peci/npcm7xx_peci.h"
> #include "hw/timer/npcm7xx_timer.h"
> #include "hw/ssi/npcm7xx_fiu.h"
> #include "hw/usb/hcd-ehci.h"
> @@ -105,6 +106,7 @@ typedef struct NPCM7xxState {
> NPCM7xxFIUState fiu[2];
> NPCM7xxEMCState emc[2];
> NPCM7xxSDHCIState mmc;
> + NPCM7xxPECIState peci;
> } NPCM7xxState;
>
> #define TYPE_NPCM7XX "npcm7xx"
> diff --git a/include/hw/peci/npcm7xx_peci.h b/include/hw/peci/npcm7xx_peci.h
> new file mode 100644
> index 0000000000..421f445041
> --- /dev/null
> +++ b/include/hw/peci/npcm7xx_peci.h
> @@ -0,0 +1,37 @@
> +/*
> + * Nuvoton NPCM7xx PECI Module
> + *
> + * Copyright 2021 Google LLC
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef NPCM7XX_PECI_H
> +#define NPCM7XX_PECI_H
> +
> +#include "exec/memory.h"
> +#include "hw/irq.h"
> +#include "hw/peci/peci.h"
> +#include "hw/sysbus.h"
> +
> +typedef struct NPCM7xxPECIState {
> + SysBusDevice parent;
> +
> + MemoryRegion iomem;
> +
> + PECIBus *bus;
> + qemu_irq irq;
> +
> + PECICmd pcmd;
> +
> + /* Registers */
> + uint8_t status;
> + uint8_t ctl2;
> + uint8_t pddr;
> +} NPCM7xxPECIState;
> +
> +#define TYPE_NPCM7XX_PECI "npcm7xx-peci"
> +#define NPCM7XX_PECI(obj) \
> + OBJECT_CHECK(NPCM7xxPECIState, (obj), TYPE_NPCM7XX_PECI)
> +
> +#endif /* NPCM7XX_PECI_H */
> --
> 2.37.2.789.g6183377224-goog
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH 3/3] hw/peci: add support for EndPointConfig reads
2022-09-06 22:05 [RFC PATCH 0/3] Initial PECI bus support Titus Rwantare
2022-09-06 22:05 ` [RFC PATCH 1/3] hw/peci: add initial support for PECI Titus Rwantare
2022-09-06 22:05 ` [RFC PATCH 2/3] hw/peci: add PECI support for NPCM7xx BMCs Titus Rwantare
@ 2022-09-06 22:05 ` Titus Rwantare
2022-09-09 19:48 ` Peter Delevoryas
2022-09-09 19:54 ` [RFC PATCH 0/3] Initial PECI bus support Peter Delevoryas
3 siblings, 1 reply; 13+ messages in thread
From: Titus Rwantare @ 2022-09-06 22:05 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-arm, peter, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Titus Rwantare, Hao Wu
Signed-off-by: Titus Rwantare <titusr@google.com>
Reviewed-by: Hao Wu <wuhaotsh@google.com>
---
hw/peci/peci-client.c | 63 ++++++++++++++++++++++++++++++++++++++++++
hw/peci/peci-core.c | 44 +++++++++++++++++++++++++++--
include/hw/peci/peci.h | 23 +++++++++++++++
3 files changed, 128 insertions(+), 2 deletions(-)
diff --git a/hw/peci/peci-client.c b/hw/peci/peci-client.c
index 2aa797b5f6..8d93333248 100644
--- a/hw/peci/peci-client.c
+++ b/hw/peci/peci-client.c
@@ -23,6 +23,64 @@
#define PECI_CLIENT_DEFAULT_TEMP 30
+/* TODO: move this out into a config */
+static const PECIEndPtConfig spr_config[] = {
+ {
+ .hdr.msg_type = LOCAL_PCI_CFG,
+ .hdr.addr_type = 0x4,
+ .hdr.bus = 31,
+ .hdr.dev = 0,
+ .hdr.func = 2,
+ .hdr.reg = 0xD4,
+ .data = BIT(31)
+ },
+ {
+ .hdr.msg_type = LOCAL_PCI_CFG,
+ .hdr.addr_type = 0x4,
+ .hdr.bus = 31,
+ .hdr.dev = 0,
+ .hdr.func = 2,
+ .hdr.reg = 0xD0,
+ .data = BIT(31) | BIT(30)
+ },
+ {
+ .hdr.msg_type = LOCAL_PCI_CFG,
+ .hdr.addr_type = 0x4,
+ .hdr.bus = 31,
+ .hdr.dev = 30,
+ .hdr.func = 6,
+ .hdr.reg = 0x84,
+ .data = 0x03FFFFFF
+ },
+ {
+ .hdr.msg_type = LOCAL_PCI_CFG,
+ .hdr.addr_type = 0x4,
+ .hdr.bus = 31,
+ .hdr.dev = 30,
+ .hdr.func = 6,
+ .hdr.reg = 0x80,
+ .data = 0xFFFFFFFF
+ },
+ {
+ .hdr.msg_type = LOCAL_PCI_CFG,
+ .hdr.addr_type = 0x4,
+ .hdr.bus = 31,
+ .hdr.dev = 30,
+ .hdr.func = 6,
+ .hdr.reg = 0x84,
+ .data = 0x03FFFFFF
+ },
+ {
+ .hdr.msg_type = LOCAL_PCI_CFG,
+ .hdr.addr_type = 0x4,
+ .hdr.bus = 31,
+ .hdr.dev = 30,
+ .hdr.func = 6,
+ .hdr.reg = 0x80,
+ .data = 0xFFFFFFFF
+ },
+};
+
static void peci_client_update_temps(PECIClientDevice *client)
{
uint8_t temp_cpu = 0;
@@ -115,7 +173,12 @@ PECIClientDevice *peci_add_client(PECIBus *bus,
break;
case FAM6_ICELAKE_X:
+ client->revision = 0x40;
+ break;
+
case FAM6_SAPPHIRE_RAPIDS_X:
+ client->endpt_conf = spr_config;
+ client->num_entries = sizeof(spr_config) / sizeof(spr_config[0]);
client->revision = 0x40;
client->ucode = 0x8c0004a0;
break;
diff --git a/hw/peci/peci-core.c b/hw/peci/peci-core.c
index 8210bfa198..a961ae51f3 100644
--- a/hw/peci/peci-core.c
+++ b/hw/peci/peci-core.c
@@ -22,6 +22,47 @@
#define PECI_FCS_OK 0
#define PECI_FCS_ERR 1
+static PECIEndPtHeader peci_fmt_end_pt_header(PECICmd *pcmd)
+{
+ uint32_t val = pcmd->rx[7] | (pcmd->rx[8] << 8) | (pcmd->rx[9] << 16) |
+ (pcmd->rx[10] << 24);
+
+ PECIEndPtHeader header = {
+ .msg_type = pcmd->rx[1],
+ .addr_type = pcmd->rx[5],
+ .bus = (val >> 20) & 0xFF,
+ .dev = (val >> 15) & 0x1F,
+ .func = (val >> 12) & 0x7,
+ .reg = val & 0xFFF,
+ };
+
+ return header;
+}
+
+static void peci_rd_endpt_cfg(PECIClientDevice *client, PECICmd *pcmd)
+{
+ PECIPkgCfg *resp = (PECIPkgCfg *)pcmd->tx;
+ PECIEndPtHeader req = peci_fmt_end_pt_header(pcmd);
+ PECIEndPtConfig const *c;
+
+ if (client->endpt_conf) {
+ for (size_t i = 0; i < client->num_entries; i++) {
+ c = &client->endpt_conf[i];
+
+ if (!memcmp(&req, &c->hdr, sizeof(PECIEndPtHeader))) {
+ resp->data = c->data;
+ resp->cc = PECI_DEV_CC_SUCCESS;
+ return;
+ }
+ }
+ }
+
+ qemu_log_mask(LOG_UNIMP,
+ "%s: msg_type: 0x%x bus: %u, dev: %u, func: %u, reg: 0x%x\n",
+ __func__, req.msg_type, req.bus, req.dev, req.func, req.reg);
+
+}
+
static void peci_rd_pkg_cfg(PECIClientDevice *client, PECICmd *pcmd)
{
PECIPkgCfg *resp = (PECIPkgCfg *)pcmd->tx;
@@ -153,8 +194,7 @@ int peci_handle_cmd(PECIBus *bus, PECICmd *pcmd)
break;
case PECI_CMD_RD_END_PT_CFG:
- qemu_log_mask(LOG_UNIMP, "%s: unimplemented CMD_RD_END_PT_CFG\n",
- __func__);
+ peci_rd_endpt_cfg(client, pcmd);
break;
default:
diff --git a/include/hw/peci/peci.h b/include/hw/peci/peci.h
index 1a0abe65cd..4fb2fc236e 100644
--- a/include/hw/peci/peci.h
+++ b/include/hw/peci/peci.h
@@ -112,6 +112,26 @@ typedef struct PECITempTarget {
uint8_t tjmax;
} PECITempTarget;
+typedef enum PECIEndPtType {
+ LOCAL_PCI_CFG = 3,
+ PCI_CFG,
+ MMIO_BDF,
+} PECIEndPtType;
+
+typedef struct __attribute__ ((__packed__)) {
+ PECIEndPtType msg_type;
+ uint8_t addr_type;
+ uint8_t bus;
+ uint8_t dev;
+ uint8_t func;
+ uint16_t reg;
+} PECIEndPtHeader;
+
+typedef struct {
+ PECIEndPtHeader hdr;
+ uint32_t data;
+} PECIEndPtConfig;
+
#define PECI_BASE_ADDR 0x30
#define PECI_BUFFER_SIZE 0x100
#define PECI_NUM_CPUS_MAX 56
@@ -140,6 +160,9 @@ typedef struct PECIClientDevice {
uint8_t dimm_temp_max;
uint8_t dimm_temp[PECI_NUM_DIMMS_MAX];
+ /* EndPtConfig info */
+ PECIEndPtConfig const *endpt_conf;
+ size_t num_entries;
} PECIClientDevice;
#define TYPE_PECI_CLIENT "peci-client"
--
2.37.2.789.g6183377224-goog
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 3/3] hw/peci: add support for EndPointConfig reads
2022-09-06 22:05 ` [RFC PATCH 3/3] hw/peci: add support for EndPointConfig reads Titus Rwantare
@ 2022-09-09 19:48 ` Peter Delevoryas
2022-09-13 18:21 ` Titus Rwantare
0 siblings, 1 reply; 13+ messages in thread
From: Peter Delevoryas @ 2022-09-09 19:48 UTC (permalink / raw)
To: Titus Rwantare
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Hao Wu
On Tue, Sep 06, 2022 at 10:05:52PM +0000, Titus Rwantare wrote:
> Signed-off-by: Titus Rwantare <titusr@google.com>
> Reviewed-by: Hao Wu <wuhaotsh@google.com>
> ---
> hw/peci/peci-client.c | 63 ++++++++++++++++++++++++++++++++++++++++++
> hw/peci/peci-core.c | 44 +++++++++++++++++++++++++++--
> include/hw/peci/peci.h | 23 +++++++++++++++
> 3 files changed, 128 insertions(+), 2 deletions(-)
>
> diff --git a/hw/peci/peci-client.c b/hw/peci/peci-client.c
> index 2aa797b5f6..8d93333248 100644
> --- a/hw/peci/peci-client.c
> +++ b/hw/peci/peci-client.c
> @@ -23,6 +23,64 @@
>
> #define PECI_CLIENT_DEFAULT_TEMP 30
>
> +/* TODO: move this out into a config */
> +static const PECIEndPtConfig spr_config[] = {
> + {
> + .hdr.msg_type = LOCAL_PCI_CFG,
> + .hdr.addr_type = 0x4,
> + .hdr.bus = 31,
> + .hdr.dev = 0,
> + .hdr.func = 2,
> + .hdr.reg = 0xD4,
> + .data = BIT(31)
> + },
> + {
> + .hdr.msg_type = LOCAL_PCI_CFG,
> + .hdr.addr_type = 0x4,
> + .hdr.bus = 31,
> + .hdr.dev = 0,
> + .hdr.func = 2,
> + .hdr.reg = 0xD0,
> + .data = BIT(31) | BIT(30)
> + },
> + {
> + .hdr.msg_type = LOCAL_PCI_CFG,
> + .hdr.addr_type = 0x4,
> + .hdr.bus = 31,
> + .hdr.dev = 30,
> + .hdr.func = 6,
> + .hdr.reg = 0x84,
> + .data = 0x03FFFFFF
> + },
> + {
> + .hdr.msg_type = LOCAL_PCI_CFG,
> + .hdr.addr_type = 0x4,
> + .hdr.bus = 31,
> + .hdr.dev = 30,
> + .hdr.func = 6,
> + .hdr.reg = 0x80,
> + .data = 0xFFFFFFFF
> + },
> + {
> + .hdr.msg_type = LOCAL_PCI_CFG,
> + .hdr.addr_type = 0x4,
> + .hdr.bus = 31,
> + .hdr.dev = 30,
> + .hdr.func = 6,
> + .hdr.reg = 0x84,
> + .data = 0x03FFFFFF
> + },
> + {
> + .hdr.msg_type = LOCAL_PCI_CFG,
> + .hdr.addr_type = 0x4,
> + .hdr.bus = 31,
> + .hdr.dev = 30,
> + .hdr.func = 6,
> + .hdr.reg = 0x80,
> + .data = 0xFFFFFFFF
> + },
> +};
> +
> static void peci_client_update_temps(PECIClientDevice *client)
> {
> uint8_t temp_cpu = 0;
> @@ -115,7 +173,12 @@ PECIClientDevice *peci_add_client(PECIBus *bus,
> break;
>
> case FAM6_ICELAKE_X:
> + client->revision = 0x40;
> + break;
> +
> case FAM6_SAPPHIRE_RAPIDS_X:
> + client->endpt_conf = spr_config;
> + client->num_entries = sizeof(spr_config) / sizeof(spr_config[0]);
> client->revision = 0x40;
> client->ucode = 0x8c0004a0;
> break;
> diff --git a/hw/peci/peci-core.c b/hw/peci/peci-core.c
> index 8210bfa198..a961ae51f3 100644
> --- a/hw/peci/peci-core.c
> +++ b/hw/peci/peci-core.c
> @@ -22,6 +22,47 @@
> #define PECI_FCS_OK 0
> #define PECI_FCS_ERR 1
>
> +static PECIEndPtHeader peci_fmt_end_pt_header(PECICmd *pcmd)
> +{
> + uint32_t val = pcmd->rx[7] | (pcmd->rx[8] << 8) | (pcmd->rx[9] << 16) |
> + (pcmd->rx[10] << 24);
> +
> + PECIEndPtHeader header = {
> + .msg_type = pcmd->rx[1],
> + .addr_type = pcmd->rx[5],
> + .bus = (val >> 20) & 0xFF,
> + .dev = (val >> 15) & 0x1F,
> + .func = (val >> 12) & 0x7,
> + .reg = val & 0xFFF,
> + };
> +
> + return header;
> +}
> +
> +static void peci_rd_endpt_cfg(PECIClientDevice *client, PECICmd *pcmd)
> +{
> + PECIPkgCfg *resp = (PECIPkgCfg *)pcmd->tx;
> + PECIEndPtHeader req = peci_fmt_end_pt_header(pcmd);
> + PECIEndPtConfig const *c;
> +
> + if (client->endpt_conf) {
> + for (size_t i = 0; i < client->num_entries; i++) {
> + c = &client->endpt_conf[i];
> +
> + if (!memcmp(&req, &c->hdr, sizeof(PECIEndPtHeader))) {
> + resp->data = c->data;
> + resp->cc = PECI_DEV_CC_SUCCESS;
> + return;
> + }
> + }
> + }
> +
> + qemu_log_mask(LOG_UNIMP,
> + "%s: msg_type: 0x%x bus: %u, dev: %u, func: %u, reg: 0x%x\n",
> + __func__, req.msg_type, req.bus, req.dev, req.func, req.reg);
> +
> +}
> +
> static void peci_rd_pkg_cfg(PECIClientDevice *client, PECICmd *pcmd)
> {
> PECIPkgCfg *resp = (PECIPkgCfg *)pcmd->tx;
> @@ -153,8 +194,7 @@ int peci_handle_cmd(PECIBus *bus, PECICmd *pcmd)
> break;
>
> case PECI_CMD_RD_END_PT_CFG:
> - qemu_log_mask(LOG_UNIMP, "%s: unimplemented CMD_RD_END_PT_CFG\n",
> - __func__);
> + peci_rd_endpt_cfg(client, pcmd);
> break;
>
> default:
> diff --git a/include/hw/peci/peci.h b/include/hw/peci/peci.h
> index 1a0abe65cd..4fb2fc236e 100644
> --- a/include/hw/peci/peci.h
> +++ b/include/hw/peci/peci.h
> @@ -112,6 +112,26 @@ typedef struct PECITempTarget {
> uint8_t tjmax;
> } PECITempTarget;
>
> +typedef enum PECIEndPtType {
> + LOCAL_PCI_CFG = 3,
> + PCI_CFG,
> + MMIO_BDF,
> +} PECIEndPtType;
> +
> +typedef struct __attribute__ ((__packed__)) {
> + PECIEndPtType msg_type;
> + uint8_t addr_type;
> + uint8_t bus;
> + uint8_t dev;
> + uint8_t func;
> + uint16_t reg;
> +} PECIEndPtHeader;
> +
> +typedef struct {
> + PECIEndPtHeader hdr;
> + uint32_t data;
> +} PECIEndPtConfig;
I noticed the summary is "hw/peci: add support for EndPointConfig reads"
but type definitions here use "EndPt", maybe they should be
"PECIEndPoint*"? I don't think extending to Point is too long.
> +
> #define PECI_BASE_ADDR 0x30
> #define PECI_BUFFER_SIZE 0x100
> #define PECI_NUM_CPUS_MAX 56
> @@ -140,6 +160,9 @@ typedef struct PECIClientDevice {
> uint8_t dimm_temp_max;
> uint8_t dimm_temp[PECI_NUM_DIMMS_MAX];
>
> + /* EndPtConfig info */
> + PECIEndPtConfig const *endpt_conf;
> + size_t num_entries;
> } PECIClientDevice;
>
> #define TYPE_PECI_CLIENT "peci-client"
> --
> 2.37.2.789.g6183377224-goog
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 3/3] hw/peci: add support for EndPointConfig reads
2022-09-09 19:48 ` Peter Delevoryas
@ 2022-09-13 18:21 ` Titus Rwantare
0 siblings, 0 replies; 13+ messages in thread
From: Titus Rwantare @ 2022-09-13 18:21 UTC (permalink / raw)
To: Peter Delevoryas
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo, Hao Wu
On Fri, 9 Sept 2022 at 12:48, Peter Delevoryas <peter@pjd.dev> wrote:
>
> On Tue, Sep 06, 2022 at 10:05:52PM +0000, Titus Rwantare wrote:
> > Signed-off-by: Titus Rwantare <titusr@google.com>
> > Reviewed-by: Hao Wu <wuhaotsh@google.com>
> > ---
...
> > +++ b/include/hw/peci/peci.h
> > @@ -112,6 +112,26 @@ typedef struct PECITempTarget {
> > uint8_t tjmax;
> > } PECITempTarget;
> >
> > +typedef enum PECIEndPtType {
> > + LOCAL_PCI_CFG = 3,
> > + PCI_CFG,
> > + MMIO_BDF,
> > +} PECIEndPtType;
> > +
> > +typedef struct __attribute__ ((__packed__)) {
> > + PECIEndPtType msg_type;
> > + uint8_t addr_type;
> > + uint8_t bus;
> > + uint8_t dev;
> > + uint8_t func;
> > + uint16_t reg;
> > +} PECIEndPtHeader;
> > +
> > +typedef struct {
> > + PECIEndPtHeader hdr;
> > + uint32_t data;
> > +} PECIEndPtConfig;
>
> I noticed the summary is "hw/peci: add support for EndPointConfig reads"
> but type definitions here use "EndPt", maybe they should be
> "PECIEndPoint*"? I don't think extending to Point is too long.
Fair, fixed in v2.
Titus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 0/3] Initial PECI bus support
2022-09-06 22:05 [RFC PATCH 0/3] Initial PECI bus support Titus Rwantare
` (2 preceding siblings ...)
2022-09-06 22:05 ` [RFC PATCH 3/3] hw/peci: add support for EndPointConfig reads Titus Rwantare
@ 2022-09-09 19:54 ` Peter Delevoryas
2022-09-13 18:20 ` Titus Rwantare
3 siblings, 1 reply; 13+ messages in thread
From: Peter Delevoryas @ 2022-09-09 19:54 UTC (permalink / raw)
To: Titus Rwantare
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo
On Tue, Sep 06, 2022 at 10:05:49PM +0000, Titus Rwantare wrote:
> The Platform Environment Control Interface (PECI), is a way for Intel
> processors to communicate with management controllers.
>
> This series of patches simulate some PECI subsystem functionality. This
> work is currently used against Nuvoton 7xx BMC, but it can easily be
> extended to support Aspeed BMCs. Most of the functionality is derived
> from PECI support in openbmc. See https://github.com/openbmc/libpeci
>
> The main consumer of this work is openbmc, so functionality not
> exercised by the openbmc/libpeci is unlikely to be present here.
>
> peci-core.c is an attempt to split out functionality defined by the
> spec. Anything that is not expected to change between BMC vendors.
>
> The following commands have some support:
> Ping()
> GetDIB()
> GetTemp()
> ~RdPkgConfig()
> ~RdEndPtConfig()
>
> To be implemented:
> RdIAMSR()
> RdPCIConfig()
> RdPCIConfigLocal()
>
> Currently, in the board file during bmc_init() one may specify defaults
> as follows:
>
> static void my_machine_peci_init(NPCM7xxState *soc)
> {
> PECIBus *peci_bus = npcm7xx_peci_get_bus(soc);
> DeviceState *dev;
>
> /* per socket properties - both sockets are identical in this case */
> PECIClientProperties peci_props = {
> .cpu_family = FAM6_SAPPHIRE_RAPIDS_X,
> .cpus = 56,
> .dimms = 16
> };
>
> /* socket 0 - with example setting a few of the cpu and dimm temperatures in millidegrees */
> dev = DEVICE(peci_add_client(peci_bus, 0x30, &peci_props));
> object_property_set_uint(OBJECT(dev), "cpu_temp[0]", 30000, &error_abort);
> object_property_set_uint(OBJECT(dev), "cpu_temp[2]", 35000, &error_abort);
> object_property_set_uint(OBJECT(dev), "dimm_temp[1]", 40000, &error_abort);
> object_property_set_uint(OBJECT(dev), "dimm_temp[8]", 36000, &error_abort);
>
> /* socket 1 */
> dev = DEVICE(peci_add_client(peci_bus, 0x31, &peci_props));
> object_property_set_uint(OBJECT(dev), "cpu_temp[9]", 50000, &error_abort);
> object_property_set_uint(OBJECT(dev), "dimm_temp[0]", 31000, &error_abort);
> object_property_set_uint(OBJECT(dev), "dimm_temp[14]", 36000, &error_abort);
> ...
> }
>
> This is something that can also be extended as other parameters arise that need
> to differ between platforms. So far you can have have different CPUs, DIMM counts,
> DIMM temperatures here. These fields can also be adjusted at runtime through qmp.
That looks good to me, seems like the standard way to do it in QEMU.
>
> A lot of the registers are hard coded, see hw/peci/peci-client.c. I'd like to
> gauge interest in what potential users would like to be adjustable at runtime.
> I've not written QEMU models that read config files at runtime, something I'd
> appreciate guidance on.
This part I don't totally understand. I also barely know anything about
PECI.
Is the register location for things different between CPU generations?
If so (and I expect it probably is), why is there only a configuration
for Sapphire Rapids, and not for the other ones?
Is that because of PECI protocol changes between generations?
In which case, maybe there needs to be a notion of PECI version
somewhere?
Also, I don't understand why it would be adjustable at runtime, do we
change register locations during execution?
I would expect it to be part of the board definition.
You could provide a bunch of sample configs for the CPU's that you're
testing for, and the board configuration could just select the sample
config it is using (corresponding to the CPU model).
That's the model I would imagine, but I might be missing some important
context here.
Thanks,
Peter
>
> Thanks all
>
> Titus Rwantare (3):
> hw/peci: add initial support for PECI
> hw/peci: add PECI support for NPCM7xx BMCs
> hw/peci: add support for EndPointConfig reads
>
> MAINTAINERS | 10 +-
> hw/Kconfig | 1 +
> hw/arm/Kconfig | 1 +
> hw/arm/npcm7xx.c | 9 +
> hw/meson.build | 1 +
> hw/peci/Kconfig | 2 +
> hw/peci/meson.build | 2 +
> hw/peci/npcm7xx_peci.c | 204 +++++++++++++++++++++++
> hw/peci/peci-client.c | 293 +++++++++++++++++++++++++++++++++
> hw/peci/peci-core.c | 222 +++++++++++++++++++++++++
> hw/peci/trace-events | 10 ++
> hw/peci/trace.h | 1 +
> include/hw/arm/npcm7xx.h | 2 +
> include/hw/peci/npcm7xx_peci.h | 37 +++++
> include/hw/peci/peci.h | 217 ++++++++++++++++++++++++
> meson.build | 1 +
> 16 files changed, 1012 insertions(+), 1 deletion(-)
> create mode 100644 hw/peci/Kconfig
> create mode 100644 hw/peci/meson.build
> create mode 100644 hw/peci/npcm7xx_peci.c
> create mode 100644 hw/peci/peci-client.c
> create mode 100644 hw/peci/peci-core.c
> create mode 100644 hw/peci/trace-events
> create mode 100644 hw/peci/trace.h
> create mode 100644 include/hw/peci/npcm7xx_peci.h
> create mode 100644 include/hw/peci/peci.h
>
> --
> 2.37.2.789.g6183377224-goog
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 0/3] Initial PECI bus support
2022-09-09 19:54 ` [RFC PATCH 0/3] Initial PECI bus support Peter Delevoryas
@ 2022-09-13 18:20 ` Titus Rwantare
2022-09-13 18:27 ` Peter Delevoryas
0 siblings, 1 reply; 13+ messages in thread
From: Titus Rwantare @ 2022-09-13 18:20 UTC (permalink / raw)
To: Peter Delevoryas
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo
On Fri, 9 Sept 2022 at 12:54, Peter Delevoryas <peter@pjd.dev> wrote:
>
> On Tue, Sep 06, 2022 at 10:05:49PM +0000, Titus Rwantare wrote:
...
> >
> > This is something that can also be extended as other parameters arise that need
> > to differ between platforms. So far you can have have different CPUs, DIMM counts,
> > DIMM temperatures here. These fields can also be adjusted at runtime through qmp.
>
> That looks good to me, seems like the standard way to do it in QEMU.
>
> >
> > A lot of the registers are hard coded, see hw/peci/peci-client.c. I'd like to
> > gauge interest in what potential users would like to be adjustable at runtime.
> > I've not written QEMU models that read config files at runtime, something I'd
> > appreciate guidance on.
>
> This part I don't totally understand. I also barely know anything about
> PECI.
>
> Is the register location for things different between CPU generations?
Some things seem to move between generations and others don't move, someone at
Intel would know better than I do.
> If so (and I expect it probably is), why is there only a configuration
> for Sapphire Rapids, and not for the other ones?
>
> Is that because of PECI protocol changes between generations?
I haven't dug into the other machines because of internal demand, but
I've found that
with newer generations, more features get used in addition to existing
ones. It's
possible these features existed on older machines.
> In which case, maybe there needs to be a notion of PECI version
> somewhere?
>
> Also, I don't understand why it would be adjustable at runtime, do we
> change register locations during execution?
>
> I would expect it to be part of the board definition.
>
> You could provide a bunch of sample configs for the CPU's that you're
> testing for, and the board configuration could just select the sample
> config it is using (corresponding to the CPU model).
>
> That's the model I would imagine, but I might be missing some important
> context here.
I think it would be nice to have additional registers at runtime, at
the time of writing,
I don't know how much of the internal workings of Sapphire Rapids
Intel is willing to
share publicly. If users are free to separately define registers, I
don't then get to
worry about this. e.g. I'd like to simulate errors from the memory controllers.
Titus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH 0/3] Initial PECI bus support
2022-09-13 18:20 ` Titus Rwantare
@ 2022-09-13 18:27 ` Peter Delevoryas
0 siblings, 0 replies; 13+ messages in thread
From: Peter Delevoryas @ 2022-09-13 18:27 UTC (permalink / raw)
To: Titus Rwantare
Cc: qemu-devel, qemu-arm, patrick, iwona.winiarska, tmaimon77,
quic_jaehyoo
On Tue, Sep 13, 2022 at 11:20:57AM -0700, Titus Rwantare wrote:
> On Fri, 9 Sept 2022 at 12:54, Peter Delevoryas <peter@pjd.dev> wrote:
> >
> > On Tue, Sep 06, 2022 at 10:05:49PM +0000, Titus Rwantare wrote:
> ...
> > >
> > > This is something that can also be extended as other parameters arise that need
> > > to differ between platforms. So far you can have have different CPUs, DIMM counts,
> > > DIMM temperatures here. These fields can also be adjusted at runtime through qmp.
> >
> > That looks good to me, seems like the standard way to do it in QEMU.
> >
> > >
> > > A lot of the registers are hard coded, see hw/peci/peci-client.c. I'd like to
> > > gauge interest in what potential users would like to be adjustable at runtime.
> > > I've not written QEMU models that read config files at runtime, something I'd
> > > appreciate guidance on.
> >
> > This part I don't totally understand. I also barely know anything about
> > PECI.
> >
> > Is the register location for things different between CPU generations?
>
> Some things seem to move between generations and others don't move, someone at
> Intel would know better than I do.
>
>
>
> > If so (and I expect it probably is), why is there only a configuration
> > for Sapphire Rapids, and not for the other ones?
> >
> > Is that because of PECI protocol changes between generations?
>
> I haven't dug into the other machines because of internal demand, but
> I've found that
> with newer generations, more features get used in addition to existing
> ones. It's
> possible these features existed on older machines.
>
>
>
> > In which case, maybe there needs to be a notion of PECI version
> > somewhere?
> >
> > Also, I don't understand why it would be adjustable at runtime, do we
> > change register locations during execution?
> >
> > I would expect it to be part of the board definition.
> >
> > You could provide a bunch of sample configs for the CPU's that you're
> > testing for, and the board configuration could just select the sample
> > config it is using (corresponding to the CPU model).
> >
> > That's the model I would imagine, but I might be missing some important
> > context here.
>
> I think it would be nice to have additional registers at runtime, at
> the time of writing,
> I don't know how much of the internal workings of Sapphire Rapids
> Intel is willing to
> share publicly. If users are free to separately define registers, I
> don't then get to
> worry about this. e.g. I'd like to simulate errors from the memory controllers.
Oh ok, yeah I guess making it more dynamic shouldn't really hurt
anything. That sounds ok then. Also yeah, perhaps keeping the register
definitions separate for privacy concerns is necessary.
Reviewed-by: Peter Delevoryas <peter@pjd.dev>
>
>
> Titus
^ permalink raw reply [flat|nested] 13+ messages in thread