* [PATCH v5 00/17] PCI endpoint fixes and improvements
@ 2023-04-15 2:35 Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 01/17] PCI: endpoint: Automatically create a function specific attributes group Damien Le Moal
` (17 more replies)
0 siblings, 18 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
This series fixes several issues with the PCI endpoint code and endpoint
test drivers (RC side and EP side).
The first 2 patches address an issue with the use of configfs to create
an endpoint driver type attributes group, preventing a potential crash
if the user creates a directory multiple times for the driver type
attributes.
The following patches are fixes and improvements for the endpoint test
drivers, EP side and RC side.
This is all tested using a Pine Rockpro64 board, with the rockchip ep
driver fixed using Rick Wertenbroek <rick.wertenbroek@gmail.com>
patches [1].
[1] https://lore.kernel.org/linux-pci/20230404082426.3880812-1-rick.wertenbroek@gmail.com/
Changes from v4:
- Addressed Bjorn comments on the commit messages (typos, text clarity)
- Changed patch 1 to use dev_err() instead of pr_err().
- Add print of invalid command value in patch 10
- Chnaged all patches author and Signed-off-by tag to use my kernel.org
email address
- Added Mani's review tags
Changes from v3:
- Corrected patch 7 and 12 title
- Added patch 11
Changes from v2:
- Add updates of the ntb and vntb function driver documentation in
patch 1 to reflect the patch changes.
- Removed unnecessary WARN_ON() call in patch 4
- Added missing cc: stable tags
- Added review tags
Changes from v1:
- Improved patch 1 commit message
- Modified patch 2 to not have to add an internal header file
- Split former patch 3 into patch 3, 4 and 5
- Removed former patch 4 introducing volatile casts and replaced it
with patch 9
- Added patch 6, 7, 8 and 10
- Added Reviewed-by tags in patches not modified
Damien Le Moal (17):
PCI: endpoint: Automatically create a function specific attributes
group
PCI: endpoint: Move pci_epf_type_add_cfs() code
PCI: epf-test: Fix DMA transfer completion initialization
PCI: epf-test: Fix DMA transfer completion detection
PCI: epf-test: Use dmaengine_submit() to initiate DMA transfer
PCI: epf-test: Simplify read/write/copy test functions
PCI: epf-test: Simplify pci_epf_test_raise_irq()
PCI: epf-test: Simplify IRQ test commands execution
PCI: epf-test: Improve handling of command and status registers
PCI: epf-test: Cleanup pci_epf_test_cmd_handler()
PCI: epf-test: Cleanup request result handling
PCI: epf-test: Simplify DMA support checks
PCI: epf-test: Simplify transfers result print
misc: pci_endpoint_test: Free IRQs before removing the device
misc: pci_endpoint_test: Re-init completion for every test
misc: pci_endpoint_test: Do not write status in IRQ handler
misc: pci_endpoint_test: Simplify pci_endpoint_test_msi_irq()
Documentation/PCI/endpoint/pci-ntb-howto.rst | 11 +-
Documentation/PCI/endpoint/pci-vntb-howto.rst | 13 +-
drivers/misc/pci_endpoint_test.c | 25 +-
drivers/pci/endpoint/functions/pci-epf-test.c | 266 ++++++++----------
drivers/pci/endpoint/pci-ep-cfs.c | 54 ++--
drivers/pci/endpoint/pci-epf-core.c | 32 ---
include/linux/pci-epf.h | 2 -
7 files changed, 175 insertions(+), 228 deletions(-)
--
2.39.2
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v5 01/17] PCI: endpoint: Automatically create a function specific attributes group
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 02/17] PCI: endpoint: Move pci_epf_type_add_cfs() code Damien Le Moal
` (16 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
A PCI endpoint function driver can define function specific attributes
under its function configfs directory using the add_cfs() endpoint
driver operation. This is done by tying up the mkdir operation for
the function configfs directory to a call to the add_cfs() operation.
However, there are no checks preventing the user from repeatedly
creating function specific attribute directories with different names,
resulting in the same endpoint specific attributes group being added
multiple times, which also result in an invalid reference counting for
the attribute groups. E.g., using the pci-epf-ntb function driver as an
example, the user creates the function as follows:
$ modprobe pci-epf-ntb
$ cd /sys/kernel/config/pci_ep/functions/pci_epf_ntb
$ mkdir func0
$ tree func0
func0/
|-- baseclass_code
|-- cache_line_size
|-- ...
`-- vendorid
$ mkdir func0/attrs
$ tree func0
func0/
|-- attrs
| |-- db_count
| |-- mw1
| |-- mw2
| |-- mw3
| |-- mw4
| |-- num_mws
| `-- spad_count
|-- baseclass_code
|-- cache_line_size
|-- ...
`-- vendorid
At this point, the function can be started by linking the EP controller.
However, if the user mistakenly creates again a directory:
$ mkdir func0/attrs2
$ tree func0
func0/
|-- attrs
| |-- db_count
| |-- mw1
| |-- mw2
| |-- mw3
| |-- mw4
| |-- num_mws
| `-- spad_count
|-- attrs2
| |-- db_count
| |-- mw1
| |-- mw2
| |-- mw3
| |-- mw4
| |-- num_mws
| `-- spad_count
|-- baseclass_code
|-- cache_line_size
|-- ...
`-- vendorid
The endpoint function specific attributes are duplicated and cause a
crash when the endpoint function device is torn down:
refcount_t: addition on 0; use-after-free.
WARNING: CPU: 2 PID: 834 at lib/refcount.c:25 refcount_warn_saturate+0xc8/0x144
CPU: 2 PID: 834 Comm: rmdir Not tainted 6.3.0-rc1 #1
Hardware name: Pine64 RockPro64 v2.1 (DT)
pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
...
Call trace:
refcount_warn_saturate+0xc8/0x144
config_item_get+0x7c/0x80
configfs_rmdir+0x17c/0x30c
vfs_rmdir+0x8c/0x204
do_rmdir+0x158/0x184
__arm64_sys_unlinkat+0x64/0x80
invoke_syscall+0x48/0x114
...
Fix this by modifying pci_epf_cfs_work() to execute the new function
pci_ep_cfs_add_type_group() which itself calls pci_epf_type_add_cfs()
to obtain the function specific attribute group and the group name
(directory name) from the endpoint function driver. If the function
driver defines an attribute group, pci_ep_cfs_add_type_group() then
proceeds to register this group using configfs_register_group(), thus
automatically exposing the function type specific configfs attributes
to the user. E.g.:
$ modprobe pci-epf-ntb
$ cd /sys/kernel/config/pci_ep/functions/pci_epf_ntb
$ mkdir func0
$ tree func0
func0/
|-- baseclass_code
|-- cache_line_size
|-- ...
|-- pci_epf_ntb.0
| |-- db_count
| |-- mw1
| |-- mw2
| |-- mw3
| |-- mw4
| |-- num_mws
| `-- spad_count
|-- primary
|-- ...
`-- vendorid
With this change, there is no need for the user to create or delete
directories in the endpoint function attributes directory. The
pci_epf_type_group_ops group operations are thus removed.
alos update the documentation for the pci-epf-ntb and pci-epf-vntb
function drivers to reflect this change, removing the explanations
showing the need to manually create the sub-directory for the function
specific attributes.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
Documentation/PCI/endpoint/pci-ntb-howto.rst | 11 ++---
Documentation/PCI/endpoint/pci-vntb-howto.rst | 13 +++---
drivers/pci/endpoint/pci-ep-cfs.c | 42 +++++++++----------
3 files changed, 29 insertions(+), 37 deletions(-)
diff --git a/Documentation/PCI/endpoint/pci-ntb-howto.rst b/Documentation/PCI/endpoint/pci-ntb-howto.rst
index 1884bf29caba..4261e7157ef1 100644
--- a/Documentation/PCI/endpoint/pci-ntb-howto.rst
+++ b/Documentation/PCI/endpoint/pci-ntb-howto.rst
@@ -88,13 +88,10 @@ commands can be used::
# echo 0x104c > functions/pci_epf_ntb/func1/vendorid
# echo 0xb00d > functions/pci_epf_ntb/func1/deviceid
-In order to configure NTB specific attributes, a new sub-directory to func1
-should be created::
-
- # mkdir functions/pci_epf_ntb/func1/pci_epf_ntb.0/
-
-The NTB function driver will populate this directory with various attributes
-that can be configured by the user::
+The PCI endpoint framework also automatically creates a sub-directory in the
+function attribute directory. This sub-directory has the same name as the name
+of the function device and is populated with the following NTB specific
+attributes that can be configured by the user::
# ls functions/pci_epf_ntb/func1/pci_epf_ntb.0/
db_count mw1 mw2 mw3 mw4 num_mws
diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst
index 4ab8e4a26d4b..70d3bc90893f 100644
--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst
+++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst
@@ -84,13 +84,10 @@ commands can be used::
# echo 0x1957 > functions/pci_epf_vntb/func1/vendorid
# echo 0x0809 > functions/pci_epf_vntb/func1/deviceid
-In order to configure NTB specific attributes, a new sub-directory to func1
-should be created::
-
- # mkdir functions/pci_epf_vntb/func1/pci_epf_vntb.0/
-
-The NTB function driver will populate this directory with various attributes
-that can be configured by the user::
+The PCI endpoint framework also automatically creates a sub-directory in the
+function attribute directory. This sub-directory has the same name as the name
+of the function device and is populated with the following NTB specific
+attributes that can be configured by the user::
# ls functions/pci_epf_vntb/func1/pci_epf_vntb.0/
db_count mw1 mw2 mw3 mw4 num_mws
@@ -103,7 +100,7 @@ A sample configuration for NTB function is given below::
# echo 1 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/num_mws
# echo 0x100000 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/mw1
-A sample configuration for virtual NTB driver for virutal PCI bus::
+A sample configuration for virtual NTB driver for virtual PCI bus::
# echo 0x1957 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_vid
# echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
index 4b8ac0ac84d5..e255a8415bd5 100644
--- a/drivers/pci/endpoint/pci-ep-cfs.c
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -23,6 +23,7 @@ struct pci_epf_group {
struct config_group group;
struct config_group primary_epc_group;
struct config_group secondary_epc_group;
+ struct config_group *type_group;
struct delayed_work cfs_work;
struct pci_epf *epf;
int index;
@@ -502,34 +503,29 @@ static struct configfs_item_operations pci_epf_ops = {
.release = pci_epf_release,
};
-static struct config_group *pci_epf_type_make(struct config_group *group,
- const char *name)
-{
- struct pci_epf_group *epf_group = to_pci_epf_group(&group->cg_item);
- struct config_group *epf_type_group;
-
- epf_type_group = pci_epf_type_add_cfs(epf_group->epf, group);
- return epf_type_group;
-}
-
-static void pci_epf_type_drop(struct config_group *group,
- struct config_item *item)
-{
- config_item_put(item);
-}
-
-static struct configfs_group_operations pci_epf_type_group_ops = {
- .make_group = &pci_epf_type_make,
- .drop_item = &pci_epf_type_drop,
-};
-
static const struct config_item_type pci_epf_type = {
- .ct_group_ops = &pci_epf_type_group_ops,
.ct_item_ops = &pci_epf_ops,
.ct_attrs = pci_epf_attrs,
.ct_owner = THIS_MODULE,
};
+static void pci_ep_cfs_add_type_group(struct pci_epf_group *epf_group)
+{
+ struct config_group *group;
+
+ group = pci_epf_type_add_cfs(epf_group->epf, &epf_group->group);
+ if (!group)
+ return;
+
+ if (IS_ERR(group)) {
+ dev_err(&epf_group->epf->dev,
+ "failed to create epf type specific attributes\n");
+ return;
+ }
+
+ configfs_register_group(&epf_group->group, group);
+}
+
static void pci_epf_cfs_work(struct work_struct *work)
{
struct pci_epf_group *epf_group;
@@ -547,6 +543,8 @@ static void pci_epf_cfs_work(struct work_struct *work)
pr_err("failed to create 'secondary' EPC interface\n");
return;
}
+
+ pci_ep_cfs_add_type_group(epf_group);
}
static struct config_group *pci_epf_make(struct config_group *group,
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 02/17] PCI: endpoint: Move pci_epf_type_add_cfs() code
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 01/17] PCI: endpoint: Automatically create a function specific attributes group Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 03/17] PCI: epf-test: Fix DMA transfer completion initialization Damien Le Moal
` (15 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
pci_epf_type_add_cfs() is called only from pci_ep_cfs_add_type_group()
in drivers/pci/endpoint/pci-ep-cfs.c, so there is no need to export this
function and we can move its code from pci-epf-core.c to pci-ep-cfs.c
as a static function.
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
---
drivers/pci/endpoint/pci-ep-cfs.c | 20 ++++++++++++++++++
drivers/pci/endpoint/pci-epf-core.c | 32 -----------------------------
include/linux/pci-epf.h | 2 --
3 files changed, 20 insertions(+), 34 deletions(-)
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
index e255a8415bd5..0fb6c376166f 100644
--- a/drivers/pci/endpoint/pci-ep-cfs.c
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -509,6 +509,26 @@ static const struct config_item_type pci_epf_type = {
.ct_owner = THIS_MODULE,
};
+static struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,
+ struct config_group *group)
+{
+ struct config_group *epf_type_group;
+
+ if (!epf->driver) {
+ dev_err(&epf->dev, "epf device not bound to driver\n");
+ return NULL;
+ }
+
+ if (!epf->driver->ops->add_cfs)
+ return NULL;
+
+ mutex_lock(&epf->lock);
+ epf_type_group = epf->driver->ops->add_cfs(epf, group);
+ mutex_unlock(&epf->lock);
+
+ return epf_type_group;
+}
+
static void pci_ep_cfs_add_type_group(struct pci_epf_group *epf_group)
{
struct config_group *group;
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 2036e38be093..355a6f56fcea 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -20,38 +20,6 @@ static DEFINE_MUTEX(pci_epf_mutex);
static struct bus_type pci_epf_bus_type;
static const struct device_type pci_epf_type;
-/**
- * pci_epf_type_add_cfs() - Help function drivers to expose function specific
- * attributes in configfs
- * @epf: the EPF device that has to be configured using configfs
- * @group: the parent configfs group (corresponding to entries in
- * pci_epf_device_id)
- *
- * Invoke to expose function specific attributes in configfs. If the function
- * driver does not have anything to expose (attributes configured by user),
- * return NULL.
- */
-struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,
- struct config_group *group)
-{
- struct config_group *epf_type_group;
-
- if (!epf->driver) {
- dev_err(&epf->dev, "epf device not bound to driver\n");
- return NULL;
- }
-
- if (!epf->driver->ops->add_cfs)
- return NULL;
-
- mutex_lock(&epf->lock);
- epf_type_group = epf->driver->ops->add_cfs(epf, group);
- mutex_unlock(&epf->lock);
-
- return epf_type_group;
-}
-EXPORT_SYMBOL_GPL(pci_epf_type_add_cfs);
-
/**
* pci_epf_unbind() - Notify the function driver that the binding between the
* EPF device and EPC device has been lost
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index a215dc8ce693..b8441db2fa52 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -214,8 +214,6 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
enum pci_epc_interface_type type);
int pci_epf_bind(struct pci_epf *epf);
void pci_epf_unbind(struct pci_epf *epf);
-struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,
- struct config_group *group);
int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);
void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);
#endif /* __LINUX_PCI_EPF_H */
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 03/17] PCI: epf-test: Fix DMA transfer completion initialization
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 01/17] PCI: endpoint: Automatically create a function specific attributes group Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 02/17] PCI: endpoint: Move pci_epf_type_add_cfs() code Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 04/17] PCI: epf-test: Fix DMA transfer completion detection Damien Le Moal
` (14 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
Re-initialize the transfer_complete DMA transfer completion before
calling tx_submit(), to avoid seeing the DMA transfer complete before
the completion is initialized, thus potentially losing the completion
notification.
Fixes: 8353813c88ef ("PCI: endpoint: Enable DMA tests for endpoints with DMA capabilities")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 0f9d2ec822ac..d65419735d2e 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -151,10 +151,10 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
return -EIO;
}
+ reinit_completion(&epf_test->transfer_complete);
tx->callback = pci_epf_test_dma_callback;
tx->callback_param = epf_test;
cookie = tx->tx_submit(tx);
- reinit_completion(&epf_test->transfer_complete);
ret = dma_submit_error(cookie);
if (ret) {
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 04/17] PCI: epf-test: Fix DMA transfer completion detection
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (2 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 03/17] PCI: epf-test: Fix DMA transfer completion initialization Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 05/17] PCI: epf-test: Use dmaengine_submit() to initiate DMA transfer Damien Le Moal
` (13 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
pci_epf_test_data_transfer() and pci_epf_test_dma_callback() are not
handling DMA transfer completion correctly, leading to completion
notifications to the RC side that are too early. This problem can be
detected when the RC side is running an IOMMU with messages such as:
pci-endpoint-test 0000:0b:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x001c address=0xfff00000 flags=0x0000]
When running the pcitest.sh tests: the address used for a previous
test transfer generates the above error while the next test transfer is
running.
Fix this by testing the DMA transfer status in
pci_epf_test_dma_callback() and notifying the completion only when the
transfer status is DMA_COMPLETE or DMA_ERROR. Furthermore, in
pci_epf_test_data_transfer(), be paranoid and check again the transfer
status and always call dmaengine_terminate_sync() before returning.
Fixes: 8353813c88ef ("PCI: endpoint: Enable DMA tests for endpoints with DMA capabilities")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 38 +++++++++++++------
1 file changed, 27 insertions(+), 11 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index d65419735d2e..dbea6eb0dee7 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -54,6 +54,9 @@ struct pci_epf_test {
struct delayed_work cmd_handler;
struct dma_chan *dma_chan_tx;
struct dma_chan *dma_chan_rx;
+ struct dma_chan *transfer_chan;
+ dma_cookie_t transfer_cookie;
+ enum dma_status transfer_status;
struct completion transfer_complete;
bool dma_supported;
bool dma_private;
@@ -85,8 +88,14 @@ static size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };
static void pci_epf_test_dma_callback(void *param)
{
struct pci_epf_test *epf_test = param;
-
- complete(&epf_test->transfer_complete);
+ struct dma_tx_state state;
+
+ epf_test->transfer_status =
+ dmaengine_tx_status(epf_test->transfer_chan,
+ epf_test->transfer_cookie, &state);
+ if (epf_test->transfer_status == DMA_COMPLETE ||
+ epf_test->transfer_status == DMA_ERROR)
+ complete(&epf_test->transfer_complete);
}
/**
@@ -120,7 +129,6 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
struct dma_async_tx_descriptor *tx;
struct dma_slave_config sconf = {};
struct device *dev = &epf->dev;
- dma_cookie_t cookie;
int ret;
if (IS_ERR_OR_NULL(chan)) {
@@ -152,25 +160,33 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
}
reinit_completion(&epf_test->transfer_complete);
+ epf_test->transfer_chan = chan;
tx->callback = pci_epf_test_dma_callback;
tx->callback_param = epf_test;
- cookie = tx->tx_submit(tx);
+ epf_test->transfer_cookie = tx->tx_submit(tx);
- ret = dma_submit_error(cookie);
+ ret = dma_submit_error(epf_test->transfer_cookie);
if (ret) {
- dev_err(dev, "Failed to do DMA tx_submit %d\n", cookie);
- return -EIO;
+ dev_err(dev, "Failed to do DMA tx_submit %d\n", ret);
+ goto terminate;
}
dma_async_issue_pending(chan);
ret = wait_for_completion_interruptible(&epf_test->transfer_complete);
if (ret < 0) {
- dmaengine_terminate_sync(chan);
- dev_err(dev, "DMA wait_for_completion_timeout\n");
- return -ETIMEDOUT;
+ dev_err(dev, "DMA wait_for_completion interrupted\n");
+ goto terminate;
}
- return 0;
+ if (epf_test->transfer_status == DMA_ERROR) {
+ dev_err(dev, "DMA transfer failed\n");
+ ret = -EIO;
+ }
+
+terminate:
+ dmaengine_terminate_sync(chan);
+
+ return ret;
}
struct epf_dma_filter {
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 05/17] PCI: epf-test: Use dmaengine_submit() to initiate DMA transfer
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (3 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 04/17] PCI: epf-test: Fix DMA transfer completion detection Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 06/17] PCI: epf-test: Simplify read/write/copy test functions Damien Le Moal
` (12 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
Instead of an open coded call to the tx_submit() operation of struct
dma_async_tx_descriptor, use the helper function dmaengine_submit().
No functional change is introduced with this.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index dbea6eb0dee7..7cdc6c915ef5 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -163,7 +163,7 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
epf_test->transfer_chan = chan;
tx->callback = pci_epf_test_dma_callback;
tx->callback_param = epf_test;
- epf_test->transfer_cookie = tx->tx_submit(tx);
+ epf_test->transfer_cookie = dmaengine_submit(tx);
ret = dma_submit_error(epf_test->transfer_cookie);
if (ret) {
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 06/17] PCI: epf-test: Simplify read/write/copy test functions
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (4 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 05/17] PCI: epf-test: Use dmaengine_submit() to initiate DMA transfer Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 07/17] PCI: epf-test: Simplify pci_epf_test_raise_irq() Damien Le Moal
` (11 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
The function pci_epf_test_cmd_handler() uses the register BAR address
as a pointer to a struct pci_epf_test_reg to determine the command sent
by the host and to execute the test function accordingly. There is no
need for doing this assignment again in each of the read, write and
copy test functions. We can simply pass the reg pointer as an argument
to the functions pci_epf_test_write(), pci_epf_test_read() and
pci_epf_test_copy().
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 21 ++++++++-----------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 7cdc6c915ef5..b8b178ac7cda 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -325,7 +325,8 @@ static void pci_epf_test_print_rate(const char *ops, u64 size,
(u64)ts.tv_sec, (u32)ts.tv_nsec, rate / 1024);
}
-static int pci_epf_test_copy(struct pci_epf_test *epf_test)
+static int pci_epf_test_copy(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
{
int ret;
bool use_dma;
@@ -337,8 +338,6 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
- enum pci_barno test_reg_bar = epf_test->test_reg_bar;
- struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size);
if (!src_addr) {
@@ -424,7 +423,8 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
return ret;
}
-static int pci_epf_test_read(struct pci_epf_test *epf_test)
+static int pci_epf_test_read(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
{
int ret;
void __iomem *src_addr;
@@ -438,8 +438,6 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
struct device *dma_dev = epf->epc->dev.parent;
- enum pci_barno test_reg_bar = epf_test->test_reg_bar;
- struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
if (!src_addr) {
@@ -514,7 +512,8 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
return ret;
}
-static int pci_epf_test_write(struct pci_epf_test *epf_test)
+static int pci_epf_test_write(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
{
int ret;
void __iomem *dst_addr;
@@ -527,8 +526,6 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
struct device *dma_dev = epf->epc->dev.parent;
- enum pci_barno test_reg_bar = epf_test->test_reg_bar;
- struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
if (!dst_addr) {
@@ -673,7 +670,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
}
if (command & COMMAND_WRITE) {
- ret = pci_epf_test_write(epf_test);
+ ret = pci_epf_test_write(epf_test, reg);
if (ret)
reg->status |= STATUS_WRITE_FAIL;
else
@@ -684,7 +681,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
}
if (command & COMMAND_READ) {
- ret = pci_epf_test_read(epf_test);
+ ret = pci_epf_test_read(epf_test, reg);
if (!ret)
reg->status |= STATUS_READ_SUCCESS;
else
@@ -695,7 +692,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
}
if (command & COMMAND_COPY) {
- ret = pci_epf_test_copy(epf_test);
+ ret = pci_epf_test_copy(epf_test, reg);
if (!ret)
reg->status |= STATUS_COPY_SUCCESS;
else
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 07/17] PCI: epf-test: Simplify pci_epf_test_raise_irq()
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (5 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 06/17] PCI: epf-test: Simplify read/write/copy test functions Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 08/17] PCI: epf-test: Simplify IRQ test commands execution Damien Le Moal
` (10 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
Change the interface of the function pci_epf_test_raise_irq() to
directly pass a pointer to the struct pci_epf_test_reg defining the test
being executed. This avoids the need for grabbing this pointer using
the register BAR address and simplifies the call sites as the IRQ type
and IRQ numbers do not have to be passed as arguments.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 21 +++++++------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index b8b178ac7cda..3835e558937a 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -607,29 +607,27 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test,
return ret;
}
-static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type,
- u16 irq)
+static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
{
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
- enum pci_barno test_reg_bar = epf_test->test_reg_bar;
- struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
reg->status |= STATUS_IRQ_RAISED;
- switch (irq_type) {
+ switch (reg->irq_type) {
case IRQ_TYPE_LEGACY:
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
PCI_EPC_IRQ_LEGACY, 0);
break;
case IRQ_TYPE_MSI:
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_MSI, irq);
+ PCI_EPC_IRQ_MSI, reg->irq_number);
break;
case IRQ_TYPE_MSIX:
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_MSIX, irq);
+ PCI_EPC_IRQ_MSIX, reg->irq_number);
break;
default:
dev_err(dev, "Failed to raise IRQ, unknown type\n");
@@ -675,8 +673,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->status |= STATUS_WRITE_FAIL;
else
reg->status |= STATUS_WRITE_SUCCESS;
- pci_epf_test_raise_irq(epf_test, reg->irq_type,
- reg->irq_number);
+ pci_epf_test_raise_irq(epf_test, reg);
goto reset_handler;
}
@@ -686,8 +683,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->status |= STATUS_READ_SUCCESS;
else
reg->status |= STATUS_READ_FAIL;
- pci_epf_test_raise_irq(epf_test, reg->irq_type,
- reg->irq_number);
+ pci_epf_test_raise_irq(epf_test, reg);
goto reset_handler;
}
@@ -697,8 +693,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
reg->status |= STATUS_COPY_SUCCESS;
else
reg->status |= STATUS_COPY_FAIL;
- pci_epf_test_raise_irq(epf_test, reg->irq_type,
- reg->irq_number);
+ pci_epf_test_raise_irq(epf_test, reg);
goto reset_handler;
}
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 08/17] PCI: epf-test: Simplify IRQ test commands execution
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (6 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 07/17] PCI: epf-test: Simplify pci_epf_test_raise_irq() Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 09/17] PCI: epf-test: Improve handling of command and status registers Damien Le Moal
` (9 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
For the commands COMMAND_RAISE_LEGACY_IRQ, COMMAND_RAISE_MSI_IRQ and
COMMAND_RAISE_MSIX_IRQ, the function pci_epf_test_cmd_handler()
sets the STATUS_IRQ_RAISED status flag and calls the epc function
pci_epc_raise_irq() directly. However, this is also exactly what the
pci_epf_test_raise_irq() function does. Avoid duplicating these
operations by directly using pci_epf_test_raise_irq() for the IRQ test
commands. It is OK to do so as the host side endpoint test driver always
set the correct IRQ type for the IRQ test commands.
At the same time, the IRQ number check done for the
COMMAND_RAISE_MSI_IRQ and COMMAND_RAISE_MSIX_IRQ commands can also be
moved to pci_epf_test_raise_irq() to also check the IRQ number requested
by the host for other test commands.
Overall, this significantly simplifies the pci_epf_test_cmd_handler()
function.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 43 ++++++++-----------
1 file changed, 17 insertions(+), 26 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 3835e558937a..ee90ba3a957b 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -613,6 +613,7 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
+ int count;
reg->status |= STATUS_IRQ_RAISED;
@@ -622,10 +623,22 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
PCI_EPC_IRQ_LEGACY, 0);
break;
case IRQ_TYPE_MSI:
+ count = pci_epc_get_msi(epc, epf->func_no, epf->vfunc_no);
+ if (reg->irq_number > count || count <= 0) {
+ dev_err(dev, "Invalid MSI IRQ number %d / %d\n",
+ reg->irq_number, count);
+ return;
+ }
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
PCI_EPC_IRQ_MSI, reg->irq_number);
break;
case IRQ_TYPE_MSIX:
+ count = pci_epc_get_msix(epc, epf->func_no, epf->vfunc_no);
+ if (reg->irq_number > count || count <= 0) {
+ dev_err(dev, "Invalid MSIX IRQ number %d / %d\n",
+ reg->irq_number, count);
+ return;
+ }
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
PCI_EPC_IRQ_MSIX, reg->irq_number);
break;
@@ -638,13 +651,11 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
static void pci_epf_test_cmd_handler(struct work_struct *work)
{
int ret;
- int count;
u32 command;
struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test,
cmd_handler.work);
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
- struct pci_epc *epc = epf->epc;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
@@ -660,10 +671,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
goto reset_handler;
}
- if (command & COMMAND_RAISE_LEGACY_IRQ) {
- reg->status = STATUS_IRQ_RAISED;
- pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_LEGACY, 0);
+ if ((command & COMMAND_RAISE_LEGACY_IRQ) ||
+ (command & COMMAND_RAISE_MSI_IRQ) ||
+ (command & COMMAND_RAISE_MSIX_IRQ)) {
+ pci_epf_test_raise_irq(epf_test, reg);
goto reset_handler;
}
@@ -697,26 +708,6 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
goto reset_handler;
}
- if (command & COMMAND_RAISE_MSI_IRQ) {
- count = pci_epc_get_msi(epc, epf->func_no, epf->vfunc_no);
- if (reg->irq_number > count || count <= 0)
- goto reset_handler;
- reg->status = STATUS_IRQ_RAISED;
- pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_MSI, reg->irq_number);
- goto reset_handler;
- }
-
- if (command & COMMAND_RAISE_MSIX_IRQ) {
- count = pci_epc_get_msix(epc, epf->func_no, epf->vfunc_no);
- if (reg->irq_number > count || count <= 0)
- goto reset_handler;
- reg->status = STATUS_IRQ_RAISED;
- pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_MSIX, reg->irq_number);
- goto reset_handler;
- }
-
reset_handler:
queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
msecs_to_jiffies(1));
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 09/17] PCI: epf-test: Improve handling of command and status registers
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (7 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 08/17] PCI: epf-test: Simplify IRQ test commands execution Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 10/17] PCI: epf-test: Cleanup pci_epf_test_cmd_handler() Damien Le Moal
` (8 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
The pci-epf-test driver uses the test register BAR memory directly
to get and execute a test registers set by the RC side and defined
using a struct pci_epf_test_reg. This direct use relies on using the
register BAR address as a pointer to a struct pci_epf_test_reg to
execute the test case and to send back the test result through the
status field of struct pci_epf_test_reg. In practice, the status field
is always updated before an interrupt is raised in
pci_epf_test_raise_irq(), to ensure that the RC side sees the updated
status when receiving an interrupt.
However, such assignment direct access does not ensure that changes to
the status register make it to memory, and so visible to the host,
before an interrupt is raised, thus potentially resulting in the RC
host not seeing the correct status result for a test.
Avoid this potential problem by using READ_ONCE()/WRITE_ONCE() when
accessing the command and status fields of a pci_epf_test_reg structure.
This ensure that a test start (pci_epf_test_cmd_handler() function) and
completion (with the function pci_epf_test_raise_irq()) achieve a correct
synchronization with the MMIO register accesses on the RC host.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index ee90ba3a957b..fa48e9b3c393 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -613,9 +613,14 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
+ u32 status = reg->status | STATUS_IRQ_RAISED;
int count;
- reg->status |= STATUS_IRQ_RAISED;
+ /*
+ * Set the status before raising the IRQ to ensure that the host sees
+ * the updated value when it gets the IRQ.
+ */
+ WRITE_ONCE(reg->status, status);
switch (reg->irq_type) {
case IRQ_TYPE_LEGACY:
@@ -659,12 +664,12 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
- command = reg->command;
+ command = READ_ONCE(reg->command);
if (!command)
goto reset_handler;
- reg->command = 0;
- reg->status = 0;
+ WRITE_ONCE(reg->command, 0);
+ WRITE_ONCE(reg->status, 0);
if (reg->irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Failed to detect IRQ type\n");
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 10/17] PCI: epf-test: Cleanup pci_epf_test_cmd_handler()
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (8 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 09/17] PCI: epf-test: Improve handling of command and status registers Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 11/17] PCI: epf-test: Cleanup request result handling Damien Le Moal
` (7 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
Command codes are never combined together as flags into a single value.
Thus we can replace the series of "if" tests in
pci_epf_test_cmd_handler() with a cleaner switch-case statement.
This also allows checking that we got a valid command and print an error
message if we did not.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 30 +++++++++----------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index fa48e9b3c393..7f482ec08754 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -676,41 +676,39 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
goto reset_handler;
}
- if ((command & COMMAND_RAISE_LEGACY_IRQ) ||
- (command & COMMAND_RAISE_MSI_IRQ) ||
- (command & COMMAND_RAISE_MSIX_IRQ)) {
+ switch (command) {
+ case COMMAND_RAISE_LEGACY_IRQ:
+ case COMMAND_RAISE_MSI_IRQ:
+ case COMMAND_RAISE_MSIX_IRQ:
pci_epf_test_raise_irq(epf_test, reg);
- goto reset_handler;
- }
-
- if (command & COMMAND_WRITE) {
+ break;
+ case COMMAND_WRITE:
ret = pci_epf_test_write(epf_test, reg);
if (ret)
reg->status |= STATUS_WRITE_FAIL;
else
reg->status |= STATUS_WRITE_SUCCESS;
pci_epf_test_raise_irq(epf_test, reg);
- goto reset_handler;
- }
-
- if (command & COMMAND_READ) {
+ break;
+ case COMMAND_READ:
ret = pci_epf_test_read(epf_test, reg);
if (!ret)
reg->status |= STATUS_READ_SUCCESS;
else
reg->status |= STATUS_READ_FAIL;
pci_epf_test_raise_irq(epf_test, reg);
- goto reset_handler;
- }
-
- if (command & COMMAND_COPY) {
+ break;
+ case COMMAND_COPY:
ret = pci_epf_test_copy(epf_test, reg);
if (!ret)
reg->status |= STATUS_COPY_SUCCESS;
else
reg->status |= STATUS_COPY_FAIL;
pci_epf_test_raise_irq(epf_test, reg);
- goto reset_handler;
+ break;
+ default:
+ dev_err(dev, "Invalid command 0x%x\n", command);
+ break;
}
reset_handler:
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 11/17] PCI: epf-test: Cleanup request result handling
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (9 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 10/17] PCI: epf-test: Cleanup pci_epf_test_cmd_handler() Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 12/17] PCI: epf-test: Simplify DMA support checks Damien Le Moal
` (6 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
Each of the test functions pci_epf_test_write(), pci_epf_test_read() and
pci_epf_test_copy() return an int result which is used by
pci_epf_test_cmd_handler() to set a success or error bit in the request
status.
In the spirit of keeping the processing of each test case self-contained
within its own test function, move the request status field update from
pci_epf_test_cmd_handler() to each of these test functions and change
these functions declaration to returning void.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 46 +++++++++----------
1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 7f482ec08754..e528b0915444 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -325,8 +325,8 @@ static void pci_epf_test_print_rate(const char *ops, u64 size,
(u64)ts.tv_sec, (u32)ts.tv_nsec, rate / 1024);
}
-static int pci_epf_test_copy(struct pci_epf_test *epf_test,
- struct pci_epf_test_reg *reg)
+static void pci_epf_test_copy(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
{
int ret;
bool use_dma;
@@ -420,11 +420,14 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test,
pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size);
err:
- return ret;
+ if (!ret)
+ reg->status |= STATUS_COPY_SUCCESS;
+ else
+ reg->status |= STATUS_COPY_FAIL;
}
-static int pci_epf_test_read(struct pci_epf_test *epf_test,
- struct pci_epf_test_reg *reg)
+static void pci_epf_test_read(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
{
int ret;
void __iomem *src_addr;
@@ -509,11 +512,14 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test,
pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size);
err:
- return ret;
+ if (!ret)
+ reg->status |= STATUS_READ_SUCCESS;
+ else
+ reg->status |= STATUS_READ_FAIL;
}
-static int pci_epf_test_write(struct pci_epf_test *epf_test,
- struct pci_epf_test_reg *reg)
+static void pci_epf_test_write(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
{
int ret;
void __iomem *dst_addr;
@@ -604,7 +610,10 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test,
pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size);
err:
- return ret;
+ if (!ret)
+ reg->status |= STATUS_WRITE_SUCCESS;
+ else
+ reg->status |= STATUS_WRITE_FAIL;
}
static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
@@ -655,7 +664,6 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
static void pci_epf_test_cmd_handler(struct work_struct *work)
{
- int ret;
u32 command;
struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test,
cmd_handler.work);
@@ -683,27 +691,15 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
pci_epf_test_raise_irq(epf_test, reg);
break;
case COMMAND_WRITE:
- ret = pci_epf_test_write(epf_test, reg);
- if (ret)
- reg->status |= STATUS_WRITE_FAIL;
- else
- reg->status |= STATUS_WRITE_SUCCESS;
+ pci_epf_test_write(epf_test, reg);
pci_epf_test_raise_irq(epf_test, reg);
break;
case COMMAND_READ:
- ret = pci_epf_test_read(epf_test, reg);
- if (!ret)
- reg->status |= STATUS_READ_SUCCESS;
- else
- reg->status |= STATUS_READ_FAIL;
+ pci_epf_test_read(epf_test, reg);
pci_epf_test_raise_irq(epf_test, reg);
break;
case COMMAND_COPY:
- ret = pci_epf_test_copy(epf_test, reg);
- if (!ret)
- reg->status |= STATUS_COPY_SUCCESS;
- else
- reg->status |= STATUS_COPY_FAIL;
+ pci_epf_test_copy(epf_test, reg);
pci_epf_test_raise_irq(epf_test, reg);
break;
default:
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 12/17] PCI: epf-test: Simplify DMA support checks
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (10 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 11/17] PCI: epf-test: Cleanup request result handling Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 13/17] PCI: epf-test: Simplify transfers result print Damien Le Moal
` (5 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
There is no need to have each read, write and copy test functions check
for the FLAG_USE_DMA flag against the DMA support status indicated by
epf_test->dma_supported. Move this test to the command handler function
pci_epf_test_cmd_handler() to check once for all cases.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 45 +++++++------------
1 file changed, 15 insertions(+), 30 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index e528b0915444..909e3e8ac01c 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -329,7 +329,6 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
struct pci_epf_test_reg *reg)
{
int ret;
- bool use_dma;
void __iomem *src_addr;
void __iomem *dst_addr;
phys_addr_t src_phys_addr;
@@ -372,14 +371,7 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
}
ktime_get_ts64(&start);
- use_dma = !!(reg->flags & FLAG_USE_DMA);
- if (use_dma) {
- if (!epf_test->dma_supported) {
- dev_err(dev, "Cannot transfer data using DMA\n");
- ret = -EINVAL;
- goto err_map_addr;
- }
-
+ if (reg->flags & FLAG_USE_DMA) {
if (epf_test->dma_private) {
dev_err(dev, "Cannot transfer data using DMA\n");
ret = -EINVAL;
@@ -405,7 +397,8 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
kfree(buf);
}
ktime_get_ts64(&end);
- pci_epf_test_print_rate("COPY", reg->size, &start, &end, use_dma);
+ pci_epf_test_print_rate("COPY", reg->size, &start, &end,
+ reg->flags & FLAG_USE_DMA);
err_map_addr:
pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, dst_phys_addr);
@@ -433,7 +426,6 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test,
void __iomem *src_addr;
void *buf;
u32 crc32;
- bool use_dma;
phys_addr_t phys_addr;
phys_addr_t dst_phys_addr;
struct timespec64 start, end;
@@ -464,14 +456,7 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test,
goto err_map_addr;
}
- use_dma = !!(reg->flags & FLAG_USE_DMA);
- if (use_dma) {
- if (!epf_test->dma_supported) {
- dev_err(dev, "Cannot transfer data using DMA\n");
- ret = -EINVAL;
- goto err_dma_map;
- }
-
+ if (reg->flags & FLAG_USE_DMA) {
dst_phys_addr = dma_map_single(dma_dev, buf, reg->size,
DMA_FROM_DEVICE);
if (dma_mapping_error(dma_dev, dst_phys_addr)) {
@@ -496,7 +481,8 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test,
ktime_get_ts64(&end);
}
- pci_epf_test_print_rate("READ", reg->size, &start, &end, use_dma);
+ pci_epf_test_print_rate("READ", reg->size, &start, &end,
+ reg->flags & FLAG_USE_DMA);
crc32 = crc32_le(~0, buf, reg->size);
if (crc32 != reg->checksum)
@@ -524,7 +510,6 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
int ret;
void __iomem *dst_addr;
void *buf;
- bool use_dma;
phys_addr_t phys_addr;
phys_addr_t src_phys_addr;
struct timespec64 start, end;
@@ -558,14 +543,7 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
get_random_bytes(buf, reg->size);
reg->checksum = crc32_le(~0, buf, reg->size);
- use_dma = !!(reg->flags & FLAG_USE_DMA);
- if (use_dma) {
- if (!epf_test->dma_supported) {
- dev_err(dev, "Cannot transfer data using DMA\n");
- ret = -EINVAL;
- goto err_dma_map;
- }
-
+ if (reg->flags & FLAG_USE_DMA) {
src_phys_addr = dma_map_single(dma_dev, buf, reg->size,
DMA_TO_DEVICE);
if (dma_mapping_error(dma_dev, src_phys_addr)) {
@@ -592,7 +570,8 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
ktime_get_ts64(&end);
}
- pci_epf_test_print_rate("WRITE", reg->size, &start, &end, use_dma);
+ pci_epf_test_print_rate("WRITE", reg->size, &start, &end,
+ reg->flags & FLAG_USE_DMA);
/*
* wait 1ms inorder for the write to complete. Without this delay L3
@@ -679,6 +658,12 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
WRITE_ONCE(reg->command, 0);
WRITE_ONCE(reg->status, 0);
+ if ((READ_ONCE(reg->flags) & FLAG_USE_DMA) &&
+ !epf_test->dma_supported) {
+ dev_err(dev, "Cannot transfer data using DMA\n");
+ goto reset_handler;
+ }
+
if (reg->irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Failed to detect IRQ type\n");
goto reset_handler;
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 13/17] PCI: epf-test: Simplify transfers result print
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (11 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 12/17] PCI: epf-test: Simplify DMA support checks Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 14/17] misc: pci_endpoint_test: Free IRQs before removing the device Damien Le Moal
` (4 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
In pci_epf_test_print_rate(), instead of open coding a reduction loop to
allow for a division by a 32-bits ns value, simply use div64_u64() to
calculate the transfer rate. To match the printed unit of KB/s, this
calculation divides the rate by 1000 instead of 1024 (that would be
KiB/s unit).
Change the format of the results printed by pci_epf_test_print_rate()
to be more compact without the double new line. Also use dev_info()
instead of pr_info().
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 39 +++++++------------
1 file changed, 14 insertions(+), 25 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 909e3e8ac01c..0bb14fb21edd 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -295,34 +295,23 @@ static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test)
return;
}
-static void pci_epf_test_print_rate(const char *ops, u64 size,
+static void pci_epf_test_print_rate(struct pci_epf_test *epf_test,
+ const char *op, u64 size,
struct timespec64 *start,
struct timespec64 *end, bool dma)
{
- struct timespec64 ts;
- u64 rate, ns;
-
- ts = timespec64_sub(*end, *start);
-
- /* convert both size (stored in 'rate') and time in terms of 'ns' */
- ns = timespec64_to_ns(&ts);
- rate = size * NSEC_PER_SEC;
-
- /* Divide both size (stored in 'rate') and ns by a common factor */
- while (ns > UINT_MAX) {
- rate >>= 1;
- ns >>= 1;
- }
-
- if (!ns)
- return;
+ struct timespec64 ts = timespec64_sub(*end, *start);
+ u64 rate = 0, ns;
/* calculate the rate */
- do_div(rate, (uint32_t)ns);
+ ns = timespec64_to_ns(&ts);
+ if (ns)
+ rate = div64_u64(size * NSEC_PER_SEC, ns * 1000);
- pr_info("\n%s => Size: %llu bytes\t DMA: %s\t Time: %llu.%09u seconds\t"
- "Rate: %llu KB/s\n", ops, size, dma ? "YES" : "NO",
- (u64)ts.tv_sec, (u32)ts.tv_nsec, rate / 1024);
+ dev_info(&epf_test->epf->dev,
+ "%s => Size: %llu B, DMA: %s, Time: %llu.%09u s, Rate: %llu KB/s\n",
+ op, size, dma ? "YES" : "NO",
+ (u64)ts.tv_sec, (u32)ts.tv_nsec, rate);
}
static void pci_epf_test_copy(struct pci_epf_test *epf_test,
@@ -397,7 +386,7 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test,
kfree(buf);
}
ktime_get_ts64(&end);
- pci_epf_test_print_rate("COPY", reg->size, &start, &end,
+ pci_epf_test_print_rate(epf_test, "COPY", reg->size, &start, &end,
reg->flags & FLAG_USE_DMA);
err_map_addr:
@@ -481,7 +470,7 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test,
ktime_get_ts64(&end);
}
- pci_epf_test_print_rate("READ", reg->size, &start, &end,
+ pci_epf_test_print_rate(epf_test, "READ", reg->size, &start, &end,
reg->flags & FLAG_USE_DMA);
crc32 = crc32_le(~0, buf, reg->size);
@@ -570,7 +559,7 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test,
ktime_get_ts64(&end);
}
- pci_epf_test_print_rate("WRITE", reg->size, &start, &end,
+ pci_epf_test_print_rate(epf_test, "WRITE", reg->size, &start, &end,
reg->flags & FLAG_USE_DMA);
/*
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 14/17] misc: pci_endpoint_test: Free IRQs before removing the device
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (12 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 13/17] PCI: epf-test: Simplify transfers result print Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 15/17] misc: pci_endpoint_test: Re-init completion for every test Damien Le Moal
` (3 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
In pci_endpoint_test_remove(), freeing the IRQs after removing the
device creates a small race window for IRQs to be received with the test
device memory already released, causing the IRQ handler to access
invalid memory, resulting in an oops.
Free the device IRQs before removing the device to avoid this issue.
Fixes: e03327122e2c ("pci_endpoint_test: Add 2 ioctl commands")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/misc/pci_endpoint_test.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index a7244de081ec..01235236e9bc 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -938,6 +938,9 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
if (id < 0)
return;
+ pci_endpoint_test_release_irq(test);
+ pci_endpoint_test_free_irq_vectors(test);
+
misc_deregister(&test->miscdev);
kfree(misc_device->name);
kfree(test->name);
@@ -947,9 +950,6 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
pci_iounmap(pdev, test->bar[bar]);
}
- pci_endpoint_test_release_irq(test);
- pci_endpoint_test_free_irq_vectors(test);
-
pci_release_regions(pdev);
pci_disable_device(pdev);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 15/17] misc: pci_endpoint_test: Re-init completion for every test
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (13 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 14/17] misc: pci_endpoint_test: Free IRQs before removing the device Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 16/17] misc: pci_endpoint_test: Do not write status in IRQ handler Damien Le Moal
` (2 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
The irq_raised completion used to detect the end of a test case is
initialized when the test device is probed, but never reinitialized
again before a test case. As a result, the irq_raised completion
synchronization is effective only for the first ioctl test case
executed. Any subsequent call to wait_for_completion() by another
ioctl() call will immediately return, potentially too early, leading to
false positive failures.
Fix this by reinitializing the irq_raised completion before starting a
new ioctl() test command.
Fixes: 2c156ac71c6b ("misc: Add host side PCI driver for PCI test function device")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/misc/pci_endpoint_test.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 01235236e9bc..24efe3b88a1f 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -729,6 +729,10 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
struct pci_dev *pdev = test->pdev;
mutex_lock(&test->mutex);
+
+ reinit_completion(&test->irq_raised);
+ test->last_irq = -ENODATA;
+
switch (cmd) {
case PCITEST_BAR:
bar = arg;
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 16/17] misc: pci_endpoint_test: Do not write status in IRQ handler
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (14 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 15/17] misc: pci_endpoint_test: Re-init completion for every test Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 17/17] misc: pci_endpoint_test: Simplify pci_endpoint_test_msi_irq() Damien Le Moal
2023-04-21 10:10 ` [PATCH v5 00/17] PCI endpoint fixes and improvements Lorenzo Pieralisi
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
pci_endpoint_test_irqhandler() always rewrites the status register when
an IRQ is raised, either as-is if STATUS_IRQ_RAISED is not set, or with
STATUS_IRQ_RAISED cleared if that flag is set. The first case creates a
race window with the endpoint side, meaning that the host side test
driver may end up reading what it just wrote, thus losing the real
status as set by the endpoint side before raising the next interrupt.
This can prevent detecting that the STATUS_IRQ_RAISED flag was set by
the endpoint.
Remove this race window by not clearing the STATUS_IRQ_RAISED status
flag and not rewriting that register for every IRQ received.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/misc/pci_endpoint_test.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 24efe3b88a1f..afd2577261f8 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -159,10 +159,7 @@ static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
if (reg & STATUS_IRQ_RAISED) {
test->last_irq = irq;
complete(&test->irq_raised);
- reg &= ~STATUS_IRQ_RAISED;
}
- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS,
- reg);
return IRQ_HANDLED;
}
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 17/17] misc: pci_endpoint_test: Simplify pci_endpoint_test_msi_irq()
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (15 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 16/17] misc: pci_endpoint_test: Do not write status in IRQ handler Damien Le Moal
@ 2023-04-15 2:35 ` Damien Le Moal
2023-04-21 10:10 ` [PATCH v5 00/17] PCI endpoint fixes and improvements Lorenzo Pieralisi
17 siblings, 0 replies; 19+ messages in thread
From: Damien Le Moal @ 2023-04-15 2:35 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci
Cc: Rick Wertenbroek, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
Simplify the code of pci_endpoint_test_msi_irq() by correctly using
booleans: remove the msix comparison to false as that variable is
already a boolean, and directly return the result of the comparison of
the raised interrupt number.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
---
drivers/misc/pci_endpoint_test.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index afd2577261f8..ed4d0ef5e5c3 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -313,21 +313,17 @@ static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
struct pci_dev *pdev = test->pdev;
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
- msix == false ? IRQ_TYPE_MSI :
- IRQ_TYPE_MSIX);
+ msix ? IRQ_TYPE_MSIX : IRQ_TYPE_MSI);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, msi_num);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
- msix == false ? COMMAND_RAISE_MSI_IRQ :
- COMMAND_RAISE_MSIX_IRQ);
+ msix ? COMMAND_RAISE_MSIX_IRQ :
+ COMMAND_RAISE_MSI_IRQ);
val = wait_for_completion_timeout(&test->irq_raised,
msecs_to_jiffies(1000));
if (!val)
return false;
- if (pci_irq_vector(pdev, msi_num - 1) == test->last_irq)
- return true;
-
- return false;
+ return pci_irq_vector(pdev, msi_num - 1) == test->last_irq;
}
static int pci_endpoint_test_validate_xfer_params(struct device *dev,
--
2.39.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v5 00/17] PCI endpoint fixes and improvements
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
` (16 preceding siblings ...)
2023-04-15 2:35 ` [PATCH v5 17/17] misc: pci_endpoint_test: Simplify pci_endpoint_test_msi_irq() Damien Le Moal
@ 2023-04-21 10:10 ` Lorenzo Pieralisi
17 siblings, 0 replies; 19+ messages in thread
From: Lorenzo Pieralisi @ 2023-04-21 10:10 UTC (permalink / raw)
To: Bjorn Helgaas, linux-pci, Damien Le Moal
Cc: Lorenzo Pieralisi, Rick Wertenbroek, Krzysztof Wilczyński,
Manivannan Sadhasivam, Kishon Vijay Abraham I, Arnd Bergmann,
Greg Kroah-Hartman
On Sat, 15 Apr 2023 11:35:25 +0900, Damien Le Moal wrote:
> This series fixes several issues with the PCI endpoint code and endpoint
> test drivers (RC side and EP side).
>
> The first 2 patches address an issue with the use of configfs to create
> an endpoint driver type attributes group, preventing a potential crash
> if the user creates a directory multiple times for the driver type
> attributes.
>
> [...]
Applied to controller/endpoint, thanks!
[01/17] PCI: endpoint: Automatically create a function specific attributes group
https://git.kernel.org/pci/pci/c/8dcae97d9819
[02/17] PCI: endpoint: Move pci_epf_type_add_cfs() code
https://git.kernel.org/pci/pci/c/f373bc7cee2a
[03/17] PCI: epf-test: Fix DMA transfer completion initialization
https://git.kernel.org/pci/pci/c/8b60b96dc008
[04/17] PCI: epf-test: Fix DMA transfer completion detection
https://git.kernel.org/pci/pci/c/5628aaabe60e
[05/17] PCI: epf-test: Use dmaengine_submit() to initiate DMA transfer
https://git.kernel.org/pci/pci/c/62d58b868ebe
[06/17] PCI: epf-test: Simplify read/write/copy test functions
https://git.kernel.org/pci/pci/c/8b5609b95b7b
[07/17] PCI: epf-test: Simplify pci_epf_test_raise_irq()
https://git.kernel.org/pci/pci/c/508f488b0913
[08/17] PCI: epf-test: Simplify IRQ test commands execution
https://git.kernel.org/pci/pci/c/82e72fc97901
[09/17] PCI: epf-test: Improve handling of command and status registers
https://git.kernel.org/pci/pci/c/ad15592c26d5
[10/17] PCI: epf-test: Cleanup pci_epf_test_cmd_handler()
https://git.kernel.org/pci/pci/c/0674535d28a8
[11/17] PCI: epf-test: Cleanup request result handling
https://git.kernel.org/pci/pci/c/00b225e73f30
[12/17] PCI: epf-test: Simplify DMA support checks
https://git.kernel.org/pci/pci/c/64cedb06b1d9
[13/17] PCI: epf-test: Simplify transfers result print
https://git.kernel.org/pci/pci/c/e68f5440ffb6
[14/17] misc: pci_endpoint_test: Free IRQs before removing the device
https://git.kernel.org/pci/pci/c/0ca8e07fc751
[15/17] misc: pci_endpoint_test: Re-init completion for every test
https://git.kernel.org/pci/pci/c/259456ae2804
[16/17] misc: pci_endpoint_test: Do not write status in IRQ handler
https://git.kernel.org/pci/pci/c/53a52a0d213e
[17/17] misc: pci_endpoint_test: Simplify pci_endpoint_test_msi_irq()
https://git.kernel.org/pci/pci/c/7885dbeb8780
Thanks,
Lorenzo
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2023-04-21 10:11 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-15 2:35 [PATCH v5 00/17] PCI endpoint fixes and improvements Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 01/17] PCI: endpoint: Automatically create a function specific attributes group Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 02/17] PCI: endpoint: Move pci_epf_type_add_cfs() code Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 03/17] PCI: epf-test: Fix DMA transfer completion initialization Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 04/17] PCI: epf-test: Fix DMA transfer completion detection Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 05/17] PCI: epf-test: Use dmaengine_submit() to initiate DMA transfer Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 06/17] PCI: epf-test: Simplify read/write/copy test functions Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 07/17] PCI: epf-test: Simplify pci_epf_test_raise_irq() Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 08/17] PCI: epf-test: Simplify IRQ test commands execution Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 09/17] PCI: epf-test: Improve handling of command and status registers Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 10/17] PCI: epf-test: Cleanup pci_epf_test_cmd_handler() Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 11/17] PCI: epf-test: Cleanup request result handling Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 12/17] PCI: epf-test: Simplify DMA support checks Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 13/17] PCI: epf-test: Simplify transfers result print Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 14/17] misc: pci_endpoint_test: Free IRQs before removing the device Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 15/17] misc: pci_endpoint_test: Re-init completion for every test Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 16/17] misc: pci_endpoint_test: Do not write status in IRQ handler Damien Le Moal
2023-04-15 2:35 ` [PATCH v5 17/17] misc: pci_endpoint_test: Simplify pci_endpoint_test_msi_irq() Damien Le Moal
2023-04-21 10:10 ` [PATCH v5 00/17] PCI endpoint fixes and improvements Lorenzo Pieralisi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.