]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/udl: Sync pending URBs at suspend / disconnect
authorTakashi Iwai <tiwai@suse.de>
Thu, 4 Aug 2022 07:58:24 +0000 (09:58 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Wed, 10 Aug 2022 08:06:58 +0000 (10:06 +0200)
We need to wait for finishing to process the all URBs after disabling
the pipe; otherwise pending URBs may stray at suspend/resume, leading
to a possible memory corruption in a worst case.

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-3-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 e008686ec738ed4bf46cc449402c908ddb120083..f01e50c5b7b78d6e3ba682a93cd3adcfad73a22f 100644 (file)
@@ -83,6 +83,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_urb_completion(struct urb *urb);
 
 int udl_init(struct udl_device *udl);
index 67fd41e59b805781316405a64d5cbb7152fa1d8c..93615648414b54388cfc8a9628ed286390bef126 100644 (file)
@@ -270,6 +270,23 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
        return ret;
 }
 
+/* wait until all pending URBs have been processed */
+int udl_sync_pending_urbs(struct drm_device *dev)
+{
+       struct udl_device *udl = to_udl(dev);
+       int ret = 0;
+
+       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,
+                                        udl->urbs.lock,
+                                        msecs_to_jiffies(2000)))
+               ret = -ETIMEDOUT;
+       spin_unlock_irq(&udl->urbs.lock);
+       return ret;
+}
+
 int udl_init(struct udl_device *udl)
 {
        struct drm_device *dev = &udl->drm;
index e67c40a48fb46cd2ed6d71625667861ecd03cfd5..50025606b6adfebb37a565c64edf280b100ea25f 100644 (file)
@@ -408,6 +408,8 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
        buf = udl_dummy_render(buf);
 
        udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer);
+
+       udl_sync_pending_urbs(dev);
 }
 
 static void