Linux CXL
 help / color / mirror / Atom feed
From: Shrihari E S <shrihari.s@samsung.com>
To: jic23@kernel.org, junjie.cao@intel.com,
	linux-cxl@vger.kernel.org, linux-pci@vger.kernel.org,
	qemu-devel@nongnu.org
Cc: shrihari.s@samsung.com, arun.george@samsung.com,
	cpgs@samsung.com, dave@stgolabs.net, dongjoo.seo1@samsung.com,
	gost.dev@samsung.com, s.neeraj@samsung.com,
	vikash.k5@samsung.com
Subject: [RFC V2 08/10] hw/pci: Add PCIe Device3 capability support
Date: Wed, 26 Aug 2026 11:04:08 +0530	[thread overview]
Message-ID: <2044366277.121787732104098.JavaMail.epsvc@epcpadp1new> (raw)
In-Reply-To: <20260826053410.1322176-1-shrihari.s@samsung.com>

This commit adds Device3 support to the PCIe devices, with which
an endpoint can be exposed as a UIO requester or completer, based
on its configuration.

Signed-off-by: Shrihari E S <shrihari.s@samsung.com>
Signed-off-by: Dongjoo Seo <dongjoo.seo1@samsung.com>
---
 hw/mem/cxl_type3.c         |   1 +
 hw/pci/meson.build         |   2 +-
 hw/pci/pci.c               |   2 +
 hw/pci/pcie.c              |  30 +++++++
 hw/pci/pcie_dev3.c         | 165 +++++++++++++++++++++++++++++++++++++
 include/hw/pci/pcie.h      |   6 ++
 include/hw/pci/pcie_dev3.h |  29 +++++++
 include/hw/pci/pcie_regs.h |  30 +++++++
 8 files changed, 264 insertions(+), 1 deletion(-)
 create mode 100644 hw/pci/pcie_dev3.c
 create mode 100644 include/hw/pci/pcie_dev3.h

diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 24bf4f8309..0adf2e8b3e 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"
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 0469250f42..600f41fc95 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -570,6 +570,7 @@ static void pci_do_device_reset(PCIDevice *dev)
     msix_reset(dev);
     pcie_sriov_pf_reset(dev);
     pcie_svc_cap_reset(dev);
+    pcie_dev3_cap_reset(dev);
 }
 
 /*
@@ -1818,6 +1819,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, val_in, 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 cc1cc500ab..6b8cc0f948 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;
+}
+
 void pcie_cap_flit_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
                                 int len)
 {
@@ -223,6 +249,10 @@ void pcie_cap_flit_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
     }
 
     pci_set_word(exp_cap + PCI_EXP_LNKSTA2, lnksta2);
+    if (dev->exp.dev3_cap) {
+        pcie_dev3_cap_flit_update(dev);
+    }
+
  }
 
 static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
diff --git a/hw/pci/pcie_dev3.c b/hw/pci/pcie_dev3.c
new file mode 100644
index 0000000000..d6794bd3fe
--- /dev/null
+++ b/hw/pci/pcie_dev3.c
@@ -0,0 +1,165 @@
+/*
+ * 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"
+
+static uint32_t pcie_dev3_cap_offset(PCIDevice *dev)
+{
+    return dev->exp.dev3_cap;
+}
+
+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);
+    pci_set_long(dev->config + offset + PCI_DEV3_CAP_HEAD,
+                 (PCI_DEV3_CAP_ID | PCI_DEV3_CAP_VER |
+                  PCI_DEV3_NEXT_CAP_OFF));
+    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;
+        /*
+         * A UIO requester must be able to issue DMA transactions.
+         * Enable PCI_COMMAND_MASTER in the PCI command register so the
+         * device's bus master bit is set when the requester capability
+         * is advertised.
+         */
+        pci_set_word(dev->config + PCI_COMMAND,
+                     pci_get_word(dev->config + PCI_COMMAND) |
+                     PCI_COMMAND_MASTER);
+    }
+
+    pci_set_long(dev->config + offset + PCI_DEV3_CAP_OFFSET, devcap3);
+    pci_set_long(dev->wmask + offset + PCI_DEV3_CTL_OFFSET, wmask);
+
+    return 0;
+}
+
+void pcie_dev3_cap_reset(PCIDevice *dev)
+{
+    uint32_t off = pcie_dev3_cap_offset(dev);
+
+    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_apply_gating(dev);
+}
+
+void pcie_dev3_apply_gating(PCIDevice *dev)
+{
+    uint32_t off = pcie_dev3_cap_offset(dev);
+    uint32_t devctl3;
+    uint32_t devsta3;
+    bool flit;
+
+    if (!off) {
+        return;
+    }
+
+    flit = pcie_link_flit_active(dev);
+    devctl3 = pci_get_long(dev->config + off + PCI_DEV3_CTL_OFFSET);
+    devsta3 = pci_get_long(dev->config + off + PCI_DEV3_STA_OFFSET);
+    if (!dev->exp.dev3.uio_req || !flit) {
+        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);
+    }
+
+    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_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len)
+{
+    uint32_t off = pcie_dev3_cap_offset(dev);
+
+    if (!off) {
+        return;
+    }
+
+    if (ranges_overlap(addr, len, off + PCI_DEV3_CTL_OFFSET, 4)) {
+        pcie_dev3_apply_gating(dev);
+    }
+}
+
+void pcie_dev3_cap_flit_update(PCIDevice *dev)
+{
+    uint32_t off = pcie_dev3_cap_offset(dev);
+    if (!off) {
+        return;
+    }
+
+    uint32_t devsta3 = pci_get_long(dev->config + off + PCI_DEV3_STA_OFFSET);
+    if (pcie_link_flit_active(dev)) {
+        devsta3 |= PCI_DEV3_STA_SEGMENT_CAP;
+    } else {
+        devsta3 &= ~PCI_DEV3_STA_SEGMENT_CAP;
+    }
+    pci_set_long(dev->config + off + PCI_DEV3_STA_OFFSET, devsta3);
+}
+
+bool pcie_dev3_uio_enabled(PCIDevice *dev)
+{
+    uint32_t off = pcie_dev3_cap_offset(dev);
+    uint32_t devctl3;
+
+    if (!off || !dev->exp.dev3.uio_req || !pcie_link_flit_active(dev)) {
+        return false;
+    }
+
+    devctl3 = pci_get_long(dev->config + off + PCI_DEV3_CTL_OFFSET);
+    return devctl3 & PCI_DEV3_CTL_UIO_REQ_EN;
+}
+
+bool pcie_dev3_tag_req_enabled(PCIDevice *dev)
+{
+    uint32_t off = pcie_dev3_cap_offset(dev);
+    uint32_t devctl3;
+
+    if (!off || !dev->exp.dev3.uio_req || !pcie_link_flit_active(dev)) {
+        return false;
+    }
+
+    devctl3 = pci_get_long(dev->config + off + PCI_DEV3_CTL_OFFSET);
+    return devctl3 & PCI_DEV3_CTL_TAG_REQ_EN;
+}
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
index 2feeb022f0..e997f3a456 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;
@@ -87,6 +88,10 @@ struct PCIExpressDevice {
     /* Streamlined Virtual Channel (SVC) introduced from PCIe 6.1 */
     uint32_t svc_cap;
     PCIESvcCap svc;
+
+    /* PCIe Device 3 Capability */
+    uint32_t dev3_cap;
+    struct PCIEDev3Cap dev3;
 };
 
 #define COMPAT_PROP_PCP "power_controller_present"
@@ -150,6 +155,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, uint32_t val, int len);
+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..0a49835ab4
--- /dev/null
+++ b/include/hw/pci/pcie_dev3.h
@@ -0,0 +1,29 @@
+/*
+ * 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);
+bool pcie_dev3_uio_enabled(PCIDevice *dev);
+bool pcie_dev3_tag_req_enabled(PCIDevice *dev);
+void pcie_dev3_apply_gating(PCIDevice *dev);
+
+#endif /* HW_PCIE_DEV3_H */
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
index 566754646c..326195a199 100644
--- a/include/hw/pci/pcie_regs.h
+++ b/include/hw/pci/pcie_regs.h
@@ -237,4 +237,34 @@ 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 */
+#define PCI_EXT_CAP_ID_DEV3 0x2f
+
+#define PCI_DEV3_CAP_HEAD              0x00
+#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.1 Device 3 Extended Capability Header. */
+#define PCI_DEV3_CAP_ID                (0x2f << 0)
+#define PCI_DEV3_CAP_VER               (0x1 << 16)
+#define PCI_DEV3_NEXT_CAP_OFF          (0x0 << 20)
+
+/* Section 7.7.9.3 Device 3 capability 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



  parent reply	other threads:[~2026-08-26  8:15 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20260826052014epcas5p11846c6a40fcec4ec4ba441ceb26e5dcc@epcas5p1.samsung.com>
     [not found] ` <20260826053410.1322176-1-shrihari.s@samsung.com>
2026-08-26  5:34   ` [RFC V2 01/10] hw/pci: Refactor flitmode from PCIESlot to PCIEPort Shrihari E S
2026-08-26  5:34   ` [RFC V2 02/10] hw/pci: Move 'x-256b-flit' property from cxl_root_port to pcie_root_port Shrihari E S
2026-08-26  5:34   ` [RFC V2 03/10] hw/pci: Add SVC capability and UIO properties to PCIe ports Shrihari E S
2026-08-26  5:34   ` [RFC V2 04/10] hw/cxl: Add Streamlined Virtual Channel (SVC) property to CXL ports Shrihari E S
2026-08-26  5:34   ` [RFC V2 05/10] hw/cxl: Wire UIO capability into HDM decoder and DVSEC registers Shrihari E S
2026-08-26  5:34   ` [RFC V2 06/10] hw/pci: Add PCIe Streamlined Virtual Channel (SVC) capability Shrihari E S
2026-08-26  5:34   ` [RFC V2 07/10] hw/pci: hw/cxl: Wire SVC initialization into port realize functions Shrihari E S
2026-08-26  5:34   ` Shrihari E S [this message]
2026-08-26  5:34   ` [RFC V2 09/10] hw/cxl: Wire SVC and Dev3 capability to CXL Type 3 device Shrihari E S
2026-08-26  5:34   ` [RFC V2 10/10] cxl: Add documentation for CXL UIO support Shrihari E S

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2044366277.121787732104098.JavaMail.epsvc@epcpadp1new \
    --to=shrihari.s@samsung.com \
    --cc=arun.george@samsung.com \
    --cc=cpgs@samsung.com \
    --cc=dave@stgolabs.net \
    --cc=dongjoo.seo1@samsung.com \
    --cc=gost.dev@samsung.com \
    --cc=jic23@kernel.org \
    --cc=junjie.cao@intel.com \
    --cc=linux-cxl@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=qemu-devel@nongnu.org \
    --cc=s.neeraj@samsung.com \
    --cc=vikash.k5@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox