Patch "USB: HCD: Fix URB giveback issue in tasklet function" has been added to the 5.19-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    USB: HCD: Fix URB giveback issue in tasklet function

to the 5.19-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     usb-hcd-fix-urb-giveback-issue-in-tasklet-function.patch
and it can be found in the queue-5.19 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit bcd8d6752d2fa9b3d117527f7cd8444380afa4a8
Author: Weitao Wang <WeitaoWang-oc@xxxxxxxxxxx>
Date:   Tue Jul 26 15:49:18 2022 +0800

    USB: HCD: Fix URB giveback issue in tasklet function
    
    [ Upstream commit 26c6c2f8a907c9e3a2f24990552a4d77235791e6 ]
    
    Usb core introduce the mechanism of giveback of URB in tasklet context to
    reduce hardware interrupt handling time. On some test situation(such as
    FIO with 4KB block size), when tasklet callback function called to
    giveback URB, interrupt handler add URB node to the bh->head list also.
    If check bh->head list again after finish all URB giveback of local_list,
    then it may introduce a "dynamic balance" between giveback URB and add URB
    to bh->head list. This tasklet callback function may not exit for a long
    time, which will cause other tasklet function calls to be delayed. Some
    real-time applications(such as KB and Mouse) will see noticeable lag.
    
    In order to prevent the tasklet function from occupying the cpu for a long
    time at a time, new URBS will not be added to the local_list even though
    the bh->head list is not empty. But also need to ensure the left URB
    giveback to be processed in time, so add a member high_prio for structure
    giveback_urb_bh to prioritize tasklet and schelule this tasklet again if
    bh->head list is not empty.
    
    At the same time, we are able to prioritize tasklet through structure
    member high_prio. So, replace the local high_prio_bh variable with this
    structure member in usb_hcd_giveback_urb.
    
    Fixes: 94dfd7edfd5c ("USB: HCD: support giveback of URB in tasklet context")
    Cc: stable <stable@xxxxxxxxxx>
    Reviewed-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Weitao Wang <WeitaoWang-oc@xxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20220726074918.5114-1-WeitaoWang-oc@xxxxxxxxxxx
    Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 06eea8848ccc..11c8ea0cccc8 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1691,7 +1691,6 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
 
 	spin_lock_irq(&bh->lock);
 	bh->running = true;
- restart:
 	list_replace_init(&bh->head, &local_list);
 	spin_unlock_irq(&bh->lock);
 
@@ -1705,10 +1704,17 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
 		bh->completing_ep = NULL;
 	}
 
-	/* check if there are new URBs to giveback */
+	/*
+	 * giveback new URBs next time to prevent this function
+	 * from not exiting for a long time.
+	 */
 	spin_lock_irq(&bh->lock);
-	if (!list_empty(&bh->head))
-		goto restart;
+	if (!list_empty(&bh->head)) {
+		if (bh->high_prio)
+			tasklet_hi_schedule(&bh->bh);
+		else
+			tasklet_schedule(&bh->bh);
+	}
 	bh->running = false;
 	spin_unlock_irq(&bh->lock);
 }
@@ -1737,7 +1743,7 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
 void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct giveback_urb_bh *bh;
-	bool running, high_prio_bh;
+	bool running;
 
 	/* pass status to tasklet via unlinked */
 	if (likely(!urb->unlinked))
@@ -1748,13 +1754,10 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 		return;
 	}
 
-	if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+	if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe))
 		bh = &hcd->high_prio_bh;
-		high_prio_bh = true;
-	} else {
+	else
 		bh = &hcd->low_prio_bh;
-		high_prio_bh = false;
-	}
 
 	spin_lock(&bh->lock);
 	list_add_tail(&urb->urb_list, &bh->head);
@@ -1763,7 +1766,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 
 	if (running)
 		;
-	else if (high_prio_bh)
+	else if (bh->high_prio)
 		tasklet_hi_schedule(&bh->bh);
 	else
 		tasklet_schedule(&bh->bh);
@@ -2959,6 +2962,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
 	/* initialize tasklets */
 	init_giveback_urb_bh(&hcd->high_prio_bh);
+	hcd->high_prio_bh.high_prio = true;
 	init_giveback_urb_bh(&hcd->low_prio_bh);
 
 	/* enable irqs just before we start the controller,
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 2c1fc9212cf2..98d1921f02b1 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -66,6 +66,7 @@
 
 struct giveback_urb_bh {
 	bool running;
+	bool high_prio;
 	spinlock_t lock;
 	struct list_head  head;
 	struct tasklet_struct bh;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux