From nobody Thu Sep 24 13:42:06 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63D24534444 for ; Wed, 23 Sep 2026 16:12:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790179983; cv=none; b=hfi877xRfQ0qV/Y4B/j3t65W5C3IKMG8MXH/Jk+zmCXAFo8W7HHJxDOZLBOoDNVazJRj/smtgoXZU3W4fn4IFb4riR97aI9AjBwGp4e4YqVjf+w1f7GvF/XVCByJMYyToKZBqugx8ZcGKVQVH/kxGyNBtKtk+ei1VrWSaqKp9yU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790179983; c=relaxed/simple; bh=kf1msQs5AJ3pdC/u2OPA1+KOX+hbHG6bACNwC5arPKo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JzyTrRpHl1uXgcS7Mwe1dkoWEN/2JhmwlsZKGGqmdBfPIssx3fRrVj9iwhHX0MRmkDthjH5RriTHhpPcgIHh6rxbhl9XDdBdz1Jz0AtzVpfx5M6VaV5x+zZmgTx6PTsnBa5VUYZgpnq9Ark2WHRzXRIHDixNVUT0yu5mJt7TqEI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=N+h/4g6Z; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="N+h/4g6Z" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject: Cc:To:From:From:Reply-To; bh=05CpQ6ZHUsiawKuttLrdc0kN5L7r+NIJwjGGxvBIGpw=; b= N+h/4g6Zp5srQnehOeIF5jJ1PuBgOIwJAt8lA6/7CXj+tX3kKyt1m8pSkKtRbBdupCGZGlogKjQdu TB9zZizjK+4IBg50ncAGgwDrl9oKP91rBz9ueoefvLoq5d7CJmJnNlOZE62JeUNBNfIJKyokIfDqP Xt8vai+lSIIUq8LkTh2vjs0quwQtiWe0sODGjv6RjD1CVmTf4OwDqiAmFQ1xF4XlH+699KQeB2LNs BREQ/IO4bEebxS4hwFVimEX7i58AgZnifYGbXh5x3XnZvYDNueqT5F3GJfaPn+Vmwwff9CuWFWBxT W53+b3TrTnLdH/g6b73PV7Es8PQ33m7OzA==; Received: from [81.79.79.1] (helo=localhost) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1x9PaZ-006ECN-KI; Wed, 23 Sep 2026 18:12:55 +0200 From: Tvrtko Ursulin To: linux-kernel@vger.kernel.org Cc: kernel-dev@igalia.com, dri-devel@lists.freedesktop.org, Tvrtko Ursulin , Boris Brezillon , Bradley Morgan , Chia-I Wu , Liviu Dudau , Matthew Brost , Steven Price , Tejun Heo Subject: [RFC v5 1/3] workqueue: Simplify unbound sysfs attribute registration Date: Wed, 23 Sep 2026 17:12:49 +0100 Message-ID: <20260923161251.45428-2-tvrtko.ursulin@igalia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260923161251.45428-1-tvrtko.ursulin@igalia.com> References: <20260923161251.45428-1-tvrtko.ursulin@igalia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Instead of manually registering each attribute we can put them in an attribute group with a visibility check and device core will handle the rest, which simplifies the registration and error unwind. Signed-off-by: Tvrtko Ursulin Cc: Boris Brezillon Cc: Bradley Morgan Cc: Chia-I Wu Cc: Liviu Dudau Cc: Matthew Brost Cc: Steven Price Cc: Tejun Heo --- kernel/workqueue.c | 98 ++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e618108c6127..e3a4ad56dae8 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -7599,8 +7599,8 @@ static const struct attribute_group wq_sysfs_group = =3D { }; __ATTRIBUTE_GROUPS(wq_sysfs); =20 -static ssize_t wq_nice_show(struct device *dev, struct device_attribute *a= ttr, - char *buf) +static ssize_t nice_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct workqueue_struct *wq =3D dev_to_wq(dev); int written; @@ -7627,8 +7627,8 @@ static struct workqueue_attrs *wq_sysfs_prep_attrs(st= ruct workqueue_struct *wq) return attrs; } =20 -static ssize_t wq_nice_store(struct device *dev, struct device_attribute *= attr, - const char *buf, size_t count) +static ssize_t nice_store(struct device *dev, struct device_attribute *att= r, + const char *buf, size_t count) { struct workqueue_struct *wq =3D dev_to_wq(dev); struct workqueue_attrs *attrs; @@ -7652,8 +7652,8 @@ static ssize_t wq_nice_store(struct device *dev, stru= ct device_attribute *attr, return ret ?: count; } =20 -static ssize_t wq_cpumask_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t unbound_cpumask_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct workqueue_struct *wq =3D dev_to_wq(dev); int written; @@ -7665,9 +7665,9 @@ static ssize_t wq_cpumask_show(struct device *dev, return written; } =20 -static ssize_t wq_cpumask_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t unbound_cpumask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct workqueue_struct *wq =3D dev_to_wq(dev); struct workqueue_attrs *attrs; @@ -7689,8 +7689,8 @@ static ssize_t wq_cpumask_store(struct device *dev, return ret ?: count; } =20 -static ssize_t wq_affn_scope_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t affn_scope_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct workqueue_struct *wq =3D dev_to_wq(dev); int written; @@ -7708,9 +7708,9 @@ static ssize_t wq_affn_scope_show(struct device *dev, return written; } =20 -static ssize_t wq_affn_scope_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t affn_scope_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct workqueue_struct *wq =3D dev_to_wq(dev); struct workqueue_attrs *attrs; @@ -7731,8 +7731,8 @@ static ssize_t wq_affn_scope_store(struct device *dev, return ret ?: count; } =20 -static ssize_t wq_affinity_strict_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t affinity_strict_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct workqueue_struct *wq =3D dev_to_wq(dev); =20 @@ -7740,9 +7740,9 @@ static ssize_t wq_affinity_strict_show(struct device = *dev, wq->attrs->affn_strict); } =20 -static ssize_t wq_affinity_strict_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t affinity_strict_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct workqueue_struct *wq =3D dev_to_wq(dev); struct workqueue_attrs *attrs; @@ -7762,14 +7762,40 @@ static ssize_t wq_affinity_strict_store(struct devi= ce *dev, return ret ?: count; } =20 -static struct device_attribute wq_sysfs_unbound_attrs[] =3D { - __ATTR(nice, 0644, wq_nice_show, wq_nice_store), - __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store), - __ATTR(affinity_scope, 0644, wq_affn_scope_show, wq_affn_scope_store), - __ATTR(affinity_strict, 0644, wq_affinity_strict_show, wq_affinity_strict= _store), - __ATTR_NULL, +static DEVICE_ATTR_RW(nice); +static DEVICE_ATTR_RW(affn_scope); +static DEVICE_ATTR_RW(affinity_strict); +/* Avoid naming clash with the other cpumask */ +static struct device_attribute dev_attr_unbound_cpumask =3D + __ATTR(cpumask, 0644, unbound_cpumask_show, unbound_cpumask_store); + +static struct attribute *wq_sysfs_unbound_attrs[] =3D { + &dev_attr_nice.attr, + &dev_attr_unbound_cpumask.attr, + &dev_attr_affn_scope.attr, + &dev_attr_affinity_strict.attr, + NULL, }; =20 +static umode_t wq_sysfs_unbound_group_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev =3D kobj_to_dev(kobj); + struct workqueue_struct *wq =3D dev_to_wq(dev); + + if (!(wq->flags & WQ_UNBOUND)) + return SYSFS_GROUP_INVISIBLE; + + return attr->mode; +} + +static const struct attribute_group wq_sysfs_unbound_group =3D { + .is_visible =3D wq_sysfs_unbound_group_visible, + .attrs =3D wq_sysfs_unbound_attrs, +}; + +__ATTRIBUTE_GROUPS(wq_sysfs_unbound); + static const struct bus_type wq_subsys =3D { .name =3D "workqueue", .dev_groups =3D wq_sysfs_groups, @@ -7907,14 +7933,9 @@ int workqueue_sysfs_register(struct workqueue_struct= *wq) wq_dev->wq =3D wq; wq_dev->dev.bus =3D &wq_subsys; wq_dev->dev.release =3D wq_device_release; + wq_dev->dev.groups =3D wq_sysfs_unbound_groups; dev_set_name(&wq_dev->dev, "%s", wq->name); =20 - /* - * attrs are created separately. Suppress uevent until - * everything is ready. - */ - dev_set_uevent_suppress(&wq_dev->dev, true); - ret =3D device_register(&wq_dev->dev); if (ret) { put_device(&wq_dev->dev); @@ -7922,21 +7943,6 @@ int workqueue_sysfs_register(struct workqueue_struct= *wq) return ret; } =20 - if (wq->flags & WQ_UNBOUND) { - struct device_attribute *attr; - - for (attr =3D wq_sysfs_unbound_attrs; attr->attr.name; attr++) { - ret =3D device_create_file(&wq_dev->dev, attr); - if (ret) { - device_unregister(&wq_dev->dev); - wq->wq_dev =3D NULL; - return ret; - } - } - } - - dev_set_uevent_suppress(&wq_dev->dev, false); - kobject_uevent(&wq_dev->dev.kobj, KOBJ_ADD); return 0; } =20 --=20 2.55.0 From nobody Thu Sep 24 13:42:06 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63F9C534445 for ; Wed, 23 Sep 2026 16:12:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790179984; cv=none; b=mD5nS+/3q2brZ1L+8eBCC1wLV3PPJ/cBvncrP9tFh4kkj+b8tVWE7xp22eMXuVEz/hPgtAFIFMfFAxyKN3ZksskGFRmfIIRLfWYT7boff/P7Jg1x2wKml68v55oPjBINT86JRjjasOy0TNE8sLMAnqt4m44kWxh9s+jA6V6Xpvc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790179984; c=relaxed/simple; bh=HMTDU7WfkUo4ovx9mmqsCEyNYrUbBc0RafTg4NR3MIs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ln0uCgGXGjWVKV7gnAFgToR65g1Hb/BWWDBJfiDwtek5RIKhAFJ0QJTvkBvVBYpk23owDHAUZor0E1Z7a7Z1piPApXlDHzsCCZclBeLwEESBjfHLD/kONwUd5G+6ZlO0MblcuOtMSZ0Qx0+pJuRGKBDDM9V+Bw1oGTTJ/e50GVE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=SxLYZBwx; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="SxLYZBwx" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject: Cc:To:From:From:Reply-To; bh=aIrQn9s9bafTu+uFiPgLvDvAAJdVYC1maxfhhoJR5Ys=; b= SxLYZBwxciDru7suCzvja0GSgnEoIdBKHG+8MDvpeEORrB7KYLkR5BqrIdrRZ6ZOy950GX/kdNB5U leEh2jLguvyZ6vjC7F1gIayUB1gS3LHt1b0fzv5b9yO57wX9DE021cA0mxscSvMZXatZ7o7FcOYGT K+Gk6qC681YPA9zdrR5WAZu8IXwuKMnQLZuSHUkvqlQHQSPobtVRJpmFI/N2MuqksP0s/FycMmjtx 98KNaIE5F5hGadNyzv3roXgCVG5qkBbvqnV4wkiZVzDSLXr7qVOLOj98TzocTIItv5mVZspTiUqD3 01AmFyQ0PJNnZ1GObsTG2S/RmYWSvFg9Dg==; Received: from [81.79.79.1] (helo=localhost) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1x9Paa-006ECS-CK; Wed, 23 Sep 2026 18:12:56 +0200 From: Tvrtko Ursulin To: linux-kernel@vger.kernel.org Cc: kernel-dev@igalia.com, dri-devel@lists.freedesktop.org, Tvrtko Ursulin , Boris Brezillon , Bradley Morgan , Chia-I Wu , Liviu Dudau , Matthew Brost , Steven Price , Tejun Heo Subject: [RFC v5 2/3] workqueue: Add support for real-time workers Date: Wed, 23 Sep 2026 17:12:50 +0100 Message-ID: <20260923161251.45428-3-tvrtko.ursulin@igalia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260923161251.45428-1-tvrtko.ursulin@igalia.com> References: <20260923161251.45428-1-tvrtko.ursulin@igalia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" For use cases such as the DRM scheduler submitting work to the GPU on behalf of low latency userspace applications, where latter have sufficient privileges to have had successfully obtained realtime Vulkan global priority, competing with random background CPU load can create large latency spikes which gets in the way of a smooth user experience. For these situations the existing WQ_HIGHPRI does not bring a noticeable improvement and a stronger hint is needed. Lets add WQ_RTPRI which creates workers with a SCHED_FIFO scheduling class to improve this. We use a minimum priority level since we only care about winning the contest against normal background CPU load. Signed-off-by: Tvrtko Ursulin Cc: Boris Brezillon Cc: Bradley Morgan Cc: Chia-I Wu Cc: Liviu Dudau Cc: Matthew Brost Cc: Steven Price Cc: Tejun Heo --- v2: * Limit WQ_RTPRI to unbound workqueues and make it have strict CPU affinitity. (Tejun) * Fixed commit message typos. (AI) * Fixed sysfs handling, max_active setting and user modified nice application. (AI) v3: * Fix worker->pool null pointer dereference race by moving the global decrement to detach_dying_workers(). * Rebase for upstream changes. v4: * Fixed onion unwind. * Moved affinity setting to default attributes. v5: * Dropped global and local limits. * Documented in workqueue.rst. * Added NR_WQ_ATTRIBUTES. * Reverted BH handling changes. v6: * Dropped separate attr->prio in favour of RTPRI_NICE_LEVEL checks. (Tejun) * Reworked on top of tj/for-7.4. --- Documentation/core-api/workqueue.rst | 5 +++++ include/linux/workqueue.h | 9 ++++---- kernel/workqueue.c | 33 +++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/= workqueue.rst index bb770f556568..24df3d87e2dd 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -225,6 +225,11 @@ resources, scheduled and executed. each other. Each maintains its separate pool of workers and implements concurrency management among its workers. =20 +``WQ_RTPRI`` + Real time priority workqueues must be created as unbound and have the st= rict + CPU affinity set. Their worker threads use the FIFO scheduling policy w= ith + the lowest priority. + ``WQ_CPU_INTENSIVE`` Work items of a CPU intensive wq do not contribute to the concurrency level. In other words, runnable CPU intensive diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index a283766a192a..161f71f4c264 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -374,8 +374,9 @@ enum wq_flags { WQ_FREEZABLE =3D 1 << 2, /* freeze during suspend */ WQ_MEM_RECLAIM =3D 1 << 3, /* may be used for memory reclaim */ WQ_HIGHPRI =3D 1 << 4, /* high priority */ - WQ_CPU_INTENSIVE =3D 1 << 5, /* cpu intensive workqueue */ - WQ_SYSFS =3D 1 << 6, /* visible in sysfs, see workqueue_sysfs_register()= */ + WQ_RTPRI =3D 1 << 5, /* real-time priority, valid only with WQ_UNBOUND */ + WQ_CPU_INTENSIVE =3D 1 << 6, /* cpu intensive workqueue */ + WQ_SYSFS =3D 1 << 7, /* visible in sysfs, see workqueue_sysfs_register()= */ =20 /* * Per-cpu workqueues are generally preferred because they tend to @@ -402,8 +403,8 @@ enum wq_flags { * * http://thread.gmane.org/gmane.linux.kernel/1480396 */ - WQ_POWER_EFFICIENT =3D 1 << 7, - WQ_PERCPU =3D 1 << 8, /* bound to a specific cpu */ + WQ_POWER_EFFICIENT =3D 1 << 8, + WQ_PERCPU =3D 1 << 9, /* bound to a specific cpu */ =20 __WQ_DESTROYING =3D 1 << 15, /* internal: workqueue is destroying */ __WQ_DRAINING =3D 1 << 16, /* internal: workqueue is draining */ diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e3a4ad56dae8..5cf486291af8 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -127,6 +127,7 @@ enum wq_internal_consts { */ RESCUER_NICE_LEVEL =3D MIN_NICE, HIGHPRI_NICE_LEVEL =3D MIN_NICE, + RTPRI_NICE_LEVEL =3D MIN_NICE - 1, =20 WQ_NAME_LEN =3D 32, WORKER_ID_LEN =3D 10 + WQ_NAME_LEN, /* "kworker/R-" + WQ_NAME_LEN */ @@ -3018,7 +3019,11 @@ static struct worker *create_worker(struct worker_po= ol *pool) goto fail; } =20 - set_user_nice(worker->task, pool->attrs->nice); + if (pool->attrs->nice =3D=3D RTPRI_NICE_LEVEL) + sched_set_fifo_low(worker->task); + else + set_user_nice(worker->task, pool->attrs->nice); + kthread_bind_mask(worker->task, pool_allowed_cpus(pool)); } =20 @@ -5928,8 +5933,17 @@ static struct workqueue_attrs *alloc_wq_std_attrs(st= ruct workqueue_struct *wq) if (!attrs) return NULL; =20 - if (wq->flags & WQ_HIGHPRI) + if (wq->flags & WQ_RTPRI) { + attrs->nice =3D RTPRI_NICE_LEVEL; + /* + * RT workqueues have strict CPU affinity for low + * latency execution. + */ + attrs->affn_scope =3D WQ_AFFN_CPU; + attrs->affn_strict =3D true; + } else if (wq->flags & WQ_HIGHPRI) { attrs->nice =3D HIGHPRI_NICE_LEVEL; + } =20 if (wq->flags & __WQ_ORDERED) attrs->ordered =3D true; @@ -6115,6 +6129,12 @@ static struct workqueue_struct *__alloc_workqueue(co= nst char *fmt, return NULL; } =20 + if (flags & WQ_RTPRI) { + if (WARN_ON_ONCE((flags & (WQ_HIGHPRI | WQ_UNBOUND)) !=3D + WQ_UNBOUND)) + return NULL; + } + /* see the comment above the definition of WQ_POWER_EFFICIENT */ if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient) flags =3D (flags & ~WQ_PERCPU) | WQ_UNBOUND; @@ -7606,7 +7626,10 @@ static ssize_t nice_show(struct device *dev, struct = device_attribute *attr, int written; =20 mutex_lock(&wq->mutex); - written =3D scnprintf(buf, PAGE_SIZE, "%d\n", wq->attrs->nice); + if (wq->attrs->nice =3D=3D RTPRI_NICE_LEVEL) + written =3D scnprintf(buf, PAGE_SIZE, "rt\n"); + else + written =3D scnprintf(buf, PAGE_SIZE, "%d\n", wq->attrs->nice); mutex_unlock(&wq->mutex); =20 return written; @@ -7786,6 +7809,10 @@ static umode_t wq_sysfs_unbound_group_visible(struct= kobject *kobj, if (!(wq->flags & WQ_UNBOUND)) return SYSFS_GROUP_INVISIBLE; =20 + /* Do not allow priority changes for RT workers. */ + if ((wq->flags & WQ_RTPRI) && !strcmp(attr->name, "nice")) + return 0444; + return attr->mode; } =20 --=20 2.55.0 From nobody Thu Sep 24 13:42:06 2026 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 322B038F630 for ; Wed, 23 Sep 2026 16:12:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790179983; cv=none; b=RmGoIYSYnCk9Rp52APOmY8cIxbNj66uLD/Fu+P39TjDXhygakFoJ1xTERdN+YS6tQ/eUVdF+0E0agv/KDKr6Ny6YIx5cLKilbNA2bbEW4ZD4X432lIvlLlJm6JTySBUNRtlPBvsIy1RkMcyo11HPt088WUnT81iLs9LmSAxUFY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790179983; c=relaxed/simple; bh=MIroo+oWA41krNykMcWeeH2okdAemzXl5AQpxiZX6u4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RZ846oTQB9CWh8Le7vY4Z+31wha3w24lEujqPU81kr92VaZgoFgSKpWTkxNU0QdeYnJOF8FxUYHqyCZZSL6EFR09ImMiO9wBYoDPc7r6QGDgwaz97HvnzHit8wTetcxUqzumKauClhK4Uir46EC7zweVK/AcdvNADrJiLiqHFqM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=a4IA+8r1; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="a4IA+8r1" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject: Cc:To:From:From:Reply-To; bh=ASsJvhG8AELMQ5KQkM/mNhuNT0ZTjSHv2ZrjZjXvQHU=; b= a4IA+8r1G3AZXW/0m9pNceRstLs+LvkVvDoIByxik6O5Moc5Awnfbr1o/wijDKPH4kiXz5M1A78zX caBcvcPeRxcsDThe8EQbcNe4VXSFTpXnhiUkJ7JuUbEXyn4f+Y32AHsCK1IjeaavT/bYGccJrW3gW zynYuqDLLoNS3/fWv8V239VtsyZU1SHwCLduGCZ/V/Eg2oMdbAPcgSzIqV1QUGiQYyBLMG2XvDy2Z opEj14lnBf9GpbsDz1nk4xdEjn71b2n2MCI75JILoB4ANJjj7LLKhMgwpOV0ALxcWluvJI5153CeA 3e1t6zAlL7Tif3lORdHaVv9bP1nyFCk+HQ==; Received: from [81.79.79.1] (helo=localhost) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1x9Pab-006ECW-48; Wed, 23 Sep 2026 18:12:56 +0200 From: Tvrtko Ursulin To: linux-kernel@vger.kernel.org Cc: kernel-dev@igalia.com, dri-devel@lists.freedesktop.org, Tvrtko Ursulin , Boris Brezillon , Chia-I Wu , Liviu Dudau , Matthew Brost , Steven Price , Tejun Heo Subject: [RFC v5 3/3] drm/panthor: Create per queue priority workqueues Date: Wed, 23 Sep 2026 17:12:51 +0100 Message-ID: <20260923161251.45428-4-tvrtko.ursulin@igalia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260923161251.45428-1-tvrtko.ursulin@igalia.com> References: <20260923161251.45428-1-tvrtko.ursulin@igalia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Split the single workqueue shared between the driver internal logic and DRM scheduler use into separate ones, where the DRM scheduler one is created per GPU priority level using the appropriate mapping to workqueue priorities. Low and medium GPU priority are served by a normal workqueue, high is server by a WQ_HIGHPRI instance, while realtime GPU priority is using the newly added WQ_RTPRI flag for lowest possible latency. These workqueues are device global and for all three we set the maximum concurrency to two in order to keep the GPU optimally fed with work. Signed-off-by: Tvrtko Ursulin Cc: Boris Brezillon Cc: Chia-I Wu Cc: Liviu Dudau Cc: Matthew Brost Cc: Steven Price Cc: Tejun Heo --- drivers/gpu/drm/panthor/panthor_sched.c | 37 ++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/pant= hor/panthor_sched.c index 5b34032deff8..de32ad68230c 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -152,11 +152,18 @@ struct panthor_scheduler { * * Used for the scheduler tick, group update or other kind of FW * event processing that can't be handled in the threaded interrupt - * path. Also passed to the drm_gpu_scheduler instances embedded - * in panthor_queue. + * path. */ struct workqueue_struct *wq; =20 + /** + * @submit_wq: Per priority workqueues for the DRM scheduler + * + * Passed to the drm_gpu_scheduler instances embedded + * in panthor_queue based on the queue priority. + */ + struct workqueue_struct *submit_wq[PANTHOR_CSG_PRIORITY_COUNT]; + /** * @heap_alloc_wq: Workqueue used to schedule tiler_oom works. * @@ -3582,8 +3589,14 @@ group_create_queue(struct panthor_group *group, goto err_free_queue; } =20 + if (group->priority >=3D ARRAY_SIZE(group->ptdev->scheduler->submit_wq) || + !group->ptdev->scheduler->submit_wq[group->priority]) { + ret =3D -EINVAL; + goto err_free_queue; + } + sched_args.name =3D queue->name; - + sched_args.submit_wq =3D group->ptdev->scheduler->submit_wq[group->priori= ty]; ret =3D drm_sched_init(&queue->scheduler, &sched_args); if (ret) goto err_free_queue; @@ -4073,6 +4086,15 @@ static void panthor_sched_fini(struct drm_device *dd= ev, void *res) if (!sched || !sched->csg_slot_count) return; =20 + if (sched->submit_wq[PANTHOR_CSG_PRIORITY_MEDIUM]) + destroy_workqueue(sched->submit_wq[PANTHOR_CSG_PRIORITY_MEDIUM]); + + if (sched->submit_wq[PANTHOR_CSG_PRIORITY_HIGH]) + destroy_workqueue(sched->submit_wq[PANTHOR_CSG_PRIORITY_HIGH]); + + if (sched->submit_wq[PANTHOR_CSG_PRIORITY_RT]) + destroy_workqueue(sched->submit_wq[PANTHOR_CSG_PRIORITY_RT]); + if (sched->wq) destroy_workqueue(sched->wq); =20 @@ -4174,7 +4196,14 @@ int panthor_sched_init(struct panthor_device *ptdev) */ sched->heap_alloc_wq =3D alloc_workqueue("panthor-heap-alloc", WQ_UNBOUND= , 0); sched->wq =3D alloc_workqueue("panthor-csf-sched", WQ_MEM_RECLAIM | WQ_UN= BOUND, 0); - if (!sched->wq || !sched->heap_alloc_wq) { + sched->submit_wq[PANTHOR_CSG_PRIORITY_MEDIUM] =3D alloc_workqueue("pantho= r-drm", WQ_MEM_RECLAIM | WQ_UNBOUND, 2); + sched->submit_wq[PANTHOR_CSG_PRIORITY_LOW] =3D sched->submit_wq[PANTHOR_C= SG_PRIORITY_MEDIUM]; + sched->submit_wq[PANTHOR_CSG_PRIORITY_HIGH] =3D alloc_workqueue("panthor-= drm-high", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 2); + sched->submit_wq[PANTHOR_CSG_PRIORITY_RT] =3D alloc_workqueue("panthor-dr= m-rt", WQ_RTPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 2); + if (!sched->wq || !sched->heap_alloc_wq || + !sched->submit_wq[PANTHOR_CSG_PRIORITY_MEDIUM] || + !sched->submit_wq[PANTHOR_CSG_PRIORITY_HIGH] || + !sched->submit_wq[PANTHOR_CSG_PRIORITY_RT]) { panthor_sched_fini(&ptdev->base, sched); drm_err(&ptdev->base, "Failed to allocate the workqueues"); return -ENOMEM; --=20 2.55.0