Commit e25d5954 authored by Takashi Iwai's avatar Takashi Iwai Committed by Thomas Zimmermann

drm/udl: Kill pending URBs at suspend and disconnect

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: default avatarThomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20220804075826.27036-4-tiwai@suse.de
parent 0f7dc324
...@@ -39,6 +39,7 @@ struct urb_node { ...@@ -39,6 +39,7 @@ struct urb_node {
struct urb_list { struct urb_list {
struct list_head list; struct list_head list;
struct list_head in_flight;
spinlock_t lock; spinlock_t lock;
wait_queue_head_t sleep; wait_queue_head_t sleep;
int available; int available;
...@@ -84,6 +85,7 @@ static inline struct urb *udl_get_urb(struct drm_device *dev) ...@@ -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_submit_urb(struct drm_device *dev, struct urb *urb, size_t len);
int udl_sync_pending_urbs(struct drm_device *dev); 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); void udl_urb_completion(struct urb *urb);
int udl_init(struct udl_device *udl); int udl_init(struct udl_device *udl);
......
...@@ -135,7 +135,7 @@ void udl_urb_completion(struct urb *urb) ...@@ -135,7 +135,7 @@ void udl_urb_completion(struct urb *urb)
urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */ urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */
spin_lock_irqsave(&udl->urbs.lock, flags); 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++; udl->urbs.available++;
spin_unlock_irqrestore(&udl->urbs.lock, flags); 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) ...@@ -180,6 +180,7 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
retry: retry:
udl->urbs.size = size; udl->urbs.size = size;
INIT_LIST_HEAD(&udl->urbs.list); INIT_LIST_HEAD(&udl->urbs.list);
INIT_LIST_HEAD(&udl->urbs.in_flight);
init_waitqueue_head(&udl->urbs.sleep); init_waitqueue_head(&udl->urbs.sleep);
udl->urbs.count = 0; udl->urbs.count = 0;
...@@ -246,7 +247,7 @@ struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout) ...@@ -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); 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--; udl->urbs.available--;
unlock: unlock:
...@@ -279,7 +280,7 @@ int udl_sync_pending_urbs(struct drm_device *dev) ...@@ -279,7 +280,7 @@ int udl_sync_pending_urbs(struct drm_device *dev)
spin_lock_irq(&udl->urbs.lock); spin_lock_irq(&udl->urbs.lock);
/* 2 seconds as a sane timeout */ /* 2 seconds as a sane timeout */
if (!wait_event_lock_irq_timeout(udl->urbs.sleep, if (!wait_event_lock_irq_timeout(udl->urbs.sleep,
udl->urbs.available == udl->urbs.count, list_empty(&udl->urbs.in_flight),
udl->urbs.lock, udl->urbs.lock,
msecs_to_jiffies(2000))) msecs_to_jiffies(2000)))
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
...@@ -287,6 +288,23 @@ int udl_sync_pending_urbs(struct drm_device *dev) ...@@ -287,6 +288,23 @@ int udl_sync_pending_urbs(struct drm_device *dev)
return ret; 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) int udl_init(struct udl_device *udl)
{ {
struct drm_device *dev = &udl->drm; struct drm_device *dev = &udl->drm;
...@@ -335,6 +353,7 @@ int udl_drop_usb(struct drm_device *dev) ...@@ -335,6 +353,7 @@ int udl_drop_usb(struct drm_device *dev)
{ {
struct udl_device *udl = to_udl(dev); struct udl_device *udl = to_udl(dev);
udl_kill_pending_urbs(dev);
udl_free_urb_list(dev); udl_free_urb_list(dev);
put_device(udl->dmadev); put_device(udl->dmadev);
udl->dmadev = NULL; udl->dmadev = NULL;
......
...@@ -397,6 +397,8 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) ...@@ -397,6 +397,8 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
struct urb *urb; struct urb *urb;
char *buf; char *buf;
udl_kill_pending_urbs(dev);
urb = udl_get_urb(dev); urb = udl_get_urb(dev);
if (!urb) if (!urb)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment