]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: endpoint: pci-epf-test: Allow overriding default BAR sizes
authorNiklas Cassel <cassel@kernel.org>
Fri, 30 Jan 2026 11:30:39 +0000 (12:30 +0100)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 30 Jan 2026 17:17:09 +0000 (11:17 -0600)
Add bar{0,1,2,3,4,5}_size attributes in configfs, so that the user is not
restricted to run pci-epf-test with the hardcoded BAR size values defined
in pci-epf-test.c.

This code is shamelessly more or less copy pasted from pci-epf-vntb.c

Signed-off-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Koichiro Den <den@valinux.co.jp>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260130113038.2143947-2-cassel@kernel.org
Documentation/PCI/endpoint/pci-test-howto.rst
drivers/pci/endpoint/functions/pci-epf-test.c

index dd66858cde46270a50b05050c6016f8e8704d469..a822866b1fb0ac726d0296196320b2a5f7e5524d 100644 (file)
@@ -84,6 +84,25 @@ device, the following commands can be used::
        # echo 32 > functions/pci_epf_test/func1/msi_interrupts
        # echo 2048 > functions/pci_epf_test/func1/msix_interrupts
 
+By default, pci-epf-test uses the following BAR sizes::
+
+       # grep . functions/pci_epf_test/func1/pci_epf_test.0/bar?_size
+         functions/pci_epf_test/func1/pci_epf_test.0/bar0_size:131072
+         functions/pci_epf_test/func1/pci_epf_test.0/bar1_size:131072
+         functions/pci_epf_test/func1/pci_epf_test.0/bar2_size:131072
+         functions/pci_epf_test/func1/pci_epf_test.0/bar3_size:131072
+         functions/pci_epf_test/func1/pci_epf_test.0/bar4_size:131072
+         functions/pci_epf_test/func1/pci_epf_test.0/bar5_size:1048576
+
+The user can override a default value using e.g.::
+       # echo 1048576 > functions/pci_epf_test/func1/pci_epf_test.0/bar1_size
+
+Overriding the default BAR sizes can only be done before binding the
+pci-epf-test device to a PCI endpoint controller driver.
+
+Note: Some endpoint controllers might have fixed-size BARs or reserved BARs;
+for such controllers, the corresponding BAR size in configfs will be ignored.
+
 
 Binding pci-epf-test Device to EP Controller
 --------------------------------------------
index 1cc630a2ee750168bb227ff6fd0600be8a7d91b1..6952ee4186224092f66294a00dd9e7e4994f0087 100644 (file)
@@ -72,6 +72,7 @@ static struct workqueue_struct *kpcitest_workqueue;
 struct pci_epf_test {
        void                    *reg[PCI_STD_NUM_BARS];
        struct pci_epf          *epf;
+       struct config_group     group;
        enum pci_barno          test_reg_bar;
        size_t                  msix_table_offset;
        struct delayed_work     cmd_handler;
@@ -85,6 +86,7 @@ struct pci_epf_test {
        bool                    dma_private;
        const struct pci_epc_features *epc_features;
        struct pci_epf_bar      db_bar;
+       size_t                  bar_size[PCI_STD_NUM_BARS];
 };
 
 struct pci_epf_test_reg {
@@ -111,7 +113,8 @@ static struct pci_epf_header test_header = {
        .interrupt_pin  = PCI_INTERRUPT_INTA,
 };
 
-static size_t bar_size[] = { 131072, 131072, 131072, 131072, 131072, 1048576 };
+/* default BAR sizes, can be overridden by the user using configfs */
+static size_t default_bar_size[] = { 131072, 131072, 131072, 131072, 131072, 1048576 };
 
 static void pci_epf_test_dma_callback(void *param)
 {
@@ -1240,7 +1243,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
                if (epc_features->bar[bar].type == BAR_FIXED)
                        test_reg_size = epc_features->bar[bar].fixed_size;
                else
-                       test_reg_size = bar_size[bar];
+                       test_reg_size = epf_test->bar_size[bar];
 
                base = pci_epf_alloc_space(epf, test_reg_size, bar,
                                           epc_features, PRIMARY_INTERFACE);
@@ -1312,6 +1315,94 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
        pci_epf_test_free_space(epf);
 }
 
+#define PCI_EPF_TEST_BAR_SIZE_R(_name, _id)                            \
+static ssize_t pci_epf_test_##_name##_show(struct config_item *item,   \
+                                          char *page)                  \
+{                                                                      \
+       struct config_group *group = to_config_group(item);             \
+       struct pci_epf_test *epf_test =                                 \
+               container_of(group, struct pci_epf_test, group);        \
+                                                                       \
+       return sysfs_emit(page, "%zu\n", epf_test->bar_size[_id]);      \
+}
+
+#define PCI_EPF_TEST_BAR_SIZE_W(_name, _id)                            \
+static ssize_t pci_epf_test_##_name##_store(struct config_item *item,  \
+                                           const char *page,           \
+                                           size_t len)                 \
+{                                                                      \
+       struct config_group *group = to_config_group(item);             \
+       struct pci_epf_test *epf_test =                                 \
+               container_of(group, struct pci_epf_test, group);        \
+       int val, ret;                                                   \
+                                                                       \
+       /*                                                              \
+        * BAR sizes can only be modified before binding to an EPC,     \
+        * because pci_epf_test_alloc_space() is called in .bind().     \
+        */                                                             \
+       if (epf_test->epf->epc)                                         \
+               return -EOPNOTSUPP;                                     \
+                                                                       \
+       ret = kstrtouint(page, 0, &val);                                \
+       if (ret)                                                        \
+               return ret;                                             \
+                                                                       \
+       if (!is_power_of_2(val))                                        \
+               return -EINVAL;                                         \
+                                                                       \
+       epf_test->bar_size[_id] = val;                                  \
+                                                                       \
+       return len;                                                     \
+}
+
+PCI_EPF_TEST_BAR_SIZE_R(bar0_size, BAR_0)
+PCI_EPF_TEST_BAR_SIZE_W(bar0_size, BAR_0)
+PCI_EPF_TEST_BAR_SIZE_R(bar1_size, BAR_1)
+PCI_EPF_TEST_BAR_SIZE_W(bar1_size, BAR_1)
+PCI_EPF_TEST_BAR_SIZE_R(bar2_size, BAR_2)
+PCI_EPF_TEST_BAR_SIZE_W(bar2_size, BAR_2)
+PCI_EPF_TEST_BAR_SIZE_R(bar3_size, BAR_3)
+PCI_EPF_TEST_BAR_SIZE_W(bar3_size, BAR_3)
+PCI_EPF_TEST_BAR_SIZE_R(bar4_size, BAR_4)
+PCI_EPF_TEST_BAR_SIZE_W(bar4_size, BAR_4)
+PCI_EPF_TEST_BAR_SIZE_R(bar5_size, BAR_5)
+PCI_EPF_TEST_BAR_SIZE_W(bar5_size, BAR_5)
+
+CONFIGFS_ATTR(pci_epf_test_, bar0_size);
+CONFIGFS_ATTR(pci_epf_test_, bar1_size);
+CONFIGFS_ATTR(pci_epf_test_, bar2_size);
+CONFIGFS_ATTR(pci_epf_test_, bar3_size);
+CONFIGFS_ATTR(pci_epf_test_, bar4_size);
+CONFIGFS_ATTR(pci_epf_test_, bar5_size);
+
+static struct configfs_attribute *pci_epf_test_attrs[] = {
+       &pci_epf_test_attr_bar0_size,
+       &pci_epf_test_attr_bar1_size,
+       &pci_epf_test_attr_bar2_size,
+       &pci_epf_test_attr_bar3_size,
+       &pci_epf_test_attr_bar4_size,
+       &pci_epf_test_attr_bar5_size,
+       NULL,
+};
+
+static const struct config_item_type pci_epf_test_group_type = {
+       .ct_attrs       = pci_epf_test_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+static struct config_group *pci_epf_test_add_cfs(struct pci_epf *epf,
+                                                struct config_group *group)
+{
+       struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+       struct config_group *epf_group = &epf_test->group;
+       struct device *dev = &epf->dev;
+
+       config_group_init_type_name(epf_group, dev_name(dev),
+                                   &pci_epf_test_group_type);
+
+       return epf_group;
+}
+
 static const struct pci_epf_device_id pci_epf_test_ids[] = {
        {
                .name = "pci_epf_test",
@@ -1324,6 +1415,7 @@ static int pci_epf_test_probe(struct pci_epf *epf,
 {
        struct pci_epf_test *epf_test;
        struct device *dev = &epf->dev;
+       enum pci_barno bar;
 
        epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL);
        if (!epf_test)
@@ -1331,6 +1423,8 @@ static int pci_epf_test_probe(struct pci_epf *epf,
 
        epf->header = &test_header;
        epf_test->epf = epf;
+       for (bar = BAR_0; bar < PCI_STD_NUM_BARS; bar++)
+               epf_test->bar_size[bar] = default_bar_size[bar];
 
        INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
 
@@ -1343,6 +1437,7 @@ static int pci_epf_test_probe(struct pci_epf *epf,
 static const struct pci_epf_ops ops = {
        .unbind = pci_epf_test_unbind,
        .bind   = pci_epf_test_bind,
+       .add_cfs = pci_epf_test_add_cfs,
 };
 
 static struct pci_epf_driver test_driver = {