Commit be7ce15d35 for qemu.org

commit be7ce15d350bad8ca636921448807b562bfa47c0
Author: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Date:   Wed Feb 4 17:32:22 2026 +0000

    hw/cxl: Get Physical Port State - update for PCIe flit mode

    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>
    Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
    Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
    Message-Id: <20260204173223.44122-3-Jonathan.Cameron@huawei.com>

diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 1c8cbe0f68..b6ac987ee0 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;