* [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support.
@ 2026-02-04 17:32 ` Jonathan Cameron
2026-02-04 17:32 ` [PATCH qemu v5 1/3] hw/cxl: Physical Port Info FMAPI - update to current spec and add defines Jonathan Cameron
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Jonathan Cameron @ 2026-02-04 17:32 UTC (permalink / raw)
To: Michael Tsirkin, qemu-devel, Arpit Kumar
Cc: linuxarm, linux-cxl, Ravi Shankar, Marcel Apfelbaum, Michael Roth
Changes since v4:
https://lore.kernel.org/qemu-devel/20250916080736.1266083-1-arpit1.kumar@samsung.com/
- Dropped initial refactor. Reason being that it is not static enough
for caching at boot to be appropriate. Kept the spec update part
of this.
- Added a patch to make sure the new flip mode stuff is reported in
the Get Physical Port State command.
- Rebased Arpit's Physical Control Control FMAPI Command given drop
of the major refactor from v4 patch 1.
I had taken this into my cxl staging tree thinking it only needed a few
minor tweaks. Then whilst testing I realized it didn't work with hotplug
and that made me consider if Arpit's original approach made sense.
So this is my proposal on how to take this forwards. Note that this is
not ready for merge (probably) just yet as I'd like Arpit to take a
look at the changes. I went through a version that had major refactors
to push the logic of building the records to the ports themselves, but
in the end don't think that brings enough benefits for the complexity.
Based on:
https://lore.kernel.org/qemu-devel/20260204170936.43959-1-Jonathan.Cameron@huawei.com/T/#t
(with all it's precursors, though hopefully they will all be in Michael's
next pull request)
I'll note this is an enormous foot gun as it lets you effectively trigger
surprise device resets. However, it's only accessible if you are using
a configuration with the fabric management parts of the CXL emulation.
For now that is a switch-cci (MCTP over USB support is near the top
of my list of things to get ready for upstram. I tested this with a
custom driver and if nothing else it exposed some gaps in Linux's
ability to rescan PCI buses after a perst event (even with drivers
unbound etc to make it safe).
Original cover letter:
This patch series refactor existing support for Identify Switch Device
and Get Physical Port State by utilizing physical ports (USP & DSP)
information stored during enumeration.
Additionally, it introduces new support for Physical Port Control
of Physical Switch Command Set as per CXL spec r3.2 Section 7.6.7.1.3.
It primarily constitutes two logic:
-Assert-Deassert PERST: Assert PERST involves physical port to be in
hold reset phase for minimum 100ms. No other physical port control
request are entertained until Deassert PERST command for the given
port is issued.
-Reset PPB: cold reset of physical port (completing enter->hold->exit
phases).
Tested using libcxl-mi interface[1]:
All active ports and all opcodes per active port is tested. Also, tested
against possible edge cases manually since the interface currently dosen't
support run time input.
Typical Qemu topology
(1 USP + 3 DSP's in a switch with 2 CXLType3 devices connected to the 2 DSP's):
FM="-object memory-backend-file,id=cxl-mem1,mem-path=$TMP_DIR/t3_cxl1.raw,size=256M \
-object memory-backend-file,id=cxl-lsa1,mem-path=$TMP_DIR/t3_lsa1.raw,size=1M \
-object memory-backend-file,id=cxl-mem2,mem-path=$TMP_DIR/t3_cxl2.raw,size=512M \
-object memory-backend-file,id=cxl-lsa2,mem-path=$TMP_DIR/t3_lsa2.raw,size=512M \
-device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1,hdm_for_passthrough=true \
-device cxl-rp,port=0,bus=cxl.1,id=cxl_rp_port0,chassis=0,slot=2 \
-device cxl-upstream,port=2,sn=1234,bus=cxl_rp_port0,id=us0,addr=0.0,multifunction=on, \
-device cxl-switch-mailbox-cci,bus=cxl_rp_port0,addr=0.1,target=us0 \
-device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
-device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
-device cxl-downstream,port=3,bus=us0,id=swport2,chassis=0,slot=6 \
-device cxl-type3,bus=swport0,memdev=cxl-mem1,id=cxl-pmem1,lsa=cxl-lsa1,sn=3 \
-device cxl-type3,bus=swport2,memdev=cxl-mem2,id=cxl-pmem2,lsa=cxl-lsa2,sn=4 \
-machine cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=1k \
-device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=4,target=us0 \
-device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=5,target=cxl-pmem1 \
-device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=6,target=cxl-pmem2 \
-device virtio-rng-pci,bus=swport1"
Tested multiple Qemu topologies:
-without any devices connected to downstream ports.
-with virtio-rng-pci devices connected to downstream ports.
-with CXLType3 devices connected to downstream ports.
-with different unique values of ports (both upstream and downstream).
Changes from v3 (https://lore.kernel.org/qemu-devel/20250909160316.00000190@huawei.com/T/):
-Namespaced the defines with cleaner prefix for Get Physical Port State
Port Information Block members.
-switch CCI implementation instead of switch FM interface as per
Jonathan's review comments, hence moved perst members initializations
from: cxl_initialize_usp_mctpcci() -> cxl_initialize_mailbox_swcci().
[1] https://github.com/computexpresslink/libcxlmi/commit/35fe68bd9a31469f832a87694d7b18d2d50be5b8
Arpit Kumar (2):
hw/cxl: Physical Port Info FMAPI - update to current spec and add
defines.
hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h)
Jonathan Cameron (1):
hw/cxl: Get Physical Port State - update for PCIe flit mode
include/hw/cxl/cxl_port.h | 73 ++++++++
include/hw/pci-bridge/cxl_downstream_port.h | 12 ++
include/hw/pci-bridge/cxl_upstream_port.h | 2 +
hw/cxl/cxl-mailbox-utils.c | 183 ++++++++++++++++++--
hw/pci-bridge/cxl_downstream.c | 9 +
hw/pci-bridge/cxl_upstream.c | 1 +
6 files changed, 268 insertions(+), 12 deletions(-)
create mode 100644 include/hw/cxl/cxl_port.h
create mode 100644 include/hw/pci-bridge/cxl_downstream_port.h
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH qemu v5 1/3] hw/cxl: Physical Port Info FMAPI - update to current spec and add defines.
2026-02-04 17:32 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Jonathan Cameron
@ 2026-02-04 17:32 ` Jonathan Cameron
2026-02-12 15:22 ` Arpit Kumar
2026-02-04 17:32 ` [PATCH qemu v5 2/3] hw/cxl: Get Physical Port State - update for PCIe flit mode Jonathan Cameron
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Jonathan Cameron @ 2026-02-04 17:32 UTC (permalink / raw)
To: Michael Tsirkin, qemu-devel, Arpit Kumar
Cc: linuxarm, linux-cxl, Ravi Shankar, Marcel Apfelbaum, Michael Roth
From: Arpit Kumar <arpit1.kumar@samsung.com>
Add a new cxl/cxl_ports.h header for field definitions related only to port
commands. Bring field naming up to date with spec as 'version' bitmasks
have been replaced with bitmasks of the specific features.
Fix a small issue where a reserved value for USP was set to 2 rather
than 0.
Signed-off-by: Arpit Kumar <arpit1.kumar@samsung.com>
Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
This is effectively lifted out of Arpit's orginal rework.
Arpit please confirm you are fine with keeping authorship on this one.
---
include/hw/cxl/cxl_port.h | 53 ++++++++++++++++++++++++++++++++++++++
hw/cxl/cxl-mailbox-utils.c | 31 ++++++++++++++--------
2 files changed, 73 insertions(+), 11 deletions(-)
diff --git a/include/hw/cxl/cxl_port.h b/include/hw/cxl/cxl_port.h
new file mode 100644
index 000000000000..04db60f7bc23
--- /dev/null
+++ b/include/hw/cxl/cxl_port.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef CXL_PORT_H
+#define CXL_PORT_H
+
+/* CXL r3.2 Table 7-19: Get Physical Port State Port Information Block Format */
+#define CXL_PORT_CONFIG_STATE_DISABLED 0x0
+#define CXL_PORT_CONFIG_STATE_BIND_IN_PROGRESS 0x1
+#define CXL_PORT_CONFIG_STATE_UNBIND_IN_PROGRESS 0x2
+#define CXL_PORT_CONFIG_STATE_DSP 0x3
+#define CXL_PORT_CONFIG_STATE_USP 0x4
+#define CXL_PORT_CONFIG_STATE_FABRIC_PORT 0x5
+#define CXL_PORT_CONFIG_STATE_INVALID_PORT_ID 0xF
+
+#define CXL_PORT_CONNECTED_DEV_MODE_NOT_CXL_OR_DISCONN 0x00
+#define CXL_PORT_CONNECTED_DEV_MODE_RCD 0x01
+#define CXL_PORT_CONNECTED_DEV_MODE_68B_VH 0x02
+#define CXL_PORT_CONNECTED_DEV_MODE_256B 0x03
+#define CXL_PORT_CONNECTED_DEV_MODE_LO_256B 0x04
+#define CXL_PORT_CONNECTED_DEV_MODE_PBR 0x05
+
+#define CXL_PORT_CONNECTED_DEV_TYPE_NONE 0x00
+#define CXL_PORT_CONNECTED_DEV_TYPE_PCIE 0x01
+#define CXL_PORT_CONNECTED_DEV_TYPE_1 0x02
+#define CXL_PORT_CONNECTED_DEV_TYPE_2_OR_HBR_SWITCH 0x03
+#define CXL_PORT_CONNECTED_DEV_TYPE_3_SLD 0x04
+#define CXL_PORT_CONNECTED_DEV_TYPE_3_MLD 0x05
+#define CXL_PORT_CONNECTED_DEV_PBR_COMPONENT 0x06
+
+#define CXL_PORT_SUPPORTS_RCD BIT(0)
+#define CXL_PORT_SUPPORTS_68B_VH BIT(1)
+#define CXL_PORT_SUPPORTS_256B BIT(2)
+#define CXL_PORT_SUPPORTS_LO_256B BIT(3)
+#define CXL_PORT_SUPPORTS_PBR BIT(4)
+
+#define CXL_PORT_LTSSM_DETECT 0x00
+#define CXL_PORT_LTSSM_POLLING 0x01
+#define CXL_PORT_LTSSM_CONFIGURATION 0x02
+#define CXL_PORT_LTSSM_RECOVERY 0x03
+#define CXL_PORT_LTSSM_L0 0x04
+#define CXL_PORT_LTSSM_L0S 0x05
+#define CXL_PORT_LTSSM_L1 0x06
+#define CXL_PORT_LTSSM_L2 0x07
+#define CXL_PORT_LTSSM_DISABLED 0x08
+#define CXL_PORT_LTSSM_LOOPBACK 0x09
+#define CXL_PORT_LTSSM_HOT_RESET 0x0A
+
+#define CXL_PORT_LINK_STATE_FLAG_LANE_REVERSED BIT(0)
+#define CXL_PORT_LINK_STATE_FLAG_PERST_ASSERTED BIT(1)
+#define CXL_PORT_LINK_STATE_FLAG_PRSNT BIT(2)
+#define CXL_PORT_LINK_STATE_FLAG_POWER_OFF BIT(3)
+
+#endif /* CXL_PORT_H */
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 2f449980cdc0..1c8cbe0f682d 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -15,6 +15,7 @@
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_events.h"
#include "hw/cxl/cxl_mailbox.h"
+#include "hw/cxl/cxl_port.h"
#include "hw/pci/pci.h"
#include "hw/pci-bridge/cxl_upstream_port.h"
#include "qemu/cutils.h"
@@ -565,16 +566,16 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
} QEMU_PACKED *in;
/*
- * CXL r3.1 Table 7-19: Get Physical Port State Port Information Block
+ * CXL r3.2 Table 7-19: Get Physical Port State Port Information Block
* Format
*/
struct cxl_fmapi_port_state_info_block {
uint8_t port_id;
uint8_t config_state;
- uint8_t connected_device_cxl_version;
+ uint8_t connected_device_mode;
uint8_t rsv1;
uint8_t connected_device_type;
- uint8_t port_cxl_version_bitmask;
+ uint8_t supported_cxl_mode_bitmask;
uint8_t max_link_width;
uint8_t negotiated_link_width;
uint8_t supported_link_speeds_vector;
@@ -623,21 +624,30 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
if (port_dev) { /* DSP */
PCIDevice *ds_dev = pci_bridge_get_sec_bus(PCI_BRIDGE(port_dev))
->devices[0];
- port->config_state = 3;
+ port->config_state = CXL_PORT_CONFIG_STATE_DSP;
if (ds_dev) {
if (object_dynamic_cast(OBJECT(ds_dev), TYPE_CXL_TYPE3)) {
- port->connected_device_type = 5; /* Assume MLD for now */
+ /* Assume MLD for now */
+ port->connected_device_type =
+ CXL_PORT_CONNECTED_DEV_TYPE_3_MLD;
} else {
- port->connected_device_type = 1;
+ port->connected_device_type =
+ CXL_PORT_CONNECTED_DEV_TYPE_PCIE;
+ port->connected_device_mode =
+ CXL_PORT_CONNECTED_DEV_MODE_NOT_CXL_OR_DISCONN;
+
}
} else {
- port->connected_device_type = 0;
+ port->connected_device_type = CXL_PORT_CONNECTED_DEV_TYPE_NONE;
+ port->connected_device_mode =
+ CXL_PORT_CONNECTED_DEV_MODE_NOT_CXL_OR_DISCONN;
}
port->supported_ld_count = 3;
} else if (usp->port == in->ports[i]) { /* USP */
port_dev = PCI_DEVICE(usp);
- port->config_state = 4;
- port->connected_device_type = 0;
+ port->config_state = CXL_PORT_CONFIG_STATE_USP;
+ port->connected_device_type = 0; /* Reserved for USP */
+ port->connected_device_mode = 0; /* Reserved for USP */
} else {
return CXL_MBOX_INVALID_INPUT;
}
@@ -667,8 +677,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
port->ltssm_state = 0x7;
port->first_lane_num = 0;
port->link_state = 0;
- port->port_cxl_version_bitmask = 0x2;
- port->connected_device_cxl_version = 0x2;
+ port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH;
}
pl_size = sizeof(*out) + sizeof(*out->ports) * in->num_ports;
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH qemu v5 2/3] hw/cxl: Get Physical Port State - update for PCIe flit mode
2026-02-04 17:32 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Jonathan Cameron
2026-02-04 17:32 ` [PATCH qemu v5 1/3] hw/cxl: Physical Port Info FMAPI - update to current spec and add defines Jonathan Cameron
@ 2026-02-04 17:32 ` Jonathan Cameron
2026-02-04 17:32 ` [PATCH qemu v5 3/3] hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h) Jonathan Cameron
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Jonathan Cameron @ 2026-02-04 17:32 UTC (permalink / raw)
To: Michael Tsirkin, qemu-devel, Arpit Kumar
Cc: linuxarm, linux-cxl, Ravi Shankar, Marcel Apfelbaum, Michael Roth
Recent support for 256B flits, was not accounted for in this FMAPI command
that should be retrieving the current status of Physical Switch Ports.
Note x-flit-mode control is via the downstream devices, so for USPs the
property must be checked to establish support, but for DSPs this mode is
always supported (control is with the next port downstream, typically the
end point. All cases the linksta2 register may be queried to obtain
current status. Note the PCI spec is a little confusing as it refers to
this bit only being non 0 if Device Readiness Status (DRS) is in particular
states (basically link trained) but Flit mode is a separate feature and DRS
may not be present. It is not yet emulated in QEMU. So assume that we
should reflect what states DRS would be reporting if it were actually
present.
One small thing to note is that the current link width for a port with
nothing connected reports the same as the capability. This is odd but valid
because the value under these circumstances is undefined (PCIe r6.2 table
7-26 Link Status Register - field Current Link Speed.)
Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
hw/cxl/cxl-mailbox-utils.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 1c8cbe0f682d..b6ac987ee021 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -627,9 +627,26 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
port->config_state = CXL_PORT_CONFIG_STATE_DSP;
if (ds_dev) {
if (object_dynamic_cast(OBJECT(ds_dev), TYPE_CXL_TYPE3)) {
+ uint16_t lnksta2;
+
+ if (!port_dev->exp.exp_cap) {
+ return CXL_MBOX_INTERNAL_ERROR;
+ }
+
+ lnksta2 = port_dev->config_read(port_dev,
+ port_dev->exp.exp_cap + PCI_EXP_LNKSTA2,
+ sizeof(lnksta2));
+
/* Assume MLD for now */
port->connected_device_type =
CXL_PORT_CONNECTED_DEV_TYPE_3_MLD;
+ if (lnksta2 & PCI_EXP_LNKSTA2_FLIT) {
+ port->connected_device_mode =
+ CXL_PORT_CONNECTED_DEV_MODE_256B;
+ } else {
+ port->connected_device_mode =
+ CXL_PORT_CONNECTED_DEV_MODE_68B_VH;
+ }
} else {
port->connected_device_type =
CXL_PORT_CONNECTED_DEV_TYPE_PCIE;
@@ -642,12 +659,17 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
port->connected_device_mode =
CXL_PORT_CONNECTED_DEV_MODE_NOT_CXL_OR_DISCONN;
}
+ /* DSP currently always support modes implemented in QEMU */
+ port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH |
+ CXL_PORT_SUPPORTS_256B;
port->supported_ld_count = 3;
} else if (usp->port == in->ports[i]) { /* USP */
port_dev = PCI_DEVICE(usp);
port->config_state = CXL_PORT_CONFIG_STATE_USP;
port->connected_device_type = 0; /* Reserved for USP */
port->connected_device_mode = 0; /* Reserved for USP */
+ port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH |
+ (CXL_USP(usp)->flitmode ? CXL_PORT_SUPPORTS_256B : 0);
} else {
return CXL_MBOX_INVALID_INPUT;
}
@@ -676,8 +698,6 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
/* TODO: Track down if we can get the rest of the info */
port->ltssm_state = 0x7;
port->first_lane_num = 0;
- port->link_state = 0;
- port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH;
}
pl_size = sizeof(*out) + sizeof(*out->ports) * in->num_ports;
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH qemu v5 3/3] hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h)
2026-02-04 17:32 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Jonathan Cameron
2026-02-04 17:32 ` [PATCH qemu v5 1/3] hw/cxl: Physical Port Info FMAPI - update to current spec and add defines Jonathan Cameron
2026-02-04 17:32 ` [PATCH qemu v5 2/3] hw/cxl: Get Physical Port State - update for PCIe flit mode Jonathan Cameron
@ 2026-02-04 17:32 ` Jonathan Cameron
2026-02-12 15:25 ` Arpit Kumar
2026-02-12 15:12 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Arpit Kumar
2026-02-20 12:58 ` Michael S. Tsirkin
4 siblings, 1 reply; 10+ messages in thread
From: Jonathan Cameron @ 2026-02-04 17:32 UTC (permalink / raw)
To: Michael Tsirkin, qemu-devel, Arpit Kumar
Cc: linuxarm, linux-cxl, Ravi Shankar, Marcel Apfelbaum, Michael Roth
From: Arpit Kumar <arpit1.kumar@samsung.com>
Added assert-deassert PERST implementation for physical ports (both USP
and DSP's).
Assert PERST involves bg operation for holding 100ms.
Reset PPB implementation for physical ports.
Signed-off-by: Arpit Kumar <arpit1.kumar@samsung.com>
Co-developed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
Changes mostly due to dropping refactor that preceeded this in original
series.
---
include/hw/cxl/cxl_port.h | 20 +++
include/hw/pci-bridge/cxl_downstream_port.h | 12 ++
include/hw/pci-bridge/cxl_upstream_port.h | 2 +
hw/cxl/cxl-mailbox-utils.c | 130 ++++++++++++++++++++
hw/pci-bridge/cxl_downstream.c | 9 ++
hw/pci-bridge/cxl_upstream.c | 1 +
6 files changed, 174 insertions(+)
diff --git a/include/hw/cxl/cxl_port.h b/include/hw/cxl/cxl_port.h
index 04db60f7bc23..fb2e22a9f2ae 100644
--- a/include/hw/cxl/cxl_port.h
+++ b/include/hw/cxl/cxl_port.h
@@ -3,6 +3,8 @@
#ifndef CXL_PORT_H
#define CXL_PORT_H
+#include "qemu/thread.h"
+
/* CXL r3.2 Table 7-19: Get Physical Port State Port Information Block Format */
#define CXL_PORT_CONFIG_STATE_DISABLED 0x0
#define CXL_PORT_CONFIG_STATE_BIND_IN_PROGRESS 0x1
@@ -50,4 +52,22 @@
#define CXL_PORT_LINK_STATE_FLAG_PRSNT BIT(2)
#define CXL_PORT_LINK_STATE_FLAG_POWER_OFF BIT(3)
+#define CXL_MAX_PHY_PORTS 256
+#define ASSERT_WAIT_TIME_MS 100 /* Assert - Deassert PERST */
+
+/* Assert - Deassert PERST */
+typedef struct CXLPhyPortPerst {
+ bool issued_assert_perst;
+ QemuMutex lock; /* protecting assert-deassert reset request */
+ uint64_t asrt_time;
+ QemuThread asrt_thread; /* thread for 100ms delay */
+} CXLPhyPortPerst;
+
+void cxl_init_physical_port_control(CXLPhyPortPerst *perst);
+
+static inline bool cxl_perst_asserted(CXLPhyPortPerst *perst)
+{
+ return perst->issued_assert_perst || perst->asrt_time < ASSERT_WAIT_TIME_MS;
+}
+
#endif /* CXL_PORT_H */
diff --git a/include/hw/pci-bridge/cxl_downstream_port.h b/include/hw/pci-bridge/cxl_downstream_port.h
new file mode 100644
index 000000000000..1611504c8764
--- /dev/null
+++ b/include/hw/pci-bridge/cxl_downstream_port.h
@@ -0,0 +1,12 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef CXL_DOWNSTREAM_PORT_H
+#define CXL_DOWNSTREAM_PORT_H
+#include "include/hw/cxl/cxl_port.h"
+
+typedef struct CXLDownstreamPort CXLDownstreamPort;
+CXLPhyPortPerst *cxl_dsp_get_perst(CXLDownstreamPort *dsp);
+
+#endif
diff --git a/include/hw/pci-bridge/cxl_upstream_port.h b/include/hw/pci-bridge/cxl_upstream_port.h
index e3d6a27acc86..dfe01771c7d7 100644
--- a/include/hw/pci-bridge/cxl_upstream_port.h
+++ b/include/hw/pci-bridge/cxl_upstream_port.h
@@ -4,6 +4,7 @@
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_port.h"
#include "hw/cxl/cxl.h"
+#include "hw/cxl/cxl_port.h"
typedef struct CXLUpstreamPort {
/*< private >*/
@@ -12,6 +13,7 @@ typedef struct CXLUpstreamPort {
/*< public >*/
CXLComponentState cxl_cstate;
CXLCCI swcci;
+ CXLPhyPortPerst perst;
PCIExpLinkSpeed speed;
PCIExpLinkWidth width;
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index b6ac987ee021..c83b5f90d4d3 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -17,6 +17,7 @@
#include "hw/cxl/cxl_mailbox.h"
#include "hw/cxl/cxl_port.h"
#include "hw/pci/pci.h"
+#include "hw/pci-bridge/cxl_downstream_port.h"
#include "hw/pci-bridge/cxl_upstream_port.h"
#include "qemu/cutils.h"
#include "qemu/host-utils.h"
@@ -119,6 +120,7 @@ enum {
PHYSICAL_SWITCH = 0x51,
#define IDENTIFY_SWITCH_DEVICE 0x0
#define GET_PHYSICAL_PORT_STATE 0x1
+ #define PHYSICAL_PORT_CONTROL 0x2
TUNNEL = 0x53,
#define MANAGEMENT_COMMAND 0x0
FMAPI_DCD_MGMT = 0x56,
@@ -616,6 +618,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
struct cxl_fmapi_port_state_info_block *port;
/* First try to match on downstream port */
PCIDevice *port_dev;
+ CXLPhyPortPerst *perst;
uint16_t lnkcap, lnkcap2, lnksta;
port = &out->ports[i];
@@ -663,6 +666,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH |
CXL_PORT_SUPPORTS_256B;
port->supported_ld_count = 3;
+ perst = cxl_dsp_get_perst(CXL_DSP(port_dev));
} else if (usp->port == in->ports[i]) { /* USP */
port_dev = PCI_DEVICE(usp);
port->config_state = CXL_PORT_CONFIG_STATE_USP;
@@ -670,6 +674,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
port->connected_device_mode = 0; /* Reserved for USP */
port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH |
(CXL_USP(usp)->flitmode ? CXL_PORT_SUPPORTS_256B : 0);
+ perst = &CXL_USP(usp)->perst;
} else {
return CXL_MBOX_INVALID_INPUT;
}
@@ -698,6 +703,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
/* TODO: Track down if we can get the rest of the info */
port->ltssm_state = 0x7;
port->first_lane_num = 0;
+ port->link_state = perst ? CXL_PORT_LINK_STATE_FLAG_PERST_ASSERTED : 0;
}
pl_size = sizeof(*out) + sizeof(*out->ports) * in->num_ports;
@@ -706,6 +712,115 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
+static void *bg_assertcb(void *opaque)
+{
+ CXLPhyPortPerst *perst = opaque;
+
+ /* holding reset phase for 100ms */
+ while (perst->asrt_time--) {
+ usleep(1000);
+ }
+ perst->issued_assert_perst = true;
+ return NULL;
+}
+
+static CXLRetCode cxl_deassert_perst(Object *obj, CXLPhyPortPerst *perst)
+{
+ if (!perst->issued_assert_perst) {
+ return CXL_MBOX_INTERNAL_ERROR;
+ }
+
+ QEMU_LOCK_GUARD(&perst->lock);
+ resettable_release_reset(obj, RESET_TYPE_COLD);
+ perst->issued_assert_perst = false;
+ perst->asrt_time = ASSERT_WAIT_TIME_MS;
+
+ return CXL_MBOX_SUCCESS;
+}
+
+static CXLRetCode cxl_assert_perst(Object *obj, CXLPhyPortPerst *perst)
+{
+ if (cxl_perst_asserted(perst)) {
+ return CXL_MBOX_INTERNAL_ERROR;
+ }
+
+ QEMU_LOCK_GUARD(&perst->lock);
+ resettable_assert_reset(obj, RESET_TYPE_COLD);
+ qemu_thread_create(&perst->asrt_thread, "assert_thread", bg_assertcb,
+ perst, QEMU_THREAD_DETACHED);
+
+ return CXL_MBOX_SUCCESS;
+}
+
+static CXLDownstreamPort *cxl_find_dsp_on_bus(PCIBus *bus, uint8_t pn)
+{
+
+ PCIDevice *port_dev = pcie_find_port_by_pn(bus, pn);
+
+ if (object_dynamic_cast(OBJECT(port_dev), TYPE_CXL_DSP)) {
+ return CXL_DSP(port_dev);
+ }
+
+ return NULL;
+}
+
+/* CXL r3.2 Section 7.6.7.1.3: Get Physical Port Control (Opcode 5102h) */
+static CXLRetCode cmd_physical_port_control(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ CXLUpstreamPort *pp = CXL_USP(cci->d);
+ CXLPhyPortPerst *perst;
+ PCIDevice *dev;
+
+ struct cxl_fmapi_get_physical_port_control_req_pl {
+ uint8_t ppb_id;
+ uint8_t ports_op;
+ } QEMU_PACKED *in = (void *)payload_in;
+
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
+ if (PCIE_PORT(pp)->port == in->ppb_id) {
+ dev = PCI_DEVICE(pp);
+ perst = &pp->perst;
+ } else {
+ CXLDownstreamPort *dsp =
+ cxl_find_dsp_on_bus(&PCI_BRIDGE(pp)->sec_bus, in->ppb_id);
+
+ if (!dsp) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ dev = PCI_DEVICE(dsp);
+ perst = cxl_dsp_get_perst(dsp);
+ }
+
+ switch (in->ports_op) {
+ case 0:
+ return cxl_assert_perst(OBJECT(&dev->qdev), perst);
+ case 1:
+ return cxl_deassert_perst(OBJECT(&dev->qdev), perst);
+ case 2: {
+ if (!perst) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ if (perst->issued_assert_perst ||
+ perst->asrt_time < ASSERT_WAIT_TIME_MS) {
+ return CXL_MBOX_INTERNAL_ERROR;
+ }
+ device_cold_reset(&dev->qdev);
+ return CXL_MBOX_SUCCESS;
+ }
+ default:
+ return CXL_MBOX_INVALID_INPUT;
+ }
+}
+
/* CXL r3.1 Section 8.2.9.1.2: Background Operation Status (Opcode 0002h) */
static CXLRetCode cmd_infostat_bg_op_sts(const struct cxl_cmd *cmd,
uint8_t *payload_in,
@@ -4412,6 +4527,8 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
cmd_identify_switch_device, 0, 0 },
[PHYSICAL_SWITCH][GET_PHYSICAL_PORT_STATE] = { "SWITCH_PHYSICAL_PORT_STATS",
cmd_get_physical_port_state, ~0, 0 },
+ [PHYSICAL_SWITCH][PHYSICAL_PORT_CONTROL] = { "SWITCH_PHYSICAL_PORT_CONTROL",
+ cmd_physical_port_control, 2, 0 },
[TUNNEL][MANAGEMENT_COMMAND] = { "TUNNEL_MANAGEMENT_COMMAND",
cmd_tunnel_management_cmd, ~0, 0 },
};
@@ -4618,6 +4735,19 @@ static void cxl_rebuild_cel(CXLCCI *cci)
}
}
+void cxl_init_physical_port_control(CXLPhyPortPerst *perst)
+{
+ qemu_mutex_init(&perst->lock);
+ perst->issued_assert_perst = false;
+ /*
+ * Assert PERST involves physical port to be in
+ * hold reset phase for minimum 100ms. No other
+ * physical port control requests are entertained
+ * until Deassert PERST command.
+ */
+ perst->asrt_time = ASSERT_WAIT_TIME_MS;
+}
+
void cxl_init_cci(CXLCCI *cci, size_t payload_max)
{
cci->payload_max = payload_max;
diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index 320818a8f1ce..ec450d1aa09e 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -13,9 +13,11 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_port.h"
+#include "hw/pci-bridge/cxl_downstream_port.h"
#include "hw/core/qdev-properties.h"
#include "hw/core/qdev-properties-system.h"
#include "hw/cxl/cxl.h"
+#include "hw/cxl/cxl_port.h"
#include "qapi/error.h"
typedef struct CXLDownstreamPort {
@@ -24,6 +26,7 @@ typedef struct CXLDownstreamPort {
/*< public >*/
CXLComponentState cxl_cstate;
+ CXLPhyPortPerst perst;
} CXLDownstreamPort;
#define CXL_DOWNSTREAM_PORT_MSI_OFFSET 0x70
@@ -81,6 +84,11 @@ static void cxl_dsp_config_write(PCIDevice *d, uint32_t address,
cxl_dsp_dvsec_write_config(d, address, val, len);
}
+CXLPhyPortPerst *cxl_dsp_get_perst(CXLDownstreamPort *dsp)
+{
+ return &dsp->perst;
+}
+
static void cxl_dsp_reset(DeviceState *qdev)
{
PCIDevice *d = PCI_DEVICE(qdev);
@@ -92,6 +100,7 @@ static void cxl_dsp_reset(DeviceState *qdev)
pci_bridge_reset(qdev);
latch_registers(dsp);
+ cxl_init_physical_port_control(&dsp->perst);
}
static void build_dvsecs(PCIDevice *d, CXLComponentState *cxl)
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index fb8d19539c9f..b6281cbd4cb0 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -103,6 +103,7 @@ static void cxl_usp_reset(DeviceState *qdev)
pcie_cap_deverr_reset(d);
pcie_cap_fill_link_ep_usp(d, usp->width, usp->speed, usp->flitmode);
latch_registers(usp);
+ cxl_init_physical_port_control(&usp->perst);
}
static void build_dvsecs(CXLUpstreamPort *usp)
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support.
2026-02-04 17:32 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Jonathan Cameron
` (2 preceding siblings ...)
2026-02-04 17:32 ` [PATCH qemu v5 3/3] hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h) Jonathan Cameron
@ 2026-02-12 15:12 ` Arpit Kumar
2026-02-20 12:58 ` Michael S. Tsirkin
4 siblings, 0 replies; 10+ messages in thread
From: Arpit Kumar @ 2026-02-12 15:12 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Michael Tsirkin, qemu-devel, linuxarm, linux-cxl, Ravi Shankar,
Marcel Apfelbaum, Michael Roth, Arpit Kumar, cpgs
[-- Attachment #1: Type: text/plain, Size: 6104 bytes --]
On 04/02/26 05:32PM, Jonathan Cameron wrote:
>Changes since v4:
>https://lore.kernel.org/qemu-devel/20250916080736.1266083-1-arpit1.kumar@samsung.com/
>- Dropped initial refactor. Reason being that it is not static enough
> for caching at boot to be appropriate. Kept the spec update part
> of this.
>- Added a patch to make sure the new flip mode stuff is reported in
> the Get Physical Port State command.
>- Rebased Arpit's Physical Control Control FMAPI Command given drop
> of the major refactor from v4 patch 1.
>
>I had taken this into my cxl staging tree thinking it only needed a few
>minor tweaks. Then whilst testing I realized it didn't work with hotplug
>and that made me consider if Arpit's original approach made sense.
>
>So this is my proposal on how to take this forwards. Note that this is
>not ready for merge (probably) just yet as I'd like Arpit to take a
>look at the changes. I went through a version that had major refactors
>to push the logic of building the records to the ports themselves, but
>in the end don't think that brings enough benefits for the complexity.
>
Hi Jonathan,
Thanks for the patch series. I have reviewed the changes in detail, and
the approach looks good to me. Thanks for the rework and keeping me in
the loop.
>Based on:
>https://lore.kernel.org/qemu-devel/20260204170936.43959-1-Jonathan.Cameron@huawei.com/T/#t
>(with all it's precursors, though hopefully they will all be in Michael's
>next pull request)
>
>I'll note this is an enormous foot gun as it lets you effectively trigger
>surprise device resets. However, it's only accessible if you are using
>a configuration with the fabric management parts of the CXL emulation.
>For now that is a switch-cci (MCTP over USB support is near the top
>of my list of things to get ready for upstram. I tested this with a
>custom driver and if nothing else it exposed some gaps in Linux's
>ability to rescan PCI buses after a perst event (even with drivers
>unbound etc to make it safe).
>
>Original cover letter:
>
>This patch series refactor existing support for Identify Switch Device
>and Get Physical Port State by utilizing physical ports (USP & DSP)
>information stored during enumeration.
>
>Additionally, it introduces new support for Physical Port Control
>of Physical Switch Command Set as per CXL spec r3.2 Section 7.6.7.1.3.
>It primarily constitutes two logic:
> -Assert-Deassert PERST: Assert PERST involves physical port to be in
> hold reset phase for minimum 100ms. No other physical port control
> request are entertained until Deassert PERST command for the given
> port is issued.
> -Reset PPB: cold reset of physical port (completing enter->hold->exit
> phases).
>
>Tested using libcxl-mi interface[1]:
>All active ports and all opcodes per active port is tested. Also, tested
>against possible edge cases manually since the interface currently dosen't
>support run time input.
>
>Typical Qemu topology
>(1 USP + 3 DSP's in a switch with 2 CXLType3 devices connected to the 2 DSP's):
>FM="-object memory-backend-file,id=cxl-mem1,mem-path=$TMP_DIR/t3_cxl1.raw,size=256M \
> -object memory-backend-file,id=cxl-lsa1,mem-path=$TMP_DIR/t3_lsa1.raw,size=1M \
> -object memory-backend-file,id=cxl-mem2,mem-path=$TMP_DIR/t3_cxl2.raw,size=512M \
> -object memory-backend-file,id=cxl-lsa2,mem-path=$TMP_DIR/t3_lsa2.raw,size=512M \
> -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1,hdm_for_passthrough=true \
> -device cxl-rp,port=0,bus=cxl.1,id=cxl_rp_port0,chassis=0,slot=2 \
> -device cxl-upstream,port=2,sn=1234,bus=cxl_rp_port0,id=us0,addr=0.0,multifunction=on, \
> -device cxl-switch-mailbox-cci,bus=cxl_rp_port0,addr=0.1,target=us0 \
> -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
> -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
> -device cxl-downstream,port=3,bus=us0,id=swport2,chassis=0,slot=6 \
> -device cxl-type3,bus=swport0,memdev=cxl-mem1,id=cxl-pmem1,lsa=cxl-lsa1,sn=3 \
> -device cxl-type3,bus=swport2,memdev=cxl-mem2,id=cxl-pmem2,lsa=cxl-lsa2,sn=4 \
> -machine cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=1k \
> -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=4,target=us0 \
> -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=5,target=cxl-pmem1 \
> -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=6,target=cxl-pmem2 \
> -device virtio-rng-pci,bus=swport1"
>
>Tested multiple Qemu topologies:
> -without any devices connected to downstream ports.
> -with virtio-rng-pci devices connected to downstream ports.
> -with CXLType3 devices connected to downstream ports.
> -with different unique values of ports (both upstream and downstream).
>
>Changes from v3 (https://lore.kernel.org/qemu-devel/20250909160316.00000190@huawei.com/T/):
> -Namespaced the defines with cleaner prefix for Get Physical Port State
> Port Information Block members.
> -switch CCI implementation instead of switch FM interface as per
> Jonathan's review comments, hence moved perst members initializations
> from: cxl_initialize_usp_mctpcci() -> cxl_initialize_mailbox_swcci().
>
>[1] https://github.com/computexpresslink/libcxlmi/commit/35fe68bd9a31469f832a87694d7b18d2d50be5b8
>
>
>Arpit Kumar (2):
> hw/cxl: Physical Port Info FMAPI - update to current spec and add
> defines.
> hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h)
>
>Jonathan Cameron (1):
> hw/cxl: Get Physical Port State - update for PCIe flit mode
>
> include/hw/cxl/cxl_port.h | 73 ++++++++
> include/hw/pci-bridge/cxl_downstream_port.h | 12 ++
> include/hw/pci-bridge/cxl_upstream_port.h | 2 +
> hw/cxl/cxl-mailbox-utils.c | 183 ++++++++++++++++++--
> hw/pci-bridge/cxl_downstream.c | 9 +
> hw/pci-bridge/cxl_upstream.c | 1 +
> 6 files changed, 268 insertions(+), 12 deletions(-)
> create mode 100644 include/hw/cxl/cxl_port.h
> create mode 100644 include/hw/pci-bridge/cxl_downstream_port.h
>
>--
>2.51.0
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH qemu v5 1/3] hw/cxl: Physical Port Info FMAPI - update to current spec and add defines.
2026-02-04 17:32 ` [PATCH qemu v5 1/3] hw/cxl: Physical Port Info FMAPI - update to current spec and add defines Jonathan Cameron
@ 2026-02-12 15:22 ` Arpit Kumar
0 siblings, 0 replies; 10+ messages in thread
From: Arpit Kumar @ 2026-02-12 15:22 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Michael Tsirkin, qemu-devel, linuxarm, linux-cxl, Ravi Shankar,
Marcel Apfelbaum, Michael Roth, Arpit Kumar, cpgs
[-- Attachment #1: Type: text/plain, Size: 7149 bytes --]
On 04/02/26 05:32PM, Jonathan Cameron wrote:
>From: Arpit Kumar <arpit1.kumar@samsung.com>
>
>Add a new cxl/cxl_ports.h header for field definitions related only to port
>commands. Bring field naming up to date with spec as 'version' bitmasks
>have been replaced with bitmasks of the specific features.
>
>Fix a small issue where a reserved value for USP was set to 2 rather
>than 0.
>
>Signed-off-by: Arpit Kumar <arpit1.kumar@samsung.com>
>Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
>Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
>
>---
>This is effectively lifted out of Arpit's orginal rework.
>Arpit please confirm you are fine with keeping authorship on this one.
>---
Hi Jonathan,
I'm fine with keeping the authorship on this patch and the split looks
good to me. I only noticed a minor extra line, but nothing functional.
Thanks,
Arpit
> include/hw/cxl/cxl_port.h | 53 ++++++++++++++++++++++++++++++++++++++
> hw/cxl/cxl-mailbox-utils.c | 31 ++++++++++++++--------
> 2 files changed, 73 insertions(+), 11 deletions(-)
>
>diff --git a/include/hw/cxl/cxl_port.h b/include/hw/cxl/cxl_port.h
>new file mode 100644
>index 000000000000..04db60f7bc23
>--- /dev/null
>+++ b/include/hw/cxl/cxl_port.h
>@@ -0,0 +1,53 @@
>+/* SPDX-License-Identifier: GPL-2.0-or-later */
>+
>+#ifndef CXL_PORT_H
>+#define CXL_PORT_H
>+
>+/* CXL r3.2 Table 7-19: Get Physical Port State Port Information Block Format */
>+#define CXL_PORT_CONFIG_STATE_DISABLED 0x0
>+#define CXL_PORT_CONFIG_STATE_BIND_IN_PROGRESS 0x1
>+#define CXL_PORT_CONFIG_STATE_UNBIND_IN_PROGRESS 0x2
>+#define CXL_PORT_CONFIG_STATE_DSP 0x3
>+#define CXL_PORT_CONFIG_STATE_USP 0x4
>+#define CXL_PORT_CONFIG_STATE_FABRIC_PORT 0x5
>+#define CXL_PORT_CONFIG_STATE_INVALID_PORT_ID 0xF
>+
>+#define CXL_PORT_CONNECTED_DEV_MODE_NOT_CXL_OR_DISCONN 0x00
>+#define CXL_PORT_CONNECTED_DEV_MODE_RCD 0x01
>+#define CXL_PORT_CONNECTED_DEV_MODE_68B_VH 0x02
>+#define CXL_PORT_CONNECTED_DEV_MODE_256B 0x03
>+#define CXL_PORT_CONNECTED_DEV_MODE_LO_256B 0x04
>+#define CXL_PORT_CONNECTED_DEV_MODE_PBR 0x05
>+
>+#define CXL_PORT_CONNECTED_DEV_TYPE_NONE 0x00
>+#define CXL_PORT_CONNECTED_DEV_TYPE_PCIE 0x01
>+#define CXL_PORT_CONNECTED_DEV_TYPE_1 0x02
>+#define CXL_PORT_CONNECTED_DEV_TYPE_2_OR_HBR_SWITCH 0x03
>+#define CXL_PORT_CONNECTED_DEV_TYPE_3_SLD 0x04
>+#define CXL_PORT_CONNECTED_DEV_TYPE_3_MLD 0x05
>+#define CXL_PORT_CONNECTED_DEV_PBR_COMPONENT 0x06
>+
>+#define CXL_PORT_SUPPORTS_RCD BIT(0)
>+#define CXL_PORT_SUPPORTS_68B_VH BIT(1)
>+#define CXL_PORT_SUPPORTS_256B BIT(2)
>+#define CXL_PORT_SUPPORTS_LO_256B BIT(3)
>+#define CXL_PORT_SUPPORTS_PBR BIT(4)
>+
>+#define CXL_PORT_LTSSM_DETECT 0x00
>+#define CXL_PORT_LTSSM_POLLING 0x01
>+#define CXL_PORT_LTSSM_CONFIGURATION 0x02
>+#define CXL_PORT_LTSSM_RECOVERY 0x03
>+#define CXL_PORT_LTSSM_L0 0x04
>+#define CXL_PORT_LTSSM_L0S 0x05
>+#define CXL_PORT_LTSSM_L1 0x06
>+#define CXL_PORT_LTSSM_L2 0x07
>+#define CXL_PORT_LTSSM_DISABLED 0x08
>+#define CXL_PORT_LTSSM_LOOPBACK 0x09
>+#define CXL_PORT_LTSSM_HOT_RESET 0x0A
>+
>+#define CXL_PORT_LINK_STATE_FLAG_LANE_REVERSED BIT(0)
>+#define CXL_PORT_LINK_STATE_FLAG_PERST_ASSERTED BIT(1)
>+#define CXL_PORT_LINK_STATE_FLAG_PRSNT BIT(2)
>+#define CXL_PORT_LINK_STATE_FLAG_POWER_OFF BIT(3)
>+
>+#endif /* CXL_PORT_H */
>diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
>index 2f449980cdc0..1c8cbe0f682d 100644
>--- a/hw/cxl/cxl-mailbox-utils.c
>+++ b/hw/cxl/cxl-mailbox-utils.c
>@@ -15,6 +15,7 @@
> #include "hw/cxl/cxl.h"
> #include "hw/cxl/cxl_events.h"
> #include "hw/cxl/cxl_mailbox.h"
>+#include "hw/cxl/cxl_port.h"
> #include "hw/pci/pci.h"
> #include "hw/pci-bridge/cxl_upstream_port.h"
> #include "qemu/cutils.h"
>@@ -565,16 +566,16 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> } QEMU_PACKED *in;
>
> /*
>- * CXL r3.1 Table 7-19: Get Physical Port State Port Information Block
>+ * CXL r3.2 Table 7-19: Get Physical Port State Port Information Block
> * Format
> */
> struct cxl_fmapi_port_state_info_block {
> uint8_t port_id;
> uint8_t config_state;
>- uint8_t connected_device_cxl_version;
>+ uint8_t connected_device_mode;
> uint8_t rsv1;
> uint8_t connected_device_type;
>- uint8_t port_cxl_version_bitmask;
>+ uint8_t supported_cxl_mode_bitmask;
> uint8_t max_link_width;
> uint8_t negotiated_link_width;
> uint8_t supported_link_speeds_vector;
>@@ -623,21 +624,30 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> if (port_dev) { /* DSP */
> PCIDevice *ds_dev = pci_bridge_get_sec_bus(PCI_BRIDGE(port_dev))
> ->devices[0];
>- port->config_state = 3;
>+ port->config_state = CXL_PORT_CONFIG_STATE_DSP;
> if (ds_dev) {
> if (object_dynamic_cast(OBJECT(ds_dev), TYPE_CXL_TYPE3)) {
>- port->connected_device_type = 5; /* Assume MLD for now */
>+ /* Assume MLD for now */
>+ port->connected_device_type =
>+ CXL_PORT_CONNECTED_DEV_TYPE_3_MLD;
> } else {
>- port->connected_device_type = 1;
>+ port->connected_device_type =
>+ CXL_PORT_CONNECTED_DEV_TYPE_PCIE;
>+ port->connected_device_mode =
>+ CXL_PORT_CONNECTED_DEV_MODE_NOT_CXL_OR_DISCONN;
>+
I believe this extra line can be removed here.
> }
> } else {
>- port->connected_device_type = 0;
>+ port->connected_device_type = CXL_PORT_CONNECTED_DEV_TYPE_NONE;
>+ port->connected_device_mode =
>+ CXL_PORT_CONNECTED_DEV_MODE_NOT_CXL_OR_DISCONN;
> }
> port->supported_ld_count = 3;
> } else if (usp->port == in->ports[i]) { /* USP */
> port_dev = PCI_DEVICE(usp);
>- port->config_state = 4;
>- port->connected_device_type = 0;
>+ port->config_state = CXL_PORT_CONFIG_STATE_USP;
>+ port->connected_device_type = 0; /* Reserved for USP */
>+ port->connected_device_mode = 0; /* Reserved for USP */
> } else {
> return CXL_MBOX_INVALID_INPUT;
> }
>@@ -667,8 +677,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> port->ltssm_state = 0x7;
> port->first_lane_num = 0;
> port->link_state = 0;
>- port->port_cxl_version_bitmask = 0x2;
>- port->connected_device_cxl_version = 0x2;
>+ port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH;
> }
>
> pl_size = sizeof(*out) + sizeof(*out->ports) * in->num_ports;
>--
>2.51.0
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH qemu v5 3/3] hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h)
2026-02-04 17:32 ` [PATCH qemu v5 3/3] hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h) Jonathan Cameron
@ 2026-02-12 15:25 ` Arpit Kumar
0 siblings, 0 replies; 10+ messages in thread
From: Arpit Kumar @ 2026-02-12 15:25 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Michael Tsirkin, qemu-devel, linuxarm, linux-cxl, Ravi Shankar,
Marcel Apfelbaum, Michael Roth, Arpit Kumar, cpgs
[-- Attachment #1: Type: text/plain, Size: 12302 bytes --]
On 04/02/26 05:32PM, Jonathan Cameron wrote:
>From: Arpit Kumar <arpit1.kumar@samsung.com>
>
>Added assert-deassert PERST implementation for physical ports (both USP
>and DSP's).
>
>Assert PERST involves bg operation for holding 100ms.
>Reset PPB implementation for physical ports.
>
>Signed-off-by: Arpit Kumar <arpit1.kumar@samsung.com>
>Co-developed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>
>---
>Changes mostly due to dropping refactor that preceeded this in original
>series.
Looks good to me!
>---
> include/hw/cxl/cxl_port.h | 20 +++
> include/hw/pci-bridge/cxl_downstream_port.h | 12 ++
> include/hw/pci-bridge/cxl_upstream_port.h | 2 +
> hw/cxl/cxl-mailbox-utils.c | 130 ++++++++++++++++++++
> hw/pci-bridge/cxl_downstream.c | 9 ++
> hw/pci-bridge/cxl_upstream.c | 1 +
> 6 files changed, 174 insertions(+)
>
>diff --git a/include/hw/cxl/cxl_port.h b/include/hw/cxl/cxl_port.h
>index 04db60f7bc23..fb2e22a9f2ae 100644
>--- a/include/hw/cxl/cxl_port.h
>+++ b/include/hw/cxl/cxl_port.h
>@@ -3,6 +3,8 @@
> #ifndef CXL_PORT_H
> #define CXL_PORT_H
>
>+#include "qemu/thread.h"
>+
> /* CXL r3.2 Table 7-19: Get Physical Port State Port Information Block Format */
> #define CXL_PORT_CONFIG_STATE_DISABLED 0x0
> #define CXL_PORT_CONFIG_STATE_BIND_IN_PROGRESS 0x1
>@@ -50,4 +52,22 @@
> #define CXL_PORT_LINK_STATE_FLAG_PRSNT BIT(2)
> #define CXL_PORT_LINK_STATE_FLAG_POWER_OFF BIT(3)
>
>+#define CXL_MAX_PHY_PORTS 256
>+#define ASSERT_WAIT_TIME_MS 100 /* Assert - Deassert PERST */
>+
>+/* Assert - Deassert PERST */
>+typedef struct CXLPhyPortPerst {
>+ bool issued_assert_perst;
>+ QemuMutex lock; /* protecting assert-deassert reset request */
>+ uint64_t asrt_time;
>+ QemuThread asrt_thread; /* thread for 100ms delay */
>+} CXLPhyPortPerst;
>+
>+void cxl_init_physical_port_control(CXLPhyPortPerst *perst);
>+
>+static inline bool cxl_perst_asserted(CXLPhyPortPerst *perst)
>+{
>+ return perst->issued_assert_perst || perst->asrt_time < ASSERT_WAIT_TIME_MS;
>+}
>+
> #endif /* CXL_PORT_H */
>diff --git a/include/hw/pci-bridge/cxl_downstream_port.h b/include/hw/pci-bridge/cxl_downstream_port.h
>new file mode 100644
>index 000000000000..1611504c8764
>--- /dev/null
>+++ b/include/hw/pci-bridge/cxl_downstream_port.h
>@@ -0,0 +1,12 @@
>+/*
>+ * SPDX-License-Identifier: GPL-2.0-or-later
>+ */
>+
>+#ifndef CXL_DOWNSTREAM_PORT_H
>+#define CXL_DOWNSTREAM_PORT_H
>+#include "include/hw/cxl/cxl_port.h"
>+
>+typedef struct CXLDownstreamPort CXLDownstreamPort;
>+CXLPhyPortPerst *cxl_dsp_get_perst(CXLDownstreamPort *dsp);
>+
>+#endif
>diff --git a/include/hw/pci-bridge/cxl_upstream_port.h b/include/hw/pci-bridge/cxl_upstream_port.h
>index e3d6a27acc86..dfe01771c7d7 100644
>--- a/include/hw/pci-bridge/cxl_upstream_port.h
>+++ b/include/hw/pci-bridge/cxl_upstream_port.h
>@@ -4,6 +4,7 @@
> #include "hw/pci/pcie.h"
> #include "hw/pci/pcie_port.h"
> #include "hw/cxl/cxl.h"
>+#include "hw/cxl/cxl_port.h"
>
> typedef struct CXLUpstreamPort {
> /*< private >*/
>@@ -12,6 +13,7 @@ typedef struct CXLUpstreamPort {
> /*< public >*/
> CXLComponentState cxl_cstate;
> CXLCCI swcci;
>+ CXLPhyPortPerst perst;
>
> PCIExpLinkSpeed speed;
> PCIExpLinkWidth width;
>diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
>index b6ac987ee021..c83b5f90d4d3 100644
>--- a/hw/cxl/cxl-mailbox-utils.c
>+++ b/hw/cxl/cxl-mailbox-utils.c
>@@ -17,6 +17,7 @@
> #include "hw/cxl/cxl_mailbox.h"
> #include "hw/cxl/cxl_port.h"
> #include "hw/pci/pci.h"
>+#include "hw/pci-bridge/cxl_downstream_port.h"
> #include "hw/pci-bridge/cxl_upstream_port.h"
> #include "qemu/cutils.h"
> #include "qemu/host-utils.h"
>@@ -119,6 +120,7 @@ enum {
> PHYSICAL_SWITCH = 0x51,
> #define IDENTIFY_SWITCH_DEVICE 0x0
> #define GET_PHYSICAL_PORT_STATE 0x1
>+ #define PHYSICAL_PORT_CONTROL 0x2
> TUNNEL = 0x53,
> #define MANAGEMENT_COMMAND 0x0
> FMAPI_DCD_MGMT = 0x56,
>@@ -616,6 +618,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> struct cxl_fmapi_port_state_info_block *port;
> /* First try to match on downstream port */
> PCIDevice *port_dev;
>+ CXLPhyPortPerst *perst;
> uint16_t lnkcap, lnkcap2, lnksta;
>
> port = &out->ports[i];
>@@ -663,6 +666,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH |
> CXL_PORT_SUPPORTS_256B;
> port->supported_ld_count = 3;
>+ perst = cxl_dsp_get_perst(CXL_DSP(port_dev));
> } else if (usp->port == in->ports[i]) { /* USP */
> port_dev = PCI_DEVICE(usp);
> port->config_state = CXL_PORT_CONFIG_STATE_USP;
>@@ -670,6 +674,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> port->connected_device_mode = 0; /* Reserved for USP */
> port->supported_cxl_mode_bitmask = CXL_PORT_SUPPORTS_68B_VH |
> (CXL_USP(usp)->flitmode ? CXL_PORT_SUPPORTS_256B : 0);
>+ perst = &CXL_USP(usp)->perst;
> } else {
> return CXL_MBOX_INVALID_INPUT;
> }
>@@ -698,6 +703,7 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> /* TODO: Track down if we can get the rest of the info */
> port->ltssm_state = 0x7;
> port->first_lane_num = 0;
>+ port->link_state = perst ? CXL_PORT_LINK_STATE_FLAG_PERST_ASSERTED : 0;
> }
>
> pl_size = sizeof(*out) + sizeof(*out->ports) * in->num_ports;
>@@ -706,6 +712,115 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> return CXL_MBOX_SUCCESS;
> }
>
>+static void *bg_assertcb(void *opaque)
>+{
>+ CXLPhyPortPerst *perst = opaque;
>+
>+ /* holding reset phase for 100ms */
>+ while (perst->asrt_time--) {
>+ usleep(1000);
>+ }
>+ perst->issued_assert_perst = true;
>+ return NULL;
>+}
>+
>+static CXLRetCode cxl_deassert_perst(Object *obj, CXLPhyPortPerst *perst)
>+{
>+ if (!perst->issued_assert_perst) {
>+ return CXL_MBOX_INTERNAL_ERROR;
>+ }
>+
>+ QEMU_LOCK_GUARD(&perst->lock);
>+ resettable_release_reset(obj, RESET_TYPE_COLD);
>+ perst->issued_assert_perst = false;
>+ perst->asrt_time = ASSERT_WAIT_TIME_MS;
>+
>+ return CXL_MBOX_SUCCESS;
>+}
>+
>+static CXLRetCode cxl_assert_perst(Object *obj, CXLPhyPortPerst *perst)
>+{
>+ if (cxl_perst_asserted(perst)) {
>+ return CXL_MBOX_INTERNAL_ERROR;
>+ }
>+
>+ QEMU_LOCK_GUARD(&perst->lock);
>+ resettable_assert_reset(obj, RESET_TYPE_COLD);
>+ qemu_thread_create(&perst->asrt_thread, "assert_thread", bg_assertcb,
>+ perst, QEMU_THREAD_DETACHED);
>+
>+ return CXL_MBOX_SUCCESS;
>+}
>+
>+static CXLDownstreamPort *cxl_find_dsp_on_bus(PCIBus *bus, uint8_t pn)
>+{
>+
>+ PCIDevice *port_dev = pcie_find_port_by_pn(bus, pn);
>+
>+ if (object_dynamic_cast(OBJECT(port_dev), TYPE_CXL_DSP)) {
>+ return CXL_DSP(port_dev);
>+ }
>+
>+ return NULL;
>+}
>+
>+/* CXL r3.2 Section 7.6.7.1.3: Get Physical Port Control (Opcode 5102h) */
>+static CXLRetCode cmd_physical_port_control(const struct cxl_cmd *cmd,
>+ uint8_t *payload_in,
>+ size_t len_in,
>+ uint8_t *payload_out,
>+ size_t *len_out,
>+ CXLCCI *cci)
>+{
>+ CXLUpstreamPort *pp = CXL_USP(cci->d);
>+ CXLPhyPortPerst *perst;
>+ PCIDevice *dev;
>+
>+ struct cxl_fmapi_get_physical_port_control_req_pl {
>+ uint8_t ppb_id;
>+ uint8_t ports_op;
>+ } QEMU_PACKED *in = (void *)payload_in;
>+
>+ if (len_in < sizeof(*in)) {
>+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
>+ }
>+
>+ if (PCIE_PORT(pp)->port == in->ppb_id) {
>+ dev = PCI_DEVICE(pp);
>+ perst = &pp->perst;
>+ } else {
>+ CXLDownstreamPort *dsp =
>+ cxl_find_dsp_on_bus(&PCI_BRIDGE(pp)->sec_bus, in->ppb_id);
>+
>+ if (!dsp) {
>+ return CXL_MBOX_INVALID_INPUT;
>+ }
>+ dev = PCI_DEVICE(dsp);
>+ perst = cxl_dsp_get_perst(dsp);
>+ }
>+
>+ switch (in->ports_op) {
>+ case 0:
>+ return cxl_assert_perst(OBJECT(&dev->qdev), perst);
>+ case 1:
>+ return cxl_deassert_perst(OBJECT(&dev->qdev), perst);
>+ case 2: {
>+ if (!perst) {
>+ return CXL_MBOX_INVALID_INPUT;
>+ }
>+
>+ if (perst->issued_assert_perst ||
>+ perst->asrt_time < ASSERT_WAIT_TIME_MS) {
>+ return CXL_MBOX_INTERNAL_ERROR;
>+ }
>+ device_cold_reset(&dev->qdev);
>+ return CXL_MBOX_SUCCESS;
>+ }
>+ default:
>+ return CXL_MBOX_INVALID_INPUT;
>+ }
>+}
>+
> /* CXL r3.1 Section 8.2.9.1.2: Background Operation Status (Opcode 0002h) */
> static CXLRetCode cmd_infostat_bg_op_sts(const struct cxl_cmd *cmd,
> uint8_t *payload_in,
>@@ -4412,6 +4527,8 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
> cmd_identify_switch_device, 0, 0 },
> [PHYSICAL_SWITCH][GET_PHYSICAL_PORT_STATE] = { "SWITCH_PHYSICAL_PORT_STATS",
> cmd_get_physical_port_state, ~0, 0 },
>+ [PHYSICAL_SWITCH][PHYSICAL_PORT_CONTROL] = { "SWITCH_PHYSICAL_PORT_CONTROL",
>+ cmd_physical_port_control, 2, 0 },
> [TUNNEL][MANAGEMENT_COMMAND] = { "TUNNEL_MANAGEMENT_COMMAND",
> cmd_tunnel_management_cmd, ~0, 0 },
> };
>@@ -4618,6 +4735,19 @@ static void cxl_rebuild_cel(CXLCCI *cci)
> }
> }
>
>+void cxl_init_physical_port_control(CXLPhyPortPerst *perst)
>+{
>+ qemu_mutex_init(&perst->lock);
>+ perst->issued_assert_perst = false;
>+ /*
>+ * Assert PERST involves physical port to be in
>+ * hold reset phase for minimum 100ms. No other
>+ * physical port control requests are entertained
>+ * until Deassert PERST command.
>+ */
>+ perst->asrt_time = ASSERT_WAIT_TIME_MS;
>+}
>+
> void cxl_init_cci(CXLCCI *cci, size_t payload_max)
> {
> cci->payload_max = payload_max;
>diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
>index 320818a8f1ce..ec450d1aa09e 100644
>--- a/hw/pci-bridge/cxl_downstream.c
>+++ b/hw/pci-bridge/cxl_downstream.c
>@@ -13,9 +13,11 @@
> #include "hw/pci/msi.h"
> #include "hw/pci/pcie.h"
> #include "hw/pci/pcie_port.h"
>+#include "hw/pci-bridge/cxl_downstream_port.h"
> #include "hw/core/qdev-properties.h"
> #include "hw/core/qdev-properties-system.h"
> #include "hw/cxl/cxl.h"
>+#include "hw/cxl/cxl_port.h"
> #include "qapi/error.h"
>
> typedef struct CXLDownstreamPort {
>@@ -24,6 +26,7 @@ typedef struct CXLDownstreamPort {
>
> /*< public >*/
> CXLComponentState cxl_cstate;
>+ CXLPhyPortPerst perst;
> } CXLDownstreamPort;
>
> #define CXL_DOWNSTREAM_PORT_MSI_OFFSET 0x70
>@@ -81,6 +84,11 @@ static void cxl_dsp_config_write(PCIDevice *d, uint32_t address,
> cxl_dsp_dvsec_write_config(d, address, val, len);
> }
>
>+CXLPhyPortPerst *cxl_dsp_get_perst(CXLDownstreamPort *dsp)
>+{
>+ return &dsp->perst;
>+}
>+
> static void cxl_dsp_reset(DeviceState *qdev)
> {
> PCIDevice *d = PCI_DEVICE(qdev);
>@@ -92,6 +100,7 @@ static void cxl_dsp_reset(DeviceState *qdev)
> pci_bridge_reset(qdev);
>
> latch_registers(dsp);
>+ cxl_init_physical_port_control(&dsp->perst);
> }
>
> static void build_dvsecs(PCIDevice *d, CXLComponentState *cxl)
>diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
>index fb8d19539c9f..b6281cbd4cb0 100644
>--- a/hw/pci-bridge/cxl_upstream.c
>+++ b/hw/pci-bridge/cxl_upstream.c
>@@ -103,6 +103,7 @@ static void cxl_usp_reset(DeviceState *qdev)
> pcie_cap_deverr_reset(d);
> pcie_cap_fill_link_ep_usp(d, usp->width, usp->speed, usp->flitmode);
> latch_registers(usp);
>+ cxl_init_physical_port_control(&usp->perst);
> }
>
> static void build_dvsecs(CXLUpstreamPort *usp)
>--
>2.51.0
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support.
2026-02-04 17:32 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Jonathan Cameron
` (3 preceding siblings ...)
2026-02-12 15:12 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Arpit Kumar
@ 2026-02-20 12:58 ` Michael S. Tsirkin
2026-02-23 11:01 ` Jonathan Cameron
4 siblings, 1 reply; 10+ messages in thread
From: Michael S. Tsirkin @ 2026-02-20 12:58 UTC (permalink / raw)
To: Jonathan Cameron
Cc: qemu-devel, Arpit Kumar, linuxarm, linux-cxl, Ravi Shankar,
Marcel Apfelbaum, Michael Roth
On Wed, Feb 04, 2026 at 05:32:20PM +0000, Jonathan Cameron wrote:
> Changes since v4:
> https://lore.kernel.org/qemu-devel/20250916080736.1266083-1-arpit1.kumar@samsung.com/
> - Dropped initial refactor. Reason being that it is not static enough
> for caching at boot to be appropriate. Kept the spec update part
> of this.
> - Added a patch to make sure the new flip mode stuff is reported in
> the Get Physical Port State command.
> - Rebased Arpit's Physical Control Control FMAPI Command given drop
> of the major refactor from v4 patch 1.
>
> I had taken this into my cxl staging tree thinking it only needed a few
> minor tweaks. Then whilst testing I realized it didn't work with hotplug
> and that made me consider if Arpit's original approach made sense.
>
> So this is my proposal on how to take this forwards. Note that this is
> not ready for merge (probably) just yet as I'd like Arpit to take a
> look at the changes.
I'd appreciate it if you add rfc in the subject in such cases.
Thanks!
> I went through a version that had major refactors
> to push the logic of building the records to the ports themselves, but
> in the end don't think that brings enough benefits for the complexity.
>
> Based on:
> https://lore.kernel.org/qemu-devel/20260204170936.43959-1-Jonathan.Cameron@huawei.com/T/#t
> (with all it's precursors, though hopefully they will all be in Michael's
> next pull request)
>
> I'll note this is an enormous foot gun as it lets you effectively trigger
> surprise device resets. However, it's only accessible if you are using
> a configuration with the fabric management parts of the CXL emulation.
> For now that is a switch-cci (MCTP over USB support is near the top
> of my list of things to get ready for upstram. I tested this with a
> custom driver and if nothing else it exposed some gaps in Linux's
> ability to rescan PCI buses after a perst event (even with drivers
> unbound etc to make it safe).
>
> Original cover letter:
>
> This patch series refactor existing support for Identify Switch Device
> and Get Physical Port State by utilizing physical ports (USP & DSP)
> information stored during enumeration.
>
> Additionally, it introduces new support for Physical Port Control
> of Physical Switch Command Set as per CXL spec r3.2 Section 7.6.7.1.3.
> It primarily constitutes two logic:
> -Assert-Deassert PERST: Assert PERST involves physical port to be in
> hold reset phase for minimum 100ms. No other physical port control
> request are entertained until Deassert PERST command for the given
> port is issued.
> -Reset PPB: cold reset of physical port (completing enter->hold->exit
> phases).
>
> Tested using libcxl-mi interface[1]:
> All active ports and all opcodes per active port is tested. Also, tested
> against possible edge cases manually since the interface currently dosen't
> support run time input.
>
> Typical Qemu topology
> (1 USP + 3 DSP's in a switch with 2 CXLType3 devices connected to the 2 DSP's):
> FM="-object memory-backend-file,id=cxl-mem1,mem-path=$TMP_DIR/t3_cxl1.raw,size=256M \
> -object memory-backend-file,id=cxl-lsa1,mem-path=$TMP_DIR/t3_lsa1.raw,size=1M \
> -object memory-backend-file,id=cxl-mem2,mem-path=$TMP_DIR/t3_cxl2.raw,size=512M \
> -object memory-backend-file,id=cxl-lsa2,mem-path=$TMP_DIR/t3_lsa2.raw,size=512M \
> -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1,hdm_for_passthrough=true \
> -device cxl-rp,port=0,bus=cxl.1,id=cxl_rp_port0,chassis=0,slot=2 \
> -device cxl-upstream,port=2,sn=1234,bus=cxl_rp_port0,id=us0,addr=0.0,multifunction=on, \
> -device cxl-switch-mailbox-cci,bus=cxl_rp_port0,addr=0.1,target=us0 \
> -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
> -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
> -device cxl-downstream,port=3,bus=us0,id=swport2,chassis=0,slot=6 \
> -device cxl-type3,bus=swport0,memdev=cxl-mem1,id=cxl-pmem1,lsa=cxl-lsa1,sn=3 \
> -device cxl-type3,bus=swport2,memdev=cxl-mem2,id=cxl-pmem2,lsa=cxl-lsa2,sn=4 \
> -machine cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=1k \
> -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=4,target=us0 \
> -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=5,target=cxl-pmem1 \
> -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=6,target=cxl-pmem2 \
> -device virtio-rng-pci,bus=swport1"
>
> Tested multiple Qemu topologies:
> -without any devices connected to downstream ports.
> -with virtio-rng-pci devices connected to downstream ports.
> -with CXLType3 devices connected to downstream ports.
> -with different unique values of ports (both upstream and downstream).
>
> Changes from v3 (https://lore.kernel.org/qemu-devel/20250909160316.00000190@huawei.com/T/):
> -Namespaced the defines with cleaner prefix for Get Physical Port State
> Port Information Block members.
> -switch CCI implementation instead of switch FM interface as per
> Jonathan's review comments, hence moved perst members initializations
> from: cxl_initialize_usp_mctpcci() -> cxl_initialize_mailbox_swcci().
>
> [1] https://github.com/computexpresslink/libcxlmi/commit/35fe68bd9a31469f832a87694d7b18d2d50be5b8
>
>
> Arpit Kumar (2):
> hw/cxl: Physical Port Info FMAPI - update to current spec and add
> defines.
> hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h)
>
> Jonathan Cameron (1):
> hw/cxl: Get Physical Port State - update for PCIe flit mode
>
> include/hw/cxl/cxl_port.h | 73 ++++++++
> include/hw/pci-bridge/cxl_downstream_port.h | 12 ++
> include/hw/pci-bridge/cxl_upstream_port.h | 2 +
> hw/cxl/cxl-mailbox-utils.c | 183 ++++++++++++++++++--
> hw/pci-bridge/cxl_downstream.c | 9 +
> hw/pci-bridge/cxl_upstream.c | 1 +
> 6 files changed, 268 insertions(+), 12 deletions(-)
> create mode 100644 include/hw/cxl/cxl_port.h
> create mode 100644 include/hw/pci-bridge/cxl_downstream_port.h
>
> --
> 2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support.
2026-02-20 12:58 ` Michael S. Tsirkin
@ 2026-02-23 11:01 ` Jonathan Cameron
2026-02-23 11:28 ` Jonathan Cameron
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Cameron @ 2026-02-23 11:01 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: qemu-devel, Arpit Kumar, linuxarm, linux-cxl, Ravi Shankar,
Marcel Apfelbaum, Michael Roth
On Fri, 20 Feb 2026 07:58:49 -0500
"Michael S. Tsirkin" <mst@redhat.com> wrote:
> On Wed, Feb 04, 2026 at 05:32:20PM +0000, Jonathan Cameron wrote:
> > Changes since v4:
> > https://lore.kernel.org/qemu-devel/20250916080736.1266083-1-arpit1.kumar@samsung.com/
> > - Dropped initial refactor. Reason being that it is not static enough
> > for caching at boot to be appropriate. Kept the spec update part
> > of this.
> > - Added a patch to make sure the new flip mode stuff is reported in
> > the Get Physical Port State command.
> > - Rebased Arpit's Physical Control Control FMAPI Command given drop
> > of the major refactor from v4 patch 1.
> >
> > I had taken this into my cxl staging tree thinking it only needed a few
> > minor tweaks. Then whilst testing I realized it didn't work with hotplug
> > and that made me consider if Arpit's original approach made sense.
> >
> > So this is my proposal on how to take this forwards. Note that this is
> > not ready for merge (probably) just yet as I'd like Arpit to take a
> > look at the changes.
>
> I'd appreciate it if you add rfc in the subject in such cases.
> Thanks!
Will do.
Arpit is happy with this, so now I think main thing it needs is review of the
PCI interactions and the resets. They seem fine to me but I'm not that
familiar with that stuff so am relying on PCI / reset experts.
That part is all in patch 3. If you are happy with that part, then I'm
very much in favor of merging this.
Jonathan
>
> > I went through a version that had major refactors
> > to push the logic of building the records to the ports themselves, but
> > in the end don't think that brings enough benefits for the complexity.
> >
> > Based on:
> > https://lore.kernel.org/qemu-devel/20260204170936.43959-1-Jonathan.Cameron@huawei.com/T/#t
> > (with all it's precursors, though hopefully they will all be in Michael's
> > next pull request)
> >
> > I'll note this is an enormous foot gun as it lets you effectively trigger
> > surprise device resets. However, it's only accessible if you are using
> > a configuration with the fabric management parts of the CXL emulation.
> > For now that is a switch-cci (MCTP over USB support is near the top
> > of my list of things to get ready for upstram. I tested this with a
> > custom driver and if nothing else it exposed some gaps in Linux's
> > ability to rescan PCI buses after a perst event (even with drivers
> > unbound etc to make it safe).
> >
> > Original cover letter:
> >
> > This patch series refactor existing support for Identify Switch Device
> > and Get Physical Port State by utilizing physical ports (USP & DSP)
> > information stored during enumeration.
> >
> > Additionally, it introduces new support for Physical Port Control
> > of Physical Switch Command Set as per CXL spec r3.2 Section 7.6.7.1.3.
> > It primarily constitutes two logic:
> > -Assert-Deassert PERST: Assert PERST involves physical port to be in
> > hold reset phase for minimum 100ms. No other physical port control
> > request are entertained until Deassert PERST command for the given
> > port is issued.
> > -Reset PPB: cold reset of physical port (completing enter->hold->exit
> > phases).
> >
> > Tested using libcxl-mi interface[1]:
> > All active ports and all opcodes per active port is tested. Also, tested
> > against possible edge cases manually since the interface currently dosen't
> > support run time input.
> >
> > Typical Qemu topology
> > (1 USP + 3 DSP's in a switch with 2 CXLType3 devices connected to the 2 DSP's):
> > FM="-object memory-backend-file,id=cxl-mem1,mem-path=$TMP_DIR/t3_cxl1.raw,size=256M \
> > -object memory-backend-file,id=cxl-lsa1,mem-path=$TMP_DIR/t3_lsa1.raw,size=1M \
> > -object memory-backend-file,id=cxl-mem2,mem-path=$TMP_DIR/t3_cxl2.raw,size=512M \
> > -object memory-backend-file,id=cxl-lsa2,mem-path=$TMP_DIR/t3_lsa2.raw,size=512M \
> > -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1,hdm_for_passthrough=true \
> > -device cxl-rp,port=0,bus=cxl.1,id=cxl_rp_port0,chassis=0,slot=2 \
> > -device cxl-upstream,port=2,sn=1234,bus=cxl_rp_port0,id=us0,addr=0.0,multifunction=on, \
> > -device cxl-switch-mailbox-cci,bus=cxl_rp_port0,addr=0.1,target=us0 \
> > -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
> > -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
> > -device cxl-downstream,port=3,bus=us0,id=swport2,chassis=0,slot=6 \
> > -device cxl-type3,bus=swport0,memdev=cxl-mem1,id=cxl-pmem1,lsa=cxl-lsa1,sn=3 \
> > -device cxl-type3,bus=swport2,memdev=cxl-mem2,id=cxl-pmem2,lsa=cxl-lsa2,sn=4 \
> > -machine cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=1k \
> > -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=4,target=us0 \
> > -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=5,target=cxl-pmem1 \
> > -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=6,target=cxl-pmem2 \
> > -device virtio-rng-pci,bus=swport1"
> >
> > Tested multiple Qemu topologies:
> > -without any devices connected to downstream ports.
> > -with virtio-rng-pci devices connected to downstream ports.
> > -with CXLType3 devices connected to downstream ports.
> > -with different unique values of ports (both upstream and downstream).
> >
> > Changes from v3 (https://lore.kernel.org/qemu-devel/20250909160316.00000190@huawei.com/T/):
> > -Namespaced the defines with cleaner prefix for Get Physical Port State
> > Port Information Block members.
> > -switch CCI implementation instead of switch FM interface as per
> > Jonathan's review comments, hence moved perst members initializations
> > from: cxl_initialize_usp_mctpcci() -> cxl_initialize_mailbox_swcci().
> >
> > [1] https://github.com/computexpresslink/libcxlmi/commit/35fe68bd9a31469f832a87694d7b18d2d50be5b8
> >
> >
> > Arpit Kumar (2):
> > hw/cxl: Physical Port Info FMAPI - update to current spec and add
> > defines.
> > hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h)
> >
> > Jonathan Cameron (1):
> > hw/cxl: Get Physical Port State - update for PCIe flit mode
> >
> > include/hw/cxl/cxl_port.h | 73 ++++++++
> > include/hw/pci-bridge/cxl_downstream_port.h | 12 ++
> > include/hw/pci-bridge/cxl_upstream_port.h | 2 +
> > hw/cxl/cxl-mailbox-utils.c | 183 ++++++++++++++++++--
> > hw/pci-bridge/cxl_downstream.c | 9 +
> > hw/pci-bridge/cxl_upstream.c | 1 +
> > 6 files changed, 268 insertions(+), 12 deletions(-)
> > create mode 100644 include/hw/cxl/cxl_port.h
> > create mode 100644 include/hw/pci-bridge/cxl_downstream_port.h
> >
> > --
> > 2.51.0
>
>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support.
2026-02-23 11:01 ` Jonathan Cameron
@ 2026-02-23 11:28 ` Jonathan Cameron
0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Cameron @ 2026-02-23 11:28 UTC (permalink / raw)
To: Jonathan Cameron via qemu development
Cc: Jonathan Cameron, Michael S. Tsirkin, Arpit Kumar, linuxarm,
linux-cxl, Ravi Shankar, Marcel Apfelbaum, Michael Roth
On Mon, 23 Feb 2026 11:01:09 +0000
Jonathan Cameron via qemu development <qemu-devel@nongnu.org> wrote:
> On Fri, 20 Feb 2026 07:58:49 -0500
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
>
> > On Wed, Feb 04, 2026 at 05:32:20PM +0000, Jonathan Cameron wrote:
> > > Changes since v4:
> > > https://lore.kernel.org/qemu-devel/20250916080736.1266083-1-arpit1.kumar@samsung.com/
> > > - Dropped initial refactor. Reason being that it is not static enough
> > > for caching at boot to be appropriate. Kept the spec update part
> > > of this.
> > > - Added a patch to make sure the new flip mode stuff is reported in
> > > the Get Physical Port State command.
> > > - Rebased Arpit's Physical Control Control FMAPI Command given drop
> > > of the major refactor from v4 patch 1.
> > >
> > > I had taken this into my cxl staging tree thinking it only needed a few
> > > minor tweaks. Then whilst testing I realized it didn't work with hotplug
> > > and that made me consider if Arpit's original approach made sense.
> > >
> > > So this is my proposal on how to take this forwards. Note that this is
> > > not ready for merge (probably) just yet as I'd like Arpit to take a
> > > look at the changes.
> >
> > I'd appreciate it if you add rfc in the subject in such cases.
> > Thanks!
>
> Will do.
>
> Arpit is happy with this, so now I think main thing it needs is review of the
> PCI interactions and the resets. They seem fine to me but I'm not that
> familiar with that stuff so am relying on PCI / reset experts.
>
> That part is all in patch 3. If you are happy with that part, then I'm
> very much in favor of merging this.
I caught up with rest of the list and see this was in your pull request.
All good then!
Thanks,
Jonathan
>
> Jonathan
>
> >
> > > I went through a version that had major refactors
> > > to push the logic of building the records to the ports themselves, but
> > > in the end don't think that brings enough benefits for the complexity.
> > >
> > > Based on:
> > > https://lore.kernel.org/qemu-devel/20260204170936.43959-1-Jonathan.Cameron@huawei.com/T/#t
> > > (with all it's precursors, though hopefully they will all be in Michael's
> > > next pull request)
> > >
> > > I'll note this is an enormous foot gun as it lets you effectively trigger
> > > surprise device resets. However, it's only accessible if you are using
> > > a configuration with the fabric management parts of the CXL emulation.
> > > For now that is a switch-cci (MCTP over USB support is near the top
> > > of my list of things to get ready for upstram. I tested this with a
> > > custom driver and if nothing else it exposed some gaps in Linux's
> > > ability to rescan PCI buses after a perst event (even with drivers
> > > unbound etc to make it safe).
> > >
> > > Original cover letter:
> > >
> > > This patch series refactor existing support for Identify Switch Device
> > > and Get Physical Port State by utilizing physical ports (USP & DSP)
> > > information stored during enumeration.
> > >
> > > Additionally, it introduces new support for Physical Port Control
> > > of Physical Switch Command Set as per CXL spec r3.2 Section 7.6.7.1.3.
> > > It primarily constitutes two logic:
> > > -Assert-Deassert PERST: Assert PERST involves physical port to be in
> > > hold reset phase for minimum 100ms. No other physical port control
> > > request are entertained until Deassert PERST command for the given
> > > port is issued.
> > > -Reset PPB: cold reset of physical port (completing enter->hold->exit
> > > phases).
> > >
> > > Tested using libcxl-mi interface[1]:
> > > All active ports and all opcodes per active port is tested. Also, tested
> > > against possible edge cases manually since the interface currently dosen't
> > > support run time input.
> > >
> > > Typical Qemu topology
> > > (1 USP + 3 DSP's in a switch with 2 CXLType3 devices connected to the 2 DSP's):
> > > FM="-object memory-backend-file,id=cxl-mem1,mem-path=$TMP_DIR/t3_cxl1.raw,size=256M \
> > > -object memory-backend-file,id=cxl-lsa1,mem-path=$TMP_DIR/t3_lsa1.raw,size=1M \
> > > -object memory-backend-file,id=cxl-mem2,mem-path=$TMP_DIR/t3_cxl2.raw,size=512M \
> > > -object memory-backend-file,id=cxl-lsa2,mem-path=$TMP_DIR/t3_lsa2.raw,size=512M \
> > > -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1,hdm_for_passthrough=true \
> > > -device cxl-rp,port=0,bus=cxl.1,id=cxl_rp_port0,chassis=0,slot=2 \
> > > -device cxl-upstream,port=2,sn=1234,bus=cxl_rp_port0,id=us0,addr=0.0,multifunction=on, \
> > > -device cxl-switch-mailbox-cci,bus=cxl_rp_port0,addr=0.1,target=us0 \
> > > -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
> > > -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
> > > -device cxl-downstream,port=3,bus=us0,id=swport2,chassis=0,slot=6 \
> > > -device cxl-type3,bus=swport0,memdev=cxl-mem1,id=cxl-pmem1,lsa=cxl-lsa1,sn=3 \
> > > -device cxl-type3,bus=swport2,memdev=cxl-mem2,id=cxl-pmem2,lsa=cxl-lsa2,sn=4 \
> > > -machine cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=1k \
> > > -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=4,target=us0 \
> > > -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=5,target=cxl-pmem1 \
> > > -device i2c_mctp_cxl,bus=aspeed.i2c.bus.0,address=6,target=cxl-pmem2 \
> > > -device virtio-rng-pci,bus=swport1"
> > >
> > > Tested multiple Qemu topologies:
> > > -without any devices connected to downstream ports.
> > > -with virtio-rng-pci devices connected to downstream ports.
> > > -with CXLType3 devices connected to downstream ports.
> > > -with different unique values of ports (both upstream and downstream).
> > >
> > > Changes from v3 (https://lore.kernel.org/qemu-devel/20250909160316.00000190@huawei.com/T/):
> > > -Namespaced the defines with cleaner prefix for Get Physical Port State
> > > Port Information Block members.
> > > -switch CCI implementation instead of switch FM interface as per
> > > Jonathan's review comments, hence moved perst members initializations
> > > from: cxl_initialize_usp_mctpcci() -> cxl_initialize_mailbox_swcci().
> > >
> > > [1] https://github.com/computexpresslink/libcxlmi/commit/35fe68bd9a31469f832a87694d7b18d2d50be5b8
> > >
> > >
> > > Arpit Kumar (2):
> > > hw/cxl: Physical Port Info FMAPI - update to current spec and add
> > > defines.
> > > hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h)
> > >
> > > Jonathan Cameron (1):
> > > hw/cxl: Get Physical Port State - update for PCIe flit mode
> > >
> > > include/hw/cxl/cxl_port.h | 73 ++++++++
> > > include/hw/pci-bridge/cxl_downstream_port.h | 12 ++
> > > include/hw/pci-bridge/cxl_upstream_port.h | 2 +
> > > hw/cxl/cxl-mailbox-utils.c | 183 ++++++++++++++++++--
> > > hw/pci-bridge/cxl_downstream.c | 9 +
> > > hw/pci-bridge/cxl_upstream.c | 1 +
> > > 6 files changed, 268 insertions(+), 12 deletions(-)
> > > create mode 100644 include/hw/cxl/cxl_port.h
> > > create mode 100644 include/hw/pci-bridge/cxl_downstream_port.h
> > >
> > > --
> > > 2.51.0
> >
> >
> >
>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-02-23 11:28 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <CGME20260212151259epcas5p2364104fe9a48c7673863df040dacbfef@epcas5p2.samsung.com>
2026-02-04 17:32 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Jonathan Cameron
2026-02-04 17:32 ` [PATCH qemu v5 1/3] hw/cxl: Physical Port Info FMAPI - update to current spec and add defines Jonathan Cameron
2026-02-12 15:22 ` Arpit Kumar
2026-02-04 17:32 ` [PATCH qemu v5 2/3] hw/cxl: Get Physical Port State - update for PCIe flit mode Jonathan Cameron
2026-02-04 17:32 ` [PATCH qemu v5 3/3] hw/cxl: Add Physical Port Control FMAPI Command (Opcode 5102h) Jonathan Cameron
2026-02-12 15:25 ` Arpit Kumar
2026-02-12 15:12 ` [PATCH qemu v5 0/3] hw/cxl: FM-API Physical Switch Command Set Support Arpit Kumar
2026-02-20 12:58 ` Michael S. Tsirkin
2026-02-23 11:01 ` Jonathan Cameron
2026-02-23 11:28 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox