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
next prev 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