[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