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 e008686..f01e50c 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 67fd41e..9361564 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 e67c40a..5002560 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