[PATCH 11/11] PCI: endpoint: pci-epf-vntb: Expose packed MWs through configfs

Koichiro Den <[email protected]> Tue, 4 Aug 2026 03:04:38 +0900
Newsgroups dev.linux.lists.ntb,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <[email protected]>
The packed MW data path is now complete. Add packed_mws to enable it and
allow up to 16 logical MWs when packing is selected.

Use mw1 as the aggregate BAR size and restrict the other MW size and BAR
attributes while packing is enabled.

Signed-off-by: Koichiro Den <[email protected]>
---
 Documentation/PCI/endpoint/pci-vntb-howto.rst | 16 ++++-
 drivers/pci/endpoint/functions/pci-epf-vntb.c | 60 ++++++++++++++++++-
 2 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst
index 3679f5c30254..8c74a39f1aee 100644
--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst
+++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst
@@ -92,7 +92,7 @@ attributes that can be configured by the user::
 	# ls functions/pci_epf_vntb/func1/pci_epf_vntb.0/
 	ctrl_bar  db_count  mw1_bar  mw2_bar  mw3_bar  mw4_bar	spad_count
 	db_bar	  mw1	    mw2      mw3      mw4      num_mws	vbus_number
-	vntb_vid  vntb_pid
+	vntb_vid  vntb_pid  packed_mws
 
 A sample configuration for NTB function is given below::
 
@@ -105,6 +105,20 @@ By default, each construct is assigned a BAR, as needed and in order.
 Should a specific BAR setup be required by the platform, BAR may be assigned
 to each construct using the related ``XYZ_bar`` entry.
 
+Without packing, ``num_mws`` is limited to four and each memory window uses
+its corresponding ``mwN`` size and ``mwN_bar``. To expose 2, 4, 8, or 16
+logical memory windows in one BAR, set ``packed_mws`` to the same value as
+``num_mws``. In that mode, ``mw1`` is the aggregate BAR size and must be a
+power of two no larger than 2 GiB. It is divided equally
+into 4 KiB-aligned logical windows, and ``mw1_bar`` is their shared BAR. The
+``mw2`` through ``mw4`` entries report the logical window size when in range
+and reject writes.
+
+Packed MWs require an NTB client that uses MW translation group operations;
+``ntb_transport`` supports them. Per-MW size limiting through its
+``max_mw_size`` parameter is not supported. ``ntb_transport`` also needs four
+control scratchpads plus two scratchpads per logical MW.
+
 A sample configuration for virtual NTB driver for virtual PCI bus::
 
 	# echo 0x1957 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_vid
diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 526cc31d9435..2f6af0306563 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -1295,6 +1295,7 @@ static ssize_t epf_ntb_##_name##_show(struct config_item *item,		\
 	struct config_group *group = to_config_group(item);		\
 	struct epf_ntb *ntb = to_epf_ntb(group);			\
 	struct device *dev = &ntb->epf->dev;				\
+	u32 packed_mws;							\
 	int win_no, idx;						\
 									\
 	if (sscanf(#_name, "mw%d", &win_no) != 1)			\
@@ -1306,6 +1307,14 @@ static ssize_t epf_ntb_##_name##_show(struct config_item *item,		\
 			win_no, ntb->num_mws);				\
 		return -ERANGE;						\
 	}								\
+	packed_mws = ntb->packed_mws;					\
+	if (packed_mws && idx > 0) {					\
+		u64 size = ntb->mws_size[0];				\
+									\
+		if (size % packed_mws)					\
+			return -EINVAL;					\
+		return sprintf(page, "%llu\n", size / packed_mws);	\
+	}								\
 	idx = array_index_nospec(idx, ntb->num_mws);			\
 	return sprintf(page, "%llu\n", ntb->mws_size[idx]);		\
 }
@@ -1337,6 +1346,8 @@ static ssize_t epf_ntb_##_name##_store(struct config_item *item,	\
 			win_no, ntb->num_mws);				\
 		return -ERANGE;						\
 	}								\
+	if (ntb->packed_mws && idx > 0)					\
+		return -EINVAL;						\
 	idx = array_index_nospec(idx, ntb->num_mws);			\
 	ntb->mws_size[idx] = val;					\
 									\
@@ -1372,6 +1383,9 @@ static ssize_t epf_ntb_##_name##_store(struct config_item *item,	\
 		if (val < NO_BAR || val > BAR_5)			\
 			return -EINVAL;					\
 									\
+		if (ntb->packed_mws && _id >= BAR_MW2)			\
+			return -EINVAL;					\
+									\
 		ntb->epf_ntb_bar[_id] = val;				\
 									\
 		return len;						\
@@ -1392,7 +1406,10 @@ static ssize_t epf_ntb_num_mws_store(struct config_item *item,
 	if (ret)
 		return ret;
 
-	if (val > MAX_MW)
+	if (val > EPF_NTB_MAX_MW)
+		return -EINVAL;
+
+	if (ntb->packed_mws && val != ntb->packed_mws)
 		return -EINVAL;
 
 	ntb->num_mws = val;
@@ -1400,6 +1417,44 @@ static ssize_t epf_ntb_num_mws_store(struct config_item *item,
 	return len;
 }
 
+static ssize_t epf_ntb_packed_mws_store(struct config_item *item,
+					const char *page, size_t len)
+{
+	struct config_group *group = to_config_group(item);
+	struct epf_ntb *ntb = to_epf_ntb(group);
+	u32 val;
+	int ret;
+	int i;
+
+	if (epf_ntb_epc_attached(ntb))
+		return -EOPNOTSUPP;
+
+	ret = kstrtou32(page, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val > EPF_NTB_MAX_MW ||
+	    (val && (val < 2 || !is_power_of_2(val))))
+		return -EINVAL;
+
+	if (val && ntb->num_mws && val != ntb->num_mws)
+		return -EINVAL;
+
+	if (val) {
+		for (i = 1; i < MAX_MW; i++)
+			if (ntb->mws_size[i])
+				return -EINVAL;
+
+		for (i = BAR_MW2; i <= BAR_MW4; i++)
+			if (ntb->epf_ntb_bar[i] != NO_BAR)
+				return -EINVAL;
+	}
+
+	ntb->packed_mws = val;
+
+	return len;
+}
+
 static ssize_t epf_ntb_db_count_store(struct config_item *item,
 				      const char *page, size_t len)
 {
@@ -1427,6 +1482,7 @@ EPF_NTB_R(spad_count)
 EPF_NTB_W(spad_count)
 EPF_NTB_R(db_count)
 EPF_NTB_R(num_mws)
+EPF_NTB_R(packed_mws)
 EPF_NTB_R(vbus_number)
 EPF_NTB_W(vbus_number)
 EPF_NTB_R(vntb_pid)
@@ -1457,6 +1513,7 @@ EPF_NTB_BAR_W(mw4_bar, BAR_MW4)
 CONFIGFS_ATTR(epf_ntb_, spad_count);
 CONFIGFS_ATTR(epf_ntb_, db_count);
 CONFIGFS_ATTR(epf_ntb_, num_mws);
+CONFIGFS_ATTR(epf_ntb_, packed_mws);
 CONFIGFS_ATTR(epf_ntb_, mw1);
 CONFIGFS_ATTR(epf_ntb_, mw2);
 CONFIGFS_ATTR(epf_ntb_, mw3);
@@ -1475,6 +1532,7 @@ static struct configfs_attribute *epf_ntb_attrs[] = {
 	&epf_ntb_attr_spad_count,
 	&epf_ntb_attr_db_count,
 	&epf_ntb_attr_num_mws,
+	&epf_ntb_attr_packed_mws,
 	&epf_ntb_attr_mw1,
 	&epf_ntb_attr_mw2,
 	&epf_ntb_attr_mw3,
-- 
2.51.0