All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH qemu v1 1/8] hw/pci: Refactor flitmode from PCIESlot to PCIEPort
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
@ 2026-11-04 11:52   ` Shrihari E S
  2026-11-04 11:52   ` [PATCH qemu v1 2/8] hw/pci: Move 'x-256b-flit' property from cxl_root_port to pcie_root_port Shrihari E S
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Move the 'flitmode' field from PCIESlot to its parent PCIEPort so
that all the derived port types carry the 256-byte flit mode state
in a single field. The 'x-256b-flit' property defaults to off on
all the port types.

The x-256b-flit property is based on a patch series from Davidlohr
Bueso that adds flit mode signaling for CXL ports[1].

[1]: https://lore.kernel.org/all/20251103195209.1319917-2-dave@stgolabs.net/

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
---
 hw/pci-bridge/cxl_downstream.c            |  6 +++---
 hw/pci-bridge/cxl_root_port.c             |  6 +++---
 hw/pci-bridge/cxl_upstream.c              | 11 +++++++----
 hw/pci/pcie.c                             |  2 +-
 include/hw/pci-bridge/cxl_upstream_port.h |  1 -
 include/hw/pci/pcie_port.h                |  2 +-
 6 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index d1e27994a3..134b91220a 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -118,7 +118,7 @@ static void cxl_dsp_reset(DeviceState *qdev)
 
 static void build_dvsecs(PCIDevice *d, CXLComponentState *cxl)
 {
-    PCIESlot *s = PCIE_SLOT(d);
+    PCIEPort *p = PCIE_PORT(d);
     CXLDVSECRegisterLocator *regloc_dvsec;
     uint8_t *dvsec;
     int i;
@@ -132,7 +132,7 @@ static void build_dvsecs(PCIDevice *d, CXLComponentState *cxl)
     dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){
         .cap                     = 0x27, /* Cache, IO, Mem, non-MLD */
         .ctrl                    = 0x02, /* IO always enabled */
-        .status                  = s->flitmode ? 0x6 : 0x26, /* lack of 68B */
+        .status                  = p->flitmode ? 0x6 : 0x26, /* lack of 68B */
         .rcvd_mod_ts_data_phase1 = 0xef, /* WTF? */
     };
     cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT,
@@ -259,7 +259,7 @@ static const Property cxl_dsp_props[] = {
                                 speed, PCIE_LINK_SPEED_64),
     DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
                                 width, PCIE_LINK_WIDTH_16),
-    DEFINE_PROP_BOOL("x-256b-flit", PCIESlot, flitmode, true),
+    DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
 };
 
 static void cxl_dsp_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index 0ee18ef5c3..01463dbb07 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -112,7 +112,7 @@ static void latch_registers(CXLRootPort *crp)
 
 static void build_dvsecs(PCIDevice *d, CXLComponentState *cxl)
 {
-    PCIESlot *s = PCIE_SLOT(d);
+    PCIEPort *p = PCIE_PORT(d);
     CXLDVSECRegisterLocator *regloc_dvsec;
     uint8_t *dvsec;
     int i;
@@ -135,7 +135,7 @@ static void build_dvsecs(PCIDevice *d, CXLComponentState *cxl)
     dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){
         .cap                     = 0x26, /* IO, Mem, non-MLD */
         .ctrl                    = 0x2,
-        .status                  = s->flitmode ? 0x6 : 0x26, /* lack of 68B */
+        .status                  = p->flitmode ? 0x6 : 0x26, /* lack of 68B */
         .rcvd_mod_ts_data_phase1 = 0xef,
     };
     cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,
@@ -237,7 +237,7 @@ static const Property gen_rp_props[] = {
                                 speed, PCIE_LINK_SPEED_64),
     DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
                                 width, PCIE_LINK_WIDTH_32),
-    DEFINE_PROP_BOOL("x-256b-flit", PCIESlot, flitmode, true),
+    DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
 };
 
 static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr,
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index ef5480b116..0b1fa9594b 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -136,7 +136,8 @@ static void latch_registers(CXLUpstreamPort *usp)
     uint32_t *write_msk = usp->cxl_cstate.crb.cache_mem_regs_write_mask;
 
     cxl_component_register_init_common(reg_state, write_msk,
-                                       CXL2_UPSTREAM_PORT, usp->flitmode);
+                                       CXL2_UPSTREAM_PORT,
+                                       PCIE_PORT(usp)->flitmode);
     ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8);
 }
 
@@ -147,7 +148,8 @@ static void cxl_usp_reset(DeviceState *qdev)
 
     pci_bridge_reset(qdev);
     pcie_cap_deverr_reset(d);
-    pcie_cap_fill_link_ep_usp(d, usp->width, usp->speed, usp->flitmode);
+    pcie_cap_fill_link_ep_usp(d, usp->width, usp->speed,
+                              PCIE_PORT(usp)->flitmode);
     latch_registers(usp);
 }
 
@@ -168,7 +170,8 @@ static void build_dvsecs(CXLUpstreamPort *usp)
     dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){
         .cap                     = 0x27, /* Cache, IO, Mem, non-MLD */
         .ctrl                    = 0x27, /* Cache, IO, Mem */
-        .status                  = usp->flitmode ? 0x6 : 0x26, /* lack of 68B */
+        .status                  = PCIE_PORT(usp)->flitmode ?
+                                  0x6 : 0x26, /* lack of 68B */
         .rcvd_mod_ts_data_phase1 = 0xef, /* WTF? */
     };
     cxl_component_create_dvsec(cxl_cstate, CXL2_UPSTREAM_PORT,
@@ -436,7 +439,7 @@ static const Property cxl_upstream_props[] = {
                                 speed, PCIE_LINK_SPEED_32),
     DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLUpstreamPort,
                                 width, PCIE_LINK_WIDTH_16),
-    DEFINE_PROP_BOOL("x-256b-flit", CXLUpstreamPort, flitmode, false),
+    DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
 };
 
 static void cxl_upstream_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 1de0b1e4fd..4f6fc9db61 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -217,7 +217,7 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
         /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */
     }
 
-    pcie_cap_fill_lnk(exp_cap, s->width, s->speed, s->flitmode);
+    pcie_cap_fill_lnk(exp_cap, s->width, s->speed, PCIE_PORT(s)->flitmode);
 }
 
 int pcie_cap_init(PCIDevice *dev, uint8_t offset,
diff --git a/include/hw/pci-bridge/cxl_upstream_port.h b/include/hw/pci-bridge/cxl_upstream_port.h
index d4186234c8..e8f5e43faf 100644
--- a/include/hw/pci-bridge/cxl_upstream_port.h
+++ b/include/hw/pci-bridge/cxl_upstream_port.h
@@ -21,7 +21,6 @@ typedef struct CXLUpstreamPort {
 
     PCIExpLinkSpeed speed;
     PCIExpLinkWidth width;
-    bool flitmode;
 
     DOECap doe_cdat;
     uint64_t sn;
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index 53cd64c5ed..1bcc734649 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -33,6 +33,7 @@ struct PCIEPort {
     /*< private >*/
     PCIBridge   parent_obj;
     /*< public >*/
+    bool flitmode;
 
     /* pci express switch port */
     uint8_t     port;
@@ -58,7 +59,6 @@ struct PCIESlot {
 
     PCIExpLinkSpeed speed;
     PCIExpLinkWidth width;
-    bool flitmode;
 
     /* Disable ACS (really for a pcie_root_port) */
     bool        disable_acs;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH qemu v1 2/8] hw/pci: Move 'x-256b-flit' property from cxl_root_port to pcie_root_port
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
  2026-11-04 11:52   ` [PATCH qemu v1 1/8] hw/pci: Refactor flitmode from PCIESlot to PCIEPort Shrihari E S
@ 2026-11-04 11:52   ` Shrihari E S
  2026-11-04 11:52   ` [PATCH qemu v1 3/8] hw/cxl: Wire UIO capability into HDM decoder and DVSEC registers Shrihari E S
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Relocate the 'x-256b-flit' property from cxl_root_port to its parent
pcie_root_port so that all root port types inherit the property.

The cxl_root_port and cxl_downstream_port no longer carry a local
property definition; the property is inherited from pcie_root_port
and PCIEPort respectively.

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
---
 hw/pci-bridge/cxl_root_port.c  | 1 -
 hw/pci-bridge/pcie_root_port.c | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index 01463dbb07..e82685d1ab 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -237,7 +237,6 @@ static const Property gen_rp_props[] = {
                                 speed, PCIE_LINK_SPEED_64),
     DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
                                 width, PCIE_LINK_WIDTH_32),
-    DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
 };
 
 static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr,
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index fe3ced5685..bc173dbf30 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -152,6 +152,7 @@ static const Property rp_props[] = {
     DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
                     QEMU_PCIE_SLTCAP_PCP_BITNR, true),
     DEFINE_PROP_BOOL("disable-acs", PCIESlot, disable_acs, false),
+    DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
 };
 
 static void rp_instance_post_init(Object *obj)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH qemu v1 3/8] hw/cxl: Wire UIO capability into HDM decoder and DVSEC registers
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
  2026-11-04 11:52   ` [PATCH qemu v1 1/8] hw/pci: Refactor flitmode from PCIESlot to PCIEPort Shrihari E S
  2026-11-04 11:52   ` [PATCH qemu v1 2/8] hw/pci: Move 'x-256b-flit' property from cxl_root_port to pcie_root_port Shrihari E S
@ 2026-11-04 11:52   ` Shrihari E S
  2026-11-04 17:25     ` Junjie Cao
  2026-11-04 11:52   ` [PATCH qemu v1 4/8] hw/pci: Add PCIe Streamlined Virtual Channel (SVC) capability Shrihari E S
                     ` (4 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Add the UIO Capable bit and the UIO Capable Decoder Count field to
the HDM decoder capability register of the CXL components, and open
the UIO To HDM Enable bit of the Port Extensions DVSEC for the CXL
downstream ports.

Add the x-uio property to the pxb-cxl host bridge. The host bridge
is not a PCIe device in QEMU, so it carries neither the SVC nor the
256-byte flit mode capability itself: the bit gates whether the
root ports within the host bridge advertise UIO, and each root port
validates its own UIO dependent configuration.

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
Signed-off-by: Dongjoo Seo <dongjoo.seo1@samsung.com>
---
 hw/cxl/cxl-component-utils.c              | 55 ++++++++++++++++++++---
 hw/mem/cxl_type3.c                        |  7 ++-
 hw/pci-bridge/cxl_downstream.c            |  2 +-
 hw/pci-bridge/cxl_root_port.c             |  3 +-
 hw/pci-bridge/cxl_upstream.c              |  3 +-
 hw/pci-bridge/pci_expander_bridge.c       | 17 +++++--
 include/hw/cxl/cxl_component.h            |  2 +-
 include/hw/cxl/cxl_device.h               |  1 +
 include/hw/pci-bridge/cxl_upstream_port.h |  1 +
 include/hw/pci/pci_bridge.h               |  1 +
 10 files changed, 78 insertions(+), 14 deletions(-)

diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c
index 31bbedb502..01458104be 100644
--- a/hw/cxl/cxl-component-utils.c
+++ b/hw/cxl/cxl-component-utils.c
@@ -305,7 +305,7 @@ static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk)
 }
 
 static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
-                            enum reg_type type, bool bi)
+                            enum reg_type type, bool bi, bool uio)
 {
     int decoder_count = CXL_HDM_DECODER_COUNT;
     int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO;
@@ -325,9 +325,30 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
         ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 3_6_12_WAY, 0);
         ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 16_WAY, 0);
     }
-    ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, UIO, 0);
+    /*
+     * UIO Capable is enumerated for CXL.mem devices, USPs, CXL root
+     * ports and CXL Host Bridges (CXL 3.2 8.2.4.20.1, Table 8-27).
+     * A root port is the ingress routing point of the Host Bridge
+     * for UIO requests (CXL 3.2 9.16, Table 9-18); CXL downstream
+     * ports do not report the bit. In a Host Bridge the bit means
+     * that all the root ports within the Host Bridge are capable
+     * of routing UIO requests, and each root port signals UIO here
+     * when its own SVC and 256-byte flit mode configuration carries
+     * it.
+     */
+    ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, UIO,
+                     (type == CXL2_TYPE3_DEVICE || type == CXL2_UPSTREAM_PORT
+                     || type == CXL2_ROOT_PORT || type == CXL2_RC) && uio);
+    /*
+     * UIO Capable Decoder Count uses the same encoding as Decoder
+     * Count (CXL 3.2 8.2.4.20.1) and is reserved for CXL.mem devices,
+     * which carry no limit on the number of UIO-capable HDM decoders.
+     */
     ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY,
-                     UIO_DECODER_COUNT, 0);
+                     UIO_DECODER_COUNT,
+                     (type == CXL2_UPSTREAM_PORT || type == CXL2_ROOT_PORT
+                     || type == CXL2_RC)
+                     && uio ? cxl_decoder_count_enc(decoder_count) : 0);
     ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, MEMDATA_NXM_CAP, 0);
     ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY,
                      SUPPORTED_COHERENCY_MODEL,
@@ -342,6 +363,21 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
         write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc] = 0xf0000000;
         write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc] = 0xffffffff;
         write_msk[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc] = 0x13ff;
+        if (uio) {
+            write_msk[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc] |=
+                R_CXL_HDM_DECODER0_CTRL_UIO_MASK;
+            /*
+             * UIG and UIW are RWL for a switch and a Host Bridge if the
+             * UIO Capable bit is set, and reserved for CXL.mem devices
+             * (CXL 3.2 8.2.4.20.7).
+             */
+            if (type == CXL2_UPSTREAM_PORT || type == CXL2_ROOT_PORT ||
+                type == CXL2_RC) {
+                write_msk[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc] |=
+                    R_CXL_HDM_DECODER0_CTRL_UIG_MASK |
+                    R_CXL_HDM_DECODER0_CTRL_UIW_MASK;
+            }
+        }
         if (type == CXL2_DEVICE ||
             type == CXL2_TYPE3_DEVICE ||
             type == CXL2_LOGICAL_DEVICE) {
@@ -391,7 +427,7 @@ static void bi_decoder_init_common(uint32_t *reg_state, uint32_t *write_msk,
 void cxl_component_register_init_common(uint32_t *reg_state,
                                         uint32_t *write_msk,
                                         enum reg_type type,
-                                        bool bi)
+                                        bool bi, bool uio)
 {
     int caps = 0;
 
@@ -431,7 +467,7 @@ void cxl_component_register_init_common(uint32_t *reg_state,
     case CXL2_LOGICAL_DEVICE:
         /* + HDM */
         init_cap_reg(HDM, 5, 1);
-        hdm_init_common(reg_state, write_msk, type, bi);
+        hdm_init_common(reg_state, write_msk, type, bi, uio);
         /* fallthrough */
     case CXL2_DOWNSTREAM_PORT:
     case CXL2_DEVICE:
@@ -523,7 +559,14 @@ void cxl_component_create_dvsec(CXLComponentState *cxl,
     case NON_CXL_FUNCTION_MAP_DVSEC:
         break; /* Not yet implemented */
     case EXTENSIONS_PORT_DVSEC:
-        wmask[offset + offsetof(CXLDVSECPortExt, control)] = 0x0F;
+        /*
+         * Bit 4 of the control register is the UIO To HDM Enable
+         * bit, RW for a downstream port capable of UIO Direct P2P
+         * accesses to HDM and RsvdP for the other port types
+         * (CXL 3.2 8.1.5.2).
+         */
+        wmask[offset + offsetof(CXLDVSECPortExt, control)] =
+            cxl_dev_type == CXL2_DOWNSTREAM_PORT ? 0x1F : 0x0F;
         wmask[offset + offsetof(CXLDVSECPortExt, control) + 1] = 0x40;
         wmask[offset + offsetof(CXLDVSECPortExt, alt_bus_base)] = 0xFF;
         wmask[offset + offsetof(CXLDVSECPortExt, alt_bus_limit)] = 0xFF;
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index b7ad437cbc..778a18ddea 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -590,6 +590,9 @@ static void hdm_decoder_commit(CXLType3Dev *ct3d, int which)
     /* TODO: Sanity checks that the decoder is possible */
     ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, ERR, 0);
     ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED, 1);
+    if (!ct3d->uio_comp_capable) {
+        ctrl = FIELD_DP32(ctrl, CXL_HDM_DECODER0_CTRL, UIO, 0);
+    }
 
     /* Get interleave details for chmu */
     ig = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IG);
@@ -1512,7 +1515,8 @@ void ct3d_reset(DeviceState *dev)
     pcie_cap_fill_link_ep_usp(PCI_DEVICE(dev), ct3d->width, ct3d->speed,
                               ct3d->flitmode);
     cxl_component_register_init_common(reg_state, write_msk,
-                                       CXL2_TYPE3_DEVICE, ct3d->hdmdb);
+                                       CXL2_TYPE3_DEVICE, ct3d->hdmdb,
+                                       ct3d->uio_comp_capable);
     cxl_device_register_init_t3(ct3d, CXL_T3_MSIX_MBOX);
 
     /*
@@ -1552,6 +1556,7 @@ static const Property ct3_props[] = {
                                 width, PCIE_LINK_WIDTH_16),
     DEFINE_PROP_BOOL("x-256b-flit", CXLType3Dev, flitmode, false),
     DEFINE_PROP_BOOL("hdm-db", CXLType3Dev, hdmdb, false),
+    DEFINE_PROP_BOOL("x-uio", CXLType3Dev, uio_comp_capable, false),
     DEFINE_PROP_UINT16("chmu-port", CXLType3Dev, cxl_dstate.chmu[0].port, 0),
 };
 
diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index 134b91220a..bc1e65bc89 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -42,7 +42,7 @@ static void latch_registers(CXLDownstreamPort *dsp)
     uint32_t *write_msk = dsp->cxl_cstate.crb.cache_mem_regs_write_mask;
 
     cxl_component_register_init_common(reg_state, write_msk,
-                                       CXL2_DOWNSTREAM_PORT, true);
+                                       CXL2_DOWNSTREAM_PORT, true, false);
 }
 
 /* TODO: Look at sharing this code across all CXL port types */
diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index e82685d1ab..4be2b400f9 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -53,6 +53,7 @@ typedef struct CXLRootPort {
     CPMUState cpmu;
     MemoryRegion cpmu_registers;
     PCIResReserve res_reserve;
+    bool uio_capable;
 } CXLRootPort;
 
 #define TYPE_CXL_ROOT_PORT "cxl-rp"
@@ -107,7 +108,7 @@ static void latch_registers(CXLRootPort *crp)
     uint32_t *write_msk = crp->cxl_cstate.crb.cache_mem_regs_write_mask;
 
     cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT,
-                                       true);
+                                       true, crp->uio_capable);
 }
 
 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 0b1fa9594b..63d2fd54d4 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -137,7 +137,8 @@ static void latch_registers(CXLUpstreamPort *usp)
 
     cxl_component_register_init_common(reg_state, write_msk,
                                        CXL2_UPSTREAM_PORT,
-                                       PCIE_PORT(usp)->flitmode);
+                                       PCIE_PORT(usp)->flitmode,
+                                       usp->uio_capable);
     ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8);
 }
 
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 25dfee6a9b..8161470172 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -294,19 +294,21 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
 
 static void pxb_cxl_dev_reset(DeviceState *dev)
 {
-    CXLHost *cxl = PXB_CXL_DEV(dev)->cxl_host_bridge;
+    PXBCXLDev *pxb = PXB_CXL_DEV(dev);
+    CXLHost *cxl = pxb->cxl_host_bridge;
     CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
     PCIHostState *hb = PCI_HOST_BRIDGE(cxl);
     uint32_t *reg_state = cxl_cstate->crb.cache_mem_registers;
     uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask;
     int dsp_count = 0;
 
-    cxl_component_register_init_common(reg_state, write_msk, CXL2_RC, false);
+    cxl_component_register_init_common(reg_state, write_msk, CXL2_RC, false,
+                                       pxb->uio_capable);
     /*
      * The CXL specification allows for host bridges with no HDM decoders
      * if they only have a single root port.
      */
-    if (!PXB_CXL_DEV(dev)->hdm_for_passthrough) {
+    if (!pxb->hdm_for_passthrough) {
         dsp_count = pcie_count_ds_ports(hb->bus);
     }
     /* Initial reset will have 0 dsp so wait until > 0 */
@@ -507,6 +509,15 @@ static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp)
 
 static const Property pxb_cxl_dev_properties[] = {
     DEFINE_PROP_BOOL("hdm_for_passthrough", PXBCXLDev, hdm_for_passthrough, false),
+    /*
+     * The host bridge is not a PCIe device in QEMU, so it carries
+     * neither the SVC nor the 256-byte flit mode capability itself;
+     * each root port within the host bridge reports the UIO Capable
+     * bit of its own HDM decoder capability when this property is
+     * set together with its own SVC and 256-byte flit mode
+     * configuration.
+     */
+    DEFINE_PROP_BOOL("x-uio", PXBCXLDev, uio_capable, false),
 };
 
 static void pxb_cxl_dev_class_init(ObjectClass *klass, const void *data)
diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h
index d734f88d2c..662fdb0833 100644
--- a/include/hw/cxl/cxl_component.h
+++ b/include/hw/cxl/cxl_component.h
@@ -315,7 +315,7 @@ void cxl_component_register_block_init(Object *obj,
                                        const char *type);
 void cxl_component_register_init_common(uint32_t *reg_state,
                                         uint32_t *write_msk,
-                                        enum reg_type type, bool bi);
+                                        enum reg_type type, bool bi, bool uio);
 
 void cxl_component_create_dvsec(CXLComponentState *cxl_cstate,
                                 enum reg_type cxl_dev_type, uint16_t length,
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index 3b5dcb5aec..e8480026c3 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -883,6 +883,7 @@ struct CXLType3Dev {
     PCIExpLinkSpeed speed;
     PCIExpLinkWidth width;
     bool flitmode;
+    bool uio_comp_capable;
 
     /* DOE */
     DOECap doe_cdat;
diff --git a/include/hw/pci-bridge/cxl_upstream_port.h b/include/hw/pci-bridge/cxl_upstream_port.h
index e8f5e43faf..db417b6c03 100644
--- a/include/hw/pci-bridge/cxl_upstream_port.h
+++ b/include/hw/pci-bridge/cxl_upstream_port.h
@@ -21,6 +21,7 @@ typedef struct CXLUpstreamPort {
 
     PCIExpLinkSpeed speed;
     PCIExpLinkWidth width;
+    bool uio_capable;
 
     DOECap doe_cdat;
     uint64_t sn;
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index a055fd8d32..09ea8e193f 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -115,6 +115,7 @@ typedef struct PXBCXLDev {
     /*< public >*/
 
     bool hdm_for_passthrough;
+    bool uio_capable;
     CXLHost *cxl_host_bridge; /* Pointer to a CXLHost */
 } PXBCXLDev;
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH qemu v1 4/8] hw/pci: Add PCIe Streamlined Virtual Channel (SVC) capability
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
                     ` (2 preceding siblings ...)
  2026-11-04 11:52   ` [PATCH qemu v1 3/8] hw/cxl: Wire UIO capability into HDM decoder and DVSEC registers Shrihari E S
@ 2026-11-04 11:52   ` Shrihari E S
  2026-11-04 17:25     ` Junjie Cao
  2026-11-04 11:52   ` [PATCH qemu v1 5/8] hw/pci: Wire SVC initialization into port realize functions Shrihari E S
                     ` (3 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

From: Dongjoo Seo <dongjoo.seo1@samsung.com>

Implement the PCIe Streamlined Virtual Channel (SVC) Extended
Capability (PCIe 6.4 section 7.9.29), one of the main prerequisites
for UIO support, with the port capability, control and status
registers and a set of SVC resources.

The capability carries three SVC resources: the default VC0, a
mandatory UIO VC and an optional UIO VC. The write-config path
validates a guest's Resource Control writes against the resource
capability and rejects an invalid configuration by clearing the VC
Enable bit, and the reset path clears the software written state.

Signed-off-by: Dongjoo Seo <dongjoo.seo1@samsung.com>
Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
---
 hw/pci/meson.build         |   2 +-
 hw/pci/pci.c               |   5 +
 hw/pci/pcie.c              |  76 ++++++++++++++-
 hw/pci/pcie_svc.c          | 185 +++++++++++++++++++++++++++++++++++++
 include/hw/pci/pcie.h      |   6 ++
 include/hw/pci/pcie_regs.h |  74 +++++++++++++++
 include/hw/pci/pcie_svc.h  |  20 ++++
 7 files changed, 362 insertions(+), 6 deletions(-)
 create mode 100644 hw/pci/pcie_svc.c
 create mode 100644 include/hw/pci/pcie_svc.h

diff --git a/hw/pci/meson.build b/hw/pci/meson.build
index b9c34b2acf..d55882a0c9 100644
--- a/hw/pci/meson.build
+++ b/hw/pci/meson.build
@@ -14,7 +14,7 @@ pci_ss.add(files(
 # The functions in these modules can be used by devices too.  Since we
 # allow plugging PCIe devices into PCI buses, include them even if
 # CONFIG_PCI_EXPRESS=n.
-pci_ss.add(files('pcie.c', 'pcie_aer.c'))
+pci_ss.add(files('pcie.c', 'pcie_aer.c', 'pcie_svc.c'))
 pci_ss.add(files('pcie_doe.c'))
 system_ss.add(when: 'CONFIG_PCI_EXPRESS', if_true: files('pcie_port.c', 'pcie_host.c'))
 system_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 5996229c81..50472cab88 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -30,6 +30,7 @@
 #include "hw/pci/pci_bridge.h"
 #include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
+#include "hw/pci/pcie_svc.h"
 #include "hw/core/qdev-properties.h"
 #include "hw/core/qdev-properties-system.h"
 #include "migration/cpr.h"
@@ -568,6 +569,8 @@ static void pci_do_device_reset(PCIDevice *dev)
     msi_reset(dev);
     msix_reset(dev);
     pcie_sriov_pf_reset(dev);
+    pcie_cap_flit_reset(dev);
+    pcie_svc_cap_reset(dev);
 }
 
 /*
@@ -1814,6 +1817,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int
     msi_write_config(d, addr, val_in, l);
     msix_write_config(d, addr, val_in, l);
     pcie_sriov_config_write(d, addr, val_in, l);
+    pcie_cap_flit_write_config(d, addr, l);
+    pcie_svc_cap_write_config(d, addr, val_in, l);
 }
 
 /***********************************************************/
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 4f6fc9db61..b05f70022a 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -112,8 +112,9 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
 }
 
 /* Includes setting the target speed default */
-static void pcie_cap_fill_lnk(uint8_t *exp_cap, PCIExpLinkWidth width,
-                              PCIExpLinkSpeed speed, bool flitmode)
+static void pcie_cap_fill_lnk(PCIDevice *dev, uint8_t *exp_cap,
+                              PCIExpLinkWidth width, PCIExpLinkSpeed speed,
+                              bool flitmode)
 {
     /* Clear and fill LNKCAP from what was configured above */
     pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
@@ -160,8 +161,14 @@ static void pcie_cap_fill_lnk(uint8_t *exp_cap, PCIExpLinkWidth width,
     }
 
     if (flitmode) {
-        pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA2,
+        uint32_t pos = dev->exp.exp_cap;
+
+        pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA2,
                                    PCI_EXP_LNKSTA2_FLIT);
+        pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
+                                   PCI_EXP_FLAGS_FLIT);
+        pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_LNKCTL,
+                                   PCI_EXP_LNKCTL_FLIT_DIS);
     }
 }
 
@@ -180,7 +187,65 @@ void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
                                QEMU_PCI_EXP_LNKSTA_NLW(width) |
                                QEMU_PCI_EXP_LNKSTA_CLS(speed));
 
-    pcie_cap_fill_lnk(exp_cap, width, speed, flitmode);
+    pcie_cap_fill_lnk(dev, exp_cap, width, speed, flitmode);
+}
+
+/*
+ * Derive the read-only Flit Status bit of the Link Status 2
+ * register from the Flit Disable bit of the Link Control register.
+ */
+static void pcie_cap_flit_update_sta(PCIDevice *dev)
+{
+    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+    uint16_t lnkctl = pci_get_word(exp_cap + PCI_EXP_LNKCTL);
+    uint16_t lnksta2 = pci_get_word(exp_cap + PCI_EXP_LNKSTA2);
+
+    if (lnkctl & PCI_EXP_LNKCTL_FLIT_DIS) {
+        lnksta2 &= ~PCI_EXP_LNKSTA2_FLIT;
+    } else {
+        lnksta2 |= PCI_EXP_LNKSTA2_FLIT;
+    }
+
+    pci_set_word(exp_cap + PCI_EXP_LNKSTA2, lnksta2);
+}
+
+void pcie_cap_flit_write_config(PCIDevice *dev, uint32_t addr, int len)
+{
+    if (!pci_is_express(dev) || !dev->exp.exp_cap) {
+        return;
+    }
+
+    if (!ranges_overlap(addr, len,
+                        dev->exp.exp_cap + PCI_EXP_LNKCTL, 2)) {
+        return;
+    }
+
+    if (!(pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
+          PCI_EXP_FLAGS_FLIT)) {
+        return;
+    }
+
+    pcie_cap_flit_update_sta(dev);
+}
+
+/*
+ * The Flit Disable bit of the Link Control register keeps its value
+ * across a device reset. Derive the Flit Status bit again from the
+ * current Flit Disable value so the two fields stay consistent after
+ * the reset.
+ */
+void pcie_cap_flit_reset(PCIDevice *dev)
+{
+    if (!pci_is_express(dev) || !dev->exp.exp_cap) {
+        return;
+    }
+
+    if (!(pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
+          PCI_EXP_FLAGS_FLIT)) {
+        return;
+    }
+
+    pcie_cap_flit_update_sta(dev);
 }
 
 static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
@@ -217,7 +282,8 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
         /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */
     }
 
-    pcie_cap_fill_lnk(exp_cap, s->width, s->speed, PCIE_PORT(s)->flitmode);
+    pcie_cap_fill_lnk(dev, exp_cap, s->width, s->speed,
+                      PCIE_PORT(s)->flitmode);
 }
 
 int pcie_cap_init(PCIDevice *dev, uint8_t offset,
diff --git a/hw/pci/pcie_svc.c b/hw/pci/pcie_svc.c
new file mode 100644
index 0000000000..38d2c732a6
--- /dev/null
+++ b/hw/pci/pcie_svc.c
@@ -0,0 +1,185 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * PCIe Streamlined Virtual Channel (SVC) Extended Capability
+ *
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "hw/pci/pci_device.h"
+#include "hw/pci/pcie.h"
+#include "hw/pci/pcie_svc.h"
+#include "hw/pci/pcie_port.h"
+
+int pcie_svc_cap_init(PCIDevice *dev, uint32_t offset, bool flitmode,
+                      Error **errp)
+{
+    uint32_t res_ctrl_wmask;
+
+    if (!pci_is_express(dev)) {
+        error_setg(errp, "SVC ECAP requires PCIe");
+        return -EINVAL;
+    }
+
+    pcie_add_capability(dev, PCI_SVC_CAP_ID, 1, offset,
+                        PCI_SVC_SIZEOF);
+    dev->exp.svc_cap = offset;
+
+    pci_set_long(dev->wmask + offset + PCI_SVC_CTL_OFFSET,
+                 PCI_SVC_CTL_VC_EN_CMP);
+
+    /*
+     * Per PCIe 6.4 Section 7.9.29.5, the SVC Status register resets to
+     * 0: Use VC/MFVC is 0b, meaning the port permanently uses SVC. If
+     * legacy VC/MFVC capabilities are ever implemented, the default
+     * value would need to be 1b and writing 1 to the field would
+     * enable SVC.
+     */
+    pci_set_long(dev->config + offset + PCI_SVC_STA_OFFSET, 0);
+
+    /*
+     * Per PCIe 6.4 Specification Section 7.9.29 all the register
+     * fields of set 0 are hardwired: it carries the default VC0
+     * (VC ID 000b) with the protocols of VC0 (0000b) and TC0 mapped
+     * to it.
+     */
+    pci_set_long(dev->config + offset + PCI_SVC_RES_CAP(0), 0);
+    pci_set_long(dev->config + offset + PCI_SVC_RES_CTRL(0),
+                 PCI_SVC_TC_VC_MAP(0) | PCI_SVC_VC_ENABLE);
+    pci_set_long(dev->config + offset + PCI_SVC_RES_STATUS(0), 0);
+
+    /*
+     * Bit 0 of the TC/VC map is read-only and Clear on the extended
+     * sets, and the Shared Flow Control fields are RsvdP on a port
+     * without 256-byte flit mode (7.9.29.7).
+     */
+    res_ctrl_wmask = PCI_SVC_TC_VC_MAP_RW |
+                     PCI_SVC_VC_PROTOCOL_SELECTED |
+                     PCI_SVC_VC_ENABLE;
+    if (flitmode) {
+        res_ctrl_wmask |= PCI_SVC_SHARED_FLOW_CONTROL_ENABLE |
+                          PCI_SVC_SHARED_FLOW_CONTROL_LIMIT;
+    }
+
+    /*
+     * Set 1 carries VC3 (UIO only, protocols supported 0010b) and
+     * set 2 carries VC4 (UIO or non-UIO, protocols supported 0011b),
+     * per Table 2-46 in the PCIe 6.4 specification.
+     */
+    pci_set_long(dev->config + offset + PCI_SVC_CAP_OFFSET,
+                 PCI_SVC_CAP1_EVCC);
+
+    pci_set_long(dev->config + offset + PCI_SVC_RES_CAP(1),
+                 PCI_SVC_VC_PROTOCOL_UIO |
+                 (3 << PCI_SVC_VC_ID_SHIFT));
+    pci_set_long(dev->wmask + offset + PCI_SVC_RES_CTRL(1),
+                 res_ctrl_wmask);
+    pci_set_long(dev->config + offset + PCI_SVC_RES_STATUS(1), 0);
+
+    pci_set_long(dev->config + offset + PCI_SVC_RES_CAP(2),
+                 PCI_SVC_VC_PROTOCOL_UIO_NONUIO |
+                 (4 << PCI_SVC_VC_ID_SHIFT));
+    pci_set_long(dev->wmask + offset + PCI_SVC_RES_CTRL(2),
+                 res_ctrl_wmask);
+    pci_set_long(dev->config + offset + PCI_SVC_RES_STATUS(2), 0);
+
+    return 0;
+}
+
+void pcie_svc_cap_reset(PCIDevice *dev)
+{
+    uint32_t offset;
+    int i;
+
+    if (!pci_is_express(dev) || !dev->exp.svc_cap) {
+        return;
+    }
+
+    offset = dev->exp.svc_cap;
+    pci_set_long(dev->config + offset + PCI_SVC_CTL_OFFSET, 0);
+    pci_set_long(dev->config + offset + PCI_SVC_STA_OFFSET, 0);
+
+    /*
+     * Clear the writable Resource Control registers back to their
+     * reset value as well: a guest-enabled VC would otherwise survive
+     * a system reset while the Control and Status registers are
+     * cleared.
+     */
+    for (i = 1; i <= PCI_SVC_EVCC; i++) {
+        pci_set_long(dev->config + offset + PCI_SVC_RES_CTRL(i), 0);
+        pci_set_long(dev->config + offset + PCI_SVC_RES_STATUS(i), 0);
+    }
+}
+
+/*
+ * Since QEMU doesn't emulate the Flow control states, this function verifies
+ * the SVC VC enablement done by the software and once done, it clears the
+ * "SVC VC Negotiation pending" bit of SVC Resource status Register. Ideally
+ * The hardware should clear this while exiting from FC_INIT2 state.
+ */
+void pcie_svc_cap_write_config(PCIDevice *dev,
+                               uint32_t addr, uint32_t val, int len)
+{
+    uint32_t offset = dev->exp.svc_cap;
+    int i;
+
+    if (!offset) {
+        return;
+    }
+
+    /*
+     * Validate the SVC Resource Control registers of the software
+     * enabled resource sets (set 1 carries VC3 and set 2 carries
+     * VC4) per 7.9.29.7 in the PCIe 6.4 Specification. Set 0 carries
+     * the default VC0 and all its registers are hardwired.
+     */
+    for (i = 1; i <= PCI_SVC_EVCC; i++) {
+        uint32_t res_ctrl, res_cap, res_sta, proto, vc;
+        bool valid;
+
+        if (!ranges_overlap(addr, len, offset + PCI_SVC_RES_CTRL(i), 4)) {
+            continue;
+        }
+
+        res_cap = pci_get_long(dev->config + offset +
+                                PCI_SVC_RES_CAP(i));
+        res_ctrl = pci_get_long(dev->config + offset +
+                                PCI_SVC_RES_CTRL(i));
+        res_sta = pci_get_long(dev->config + offset +
+                                PCI_SVC_RES_STATUS(i));
+
+        /* The VC carried by the set, from the SVC VC ID field */
+        vc = (res_cap & PCI_SVC_VC_ID_MASK) >> PCI_SVC_VC_ID_SHIFT;
+
+        /* Started SVC VC negotiation */
+        res_sta |= PCI_SVC_VC_NEGO;
+        pci_set_long(dev->config + offset + PCI_SVC_RES_STATUS(i), res_sta);
+
+        /*
+         * Software maps TC<vc> to the VC, per the SVC TC/VC default
+         * assignments (Table 2-46), and selects the use of the VC:
+         * 0010b selects the UIO protocols and 0001b the non-UIO
+         * protocols. The set carries the selection when its
+         * Protocols Supported field permits the use: 0010b permits
+         * the UIO protocols only and 0011b permits either use.
+         */
+        proto = res_ctrl & PCI_SVC_VC_PROTOCOL_SELECTED;
+        valid = (res_ctrl & PCI_SVC_TC_VC_MAP(vc)) &&
+                ((proto == PCI_SVC_VC_PROTOCOL_UIO &&
+                  (res_cap & PCI_SVC_VC_PROTOCOL_UIO)) ||
+                 (proto == PCI_SVC_VC_PROTOCOL_NONUIO &&
+                  (res_cap & PCI_SVC_VC_PROTOCOL_NONUIO)));
+
+        if (!valid) {
+            pci_long_test_and_clear_mask(dev->config + offset +
+                                         PCI_SVC_RES_CTRL(i),
+                                         PCI_SVC_VC_ENABLE);
+        }
+
+        /* SVC Negotiation completed */
+        res_sta &= ~PCI_SVC_VC_NEGO;
+        pci_set_long(dev->config + offset + PCI_SVC_RES_STATUS(i), res_sta);
+    }
+}
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
index 79808126dc..3d092e8871 100644
--- a/include/hw/pci/pcie.h
+++ b/include/hw/pci/pcie.h
@@ -25,6 +25,7 @@
 #include "hw/pci/pcie_regs.h"
 #include "hw/pci/pcie_aer.h"
 #include "hw/pci/pcie_sriov.h"
+#include "hw/pci/pcie_svc.h"
 #include "hw/core/hotplug.h"
 
 typedef struct PCIEPort PCIEPort;
@@ -82,6 +83,9 @@ struct PCIExpressDevice {
     uint16_t sriov_cap;
     PCIESriovPF sriov_pf;
     PCIESriovVF sriov_vf;
+
+    /* Streamlined Virtual Channel (SVC) introduced from PCIe 6.1 */
+    uint32_t svc_cap;
 };
 
 #define COMPAT_PROP_PCP "power_controller_present"
@@ -143,6 +147,8 @@ void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
 void pcie_ats_init(PCIDevice *dev, uint16_t offset, bool aligned);
 void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
                                PCIExpLinkSpeed speed, bool flitmode);
+void pcie_cap_flit_write_config(PCIDevice *dev, uint32_t addr, int len);
+void pcie_cap_flit_reset(PCIDevice *dev);
 
 void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
                                Error **errp);
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
index 33a22229fe..044b3caae4 100644
--- a/include/hw/pci/pcie_regs.h
+++ b/include/hw/pci/pcie_regs.h
@@ -81,6 +81,7 @@ typedef enum PCIExpLinkWidth {
 #define PCI_EXP_DEVCAP2_EETLPP          0x200000
 
 #define PCI_EXP_DEVCTL2_EETLPPB         0x8000
+#define PCI_EXP_LNKCTL_FLIT_DIS         0x2000
 
 /* ARI */
 #define PCI_ARI_VER                     1
@@ -182,4 +183,77 @@ typedef enum PCIExpLinkWidth {
 #define PCI_DOE_VER                     0x1
 #define PCI_DOE_SIZEOF                  24
 
+/* Streamlined Virtual Channel (SVC) PCIe 6.4 section 7.9.29 */
+#define PCI_SVC_CAP_ID                  0x35
+
+/*
+ * The capability structure is sized for the maximum SVC Extended VC
+ * Count of 7 (7.9.29.2): 0x14 bytes of port registers followed by
+ * eight resource sets of 0x0c bytes each. With EVCC 2 the register
+ * space of the resource sets beyond the enabled EVCC is reserved.
+ */
+#define PCI_SVC_SIZEOF                  0x74
+
+#define PCI_SVC_CAP_OFFSET              0x04
+#define PCI_SVC_CTL_OFFSET              0x0c
+#define PCI_SVC_STA_OFFSET              0x10
+
+/* VC Enablement Completed (7.9.29.4) */
+#define PCI_SVC_CTL_VC_EN_CMP          BIT(0)
+
+/*
+ * Two SVC resource sets beyond set 0: set 1 carries VC3 and set 2
+ * carries VC4, per Table 2-46 in the PCIe 6.4 specification. Set 0
+ * carries the default VC0 and all its registers are hardwired.
+ */
+#define PCI_SVC_EVCC                    2
+#define PCI_SVC_CAP1_EVCC               (PCI_SVC_EVCC << 0)
+
+/* 7.9.29.6 SVC Resource capability Register */
+#define PCI_SVC_RES_CAP_BASE            0x14
+#define PCI_SVC_RES_CAP(n)              (PCI_SVC_RES_CAP_BASE + ((n) * 0x0c))
+
+/*
+ * SVC VC Protocols Supported encodings (11:8), per 7.9.29.6 in the
+ * PCIe 6.4 specification: 0010b permits the UIO protocols on the VC,
+ * 0011b permits the UIO protocols or the non-UIO protocols, and
+ * 0001b permits the non-UIO protocols. Bit 9 of the field carries
+ * the UIO permission and bit 8 the non-UIO permission.
+ */
+#define PCI_SVC_VC_PROTOCOL_NONUIO      (0x1 << 8)
+#define PCI_SVC_VC_PROTOCOL_UIO         (0x2 << 8)
+#define PCI_SVC_VC_PROTOCOL_UIO_NONUIO  (0x3 << 8)
+#define PCI_SVC_VC_ID_SHIFT             12
+#define PCI_SVC_VC_ID_MASK              (0x7 << PCI_SVC_VC_ID_SHIFT)
+
+/* 7.9.29.7 SVC Resource Control Register */
+#define PCI_SVC_RES_CTRL_BASE           0x18
+#define PCI_SVC_RES_CTRL(n)             (PCI_SVC_RES_CTRL_BASE + ((n) * 0x0c))
+#define PCI_SVC_VC_ENABLE               BIT(31)
+#define PCI_SVC_SHARED_FLOW_CONTROL_ENABLE  BIT(30)
+
+/*
+ * SVC VC Protocol Selected field (11:8): software selects 0010b to
+ * use the UIO protocols on the VC and 0001b to use the non-UIO
+ * protocols, per 7.9.29.7 in the PCIe 6.4 specification. The other
+ * encodings of the field are reserved.
+ */
+#define PCI_SVC_VC_PROTOCOL_SELECTED    (0xf << 8)
+#define PCI_SVC_SHARED_FLOW_CONTROL_LIMIT   (0x7 << 27)
+#define PCI_SVC_TC_VC_MAP_ENABLE        (0xff << 0)
+
+/*
+ * Bit 0 of the TC/VC map is read-only: Set for the default VC0 and
+ * Clear for the other VCs (7.9.29.7).
+ */
+#define PCI_SVC_TC_VC_MAP_RW            (0xfe << 0)
+
+/* Bit n of the field carries the mapping of TCn (7.9.29.7) */
+#define PCI_SVC_TC_VC_MAP(n)            (BIT(n) & PCI_SVC_TC_VC_MAP_ENABLE)
+
+/* 7.9.29.8 SVC Resource Status Register */
+#define PCI_SVC_RES_STATUS_BASE         0x1c
+#define PCI_SVC_RES_STATUS(n)           (PCI_SVC_RES_STATUS_BASE + ((n) * 0x0c))
+#define PCI_SVC_VC_NEGO                 BIT(1)
+
 #endif /* QEMU_PCIE_REGS_H */
diff --git a/include/hw/pci/pcie_svc.h b/include/hw/pci/pcie_svc.h
new file mode 100644
index 0000000000..6f52dc0a1c
--- /dev/null
+++ b/include/hw/pci/pcie_svc.h
@@ -0,0 +1,20 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * PCIe Streamlined Virtual Channel (SVC) Extended Capability
+ *
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef HW_PCIE_SVC_H
+#define HW_PCIE_SVC_H
+
+#include "hw/pci/pci.h"
+
+int  pcie_svc_cap_init(PCIDevice *dev, uint32_t offset, bool flitmode,
+                       Error **errp);
+void pcie_svc_cap_reset(PCIDevice *dev);
+void pcie_svc_cap_write_config(PCIDevice *dev,
+                               uint32_t addr, uint32_t val, int len);
+
+#endif /* HW_PCIE_SVC_H */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH qemu v1 5/8] hw/pci: Wire SVC initialization into port realize functions
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
                     ` (3 preceding siblings ...)
  2026-11-04 11:52   ` [PATCH qemu v1 4/8] hw/pci: Add PCIe Streamlined Virtual Channel (SVC) capability Shrihari E S
@ 2026-11-04 11:52   ` Shrihari E S
  2026-11-04 17:25     ` Junjie Cao
  2026-11-04 11:52   ` [PATCH qemu v1 6/8] hw/pci: Add PCIe Device3 capability support Shrihari E S
                     ` (2 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

With the x-svc option, a port appends the SVC capability at the end
of its extended capability chain at realize time.

In the same realize path a CXL root port derives its UIO status: it
is UIO capable when the parent pxb-cxl host bridge carries x-uio and
its own SVC and 256-byte flit mode configuration carry it; a root
port on any other bus does not carry UIO.

PXB PCIe root ports, CXL root ports, CXL switch ports and PCIe
switch ports accept the x-svc option; the port types without a
reserved SVC capability offset do not carry it.

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
Signed-off-by: Dongjoo Seo <dongjoo.seo1@samsung.com>
---
 hw/pci-bridge/cxl_downstream.c     | 10 ++++++++++
 hw/pci-bridge/cxl_root_port.c      | 29 +++++++++++++++++++++++++++++
 hw/pci-bridge/cxl_upstream.c       | 14 ++++++++++++++
 hw/pci-bridge/gen_pcie_root_port.c |  3 +++
 hw/pci-bridge/pcie_root_port.c     | 14 ++++++++++++++
 hw/pci-bridge/xio3130_downstream.c |  6 ++++++
 hw/pci-bridge/xio3130_upstream.c   | 19 +++++++++++++++++++
 include/hw/pci/pcie_port.h         |  4 ++++
 8 files changed, 99 insertions(+)

diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index bc1e65bc89..b710ce4f2c 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -229,6 +229,15 @@ static void cxl_dsp_realize(PCIDevice *d, Error **errp)
                      PCI_BASE_ADDRESS_SPACE_MEMORY |
                          PCI_BASE_ADDRESS_MEM_TYPE_64,
                      &dsp->bar);
+    if (p->svc) {
+        /*
+         * SVC is appended after the DVSECs so that the extended
+         * capability layout is unchanged when the port does not
+         * carry SVC.
+         */
+        pcie_svc_cap_init(d, cxl_cstate->dvsec_offset, p->flitmode,
+                          errp);
+    }
 
     return;
 
@@ -260,6 +269,7 @@ static const Property cxl_dsp_props[] = {
     DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
                                 width, PCIE_LINK_WIDTH_16),
     DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
+    DEFINE_PROP_BOOL("x-svc", PCIEPort, svc, false),
 };
 
 static void cxl_dsp_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index 4be2b400f9..4e7eea9deb 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -164,7 +164,9 @@ static void cxl_rp_realize(DeviceState *dev, Error **errp)
 {
     PCIDevice *pci_dev     = PCI_DEVICE(dev);
     PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+    PCIEPort *p            = PCIE_PORT(dev);
     CXLRootPort *crp       = CXL_ROOT_PORT(dev);
+    PCIDevice *hb_dev;
     CXLComponentState *cxl_cstate = &crp->cxl_cstate;
     ComponentRegisters *cregs = &cxl_cstate->crb;
     MemoryRegion *component_bar = &cregs->component_registers;
@@ -212,6 +214,33 @@ static void cxl_rp_realize(DeviceState *dev, Error **errp)
                      PCI_BASE_ADDRESS_SPACE_MEMORY |
                      PCI_BASE_ADDRESS_MEM_TYPE_64,
                      &crp->bar);
+    /*
+     * The Host Bridge UIO Capable bit marks all the root ports
+     * within the Host Bridge as capable of routing UIO requests
+     * (CXL 3.2 8.2.4.20.1): a root port below a pxb-cxl host bridge
+     * carries the UIO capability when the host bridge carries x-uio
+     * and its own SVC and 256-byte flit mode configuration carries
+     * it. A root port on any other bus carries no pxb-cxl host
+     * bridge above it.
+     */
+    hb_dev = pci_get_bus(pci_dev)->parent_dev;
+    crp->uio_capable = hb_dev && object_dynamic_cast(OBJECT(hb_dev),
+                                                     TYPE_PXB_CXL_DEV) &&
+                       PXB_CXL_DEV(hb_dev)->uio_capable &&
+                       p->svc && p->flitmode;
+
+    /*
+     * SVC is appended after the DVSECs so that the extended
+     * capability layout is unchanged when the port does not carry
+     * SVC.
+     */
+    if (p->svc) {
+        rc = pcie_svc_cap_init(pci_dev, cxl_cstate->dvsec_offset,
+                               p->flitmode, errp);
+        if (rc < 0) {
+            return;
+        }
+    }
 }
 
 static void cxl_rp_reset_hold(Object *obj, ResetType type)
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index 63d2fd54d4..a16e2e9744 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -414,6 +414,19 @@ static void cxl_usp_realize(PCIDevice *d, Error **errp)
         goto err_cap;
     }
 
+    if (p->svc) {
+        /*
+         * SVC is appended after the DOE capability so that the
+         * extended capability layout is unchanged when the port
+         * does not carry SVC.
+         */
+        rc = pcie_svc_cap_init(d,
+                               cxl_cstate->dvsec_offset + PCI_DOE_SIZEOF,
+                               p->flitmode, errp);
+        if (p->flitmode && rc >= 0) {
+            usp->uio_capable = true;
+        }
+    }
     return;
 
 err_cap:
@@ -441,6 +454,7 @@ static const Property cxl_upstream_props[] = {
     DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLUpstreamPort,
                                 width, PCIE_LINK_WIDTH_16),
     DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
+    DEFINE_PROP_BOOL("x-svc", PCIEPort, svc, false),
 };
 
 static void cxl_upstream_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
index 2f7257d166..d4df4a7c16 100644
--- a/hw/pci-bridge/gen_pcie_root_port.c
+++ b/hw/pci-bridge/gen_pcie_root_port.c
@@ -26,6 +26,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(GenPCIERootPort, GEN_PCIE_ROOT_PORT)
 #define GEN_PCIE_ROOT_PORT_AER_OFFSET           0x100
 #define GEN_PCIE_ROOT_PORT_ACS_OFFSET \
         (GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF)
+#define GEN_PCIE_ROOT_PORT_SVC_OFFSET \
+        (GEN_PCIE_ROOT_PORT_ACS_OFFSET + PCI_ACS_SIZEOF)
 
 #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR       1
 #define GEN_PCIE_ROOT_DEFAULT_IO_RANGE          4096
@@ -166,6 +168,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, const void *data)
     rpc->interrupts_uninit = gen_rp_interrupts_uninit;
     rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
     rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET;
+    rpc->svc_offset = GEN_PCIE_ROOT_PORT_SVC_OFFSET;
 }
 
 static const TypeInfo gen_rp_dev_info = {
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index bc173dbf30..645394310c 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -68,6 +68,15 @@ static void rp_realize(PCIDevice *d, Error **errp)
     int rc;
 
     pci_config_set_interrupt_pin(d->config, 1);
+    if (!pci_is_cxl(d) && p->svc && !rpc->svc_offset) {
+        /*
+         * Only root port types with a reserved offset for the SVC
+         * capability in their extended capability space support it.
+         */
+        error_setg(errp, "%s: SVC is not supported by this port type",
+                   object_get_typename(OBJECT(d)));
+        return;
+    }
     if (d->cap_present & QEMU_PCIE_CAP_CXL) {
         pci_bridge_initfn(d, TYPE_CXL_BUS);
     } else {
@@ -120,6 +129,10 @@ static void rp_realize(PCIDevice *d, Error **errp)
     if (rpc->acs_offset && !s->disable_acs) {
         pcie_acs_init(d, rpc->acs_offset);
     }
+    if (!pci_is_cxl(d) && p->svc) {
+        pcie_svc_cap_init(d, rpc->svc_offset, p->flitmode, errp);
+    }
+
     return;
 
 err:
@@ -153,6 +166,7 @@ static const Property rp_props[] = {
                     QEMU_PCIE_SLTCAP_PCP_BITNR, true),
     DEFINE_PROP_BOOL("disable-acs", PCIESlot, disable_acs, false),
     DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
+    DEFINE_PROP_BOOL("x-svc", PCIEPort, svc, false),
 };
 
 static void rp_instance_post_init(Object *obj)
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index 0c3fed3053..af4bb5dc83 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -110,6 +110,10 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp)
     if (rc < 0) {
         goto err;
     }
+    if (p->svc) {
+        pcie_svc_cap_init(d, XIO3130_AER_OFFSET + PCI_ERR_SIZEOF,
+                          p->flitmode, errp);
+    }
 
     return;
 
@@ -137,6 +141,8 @@ static void xio3130_downstream_exitfn(PCIDevice *d)
 static const Property xio3130_downstream_props[] = {
     DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
                     QEMU_PCIE_SLTCAP_PCP_BITNR, true),
+    DEFINE_PROP_BOOL("x-svc", PCIEPort, svc, false),
+    DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
 };
 
 static const VMStateDescription vmstate_xio3130_downstream = {
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index 40057b749b..5ba234bc06 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -24,6 +24,7 @@
 #include "hw/pci/msi.h"
 #include "hw/pci/pcie.h"
 #include "hw/pci/pcie_port.h"
+#include "hw/core/qdev-properties.h"
 #include "migration/vmstate.h"
 #include "qemu/module.h"
 
@@ -49,9 +50,17 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
 static void xio3130_upstream_reset(DeviceState *qdev)
 {
     PCIDevice *d = PCI_DEVICE(qdev);
+    PCIEPort *p = PCIE_PORT(d);
 
     pci_bridge_reset(qdev);
     pcie_cap_deverr_reset(d);
+    /*
+     * An upstream port is not a PCIESlot, so the link capability
+     * and status registers are filled here from the port's
+     * configuration, the way the CXL upstream port does.
+     */
+    pcie_cap_fill_link_ep_usp(d, QEMU_PCI_EXP_LNK_X1,
+                              QEMU_PCI_EXP_LNK_2_5GT, p->flitmode);
 }
 
 static void xio3130_upstream_realize(PCIDevice *d, Error **errp)
@@ -91,6 +100,10 @@ static void xio3130_upstream_realize(PCIDevice *d, Error **errp)
     if (rc < 0) {
         goto err;
     }
+    if (p->svc) {
+        pcie_svc_cap_init(d, XIO3130_AER_OFFSET + PCI_ERR_SIZEOF,
+                          p->flitmode, errp);
+    }
 
     return;
 
@@ -123,6 +136,11 @@ static const VMStateDescription vmstate_xio3130_upstream = {
     }
 };
 
+static const Property xio3130_upstream_props[] = {
+    DEFINE_PROP_BOOL("x-svc", PCIEPort, svc, false),
+    DEFINE_PROP_BOOL("x-256b-flit", PCIEPort, flitmode, false),
+};
+
 static void xio3130_upstream_class_init(ObjectClass *klass, const void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -138,6 +156,7 @@ static void xio3130_upstream_class_init(ObjectClass *klass, const void *data)
     dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
     device_class_set_legacy_reset(dc, xio3130_upstream_reset);
     dc->vmsd = &vmstate_xio3130_upstream;
+    device_class_set_props(dc, xio3130_upstream_props);
 }
 
 static const TypeInfo xio3130_upstream_info = {
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index 1bcc734649..492721ba43 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -35,6 +35,9 @@ struct PCIEPort {
     /*< public >*/
     bool flitmode;
 
+    /* Streamlined Virtual Channel (SVC) capability */
+    bool svc;
+
     /* pci express switch port */
     uint8_t     port;
 };
@@ -94,6 +97,7 @@ struct PCIERootPortClass {
     int aer_offset;
     int ssvid_offset;
     int acs_offset;    /* If nonzero, optional ACS capability offset */
+    int svc_offset;    /* optional SVC capability */
     int ssid;
 };
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH qemu v1 6/8] hw/pci: Add PCIe Device3 capability support
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
                     ` (4 preceding siblings ...)
  2026-11-04 11:52   ` [PATCH qemu v1 5/8] hw/pci: Wire SVC initialization into port realize functions Shrihari E S
@ 2026-11-04 11:52   ` Shrihari E S
  2026-11-04 11:52   ` [PATCH qemu v1 7/8] hw/cxl: Wire SVC and Dev3 capabilities to CXL Type 3 device Shrihari E S
  2026-11-04 11:52   ` [PATCH qemu v1 8/8] cxl: Add documentation for CXL UIO support Shrihari E S
  7 siblings, 0 replies; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Add the PCIe Device 3 Extended Capability (PCIe 6.4 section 7.7.9),
with which an endpoint exposes its UIO requester and completer
support and the related control bits.

The capability tracks the link's flit state: the requester-enable
bits stay clear while the link is not in flit mode, and the Segment
Captured status bit follows the flit state.

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
Signed-off-by: Dongjoo Seo <dongjoo.seo1@samsung.com>
---
 hw/pci/meson.build         |   2 +-
 hw/pci/pci.c               |   2 +
 hw/pci/pcie.c              |  29 ++++++++++
 hw/pci/pcie_dev3.c         | 111 +++++++++++++++++++++++++++++++++++++
 include/hw/pci/pcie.h      |   5 ++
 include/hw/pci/pcie_dev3.h |  26 +++++++++
 include/hw/pci/pcie_regs.h |  26 +++++++++
 7 files changed, 200 insertions(+), 1 deletion(-)
 create mode 100644 hw/pci/pcie_dev3.c
 create mode 100644 include/hw/pci/pcie_dev3.h

diff --git a/hw/pci/meson.build b/hw/pci/meson.build
index d55882a0c9..0a7f3b162a 100644
--- a/hw/pci/meson.build
+++ b/hw/pci/meson.build
@@ -14,7 +14,7 @@ pci_ss.add(files(
 # The functions in these modules can be used by devices too.  Since we
 # allow plugging PCIe devices into PCI buses, include them even if
 # CONFIG_PCI_EXPRESS=n.
-pci_ss.add(files('pcie.c', 'pcie_aer.c', 'pcie_svc.c'))
+pci_ss.add(files('pcie.c', 'pcie_aer.c', 'pcie_svc.c', 'pcie_dev3.c'))
 pci_ss.add(files('pcie_doe.c'))
 system_ss.add(when: 'CONFIG_PCI_EXPRESS', if_true: files('pcie_port.c', 'pcie_host.c'))
 system_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 50472cab88..cc5e40ac5c 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -571,6 +571,7 @@ static void pci_do_device_reset(PCIDevice *dev)
     pcie_sriov_pf_reset(dev);
     pcie_cap_flit_reset(dev);
     pcie_svc_cap_reset(dev);
+    pcie_dev3_cap_reset(dev);
 }
 
 /*
@@ -1819,6 +1820,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int
     pcie_sriov_config_write(d, addr, val_in, l);
     pcie_cap_flit_write_config(d, addr, l);
     pcie_svc_cap_write_config(d, addr, val_in, l);
+    pcie_dev3_cap_write_config(d, addr, val_in, l);
 }
 
 /***********************************************************/
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index b05f70022a..9f16cc8d1b 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -190,6 +190,32 @@ void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
     pcie_cap_fill_lnk(dev, exp_cap, width, speed, flitmode);
 }
 
+bool pcie_link_flit_active(PCIDevice *dev)
+{
+    uint8_t *exp_cap;
+    uint16_t lnksta2;
+    uint16_t lnkctl;
+    uint16_t flags;
+
+    if (!pci_is_express(dev) || !dev->exp.exp_cap) {
+        return false;
+    }
+
+    exp_cap = dev->config + dev->exp.exp_cap;
+    flags = pci_get_word(exp_cap + PCI_EXP_FLAGS);
+    if (!(flags & PCI_EXP_FLAGS_FLIT)) {
+        return false;
+    }
+    lnkctl = pci_get_word(exp_cap + PCI_EXP_LNKCTL);
+    lnksta2 = pci_get_word(exp_cap + PCI_EXP_LNKSTA2);
+
+    if (lnkctl & PCI_EXP_LNKCTL_FLIT_DIS) {
+        return false;
+    }
+
+    return lnksta2 & PCI_EXP_LNKSTA2_FLIT;
+}
+
 /*
  * Derive the read-only Flit Status bit of the Link Status 2
  * register from the Flit Disable bit of the Link Control register.
@@ -226,6 +252,9 @@ void pcie_cap_flit_write_config(PCIDevice *dev, uint32_t addr, int len)
     }
 
     pcie_cap_flit_update_sta(dev);
+    if (dev->exp.dev3_cap) {
+        pcie_dev3_cap_flit_update(dev);
+    }
 }
 
 /*
diff --git a/hw/pci/pcie_dev3.c b/hw/pci/pcie_dev3.c
new file mode 100644
index 0000000000..8ca7c74b8c
--- /dev/null
+++ b/hw/pci/pcie_dev3.c
@@ -0,0 +1,111 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * PCIe Device3 Extended Capability
+ *
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci_device.h"
+#include "hw/pci/pcie.h"
+#include "hw/pci/pcie_port.h"
+#include "hw/pci/pcie_dev3.h"
+
+int pcie_dev3_cap_init(PCIDevice *dev, uint32_t offset,
+                       bool uio_req, bool uio_comp, Error **errp)
+{
+    uint32_t devcap3 = 0;
+    uint32_t wmask = 0;
+
+    if (!pci_is_express(dev)) {
+        error_setg(errp, "Device 3 ECAP requires PCIe");
+        return -EINVAL;
+    }
+
+    pcie_add_capability(dev, PCI_EXT_CAP_ID_DEV3, 1, offset, PCI_DEV3_SIZEOF);
+    dev->exp.dev3_cap = offset;
+    dev->exp.dev3.uio_req = uio_req;
+    dev->exp.dev3.uio_comp = uio_comp;
+
+    /*
+     * In this implementation, 14-bit tag support is only advertised
+     * when UIO is enabled. A real device may support 14-bit tags
+     * independently of UIO.
+     */
+    if (uio_comp) {
+        devcap3 |= PCI_DEV3_CAP_TAG_COMP | PCI_DEV3_CAP_UIO_COMP;
+    }
+    if (uio_req) {
+        devcap3 |= PCI_DEV3_CAP_TAG_REQ | PCI_DEV3_CAP_UIO_REQ;
+        wmask |= PCI_DEV3_CTL_TAG_REQ_EN |
+                 PCI_DEV3_CTL_UIO_REQ_EN |
+                 PCI_DEV3_CTL_UIO_256B_DIS;
+    }
+
+    pci_set_long(dev->config + offset + PCI_DEV3_CAP_OFFSET, devcap3);
+    pci_set_long(dev->wmask + offset + PCI_DEV3_CTL_OFFSET, wmask);
+
+    return 0;
+}
+
+/*
+ * Track the link's flit state in the Device 3 capability: the
+ * requester-enable bits of the Device Control 3 register are cleared
+ * while the link is not in flit mode, and the Segment Captured
+ * status bit follows the link's flit state.
+ */
+void pcie_dev3_cap_flit_update(PCIDevice *dev)
+{
+    uint32_t off = dev->exp.dev3_cap;
+    uint32_t devctl3;
+    uint32_t devsta3;
+    bool flit;
+
+    if (!off) {
+        return;
+    }
+
+    flit = pcie_link_flit_active(dev);
+    if (!dev->exp.dev3.uio_req || !flit) {
+        devctl3 = pci_get_long(dev->config + off + PCI_DEV3_CTL_OFFSET);
+        devctl3 &= ~(PCI_DEV3_CTL_TAG_REQ_EN |
+                     PCI_DEV3_CTL_UIO_REQ_EN |
+                     PCI_DEV3_CTL_UIO_256B_DIS);
+        pci_set_long(dev->config + off + PCI_DEV3_CTL_OFFSET, devctl3);
+    }
+
+    devsta3 = pci_get_long(dev->config + off + PCI_DEV3_STA_OFFSET);
+    if (flit) {
+        devsta3 |= PCI_DEV3_STA_SEGMENT_CAP;
+    } else {
+        devsta3 &= ~PCI_DEV3_STA_SEGMENT_CAP;
+    }
+    pci_set_long(dev->config + off + PCI_DEV3_STA_OFFSET, devsta3);
+}
+
+void pcie_dev3_cap_reset(PCIDevice *dev)
+{
+    uint32_t off = dev->exp.dev3_cap;
+
+    if (!off) {
+        return;
+    }
+
+    pci_set_long(dev->config + off + PCI_DEV3_CTL_OFFSET, 0);
+    pci_set_long(dev->config + off + PCI_DEV3_STA_OFFSET, 0);
+    pcie_dev3_cap_flit_update(dev);
+}
+
+void pcie_dev3_cap_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len)
+{
+    if (!dev->exp.dev3_cap) {
+        return;
+    }
+
+    if (ranges_overlap(addr, len,
+                       dev->exp.dev3_cap + PCI_DEV3_CTL_OFFSET, 4)) {
+        pcie_dev3_cap_flit_update(dev);
+    }
+}
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
index 3d092e8871..95f670c830 100644
--- a/include/hw/pci/pcie.h
+++ b/include/hw/pci/pcie.h
@@ -26,6 +26,7 @@
 #include "hw/pci/pcie_aer.h"
 #include "hw/pci/pcie_sriov.h"
 #include "hw/pci/pcie_svc.h"
+#include "hw/pci/pcie_dev3.h"
 #include "hw/core/hotplug.h"
 
 typedef struct PCIEPort PCIEPort;
@@ -86,6 +87,9 @@ struct PCIExpressDevice {
 
     /* Streamlined Virtual Channel (SVC) introduced from PCIe 6.1 */
     uint32_t svc_cap;
+    /* PCIe Device 3 Capability */
+    uint32_t dev3_cap;
+    struct PCIEDev3Cap dev3;
 };
 
 #define COMPAT_PROP_PCP "power_controller_present"
@@ -149,6 +153,7 @@ void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
                                PCIExpLinkSpeed speed, bool flitmode);
 void pcie_cap_flit_write_config(PCIDevice *dev, uint32_t addr, int len);
 void pcie_cap_flit_reset(PCIDevice *dev);
+bool pcie_link_flit_active(PCIDevice *dev);
 
 void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
                                Error **errp);
diff --git a/include/hw/pci/pcie_dev3.h b/include/hw/pci/pcie_dev3.h
new file mode 100644
index 0000000000..4cfa07fe32
--- /dev/null
+++ b/include/hw/pci/pcie_dev3.h
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * PCIe Device3 Extended Capability
+ *
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef HW_PCIE_DEV3_H
+#define HW_PCIE_DEV3_H
+
+#include "hw/pci/pci.h"
+
+typedef struct PCIEDev3Cap {
+    bool uio_req;
+    bool uio_comp;
+} PCIEDev3Cap;
+
+int pcie_dev3_cap_init(PCIDevice *dev, uint32_t offset,
+                       bool uio_req, bool uio_comp, Error **errp);
+void pcie_dev3_cap_reset(PCIDevice *dev);
+void pcie_dev3_cap_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len);
+void pcie_dev3_cap_flit_update(PCIDevice *dev);
+
+#endif /* HW_PCIE_DEV3_H */
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
index 044b3caae4..484178adb3 100644
--- a/include/hw/pci/pcie_regs.h
+++ b/include/hw/pci/pcie_regs.h
@@ -256,4 +256,30 @@ typedef enum PCIExpLinkWidth {
 #define PCI_SVC_RES_STATUS(n)           (PCI_SVC_RES_STATUS_BASE + ((n) * 0x0c))
 #define PCI_SVC_VC_NEGO                 BIT(1)
 
+/* PCIe Device 3 capability structure. PCIe 6.4 Specification Section 7.7.9 */
+#ifndef PCI_EXT_CAP_ID_DEV3
+#define PCI_EXT_CAP_ID_DEV3 0x2f
+#endif
+
+#define PCI_DEV3_CAP_OFFSET            0x04
+#define PCI_DEV3_CTL_OFFSET            0x08
+#define PCI_DEV3_STA_OFFSET            0x0c
+#define PCI_DEV3_SIZEOF                0x10
+
+/* Section 7.7.9.2 Device Capabilities 3 Register */
+#define PCI_DMWR_REQ_SUPPORTED         BIT(0)
+#define PCI_DEV3_CAP_TAG_COMP          BIT(1)
+#define PCI_DEV3_CAP_TAG_REQ           BIT(2)
+#define PCI_L0P_SUPPORTED              BIT(3)
+#define PCI_DEV3_CAP_UIO_COMP          BIT(10)
+#define PCI_DEV3_CAP_UIO_REQ           BIT(11)
+
+/* Section 7.7.9.3 Device Control 3 Register */
+#define PCI_DEV3_CTL_TAG_REQ_EN        BIT(2)
+#define PCI_DEV3_CTL_UIO_REQ_EN        BIT(7)
+#define PCI_DEV3_CTL_UIO_256B_DIS      BIT(8)
+
+/* Section 7.7.9.4 Device Status 3 Register */
+#define PCI_DEV3_STA_SEGMENT_CAP       BIT(3)
+
 #endif /* QEMU_PCIE_REGS_H */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH qemu v1 7/8] hw/cxl: Wire SVC and Dev3 capabilities to CXL Type 3 device
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
                     ` (5 preceding siblings ...)
  2026-11-04 11:52   ` [PATCH qemu v1 6/8] hw/pci: Add PCIe Device3 capability support Shrihari E S
@ 2026-11-04 11:52   ` Shrihari E S
  2026-11-04 17:25     ` Junjie Cao
  2026-11-04 11:52   ` [PATCH qemu v1 8/8] cxl: Add documentation for CXL UIO support Shrihari E S
  7 siblings, 1 reply; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Add the SVC and Dev3 capabilities to the CXL type 3 device to make
it work as a UIO completer. The x-uio option works together with
the x-svc and x-256b-flit options: the device carries the UIO
capability when all three are set, and logs a warning that UIO is
not enabled when x-uio is set without x-svc and x-256b-flit.

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
Signed-off-by: Dongjoo Seo <dongjoo.seo1@samsung.com>
---
 hw/mem/cxl_type3.c          | 29 +++++++++++++++++++++++++++++
 include/hw/cxl/cxl_device.h |  1 +
 2 files changed, 30 insertions(+)

diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 778a18ddea..12430c77d2 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -17,6 +17,7 @@
 #include "hw/mem/memory-device.h"
 #include "hw/mem/pc-dimm.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pcie_dev3.h"
 #include "hw/core/qdev-properties.h"
 #include "hw/core/qdev-properties-system.h"
 #include "qapi/error.h"
@@ -1191,6 +1192,33 @@ void ct3_realize(PCIDevice *pci_dev, Error **errp)
     pcie_doe_init(pci_dev, &ct3d->doe_comp, 0x1b0, doe_comp_prot, true,
                   CXL_T3_MSIX_PCIE_DOE_COMPLIANCE);
 
+    /*
+     * The HDM decoder UIO capability builds on the SVC and 256-byte
+     * flit mode capabilities in the PCIe config space: the device
+     * carries the UIO capability when it is configured for SVC and
+     * 256-byte flit mode as well.
+     */
+    if (ct3d->uio_comp_capable && (!ct3d->svc || !ct3d->flitmode)) {
+        warn_report("x-uio=on requires x-svc=on and x-256b-flit=on; "
+                    "UIO will not be enabled on this device");
+        ct3d->uio_comp_capable = false;
+    }
+
+    if (ct3d->svc) {
+        /* SVC capability of the type3 device */
+        rc = pcie_svc_cap_init(pci_dev, 0x200 + PCI_ERR_SIZEOF,
+                               ct3d->flitmode, errp);
+        if ((rc >= 0) && ct3d->uio_comp_capable) {
+            /*
+             * The Dev3 Capability is placed after SVC in the PCIe
+             * config space, and the device is initialized as a UIO
+             * completer.
+             */
+            pcie_dev3_cap_init(pci_dev, 0x200 + PCI_ERR_SIZEOF + PCI_SVC_SIZEOF,
+                               false, true, errp);
+        }
+    }
+
     /* Set default value for patrol scrub attributes */
     ct3d->patrol_scrub_attrs.scrub_cycle_cap =
                            CXL_MEMDEV_PS_SCRUB_CYCLE_CHANGE_CAP_DEFAULT |
@@ -1556,6 +1584,7 @@ static const Property ct3_props[] = {
                                 width, PCIE_LINK_WIDTH_16),
     DEFINE_PROP_BOOL("x-256b-flit", CXLType3Dev, flitmode, false),
     DEFINE_PROP_BOOL("hdm-db", CXLType3Dev, hdmdb, false),
+    DEFINE_PROP_BOOL("x-svc", CXLType3Dev, svc, false),
     DEFINE_PROP_BOOL("x-uio", CXLType3Dev, uio_comp_capable, false),
     DEFINE_PROP_UINT16("chmu-port", CXLType3Dev, cxl_dstate.chmu[0].port, 0),
 };
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index e8480026c3..a095febf90 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -884,6 +884,7 @@ struct CXLType3Dev {
     PCIExpLinkWidth width;
     bool flitmode;
     bool uio_comp_capable;
+    bool svc;
 
     /* DOE */
     DOECap doe_cdat;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH qemu v1 8/8] cxl: Add documentation for CXL UIO support
       [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
                     ` (6 preceding siblings ...)
  2026-11-04 11:52   ` [PATCH qemu v1 7/8] hw/cxl: Wire SVC and Dev3 capabilities to CXL Type 3 device Shrihari E S
@ 2026-11-04 11:52   ` Shrihari E S
  7 siblings, 0 replies; 12+ messages in thread
From: Shrihari E S @ 2026-11-04 11:52 UTC (permalink / raw)
  To: jic23, junjie.cao, linux-cxl, linux-pci, qemu-devel, anisa.su887,
	mst, marcel.apfelbaum
  Cc: shrihari.s, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Add a section for the UIO related device options, and a
command-line example demonstrating a topology with three CXL Type-3
devices connected via a switch, with Unordered I/O (UIO) enabled on
all ports and endpoints. The example shows the correct usage of
the x-svc, x-256b-flit and x-uio options, including the x-uio option
of the pxb-cxl host bridge, which marks all the root ports within
the host bridge as capable of routing UIO requests.

The x-uio option of the CXL type3 device works together with x-svc
and x-256b-flit: the device carries the UIO capability when all
three are set.

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
Signed-off-by: Dongjoo Seo <dongjoo.seo1@samsung.com>
---
 docs/system/devices/cxl.rst | 54 ++++++++++++++++++++++++++++++++++---
 1 file changed, 51 insertions(+), 3 deletions(-)

diff --git a/docs/system/devices/cxl.rst b/docs/system/devices/cxl.rst
index 32b1b5d773..e2d66b0e4e 100644
--- a/docs/system/devices/cxl.rst
+++ b/docs/system/devices/cxl.rst
@@ -394,12 +394,12 @@ use HDM-DB for coherence, which requires operating in Flit mode::
   -object memory-backend-ram,id=cxl-mem2,share=on,size=256M \
   -object memory-backend-ram,id=cxl-mem3,share=on,size=256M \
   -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
-  -device cxl-rp,port=0,bus=cxl.1,id=root_port0,chassis=0,slot=0 \
+  -device cxl-rp,port=0,bus=cxl.1,id=root_port0,chassis=0,slot=0,x-256b-flit=on \
   -device cxl-rp,port=1,bus=cxl.1,id=root_port1,chassis=0,slot=1 \
   -device cxl-upstream,bus=root_port0,id=us0,x-256b-flit=on \
-  -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
+  -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4,x-256b-flit=on \
   -device cxl-type3,bus=swport0,volatile-memdev=cxl-mem0,id=cxl-mem0,sn=0x1,x-256b-flit=on,hdm-db=on \
-  -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
+  -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5,x-256b-flit=on \
   -device cxl-type3,bus=swport1,volatile-memdev=cxl-mem1,id=cxl-mem1,sn=0x2,x-256b-flit=on,hdm-db=on \
   -device cxl-downstream,port=2,bus=us0,id=swport2,chassis=0,slot=6 \
   -device cxl-type3,bus=swport2,volatile-memdev=cxl-mem2,id=cxl-mem2,sn=0x3 \
@@ -407,6 +407,54 @@ use HDM-DB for coherence, which requires operating in Flit mode::
   -device cxl-type3,bus=swport3,volatile-memdev=cxl-mem3,id=cxl-mem3,sn=0x4 \
   -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k
 
+Unordered I/O (UIO) Support
+---------------------------
+CXL 3.2 and PCIe 6.1 introduce Unordered I/O (UIO), which allows memory
+transactions to bypass strict ordering requirements, potentially improving
+performance for certain workloads. UIO support builds on three
+coordinated features:
+
+1. **256-byte Flit Mode**: Enabled via ``x-256b-flit=on`` on all ports
+   and devices in the UIO path
+2. **Streamlined Virtual Channel (SVC)**: Enabled via ``x-svc`` on all ports
+   and CXL type3 device. SVC is a PCIe extended capability
+   (PCIe 6.4 section 7.9.29) that provides dedicated virtual channels for
+   UIO traffic.
+3. **Device 3 Extended Capability**: Enabled via ``x-uio`` on the CXL type3
+   device. Device 3 is a PCIe extended capability (PCIe 6.4 section 7.7.9)
+   that advertises a device's UIO requester/completer support. ``x-uio``
+   works together with the ``x-svc`` and ``x-256b-flit`` options: the
+   device carries the UIO capability when all three are set.
+
+``x-uio`` is also accepted by the ``pxb-cxl`` host bridge: it sets the
+UIO Capable bit of the host bridge HDM decoder capability. Each root
+port within the host bridge completes the advertisement, reporting the
+UIO Capable bit of its own HDM decoder capability when the host bridge
+carries ``x-uio`` and its own ``x-svc`` and ``x-256b-flit`` options
+are set.
+
+An example of 3 type3 devices with volatile memory below a switch. All the
+devices and ports support the Unordered IO (UIO) feature, which builds on
+the Streamlined Virtual Channel (SVC) capability, the Device 3 capability
+and 256-byte flit mode::
+
+  qemu-system-x86_64 -M q35,cxl=on -m 4G,maxmem=8G,slots=8 -smp 4 \
+  ...
+  -object memory-backend-ram,id=target-mem1,size=512M \
+  -object memory-backend-ram,id=target-mem2,size=512M \
+  -object memory-backend-ram,id=target-mem3,size=512M \
+  -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1,x-uio=on \
+  -device cxl-rp,port=0,bus=cxl.1,id=rp13,chassis=0,slot=0,x-svc=on,x-256b-flit=on,x-speed=64,x-width=16 \
+  -device cxl-rp,port=1,bus=cxl.1,id=root_port1,chassis=0,slot=1,x-svc=on,x-256b-flit=on,x-speed=64,x-width=16 \
+  -device cxl-upstream,port=2,sn=1234,bus=rp13,id=us0,x-svc=on,x-256b-flit=on,x-speed=64,x-width=16 \
+  -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4,x-svc=on,x-256b-flit=on,x-speed=64,x-width=16 \
+  -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5,x-svc=on,x-256b-flit=on,x-speed=64,x-width=16 \
+  -device cxl-downstream,port=2,bus=us0,id=swport2,chassis=0,slot=6,x-svc=on,x-256b-flit=on,x-speed=64,x-width=16 \
+  -device cxl-type3,id=mem1,bus=swport0,volatile-memdev=target-mem1,x-uio=on,x-svc=on,x-256b-flit=on,sn=1233 \
+  -device cxl-type3,id=mem2,bus=swport1,volatile-memdev=target-mem2,x-uio=on,x-svc=on,x-256b-flit=on,sn=1234 \
+  -device cxl-type3,id=mem3,bus=swport2,volatile-memdev=target-mem3,x-uio=on,x-svc=on,x-256b-flit=on,sn=1235 \
+  -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k
+
 A simple arm/virt example featuring a single direct connected CXL Type 3
 Volatile Memory device::
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH qemu v1 3/8] hw/cxl: Wire UIO capability into HDM decoder and DVSEC registers
  2026-11-04 11:52   ` [PATCH qemu v1 3/8] hw/cxl: Wire UIO capability into HDM decoder and DVSEC registers Shrihari E S
@ 2026-11-04 17:25     ` Junjie Cao
  0 siblings, 0 replies; 12+ messages in thread
From: Junjie Cao @ 2026-11-04 17:25 UTC (permalink / raw)
  To: shrihari.s
  Cc: jic23, linux-cxl, linux-pci, qemu-devel, anisa.su887, mst,
	marcel.apfelbaum, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Hi Shrihari,

The switch/HB write mask opens UIG and UIW, but leaves ISP read-only.
CXL 3.2 section 8.2.4.20.7 makes ISP writable on a UIO-capable switch
or Host Bridge too.

With two UIO-enabled host bridges in a two-way CFMWS (4 KiB granularity),
the switch below the second HB advertises UIO, but writing decoder 0
Control with UIO=1, UIG=4, UIW=1 (two ways), ISP=1 reads back
0x00144000 rather than 0x01144000. Software cannot configure the second
position in the interleave set.

Could R_CXL_HDM_DECODER0_CTRL_ISP_MASK be included alongside UIG and UIW
in that switch/HB branch?

It may also be worth diagnosing a partially configured host bridge:
with x-uio=on and two RPs, one without SVC/flit, the HB reads 0x22382
but that RP reads 0x312. The HB UIO bit is defined to cover all its
root ports (8.2.4.20.1). A warning would make this inconsistent setup
easier to spot.

Many thanks,
Junjie

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH qemu v1 4/8] hw/pci: Add PCIe Streamlined Virtual Channel (SVC) capability
  2026-11-04 11:52   ` [PATCH qemu v1 4/8] hw/pci: Add PCIe Streamlined Virtual Channel (SVC) capability Shrihari E S
@ 2026-11-04 17:25     ` Junjie Cao
  0 siblings, 0 replies; 12+ messages in thread
From: Junjie Cao @ 2026-11-04 17:25 UTC (permalink / raw)
  To: shrihari.s
  Cc: jic23, linux-cxl, linux-pci, qemu-devel, anisa.su887, mst,
	marcel.apfelbaum, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Hi Shrihari,

The protocol-selection checks now reject the bad writes from my previous
review. The TC/VC map defaults need another change, though.

On 3c99db7705c1 plus this series, Resource Control sets 1 and 2 read
zero at cold boot and after a system reset on the tested CXL root,
upstream and downstream ports and Type-3 devices. PCIe 6.2 section
7.9.29.7 requires the TC/VC Map default to match Table 2-46:
TC3 to VC3 and TC4 to VC4.

Software that keeps the default map and only selects UIO and sets VC
Enable writes 0x80000200, which reads back 0x200. Restoring defaults
of 0x08 and 0x10 makes that read-modify-write produce 0x80000208 and
0x80000210; both then retain VC Enable.

Could init and reset restore those map bits while leaving VC Enable
clear?

Many thanks,
Junjie

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH qemu v1 5/8] hw/pci: Wire SVC initialization into port realize functions
  2026-11-04 11:52   ` [PATCH qemu v1 5/8] hw/pci: Wire SVC initialization into port realize functions Shrihari E S
@ 2026-11-04 17:25     ` Junjie Cao
  0 siblings, 0 replies; 12+ messages in thread
From: Junjie Cao @ 2026-11-04 17:25 UTC (permalink / raw)
  To: shrihari.s
  Cc: jic23, linux-cxl, linux-pci, qemu-devel, anisa.su887, mst,
	marcel.apfelbaum, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Tested port capability enumeration and CXL RP/USP UIO gating on q35
at cold boot and after system reset, with the full series on
3c99db7705c1. The ioh3420,x-svc=on case reports an error instead of
aborting.

Also checked the CXL capability chains and USP HDM UIO advertisement
on aarch64 virt using qtest.

Tested-by: Junjie Cao <junjie.cao@linux.dev>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH qemu v1 7/8] hw/cxl: Wire SVC and Dev3 capabilities to CXL Type 3 device
  2026-11-04 11:52   ` [PATCH qemu v1 7/8] hw/cxl: Wire SVC and Dev3 capabilities to CXL Type 3 device Shrihari E S
@ 2026-11-04 17:25     ` Junjie Cao
  0 siblings, 0 replies; 12+ messages in thread
From: Junjie Cao @ 2026-11-04 17:25 UTC (permalink / raw)
  To: shrihari.s
  Cc: jic23, linux-cxl, linux-pci, qemu-devel, anisa.su887, mst,
	marcel.apfelbaum, arun.george, cpgs, dave, dongjoo.seo1, gost.dev,
	s.neeraj, vikash.k5, anisa.su, junjie.cao

Tested Type-3 capability enumeration and UIO/SVC/flit dependency
combinations at cold boot and after system reset on q35, with the
full series on 3c99db7705c1.

Linux UIO discovery and a 1-way UIO region commit also passed with
Davidlohr's pcie-uio-rfc kernel [1]. For that kernel's UIO checks,
QEMU used hdm-db=on and CFMWS restrictions=0x2d; the guest kernel
enabled CONFIG_CXL_REGION_INVALIDATION_TEST to allow region setup
in the VM.

[1] https://github.com/davidlohr/linux/commit/4726547f45a612b2d953f5f4e13ab6fe34672c7c

Tested-by: Junjie Cao <junjie.cao@linux.dev>

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-11-04 17:25 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CGME20261104113014epcas5p1dbf4b09e2849d28b46eb39db7990a54f@epcas5p1.samsung.com>
     [not found] ` <20261104115242.2035807-1-shrihari.s@samsung.com>
2026-11-04 11:52   ` [PATCH qemu v1 1/8] hw/pci: Refactor flitmode from PCIESlot to PCIEPort Shrihari E S
2026-11-04 11:52   ` [PATCH qemu v1 2/8] hw/pci: Move 'x-256b-flit' property from cxl_root_port to pcie_root_port Shrihari E S
2026-11-04 11:52   ` [PATCH qemu v1 3/8] hw/cxl: Wire UIO capability into HDM decoder and DVSEC registers Shrihari E S
2026-11-04 17:25     ` Junjie Cao
2026-11-04 11:52   ` [PATCH qemu v1 4/8] hw/pci: Add PCIe Streamlined Virtual Channel (SVC) capability Shrihari E S
2026-11-04 17:25     ` Junjie Cao
2026-11-04 11:52   ` [PATCH qemu v1 5/8] hw/pci: Wire SVC initialization into port realize functions Shrihari E S
2026-11-04 17:25     ` Junjie Cao
2026-11-04 11:52   ` [PATCH qemu v1 6/8] hw/pci: Add PCIe Device3 capability support Shrihari E S
2026-11-04 11:52   ` [PATCH qemu v1 7/8] hw/cxl: Wire SVC and Dev3 capabilities to CXL Type 3 device Shrihari E S
2026-11-04 17:25     ` Junjie Cao
2026-11-04 11:52   ` [PATCH qemu v1 8/8] cxl: Add documentation for CXL UIO support Shrihari E S

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.