2022-07-01 02:35:23

by Shuah Khan

[permalink] [raw]
Subject: [PATCH 0/2] rtsx_usb fixes

This two patch series consists of:

-- fix to "rejecting DMA map of vmalloc memory" dma mapping error
due to passing dma mapped buffer to usb_bulk_msg(). This results
in an attempt to map it again and fail.
-- a second fix to use separate command and response buffers to avoid
potential conflicts.

Shuah Khan (2):
misc: rtsx_usb: fix use of dma mapped buffer for usb bulk transfer
misc: rtsx_usb: use separate command and response buffers

drivers/misc/cardreader/rtsx_usb.c | 25 +++++++++++++++++--------
include/linux/rtsx_usb.h | 2 --
2 files changed, 17 insertions(+), 10 deletions(-)

--
2.34.1


2022-07-01 02:35:26

by Shuah Khan

[permalink] [raw]
Subject: [PATCH 1/2] misc: rtsx_usb: fix use of dma mapped buffer for usb bulk transfer

rtsx_usb driver allocates coherent dma buffer for urb transfers.
This buffer is passed to usb_bulk_msg() and usb core tries to
map already mapped buffer running into a dma mapping error.

xhci_hcd 0000:01:00.0: rejecting DMA map of vmalloc memory
WARNING: CPU: 1 PID: 279 at include/linux/dma-mapping.h:326 usb_ hcd_map_urb_for_dma+0x7d6/0x820

...

xhci_map_urb_for_dma+0x291/0x4e0
usb_hcd_submit_urb+0x199/0x12b0
...
usb_submit_urb+0x3b8/0x9e0
usb_start_wait_urb+0xe3/0x2d0
usb_bulk_msg+0x115/0x240
rtsx_usb_transfer_data+0x185/0x1a8 [rtsx_usb]
rtsx_usb_send_cmd+0xbb/0x123 [rtsx_usb]
rtsx_usb_write_register+0x12c/0x143 [rtsx_usb]
rtsx_usb_probe+0x226/0x4b2 [rtsx_usb]

Fix it to use kmalloc() to get DMA-able memory region instead.

Signed-off-by: Shuah Khan <[email protected]>
---
drivers/misc/cardreader/rtsx_usb.c | 13 +++++++------
include/linux/rtsx_usb.h | 1 -
2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c
index 1ef9b61077c4..e147cc8ab0fd 100644
--- a/drivers/misc/cardreader/rtsx_usb.c
+++ b/drivers/misc/cardreader/rtsx_usb.c
@@ -631,8 +631,7 @@ static int rtsx_usb_probe(struct usb_interface *intf,

ucr->pusb_dev = usb_dev;

- ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
- GFP_KERNEL, &ucr->iobuf_dma);
+ ucr->iobuf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
if (!ucr->iobuf)
return -ENOMEM;

@@ -668,8 +667,9 @@ static int rtsx_usb_probe(struct usb_interface *intf,

out_init_fail:
usb_set_intfdata(ucr->pusb_intf, NULL);
- usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
- ucr->iobuf_dma);
+ kfree(ucr->iobuf);
+ ucr->iobuf = NULL;
+ ucr->cmd_buf = ucr->rsp_buf = NULL;
return ret;
}

@@ -682,8 +682,9 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
mfd_remove_devices(&intf->dev);

usb_set_intfdata(ucr->pusb_intf, NULL);
- usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
- ucr->iobuf_dma);
+ kfree(ucr->iobuf);
+ ucr->iobuf = NULL;
+ ucr->cmd_buf = ucr->rsp_buf = NULL;
}

#ifdef CONFIG_PM
diff --git a/include/linux/rtsx_usb.h b/include/linux/rtsx_usb.h
index 159729cffd8e..a07f7341ebc2 100644
--- a/include/linux/rtsx_usb.h
+++ b/include/linux/rtsx_usb.h
@@ -55,7 +55,6 @@ struct rtsx_ucr {
struct usb_interface *pusb_intf;
struct usb_sg_request current_sg;
unsigned char *iobuf;
- dma_addr_t iobuf_dma;

struct timer_list sg_timer;
struct mutex dev_mutex;
--
2.34.1

2022-07-01 02:35:26

by Shuah Khan

[permalink] [raw]
Subject: [PATCH 2/2] misc: rtsx_usb: use separate command and response buffers

rtsx_usb uses same buffer for command and response. There could
be a potential conflict using the same buffer for both especially
if retries and timeouts are involved.

Use separate command and response buffers to avoid conflicts.

Signed-off-by: Shuah Khan <[email protected]>
---
drivers/misc/cardreader/rtsx_usb.c | 26 +++++++++++++++++---------
include/linux/rtsx_usb.h | 1 -
2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c
index e147cc8ab0fd..4e2108052509 100644
--- a/drivers/misc/cardreader/rtsx_usb.c
+++ b/drivers/misc/cardreader/rtsx_usb.c
@@ -631,15 +631,18 @@ static int rtsx_usb_probe(struct usb_interface *intf,

ucr->pusb_dev = usb_dev;

- ucr->iobuf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
- if (!ucr->iobuf)
+ ucr->cmd_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+ if (!ucr->cmd_buf)
return -ENOMEM;

+ ucr->rsp_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+ if (!ucr->rsp_buf)
+ goto out_free_cmd_buf;
+
usb_set_intfdata(intf, ucr);

ucr->vendor_id = id->idVendor;
ucr->product_id = id->idProduct;
- ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;

mutex_init(&ucr->dev_mutex);

@@ -667,9 +670,11 @@ static int rtsx_usb_probe(struct usb_interface *intf,

out_init_fail:
usb_set_intfdata(ucr->pusb_intf, NULL);
- kfree(ucr->iobuf);
- ucr->iobuf = NULL;
- ucr->cmd_buf = ucr->rsp_buf = NULL;
+ kfree(ucr->rsp_buf);
+ ucr->rsp_buf = NULL;
+out_free_cmd_buf:
+ kfree(ucr->cmd_buf);
+ ucr->cmd_buf = NULL;
return ret;
}

@@ -682,9 +687,12 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
mfd_remove_devices(&intf->dev);

usb_set_intfdata(ucr->pusb_intf, NULL);
- kfree(ucr->iobuf);
- ucr->iobuf = NULL;
- ucr->cmd_buf = ucr->rsp_buf = NULL;
+
+ kfree(ucr->cmd_buf);
+ ucr->cmd_buf = NULL;
+
+ kfree(ucr->rsp_buf);
+ ucr->rsp_buf = NULL;
}

#ifdef CONFIG_PM
diff --git a/include/linux/rtsx_usb.h b/include/linux/rtsx_usb.h
index a07f7341ebc2..3247ed8e9ff0 100644
--- a/include/linux/rtsx_usb.h
+++ b/include/linux/rtsx_usb.h
@@ -54,7 +54,6 @@ struct rtsx_ucr {
struct usb_device *pusb_dev;
struct usb_interface *pusb_intf;
struct usb_sg_request current_sg;
- unsigned char *iobuf;

struct timer_list sg_timer;
struct mutex dev_mutex;
--
2.34.1