]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/udl: Kill pending URBs at suspend and disconnect
authorTakashi Iwai <tiwai@suse.de>
Thu, 4 Aug 2022 07:58:25 +0000 (09:58 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Wed, 10 Aug 2022 08:07:01 +0000 (10:07 +0200)
At both suspend and disconnect, we should rather cancel the pending
URBs immediately.  For the suspend case, the display will be turned
off, so it makes no sense to process the rendering.  And for the
disconnect case, the device may be no longer accessible, hence we
shouldn't do any submission.

Tested-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20220804075826.27036-4-tiwai@suse.de
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/udl/udl_modeset.c

index f01e50c5b7b78d6e3ba682a93cd3adcfad73a22f..28aaf75d71cf09ffadbcace9acc7506cff3b0793 100644 (file)
@@ -39,6 +39,7 @@ struct urb_node {
 
 struct urb_list {
        struct list_head list;
+       struct list_head in_flight;
        spinlock_t lock;
        wait_queue_head_t sleep;
        int available;
@@ -84,6 +85,7 @@ static inline struct urb *udl_get_urb(struct drm_device *dev)
 
 int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len);
 int udl_sync_pending_urbs(struct drm_device *dev);
+void udl_kill_pending_urbs(struct drm_device *dev);
 void udl_urb_completion(struct urb *urb);
 
 int udl_init(struct udl_device *udl);
index 93615648414b54388cfc8a9628ed286390bef126..47204b7eb10e781db5ddbee5e6cd3aa9cedc3a18 100644 (file)
@@ -135,7 +135,7 @@ void udl_urb_completion(struct urb *urb)
        urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */
 
        spin_lock_irqsave(&udl->urbs.lock, flags);
-       list_add_tail(&unode->entry, &udl->urbs.list);
+       list_move(&unode->entry, &udl->urbs.list);
        udl->urbs.available++;
        spin_unlock_irqrestore(&udl->urbs.lock, flags);
 
@@ -180,6 +180,7 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
 retry:
        udl->urbs.size = size;
        INIT_LIST_HEAD(&udl->urbs.list);
+       INIT_LIST_HEAD(&udl->urbs.in_flight);
 
        init_waitqueue_head(&udl->urbs.sleep);
        udl->urbs.count = 0;
@@ -246,7 +247,7 @@ struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout)
        }
 
        unode = list_first_entry(&udl->urbs.list, struct urb_node, entry);
-       list_del_init(&unode->entry);
+       list_move(&unode->entry, &udl->urbs.in_flight);
        udl->urbs.available--;
 
 unlock:
@@ -279,7 +280,7 @@ int udl_sync_pending_urbs(struct drm_device *dev)
        spin_lock_irq(&udl->urbs.lock);
        /* 2 seconds as a sane timeout */
        if (!wait_event_lock_irq_timeout(udl->urbs.sleep,
-                                        udl->urbs.available == udl->urbs.count,
+                                        list_empty(&udl->urbs.in_flight),
                                         udl->urbs.lock,
                                         msecs_to_jiffies(2000)))
                ret = -ETIMEDOUT;
@@ -287,6 +288,23 @@ int udl_sync_pending_urbs(struct drm_device *dev)
        return ret;
 }
 
+/* kill pending URBs */
+void udl_kill_pending_urbs(struct drm_device *dev)
+{
+       struct udl_device *udl = to_udl(dev);
+       struct urb_node *unode;
+
+       spin_lock_irq(&udl->urbs.lock);
+       while (!list_empty(&udl->urbs.in_flight)) {
+               unode = list_first_entry(&udl->urbs.in_flight,
+                                        struct urb_node, entry);
+               spin_unlock_irq(&udl->urbs.lock);
+               usb_kill_urb(unode->urb);
+               spin_lock_irq(&udl->urbs.lock);
+       }
+       spin_unlock_irq(&udl->urbs.lock);
+}
+
 int udl_init(struct udl_device *udl)
 {
        struct drm_device *dev = &udl->drm;
@@ -335,6 +353,7 @@ int udl_drop_usb(struct drm_device *dev)
 {
        struct udl_device *udl = to_udl(dev);
 
+       udl_kill_pending_urbs(dev);
        udl_free_urb_list(dev);
        put_device(udl->dmadev);
        udl->dmadev = NULL;
index 50025606b6adfebb37a565c64edf280b100ea25f..169110d8fc2e193b235d8b4cc2ee5c4849d49ca0 100644 (file)
@@ -397,6 +397,8 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
        struct urb *urb;
        char *buf;
 
+       udl_kill_pending_urbs(dev);
+
        urb = udl_get_urb(dev);
        if (!urb)
                return;