[PATCH v2 5/6] rtsx_usb: hold runtime PM during transfers

From: Sean Rhodes

Date: Thu Mar 05 2026 - 14:41:15 EST


Hold a runtime-PM reference across bulk transfers, and mark the device
busy afterwards.

When runtime PM is already in progress (e.g. from rtsx_usb_suspend()),
avoid forcing a runtime resume from within the PM path by using
usb_autopm_get_interface_no_resume() unless the interface is already
runtime-suspended.

Signed-off-by: Sean Rhodes <sean@starlabs.systems>
---
drivers/misc/cardreader/rtsx_usb.c | 38 ++++++++++++++++++++++++------
1 file changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c
index 1830e9ed2521..5d818b632788 100644
--- a/drivers/misc/cardreader/rtsx_usb.c
+++ b/drivers/misc/cardreader/rtsx_usb.c
@@ -12,6 +12,7 @@
#include <linux/usb.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
#include <linux/rtsx_usb.h>

static int polling_pipe = 1;
@@ -65,19 +66,42 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
}

int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
- void *buf, unsigned int len, int num_sg,
- unsigned int *act_len, int timeout)
+ void *buf, unsigned int len, int num_sg,
+ unsigned int *act_len, int timeout)
{
+ int ret;
+ struct device *dev = &ucr->pusb_intf->dev;
+
if (timeout < 600)
timeout = 600;

+ /*
+ * During runtime suspend/resume callbacks, avoid forcing a runtime resume
+ * from within the PM path. The device is still active when
+ * rtsx_usb_suspend() runs, but usb_autopm_get_interface() can block when
+ * runtime PM is already in progress.
+ */
+ if (pm_runtime_status_suspended(dev)) {
+ ret = usb_autopm_get_interface(ucr->pusb_intf);
+ } else {
+ usb_autopm_get_interface_no_resume(ucr->pusb_intf);
+ ret = 0;
+ }
+ if (ret)
+ return ret;
+
if (num_sg)
- return rtsx_usb_bulk_transfer_sglist(ucr, pipe,
- (struct scatterlist *)buf, num_sg, len, act_len,
- timeout);
+ ret = rtsx_usb_bulk_transfer_sglist(ucr, pipe,
+ (struct scatterlist *)buf,
+ num_sg, len, act_len,
+ timeout);
else
- return usb_bulk_msg(ucr->pusb_dev, pipe, buf, len, act_len,
- timeout);
+ ret = usb_bulk_msg(ucr->pusb_dev, pipe, buf, len, act_len,
+ timeout);
+
+ usb_mark_last_busy(ucr->pusb_dev);
+ usb_autopm_put_interface(ucr->pusb_intf);
+ return ret;
}
EXPORT_SYMBOL_GPL(rtsx_usb_transfer_data);

--
2.51.0