dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/11] drm/udl: More fixes
@ 2022-09-06  7:39 Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 01/11] drm/udl: Restore display mode on resume Takashi Iwai
                   ` (10 more replies)
  0 siblings, 11 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

Hi,

this is a revised patch set for cleaning up and fixes for UDL driver.
It covers the PM problems, regressions in the previous patch set,
fixes for the stalls on some systems, as well as more hardening.


Takashi

===

v1->v2: cleanups as suggested by Thomas
- Drop numurbs parameter patch
- Clean up / simplify clipping patch
- Code cleanup and changes for urb management patch
- Put Acks on some given patches

===

Takashi Iwai (8):
  Revert "drm/udl: Kill pending URBs at suspend and disconnect"
  drm/udl: Suppress error print for -EPROTO at URB completion
  drm/udl: Increase the default URB list size to 20
  drm/udl: Drop unneeded alignment
  drm/udl: Fix potential URB leaks
  drm/udl: Fix inconsistent urbs.count value during udl_free_urb_list()
  drm/udl: Don't re-initialize stuff at retrying the URB list allocation
  drm/udl: Sync pending URBs at the end of suspend

Thomas Zimmermann (3):
  drm/udl: Restore display mode on resume
  drm/udl: Add reset_resume
  drm/udl: Enable damage clipping

 drivers/gpu/drm/udl/udl_drv.c      | 19 +++++-
 drivers/gpu/drm/udl/udl_drv.h      | 13 +---
 drivers/gpu/drm/udl/udl_main.c     | 95 +++++++++++++++---------------
 drivers/gpu/drm/udl/udl_modeset.c  | 36 ++---------
 drivers/gpu/drm/udl/udl_transfer.c | 45 ++------------
 5 files changed, 75 insertions(+), 133 deletions(-)

-- 
2.35.3


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 01/11] drm/udl: Restore display mode on resume
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 02/11] drm/udl: Add reset_resume Takashi Iwai
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

From: Thomas Zimmermann <tzimmermann@suse.de>

Restore the display mode whne resuming from suspend. Currently, the
display remains dark.

On resume, the CRTC's mode does not change, but the 'active' flag
changes to 'true'. Taking this into account when considering a mode
switch restores the display mode.

The bug is reproducable by using Gnome with udl and observing the
adapter's suspend/resume behavior.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_modeset.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 169110d8fc2e..df987644fb5d 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -8,6 +8,7 @@
  * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_damage_helper.h>
@@ -382,7 +383,7 @@ udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	udl_handle_damage(fb, &shadow_plane_state->data[0], 0, 0, fb->width, fb->height);
 
-	if (!crtc_state->mode_changed)
+	if (!drm_atomic_crtc_needs_modeset(crtc_state))
 		return;
 
 	/* enable display */
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 02/11] drm/udl: Add reset_resume
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 01/11] drm/udl: Restore display mode on resume Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-07  6:58   ` Daniel Vetter
  2022-09-06  7:39 ` [PATCH v2 03/11] drm/udl: Enable damage clipping Takashi Iwai
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

From: Thomas Zimmermann <tzimmermann@suse.de>

Implement the reset_resume callback of struct usb_driver. Set the
standard channel when called.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_drv.c  | 11 +++++++++++
 drivers/gpu/drm/udl/udl_drv.h  |  1 +
 drivers/gpu/drm/udl/udl_main.c |  2 +-
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 5703277c6f52..0ba88e5472a9 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -32,6 +32,16 @@ static int udl_usb_resume(struct usb_interface *interface)
 	return drm_mode_config_helper_resume(dev);
 }
 
+static int udl_usb_reset_resume(struct usb_interface *interface)
+{
+	struct drm_device *dev = usb_get_intfdata(interface);
+	struct udl_device *udl = to_udl(dev);
+
+	udl_select_std_channel(udl);
+
+	return drm_mode_config_helper_resume(dev);
+}
+
 /*
  * FIXME: Dma-buf sharing requires DMA support by the importing device.
  *        This function is a workaround to make USB devices work as well.
@@ -140,6 +150,7 @@ static struct usb_driver udl_driver = {
 	.disconnect = udl_usb_disconnect,
 	.suspend = udl_usb_suspend,
 	.resume = udl_usb_resume,
+	.reset_resume = udl_usb_reset_resume,
 	.id_table = id_table,
 };
 module_usb_driver(udl_driver);
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 28aaf75d71cf..37c14b0ff1fc 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -95,6 +95,7 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr,
 		     u32 byte_offset, u32 device_byte_offset, u32 byte_width);
 
 int udl_drop_usb(struct drm_device *dev);
+int udl_select_std_channel(struct udl_device *udl);
 
 #define CMD_WRITE_RAW8   "\xAF\x60" /**< 8 bit raw write command. */
 #define CMD_WRITE_RL8    "\xAF\x61" /**< 8 bit run length command. */
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index fdafbf8f3c3c..7d1e6bbc165c 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -92,7 +92,7 @@ static int udl_parse_vendor_descriptor(struct udl_device *udl)
 /*
  * Need to ensure a channel is selected before submitting URBs
  */
-static int udl_select_std_channel(struct udl_device *udl)
+int udl_select_std_channel(struct udl_device *udl)
 {
 	static const u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7,
 					 0x1C, 0x88, 0x5E, 0x15,
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 03/11] drm/udl: Enable damage clipping
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 01/11] drm/udl: Restore display mode on resume Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 02/11] drm/udl: Add reset_resume Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 04/11] Revert "drm/udl: Kill pending URBs at suspend and disconnect" Takashi Iwai
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

From: Thomas Zimmermann <tzimmermann@suse.de>

Call drm_plane_enable_fb_damage_clips() and give userspace a chance
of minimizing the updated display area.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_modeset.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index df987644fb5d..187aba2d7825 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -484,6 +484,7 @@ int udl_modeset_init(struct drm_device *dev)
 					   format_count, NULL, connector);
 	if (ret)
 		return ret;
+	drm_plane_enable_fb_damage_clips(&udl->display_pipe.plane);
 
 	drm_mode_config_reset(dev);
 
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 04/11] Revert "drm/udl: Kill pending URBs at suspend and disconnect"
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (2 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 03/11] drm/udl: Enable damage clipping Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 05/11] drm/udl: Suppress error print for -EPROTO at URB completion Takashi Iwai
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

This reverts the recent fix commit
  e25d5954264d ("drm/udl: Kill pending URBs at suspend and disconnect")
as it turned out to lead to potential hangup at a disconnection, and
it doesn't help much for suspend/resume problem, either.

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_drv.h     |  2 --
 drivers/gpu/drm/udl/udl_main.c    | 25 +++----------------------
 drivers/gpu/drm/udl/udl_modeset.c |  2 --
 3 files changed, 3 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 37c14b0ff1fc..5923d2e02bc8 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -39,7 +39,6 @@ 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;
@@ -85,7 +84,6 @@ 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);
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index 7d1e6bbc165c..a9f6b710b254 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -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_move(&unode->entry, &udl->urbs.list);
+	list_add_tail(&unode->entry, &udl->urbs.list);
 	udl->urbs.available++;
 	spin_unlock_irqrestore(&udl->urbs.lock, flags);
 
@@ -180,7 +180,6 @@ 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;
@@ -247,7 +246,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_move(&unode->entry, &udl->urbs.in_flight);
+	list_del_init(&unode->entry);
 	udl->urbs.available--;
 
 unlock:
@@ -281,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,
-					 list_empty(&udl->urbs.in_flight),
+					 udl->urbs.available == udl->urbs.count,
 					 udl->urbs.lock,
 					 msecs_to_jiffies(2000)))
 		ret = -ETIMEDOUT;
@@ -289,23 +288,6 @@ 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;
@@ -354,7 +336,6 @@ 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;
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 187aba2d7825..c34d564773a3 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -398,8 +398,6 @@ 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;
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 05/11] drm/udl: Suppress error print for -EPROTO at URB completion
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (3 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 04/11] Revert "drm/udl: Kill pending URBs at suspend and disconnect" Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 06/11] drm/udl: Increase the default URB list size to 20 Takashi Iwai
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

The driver may receive -EPROTO at the URB completion when the device
gets disconnected, and it's a normal situation.  Suppress the error
print for that, too.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index a9f6b710b254..6aed6e0f669c 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -126,6 +126,7 @@ void udl_urb_completion(struct urb *urb)
 	if (urb->status) {
 		if (!(urb->status == -ENOENT ||
 		    urb->status == -ECONNRESET ||
+		    urb->status == -EPROTO ||
 		    urb->status == -ESHUTDOWN)) {
 			DRM_ERROR("%s - nonzero write bulk status received: %d\n",
 				__func__, urb->status);
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 06/11] drm/udl: Increase the default URB list size to 20
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (4 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 05/11] drm/udl: Suppress error print for -EPROTO at URB completion Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 07/11] drm/udl: Drop unneeded alignment Takashi Iwai
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

It seems that the current size (4) for the URB list is too small on
some devices, and it resulted in the occasional stalls.  Increase the
default URB list size to 20 for working around it.

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index 6aed6e0f669c..2b7eafd48ec2 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -20,7 +20,7 @@
 #define NR_USB_REQUEST_CHANNEL 0x12
 
 #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
-#define WRITES_IN_FLIGHT (4)
+#define WRITES_IN_FLIGHT (20)
 #define MAX_VENDOR_DESCRIPTOR_SIZE 256
 
 static int udl_parse_vendor_descriptor(struct udl_device *udl)
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 07/11] drm/udl: Drop unneeded alignment
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (5 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 06/11] drm/udl: Increase the default URB list size to 20 Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-07  7:29   ` Thomas Zimmermann
  2022-09-06  7:39 ` [PATCH v2 08/11] drm/udl: Fix potential URB leaks Takashi Iwai
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

The alignment of damaged area was needed for the original udlfb driver
that tried to trim the superfluous copies between front and backend
buffers and handle data in long int.  It's not the case for udl DRM
driver, hence we can omit the whole unneeded alignment, as well as the
dead code.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_modeset.c  | 28 +--------------------
 drivers/gpu/drm/udl/udl_transfer.c | 40 ------------------------------
 2 files changed, 1 insertion(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index c34d564773a3..9896c16c74f5 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -243,28 +243,6 @@ static long udl_log_cpp(unsigned int cpp)
 	return __ffs(cpp);
 }
 
-static int udl_aligned_damage_clip(struct drm_rect *clip, int x, int y,
-				   int width, int height)
-{
-	int x1, x2;
-
-	if (WARN_ON_ONCE(x < 0) ||
-	    WARN_ON_ONCE(y < 0) ||
-	    WARN_ON_ONCE(width < 0) ||
-	    WARN_ON_ONCE(height < 0))
-		return -EINVAL;
-
-	x1 = ALIGN_DOWN(x, sizeof(unsigned long));
-	x2 = ALIGN(width + (x - x1), sizeof(unsigned long)) + x1;
-
-	clip->x1 = x1;
-	clip->y1 = y;
-	clip->x2 = x2;
-	clip->y2 = y + height;
-
-	return 0;
-}
-
 static int udl_handle_damage(struct drm_framebuffer *fb,
 			     const struct iosys_map *map,
 			     int x, int y, int width, int height)
@@ -282,11 +260,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb,
 		return ret;
 	log_bpp = ret;
 
-	ret = udl_aligned_damage_clip(&clip, x, y, width, height);
-	if (ret)
-		return ret;
-	else if ((clip.x2 > fb->width) || (clip.y2 > fb->height))
-		return -EINVAL;
+	drm_rect_init(&clip, x, y, width, height);
 
 	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
 	if (ret)
diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
index 176ef2a6a731..a431208dda85 100644
--- a/drivers/gpu/drm/udl/udl_transfer.c
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -25,46 +25,6 @@
 #define MIN_RAW_PIX_BYTES	2
 #define MIN_RAW_CMD_BYTES	(RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
 
-/*
- * Trims identical data from front and back of line
- * Sets new front buffer address and width
- * And returns byte count of identical pixels
- * Assumes CPU natural alignment (unsigned long)
- * for back and front buffer ptrs and width
- */
-#if 0
-static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
-{
-	int j, k;
-	const unsigned long *back = (const unsigned long *) bback;
-	const unsigned long *front = (const unsigned long *) *bfront;
-	const int width = *width_bytes / sizeof(unsigned long);
-	int identical = width;
-	int start = width;
-	int end = width;
-
-	for (j = 0; j < width; j++) {
-		if (back[j] != front[j]) {
-			start = j;
-			break;
-		}
-	}
-
-	for (k = width - 1; k > j; k--) {
-		if (back[k] != front[k]) {
-			end = k+1;
-			break;
-		}
-	}
-
-	identical = start + (width - end);
-	*bfront = (u8 *) &front[start];
-	*width_bytes = (end - start) * sizeof(unsigned long);
-
-	return identical * sizeof(unsigned long);
-}
-#endif
-
 static inline u16 pixel32_to_be16(const uint32_t pixel)
 {
 	return (((pixel >> 3) & 0x001f) |
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 08/11] drm/udl: Fix potential URB leaks
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (6 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 07/11] drm/udl: Drop unneeded alignment Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 09/11] drm/udl: Fix inconsistent urbs.count value during udl_free_urb_list() Takashi Iwai
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

A couple of error handlings forgot to process the URB completion.
Those are both with WARN_ON() so should be visible, but we must fix
them in anyway.

Fixes: 7350b2a3fbc6 ("drm/udl: Replace BUG_ON() with WARN_ON()")
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_main.c     | 8 +++++---
 drivers/gpu/drm/udl/udl_transfer.c | 5 ++++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index 2b7eafd48ec2..de28eeff3155 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -260,11 +260,13 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
 	struct udl_device *udl = to_udl(dev);
 	int ret;
 
-	if (WARN_ON(len > udl->urbs.size))
-		return -EINVAL;
-
+	if (WARN_ON(len > udl->urbs.size)) {
+		ret = -EINVAL;
+		goto error;
+	}
 	urb->transfer_buffer_length = len; /* set to actual payload len */
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
+ error:
 	if (ret) {
 		udl_urb_completion(urb); /* because no one else will */
 		DRM_ERROR("usb_submit_urb error %x\n", ret);
diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
index a431208dda85..b57844632dbd 100644
--- a/drivers/gpu/drm/udl/udl_transfer.c
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -180,8 +180,11 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr,
 	u8 *cmd = *urb_buf_ptr;
 	u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
 
-	if (WARN_ON(!(log_bpp == 1 || log_bpp == 2)))
+	if (WARN_ON(!(log_bpp == 1 || log_bpp == 2))) {
+		/* need to finish URB at error from this function */
+		udl_urb_completion(urb);
 		return -EINVAL;
+	}
 
 	line_start = (u8 *) (front + byte_offset);
 	next_pixel = line_start;
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 09/11] drm/udl: Fix inconsistent urbs.count value during udl_free_urb_list()
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (7 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 08/11] drm/udl: Fix potential URB leaks Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-07  7:31   ` Thomas Zimmermann
  2022-09-06  7:39 ` [PATCH v2 10/11] drm/udl: Don't re-initialize stuff at retrying the URB list allocation Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 11/11] drm/udl: Sync pending URBs at the end of suspend Takashi Iwai
  10 siblings, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

In the current design, udl_get_urb() may be called asynchronously
during the driver freeing its URL list via udl_free_urb_list().
The problem is that the sync is determined by comparing the urbs.count
and urbs.available fields, while we clear urbs.count field only once
after udl_free_urb_list() finishes, i.e. during udl_free_urb_list(),
the state becomes inconsistent.

For fixing this inconsistency and also for hardening the locking
scheme, this patch does a slight refactoring of the code around
udl_get_urb() and udl_free_urb_list().  Now urbs.count is updated in
the same spinlock at extracting a URB from the list in
udl_free_url_list().

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_drv.h  |  8 +------
 drivers/gpu/drm/udl/udl_main.c | 44 +++++++++++++++++++++++-----------
 2 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 5923d2e02bc8..d943684b5bbb 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -74,13 +74,7 @@ static inline struct usb_device *udl_to_usb_device(struct udl_device *udl)
 int udl_modeset_init(struct drm_device *dev);
 struct drm_connector *udl_connector_init(struct drm_device *dev);
 
-struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout);
-
-#define GET_URB_TIMEOUT	HZ
-static inline struct urb *udl_get_urb(struct drm_device *dev)
-{
-	return udl_get_urb_timeout(dev, GET_URB_TIMEOUT);
-}
+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);
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index de28eeff3155..df7ebe1fdc90 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -23,6 +23,8 @@
 #define WRITES_IN_FLIGHT (20)
 #define MAX_VENDOR_DESCRIPTOR_SIZE 256
 
+static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout);
+
 static int udl_parse_vendor_descriptor(struct udl_device *udl)
 {
 	struct usb_device *udev = udl_to_usb_device(udl);
@@ -140,21 +142,23 @@ void udl_urb_completion(struct urb *urb)
 	udl->urbs.available++;
 	spin_unlock_irqrestore(&udl->urbs.lock, flags);
 
-	wake_up(&udl->urbs.sleep);
+	wake_up_all(&udl->urbs.sleep);
 }
 
 static void udl_free_urb_list(struct drm_device *dev)
 {
 	struct udl_device *udl = to_udl(dev);
-	int count = udl->urbs.count;
 	struct urb_node *unode;
 	struct urb *urb;
 
 	DRM_DEBUG("Waiting for completes and freeing all render urbs\n");
 
 	/* keep waiting and freeing, until we've got 'em all */
-	while (count--) {
-		urb = udl_get_urb_timeout(dev, MAX_SCHEDULE_TIMEOUT);
+	while (udl->urbs.count) {
+		spin_lock_irq(&udl->urbs.lock);
+		urb = udl_get_urb_locked(udl, MAX_SCHEDULE_TIMEOUT);
+		udl->urbs.count--;
+		spin_unlock_irq(&udl->urbs.lock);
 		if (WARN_ON(!urb))
 			break;
 		unode = urb->context;
@@ -164,7 +168,8 @@ static void udl_free_urb_list(struct drm_device *dev)
 		usb_free_urb(urb);
 		kfree(unode);
 	}
-	udl->urbs.count = 0;
+
+	wake_up(&udl->urbs.sleep);
 }
 
 static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
@@ -228,33 +233,44 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
 	return udl->urbs.count;
 }
 
-struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout)
+static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout)
 {
-	struct udl_device *udl = to_udl(dev);
-	struct urb_node *unode = NULL;
+	struct urb_node *unode;
 
-	if (!udl->urbs.count)
-		return NULL;
+	assert_spin_locked(&udl->urbs.lock);
 
 	/* Wait for an in-flight buffer to complete and get re-queued */
-	spin_lock_irq(&udl->urbs.lock);
 	if (!wait_event_lock_irq_timeout(udl->urbs.sleep,
+					 !udl->urbs.count ||
 					 !list_empty(&udl->urbs.list),
 					 udl->urbs.lock, timeout)) {
 		DRM_INFO("wait for urb interrupted: available: %d\n",
 			 udl->urbs.available);
-		goto unlock;
+		return NULL;
 	}
 
+	if (!udl->urbs.count)
+		return NULL;
+
 	unode = list_first_entry(&udl->urbs.list, struct urb_node, entry);
 	list_del_init(&unode->entry);
 	udl->urbs.available--;
 
-unlock:
-	spin_unlock_irq(&udl->urbs.lock);
 	return unode ? unode->urb : NULL;
 }
 
+#define GET_URB_TIMEOUT	HZ
+struct urb *udl_get_urb(struct drm_device *dev)
+{
+	struct udl_device *udl = to_udl(dev);
+	struct urb *urb;
+
+	spin_lock_irq(&udl->urbs.lock);
+	urb = udl_get_urb_locked(udl, GET_URB_TIMEOUT);
+	spin_unlock_irq(&udl->urbs.lock);
+	return urb;
+}
+
 int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
 {
 	struct udl_device *udl = to_udl(dev);
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 10/11] drm/udl: Don't re-initialize stuff at retrying the URB list allocation
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (8 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 09/11] drm/udl: Fix inconsistent urbs.count value during udl_free_urb_list() Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-06  7:39 ` [PATCH v2 11/11] drm/udl: Sync pending URBs at the end of suspend Takashi Iwai
  10 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

