mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-18 23:52:14 -06:00
hw/cxl: Add a switch mailbox CCI function
CXL switch CCIs were added in CXL r3.0. They are a PCI function, identified by class code that provides a CXL mailbox (identical to that previously defined for CXL type 3 memory devices) over which various FM-API commands may be used. Whilst the intent of this feature is enable switch control from a BMC attached to a switch upstream port, it is also useful to allow emulation of this feature on the upstream port connected to a host using the CXL devices as this greatly simplifies testing. Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Message-Id: <20231023160806.13206-7-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
2710d49a7c
commit
4a58330343
7 changed files with 175 additions and 1 deletions
|
@ -67,6 +67,9 @@ static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size)
|
||||||
|
|
||||||
if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) {
|
if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) {
|
||||||
cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate;
|
cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate;
|
||||||
|
} else if (object_dynamic_cast(OBJECT(cci->intf),
|
||||||
|
TYPE_CXL_SWITCH_MAILBOX_CCI)) {
|
||||||
|
cxl_dstate = &CXL_SWITCH_MAILBOX_CCI(cci->intf)->cxl_dstate;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +138,9 @@ static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value,
|
||||||
|
|
||||||
if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) {
|
if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) {
|
||||||
cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate;
|
cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate;
|
||||||
|
} else if (object_dynamic_cast(OBJECT(cci->intf),
|
||||||
|
TYPE_CXL_SWITCH_MAILBOX_CCI)) {
|
||||||
|
cxl_dstate = &CXL_SWITCH_MAILBOX_CCI(cci->intf)->cxl_dstate;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -365,6 +371,27 @@ void cxl_device_register_init_t3(CXLType3Dev *ct3d)
|
||||||
CXL_MAILBOX_MAX_PAYLOAD_SIZE);
|
CXL_MAILBOX_MAX_PAYLOAD_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cxl_device_register_init_swcci(CSWMBCCIDev *sw)
|
||||||
|
{
|
||||||
|
CXLDeviceState *cxl_dstate = &sw->cxl_dstate;
|
||||||
|
uint64_t *cap_h = cxl_dstate->caps_reg_state64;
|
||||||
|
const int cap_count = 3;
|
||||||
|
|
||||||
|
/* CXL Device Capabilities Array Register */
|
||||||
|
ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_ID, 0);
|
||||||
|
ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1);
|
||||||
|
ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count);
|
||||||
|
|
||||||
|
cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1, 2);
|
||||||
|
device_reg_init_common(cxl_dstate);
|
||||||
|
|
||||||
|
cxl_device_cap_init(cxl_dstate, MAILBOX, 2, 1);
|
||||||
|
mailbox_reg_init_common(cxl_dstate);
|
||||||
|
|
||||||
|
cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000, 1);
|
||||||
|
memdev_reg_init_common(cxl_dstate);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t cxl_device_get_timestamp(CXLDeviceState *cxl_dstate)
|
uint64_t cxl_device_get_timestamp(CXLDeviceState *cxl_dstate)
|
||||||
{
|
{
|
||||||
uint64_t time, delta;
|
uint64_t time, delta;
|
||||||
|
|
|
@ -754,6 +754,15 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = {
|
||||||
cmd_media_clear_poison, 72, 0 },
|
cmd_media_clear_poison, 72, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
|
||||||
|
[TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 },
|
||||||
|
[TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 0,
|
||||||
|
IMMEDIATE_POLICY_CHANGE },
|
||||||
|
[LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0,
|
||||||
|
0 },
|
||||||
|
[LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
|
int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
|
||||||
size_t len_in, uint8_t *pl_in, size_t *len_out,
|
size_t len_in, uint8_t *pl_in, size_t *len_out,
|
||||||
uint8_t *pl_out, bool *bg_started)
|
uint8_t *pl_out, bool *bg_started)
|
||||||
|
@ -795,6 +804,15 @@ void cxl_init_cci(CXLCCI *cci, size_t payload_max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cxl_initialize_mailbox_swcci(CXLCCI *cci, DeviceState *intf,
|
||||||
|
DeviceState *d, size_t payload_max)
|
||||||
|
{
|
||||||
|
cci->cxl_cmd_set = cxl_cmd_set_sw;
|
||||||
|
cci->d = d;
|
||||||
|
cci->intf = intf;
|
||||||
|
cxl_init_cci(cci, payload_max);
|
||||||
|
}
|
||||||
|
|
||||||
void cxl_initialize_mailbox_t3(CXLCCI *cci, DeviceState *d, size_t payload_max)
|
void cxl_initialize_mailbox_t3(CXLCCI *cci, DeviceState *d, size_t payload_max)
|
||||||
{
|
{
|
||||||
cci->cxl_cmd_set = cxl_cmd_set;
|
cci->cxl_cmd_set = cxl_cmd_set;
|
||||||
|
|
|
@ -6,6 +6,7 @@ system_ss.add(when: 'CONFIG_CXL',
|
||||||
'cxl-host.c',
|
'cxl-host.c',
|
||||||
'cxl-cdat.c',
|
'cxl-cdat.c',
|
||||||
'cxl-events.c',
|
'cxl-events.c',
|
||||||
|
'switch-mailbox-cci.c',
|
||||||
),
|
),
|
||||||
if_false: files(
|
if_false: files(
|
||||||
'cxl-host-stubs.c',
|
'cxl-host-stubs.c',
|
||||||
|
|
111
hw/cxl/switch-mailbox-cci.c
Normal file
111
hw/cxl/switch-mailbox-cci.c
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*
|
||||||
|
* Emulation of a CXL Switch Mailbox CCI PCIe function.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Huawei Technologies.
|
||||||
|
*
|
||||||
|
* From www.computeexpresslink.org
|
||||||
|
* Compute Express Link (CXL) Specification revision 3.0 Version 1.0
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/pci/pci.h"
|
||||||
|
#include "hw/pci-bridge/cxl_upstream_port.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu/log.h"
|
||||||
|
#include "qemu/module.h"
|
||||||
|
#include "hw/qdev-properties.h"
|
||||||
|
#include "hw/cxl/cxl.h"
|
||||||
|
|
||||||
|
static void cswmbcci_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
CSWMBCCIDev *cswmb = CXL_SWITCH_MAILBOX_CCI(dev);
|
||||||
|
cxl_device_register_init_swcci(cswmb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cswbcci_realize(PCIDevice *pci_dev, Error **errp)
|
||||||
|
{
|
||||||
|
CSWMBCCIDev *cswmb = CXL_SWITCH_MAILBOX_CCI(pci_dev);
|
||||||
|
CXLComponentState *cxl_cstate = &cswmb->cxl_cstate;
|
||||||
|
CXLDeviceState *cxl_dstate = &cswmb->cxl_dstate;
|
||||||
|
CXLDVSECRegisterLocator *regloc_dvsec;
|
||||||
|
CXLUpstreamPort *usp;
|
||||||
|
|
||||||
|
if (!cswmb->target) {
|
||||||
|
error_setg(errp, "Target not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usp = CXL_USP(cswmb->target);
|
||||||
|
|
||||||
|
pcie_endpoint_cap_init(pci_dev, 0x80);
|
||||||
|
cxl_cstate->dvsec_offset = 0x100;
|
||||||
|
cxl_cstate->pdev = pci_dev;
|
||||||
|
cswmb->cci = &usp->swcci;
|
||||||
|
cxl_device_register_block_init(OBJECT(pci_dev), cxl_dstate, cswmb->cci);
|
||||||
|
pci_register_bar(pci_dev, 0,
|
||||||
|
PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||||
|
PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||||
|
&cxl_dstate->device_registers);
|
||||||
|
regloc_dvsec = &(CXLDVSECRegisterLocator) {
|
||||||
|
.rsvd = 0,
|
||||||
|
.reg0_base_lo = RBI_CXL_DEVICE_REG | 0,
|
||||||
|
.reg0_base_hi = 0,
|
||||||
|
};
|
||||||
|
cxl_component_create_dvsec(cxl_cstate, CXL3_SWITCH_MAILBOX_CCI,
|
||||||
|
REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,
|
||||||
|
REG_LOC_DVSEC_REVID, (uint8_t *)regloc_dvsec);
|
||||||
|
|
||||||
|
cxl_initialize_mailbox_swcci(cswmb->cci, DEVICE(pci_dev),
|
||||||
|
DEVICE(cswmb->target),
|
||||||
|
CXL_MAILBOX_MAX_PAYLOAD_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cswmbcci_exit(PCIDevice *pci_dev)
|
||||||
|
{
|
||||||
|
/* Nothing to do here yet */
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property cxl_switch_cci_props[] = {
|
||||||
|
DEFINE_PROP_LINK("target", CSWMBCCIDev,
|
||||||
|
target, TYPE_CXL_USP, PCIDevice *),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cswmbcci_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
|
||||||
|
|
||||||
|
pc->realize = cswbcci_realize;
|
||||||
|
pc->exit = cswmbcci_exit;
|
||||||
|
/* Serial bus, CXL Switch CCI */
|
||||||
|
pc->class_id = 0x0c0b;
|
||||||
|
/*
|
||||||
|
* Huawei Technologies
|
||||||
|
* CXL Switch Mailbox CCI - DID assigned for emulation only.
|
||||||
|
* No real hardware will ever use this ID.
|
||||||
|
*/
|
||||||
|
pc->vendor_id = 0x19e5;
|
||||||
|
pc->device_id = 0xa123;
|
||||||
|
pc->revision = 0;
|
||||||
|
dc->desc = "CXL Switch Mailbox CCI";
|
||||||
|
dc->reset = cswmbcci_reset;
|
||||||
|
device_class_set_props(dc, cxl_switch_cci_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo cswmbcci_info = {
|
||||||
|
.name = TYPE_CXL_SWITCH_MAILBOX_CCI,
|
||||||
|
.parent = TYPE_PCI_DEVICE,
|
||||||
|
.class_init = cswmbcci_class_init,
|
||||||
|
.instance_size = sizeof(CSWMBCCIDev),
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ INTERFACE_PCIE_DEVICE },
|
||||||
|
{ }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cxl_switch_mailbox_cci_register(void)
|
||||||
|
{
|
||||||
|
type_register_static(&cswmbcci_info);
|
||||||
|
}
|
||||||
|
type_init(cxl_switch_mailbox_cci_register);
|
|
@ -26,7 +26,8 @@ enum reg_type {
|
||||||
CXL2_LOGICAL_DEVICE,
|
CXL2_LOGICAL_DEVICE,
|
||||||
CXL2_ROOT_PORT,
|
CXL2_ROOT_PORT,
|
||||||
CXL2_UPSTREAM_PORT,
|
CXL2_UPSTREAM_PORT,
|
||||||
CXL2_DOWNSTREAM_PORT
|
CXL2_DOWNSTREAM_PORT,
|
||||||
|
CXL3_SWITCH_MAILBOX_CCI,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -211,8 +211,10 @@ void cxl_device_register_block_init(Object *obj, CXLDeviceState *dev,
|
||||||
CXLCCI *cci);
|
CXLCCI *cci);
|
||||||
|
|
||||||
typedef struct CXLType3Dev CXLType3Dev;
|
typedef struct CXLType3Dev CXLType3Dev;
|
||||||
|
typedef struct CSWMBCCIDev CSWMBCCIDev;
|
||||||
/* Set up default values for the register block */
|
/* Set up default values for the register block */
|
||||||
void cxl_device_register_init_t3(CXLType3Dev *ct3d);
|
void cxl_device_register_init_t3(CXLType3Dev *ct3d);
|
||||||
|
void cxl_device_register_init_swcci(CSWMBCCIDev *sw);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CXL 2.0 - 8.2.8.1 including errata F4
|
* CXL 2.0 - 8.2.8.1 including errata F4
|
||||||
|
@ -259,6 +261,8 @@ CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MEMORY_DEVICE,
|
||||||
CXL_DEVICE_CAP_REG_SIZE * 2)
|
CXL_DEVICE_CAP_REG_SIZE * 2)
|
||||||
|
|
||||||
void cxl_initialize_mailbox_t3(CXLCCI *cci, DeviceState *d, size_t payload_max);
|
void cxl_initialize_mailbox_t3(CXLCCI *cci, DeviceState *d, size_t payload_max);
|
||||||
|
void cxl_initialize_mailbox_swcci(CXLCCI *cci, DeviceState *intf,
|
||||||
|
DeviceState *d, size_t payload_max);
|
||||||
void cxl_init_cci(CXLCCI *cci, size_t payload_max);
|
void cxl_init_cci(CXLCCI *cci, size_t payload_max);
|
||||||
int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
|
int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
|
||||||
size_t len_in, uint8_t *pl_in,
|
size_t len_in, uint8_t *pl_in,
|
||||||
|
@ -397,6 +401,17 @@ struct CXLType3Class {
|
||||||
uint8_t *data);
|
uint8_t *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CSWMBCCIDev {
|
||||||
|
PCIDevice parent_obj;
|
||||||
|
PCIDevice *target;
|
||||||
|
CXLComponentState cxl_cstate;
|
||||||
|
CXLDeviceState cxl_dstate;
|
||||||
|
CXLCCI *cci;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TYPE_CXL_SWITCH_MAILBOX_CCI "cxl-switch-mailbox-cci"
|
||||||
|
OBJECT_DECLARE_TYPE(CSWMBCCIDev, CSWMBCCIClass, CXL_SWITCH_MAILBOX_CCI)
|
||||||
|
|
||||||
MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
|
MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
|
||||||
unsigned size, MemTxAttrs attrs);
|
unsigned size, MemTxAttrs attrs);
|
||||||
MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
|
MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
|
||||||
|
|
|
@ -11,6 +11,7 @@ typedef struct CXLUpstreamPort {
|
||||||
|
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
CXLComponentState cxl_cstate;
|
CXLComponentState cxl_cstate;
|
||||||
|
CXLCCI swcci;
|
||||||
DOECap doe_cdat;
|
DOECap doe_cdat;
|
||||||
uint64_t sn;
|
uint64_t sn;
|
||||||
} CXLUpstreamPort;
|
} CXLUpstreamPort;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue