Add a new pci-epf-test command that exercises the newly added EPC API
pci_epc_get_remote_resources().
The test is intentionally a smoke test. It verifies that the API either
returns -EOPNOTSUPP or a well-formed resource list (non-zero phys/size
and known resource types). The result is reported to the host via a
status bit and an interrupt, consistent with existing pci-epf-test
commands.
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 88 +++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 6952ee418622..6446a0a23865 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -35,6 +35,7 @@
#define COMMAND_DISABLE_DOORBELL BIT(7)
#define COMMAND_BAR_SUBRANGE_SETUP BIT(8)
#define COMMAND_BAR_SUBRANGE_CLEAR BIT(9)
+#define COMMAND_EPC_API BIT(10)
#define STATUS_READ_SUCCESS BIT(0)
#define STATUS_READ_FAIL BIT(1)
@@ -54,6 +55,8 @@
#define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15)
#define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16)
#define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17)
+#define STATUS_EPC_API_SUCCESS BIT(18)
+#define STATUS_EPC_API_FAIL BIT(19)
#define FLAG_USE_DMA BIT(0)
@@ -967,6 +970,87 @@ static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test,
reg->status = cpu_to_le32(status);
}
+static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
+{
+ struct pci_epc_remote_resource *resources = NULL;
+ u32 status = le32_to_cpu(reg->status);
+ struct pci_epf *epf = epf_test->epf;
+ struct device *dev = &epf->dev;
+ struct pci_epc *epc = epf->epc;
+ int num_resources;
+ int ret, i;
+
+ num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
+ epf->vfunc_no, NULL, 0);
+ if (num_resources == -EOPNOTSUPP || num_resources == 0)
+ goto out_success;
+ if (num_resources < 0)
+ goto err;
+
+ resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
+ if (!resources)
+ goto err;
+
+ ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
+ resources, num_resources);
+ if (ret < 0) {
+ dev_err(dev, "EPC remote resource query failed: %d\n", ret);
+ goto err_free;
+ }
+ if (ret > num_resources) {
+ dev_err(dev, "EPC API returned %d resources (max %d)\n",
+ ret, num_resources);
+ goto err_free;
+ }
+
+ for (i = 0; i < ret; i++) {
+ struct pci_epc_remote_resource *res = &resources[i];
+
+ if (!res->phys_addr || !res->size) {
+ dev_err(dev,
+ "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
+ i, res->type, &res->phys_addr, res->size);
+ goto err_free;
+ }
+
+ /* Guard against address overflow */
+ if (res->phys_addr + res->size < res->phys_addr) {
+ dev_err(dev,
+ "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
+ i, &res->phys_addr, res->size);
+ goto err_free;
+ }
+
+ switch (res->type) {
+ case PCI_EPC_RR_DMA_CTRL_MMIO:
+ /* Generic checks above are sufficient. */
+ break;
+ case PCI_EPC_RR_DMA_CHAN_DESC:
+ /*
+ * hw_chan_id and ep2rc are informational. No extra validation
+ * beyond the generic checks above is needed.
+ */
+ break;
+ default:
+ dev_err(dev, "Unknown remote resource type %d\n", res->type);
+ goto err_free;
+ }
+ }
+
+out_success:
+ kfree(resources);
+ status |= STATUS_EPC_API_SUCCESS;
+ reg->status = cpu_to_le32(status);
+ return;
+
+err_free:
+ kfree(resources);
+err:
+ status |= STATUS_EPC_API_FAIL;
+ reg->status = cpu_to_le32(status);
+}
+
static void pci_epf_test_cmd_handler(struct work_struct *work)
{
u32 command;
@@ -1030,6 +1114,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
pci_epf_test_bar_subrange_clear(epf_test, reg);
pci_epf_test_raise_irq(epf_test, reg);
break;
+ case COMMAND_EPC_API:
+ pci_epf_test_epc_api(epf_test, reg);
+ pci_epf_test_raise_irq(epf_test, reg);
+ break;
default:
dev_err(dev, "Invalid command 0x%x\n", command);
break;
--
2.51.0
Hi Koichiro,
kernel test robot noticed the following build warnings:
[auto build test WARNING on pci/next]
[also build test WARNING on next-20260204]
[cannot apply to vkoul-dmaengine/next pci/for-linus linus/master v6.19-rc8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Koichiro-Den/dmaengine-Add-hw_id-to-dma_slave_caps/20260204-230604
base: https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link: https://lore.kernel.org/r/20260204145440.950609-10-den%40valinux.co.jp
patch subject: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
config: um-randconfig-001-20260205 (https://download.01.org/0day-ci/archive/20260205/202602051059.2bwjcYJE-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260205/202602051059.2bwjcYJE-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602051059.2bwjcYJE-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/pci/endpoint/functions/pci-epf-test.c:11:
In file included from include/linux/dmaengine.h:12:
In file included from include/linux/scatterlist.h:9:
In file included from arch/um/include/asm/io.h:24:
include/asm-generic/io.h:1209:55: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
1209 | return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port;
| ~~~~~~~~~~ ^
>> drivers/pci/endpoint/functions/pci-epf-test.c:1013:36: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
1012 | "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
| ~~~~
| %u
1013 | i, res->type, &res->phys_addr, res->size);
| ^~~~~~~~~
include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
drivers/pci/endpoint/functions/pci-epf-test.c:1021:25: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
1020 | "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
| ~~~~
| %u
1021 | i, &res->phys_addr, res->size);
| ^~~~~~~~~
include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
3 warnings generated.
vim +1013 drivers/pci/endpoint/functions/pci-epf-test.c
972
973 static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
974 struct pci_epf_test_reg *reg)
975 {
976 struct pci_epc_remote_resource *resources = NULL;
977 u32 status = le32_to_cpu(reg->status);
978 struct pci_epf *epf = epf_test->epf;
979 struct device *dev = &epf->dev;
980 struct pci_epc *epc = epf->epc;
981 int num_resources;
982 int ret, i;
983
984 num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
985 epf->vfunc_no, NULL, 0);
986 if (num_resources == -EOPNOTSUPP || num_resources == 0)
987 goto out_success;
988 if (num_resources < 0)
989 goto err;
990
991 resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
992 if (!resources)
993 goto err;
994
995 ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
996 resources, num_resources);
997 if (ret < 0) {
998 dev_err(dev, "EPC remote resource query failed: %d\n", ret);
999 goto err_free;
1000 }
1001 if (ret > num_resources) {
1002 dev_err(dev, "EPC API returned %d resources (max %d)\n",
1003 ret, num_resources);
1004 goto err_free;
1005 }
1006
1007 for (i = 0; i < ret; i++) {
1008 struct pci_epc_remote_resource *res = &resources[i];
1009
1010 if (!res->phys_addr || !res->size) {
1011 dev_err(dev,
1012 "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
> 1013 i, res->type, &res->phys_addr, res->size);
1014 goto err_free;
1015 }
1016
1017 /* Guard against address overflow */
1018 if (res->phys_addr + res->size < res->phys_addr) {
1019 dev_err(dev,
1020 "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
1021 i, &res->phys_addr, res->size);
1022 goto err_free;
1023 }
1024
1025 switch (res->type) {
1026 case PCI_EPC_RR_DMA_CTRL_MMIO:
1027 /* Generic checks above are sufficient. */
1028 break;
1029 case PCI_EPC_RR_DMA_CHAN_DESC:
1030 /*
1031 * hw_chan_id and ep2rc are informational. No extra validation
1032 * beyond the generic checks above is needed.
1033 */
1034 break;
1035 default:
1036 dev_err(dev, "Unknown remote resource type %d\n", res->type);
1037 goto err_free;
1038 }
1039 }
1040
1041 out_success:
1042 kfree(resources);
1043 status |= STATUS_EPC_API_SUCCESS;
1044 reg->status = cpu_to_le32(status);
1045 return;
1046
1047 err_free:
1048 kfree(resources);
1049 err:
1050 status |= STATUS_EPC_API_FAIL;
1051 reg->status = cpu_to_le32(status);
1052 }
1053
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Koichiro,
kernel test robot noticed the following build warnings:
[auto build test WARNING on pci/next]
[also build test WARNING on next-20260204]
[cannot apply to vkoul-dmaengine/next pci/for-linus linus/master v6.19-rc8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Koichiro-Den/dmaengine-Add-hw_id-to-dma_slave_caps/20260204-230604
base: https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link: https://lore.kernel.org/r/20260204145440.950609-10-den%40valinux.co.jp
patch subject: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
config: i386-randconfig-003-20260205 (https://download.01.org/0day-ci/archive/20260205/202602050741.nyI2oa7X-lkp@intel.com/config)
compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260205/202602050741.nyI2oa7X-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602050741.nyI2oa7X-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from include/linux/device.h:15,
from include/linux/dmaengine.h:8,
from drivers/pci/endpoint/functions/pci-epf-test.c:11:
drivers/pci/endpoint/functions/pci-epf-test.c: In function 'pci_epf_test_epc_api':
>> drivers/pci/endpoint/functions/pci-epf-test.c:1012:33: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 6 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
1012 | "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ^~~
include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~~
drivers/pci/endpoint/functions/pci-epf-test.c:1011:25: note: in expansion of macro 'dev_err'
1011 | dev_err(dev,
| ^~~~~~~
drivers/pci/endpoint/functions/pci-epf-test.c:1012:88: note: format string is defined here
1012 | "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
| ~~~^
| |
| long long unsigned int
| %u
drivers/pci/endpoint/functions/pci-epf-test.c:1020:33: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 5 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
1020 | "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ^~~
include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~~
drivers/pci/endpoint/functions/pci-epf-test.c:1019:25: note: in expansion of macro 'dev_err'
1019 | dev_err(dev,
| ^~~~~~~
drivers/pci/endpoint/functions/pci-epf-test.c:1020:81: note: format string is defined here
1020 | "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
| ~~~^
| |
| long long unsigned int
| %u
vim +1012 drivers/pci/endpoint/functions/pci-epf-test.c
972
973 static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
974 struct pci_epf_test_reg *reg)
975 {
976 struct pci_epc_remote_resource *resources = NULL;
977 u32 status = le32_to_cpu(reg->status);
978 struct pci_epf *epf = epf_test->epf;
979 struct device *dev = &epf->dev;
980 struct pci_epc *epc = epf->epc;
981 int num_resources;
982 int ret, i;
983
984 num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
985 epf->vfunc_no, NULL, 0);
986 if (num_resources == -EOPNOTSUPP || num_resources == 0)
987 goto out_success;
988 if (num_resources < 0)
989 goto err;
990
991 resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
992 if (!resources)
993 goto err;
994
995 ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
996 resources, num_resources);
997 if (ret < 0) {
998 dev_err(dev, "EPC remote resource query failed: %d\n", ret);
999 goto err_free;
1000 }
1001 if (ret > num_resources) {
1002 dev_err(dev, "EPC API returned %d resources (max %d)\n",
1003 ret, num_resources);
1004 goto err_free;
1005 }
1006
1007 for (i = 0; i < ret; i++) {
1008 struct pci_epc_remote_resource *res = &resources[i];
1009
1010 if (!res->phys_addr || !res->size) {
1011 dev_err(dev,
> 1012 "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
1013 i, res->type, &res->phys_addr, res->size);
1014 goto err_free;
1015 }
1016
1017 /* Guard against address overflow */
1018 if (res->phys_addr + res->size < res->phys_addr) {
1019 dev_err(dev,
1020 "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
1021 i, &res->phys_addr, res->size);
1022 goto err_free;
1023 }
1024
1025 switch (res->type) {
1026 case PCI_EPC_RR_DMA_CTRL_MMIO:
1027 /* Generic checks above are sufficient. */
1028 break;
1029 case PCI_EPC_RR_DMA_CHAN_DESC:
1030 /*
1031 * hw_chan_id and ep2rc are informational. No extra validation
1032 * beyond the generic checks above is needed.
1033 */
1034 break;
1035 default:
1036 dev_err(dev, "Unknown remote resource type %d\n", res->type);
1037 goto err_free;
1038 }
1039 }
1040
1041 out_success:
1042 kfree(resources);
1043 status |= STATUS_EPC_API_SUCCESS;
1044 reg->status = cpu_to_le32(status);
1045 return;
1046
1047 err_free:
1048 kfree(resources);
1049 err:
1050 status |= STATUS_EPC_API_FAIL;
1051 reg->status = cpu_to_le32(status);
1052 }
1053
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On Wed, Feb 04, 2026 at 11:54:37PM +0900, Koichiro Den wrote:
> Add a new pci-epf-test command that exercises the newly added EPC API
> pci_epc_get_remote_resources().
>
> The test is intentionally a smoke test. It verifies that the API either
> returns -EOPNOTSUPP or a well-formed resource list (non-zero phys/size
> and known resource types). The result is reported to the host via a
> status bit and an interrupt, consistent with existing pci-epf-test
> commands.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
> drivers/pci/endpoint/functions/pci-epf-test.c | 88 +++++++++++++++++++
> 1 file changed, 88 insertions(+)
>
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index 6952ee418622..6446a0a23865 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -35,6 +35,7 @@
> #define COMMAND_DISABLE_DOORBELL BIT(7)
> #define COMMAND_BAR_SUBRANGE_SETUP BIT(8)
> #define COMMAND_BAR_SUBRANGE_CLEAR BIT(9)
> +#define COMMAND_EPC_API BIT(10)
>
> #define STATUS_READ_SUCCESS BIT(0)
> #define STATUS_READ_FAIL BIT(1)
> @@ -54,6 +55,8 @@
> #define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15)
> #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16)
> #define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17)
> +#define STATUS_EPC_API_SUCCESS BIT(18)
> +#define STATUS_EPC_API_FAIL BIT(19)
>
> #define FLAG_USE_DMA BIT(0)
>
> @@ -967,6 +970,87 @@ static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test,
> reg->status = cpu_to_le32(status);
> }
>
> +static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
> + struct pci_epf_test_reg *reg)
> +{
> + struct pci_epc_remote_resource *resources = NULL;
> + u32 status = le32_to_cpu(reg->status);
> + struct pci_epf *epf = epf_test->epf;
> + struct device *dev = &epf->dev;
> + struct pci_epc *epc = epf->epc;
> + int num_resources;
> + int ret, i;
> +
> + num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
> + epf->vfunc_no, NULL, 0);
> + if (num_resources == -EOPNOTSUPP || num_resources == 0)
> + goto out_success;
> + if (num_resources < 0)
> + goto err;
> +
> + resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
use auto cleanup
struct pci_epc_remote_resource *resources __free(kfree) =
kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
> + if (!resources)
> + goto err;
> +
> + ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
> + resources, num_resources);
> + if (ret < 0) {
> + dev_err(dev, "EPC remote resource query failed: %d\n", ret);
> + goto err_free;
> + }
> + if (ret > num_resources) {
> + dev_err(dev, "EPC API returned %d resources (max %d)\n",
> + ret, num_resources);
> + goto err_free;
> + }
> +
> + for (i = 0; i < ret; i++) {
> + struct pci_epc_remote_resource *res = &resources[i];
> +
> + if (!res->phys_addr || !res->size) {
> + dev_err(dev,
> + "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
> + i, res->type, &res->phys_addr, res->size);
> + goto err_free;
> + }
> +
> + /* Guard against address overflow */
> + if (res->phys_addr + res->size < res->phys_addr) {
> + dev_err(dev,
> + "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
> + i, &res->phys_addr, res->size);
> + goto err_free;
> + }
> +
> + switch (res->type) {
> + case PCI_EPC_RR_DMA_CTRL_MMIO:
> + /* Generic checks above are sufficient. */
> + break;
> + case PCI_EPC_RR_DMA_CHAN_DESC:
> + /*
> + * hw_chan_id and ep2rc are informational. No extra validation
> + * beyond the generic checks above is needed.
> + */
> + break;
> + default:
> + dev_err(dev, "Unknown remote resource type %d\n", res->type);
> + goto err_free;
can you call subrange to map to one of bar?
Frank
> + }
> + }
> +
> +out_success:
> + kfree(resources);
> + status |= STATUS_EPC_API_SUCCESS;
> + reg->status = cpu_to_le32(status);
> + return;
> +
> +err_free:
> + kfree(resources);
> +err:
> + status |= STATUS_EPC_API_FAIL;
> + reg->status = cpu_to_le32(status);
> +}
> +
> static void pci_epf_test_cmd_handler(struct work_struct *work)
> {
> u32 command;
> @@ -1030,6 +1114,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> pci_epf_test_bar_subrange_clear(epf_test, reg);
> pci_epf_test_raise_irq(epf_test, reg);
> break;
> + case COMMAND_EPC_API:
> + pci_epf_test_epc_api(epf_test, reg);
> + pci_epf_test_raise_irq(epf_test, reg);
> + break;
> default:
> dev_err(dev, "Invalid command 0x%x\n", command);
> break;
> --
> 2.51.0
>
On Wed, Feb 04, 2026 at 02:37:08PM -0500, Frank Li wrote:
> On Wed, Feb 04, 2026 at 11:54:37PM +0900, Koichiro Den wrote:
> > Add a new pci-epf-test command that exercises the newly added EPC API
> > pci_epc_get_remote_resources().
> >
> > The test is intentionally a smoke test. It verifies that the API either
> > returns -EOPNOTSUPP or a well-formed resource list (non-zero phys/size
> > and known resource types). The result is reported to the host via a
> > status bit and an interrupt, consistent with existing pci-epf-test
> > commands.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> > drivers/pci/endpoint/functions/pci-epf-test.c | 88 +++++++++++++++++++
> > 1 file changed, 88 insertions(+)
> >
> > diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> > index 6952ee418622..6446a0a23865 100644
> > --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> > +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> > @@ -35,6 +35,7 @@
> > #define COMMAND_DISABLE_DOORBELL BIT(7)
> > #define COMMAND_BAR_SUBRANGE_SETUP BIT(8)
> > #define COMMAND_BAR_SUBRANGE_CLEAR BIT(9)
> > +#define COMMAND_EPC_API BIT(10)
> >
> > #define STATUS_READ_SUCCESS BIT(0)
> > #define STATUS_READ_FAIL BIT(1)
> > @@ -54,6 +55,8 @@
> > #define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15)
> > #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16)
> > #define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17)
> > +#define STATUS_EPC_API_SUCCESS BIT(18)
> > +#define STATUS_EPC_API_FAIL BIT(19)
> >
> > #define FLAG_USE_DMA BIT(0)
> >
> > @@ -967,6 +970,87 @@ static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test,
> > reg->status = cpu_to_le32(status);
> > }
> >
> > +static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
> > + struct pci_epf_test_reg *reg)
> > +{
> > + struct pci_epc_remote_resource *resources = NULL;
> > + u32 status = le32_to_cpu(reg->status);
> > + struct pci_epf *epf = epf_test->epf;
> > + struct device *dev = &epf->dev;
> > + struct pci_epc *epc = epf->epc;
> > + int num_resources;
> > + int ret, i;
> > +
> > + num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
> > + epf->vfunc_no, NULL, 0);
> > + if (num_resources == -EOPNOTSUPP || num_resources == 0)
> > + goto out_success;
> > + if (num_resources < 0)
> > + goto err;
> > +
> > + resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
>
> use auto cleanup
> struct pci_epc_remote_resource *resources __free(kfree) =
> kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
I'll update it, thanks for pointing that out.
>
> > + if (!resources)
> > + goto err;
> > +
> > + ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
> > + resources, num_resources);
> > + if (ret < 0) {
> > + dev_err(dev, "EPC remote resource query failed: %d\n", ret);
> > + goto err_free;
> > + }
> > + if (ret > num_resources) {
> > + dev_err(dev, "EPC API returned %d resources (max %d)\n",
> > + ret, num_resources);
> > + goto err_free;
> > + }
> > +
> > + for (i = 0; i < ret; i++) {
> > + struct pci_epc_remote_resource *res = &resources[i];
> > +
> > + if (!res->phys_addr || !res->size) {
> > + dev_err(dev,
> > + "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
> > + i, res->type, &res->phys_addr, res->size);
> > + goto err_free;
> > + }
> > +
> > + /* Guard against address overflow */
> > + if (res->phys_addr + res->size < res->phys_addr) {
> > + dev_err(dev,
> > + "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
> > + i, &res->phys_addr, res->size);
> > + goto err_free;
> > + }
> > +
> > + switch (res->type) {
> > + case PCI_EPC_RR_DMA_CTRL_MMIO:
> > + /* Generic checks above are sufficient. */
> > + break;
> > + case PCI_EPC_RR_DMA_CHAN_DESC:
> > + /*
> > + * hw_chan_id and ep2rc are informational. No extra validation
> > + * beyond the generic checks above is needed.
> > + */
> > + break;
> > + default:
> > + dev_err(dev, "Unknown remote resource type %d\n", res->type);
> > + goto err_free;
>
> can you call subrange to map to one of bar?
Just for the record, BAR_SUBRANGE_TEST has already landed into the tree and
excercises BAR subrange mapping end-to-end.
In my opinion, simply mapping the returned resources into BAR subranges
here would mostly duplicate the existing subrange test unless we also add
host side validation, and some resource types may be MMIO, so I'd prefer to
keep this as a smoke test. If you had a specific failure mode in mind that
is not covered by BAR_SUBRANGE_TEST, please let me know, I can try to add a
targeted check.
Thanks for the review,
Koichiro
>
> Frank
> > + }
> > + }
> > +
> > +out_success:
> > + kfree(resources);
> > + status |= STATUS_EPC_API_SUCCESS;
> > + reg->status = cpu_to_le32(status);
> > + return;
> > +
> > +err_free:
> > + kfree(resources);
> > +err:
> > + status |= STATUS_EPC_API_FAIL;
> > + reg->status = cpu_to_le32(status);
> > +}
> > +
> > static void pci_epf_test_cmd_handler(struct work_struct *work)
> > {
> > u32 command;
> > @@ -1030,6 +1114,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> > pci_epf_test_bar_subrange_clear(epf_test, reg);
> > pci_epf_test_raise_irq(epf_test, reg);
> > break;
> > + case COMMAND_EPC_API:
> > + pci_epf_test_epc_api(epf_test, reg);
> > + pci_epf_test_raise_irq(epf_test, reg);
> > + break;
> > default:
> > dev_err(dev, "Invalid command 0x%x\n", command);
> > break;
> > --
> > 2.51.0
> >
© 2016 - 2026 Red Hat, Inc.