udl_alloc_urb_list() retires the allocation if there is no enough room
left, and it reinitializes the stuff unnecessarily such as the linked
list head and the waitqueue, which could be harmful.  Those should be
outside the retry loop.

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_main.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index df7ebe1fdc90..808a5ab5e14e 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -182,15 +182,14 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
 	struct usb_device *udev = udl_to_usb_device(udl);
 
 	spin_lock_init(&udl->urbs.lock);
-
-retry:
-	udl->urbs.size = size;
 	INIT_LIST_HEAD(&udl->urbs.list);
-
 	init_waitqueue_head(&udl->urbs.sleep);
 	udl->urbs.count = 0;
 	udl->urbs.available = 0;
 
+retry:
+	udl->urbs.size = size;
+
 	while (udl->urbs.count * size < wanted_size) {
 		unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
 		if (!unode)
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 11/11] drm/udl: Sync pending URBs at the end of suspend
  2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
                   ` (9 preceding siblings ...)
  2022-09-06  7:39 ` [PATCH v2 10/11] drm/udl: Don't re-initialize stuff at retrying the URB list allocation Takashi Iwai
@ 2022-09-06  7:39 ` Takashi Iwai
  2022-09-07  7:34   ` Thomas Zimmermann
  10 siblings, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2022-09-06  7:39 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

It's better to perform the sync at the very last of the suspend
instead of the pipe-disable function, so that we can catch all pending
URBs (if any).

While we're at it, drop the error code from udl_sync_pending_urb()
since we basically ignore it; instead, give a clear error message
indicating a problem.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/udl/udl_drv.c     | 8 +++++++-
 drivers/gpu/drm/udl/udl_drv.h     | 2 +-
 drivers/gpu/drm/udl/udl_main.c    | 6 ++----
 drivers/gpu/drm/udl/udl_modeset.c | 2 --
 4 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 0ba88e5472a9..91effdcefb6d 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -21,8 +21,14 @@ static int udl_usb_suspend(struct usb_interface *interface,
 			   pm_message_t message)
 {
 	struct drm_device *dev = usb_get_intfdata(interface);
+	int ret;
 
-	return drm_mode_config_helper_suspend(dev);
+	ret = drm_mode_config_helper_suspend(dev);
+	if (ret)
+		return ret;
+
+	udl_sync_pending_urbs(dev);
+	return 0;
 }
 
 static int udl_usb_resume(struct usb_interface *interface)
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index d943684b5bbb..b4cc7cc568c7 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -77,7 +77,7 @@ struct drm_connector *udl_connector_init(struct drm_device *dev);
 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_sync_pending_urbs(struct drm_device *dev);
 void udl_urb_completion(struct urb *urb);
 
 int udl_init(struct udl_device *udl);
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index 808a5ab5e14e..442080fa1061 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -290,10 +290,9 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
 }
 
 /* wait until all pending URBs have been processed */
-int udl_sync_pending_urbs(struct drm_device *dev)
+void 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 */
@@ -301,9 +300,8 @@ int udl_sync_pending_urbs(struct drm_device *dev)
 					 udl->urbs.available == udl->urbs.count,
 					 udl->urbs.lock,
 					 msecs_to_jiffies(2000)))
-		ret = -ETIMEDOUT;
+		drm_err(dev, "Timeout for syncing pending URBs\n");
 	spin_unlock_irq(&udl->urbs.lock);
-	return ret;
 }
 
 int udl_init(struct udl_device *udl)
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 9896c16c74f5..c506fff8f0c4 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -383,8 +383,6 @@ 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
-- 
2.35.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 02/11] drm/udl: Add reset_resume
  2022-09-06  7:39 ` [PATCH v2 02/11] drm/udl: Add reset_resume Takashi Iwai
@ 2022-09-07  6:58   ` Daniel Vetter
  0 siblings, 0 replies; 17+ messages in thread
From: Daniel Vetter @ 2022-09-07  6:58 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: dri-devel, linux-kernel, Thomas Zimmermann

On Tue, Sep 06, 2022 at 09:39:42AM +0200, Takashi Iwai wrote:
> From: Thomas Zimmermann <tzimmermann@suse.de>
> 
> Implement the reset_resume callback of struct usb_driver. Set the
> standard channel when called.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>  drivers/gpu/drm/udl/udl_drv.c  | 11 +++++++++++
>  drivers/gpu/drm/udl/udl_drv.h  |  1 +
>  drivers/gpu/drm/udl/udl_main.c |  2 +-
>  3 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
> index 5703277c6f52..0ba88e5472a9 100644
> --- a/drivers/gpu/drm/udl/udl_drv.c
> +++ b/drivers/gpu/drm/udl/udl_drv.c
> @@ -32,6 +32,16 @@ static int udl_usb_resume(struct usb_interface *interface)
>  	return drm_mode_config_helper_resume(dev);
>  }
>  
> +static int udl_usb_reset_resume(struct usb_interface *interface)
> +{
> +	struct drm_device *dev = usb_get_intfdata(interface);
> +	struct udl_device *udl = to_udl(dev);
> +
> +	udl_select_std_channel(udl);
> +
> +	return drm_mode_config_helper_resume(dev);

Bit a bikeshed, but in the driver load case it would be neat to put the
call to udl_select_std_channel right above the call to
drm_mode_config_reset. But that is _really_ a bikeshed :-)

