From: Greg Kroah-Hartman Date: Sat, 12 Jul 2025 14:45:33 +0000 (+0200) Subject: 6.15-stable patches X-Git-Tag: v5.15.188~44 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b1536bb207004b8cf9777e95b5edf6235aaf624e;p=thirdparty%2Fkernel%2Fstable-queue.git 6.15-stable patches added patches: drm-framebuffer-acquire-internal-references-on-gem-handles.patch drm-xe-allocate-pf-queue-size-on-pow2-boundary.patch revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch --- diff --git a/queue-6.15/drm-framebuffer-acquire-internal-references-on-gem-handles.patch b/queue-6.15/drm-framebuffer-acquire-internal-references-on-gem-handles.patch new file mode 100644 index 0000000000..a55a8d2ee9 --- /dev/null +++ b/queue-6.15/drm-framebuffer-acquire-internal-references-on-gem-handles.patch @@ -0,0 +1,303 @@ +From f6bfc9afc7510cb5e6fbe0a17c507917b0120280 Mon Sep 17 00:00:00 2001 +From: Thomas Zimmermann +Date: Mon, 7 Jul 2025 15:11:55 +0200 +Subject: drm/framebuffer: Acquire internal references on GEM handles +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Zimmermann + +commit f6bfc9afc7510cb5e6fbe0a17c507917b0120280 upstream. + +Acquire GEM handles in drm_framebuffer_init() and release them in +the corresponding drm_framebuffer_cleanup(). Ties the handle's +lifetime to the framebuffer. Not all GEM buffer objects have GEM +handles. If not set, no refcounting takes place. This is the case +for some fbdev emulation. This is not a problem as these GEM objects +do not use dma-bufs and drivers will not release them while fbdev +emulation is running. Framebuffer flags keep a bit per color plane +of which the framebuffer holds a GEM handle reference. + +As all drivers use drm_framebuffer_init(), they will now all hold +dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire +references on GEM handles for framebuffers"). + +In the GEM framebuffer helpers, restore the original ref counting +on buffer objects. As the helpers for handle refcounting are now +no longer called from outside the DRM core, unexport the symbols. + +v3: +- don't mix internal flags with mode flags (Christian) +v2: +- track framebuffer handle refs by flag +- drop gma500 cleanup (Christian) + +Signed-off-by: Thomas Zimmermann +Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers") +Reported-by: Bert Karwatzki +Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/ +Tested-by: Bert Karwatzki +Tested-by: Mario Limonciello +Tested-by: Borislav Petkov (AMD) +Cc: Thomas Zimmermann +Cc: Anusha Srivatsa +Cc: Christian König +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Sumit Semwal +Cc: "Christian König" +Cc: linux-media@vger.kernel.org +Cc: dri-devel@lists.freedesktop.org +Cc: linaro-mm-sig@lists.linaro.org +Cc: +Reviewed-by: Christian König +Link: https://lore.kernel.org/r/20250707131224.249496-1-tzimmermann@suse.de +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/drm_framebuffer.c | 31 ++++++++++++++++++++-- + drivers/gpu/drm/drm_gem.c | 38 +++++++++++++++++---------- + drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 ++++------- + drivers/gpu/drm/drm_internal.h | 2 - + include/drm/drm_framebuffer.h | 7 ++++ + 5 files changed, 68 insertions(+), 26 deletions(-) + +--- a/drivers/gpu/drm/drm_framebuffer.c ++++ b/drivers/gpu/drm/drm_framebuffer.c +@@ -862,11 +862,23 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebu + int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs) + { ++ unsigned int i; + int ret; ++ bool exists; + + if (WARN_ON_ONCE(fb->dev != dev || !fb->format)) + return -EINVAL; + ++ for (i = 0; i < fb->format->num_planes; i++) { ++ if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))) ++ fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); ++ if (fb->obj[i]) { ++ exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]); ++ if (exists) ++ fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); ++ } ++ } ++ + INIT_LIST_HEAD(&fb->filp_head); + + fb->funcs = funcs; +@@ -875,7 +887,7 @@ int drm_framebuffer_init(struct drm_devi + ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB, + false, drm_framebuffer_free); + if (ret) +- goto out; ++ goto err; + + mutex_lock(&dev->mode_config.fb_lock); + dev->mode_config.num_fb++; +@@ -883,7 +895,16 @@ int drm_framebuffer_init(struct drm_devi + mutex_unlock(&dev->mode_config.fb_lock); + + drm_mode_object_register(dev, &fb->base); +-out: ++ ++ return 0; ++ ++err: ++ for (i = 0; i < fb->format->num_planes; i++) { ++ if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) { ++ drm_gem_object_handle_put_unlocked(fb->obj[i]); ++ fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); ++ } ++ } + return ret; + } + EXPORT_SYMBOL(drm_framebuffer_init); +@@ -960,6 +981,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister + void drm_framebuffer_cleanup(struct drm_framebuffer *fb) + { + struct drm_device *dev = fb->dev; ++ unsigned int i; ++ ++ for (i = 0; i < fb->format->num_planes; i++) { ++ if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) ++ drm_gem_object_handle_put_unlocked(fb->obj[i]); ++ } + + mutex_lock(&dev->mode_config.fb_lock); + list_del(&fb->head); +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -223,23 +223,34 @@ static void drm_gem_object_handle_get(st + } + + /** +- * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles ++ * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any + * @obj: GEM object + * +- * Acquires a reference on the GEM buffer object's handle. Required +- * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked() +- * to release the reference. ++ * Acquires a reference on the GEM buffer object's handle. Required to keep ++ * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked() ++ * to release the reference. Does nothing if the buffer object has no handle. ++ * ++ * Returns: ++ * True if a handle exists, or false otherwise + */ +-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj) ++bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj) + { + struct drm_device *dev = obj->dev; + + guard(mutex)(&dev->object_name_lock); + +- drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */ ++ /* ++ * First ref taken during GEM object creation, if any. Some ++ * drivers set up internal framebuffers with GEM objects that ++ * do not have a GEM handle. Hence, this counter can be zero. ++ */ ++ if (!obj->handle_count) ++ return false; ++ + drm_gem_object_handle_get(obj); ++ ++ return true; + } +-EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked); + + /** + * drm_gem_object_handle_free - release resources bound to userspace handles +@@ -272,7 +283,7 @@ static void drm_gem_object_exported_dma_ + } + + /** +- * drm_gem_object_handle_put_unlocked - releases reference on user-space handles ++ * drm_gem_object_handle_put_unlocked - releases reference on user-space handle + * @obj: GEM object + * + * Releases a reference on the GEM buffer object's handle. Possibly releases +@@ -283,14 +294,14 @@ void drm_gem_object_handle_put_unlocked( + struct drm_device *dev = obj->dev; + bool final = false; + +- if (WARN_ON(READ_ONCE(obj->handle_count) == 0)) ++ if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0)) + return; + + /* +- * Must bump handle count first as this may be the last +- * ref, in which case the object would disappear before we +- * checked for a name +- */ ++ * Must bump handle count first as this may be the last ++ * ref, in which case the object would disappear before ++ * we checked for a name. ++ */ + + mutex_lock(&dev->object_name_lock); + if (--obj->handle_count == 0) { +@@ -303,7 +314,6 @@ void drm_gem_object_handle_put_unlocked( + if (final) + drm_gem_object_put(obj); + } +-EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked); + + /* + * Called at device or object close to release the file's +--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c ++++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c +@@ -99,7 +99,7 @@ void drm_gem_fb_destroy(struct drm_frame + unsigned int i; + + for (i = 0; i < fb->format->num_planes; i++) +- drm_gem_object_handle_put_unlocked(fb->obj[i]); ++ drm_gem_object_put(fb->obj[i]); + + drm_framebuffer_cleanup(fb); + kfree(fb); +@@ -182,10 +182,8 @@ int drm_gem_fb_init_with_funcs(struct dr + if (!objs[i]) { + drm_dbg_kms(dev, "Failed to lookup GEM object\n"); + ret = -ENOENT; +- goto err_gem_object_handle_put_unlocked; ++ goto err_gem_object_put; + } +- drm_gem_object_handle_get_unlocked(objs[i]); +- drm_gem_object_put(objs[i]); + + min_size = (height - 1) * mode_cmd->pitches[i] + + drm_format_info_min_pitch(info, i, width) +@@ -195,22 +193,22 @@ int drm_gem_fb_init_with_funcs(struct dr + drm_dbg_kms(dev, + "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n", + objs[i]->size, min_size, i); +- drm_gem_object_handle_put_unlocked(objs[i]); ++ drm_gem_object_put(objs[i]); + ret = -EINVAL; +- goto err_gem_object_handle_put_unlocked; ++ goto err_gem_object_put; + } + } + + ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs); + if (ret) +- goto err_gem_object_handle_put_unlocked; ++ goto err_gem_object_put; + + return 0; + +-err_gem_object_handle_put_unlocked: ++err_gem_object_put: + while (i > 0) { + --i; +- drm_gem_object_handle_put_unlocked(objs[i]); ++ drm_gem_object_put(objs[i]); + } + return ret; + } +--- a/drivers/gpu/drm/drm_internal.h ++++ b/drivers/gpu/drm/drm_internal.h +@@ -161,7 +161,7 @@ void drm_sysfs_lease_event(struct drm_de + + /* drm_gem.c */ + int drm_gem_init(struct drm_device *dev); +-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj); ++bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj); + void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj); + int drm_gem_handle_create_tail(struct drm_file *file_priv, + struct drm_gem_object *obj, +--- a/include/drm/drm_framebuffer.h ++++ b/include/drm/drm_framebuffer.h +@@ -23,6 +23,7 @@ + #ifndef __DRM_FRAMEBUFFER_H__ + #define __DRM_FRAMEBUFFER_H__ + ++#include + #include + #include + #include +@@ -100,6 +101,8 @@ struct drm_framebuffer_funcs { + unsigned num_clips); + }; + ++#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i) BIT(0u + (_i)) ++ + /** + * struct drm_framebuffer - frame buffer object + * +@@ -189,6 +192,10 @@ struct drm_framebuffer { + */ + int flags; + /** ++ * @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF. ++ */ ++ unsigned int internal_flags; ++ /** + * @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock. + */ + struct list_head filp_head; diff --git a/queue-6.15/drm-xe-allocate-pf-queue-size-on-pow2-boundary.patch b/queue-6.15/drm-xe-allocate-pf-queue-size-on-pow2-boundary.patch new file mode 100644 index 0000000000..0e376d5464 --- /dev/null +++ b/queue-6.15/drm-xe-allocate-pf-queue-size-on-pow2-boundary.patch @@ -0,0 +1,35 @@ +From c9a95dbe06102cf01afee4cd83ecb29f8d587a72 Mon Sep 17 00:00:00 2001 +From: Matthew Brost +Date: Wed, 2 Jul 2025 14:35:11 -0700 +Subject: drm/xe: Allocate PF queue size on pow2 boundary + +From: Matthew Brost + +commit c9a95dbe06102cf01afee4cd83ecb29f8d587a72 upstream. + +CIRC_SPACE does not work unless the size argument is a power of 2, +allocate PF queue size on power of 2 boundary. + +Cc: stable@vger.kernel.org +Fixes: 3338e4f90c14 ("drm/xe: Use topology to determine page fault queue size") +Fixes: 29582e0ea75c ("drm/xe: Add page queue multiplier") +Signed-off-by: Matthew Brost +Reviewed-by: Francois Dugast +Link: https://lore.kernel.org/r/20250702213511.3226167-1-matthew.brost@intel.com +(cherry picked from commit 491b9783126303755717c0cbde0b08ee59b6abab) +Signed-off-by: Lucas De Marchi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/xe/xe_gt_pagefault.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/xe/xe_gt_pagefault.c ++++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c +@@ -444,6 +444,7 @@ static int xe_alloc_pf_queue(struct xe_g + #define PF_MULTIPLIER 8 + pf_queue->num_dw = + (num_eus + XE_NUM_HW_ENGINES) * PF_MSG_LEN_DW * PF_MULTIPLIER; ++ pf_queue->num_dw = roundup_pow_of_two(pf_queue->num_dw); + #undef PF_MULTIPLIER + + pf_queue->gt = gt; diff --git a/queue-6.15/revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch b/queue-6.15/revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch new file mode 100644 index 0000000000..6797579e08 --- /dev/null +++ b/queue-6.15/revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch @@ -0,0 +1,57 @@ +From f6c7bc4a6823a0a959f40866a1efe99bd03c2c5b Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Tue, 17 Jun 2025 13:07:11 +0800 +Subject: Revert "usb: gadget: u_serial: Add null pointer check in gs_start_io" + +From: Kuen-Han Tsai + +commit f6c7bc4a6823a0a959f40866a1efe99bd03c2c5b upstream. + +This reverts commit ffd603f214237e250271162a5b325c6199a65382. + +Commit ffd603f21423 ("usb: gadget: u_serial: Add null pointer check in +gs_start_io") adds null pointer checks at the beginning of the +gs_start_io() function to prevent a null pointer dereference. However, +these checks are redundant because the function's comment already +requires callers to hold the port_lock and ensure port.tty and port_usb +are not null. All existing callers already follow these rules. + +The true cause of the null pointer dereference is a race condition. When +gs_start_io() calls either gs_start_rx() or gs_start_tx(), the port_lock +is temporarily released for usb_ep_queue(). This allows port.tty and +port_usb to be cleared. + +Fixes: ffd603f21423 ("usb: gadget: u_serial: Add null pointer check in gs_start_io") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Reviewed-by: Prashanth K +Link: https://lore.kernel.org/r/20250617050844.1848232-1-khtsai@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/u_serial.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +--- a/drivers/usb/gadget/function/u_serial.c ++++ b/drivers/usb/gadget/function/u_serial.c +@@ -544,20 +544,16 @@ static int gs_alloc_requests(struct usb_ + static int gs_start_io(struct gs_port *port) + { + struct list_head *head = &port->read_pool; +- struct usb_ep *ep; ++ struct usb_ep *ep = port->port_usb->out; + int status; + unsigned started; + +- if (!port->port_usb || !port->port.tty) +- return -EIO; +- + /* Allocate RX and TX I/O buffers. We can't easily do this much + * earlier (with GFP_KERNEL) because the requests are coupled to + * endpoints, as are the packet sizes we'll be using. Different + * configurations may use different endpoints with a given port; + * and high speed vs full speed changes packet sizes too. + */ +- ep = port->port_usb->out; + status = gs_alloc_requests(ep, head, gs_read_complete, + &port->read_allocated); + if (status) diff --git a/queue-6.15/series b/queue-6.15/series index a6d5cb6845..5cf58f6eed 100644 --- a/queue-6.15/series +++ b/queue-6.15/series @@ -89,3 +89,7 @@ drm-gem-fix-race-in-drm_gem_handle_create_tail.patch drm-xe-bmg-fix-compressed-vram-handling.patch revert-drm-xe-xe2-enable-indirect-ring-state-support-for-xe2.patch drm-nouveau-do-not-fail-module-init-on-debugfs-errors.patch +usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch +revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch +drm-framebuffer-acquire-internal-references-on-gem-handles.patch +drm-xe-allocate-pf-queue-size-on-pow2-boundary.patch diff --git a/queue-6.15/usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch b/queue-6.15/usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch new file mode 100644 index 0000000000..74d0f7a712 --- /dev/null +++ b/queue-6.15/usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch @@ -0,0 +1,59 @@ +From c529c3730bd09115684644e26bf01ecbd7e2c2c9 Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Tue, 17 Jun 2025 13:07:12 +0800 +Subject: usb: gadget: u_serial: Fix race condition in TTY wakeup + +From: Kuen-Han Tsai + +commit c529c3730bd09115684644e26bf01ecbd7e2c2c9 upstream. + +A race condition occurs when gs_start_io() calls either gs_start_rx() or +gs_start_tx(), as those functions briefly drop the port_lock for +usb_ep_queue(). This allows gs_close() and gserial_disconnect() to clear +port.tty and port_usb, respectively. + +Use the null-safe TTY Port helper function to wake up TTY. + +Example + CPU1: CPU2: + gserial_connect() // lock + gs_close() // await lock + gs_start_rx() // unlock + usb_ep_queue() + gs_close() // lock, reset port.tty and unlock + gs_start_rx() // lock + tty_wakeup() // NPE + +Fixes: 35f95fd7f234 ("TTY: usb/u_serial, use tty from tty_port") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Reviewed-by: Prashanth K +Link: https://lore.kernel.org/linux-usb/20240116141801.396398-1-khtsai@google.com/ +Link: https://lore.kernel.org/r/20250617050844.1848232-2-khtsai@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/u_serial.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/usb/gadget/function/u_serial.c ++++ b/drivers/usb/gadget/function/u_serial.c +@@ -295,8 +295,8 @@ __acquires(&port->port_lock) + break; + } + +- if (do_tty_wake && port->port.tty) +- tty_wakeup(port->port.tty); ++ if (do_tty_wake) ++ tty_port_tty_wakeup(&port->port); + return status; + } + +@@ -578,7 +578,7 @@ static int gs_start_io(struct gs_port *p + gs_start_tx(port); + /* Unblock any pending writes into our circular buffer, in case + * we didn't in gs_start_tx() */ +- tty_wakeup(port->port.tty); ++ tty_port_tty_wakeup(&port->port); + } else { + /* Free reqs only if we are still connected */ + if (port->port_usb) {