Also thanks for sending me on a bit a wild goose chase trying to figure
out what this reset_resume hook actually does and why.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> +}
> +
>  /*
>   * FIXME: Dma-buf sharing requires DMA support by the importing device.
>   *        This function is a workaround to make USB devices work as well.
> @@ -140,6 +150,7 @@ static struct usb_driver udl_driver = {
>  	.disconnect = udl_usb_disconnect,
>  	.suspend = udl_usb_suspend,
>  	.resume = udl_usb_resume,
> +	.reset_resume = udl_usb_reset_resume,
>  	.id_table = id_table,
>  };
>  module_usb_driver(udl_driver);
> diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
> index 28aaf75d71cf..37c14b0ff1fc 100644
> --- a/drivers/gpu/drm/udl/udl_drv.h
> +++ b/drivers/gpu/drm/udl/udl_drv.h
> @@ -95,6 +95,7 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr,
>  		     u32 byte_offset, u32 device_byte_offset, u32 byte_width);
>  
>  int udl_drop_usb(struct drm_device *dev);
> +int udl_select_std_channel(struct udl_device *udl);
>  
>  #define CMD_WRITE_RAW8   "\xAF\x60" /**< 8 bit raw write command. */
>  #define CMD_WRITE_RL8    "\xAF\x61" /**< 8 bit run length command. */
> diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
> index fdafbf8f3c3c..7d1e6bbc165c 100644
> --- a/drivers/gpu/drm/udl/udl_main.c
> +++ b/drivers/gpu/drm/udl/udl_main.c
> @@ -92,7 +92,7 @@ static int udl_parse_vendor_descriptor(struct udl_device *udl)
>  /*
>   * Need to ensure a channel is selected before submitting URBs
>   */
> -static int udl_select_std_channel(struct udl_device *udl)
> +int udl_select_std_channel(struct udl_device *udl)
>  {
>  	static const u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7,
>  					 0x1C, 0x88, 0x5E, 0x15,
> -- 
> 2.35.3
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 07/11] drm/udl: Drop unneeded alignment
  2022-09-06  7:39 ` [PATCH v2 07/11] drm/udl: Drop unneeded alignment Takashi Iwai
@ 2022-09-07  7:29   ` Thomas Zimmermann
  2022-09-08  7:01     ` Takashi Iwai
  0 siblings, 1 reply; 17+ messages in thread
From: Thomas Zimmermann @ 2022-09-07  7:29 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: linux-kernel, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 4081 bytes --]

Hi

Am 06.09.22 um 09:39 schrieb Takashi Iwai:
> The alignment of damaged area was needed for the original udlfb driver
> that tried to trim the superfluous copies between front and backend
> buffers and handle data in long int.  It's not the case for udl DRM
> driver, hence we can omit the whole unneeded alignment, as well as the
> dead code.
> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>

with an entirely optional comment below.

> ---
>   drivers/gpu/drm/udl/udl_modeset.c  | 28 +--------------------
>   drivers/gpu/drm/udl/udl_transfer.c | 40 ------------------------------
>   2 files changed, 1 insertion(+), 67 deletions(-)
> 
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index c34d564773a3..9896c16c74f5 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -243,28 +243,6 @@ static long udl_log_cpp(unsigned int cpp)
>   	return __ffs(cpp);
>   }
>   
> -static int udl_aligned_damage_clip(struct drm_rect *clip, int x, int y,
> -				   int width, int height)
> -{
> -	int x1, x2;
> -
> -	if (WARN_ON_ONCE(x < 0) ||
> -	    WARN_ON_ONCE(y < 0) ||
> -	    WARN_ON_ONCE(width < 0) ||
> -	    WARN_ON_ONCE(height < 0))
> -		return -EINVAL;
> -
> -	x1 = ALIGN_DOWN(x, sizeof(unsigned long));
> -	x2 = ALIGN(width + (x - x1), sizeof(unsigned long)) + x1;
> -
> -	clip->x1 = x1;
> -	clip->y1 = y;
> -	clip->x2 = x2;
> -	clip->y2 = y + height;
> -
> -	return 0;
> -}
> -
>   static int udl_handle_damage(struct drm_framebuffer *fb,
>   			     const struct iosys_map *map,
>   			     int x, int y, int width, int height)
> @@ -282,11 +260,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb,
>   		return ret;
>   	log_bpp = ret;
>   
> -	ret = udl_aligned_damage_clip(&clip, x, y, width, height);
> -	if (ret)
> -		return ret;
> -	else if ((clip.x2 > fb->width) || (clip.y2 > fb->height))
> -		return -EINVAL;
> +	drm_rect_init(&clip, x, y, width, height);

The clip rectangle could be passed directly by the caller, which would 
simplify the update function. But that's really just nitpicking.

Best regards
Thomas

>   
>   	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
>   	if (ret)
> diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
> index 176ef2a6a731..a431208dda85 100644
> --- a/drivers/gpu/drm/udl/udl_transfer.c
> +++ b/drivers/gpu/drm/udl/udl_transfer.c
> @@ -25,46 +25,6 @@
>   #define MIN_RAW_PIX_BYTES	2
>   #define MIN_RAW_CMD_BYTES	(RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
>   
> -/*
> - * Trims identical data from front and back of line
> - * Sets new front buffer address and width
> - * And returns byte count of identical pixels
> - * Assumes CPU natural alignment (unsigned long)
> - * for back and front buffer ptrs and width
> - */
> -#if 0
> -static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
> -{
> -	int j, k;
> -	const unsigned long *back = (const unsigned long *) bback;
> -	const unsigned long *front = (const unsigned long *) *bfront;
> -	const int width = *width_bytes / sizeof(unsigned long);
> -	int identical = width;
> -	int start = width;
> -	int end = width;
> -
> -	for (j = 0; j < width; j++) {
> -		if (back[j] != front[j]) {
> -			start = j;
> -			break;
> -		}
> -	}
> -
> -	for (k = width - 1; k > j; k--) {
> -		if (back[k] != front[k]) {
> -			end = k+1;
> -			break;
> -		}
> -	}
> -
> -	identical = start + (width - end);
> -	*bfront = (u8 *) &front[start];
> -	*width_bytes = (end - start) * sizeof(unsigned long);
> -
> -	return identical * sizeof(unsigned long);
> -}
> -#endif
> -
>   static inline u16 pixel32_to_be16(const uint32_t pixel)
>   {
>   	return (((pixel >> 3) & 0x001f) |

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 09/11] drm/udl: Fix inconsistent urbs.count value during udl_free_urb_list()
  2022-09-06  7:39 ` [PATCH v2 09/11] drm/udl: Fix inconsistent urbs.count value during udl_free_urb_list() Takashi Iwai
@ 2022-09-07  7:31   ` Thomas Zimmermann
  0 siblings, 0 replies; 17+ messages in thread
From: Thomas Zimmermann @ 2022-09-07  7:31 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: linux-kernel, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 5627 bytes --]

Hi

Am 06.09.22 um 09:39 schrieb Takashi Iwai:
> In the current design, udl_get_urb() may be called asynchronously
> during the driver freeing its URL list via udl_free_urb_list().
> The problem is that the sync is determined by comparing the urbs.count
> and urbs.available fields, while we clear urbs.count field only once
> after udl_free_urb_list() finishes, i.e. during udl_free_urb_list(),
> the state becomes inconsistent.
> 
> For fixing this inconsistency and also for hardening the locking
> scheme, this patch does a slight refactoring of the code around
> udl_get_urb() and udl_free_urb_list().  Now urbs.count is updated in
> the same spinlock at extracting a URB from the list in
> udl_free_url_list().
> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>   drivers/gpu/drm/udl/udl_drv.h  |  8 +------
>   drivers/gpu/drm/udl/udl_main.c | 44 +++++++++++++++++++++++-----------
>   2 files changed, 31 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
> index 5923d2e02bc8..d943684b5bbb 100644
> --- a/drivers/gpu/drm/udl/udl_drv.h
> +++ b/drivers/gpu/drm/udl/udl_drv.h
> @@ -74,13 +74,7 @@ static inline struct usb_device *udl_to_usb_device(struct udl_device *udl)
>   int udl_modeset_init(struct drm_device *dev);
>   struct drm_connector *udl_connector_init(struct drm_device *dev);
>   
> -struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout);
> -
> -#define GET_URB_TIMEOUT	HZ
> -static inline struct urb *udl_get_urb(struct drm_device *dev)
> -{
> -	return udl_get_urb_timeout(dev, GET_URB_TIMEOUT);
> -}
> +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);
> diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
> index de28eeff3155..df7ebe1fdc90 100644
> --- a/drivers/gpu/drm/udl/udl_main.c
> +++ b/drivers/gpu/drm/udl/udl_main.c
> @@ -23,6 +23,8 @@
>   #define WRITES_IN_FLIGHT (20)
>   #define MAX_VENDOR_DESCRIPTOR_SIZE 256
>   
> +static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout);
> +
>   static int udl_parse_vendor_descriptor(struct udl_device *udl)
>   {
>   	struct usb_device *udev = udl_to_usb_device(udl);
> @@ -140,21 +142,23 @@ void udl_urb_completion(struct urb *urb)
>   	udl->urbs.available++;
>   	spin_unlock_irqrestore(&udl->urbs.lock, flags);
>   
> -	wake_up(&udl->urbs.sleep);
> +	wake_up_all(&udl->urbs.sleep);
>   }
>   
>   static void udl_free_urb_list(struct drm_device *dev)
>   {
>   	struct udl_device *udl = to_udl(dev);
> -	int count = udl->urbs.count;
>   	struct urb_node *unode;
>   	struct urb *urb;
>   
>   	DRM_DEBUG("Waiting for completes and freeing all render urbs\n");
>   
>   	/* keep waiting and freeing, until we've got 'em all */
> -	while (count--) {
> -		urb = udl_get_urb_timeout(dev, MAX_SCHEDULE_TIMEOUT);
> +	while (udl->urbs.count) {
> +		spin_lock_irq(&udl->urbs.lock);
> +		urb = udl_get_urb_locked(udl, MAX_SCHEDULE_TIMEOUT);
> +		udl->urbs.count--;
> +		spin_unlock_irq(&udl->urbs.lock);
>   		if (WARN_ON(!urb))
>   			break;
>   		unode = urb->context;
> @@ -164,7 +168,8 @@ static void udl_free_urb_list(struct drm_device *dev)
>   		usb_free_urb(urb);
>   		kfree(unode);
>   	}
> -	udl->urbs.count = 0;
> +
> +	wake_up(&udl->urbs.sleep);

I meant that we should maybe do a wake_up_all() here and not in the 
completion handler udl_urb_completion().

In any case

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>

>   }
>   
>   static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
> @@ -228,33 +233,44 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
>   	return udl->urbs.count;
>   }
>   
> -struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout)
> +static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout)
>   {
> -	struct udl_device *udl = to_udl(dev);
> -	struct urb_node *unode = NULL;
> +	struct urb_node *unode;
>   
> -	if (!udl->urbs.count)
> -		return NULL;
> +	assert_spin_locked(&udl->urbs.lock);
>   
>   	/* Wait for an in-flight buffer to complete and get re-queued */
> -	spin_lock_irq(&udl->urbs.lock);
>   	if (!wait_event_lock_irq_timeout(udl->urbs.sleep,
> +					 !udl->urbs.count ||
>   					 !list_empty(&udl->urbs.list),
>   					 udl->urbs.lock, timeout)) {
>   		DRM_INFO("wait for urb interrupted: available: %d\n",
>   			 udl->urbs.available);
> -		goto unlock;
> +		return NULL;
>   	}
>   
> +	if (!udl->urbs.count)
> +		return NULL;
> +
>   	unode = list_first_entry(&udl->urbs.list, struct urb_node, entry);
>   	list_del_init(&unode->entry);
>   	udl->urbs.available--;
>   
> -unlock:
> -	spin_unlock_irq(&udl->urbs.lock);
>   	return unode ? unode->urb : NULL;
>   }
>   
> +#define GET_URB_TIMEOUT	HZ
> +struct urb *udl_get_urb(struct drm_device *dev)
> +{
> +	struct udl_device *udl = to_udl(dev);
> +	struct urb *urb;
> +
> +	spin_lock_irq(&udl->urbs.lock);
> +	urb = udl_get_urb_locked(udl, GET_URB_TIMEOUT);
> +	spin_unlock_irq(&udl->urbs.lock);
> +	return urb;
> +}
> +
>   int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
>   {
>   	struct udl_device *udl = to_udl(dev);

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 11/11] drm/udl: Sync pending URBs at the end of suspend
  2022-09-06  7:39 ` [PATCH v2 11/11] drm/udl: Sync pending URBs at the end of suspend Takashi Iwai
@ 2022-09-07  7:34   ` Thomas Zimmermann
  0 siblings, 0 replies; 17+ messages in thread
From: Thomas Zimmermann @ 2022-09-07  7:34 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: linux-kernel, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 3722 bytes --]

Hi

Am 06.09.22 um 09:39 schrieb Takashi Iwai:
> It's better to perform the sync at the very last of the suspend
> instead of the pipe-disable function, so that we can catch all pending
> URBs (if any).
> 
> While we're at it, drop the error code from udl_sync_pending_urb()
> since we basically ignore it; instead, give a clear error message
> indicating a problem.
> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>

Acked-by: Thomas Zimmermann <tzimmermann@suse.de>

> ---
>   drivers/gpu/drm/udl/udl_drv.c     | 8 +++++++-
>   drivers/gpu/drm/udl/udl_drv.h     | 2 +-
>   drivers/gpu/drm/udl/udl_main.c    | 6 ++----
>   drivers/gpu/drm/udl/udl_modeset.c | 2 --
>   4 files changed, 10 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
> index 0ba88e5472a9..91effdcefb6d 100644
> --- a/drivers/gpu/drm/udl/udl_drv.c
> +++ b/drivers/gpu/drm/udl/udl_drv.c
> @@ -21,8 +21,14 @@ static int udl_usb_suspend(struct usb_interface *interface,
>   			   pm_message_t message)
>   {
>   	struct drm_device *dev = usb_get_intfdata(interface);
> +	int ret;
>   
> -	return drm_mode_config_helper_suspend(dev);
> +	ret = drm_mode_config_helper_suspend(dev);
> +	if (ret)
> +		return ret;
> +
> +	udl_sync_pending_urbs(dev);
> +	return 0;
>   }
>   
>   static int udl_usb_resume(struct usb_interface *interface)
> diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
> index d943684b5bbb..b4cc7cc568c7 100644
> --- a/drivers/gpu/drm/udl/udl_drv.h
> +++ b/drivers/gpu/drm/udl/udl_drv.h
> @@ -77,7 +77,7 @@ struct drm_connector *udl_connector_init(struct drm_device *dev);
>   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_sync_pending_urbs(struct drm_device *dev);
>   void udl_urb_completion(struct urb *urb);
>   
>   int udl_init(struct udl_device *udl);
> diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
> index 808a5ab5e14e..442080fa1061 100644
> --- a/drivers/gpu/drm/udl/udl_main.c
> +++ b/drivers/gpu/drm/udl/udl_main.c
> @@ -290,10 +290,9 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
>   }
>   
>   /* wait until all pending URBs have been processed */
> -int udl_sync_pending_urbs(struct drm_device *dev)
> +void 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 */
> @@ -301,9 +300,8 @@ int udl_sync_pending_urbs(struct drm_device *dev)
>   					 udl->urbs.available == udl->urbs.count,
>   					 udl->urbs.lock,
>   					 msecs_to_jiffies(2000)))
> -		ret = -ETIMEDOUT;
> +		drm_err(dev, "Timeout for syncing pending URBs\n");
>   	spin_unlock_irq(&udl->urbs.lock);
> -	return ret;
>   }
>   
>   int udl_init(struct udl_device *udl)
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index 9896c16c74f5..c506fff8f0c4 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -383,8 +383,6 @@ 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

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 07/11] drm/udl: Drop unneeded alignment
  2022-09-07  7:29   ` Thomas Zimmermann
@ 2022-09-08  7:01     ` Takashi Iwai
  0 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2022-09-08  7:01 UTC (permalink / raw)
  To: Thomas Zimmermann; +Cc: linux-kernel, dri-devel

On Wed, 07 Sep 2022 09:29:37 +0200,
Thomas Zimmermann wrote:
> 
> Hi
> 
> Am 06.09.22 um 09:39 schrieb Takashi Iwai:
> > The alignment of damaged area was needed for the original udlfb driver
> > that tried to trim the superfluous copies between front and backend
> > buffers and handle data in long int.  It's not the case for udl DRM
> > driver, hence we can omit the whole unneeded alignment, as well as the
> > dead code.
> > 
> > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> 
> Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
> 
> with an entirely optional comment below.
> 
> > ---
> >   drivers/gpu/drm/udl/udl_modeset.c  | 28 +--------------------
> >   drivers/gpu/drm/udl/udl_transfer.c | 40 ------------------------------
> >   2 files changed, 1 insertion(+), 67 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> > index c34d564773a3..9896c16c74f5 100644
> > --- a/drivers/gpu/drm/udl/udl_modeset.c
> > +++ b/drivers/gpu/drm/udl/udl_modeset.c
> > @@ -243,28 +243,6 @@ static long udl_log_cpp(unsigned int cpp)
> >   	return __ffs(cpp);
> >   }
> >   -static int udl_aligned_damage_clip(struct drm_rect *clip, int x,
> > int y,
> > -				   int width, int height)
> > -{
> > -	int x1, x2;
> > -
> > -	if (WARN_ON_ONCE(x < 0) ||
> > -	    WARN_ON_ONCE(y < 0) ||
> > -	    WARN_ON_ONCE(width < 0) ||
> > -	    WARN_ON_ONCE(height < 0))
> > -		return -EINVAL;
> > -
> > -	x1 = ALIGN_DOWN(x, sizeof(unsigned long));
> > -	x2 = ALIGN(width + (x - x1), sizeof(unsigned long)) + x1;
> > -
> > -	clip->x1 = x1;
> > -	clip->y1 = y;
> > -	clip->x2 = x2;
> > -	clip->y2 = y + height;
> > -
> > -	return 0;
> > -}
> > -
> >   static int udl_handle_damage(struct drm_framebuffer *fb,
> >   			     const struct iosys_map *map,
> >   			     int x, int y, int width, int height)
> > @@ -282,11 +260,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb,
> >   		return ret;
> >   	log_bpp = ret;
> >   -	ret = udl_aligned_damage_clip(&clip, x, y, width, height);
> > -	if (ret)
> > -		return ret;
> > -	else if ((clip.x2 > fb->width) || (clip.y2 > fb->height))
> > -		return -EINVAL;
> > +	drm_rect_init(&clip, x, y, width, height);
> 
> The clip rectangle could be passed directly by the caller, which would
> simplify the update function. But that's really just nitpicking.

OK, will add a patch to do this, too :)


thanks,

Takashi

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2022-09-08  7:02 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-06  7:39 [PATCH v2 00/11] drm/udl: More fixes Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 01/11] drm/udl: Restore display mode on resume Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 02/11] drm/udl: Add reset_resume Takashi Iwai
2022-09-07  6:58   ` Daniel Vetter
2022-09-06  7:39 ` [PATCH v2 03/11] drm/udl: Enable damage clipping Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 04/11] Revert "drm/udl: Kill pending URBs at suspend and disconnect" Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 05/11] drm/udl: Suppress error print for -EPROTO at URB completion Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 06/11] drm/udl: Increase the default URB list size to 20 Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 07/11] drm/udl: Drop unneeded alignment Takashi Iwai
2022-09-07  7:29   ` Thomas Zimmermann
2022-09-08  7:01     ` Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 08/11] drm/udl: Fix potential URB leaks Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 09/11] drm/udl: Fix inconsistent urbs.count value during udl_free_urb_list() Takashi Iwai
2022-09-07  7:31   ` Thomas Zimmermann
2022-09-06  7:39 ` [PATCH v2 10/11] drm/udl: Don't re-initialize stuff at retrying the URB list allocation Takashi Iwai
2022-09-06  7:39 ` [PATCH v2 11/11] drm/udl: Sync pending URBs at the end of suspend Takashi Iwai
2022-09-07  7:34   ` Thomas Zimmermann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).