From 7b8346bd9fce6b76a96c6780d2e5bba76687f97f Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Tue, 29 Jul 2025 21:06:44 +0000 Subject: [PATCH 0001/1292] KVM: arm64: Don't attempt vLPI mappings when vPE allocation is disabled commit c652887a9288 ("KVM: arm64: vgic-v3: Allow userspace to write GICD_TYPER2.nASSGIcap") makes the allocation of vPEs depend on nASSGIcap for GICv4.1 hosts. While the vGIC v4 initialization and teardown is handled correctly, it erroneously attempts to establish a vLPI mapping to a VM that has no vPEs allocated: Unable to handle kernel NULL pointer dereference at virtual address 00000000000000a8 Mem abort info: ESR = 0x0000000096000044 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x04: level 0 translation fault Data abort info: ISV = 0, ISS = 0x00000044, ISS2 = 0x00000000 CM = 0, WnR = 1, TnD = 0, TagAccess = 0 GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 user pgtable: 4k pages, 48-bit VAs, pgdp=00000073a453b000 [00000000000000a8] pgd=0000000000000000, p4d=0000000000000000 Internal error: Oops: 0000000096000044 [#1] SMP pstate: 23400009 (nzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) pc : its_irq_set_vcpu_affinity+0x58c/0x95c lr : its_irq_set_vcpu_affinity+0x1e0/0x95c sp : ffff8001029bb9e0 pmr_save: 00000060 x29: ffff8001029bba20 x28: ffff0001ca5e28c0 x27: 0000000000000000 x26: 0000000000000000 x25: ffff00019eee9f80 x24: ffff0001992b3f00 x23: ffff8001029bbab8 x22: ffff00001159fb80 x21: 00000000000024a7 x20: 00000000000024a7 x19: ffff00019eee9fb4 x18: 0000000000000494 x17: 000000000000000e x16: 0000000000000494 x15: 0000000000000002 x14: ffff0001a7f34600 x13: ffffccaad1203000 x12: 0000000000000018 x11: ffff000011991000 x10: 0000000000000000 x9 : 00000000000000a2 x8 : 00000000000020a8 x7 : 0000000000000000 x6 : 000000000000003f x5 : 0000000000000040 x4 : 0000000000000000 x3 : 0000000000000004 x2 : 0000000000000000 x1 : ffff8001029bbab8 x0 : 00000000000000a8 Call trace: its_irq_set_vcpu_affinity+0x58c/0x95c irq_set_vcpu_affinity+0x74/0xc8 its_map_vlpi+0x4c/0x94 kvm_vgic_v4_set_forwarding+0x134/0x298 kvm_arch_irq_bypass_add_producer+0x28/0x34 irq_bypass_register_producer+0xf8/0x1d8 vfio_msi_set_vector_signal+0x2c8/0x308 vfio_pci_set_msi_trigger+0x198/0x2d4 vfio_pci_set_irqs_ioctl+0xf0/0x104 vfio_pci_core_ioctl+0x6ac/0xc5c vfio_device_fops_unl_ioctl+0x128/0x370 __arm64_sys_ioctl+0x98/0xd0 el0_svc_common+0xd8/0x1d8 do_el0_svc+0x28/0x34 el0_svc+0x40/0xb8 el0t_64_sync_handler+0x70/0xbc el0t_64_sync+0x1a8/0x1ac Code: 321f0129 f940094a 8b080148 d1400900 (39000009) ---[ end trace 0000000000000000 ]--- Fix it by moving the GICv4.1 special-casing to vgic_supports_direct_msis(), returning false if the user explicitly disabled nASSGIcap for the VM. Fixes: c652887a9288 ("KVM: arm64: vgic-v3: Allow userspace to write GICD_TYPER2.nASSGIcap") Suggested-by: Oliver Upton Signed-off-by: Raghavendra Rao Ananta Link: https://lore.kernel.org/r/20250729210644.830364-1-rananta@google.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 8 ++++++++ arch/arm64/kvm/vgic/vgic.h | 10 +--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index a3ef185209e99c..70d50c77e5dc7e 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -50,6 +50,14 @@ bool vgic_has_its(struct kvm *kvm) bool vgic_supports_direct_msis(struct kvm *kvm) { + /* + * Deliberately conflate vLPI and vSGI support on GICv4.1 hardware, + * indirectly allowing userspace to control whether or not vPEs are + * allocated for the VM. + */ + if (system_supports_direct_sgis() && !vgic_supports_direct_sgis(kvm)) + return false; + return kvm_vgic_global_state.has_gicv4 && vgic_has_its(kvm); } diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index 1384a04c078481..de1c1d3261c396 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -396,15 +396,7 @@ bool vgic_supports_direct_sgis(struct kvm *kvm); static inline bool vgic_supports_direct_irqs(struct kvm *kvm) { - /* - * Deliberately conflate vLPI and vSGI support on GICv4.1 hardware, - * indirectly allowing userspace to control whether or not vPEs are - * allocated for the VM. - */ - if (system_supports_direct_sgis()) - return vgic_supports_direct_sgis(kvm); - - return vgic_supports_direct_msis(kvm); + return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm); } int vgic_v4_init(struct kvm *kvm); From 79aef1a3705bbc95b36dad892af1f313490bd65c Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Wed, 30 Jul 2025 08:31:13 +0700 Subject: [PATCH 0002/1292] of: Clarify OF device context in of_match_device() comment Open Firmware abbreviation (OF) in of_match_device() comment is written in lowercase instead, which is mistaken for prepositional word "of" ([1], [2], [3], [4]) duplicate. Clarify the context. Link: https://lore.kernel.org/all/CAL_JsqLypcBCOVZ8yYWK0J_xc2Vcr+ANrX_3v4vN55Srp4RknQ@mail.gmail.com/ [1] Link: https://lore.kernel.org/all/20220926185852.GA2581083-robh@kernel.org/ [2] Link: https://lore.kernel.org/all/CAL_JsqL4GvgFYzGUfhW5pvm4wYGrFaj6gHOYZjnOMuk2zCz67w@mail.gmail.com/ [3] Link: https://lore.kernel.org/all/20220627173825.GA2637590-robh@kernel.org/ [4] Signed-off-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20250730013113.11264-1-bagasdotme@gmail.com Signed-off-by: Rob Herring (Arm) --- drivers/of/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index c80426510ec2c0..f7e75e5276677e 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -17,8 +17,8 @@ /** * of_match_device - Tell if a struct device matches an of_device_id list - * @matches: array of of device match structures to search in - * @dev: the of device structure to match against + * @matches: array of of_device_id match structures to search in + * @dev: the OF device structure to match against * * Used by a driver to check whether an platform_device present in the * system is in its list of supported devices. From bb324f85f722848f5e5e53325bc00f13302e01d0 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Wed, 9 Jul 2025 09:45:01 +0700 Subject: [PATCH 0003/1292] drm/gpuvm: Wrap drm_gpuvm_sm_map_exec_lock() expected usage in literal code block Stephen Rothwell reports multiple indentation warnings when merging drm-msm tree: Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2445: ERROR: Unexpected indentation. [docutils] Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2447: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils] Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2451: WARNING: Definition list ends without a blank line; unexpected unindent. [docutils] Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2452: WARNING: Definition list ends without a blank line; unexpected unindent. [docutils] Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2456: ERROR: Unexpected indentation. [docutils] Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2457: WARNING: Definition list ends without a blank line; unexpected unindent. [docutils] Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2458: WARNING: Definition list ends without a blank line; unexpected unindent. [docutils] Documentation/gpu/drm-mm:506: ./drivers/gpu/drm/drm_gpuvm.c:2459: WARNING: Definition list ends without a blank line; unexpected unindent. [docutils] Fix these by wrapping drm_gpuvm_sm_map_exec_lock() expected usage example in literal code block. Fixes: 471920ce25d5 ("drm/gpuvm: Add locking helpers") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/linux-next/20250708192038.6b0fd31d@canb.auug.org.au/ Signed-off-by: Bagas Sanjaya Acked-by: Randy Dunlap Tested-by: Randy Dunlap Acked-by: Danilo Krummrich Patchwork: https://patchwork.freedesktop.org/patch/663121/ Signed-off-by: Rob Clark --- drivers/gpu/drm/drm_gpuvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index bbc7fecb6f4ab4..f62005ff9b2eef 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -2430,7 +2430,7 @@ static const struct drm_gpuvm_ops lock_ops = { * remapped, and locks+prepares (drm_exec_prepare_object()) objects that * will be newly mapped. * - * The expected usage is: + * The expected usage is:: * * vm_bind { * struct drm_exec exec; From 7abb543ff03e7874eba50a27ab025f09c96f6f7a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 9 Jul 2025 07:08:38 -0700 Subject: [PATCH 0004/1292] drm/msm: Fix build with KMS disabled When commit 98290b0a7d60 ("drm/msm: make it possible to disable KMS-related code.") was rebased on top of commit 3bebfd53af0f ("drm/msm: Defer VMA unmap for fb unpins"), the additional use of msm_kms was overlooked, resulting in a build break when KMS is disabled. Add some additional ifdef to fix that. Reported-by: Arnd Bergmann Fixes: 98290b0a7d60 ("drm/msm: make it possible to disable KMS-related code.") Signed-off-by: Rob Clark Tested-by: Arnd Bergmann Reviewed-by: Jessica Zhang Patchwork: https://patchwork.freedesktop.org/patch/663240/ --- drivers/gpu/drm/msm/msm_gem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 33d3354c61020b..c853ab3a2cda54 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -96,7 +96,6 @@ void msm_gem_vma_get(struct drm_gem_object *obj) void msm_gem_vma_put(struct drm_gem_object *obj) { struct msm_drm_private *priv = obj->dev->dev_private; - struct drm_exec exec; if (atomic_dec_return(&to_msm_bo(obj)->vma_ref)) return; @@ -104,9 +103,13 @@ void msm_gem_vma_put(struct drm_gem_object *obj) if (!priv->kms) return; +#ifdef CONFIG_DRM_MSM_KMS + struct drm_exec exec; + msm_gem_lock_vm_and_obj(&exec, obj, priv->kms->vm); put_iova_spaces(obj, priv->kms->vm, true, "vma_put"); drm_exec_fini(&exec); /* drop locks */ +#endif } /* @@ -664,9 +667,13 @@ int msm_gem_set_iova(struct drm_gem_object *obj, static bool is_kms_vm(struct drm_gpuvm *vm) { +#ifdef CONFIG_DRM_MSM_KMS struct msm_drm_private *priv = vm->drm->dev_private; return priv->kms && (priv->kms->vm == vm); +#else + return false; +#endif } /* From f4ca529de235791aeeddc32ee6741a6b6872f564 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 17 Jul 2025 08:19:30 -0700 Subject: [PATCH 0005/1292] drm/msm: Fix pagetables setup/teardown serialization An atomic counter is not sufficient, as one task could still be in the process of tearing things down while another task increments the counter back up to one and begins setup again. The race condition existed since commit b145c6e65eb0 ("drm/msm: Add support to create a local pagetable") but got bigger in commit dbbde63c9e9d ("drm/msm: Add PRR support"). Fixes: dbbde63c9e9d ("drm/msm: Add PRR support") Fixes: b145c6e65eb0 ("drm/msm: Add support to create a local pagetable") Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/664433/ --- drivers/gpu/drm/msm/msm_iommu.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 55c29f49b78898..76cdd5ea06a02e 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -14,7 +14,9 @@ struct msm_iommu { struct msm_mmu base; struct iommu_domain *domain; - atomic_t pagetables; + + struct mutex init_lock; /* protects pagetables counter and prr_page */ + int pagetables; struct page *prr_page; struct kmem_cache *pt_cache; @@ -227,7 +229,8 @@ static void msm_iommu_pagetable_destroy(struct msm_mmu *mmu) * If this is the last attached pagetable for the parent, * disable TTBR0 in the arm-smmu driver */ - if (atomic_dec_return(&iommu->pagetables) == 0) { + mutex_lock(&iommu->init_lock); + if (--iommu->pagetables == 0) { adreno_smmu->set_ttbr0_cfg(adreno_smmu->cookie, NULL); if (adreno_smmu->set_prr_bit) { @@ -236,6 +239,7 @@ static void msm_iommu_pagetable_destroy(struct msm_mmu *mmu) iommu->prr_page = NULL; } } + mutex_unlock(&iommu->init_lock); free_io_pgtable_ops(pagetable->pgtbl_ops); kfree(pagetable); @@ -568,9 +572,12 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent, bool kernel_m * If this is the first pagetable that we've allocated, send it back to * the arm-smmu driver as a trigger to set up TTBR0 */ - if (atomic_inc_return(&iommu->pagetables) == 1) { + mutex_lock(&iommu->init_lock); + if (iommu->pagetables++ == 0) { ret = adreno_smmu->set_ttbr0_cfg(adreno_smmu->cookie, &ttbr0_cfg); if (ret) { + iommu->pagetables--; + mutex_unlock(&iommu->init_lock); free_io_pgtable_ops(pagetable->pgtbl_ops); kfree(pagetable); return ERR_PTR(ret); @@ -595,6 +602,7 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent, bool kernel_m adreno_smmu->set_prr_bit(adreno_smmu->cookie, true); } } + mutex_unlock(&iommu->init_lock); /* Needed later for TLB flush */ pagetable->parent = parent; @@ -730,7 +738,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks) iommu->domain = domain; msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU); - atomic_set(&iommu->pagetables, 0); + mutex_init(&iommu->init_lock); ret = iommu_attach_device(iommu->domain, dev); if (ret) { From 25654a1756a4ace072404e89882d7ba8391900bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Sun, 20 Jul 2025 18:42:31 -0300 Subject: [PATCH 0006/1292] drm/msm: Update global fault counter when faulty process has already ended MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The global fault counter is no longer used since commit 12578c075f89 ("drm/msm/gpu: Skip retired submits in recover worker"). However, it's still needed, as we need to handle cases where a GPU fault occurs after the faulting process has already ended. Hence, increment the global fault counter when the submitting process had already ended. This way, the number of faults returned by MSM_PARAM_FAULTS will stay consistent. While here, s/unusuable/unusable. Fixes: 12578c075f89 ("drm/msm/gpu: Skip retired submits in recover worker") Signed-off-by: MaĆ­ra Canal Patchwork: https://patchwork.freedesktop.org/patch/664853/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gpu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index c317b25a8162ed..416d47185ef09e 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -465,6 +465,7 @@ static void recover_worker(struct kthread_work *work) struct msm_gem_submit *submit; struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); char *comm = NULL, *cmd = NULL; + struct task_struct *task; int i; mutex_lock(&gpu->lock); @@ -482,16 +483,20 @@ static void recover_worker(struct kthread_work *work) /* Increment the fault counts */ submit->queue->faults++; - if (submit->vm) { + + task = get_pid_task(submit->pid, PIDTYPE_PID); + if (!task) + gpu->global_faults++; + else { struct msm_gem_vm *vm = to_msm_vm(submit->vm); vm->faults++; /* * If userspace has opted-in to VM_BIND (and therefore userspace - * management of the VM), faults mark the VM as unusuable. This + * management of the VM), faults mark the VM as unusable. This * matches vulkan expectations (vulkan is the main target for - * VM_BIND) + * VM_BIND). */ if (!vm->managed) msm_gem_vm_unusable(submit->vm); From de651b6e040ba419418a37401e45d24f133e8a59 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 23 Jul 2025 12:08:49 -0700 Subject: [PATCH 0007/1292] drm/msm: Fix refcnt underflow in error path If we hit an error path in GEM obj creation before msm_gem_new_handle() updates obj->resv to point to the gpuvm resv object, then obj->resv still points to &obj->_resv. In this case we don't want to decrement the refcount of the object being freed (since the refcnt is already zero). This fixes the following splat: ------------[ cut here ]------------ refcount_t: underflow; use-after-free. WARNING: CPU: 9 PID: 7013 at lib/refcount.c:28 refcount_warn_saturate+0xf4/0x148 Modules linked in: uinput snd_seq_dummy snd_hrtimer aes_ce_ccm snd_soc_wsa884x regmap_sdw q6prm_clocks q6apm_lpass_da> qcom_pil_info i2c_hid drm_kms_helper qcom_common qcom_q6v5 phy_snps_eusb2 qcom_geni_serial drm qcom_sysmon pinctrl_s> CPU: 9 UID: 1000 PID: 7013 Comm: deqp-vk Not tainted 6.16.0-rc4-debug+ #25 PREEMPT(voluntary) Hardware name: LENOVO 83ED/LNVNB161216, BIOS NHCN53WW 08/02/2024 pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) pc : refcount_warn_saturate+0xf4/0x148 lr : refcount_warn_saturate+0xf4/0x148 sp : ffff8000a2073920 x29: ffff8000a2073920 x28: 0000000000000010 x27: 0000000000000010 x26: 0000000000000042 x25: ffff000810e09800 x24: 0000000000000010 x23: ffff8000a2073b94 x22: ffff000ddb22de00 x21: ffff000ddb22dc00 x20: ffff000ddb22ddf8 x19: ffff0008024934e0 x18: 000000000000000a x17: 0000000000000000 x16: ffff9f8c67d77340 x15: 0000000000000000 x14: 00000000ffffffff x13: 2e656572662d7265 x12: 7466612d65737520 x11: 3b776f6c66726564 x10: 00000000ffff7fff x9 : ffff9f8c67506c70 x8 : ffff9f8c69fa26f0 x7 : 00000000000bffe8 x6 : c0000000ffff7fff x5 : ffff000f53e14548 x4 : ffff6082ea2b2000 x3 : ffff0008b86ab080 x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0008b86ab080 Call trace: refcount_warn_saturate+0xf4/0x148 (P) msm_gem_free_object+0x248/0x260 [msm] drm_gem_object_free+0x24/0x40 [drm] msm_gem_new+0x1c4/0x1e0 [msm] msm_gem_new_handle+0x3c/0x1a0 [msm] msm_ioctl_gem_new+0x38/0x70 [msm] drm_ioctl_kernel+0xc8/0x138 [drm] drm_ioctl+0x2c8/0x618 [drm] __arm64_sys_ioctl+0xac/0x108 invoke_syscall.constprop.0+0x64/0xe8 el0_svc_common.constprop.0+0x40/0xe8 do_el0_svc+0x24/0x38 el0_svc+0x54/0x1d8 el0t_64_sync_handler+0x10c/0x138 el0t_64_sync+0x19c/0x1a0 irq event stamp: 3698694 hardirqs last enabled at (3698693): [] __up_console_sem+0x74/0x90 hardirqs last disabled at (3698694): [] el1_dbg+0x24/0x90 softirqs last enabled at (3697578): [] handle_softirqs+0x454/0x4b0 softirqs last disabled at (3697567): [] __do_softirq+0x1c/0x28 ---[ end trace 0000000000000000 ]--- Fixes: b58e12a66e47 ("drm/msm: Add _NO_SHARE flag") Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/665355/ --- drivers/gpu/drm/msm/msm_gem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index c853ab3a2cda54..9f0f5b77f1bd4f 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1121,10 +1121,12 @@ static void msm_gem_free_object(struct drm_gem_object *obj) put_pages(obj); } - if (msm_obj->flags & MSM_BO_NO_SHARE) { + if (obj->resv != &obj->_resv) { struct drm_gem_object *r_obj = container_of(obj->resv, struct drm_gem_object, _resv); + WARN_ON(!(msm_obj->flags & MSM_BO_NO_SHARE)); + /* Drop reference we hold to shared resv obj: */ drm_gem_object_put(r_obj); } From ad70e46e130a7f4024961a5dd5ae0ee8e7d9a3c4 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 23 Jul 2025 12:08:50 -0700 Subject: [PATCH 0008/1292] drm/msm: Fix submit error path cleanup submit_unpin_objects() should come before we unlock the objects. This fixes the splat: WARNING: CPU: 2 PID: 2171 at drivers/gpu/drm/msm/msm_gem.h:395 msm_gem_unpin_locked+0x8c/0xd8 [msm] Modules linked in: uinput snd_seq_dummy snd_hrtimer aes_ce_ccm snd_soc_wsa884x regmap_sdw q6prm_clocks q6apm_lpass_dais q6apm_dai snd_q6dsp_common q6prm snd_q6apm qcom_pd_mapper cdc_mbim cdc_wdm cdc_ncm r8153_ecm cdc_ether usbnet sunrpc nls_ascii nls_cp437 vfat fat snd_soc_x1e80100 snd_soc_lpass_rx_macro snd_soc_lpass_tx_macro snd_soc_lpass_va_macro snd_soc_lpass_wsa_macro snd_soc_qcom_common soundwire_qcom snd_soc_lpass_macro_common snd_soc_hdmi_codec snd_soc_qcom_sdw ext4 snd_soc_core snd_compress soundwire_bus snd_pcm_dmaengine snd_seq mbcache jbd2 snd_seq_device snd_pcm pm8941_pwrkey snd_timer r8152 qcom_spmi_temp_alarm industrialio snd lenovo_yoga_slim7x ath12k mii arm_smccc_trng soundcore rng_core evdev loop panel_samsung_atna33xc20 msm ubwc_config drm_client_lib drm_gpuvm drm_exec gpu_sched drm_display_helper pmic_glink_altmode aux_hpd_bridge ucsi_glink qcom_battmgr phy_qcom_qmp_combo ps883x cec aux_bridge drm_dp_aux_bus i2c_hid_of aes_ce_blk drm_kms_helper aes_ce_cipher i2c_hid qcom_q6v5_pas ghash_ce qcom_pil_info drm sha1_ce qcom_common phy_snps_eusb2 qcom_geni_serial qcom_q6v5 qcom_sysmon pinctrl_sm8550_lpass_lpi lpasscc_sc8280xp sbsa_gwdt mdt_loader gpio_keys pmic_glink i2c_dev efivarfs autofs4 CPU: 2 UID: 1000 PID: 2171 Comm: gnome-shell Not tainted 6.16.0-rc4-debug+ #25 PREEMPT(voluntary) Hardware name: LENOVO 83ED/LNVNB161216, BIOS NHCN53WW 08/02/2024 pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) pc : msm_gem_unpin_locked+0x8c/0xd8 [msm] lr : msm_gem_unpin_locked+0x88/0xd8 [msm] sp : ffff80009c963820 x29: ffff80009c963820 x28: ffff80009c9639f8 x27: ffff00080552a830 x26: 0000000000000000 x25: ffff0009d5655800 x24: 0000000000000000 x23: 0000000000000000 x22: 0000000000000000 x21: 0000000000000000 x20: ffff000831db5480 x19: ffff000816e74400 x18: 0000000000000000 x17: 0000000000000000 x16: ffffc1396afdd720 x15: 0000000000000000 x14: 0000000000000000 x13: 0000000000000000 x12: ffff0008c065bc00 x11: ffff0008c065c000 x10: 0000000000000000 x9 : ffffc13945b19074 x8 : 0000000000000000 x7 : 0000000000000209 x6 : 0000000000000002 x5 : 0000000000019d01 x4 : ffff0008ba8db080 x3 : 000000000004093f x2 : ffff3ed5e727f000 x1 : 0000000000000000 x0 : 0000000000000000 Call trace: msm_gem_unpin_locked+0x8c/0xd8 [msm] (P) msm_ioctl_gem_submit+0x32c/0x1760 [msm] drm_ioctl_kernel+0xc8/0x138 [drm] drm_ioctl+0x2c8/0x618 [drm] __arm64_sys_ioctl+0xac/0x108 invoke_syscall.constprop.0+0x64/0xe8 el0_svc_common.constprop.0+0x40/0xe8 do_el0_svc+0x24/0x38 el0_svc+0x54/0x1d8 el0t_64_sync_handler+0x10c/0x138 el0t_64_sync+0x19c/0x1a0 irq event stamp: 2185036 hardirqs last enabled at (2185035): [] _raw_spin_unlock_irqrestore+0x74/0x80 hardirqs last disabled at (2185036): [] el1_dbg+0x24/0x90 softirqs last enabled at (2184778): [] fpsimd_restore_current_state+0x3c/0x328 softirqs last disabled at (2184776): [] fpsimd_restore_current_state+0xc/0x328 ---[ end trace 0000000000000000 ]--- Fixes: 111fdd2198e6 ("drm/msm: drm_gpuvm conversion") Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/665357/ --- drivers/gpu/drm/msm/msm_gem_submit.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 5f8e939a5906ef..0ac4c199ec93c2 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -514,14 +514,15 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob */ static void submit_cleanup(struct msm_gem_submit *submit, bool error) { + if (error) + submit_unpin_objects(submit); + if (submit->exec.objects) drm_exec_fini(&submit->exec); - if (error) { - submit_unpin_objects(submit); - /* job wasn't enqueued to scheduler, so early retirement: */ + /* if job wasn't enqueued to scheduler, early retirement: */ + if (error) msm_submit_retire(submit); - } } void msm_submit_retire(struct msm_gem_submit *submit) From f22853435bbd1e9836d0dce7fd99c040b94c2bf1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 23 Jul 2025 13:28:22 -0700 Subject: [PATCH 0009/1292] drm/msm: Defer fd_install in SUBMIT ioctl Avoid fd_install() until there are no more potential error paths, to avoid put_unused_fd() after the fd is made visible to userspace. Fixes: 68dc6c2d5eec ("drm/msm: Fix submit error-path leaks") Reported-by: Dan Carpenter Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/665363/ --- drivers/gpu/drm/msm/msm_gem_submit.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 0ac4c199ec93c2..bfea19baf6d9a4 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -770,12 +770,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret == 0 && args->flags & MSM_SUBMIT_FENCE_FD_OUT) { sync_file = sync_file_create(submit->user_fence); - if (!sync_file) { + if (!sync_file) ret = -ENOMEM; - } else { - fd_install(out_fence_fd, sync_file->file); - args->fence_fd = out_fence_fd; - } } if (ret) @@ -813,10 +809,14 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out_unlock: mutex_unlock(&queue->lock); out_post_unlock: - if (ret && (out_fence_fd >= 0)) { - put_unused_fd(out_fence_fd); + if (ret) { + if (out_fence_fd >= 0) + put_unused_fd(out_fence_fd); if (sync_file) fput(sync_file->file); + } else if (sync_file) { + fd_install(out_fence_fd, sync_file->file); + args->fence_fd = out_fence_fd; } if (!IS_ERR_OR_NULL(submit)) { From e4a718a3a47e89805c3be9d46a84de1949a98d5d Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Wed, 23 Jul 2025 10:09:07 +0800 Subject: [PATCH 0010/1292] tee: fix NULL pointer dereference in tee_shm_put tee_shm_put have NULL pointer dereference: __optee_disable_shm_cache --> shm = reg_pair_to_ptr(...);//shm maybe return NULL tee_shm_free(shm); --> tee_shm_put(shm);//crash Add check in tee_shm_put to fix it. panic log: Unable to handle kernel paging request at virtual address 0000000000100cca Mem abort info: ESR = 0x0000000096000004 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x04: level 0 translation fault Data abort info: ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 CM = 0, WnR = 0, TnD = 0, TagAccess = 0 GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 user pgtable: 4k pages, 48-bit VAs, pgdp=0000002049d07000 [0000000000100cca] pgd=0000000000000000, p4d=0000000000000000 Internal error: Oops: 0000000096000004 [#1] SMP CPU: 2 PID: 14442 Comm: systemd-sleep Tainted: P OE ------- ---- 6.6.0-39-generic #38 Source Version: 938b255f6cb8817c95b0dd5c8c2944acfce94b07 Hardware name: greatwall GW-001Y1A-FTH, BIOS Great Wall BIOS V3.0 10/26/2022 pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : tee_shm_put+0x24/0x188 lr : tee_shm_free+0x14/0x28 sp : ffff001f98f9faf0 x29: ffff001f98f9faf0 x28: ffff0020df543cc0 x27: 0000000000000000 x26: ffff001f811344a0 x25: ffff8000818dac00 x24: ffff800082d8d048 x23: ffff001f850fcd18 x22: 0000000000000001 x21: ffff001f98f9fb88 x20: ffff001f83e76218 x19: ffff001f83e761e0 x18: 000000000000ffff x17: 303a30303a303030 x16: 0000000000000000 x15: 0000000000000003 x14: 0000000000000001 x13: 0000000000000000 x12: 0101010101010101 x11: 0000000000000001 x10: 0000000000000001 x9 : ffff800080e08d0c x8 : ffff001f98f9fb88 x7 : 0000000000000000 x6 : 0000000000000000 x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000 x2 : ffff001f83e761e0 x1 : 00000000ffff001f x0 : 0000000000100cca Call trace: tee_shm_put+0x24/0x188 tee_shm_free+0x14/0x28 __optee_disable_shm_cache+0xa8/0x108 optee_shutdown+0x28/0x38 platform_shutdown+0x28/0x40 device_shutdown+0x144/0x2b0 kernel_power_off+0x3c/0x80 hibernate+0x35c/0x388 state_store+0x64/0x80 kobj_attr_store+0x14/0x28 sysfs_kf_write+0x48/0x60 kernfs_fop_write_iter+0x128/0x1c0 vfs_write+0x270/0x370 ksys_write+0x6c/0x100 __arm64_sys_write+0x20/0x30 invoke_syscall+0x4c/0x120 el0_svc_common.constprop.0+0x44/0xf0 do_el0_svc+0x24/0x38 el0_svc+0x24/0x88 el0t_64_sync_handler+0x134/0x150 el0t_64_sync+0x14c/0x15 Fixes: dfd0743f1d9e ("tee: handle lookup of shm with reference count 0") Signed-off-by: Pei Xiao Reviewed-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/tee_shm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index daf6e5cfd59ae2..915239b033f5f7 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -560,9 +560,13 @@ EXPORT_SYMBOL_GPL(tee_shm_get_from_id); */ void tee_shm_put(struct tee_shm *shm) { - struct tee_device *teedev = shm->ctx->teedev; + struct tee_device *teedev; bool do_release = false; + if (!shm || !shm->ctx || !shm->ctx->teedev) + return; + + teedev = shm->ctx->teedev; mutex_lock(&teedev->mutex); if (refcount_dec_and_test(&shm->refcount)) { /* From 50a74d0095cd23d2012133e208df45a298868870 Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Wed, 23 Jul 2025 14:22:41 +0800 Subject: [PATCH 0011/1292] tee: fix memory leak in tee_dyn_shm_alloc_helper When shm_register() fails in tee_dyn_shm_alloc_helper(), the pre-allocated pages array is not freed, resulting in a memory leak. Fixes: cf4441503e20 ("tee: optee: Move pool_op helper functions") Signed-off-by: Pei Xiao Reviewed-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/tee_shm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 915239b033f5f7..2a7d253d9c554c 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -230,7 +230,7 @@ int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align, pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); if (!pages) { rc = -ENOMEM; - goto err; + goto err_pages; } for (i = 0; i < nr_pages; i++) @@ -243,11 +243,13 @@ int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align, rc = shm_register(shm->ctx, shm, pages, nr_pages, (unsigned long)shm->kaddr); if (rc) - goto err; + goto err_kfree; } return 0; -err: +err_kfree: + kfree(pages); +err_pages: free_pages_exact(shm->kaddr, shm->size); shm->kaddr = NULL; return rc; From 6bc829220b33da8522572cc50fdf5067c51d3bf3 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 1 Aug 2025 09:58:35 +0200 Subject: [PATCH 0012/1292] spi: spi-qpic-snand: use correct CW_PER_PAGE value for OOB write The qcom_spi_program_oob() function uses only the last codeword to write the OOB data into the flash, but it sets the CW_PER_PAGE field in the CFG0 register as it would use all codewords. It seems that this confuses the hardware somehow, and any access to the flash fails with a timeout error after the function is called. The problem can be easily reproduced with the following commands: # dd if=/dev/zero bs=2176 count=1 > /tmp/test.bin 1+0 records in 1+0 records out # flash_erase /dev/mtd4 0 0 Erasing 128 Kibyte @ 0 -- 100 % complete # nandwrite -O /dev/mtd4 /tmp/test.bin Writing data to block 0 at offset 0x0 # nanddump -o /dev/mtd4 >/dev/null ECC failed: 0 ECC corrected: 0 Number of bad blocks: 0 Number of bbt blocks: 0 Block size 131072, page size 2048, OOB size 128 Dumping data starting at 0x00000000 and ending at 0x00020000... [ 33.197605] qcom_snand 79b0000.spi: failure to read oob libmtd: error!: MEMREADOOB64 ioctl failed for mtd4, offset 0 (eraseblock 0) error 110 (Operation timed out) [ 35.277582] qcom_snand 79b0000.spi: failure in submitting cmd descriptor libmtd: error!: cannot read 2048 bytes from mtd4 (eraseblock 0, offset 2048) error 110 (Operation timed out) nanddump: error!: mtd_read Change the code to use the correct CW_PER_PAGE value to avoid this. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Gabor Juhos Link: https://patch.msgid.link/20250801-qpic-snand-oob-cwpp-fix-v1-1-f5a41b86af2e@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 0cfa0d960fd3c2..5216d60e01aab2 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -1196,7 +1196,7 @@ static int qcom_spi_program_oob(struct qcom_nand_controller *snandc, u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) | - FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1); + FIELD_PREP(CW_PER_PAGE_MASK, 0); cfg1 = ecc_cfg->cfg1; ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; From 72332439e6b0a39e763d4604e71774ab83423275 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 4 Aug 2025 11:50:13 +0200 Subject: [PATCH 0013/1292] spi: spi-mem: Add missing kdoc argument The "*mem" pointer has been added without description, describe it in the kdoc comment in order to fix the following W=1 warning: Warning: drivers/spi/spi-mem.c:594 function parameter 'mem' not described in 'spi_mem_calc_op_duration' Fixes: a11a51896572 ("spi: spi-mem: Take into account the actual maximum frequency") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507310409.fnuQ21qb-lkp@intel.com/ Signed-off-by: Miquel Raynal Link: https://patch.msgid.link/20250804095013.409700-1-miquel.raynal@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 5db0639d3b0159..dfa8ab1ec80f08 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -577,6 +577,7 @@ EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq); * spi_mem_calc_op_duration() - Derives the theoretical length (in ns) of an * operation. This helps finding the best variant * among a list of possible choices. + * @mem: the SPI memory * @op: the operation to benchmark * * Some chips have per-op frequency limitations, PCBs usually have their own From 07f557f60a9a4e15288c29a2924e19e44200db51 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 30 Jul 2025 11:18:28 +0100 Subject: [PATCH 0014/1292] KVM: arm64: nv: Properly check ESR_EL2.VNCR on taking a VNCR_EL2 related fault Instead of checking for the ESR_EL2.VNCR bit being set (the only case we should be here), we are actually testing random bits in ESR_EL2.DFSC. 13 obviously being a lucky number, it matches both permission and translation fault status codes, which explains why we never saw it failing. This was found by inspection, while reviewing a vaguely related patch. Whilst we're at it, turn the BUG_ON() into a WARN_ON_ONCE(), as exploding here is just silly. Fixes: 069a05e535496 ("KVM: arm64: nv: Handle VNCR_EL2-triggered faults") Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20250730101828.1168707-1-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/nested.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index efb37aad11ece7..74a2a94dad9baf 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1287,7 +1287,7 @@ int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu) struct vncr_tlb *vt = vcpu->arch.vncr_tlb; u64 esr = kvm_vcpu_get_esr(vcpu); - BUG_ON(!(esr & ESR_ELx_VNCR_SHIFT)); + WARN_ON_ONCE(!(esr & ESR_ELx_VNCR)); if (esr_fsc_is_permission_fault(esr)) { inject_vncr_perm(vcpu); From 69f8fe955d0b4a951c3726669ab58360ed562484 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 29 Jul 2025 11:23:42 -0700 Subject: [PATCH 0015/1292] KVM: arm64: nv: Handle SEAs due to VNCR redirection System register accesses redirected to the VNCR page can also generate external aborts just like any other form of memory access. Route to kvm_handle_guest_sea() for potential APEI handling, falling back to a vSError if the kernel didn't handle the abort. Take the opportunity to throw out the useless kvm_ras.h which provided a helper with a single callsite... Cc: Jiaqi Yan Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20250729182342.3281742-1-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_mmu.h | 1 + arch/arm64/include/asm/kvm_ras.h | 25 ------------------------- arch/arm64/kvm/mmu.c | 29 +++++++++++++++++------------ arch/arm64/kvm/nested.c | 3 +++ 4 files changed, 21 insertions(+), 37 deletions(-) delete mode 100644 arch/arm64/include/asm/kvm_ras.h diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index ae563ebd6aee21..e4069f2ce64232 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -180,6 +180,7 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu); int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, phys_addr_t pa, unsigned long size, bool writable); +int kvm_handle_guest_sea(struct kvm_vcpu *vcpu); int kvm_handle_guest_abort(struct kvm_vcpu *vcpu); phys_addr_t kvm_mmu_get_httbr(void); diff --git a/arch/arm64/include/asm/kvm_ras.h b/arch/arm64/include/asm/kvm_ras.h deleted file mode 100644 index 9398ade632aaf9..00000000000000 --- a/arch/arm64/include/asm/kvm_ras.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2018 - Arm Ltd */ - -#ifndef __ARM64_KVM_RAS_H__ -#define __ARM64_KVM_RAS_H__ - -#include -#include -#include - -#include - -/* - * Was this synchronous external abort a RAS notification? - * Returns '0' for errors handled by some RAS subsystem, or -ENOENT. - */ -static inline int kvm_handle_guest_sea(void) -{ - /* apei_claim_sea(NULL) expects to mask interrupts itself */ - lockdep_assert_irqs_enabled(); - - return apei_claim_sea(NULL); -} - -#endif /* __ARM64_KVM_RAS_H__ */ diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 1c78864767c5ce..9a45daf817bfd2 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -4,19 +4,20 @@ * Author: Christoffer Dall */ +#include #include #include #include #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -1811,6 +1812,19 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) read_unlock(&vcpu->kvm->mmu_lock); } +int kvm_handle_guest_sea(struct kvm_vcpu *vcpu) +{ + /* + * Give APEI the opportunity to claim the abort before handling it + * within KVM. apei_claim_sea() expects to be called with IRQs enabled. + */ + lockdep_assert_irqs_enabled(); + if (apei_claim_sea(NULL) == 0) + return 1; + + return kvm_inject_serror(vcpu); +} + /** * kvm_handle_guest_abort - handles all 2nd stage aborts * @vcpu: the VCPU pointer @@ -1834,17 +1848,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) gfn_t gfn; int ret, idx; - /* Synchronous External Abort? */ - if (kvm_vcpu_abt_issea(vcpu)) { - /* - * For RAS the host kernel may handle this abort. - * There is no need to pass the error into the guest. - */ - if (kvm_handle_guest_sea()) - return kvm_inject_serror(vcpu); - - return 1; - } + if (kvm_vcpu_abt_issea(vcpu)) + return kvm_handle_guest_sea(vcpu); esr = kvm_vcpu_get_esr(vcpu); diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 74a2a94dad9baf..64b980dbfbf824 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1289,6 +1289,9 @@ int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu) WARN_ON_ONCE(!(esr & ESR_ELx_VNCR)); + if (kvm_vcpu_abt_issea(vcpu)) + return kvm_handle_guest_sea(vcpu); + if (esr_fsc_is_permission_fault(esr)) { inject_vncr_perm(vcpu); } else if (esr_fsc_is_translation_fault(esr)) { From a4f8e70d75dd11ab1a01894893e0b03f1d0b61fd Mon Sep 17 00:00:00 2001 From: Tianyu Xu Date: Tue, 5 Aug 2025 09:54:03 +0800 Subject: [PATCH 0016/1292] spi: spi-mem: add spi_mem_adjust_op_freq() in spi_mem_supports_op() The function spi_mem_adjust_op_freq() within spi_mem_exec_op() adjusts the op->max_freq, which will informs the SPI controller of the maximum frequency for each operation. This adjustment is based on combined information from the SPI device and the board's wiring conditions. Similarly, spi_mem_supports_op() will check the capabilities of the SPI controller. It also requires the combined information before it can accurately determine whether the SPI controller supports a given operation. Signed-off-by: Tianyu Xu Reviewed-by: Miquel Raynal Link: https://patch.msgid.link/20250805015403.43928-1-tianyxu@cisco.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index dfa8ab1ec80f08..a8f14c608d2d27 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -265,6 +265,9 @@ static bool spi_mem_internal_supports_op(struct spi_mem *mem, */ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { + /* Make sure the operation frequency is correct before going futher */ + spi_mem_adjust_op_freq(mem, (struct spi_mem_op *)op); + if (spi_mem_check_op(op)) return false; From af357a6a3b7d685e7aa621c6fb1d4ed6c349ec9e Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Thu, 7 Aug 2025 12:07:42 +0200 Subject: [PATCH 0017/1292] spi: spi-fsl-lpspi: Clamp too high speed_hz Currently the driver is not able to handle the case that a SPI device specifies a higher spi-max-frequency than half of per-clk: per-clk should be at least two times of transfer speed Fix this by clamping to the max possible value and use the minimum SCK period of 2 cycles. Fixes: 77736a98b859 ("spi: lpspi: add the error info of transfer speed setting") Signed-off-by: Stefan Wahren Link: https://patch.msgid.link/20250807100742.9917-1-wahrenst@gmx.net Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 67d4000c3cef5b..313e444a34f3e8 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -330,13 +330,11 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) } if (config.speed_hz > perclk_rate / 2) { - dev_err(fsl_lpspi->dev, - "per-clk should be at least two times of transfer speed"); - return -EINVAL; + div = 2; + } else { + div = DIV_ROUND_UP(perclk_rate, config.speed_hz); } - div = DIV_ROUND_UP(perclk_rate, config.speed_hz); - for (prescale = 0; prescale <= prescale_max; prescale++) { scldiv = div / (1 << prescale) - 2; if (scldiv >= 0 && scldiv < 256) { From 13d0fe84a214658254a7412b2b46ec1507dc51f0 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 5 Aug 2025 18:05:42 +0200 Subject: [PATCH 0018/1292] spi: spi-qpic-snand: fix calculating of ECC OOB regions' properties The OOB layout used by the driver has two distinct regions which contains hardware specific ECC data, yet the qcom_spi_ooblayout_ecc() function sets the same offset and length values for both regions which is clearly wrong. Change the code to calculate the correct values for both regions. For reference, the following table shows the computed offset and length values for various OOB size/ECC strength configurations: +-----------------+-----------------+ |before the change| after the change| +-------+----------+--------+--------+--------+--------+--------+ | OOB | ECC | region | region | region | region | region | | size | strength | index | offset | length | offset | length | +-------+----------+--------+--------+--------+--------+--------+ | 128 | 8 | 0 | 113 | 15 | 0 | 49 | | | | 1 | 113 | 15 | 65 | 63 | +-------+----------+--------+--------+--------+--------+--------+ | 128 | 4 | 0 | 117 | 11 | 0 | 37 | | | | 1 | 117 | 11 | 53 | 75 | +-------+----------+--------+--------+--------+--------+--------+ | 64 | 4 | 0 | 53 | 11 | 0 | 37 | | | | 1 | 53 | 11 | 53 | 11 | +-------+----------+--------+--------+--------+--------+--------+ Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Gabor Juhos Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20250805-qpic-snand-oob-ecc-fix-v2-1-e6f811c70d6f@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 5216d60e01aab2..7b76d2c82a5287 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -210,13 +210,21 @@ static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section, struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); struct qpic_ecc *qecc = snandc->qspi->ecc; - if (section > 1) - return -ERANGE; - - oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes; - oobregion->offset = mtd->oobsize - oobregion->length; + switch (section) { + case 0: + oobregion->offset = 0; + oobregion->length = qecc->bytes * (qecc->steps - 1) + + qecc->bbm_size; + return 0; + case 1: + oobregion->offset = qecc->bytes * (qecc->steps - 1) + + qecc->bbm_size + + qecc->steps * 4; + oobregion->length = mtd->oobsize - oobregion->offset; + return 0; + } - return 0; + return -ERANGE; } static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section, From 08c5b422807435cdb79bee60da84262102e5f26a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 23 Jul 2025 13:28:23 -0700 Subject: [PATCH 0019/1292] drm/msm: Defer fd_install in VM_BIND ioctl Avoid fd_install() until there are no more potential error paths, to avoid put_unused_fd() after the fd is made visible to userspace. Fixes: 2e6a8a1fe2b2 ("drm/msm: Add VM_BIND ioctl") Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/665365/ --- drivers/gpu/drm/msm/msm_gem_vma.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 3cd8562a51092d..dc54c693b28da8 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -1460,12 +1460,8 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file) if (args->flags & MSM_VM_BIND_FENCE_FD_OUT) { sync_file = sync_file_create(job->fence); - if (!sync_file) { + if (!sync_file) ret = -ENOMEM; - } else { - fd_install(out_fence_fd, sync_file->file); - args->fence_fd = out_fence_fd; - } } if (ret) @@ -1494,10 +1490,14 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file) out_unlock: mutex_unlock(&queue->lock); out_post_unlock: - if (ret && (out_fence_fd >= 0)) { - put_unused_fd(out_fence_fd); + if (ret) { + if (out_fence_fd >= 0) + put_unused_fd(out_fence_fd); if (sync_file) fput(sync_file->file); + } else if (sync_file) { + fd_install(out_fence_fd, sync_file->file); + args->fence_fd = out_fence_fd; } if (!IS_ERR_OR_NULL(job)) { From d02d50cb062737f2b0c689fa24ef8b86f14756e5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 30 Jul 2025 15:29:05 +0100 Subject: [PATCH 0020/1292] drm/msm: Fix dereference of pointer minor before null check Currently the pointer minor is being dereferenced before it is null checked, leading to a potential null pointer dereference issue. Fix this by dereferencing the pointer only after it has been null checked. Also Replace minor->dev with dev. Fixes: 4f89cf40d01e ("drm/msm: bail out late_init_minor() if it is not a GPU device") Signed-off-by: Colin Ian King Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/666259/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_debugfs.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index bbda865addae2e..97dc70876442f9 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -325,25 +325,28 @@ static struct drm_info_list msm_debugfs_list[] = { static int late_init_minor(struct drm_minor *minor) { - struct drm_device *dev = minor->dev; - struct msm_drm_private *priv = dev->dev_private; + struct drm_device *dev; + struct msm_drm_private *priv; int ret; if (!minor) return 0; + dev = minor->dev; + priv = dev->dev_private; + if (!priv->gpu_pdev) return 0; ret = msm_rd_debugfs_init(minor); if (ret) { - DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n"); + DRM_DEV_ERROR(dev->dev, "could not install rd debugfs\n"); return ret; } ret = msm_perf_debugfs_init(minor); if (ret) { - DRM_DEV_ERROR(minor->dev->dev, "could not install perf debugfs\n"); + DRM_DEV_ERROR(dev->dev, "could not install perf debugfs\n"); return ret; } From 4a00bf1fd5add1e0da37009cba5b5ffb4de255d9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 Aug 2025 10:59:58 -0700 Subject: [PATCH 0021/1292] drm/msm: Add missing "location"s to devcoredump This is needed to properly interpret some of the sections. v2: Fix missing \n Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/666651/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index faca2a0243ab99..8420cbe129c066 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -1796,6 +1796,7 @@ static void a7xx_show_shader(struct a6xx_gpu_state_obj *obj, print_name(p, " - type: ", a7xx_statetype_names[block->statetype]); print_name(p, " - pipe: ", a7xx_pipe_names[block->pipeid]); + drm_printf(p, " - location: %d\n", block->location); for (i = 0; i < block->num_sps; i++) { drm_printf(p, " - sp: %d\n", i); @@ -1873,6 +1874,7 @@ static void a7xx_show_dbgahb_cluster(struct a6xx_gpu_state_obj *obj, print_name(p, " - pipe: ", a7xx_pipe_names[dbgahb->pipe_id]); print_name(p, " - cluster-name: ", a7xx_cluster_names[dbgahb->cluster_id]); drm_printf(p, " - context: %d\n", dbgahb->context_id); + drm_printf(p, " - location: %d\n", dbgahb->location_id); a7xx_show_registers_indented(dbgahb->regs, obj->data, p, 4); } } From 9466b45c19f6646787d6249116e52a9c4382e6ad Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 Aug 2025 10:59:59 -0700 Subject: [PATCH 0022/1292] drm/msm: Fix section names and sizes The section names randomly appended _DATA or _ADDR in many cases, and/or didn't match the reg names. Fix them so crashdec can properly resolve the section names back to reg names. Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/666654/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h | 38 +++++++++---------- .../drm/msm/adreno/adreno_gen7_9_0_snapshot.h | 24 ++++++------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h index 95d93ac6812a4d..1c18499b60bb9b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h @@ -419,47 +419,47 @@ static const struct a6xx_indexed_registers a6xx_indexed_reglist[] = { REG_A6XX_CP_SQE_STAT_DATA, 0x33, NULL }, { "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR, REG_A6XX_CP_DRAW_STATE_DATA, 0x100, NULL }, - { "CP_UCODE_DBG_DATA", REG_A6XX_CP_SQE_UCODE_DBG_ADDR, + { "CP_SQE_UCODE_DBG", REG_A6XX_CP_SQE_UCODE_DBG_ADDR, REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x8000, NULL }, - { "CP_ROQ", REG_A6XX_CP_ROQ_DBG_ADDR, + { "CP_ROQ_DBG", REG_A6XX_CP_ROQ_DBG_ADDR, REG_A6XX_CP_ROQ_DBG_DATA, 0, a6xx_get_cp_roq_size}, }; static const struct a6xx_indexed_registers a7xx_indexed_reglist[] = { { "CP_SQE_STAT", REG_A6XX_CP_SQE_STAT_ADDR, - REG_A6XX_CP_SQE_STAT_DATA, 0x33, NULL }, + REG_A6XX_CP_SQE_STAT_DATA, 0x40, NULL }, { "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR, REG_A6XX_CP_DRAW_STATE_DATA, 0x100, NULL }, - { "CP_UCODE_DBG_DATA", REG_A6XX_CP_SQE_UCODE_DBG_ADDR, + { "CP_SQE_UCODE_DBG", REG_A6XX_CP_SQE_UCODE_DBG_ADDR, REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x8000, NULL }, - { "CP_BV_SQE_STAT_ADDR", REG_A7XX_CP_BV_SQE_STAT_ADDR, - REG_A7XX_CP_BV_SQE_STAT_DATA, 0x33, NULL }, - { "CP_BV_DRAW_STATE_ADDR", REG_A7XX_CP_BV_DRAW_STATE_ADDR, + { "CP_BV_SQE_STAT", REG_A7XX_CP_BV_SQE_STAT_ADDR, + REG_A7XX_CP_BV_SQE_STAT_DATA, 0x40, NULL }, + { "CP_BV_DRAW_STATE", REG_A7XX_CP_BV_DRAW_STATE_ADDR, REG_A7XX_CP_BV_DRAW_STATE_DATA, 0x100, NULL }, - { "CP_BV_SQE_UCODE_DBG_ADDR", REG_A7XX_CP_BV_SQE_UCODE_DBG_ADDR, + { "CP_BV_SQE_UCODE_DBG", REG_A7XX_CP_BV_SQE_UCODE_DBG_ADDR, REG_A7XX_CP_BV_SQE_UCODE_DBG_DATA, 0x8000, NULL }, - { "CP_SQE_AC_STAT_ADDR", REG_A7XX_CP_SQE_AC_STAT_ADDR, - REG_A7XX_CP_SQE_AC_STAT_DATA, 0x33, NULL }, - { "CP_LPAC_DRAW_STATE_ADDR", REG_A7XX_CP_LPAC_DRAW_STATE_ADDR, + { "CP_SQE_AC_STAT", REG_A7XX_CP_SQE_AC_STAT_ADDR, + REG_A7XX_CP_SQE_AC_STAT_DATA, 0x40, NULL }, + { "CP_LPAC_DRAW_STATE", REG_A7XX_CP_LPAC_DRAW_STATE_ADDR, REG_A7XX_CP_LPAC_DRAW_STATE_DATA, 0x100, NULL }, - { "CP_SQE_AC_UCODE_DBG_ADDR", REG_A7XX_CP_SQE_AC_UCODE_DBG_ADDR, + { "CP_SQE_AC_UCODE_DBG", REG_A7XX_CP_SQE_AC_UCODE_DBG_ADDR, REG_A7XX_CP_SQE_AC_UCODE_DBG_DATA, 0x8000, NULL }, - { "CP_LPAC_FIFO_DBG_ADDR", REG_A7XX_CP_LPAC_FIFO_DBG_ADDR, + { "CP_LPAC_FIFO_DBG", REG_A7XX_CP_LPAC_FIFO_DBG_ADDR, REG_A7XX_CP_LPAC_FIFO_DBG_DATA, 0x40, NULL }, - { "CP_ROQ", REG_A6XX_CP_ROQ_DBG_ADDR, + { "CP_ROQ_DBG", REG_A6XX_CP_ROQ_DBG_ADDR, REG_A6XX_CP_ROQ_DBG_DATA, 0, a7xx_get_cp_roq_size }, }; static const struct a6xx_indexed_registers a6xx_cp_mempool_indexed = { - "CP_MEMPOOL", REG_A6XX_CP_MEM_POOL_DBG_ADDR, + "CP_MEM_POOL_DBG", REG_A6XX_CP_MEM_POOL_DBG_ADDR, REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2060, NULL, }; static const struct a6xx_indexed_registers a7xx_cp_bv_mempool_indexed[] = { - { "CP_MEMPOOL", REG_A6XX_CP_MEM_POOL_DBG_ADDR, - REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2100, NULL }, - { "CP_BV_MEMPOOL", REG_A7XX_CP_BV_MEM_POOL_DBG_ADDR, - REG_A7XX_CP_BV_MEM_POOL_DBG_DATA, 0x2100, NULL }, + { "CP_MEM_POOL_DBG", REG_A6XX_CP_MEM_POOL_DBG_ADDR, + REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2200, NULL }, + { "CP_BV_MEM_POOL_DBG", REG_A7XX_CP_BV_MEM_POOL_DBG_ADDR, + REG_A7XX_CP_BV_MEM_POOL_DBG_DATA, 0x2200, NULL }, }; #define DEBUGBUS(_id, _count) { .id = _id, .name = #_id, .count = _count } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h index e02cabb39f194c..b1f8bbf1d843bc 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h @@ -1299,29 +1299,29 @@ static struct a6xx_indexed_registers gen7_9_0_cp_indexed_reg_list[] = { REG_A6XX_CP_SQE_STAT_DATA, 0x00040}, { "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR, REG_A6XX_CP_DRAW_STATE_DATA, 0x00200}, - { "CP_ROQ", REG_A6XX_CP_ROQ_DBG_ADDR, + { "CP_ROQ_DBG", REG_A6XX_CP_ROQ_DBG_ADDR, REG_A6XX_CP_ROQ_DBG_DATA, 0x00800}, - { "CP_UCODE_DBG_DATA", REG_A6XX_CP_SQE_UCODE_DBG_ADDR, + { "CP_SQE_UCODE_DBG", REG_A6XX_CP_SQE_UCODE_DBG_ADDR, REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x08000}, - { "CP_BV_DRAW_STATE_ADDR", REG_A7XX_CP_BV_DRAW_STATE_ADDR, + { "CP_BV_DRAW_STATE", REG_A7XX_CP_BV_DRAW_STATE_ADDR, REG_A7XX_CP_BV_DRAW_STATE_DATA, 0x00200}, - { "CP_BV_ROQ_DBG_ADDR", REG_A7XX_CP_BV_ROQ_DBG_ADDR, + { "CP_BV_ROQ_DBG", REG_A7XX_CP_BV_ROQ_DBG_ADDR, REG_A7XX_CP_BV_ROQ_DBG_DATA, 0x00800}, - { "CP_BV_SQE_UCODE_DBG_ADDR", REG_A7XX_CP_BV_SQE_UCODE_DBG_ADDR, + { "CP_BV_SQE_UCODE_DBG", REG_A7XX_CP_BV_SQE_UCODE_DBG_ADDR, REG_A7XX_CP_BV_SQE_UCODE_DBG_DATA, 0x08000}, - { "CP_BV_SQE_STAT_ADDR", REG_A7XX_CP_BV_SQE_STAT_ADDR, + { "CP_BV_SQE_STAT", REG_A7XX_CP_BV_SQE_STAT_ADDR, REG_A7XX_CP_BV_SQE_STAT_DATA, 0x00040}, - { "CP_RESOURCE_TBL", REG_A7XX_CP_RESOURCE_TABLE_DBG_ADDR, + { "CP_RESOURCE_TABLE_DBG", REG_A7XX_CP_RESOURCE_TABLE_DBG_ADDR, REG_A7XX_CP_RESOURCE_TABLE_DBG_DATA, 0x04100}, - { "CP_LPAC_DRAW_STATE_ADDR", REG_A7XX_CP_LPAC_DRAW_STATE_ADDR, + { "CP_LPAC_DRAW_STATE", REG_A7XX_CP_LPAC_DRAW_STATE_ADDR, REG_A7XX_CP_LPAC_DRAW_STATE_DATA, 0x00200}, - { "CP_LPAC_ROQ", REG_A7XX_CP_LPAC_ROQ_DBG_ADDR, + { "CP_LPAC_ROQ_DBG", REG_A7XX_CP_LPAC_ROQ_DBG_ADDR, REG_A7XX_CP_LPAC_ROQ_DBG_DATA, 0x00200}, - { "CP_SQE_AC_UCODE_DBG_ADDR", REG_A7XX_CP_SQE_AC_UCODE_DBG_ADDR, + { "CP_SQE_AC_UCODE_DBG", REG_A7XX_CP_SQE_AC_UCODE_DBG_ADDR, REG_A7XX_CP_SQE_AC_UCODE_DBG_DATA, 0x08000}, - { "CP_SQE_AC_STAT_ADDR", REG_A7XX_CP_SQE_AC_STAT_ADDR, + { "CP_SQE_AC_STAT", REG_A7XX_CP_SQE_AC_STAT_ADDR, REG_A7XX_CP_SQE_AC_STAT_DATA, 0x00040}, - { "CP_LPAC_FIFO_DBG_ADDR", REG_A7XX_CP_LPAC_FIFO_DBG_ADDR, + { "CP_LPAC_FIFO_DBG", REG_A7XX_CP_LPAC_FIFO_DBG_ADDR, REG_A7XX_CP_LPAC_FIFO_DBG_DATA, 0x00040}, { "CP_AQE_ROQ_0", REG_A7XX_CP_AQE_ROQ_DBG_ADDR_0, REG_A7XX_CP_AQE_ROQ_DBG_DATA_0, 0x00100}, From a506578d8909e7e6f0d545af9850ccd4318bf6cf Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 Aug 2025 11:00:00 -0700 Subject: [PATCH 0023/1292] drm/msm: Fix order of selector programming in cluster snapshot Program the selector _after_ selecting the aperture. This aligns with the downstream driver, and fixes a case where we were failing to capture ctx0 regs (and presumably what we thought were ctx1 regs were actually ctx0). Suggested-by: Akhil P Oommen Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/666655/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 8420cbe129c066..b4c8583dd6caaf 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -759,15 +759,15 @@ static void a7xx_get_cluster(struct msm_gpu *gpu, size_t datasize; int i, regcount = 0; - /* Some clusters need a selector register to be programmed too */ - if (cluster->sel) - in += CRASHDUMP_WRITE(in, cluster->sel->cd_reg, cluster->sel->val); - in += CRASHDUMP_WRITE(in, REG_A7XX_CP_APERTURE_CNTL_CD, A7XX_CP_APERTURE_CNTL_CD_PIPE(cluster->pipe_id) | A7XX_CP_APERTURE_CNTL_CD_CLUSTER(cluster->cluster_id) | A7XX_CP_APERTURE_CNTL_CD_CONTEXT(cluster->context_id)); + /* Some clusters need a selector register to be programmed too */ + if (cluster->sel) + in += CRASHDUMP_WRITE(in, cluster->sel->cd_reg, cluster->sel->val); + for (i = 0; cluster->regs[i] != UINT_MAX; i += 2) { int count = RANGE(cluster->regs, i); From 2f2cc939ad672361ca81fcb27d76dc8154b17a1c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 Aug 2025 11:00:01 -0700 Subject: [PATCH 0024/1292] drm/msm: Constify snapshot tables A bit of divergence from the downstream driver from which these headers were imported. But no need for these tables not to be const. Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/666656/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h | 8 ++++---- drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h | 8 ++++---- drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index b4c8583dd6caaf..7fc450ab8c120d 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -11,7 +11,7 @@ static const unsigned int *gen7_0_0_external_core_regs[] __always_unused; static const unsigned int *gen7_2_0_external_core_regs[] __always_unused; static const unsigned int *gen7_9_0_external_core_regs[] __always_unused; -static struct gen7_sptp_cluster_registers gen7_9_0_sptp_clusters[] __always_unused; +static const struct gen7_sptp_cluster_registers gen7_9_0_sptp_clusters[] __always_unused; static const u32 gen7_9_0_cx_debugbus_blocks[] __always_unused; #include "adreno_gen7_0_0_snapshot.h" diff --git a/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h index cb66ece6606b57..afcc7498983f83 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h @@ -81,7 +81,7 @@ static const u32 gen7_0_0_debugbus_blocks[] = { A7XX_DBGBUS_USPTP_7, }; -static struct gen7_shader_block gen7_0_0_shader_blocks[] = { +static const struct gen7_shader_block gen7_0_0_shader_blocks[] = { {A7XX_TP0_TMO_DATA, 0x200, 4, 2, A7XX_PIPE_BR, A7XX_USPTP}, {A7XX_TP0_SMO_DATA, 0x80, 4, 2, A7XX_PIPE_BR, A7XX_USPTP}, {A7XX_TP0_MIPMAP_BASE_DATA, 0x3c0, 4, 2, A7XX_PIPE_BR, A7XX_USPTP}, @@ -695,7 +695,7 @@ static const struct gen7_sel_reg gen7_0_0_rb_rbp_sel = { .val = 0x9, }; -static struct gen7_cluster_registers gen7_0_0_clusters[] = { +static const struct gen7_cluster_registers gen7_0_0_clusters[] = { { A7XX_CLUSTER_NONE, A7XX_PIPE_BR, STATE_NON_CONTEXT, gen7_0_0_noncontext_pipe_br_registers, }, { A7XX_CLUSTER_NONE, A7XX_PIPE_BV, STATE_NON_CONTEXT, @@ -764,7 +764,7 @@ static struct gen7_cluster_registers gen7_0_0_clusters[] = { gen7_0_0_vpc_cluster_vpc_ps_pipe_bv_registers, }, }; -static struct gen7_sptp_cluster_registers gen7_0_0_sptp_clusters[] = { +static const struct gen7_sptp_cluster_registers gen7_0_0_sptp_clusters[] = { { A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, A7XX_PIPE_BR, 0, A7XX_HLSQ_STATE, gen7_0_0_sp_noncontext_pipe_br_hlsq_state_registers, 0xae00 }, { A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, A7XX_PIPE_BR, 0, A7XX_SP_TOP, @@ -914,7 +914,7 @@ static const u32 gen7_0_0_dpm_registers[] = { }; static_assert(IS_ALIGNED(sizeof(gen7_0_0_dpm_registers), 8)); -static struct gen7_reg_list gen7_0_0_reg_list[] = { +static const struct gen7_reg_list gen7_0_0_reg_list[] = { { gen7_0_0_gpu_registers, NULL }, { gen7_0_0_cx_misc_registers, NULL }, { gen7_0_0_dpm_registers, NULL }, diff --git a/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h index 6f8ad50f32ce17..6569f12bf12fde 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h @@ -95,7 +95,7 @@ static const u32 gen7_2_0_debugbus_blocks[] = { A7XX_DBGBUS_CCHE_2, }; -static struct gen7_shader_block gen7_2_0_shader_blocks[] = { +static const struct gen7_shader_block gen7_2_0_shader_blocks[] = { {A7XX_TP0_TMO_DATA, 0x200, 6, 2, A7XX_PIPE_BR, A7XX_USPTP}, {A7XX_TP0_SMO_DATA, 0x80, 6, 2, A7XX_PIPE_BR, A7XX_USPTP}, {A7XX_TP0_MIPMAP_BASE_DATA, 0x3c0, 6, 2, A7XX_PIPE_BR, A7XX_USPTP}, @@ -489,7 +489,7 @@ static const struct gen7_sel_reg gen7_2_0_rb_rbp_sel = { .val = 0x9, }; -static struct gen7_cluster_registers gen7_2_0_clusters[] = { +static const struct gen7_cluster_registers gen7_2_0_clusters[] = { { A7XX_CLUSTER_NONE, A7XX_PIPE_BR, STATE_NON_CONTEXT, gen7_2_0_noncontext_pipe_br_registers, }, { A7XX_CLUSTER_NONE, A7XX_PIPE_BV, STATE_NON_CONTEXT, @@ -558,7 +558,7 @@ static struct gen7_cluster_registers gen7_2_0_clusters[] = { gen7_0_0_vpc_cluster_vpc_ps_pipe_bv_registers, }, }; -static struct gen7_sptp_cluster_registers gen7_2_0_sptp_clusters[] = { +static const struct gen7_sptp_cluster_registers gen7_2_0_sptp_clusters[] = { { A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, A7XX_PIPE_BR, 0, A7XX_HLSQ_STATE, gen7_0_0_sp_noncontext_pipe_br_hlsq_state_registers, 0xae00 }, { A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, A7XX_PIPE_BR, 0, A7XX_SP_TOP, @@ -737,7 +737,7 @@ static const u32 gen7_2_0_dpm_registers[] = { }; static_assert(IS_ALIGNED(sizeof(gen7_2_0_dpm_registers), 8)); -static struct gen7_reg_list gen7_2_0_reg_list[] = { +static const struct gen7_reg_list gen7_2_0_reg_list[] = { { gen7_2_0_gpu_registers, NULL }, { gen7_2_0_cx_misc_registers, NULL }, { gen7_2_0_dpm_registers, NULL }, diff --git a/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h index b1f8bbf1d843bc..0956dfca1f057e 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gen7_9_0_snapshot.h @@ -117,7 +117,7 @@ static const u32 gen7_9_0_cx_debugbus_blocks[] = { A7XX_DBGBUS_GBIF_CX, }; -static struct gen7_shader_block gen7_9_0_shader_blocks[] = { +static const struct gen7_shader_block gen7_9_0_shader_blocks[] = { { A7XX_TP0_TMO_DATA, 0x0200, 6, 2, A7XX_PIPE_BR, A7XX_USPTP }, { A7XX_TP0_SMO_DATA, 0x0080, 6, 2, A7XX_PIPE_BR, A7XX_USPTP }, { A7XX_TP0_MIPMAP_BASE_DATA, 0x03C0, 6, 2, A7XX_PIPE_BR, A7XX_USPTP }, @@ -1116,7 +1116,7 @@ static const struct gen7_sel_reg gen7_9_0_rb_rbp_sel = { .val = 0x9, }; -static struct gen7_cluster_registers gen7_9_0_clusters[] = { +static const struct gen7_cluster_registers gen7_9_0_clusters[] = { { A7XX_CLUSTER_NONE, A7XX_PIPE_BR, STATE_NON_CONTEXT, gen7_9_0_non_context_pipe_br_registers, }, { A7XX_CLUSTER_NONE, A7XX_PIPE_BV, STATE_NON_CONTEXT, @@ -1185,7 +1185,7 @@ static struct gen7_cluster_registers gen7_9_0_clusters[] = { gen7_9_0_vpc_pipe_bv_cluster_vpc_ps_registers, }, }; -static struct gen7_sptp_cluster_registers gen7_9_0_sptp_clusters[] = { +static const struct gen7_sptp_cluster_registers gen7_9_0_sptp_clusters[] = { { A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, A7XX_PIPE_BR, 0, A7XX_HLSQ_STATE, gen7_9_0_non_context_sp_pipe_br_hlsq_state_registers, 0xae00}, { A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, A7XX_PIPE_BR, 0, A7XX_SP_TOP, @@ -1294,7 +1294,7 @@ static struct gen7_sptp_cluster_registers gen7_9_0_sptp_clusters[] = { gen7_9_0_tpl1_pipe_br_cluster_sp_ps_usptp_registers, 0xb000}, }; -static struct a6xx_indexed_registers gen7_9_0_cp_indexed_reg_list[] = { +static const struct a6xx_indexed_registers gen7_9_0_cp_indexed_reg_list[] = { { "CP_SQE_STAT", REG_A6XX_CP_SQE_STAT_ADDR, REG_A6XX_CP_SQE_STAT_DATA, 0x00040}, { "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR, @@ -1337,7 +1337,7 @@ static struct a6xx_indexed_registers gen7_9_0_cp_indexed_reg_list[] = { REG_A7XX_CP_AQE_STAT_DATA_1, 0x00040}, }; -static struct gen7_reg_list gen7_9_0_reg_list[] = { +static const struct gen7_reg_list gen7_9_0_reg_list[] = { { gen7_9_0_gpu_registers, NULL}, { gen7_9_0_cx_misc_registers, NULL}, { gen7_9_0_cx_dbgc_registers, NULL}, From 13ed0a1af263b56a5ebbf38ab7163cbc9dcb009e Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 Aug 2025 11:00:02 -0700 Subject: [PATCH 0025/1292] drm/msm: Fix a7xx debugbus read The bitfield positions changed in a7xx. v2: Don't open-code the bitfield building v3: Also fix cx_debugbus Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/666659/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 32 ++++++++++++++----- drivers/gpu/drm/msm/registers/adreno/a6xx.xml | 14 +++++++- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 7fc450ab8c120d..75f93213e11422 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -174,8 +174,15 @@ static int a6xx_crashdumper_run(struct msm_gpu *gpu, static int debugbus_read(struct msm_gpu *gpu, u32 block, u32 offset, u32 *data) { - u32 reg = A6XX_DBGC_CFG_DBGBUS_SEL_D_PING_INDEX(offset) | - A6XX_DBGC_CFG_DBGBUS_SEL_D_PING_BLK_SEL(block); + u32 reg; + + if (to_adreno_gpu(gpu)->info->family >= ADRENO_7XX_GEN1) { + reg = A7XX_DBGC_CFG_DBGBUS_SEL_D_PING_INDEX(offset) | + A7XX_DBGC_CFG_DBGBUS_SEL_D_PING_BLK_SEL(block); + } else { + reg = A6XX_DBGC_CFG_DBGBUS_SEL_D_PING_INDEX(offset) | + A6XX_DBGC_CFG_DBGBUS_SEL_D_PING_BLK_SEL(block); + } gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_A, reg); gpu_write(gpu, REG_A6XX_DBGC_CFG_DBGBUS_SEL_B, reg); @@ -198,11 +205,18 @@ static int debugbus_read(struct msm_gpu *gpu, u32 block, u32 offset, readl((ptr) + ((offset) << 2)) /* read a value from the CX debug bus */ -static int cx_debugbus_read(void __iomem *cxdbg, u32 block, u32 offset, +static int cx_debugbus_read(struct msm_gpu *gpu, void __iomem *cxdbg, u32 block, u32 offset, u32 *data) { - u32 reg = A6XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_INDEX(offset) | - A6XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_BLK_SEL(block); + u32 reg; + + if (to_adreno_gpu(gpu)->info->family >= ADRENO_7XX_GEN1) { + reg = A7XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_INDEX(offset) | + A7XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_BLK_SEL(block); + } else { + reg = A6XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_INDEX(offset) | + A6XX_CX_DBGC_CFG_DBGBUS_SEL_A_PING_BLK_SEL(block); + } cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_SEL_A, reg); cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_SEL_B, reg); @@ -315,7 +329,8 @@ static void a6xx_get_debugbus_block(struct msm_gpu *gpu, ptr += debugbus_read(gpu, block->id, i, ptr); } -static void a6xx_get_cx_debugbus_block(void __iomem *cxdbg, +static void a6xx_get_cx_debugbus_block(struct msm_gpu *gpu, + void __iomem *cxdbg, struct a6xx_gpu_state *a6xx_state, const struct a6xx_debugbus_block *block, struct a6xx_gpu_state_obj *obj) @@ -330,7 +345,7 @@ static void a6xx_get_cx_debugbus_block(void __iomem *cxdbg, obj->handle = block; for (ptr = obj->data, i = 0; i < block->count; i++) - ptr += cx_debugbus_read(cxdbg, block->id, i, ptr); + ptr += cx_debugbus_read(gpu, cxdbg, block->id, i, ptr); } static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, @@ -526,7 +541,8 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu, int i; for (i = 0; i < nr_cx_debugbus_blocks; i++) - a6xx_get_cx_debugbus_block(cxdbg, + a6xx_get_cx_debugbus_block(gpu, + cxdbg, a6xx_state, &cx_debugbus_blocks[i], &a6xx_state->cx_debugbus[i]); diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml index d860fd94feae85..86fab2750ba7b6 100644 --- a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml +++ b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml @@ -594,10 +594,14 @@ by a particular renderpass/blit. - + + + + + @@ -3796,6 +3800,14 @@ by a particular renderpass/blit. + + + + + + + + From a814ba2d7b847cff15565bbab781df89e190619c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 Aug 2025 11:00:03 -0700 Subject: [PATCH 0026/1292] drm/msm: Fix debugbus snapshot We weren't setting the # of captured debugbus blocks. Reported-by: Connor Abbott Suggested-by: Connor Abbott Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/666660/ --- drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 75f93213e11422..d5d1271fce611b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -438,8 +438,9 @@ static void a7xx_get_debugbus_blocks(struct msm_gpu *gpu, a6xx_state, &a7xx_debugbus_blocks[gbif_debugbus_blocks[i]], &a6xx_state->debugbus[i + debugbus_blocks_count]); } - } + a6xx_state->nr_debugbus = total_debugbus_blocks; + } } static void a6xx_get_debugbus(struct msm_gpu *gpu, From e9621ef610c4a600678da5d8020d4a0dfe686faa Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 Aug 2025 11:00:04 -0700 Subject: [PATCH 0027/1292] drm/msm: Fix a7xx TPL1 cluster snapshot Later gens have both a PIPE_BR and PIPE_NONE section. The snapshot tool seems to expect this for x1-85 as well. I guess this was just a bug in downstream kgsl, which went unnoticed? Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/666662/ --- drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h | 11 +++++++++-- drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h index afcc7498983f83..04b49d385f9df1 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gen7_0_0_snapshot.h @@ -668,12 +668,19 @@ static const u32 gen7_0_0_sp_noncontext_pipe_lpac_usptp_registers[] = { }; static_assert(IS_ALIGNED(sizeof(gen7_0_0_sp_noncontext_pipe_lpac_usptp_registers), 8)); -/* Block: TPl1 Cluster: noncontext Pipeline: A7XX_PIPE_BR */ -static const u32 gen7_0_0_tpl1_noncontext_pipe_br_registers[] = { +/* Block: TPl1 Cluster: noncontext Pipeline: A7XX_PIPE_NONE */ +static const u32 gen7_0_0_tpl1_noncontext_pipe_none_registers[] = { 0x0b600, 0x0b600, 0x0b602, 0x0b602, 0x0b604, 0x0b604, 0x0b608, 0x0b60c, 0x0b60f, 0x0b621, 0x0b630, 0x0b633, UINT_MAX, UINT_MAX, }; +static_assert(IS_ALIGNED(sizeof(gen7_0_0_tpl1_noncontext_pipe_none_registers), 8)); + +/* Block: TPl1 Cluster: noncontext Pipeline: A7XX_PIPE_BR */ +static const u32 gen7_0_0_tpl1_noncontext_pipe_br_registers[] = { + 0x0b600, 0x0b600, + UINT_MAX, UINT_MAX, +}; static_assert(IS_ALIGNED(sizeof(gen7_0_0_tpl1_noncontext_pipe_br_registers), 8)); /* Block: TPl1 Cluster: noncontext Pipeline: A7XX_PIPE_LPAC */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h b/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h index 6569f12bf12fde..772652eb61f331 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gen7_2_0_snapshot.h @@ -573,6 +573,8 @@ static const struct gen7_sptp_cluster_registers gen7_2_0_sptp_clusters[] = { gen7_0_0_sp_noncontext_pipe_lpac_usptp_registers, 0xaf80 }, { A7XX_CLUSTER_NONE, A7XX_TP0_NCTX_REG, A7XX_PIPE_BR, 0, A7XX_USPTP, gen7_0_0_tpl1_noncontext_pipe_br_registers, 0xb600 }, + { A7XX_CLUSTER_NONE, A7XX_TP0_NCTX_REG, A7XX_PIPE_NONE, 0, A7XX_USPTP, + gen7_0_0_tpl1_noncontext_pipe_none_registers, 0xb600 }, { A7XX_CLUSTER_NONE, A7XX_TP0_NCTX_REG, A7XX_PIPE_LPAC, 0, A7XX_USPTP, gen7_0_0_tpl1_noncontext_pipe_lpac_registers, 0xb780 }, { A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, A7XX_PIPE_BR, 0, A7XX_HLSQ_STATE, From ba3afadeb81ebb92ab23546fbd2ec7d9dfe216f8 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 5 Aug 2025 09:43:08 -0700 Subject: [PATCH 0028/1292] drm/msm: Fix a few comments Fix a couple comments which had become (partially) obsolete or incorrect with the gpuvm conversion. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/667237/ --- drivers/gpu/drm/msm/msm_gem.h | 2 +- drivers/gpu/drm/msm/msm_gem_vma.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 88239da1cd72ff..751c3b4965bcd9 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -100,7 +100,7 @@ struct msm_gem_vm { * * Only used for kernel managed VMs, unused for user managed VMs. * - * Protected by @mm_lock. + * Protected by vm lock. See msm_gem_lock_vm_and_obj(), for ex. */ struct drm_mm mm; diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index dc54c693b28da8..d1f5bb2e0a165c 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -319,13 +319,10 @@ msm_gem_vma_map(struct drm_gpuva *vma, int prot, struct sg_table *sgt) mutex_lock(&vm->mmu_lock); /* - * NOTE: iommu/io-pgtable can allocate pages, so we cannot hold + * NOTE: if not using pgtable preallocation, we cannot hold * a lock across map/unmap which is also used in the job_run() * path, as this can cause deadlock in job_run() vs shrinker/ * reclaim. - * - * Revisit this if we can come up with a scheme to pre-alloc pages - * for the pgtable in map/unmap ops. */ ret = vm_map_op(vm, &(struct msm_vm_map_op){ .iova = vma->va.addr, From fe2f3b1c702f0e02906419c662ca9446cc789354 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 5 Aug 2025 09:44:31 -0700 Subject: [PATCH 0029/1292] drm/msm: Handle in-place remaps Detect and handle the special case of a MAP op simply updating the vma flags of an existing vma, and skip the pgtable updates. This allows turnip to set the MSM_VMA_DUMP flag on an existing mapping without requiring additional synchronization against commands running on the GPU. Signed-off-by: Rob Clark Tested-by: Connor Abbott Patchwork: https://patchwork.freedesktop.org/patch/667238/ --- drivers/gpu/drm/msm/msm_gem_vma.c | 41 ++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index d1f5bb2e0a165c..00d0f3b7ba327d 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -451,6 +451,8 @@ msm_gem_vm_bo_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec) struct op_arg { unsigned flags; struct msm_vm_bind_job *job; + const struct msm_vm_bind_op *op; + bool kept; }; static void @@ -472,14 +474,18 @@ vma_from_op(struct op_arg *arg, struct drm_gpuva_op_map *op) } static int -msm_gem_vm_sm_step_map(struct drm_gpuva_op *op, void *arg) +msm_gem_vm_sm_step_map(struct drm_gpuva_op *op, void *_arg) { - struct msm_vm_bind_job *job = ((struct op_arg *)arg)->job; + struct op_arg *arg = _arg; + struct msm_vm_bind_job *job = arg->job; struct drm_gem_object *obj = op->map.gem.obj; struct drm_gpuva *vma; struct sg_table *sgt; unsigned prot; + if (arg->kept) + return 0; + vma = vma_from_op(arg, &op->map); if (WARN_ON(IS_ERR(vma))) return PTR_ERR(vma); @@ -599,15 +605,41 @@ msm_gem_vm_sm_step_remap(struct drm_gpuva_op *op, void *arg) } static int -msm_gem_vm_sm_step_unmap(struct drm_gpuva_op *op, void *arg) +msm_gem_vm_sm_step_unmap(struct drm_gpuva_op *op, void *_arg) { - struct msm_vm_bind_job *job = ((struct op_arg *)arg)->job; + struct op_arg *arg = _arg; + struct msm_vm_bind_job *job = arg->job; struct drm_gpuva *vma = op->unmap.va; struct msm_gem_vma *msm_vma = to_msm_vma(vma); vm_dbg("%p:%p:%p: %016llx %016llx", vma->vm, vma, vma->gem.obj, vma->va.addr, vma->va.range); + /* + * Detect in-place remap. Turnip does this to change the vma flags, + * in particular MSM_VMA_DUMP. In this case we want to avoid actually + * touching the page tables, as that would require synchronization + * against SUBMIT jobs running on the GPU. + */ + if (op->unmap.keep && + (arg->op->op == MSM_VM_BIND_OP_MAP) && + (vma->gem.obj == arg->op->obj) && + (vma->gem.offset == arg->op->obj_offset) && + (vma->va.addr == arg->op->iova) && + (vma->va.range == arg->op->range)) { + /* We are only expecting a single in-place unmap+map cb pair: */ + WARN_ON(arg->kept); + + /* Leave the existing VMA in place, but signal that to the map cb: */ + arg->kept = true; + + /* Only flags are changing, so update that in-place: */ + unsigned orig_flags = vma->flags & (DRM_GPUVA_USERBITS - 1); + vma->flags = orig_flags | arg->flags; + + return 0; + } + if (!msm_vma->mapped) goto out_close; @@ -1268,6 +1300,7 @@ vm_bind_job_prepare(struct msm_vm_bind_job *job) const struct msm_vm_bind_op *op = &job->ops[i]; struct op_arg arg = { .job = job, + .op = op, }; switch (op->op) { From 42464c51ccccb6343a932a7ea8bc9181e589f270 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 7 Aug 2025 09:10:58 -0400 Subject: [PATCH 0030/1292] drm/msm: Fix objtool warning in submit_lock_objects() Split the vmbind case into a separate helper function submit_lock_objects_vmbind() to fix objtool warning: drivers/gpu/drm/msm/msm.o: warning: objtool: submit_lock_objects+0x451: sibling call from callable instruction with modified stack frame The drm_exec_until_all_locked() macro uses computed gotos internally for its retry loop. Having return statements inside this macro, or immediately after it in certain code paths, confuses objtool's static analysis of stack frames, causing it to incorrectly flag tail call optimizations. Fixes: 92395af63a99 ("drm/msm: Add VM_BIND submitqueue") Signed-off-by: Sasha Levin Patchwork: https://patchwork.freedesktop.org/patch/667539/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem_submit.c | 49 +++++++++++++++------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index bfea19baf6d9a4..3ab3b27134f93b 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -271,32 +271,37 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, return ret; } -/* This is where we make sure all the bo's are reserved and pin'd: */ -static int submit_lock_objects(struct msm_gem_submit *submit) +static int submit_lock_objects_vmbind(struct msm_gem_submit *submit) { - unsigned flags = DRM_EXEC_INTERRUPTIBLE_WAIT; + unsigned flags = DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES; struct drm_exec *exec = &submit->exec; - int ret; + int ret = 0; - if (msm_context_is_vmbind(submit->queue->ctx)) { - flags |= DRM_EXEC_IGNORE_DUPLICATES; + drm_exec_init(&submit->exec, flags, submit->nr_bos); - drm_exec_init(&submit->exec, flags, submit->nr_bos); + drm_exec_until_all_locked (&submit->exec) { + ret = drm_gpuvm_prepare_vm(submit->vm, exec, 1); + drm_exec_retry_on_contention(exec); + if (ret) + break; - drm_exec_until_all_locked (&submit->exec) { - ret = drm_gpuvm_prepare_vm(submit->vm, exec, 1); - drm_exec_retry_on_contention(exec); - if (ret) - return ret; + ret = drm_gpuvm_prepare_objects(submit->vm, exec, 1); + drm_exec_retry_on_contention(exec); + if (ret) + break; + } - ret = drm_gpuvm_prepare_objects(submit->vm, exec, 1); - drm_exec_retry_on_contention(exec); - if (ret) - return ret; - } + return ret; +} - return 0; - } +/* This is where we make sure all the bo's are reserved and pin'd: */ +static int submit_lock_objects(struct msm_gem_submit *submit) +{ + unsigned flags = DRM_EXEC_INTERRUPTIBLE_WAIT; + int ret = 0; + + if (msm_context_is_vmbind(submit->queue->ctx)) + return submit_lock_objects_vmbind(submit); drm_exec_init(&submit->exec, flags, submit->nr_bos); @@ -305,17 +310,17 @@ static int submit_lock_objects(struct msm_gem_submit *submit) drm_gpuvm_resv_obj(submit->vm)); drm_exec_retry_on_contention(&submit->exec); if (ret) - return ret; + break; for (unsigned i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; ret = drm_exec_prepare_obj(&submit->exec, obj, 1); drm_exec_retry_on_contention(&submit->exec); if (ret) - return ret; + break; } } - return 0; + return ret; } static int submit_fence_sync(struct msm_gem_submit *submit) From 700d6868fee2d384cbd821d31db3a245d218223c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Aug 2025 09:21:28 +0200 Subject: [PATCH 0031/1292] kvm: arm64: use BUG() instead of BUG_ON(1) The BUG_ON() macro adds a little bit of complexity over BUG(), and in some cases this ends up confusing the compiler's control flow analysis in a way that results in a warning. This one now shows up with clang-21: arch/arm64/kvm/vgic/vgic-mmio.c:1094:3: error: variable 'len' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized] 1094 | BUG_ON(1); Change both instances of BUG_ON(1) to a plain BUG() in the arm64 kvm code, to avoid the false-positive warning. Signed-off-by: Arnd Bergmann Reviewed-by: Nathan Chancellor Link: https://lore.kernel.org/r/20250807072132.4170088-1-arnd@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/nvhe/list_debug.c | 2 +- arch/arm64/kvm/vgic/vgic-mmio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/list_debug.c b/arch/arm64/kvm/hyp/nvhe/list_debug.c index 46a2d4f2b3c6ef..baa6260f88dc13 100644 --- a/arch/arm64/kvm/hyp/nvhe/list_debug.c +++ b/arch/arm64/kvm/hyp/nvhe/list_debug.c @@ -17,7 +17,7 @@ static inline __must_check bool nvhe_check_data_corruption(bool v) bool corruption = unlikely(condition); \ if (corruption) { \ if (IS_ENABLED(CONFIG_BUG_ON_DATA_CORRUPTION)) { \ - BUG_ON(1); \ + BUG(); \ } else \ WARN_ON(1); \ } \ diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c index e416e433baff3e..a573b1f0c6cbee 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.c +++ b/arch/arm64/kvm/vgic/vgic-mmio.c @@ -1091,7 +1091,7 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address, len = vgic_v3_init_dist_iodev(io_device); break; default: - BUG_ON(1); + BUG(); } io_device->base_addr = dist_base_address; From eaa43934b412f0381598e308b6a25d6c9a5dce2d Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Thu, 7 Aug 2025 13:01:31 +0100 Subject: [PATCH 0032/1292] KVM: arm64: Handle AIDR_EL1 and REVIDR_EL1 in host for protected VMs Since commit 17efc1acee62 ("arm64: Expose AIDR_EL1 via sysfs"), AIDR_EL1 is read early during boot. Therefore, a guest running as a protected VM will fail to boot because when it attempts to access AIDR_EL1, access to that register is restricted in pKVM for protected guests. Similar to how MIDR_EL1 is handled by the host for protected VMs, let the host handle accesses to AIDR_EL1 as well as REVIDR_EL1. However note that, unlike MIDR_EL1, AIDR_EL1 and REVIDR_EL1 are trapped by HCR_EL2.TID1. Therefore, explicitly mark them as handled by the host for protected VMs. TID1 is always set in pKVM, because it needs to restrict access to SMIDR_EL1, which is also trapped by that bit. Reported-by: Will Deacon Signed-off-by: Fuad Tabba Link: https://lore.kernel.org/r/20250807120133.871892-2-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/nvhe/sys_regs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c index 1ddd9ed3cbb3a9..bbd60013cf9e98 100644 --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c @@ -372,6 +372,9 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = { /* Debug and Trace Registers are restricted. */ + /* Group 1 ID registers */ + HOST_HANDLED(SYS_REVIDR_EL1), + /* AArch64 mappings of the AArch32 ID registers */ /* CRm=1 */ AARCH32(SYS_ID_PFR0_EL1), @@ -460,6 +463,7 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = { HOST_HANDLED(SYS_CCSIDR_EL1), HOST_HANDLED(SYS_CLIDR_EL1), + HOST_HANDLED(SYS_AIDR_EL1), HOST_HANDLED(SYS_CSSELR_EL1), HOST_HANDLED(SYS_CTR_EL0), From 798eb597870064bff28d8a41cb5197725f7dc6f2 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Thu, 7 Aug 2025 13:01:32 +0100 Subject: [PATCH 0033/1292] KVM: arm64: Sync protected guest VBAR_EL1 on injecting an undef exception In pKVM, a race condition can occur if a guest updates its VBAR_EL1 register and, before a vCPU exit synchronizes this change, the hypervisor needs to inject an undefined exception into a protected guest. In this scenario, the vCPU still holds the stale VBAR_EL1 value from before the guest's update. When pKVM injects the exception, it ends up using the stale value. Explicitly read the live value of VBAR_EL1 from the guest and update the vCPU value immediately before pending the exception. This ensures the vCPU's value is the same as the guest's and that the exception will be handled at the correct address upon resuming the guest. Reported-by: Keir Fraser Signed-off-by: Fuad Tabba Link: https://lore.kernel.org/r/20250807120133.871892-3-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/nvhe/sys_regs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c index bbd60013cf9e98..71d2fc97f0046a 100644 --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c @@ -253,6 +253,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu) *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR); *vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR); + __vcpu_assign_sys_reg(vcpu, read_sysreg_el1(SYS_VBAR), VBAR_EL1); kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC); From f1edb159200ad1ef2fc518c7673cb9559a6f8edd Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Thu, 7 Aug 2025 13:01:33 +0100 Subject: [PATCH 0034/1292] arm64: vgic-v2: Fix guest endianness check in hVHE mode In hVHE when running at the hypervisor, SCTLR_EL1 refers to the hypervisor's System Control Register rather than the guest's. Make sure to access the guest's register to determine its endianness. Reported-by: Will Deacon Signed-off-by: Fuad Tabba Link: https://lore.kernel.org/r/20250807120133.871892-4-tabba@google.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c index 87a54375bd6edc..78579b31a4205f 100644 --- a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c +++ b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c @@ -20,7 +20,7 @@ static bool __is_be(struct kvm_vcpu *vcpu) if (vcpu_mode_is_32bit(vcpu)) return !!(read_sysreg_el2(SYS_SPSR) & PSR_AA32_E_BIT); - return !!(read_sysreg(SCTLR_EL1) & SCTLR_ELx_EE); + return !!(read_sysreg_el1(SYS_SCTLR) & SCTLR_ELx_EE); } /* From 85acc29f90e0183997dea27277057c9aec2769aa Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 6 Aug 2025 18:13:41 +0100 Subject: [PATCH 0035/1292] KVM: arm64: selftest: Add standalone test checking for KVM's own UUID Tinkering with UUIDs is a perilious task, and the KVM UUID gets broken at times. In order to spot this early enough, add a selftest that will shout if the expected value isn't found. Signed-off-by: Marc Zyngier Reviewed-by: Sebastian Ott Link: https://lore.kernel.org/r/20250721130558.50823-1-jackabt.amazon@gmail.com Link: https://lore.kernel.org/r/20250806171341.1521210-1-maz@kernel.org Signed-off-by: Oliver Upton --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/arm64/kvm-uuid.c | 70 ++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 tools/testing/selftests/kvm/arm64/kvm-uuid.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index ce817a975e50a0..e1eb1ba238a2a0 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -167,6 +167,7 @@ TEST_GEN_PROGS_arm64 += arm64/vgic_irq TEST_GEN_PROGS_arm64 += arm64/vgic_lpi_stress TEST_GEN_PROGS_arm64 += arm64/vpmu_counter_access TEST_GEN_PROGS_arm64 += arm64/no-vgic-v3 +TEST_GEN_PROGS_arm64 += arm64/kvm-uuid TEST_GEN_PROGS_arm64 += access_tracking_perf_test TEST_GEN_PROGS_arm64 += arch_timer TEST_GEN_PROGS_arm64 += coalesced_io_test diff --git a/tools/testing/selftests/kvm/arm64/kvm-uuid.c b/tools/testing/selftests/kvm/arm64/kvm-uuid.c new file mode 100644 index 00000000000000..af9581b860f143 --- /dev/null +++ b/tools/testing/selftests/kvm/arm64/kvm-uuid.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Check that nobody has tampered with KVM's UID + +#include +#include +#include +#include + +#include "processor.h" + +/* + * Do NOT redefine these constants, or try to replace them with some + * "common" version. They are hardcoded here to detect any potential + * breakage happening in the rest of the kernel. + * + * KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 + */ +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 0xb66fb428U +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 0xe911c52eU +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 0x564bcaa9U +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3 0x743a004dU + +static void guest_code(void) +{ + struct arm_smccc_res res = {}; + + smccc_hvc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &res); + + __GUEST_ASSERT(res.a0 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 && + res.a1 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 && + res.a2 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 && + res.a3 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3, + "Unexpected KVM-specific UID %lx %lx %lx %lx\n", res.a0, res.a1, res.a2, res.a3); + GUEST_DONE(); +} + +int main (int argc, char *argv[]) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + bool guest_done = false; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + + while (!guest_done) { + vcpu_run(vcpu); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + break; + case UCALL_DONE: + guest_done = true; + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_PRINTF: + printf("%s", uc.buffer); + break; + default: + TEST_FAIL("Unexpected guest exit"); + } + } + + kvm_vm_free(vm); + + return 0; +} From bb8aeaa3191b617c6faf8ae937252e059673b7ea Mon Sep 17 00:00:00 2001 From: Fanhua Li Date: Mon, 28 Jul 2025 19:50:27 +0800 Subject: [PATCH 0036/1292] drm/nouveau/nvif: Fix potential memory leak in nvif_vmm_ctor(). When the nvif_vmm_type is invalid, we will return error directly without freeing the args in nvif_vmm_ctor(), which leading a memory leak. Fix it by setting the ret -EINVAL and goto done. Reported-by: kernel test robot Closes: https://lore.kernel.org/all/202312040659.4pJpMafN-lkp@intel.com/ Fixes: 6b252cf42281 ("drm/nouveau: nvkm/vmm: implement raw ops to manage uvmm") Signed-off-by: Fanhua Li Link: https://lore.kernel.org/r/20250728115027.50878-1-lifanhua5@huawei.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nvif/vmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvif/vmm.c b/drivers/gpu/drm/nouveau/nvif/vmm.c index 99296f03371ae0..07c1ebc2a94141 100644 --- a/drivers/gpu/drm/nouveau/nvif/vmm.c +++ b/drivers/gpu/drm/nouveau/nvif/vmm.c @@ -219,7 +219,8 @@ nvif_vmm_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, case RAW: args->type = NVIF_VMM_V0_TYPE_RAW; break; default: WARN_ON(1); - return -EINVAL; + ret = -EINVAL; + goto done; } memcpy(args->data, argv, argc); From 01c2afe7358385a5381835293dfb6901f11b1691 Mon Sep 17 00:00:00 2001 From: Madhur Kumar Date: Fri, 8 Aug 2025 13:08:40 +0530 Subject: [PATCH 0037/1292] drm/nouveau: fix typos in comments Fixed three spelling mistakes in nouveau_exec.c comments: - alloctor -> allocator - exectued -> executed - depent -> depend No functional changes. Fixes: b88baab82871 ("drm/nouveau: implement new VM_BIND uAPI") Signed-off-by: Madhur Kumar Link: https://lore.kernel.org/r/20250808073840.376764-1-madhurkumar004@gmail.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nouveau_exec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index 41b7c608c90548..46294134f29446 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -60,14 +60,14 @@ * virtual address in the GPU's VA space there is no guarantee that the actual * mappings are created in the GPU's MMU. If the given memory is swapped out * at the time the bind operation is executed the kernel will stash the mapping - * details into it's internal alloctor and create the actual MMU mappings once + * details into it's internal allocator and create the actual MMU mappings once * the memory is swapped back in. While this is transparent for userspace, it is * guaranteed that all the backing memory is swapped back in and all the memory * mappings, as requested by userspace previously, are actually mapped once the * DRM_NOUVEAU_EXEC ioctl is called to submit an exec job. * * A VM_BIND job can be executed either synchronously or asynchronously. If - * exectued asynchronously, userspace may provide a list of syncobjs this job + * executed asynchronously, userspace may provide a list of syncobjs this job * will wait for and/or a list of syncobj the kernel will signal once the * VM_BIND job finished execution. If executed synchronously the ioctl will * block until the bind job is finished. For synchronous jobs the kernel will @@ -82,7 +82,7 @@ * Since VM_BIND jobs update the GPU's VA space on job submit, EXEC jobs do have * an up to date view of the VA space. However, the actual mappings might still * be pending. Hence, EXEC jobs require to have the particular fences - of - * the corresponding VM_BIND jobs they depent on - attached to them. + * the corresponding VM_BIND jobs they depend on - attached to them. */ static int From 65f97cc81b0adc5f49cf6cff5d874be0058e3f41 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 6 Aug 2025 13:24:28 -0400 Subject: [PATCH 0038/1292] cgroup/cpuset: Use static_branch_enable_cpuslocked() on cpusets_insane_config_key The following lockdep splat was observed. [ 812.359086] ============================================ [ 812.359089] WARNING: possible recursive locking detected [ 812.359097] -------------------------------------------- [ 812.359100] runtest.sh/30042 is trying to acquire lock: [ 812.359105] ffffffffa7f27420 (cpu_hotplug_lock){++++}-{0:0}, at: static_key_enable+0xe/0x20 [ 812.359131] [ 812.359131] but task is already holding lock: [ 812.359134] ffffffffa7f27420 (cpu_hotplug_lock){++++}-{0:0}, at: cpuset_write_resmask+0x98/0xa70 : [ 812.359267] Call Trace: [ 812.359272] [ 812.359367] cpus_read_lock+0x3c/0xe0 [ 812.359382] static_key_enable+0xe/0x20 [ 812.359389] check_insane_mems_config.part.0+0x11/0x30 [ 812.359398] cpuset_write_resmask+0x9f2/0xa70 [ 812.359411] cgroup_file_write+0x1c7/0x660 [ 812.359467] kernfs_fop_write_iter+0x358/0x530 [ 812.359479] vfs_write+0xabe/0x1250 [ 812.359529] ksys_write+0xf9/0x1d0 [ 812.359558] do_syscall_64+0x5f/0xe0 Since commit d74b27d63a8b ("cgroup/cpuset: Change cpuset_rwsem and hotplug lock order"), the ordering of cpu hotplug lock and cpuset_mutex had been reversed. That patch correctly used the cpuslocked version of the static branch API to enable cpusets_pre_enable_key and cpusets_enabled_key, but it didn't do the same for cpusets_insane_config_key. The cpusets_insane_config_key can be enabled in the check_insane_mems_config() which is called from update_nodemask() or cpuset_hotplug_update_tasks() with both cpu hotplug lock and cpuset_mutex held. Deadlock can happen with a pending hotplug event that tries to acquire the cpu hotplug write lock which will block further cpus_read_lock() attempt from check_insane_mems_config(). Fix that by switching to use static_branch_enable_cpuslocked(). Fixes: d74b27d63a8b ("cgroup/cpuset: Change cpuset_rwsem and hotplug lock order") Signed-off-by: Waiman Long Reviewed-by: Juri Lelli Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index f74d04429a29c0..bf149246e00105 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -280,7 +280,7 @@ static inline void check_insane_mems_config(nodemask_t *nodes) { if (!cpusets_insane_config() && movable_only_nodes(nodes)) { - static_branch_enable(&cpusets_insane_config_key); + static_branch_enable_cpuslocked(&cpusets_insane_config_key); pr_info("Unsupported (movable nodes only) cpuset configuration detected (nmask=%*pbl)!\n" "Cpuset allocations might fail even with a lot of memory available.\n", nodemask_pr_args(nodes)); From 150e298ae0ccbecff2357a72fbabd80f8849ea6e Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 6 Aug 2025 13:24:29 -0400 Subject: [PATCH 0039/1292] cgroup/cpuset: Fix a partition error with CPU hotplug It was found during testing that an invalid leaf partition with an empty effective exclusive CPU list can become a valid empty partition with no CPU afer an offline/online operation of an unrelated CPU. An empty partition root is allowed in the special case that it has no task in its cgroup and has distributed out all its CPUs to its child partitions. That is certainly not the case here. The problem is in the cpumask_subsets() test in the hotplug case (update with no new mask) of update_parent_effective_cpumask() as it also returns true if the effective exclusive CPU list is empty. Fix that by addding the cpumask_empty() test to root out this exception case. Also add the cpumask_empty() test in cpuset_hotplug_update_tasks() to avoid calling update_parent_effective_cpumask() for this special case. Fixes: 0c7f293efc87 ("cgroup/cpuset: Add cpuset.cpus.exclusive.effective for v2") Signed-off-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index bf149246e00105..d993e058a66394 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1843,7 +1843,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd, if (is_partition_valid(cs)) adding = cpumask_and(tmp->addmask, xcpus, parent->effective_xcpus); - } else if (is_partition_invalid(cs) && + } else if (is_partition_invalid(cs) && !cpumask_empty(xcpus) && cpumask_subset(xcpus, parent->effective_xcpus)) { struct cgroup_subsys_state *css; struct cpuset *child; @@ -3870,9 +3870,10 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp) partcmd = partcmd_invalidate; /* * On the other hand, an invalid partition root may be transitioned - * back to a regular one. + * back to a regular one with a non-empty effective xcpus. */ - else if (is_partition_valid(parent) && is_partition_invalid(cs)) + else if (is_partition_valid(parent) && is_partition_invalid(cs) && + !cpumask_empty(cs->effective_xcpus)) partcmd = partcmd_update; if (partcmd >= 0) { From 87eba5bc5ab1d99e31c9d3b2c386187da94a5ab1 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 6 Aug 2025 13:24:30 -0400 Subject: [PATCH 0040/1292] cgroup/cpuset: Remove the unnecessary css_get/put() in cpuset_partition_write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The css_get/put() calls in cpuset_partition_write() are unnecessary as an active reference of the kernfs node will be taken which will prevent its removal and guarantee the existence of the css. Only the online check is needed. Signed-off-by: Waiman Long Reviewed-by: Michal Koutný Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index d993e058a66394..27adb04df675d4 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -3358,14 +3358,12 @@ static ssize_t cpuset_partition_write(struct kernfs_open_file *of, char *buf, else return -EINVAL; - css_get(&cs->css); cpus_read_lock(); mutex_lock(&cpuset_mutex); if (is_cpuset_online(cs)) retval = update_prstate(cs, val); mutex_unlock(&cpuset_mutex); cpus_read_unlock(); - css_put(&cs->css); return retval ?: nbytes; } From eea51c6e3f6675b795f6439eaa960eb2948d6905 Mon Sep 17 00:00:00 2001 From: JP Kobryn Date: Wed, 6 Aug 2025 17:33:50 -0700 Subject: [PATCH 0041/1292] cgroup: avoid null de-ref in css_rstat_exit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit css_rstat_exit() may be called asynchronously in scenarios where preceding calls to css_rstat_init() have not completed. One such example is this sequence below: css_create(...) { ... init_and_link_css(css, ...); err = percpu_ref_init(...); if (err) goto err_free_css; err = cgroup_idr_alloc(...); if (err) goto err_free_css; err = css_rstat_init(css, ...); if (err) goto err_free_css; ... err_free_css: INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn); queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork); return ERR_PTR(err); } If any of the three goto jumps are taken, async cleanup will begin and css_rstat_exit() will be invoked on an uninitialized css->rstat_cpu. Avoid accessing the unitialized field by returning early in css_rstat_exit() if this is the case. Signed-off-by: JP Kobryn Suggested-by: Michal Koutný Fixes: 5da3bfa029d68 ("cgroup: use separate rstat trees for each subsystem") Cc: stable@vger.kernel.org # v6.16 Reported-by: syzbot+8d052e8b99e40bc625ed@syzkaller.appspotmail.com Acked-by: Shakeel Butt Signed-off-by: Tejun Heo --- kernel/cgroup/rstat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c index 981e2f77ad4e5a..a198e40c799b48 100644 --- a/kernel/cgroup/rstat.c +++ b/kernel/cgroup/rstat.c @@ -479,6 +479,9 @@ void css_rstat_exit(struct cgroup_subsys_state *css) if (!css_uses_rstat(css)) return; + if (!css->rstat_cpu) + return; + css_rstat_flush(css); /* sanity check */ From eb5ca9094a18fb98777bf4814ea84c93bf7c271d Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sun, 27 Jul 2025 12:59:06 +0200 Subject: [PATCH 0042/1292] mm/vmscan: fix inverted polarity in lru_gen_seq_show() Commit a7694ff11aa9 ("vmscan: don't bother with debugfs_real_fops()") started using debugfs_get_aux_num() to distinguish between the RW "lru_gen" and the RO "lru_gen_full" file [1]. Willy reported the inverted polarity [2] and Al fixed it up in [3]. However, the patch in [1] was applied. Hence, fix this up accordingly. Cc: Alexander Viro Cc: Matthew Wilcox Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/all/20250704040720.GP1880847@ZenIV/ [1] Link: https://lore.kernel.org/all/aGZu3Z730FQtqxsE@casper.infradead.org/ [2] Link: https://lore.kernel.org/all/20250704040720.GP1880847@ZenIV/ [3] Fixes: a7694ff11aa9 ("vmscan: don't bother with debugfs_real_fops()") Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250727105937.7480-1-dakr@kernel.org Signed-off-by: Danilo Krummrich --- mm/vmscan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 7de11524a9369a..a48aec8bfd9251 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -5772,9 +5772,9 @@ static int __init init_lru_gen(void) if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) pr_err("lru_gen: failed to create sysfs group\n"); - debugfs_create_file_aux_num("lru_gen", 0644, NULL, NULL, 1, + debugfs_create_file_aux_num("lru_gen", 0644, NULL, NULL, false, &lru_gen_rw_fops); - debugfs_create_file_aux_num("lru_gen_full", 0444, NULL, NULL, 0, + debugfs_create_file_aux_num("lru_gen_full", 0444, NULL, NULL, true, &lru_gen_ro_fops); return 0; From 25daf9af0ac1bf12490b723b5efaf8dcc85980bc Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 30 Jul 2025 15:51:51 -0500 Subject: [PATCH 0043/1292] soc: qcom: mdt_loader: Deal with zero e_shentsize Firmware that doesn't provide section headers leave both e_shentsize and e_shnum 0, which obvious isn't compatible with the newly introduced stricter checks. Make the section-related checks conditional on either of these values being non-zero. Fixes: 9f9967fed9d0 ("soc: qcom: mdt_loader: Ensure we don't read past the ELF header") Reported-by: Val Packett Closes: https://lore.kernel.org/all/ece307c3-7d65-440f-babd-88cf9705b908@packett.cool/ Reported-by: Neil Armstrong Closes: https://lore.kernel.org/all/aec9cd03-6fc2-4dc8-b937-8b7cf7bf4128@linaro.org/ Signed-off-by: Bjorn Andersson Fixes: 9f35ab0e53cc ("soc: qcom: mdt_loader: Fix error return values in mdt_header_valid()") Tested-by: Neil Armstrong # on SM8650-QRD Reviewed-by: Dmitry Baryshkov Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250730-mdt-loader-shentsize-zero-v1-1-04f43186229c@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 0ca268bdf1f8c5..5710ac0c07a8c8 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -39,12 +39,14 @@ static bool mdt_header_valid(const struct firmware *fw) if (phend > fw->size) return false; - if (ehdr->e_shentsize != sizeof(struct elf32_shdr)) - return false; + if (ehdr->e_shentsize || ehdr->e_shnum) { + if (ehdr->e_shentsize != sizeof(struct elf32_shdr)) + return false; - shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff); - if (shend > fw->size) - return false; + shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff); + if (shend > fw->size) + return false; + } return true; } From 62498af7b1082d76031f98e4c3d6fb2b9af47772 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:22 +0200 Subject: [PATCH 0044/1292] dt-bindings: cpufreq: Add mediatek,mt8196-cpufreq-hw binding The MediaTek MT8196 SoC has new cpufreq hardware, with added memory register ranges to control Dynamic-Voltage-Frequency-Scaling. The DVFS hardware is controlled through a set of registers referred to as "FDVFS". They set the target frequency the DVFS hardware should aim for for each performance domain. Instead of working around the old binding and its already established meanings for the reg items, add a new binding. The FDVFS register memory region is at the beginning, which allows us to easily expand this binding for future SoCs which may have more than 3 performance domains. Signed-off-by: Nicolas Frattaroli Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring (Arm) Signed-off-by: Viresh Kumar --- .../cpufreq/mediatek,mt8196-cpufreq-hw.yaml | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml diff --git a/Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml b/Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml new file mode 100644 index 00000000000000..5f3c7db3f3aa0a --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/mediatek,mt8196-cpufreq-hw.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/cpufreq/mediatek,mt8196-cpufreq-hw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Hybrid CPUFreq for MT8196/MT6991 series SoCs + +maintainers: + - Nicolas Frattaroli + +description: + MT8196 uses CPUFreq management hardware that supports dynamic voltage + frequency scaling (dvfs), and can support several performance domains. + +properties: + compatible: + const: mediatek,mt8196-cpufreq-hw + + reg: + items: + - description: FDVFS control register region + - description: OPP tables and control for performance domain 0 + - description: OPP tables and control for performance domain 1 + - description: OPP tables and control for performance domain 2 + + "#performance-domain-cells": + const: 1 + +required: + - compatible + - reg + - "#performance-domain-cells" + +additionalProperties: false + +examples: + - | + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + enable-method = "psci"; + performance-domains = <&performance 0>; + reg = <0x000>; + }; + + /* ... */ + + cpu6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-x4"; + enable-method = "psci"; + performance-domains = <&performance 1>; + reg = <0x600>; + }; + + cpu7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-x925"; + enable-method = "psci"; + performance-domains = <&performance 2>; + reg = <0x700>; + }; + }; + + /* ... */ + + soc { + #address-cells = <2>; + #size-cells = <2>; + + performance: performance-controller@c2c2034 { + compatible = "mediatek,mt8196-cpufreq-hw"; + reg = <0 0xc220400 0 0x20>, <0 0xc2c0f20 0 0x120>, + <0 0xc2c1040 0 0x120>, <0 0xc2c1160 0 0x120>; + #performance-domain-cells = <1>; + }; + }; From 2f5178abb9f5164061b9cbbb5dd860f4d206b03a Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:23 +0200 Subject: [PATCH 0045/1292] cpufreq: mediatek-hw: Refactor match data into struct While the driver could get away with having the per-compatible match data just be an array of the reg offsets, the only thing it used it for right now, this doesn't really allow it to be extended in any meaningful way if some other per-variant information needs to be communicated. In preparation of adding support for hybrid "FDVFS" for MT8196, refactor the code to make the DT match data a struct, which currently only contains a single member: the reg offsets. This will allow this struct to be extended with other members for other hardware variants. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Frattaroli Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index 74f1b4c796e4cc..b2aba1842226c7 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -41,15 +41,22 @@ struct mtk_cpufreq_data { struct resource *res; void __iomem *base; int nr_opp; + const struct mtk_cpufreq_variant *variant; }; -static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = { - [REG_FREQ_LUT_TABLE] = 0x0, - [REG_FREQ_ENABLE] = 0x84, - [REG_FREQ_PERF_STATE] = 0x88, - [REG_FREQ_HW_STATE] = 0x8c, - [REG_EM_POWER_TBL] = 0x90, - [REG_FREQ_LATENCY] = 0x110, +struct mtk_cpufreq_variant { + const u16 reg_offsets[REG_ARRAY_SIZE]; +}; + +static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { + .reg_offsets = { + [REG_FREQ_LUT_TABLE] = 0x0, + [REG_FREQ_ENABLE] = 0x84, + [REG_FREQ_PERF_STATE] = 0x88, + [REG_FREQ_HW_STATE] = 0x8c, + [REG_EM_POWER_TBL] = 0x90, + [REG_FREQ_LATENCY] = 0x110, + }, }; static int __maybe_unused @@ -157,7 +164,7 @@ static int mtk_cpu_create_freq_table(struct platform_device *pdev, static int mtk_cpu_resources_init(struct platform_device *pdev, struct cpufreq_policy *policy, - const u16 *offsets) + const struct mtk_cpufreq_variant *variant) { struct mtk_cpufreq_data *data; struct device *dev = &pdev->dev; @@ -200,9 +207,10 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, data->base = base; data->res = res; + data->variant = variant; for (i = REG_FREQ_LUT_TABLE; i < REG_ARRAY_SIZE; i++) - data->reg_bases[i] = base + offsets[i]; + data->reg_bases[i] = base + variant->reg_offsets[i]; ret = mtk_cpu_create_freq_table(pdev, data); if (ret) { @@ -336,7 +344,7 @@ static void mtk_cpufreq_hw_driver_remove(struct platform_device *pdev) } static const struct of_device_id mtk_cpufreq_hw_match[] = { - { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_offsets }, + { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_base_variant }, {} }; MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match); From 35eb6b78854d2e9671ce8ee6b735aa0114c48da8 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:24 +0200 Subject: [PATCH 0046/1292] cpufreq: mediatek-hw: Separate per-domain and per-instance data As it stood, the mediatek cpufreq driver could get away with never really having a private driver instance struct. This is because all data was stored in the per-domain structs. However, this complicates matters when actual per-instance data like the variant struct is introduced. Instead of having a pointer to it for every domain, have a pointer to a global "priv" struct that can be extended over time, and rename the "data" struct to "domain" to distinguish its purpose better. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Frattaroli Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 42 +++++++++++++++++---------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index b2aba1842226c7..53611077d0d9a2 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -35,13 +35,17 @@ enum { REG_ARRAY_SIZE, }; -struct mtk_cpufreq_data { +struct mtk_cpufreq_priv { + const struct mtk_cpufreq_variant *variant; +}; + +struct mtk_cpufreq_domain { + struct mtk_cpufreq_priv *parent; struct cpufreq_frequency_table *table; void __iomem *reg_bases[REG_ARRAY_SIZE]; struct resource *res; void __iomem *base; int nr_opp; - const struct mtk_cpufreq_variant *variant; }; struct mtk_cpufreq_variant { @@ -63,7 +67,7 @@ static int __maybe_unused mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, unsigned long *KHz) { - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; struct cpufreq_policy *policy; int i; @@ -90,7 +94,7 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); @@ -99,7 +103,7 @@ static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy, static unsigned int mtk_cpufreq_hw_get(unsigned int cpu) { - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; struct cpufreq_policy *policy; unsigned int index; @@ -118,7 +122,7 @@ static unsigned int mtk_cpufreq_hw_get(unsigned int cpu) static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; unsigned int index; index = cpufreq_table_find_index_dl(policy, target_freq, false); @@ -129,7 +133,7 @@ static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, } static int mtk_cpu_create_freq_table(struct platform_device *pdev, - struct mtk_cpufreq_data *data) + struct mtk_cpufreq_domain *data) { struct device *dev = &pdev->dev; u32 temp, i, freq, prev_freq = 0; @@ -164,9 +168,9 @@ static int mtk_cpu_create_freq_table(struct platform_device *pdev, static int mtk_cpu_resources_init(struct platform_device *pdev, struct cpufreq_policy *policy, - const struct mtk_cpufreq_variant *variant) + struct mtk_cpufreq_priv *priv) { - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; struct device *dev = &pdev->dev; struct resource *res; struct of_phandle_args args; @@ -187,6 +191,8 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, index = args.args[0]; of_node_put(args.np); + data->parent = priv; + res = platform_get_resource(pdev, IORESOURCE_MEM, index); if (!res) { dev_err(dev, "failed to get mem resource %d\n", index); @@ -207,10 +213,9 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, data->base = base; data->res = res; - data->variant = variant; for (i = REG_FREQ_LUT_TABLE; i < REG_ARRAY_SIZE; i++) - data->reg_bases[i] = base + variant->reg_offsets[i]; + data->reg_bases[i] = base + priv->variant->reg_offsets[i]; ret = mtk_cpu_create_freq_table(pdev, data); if (ret) { @@ -231,7 +236,7 @@ static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) { struct platform_device *pdev = cpufreq_get_driver_data(); int sig, pwr_hw = CPUFREQ_HW_STATUS | SVS_HW_STATUS; - struct mtk_cpufreq_data *data; + struct mtk_cpufreq_domain *data; unsigned int latency; int ret; @@ -270,7 +275,7 @@ static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) static void mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) { - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; struct resource *res = data->res; void __iomem *base = data->base; @@ -283,7 +288,7 @@ static void mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) static void mtk_cpufreq_register_em(struct cpufreq_policy *policy) { struct em_data_callback em_cb = EM_DATA_CB(mtk_cpufreq_get_cpu_power); - struct mtk_cpufreq_data *data = policy->driver_data; + struct mtk_cpufreq_domain *data = policy->driver_data; em_dev_register_perf_domain(get_cpu_device(policy->cpu), data->nr_opp, &em_cb, policy->cpus, true); @@ -305,6 +310,7 @@ static struct cpufreq_driver cpufreq_mtk_hw_driver = { static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) { + struct mtk_cpufreq_priv *priv; const void *data; int ret, cpu; struct device *cpu_dev; @@ -328,7 +334,13 @@ static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) if (!data) return -EINVAL; - platform_set_drvdata(pdev, (void *) data); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->variant = data; + + platform_set_drvdata(pdev, priv); cpufreq_mtk_hw_driver.driver_data = pdev; ret = cpufreq_register_driver(&cpufreq_mtk_hw_driver); From 32e0d669f3ac9574862a64a56c9a6dff675f8600 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Wed, 16 Jul 2025 19:51:25 +0200 Subject: [PATCH 0047/1292] cpufreq: mediatek-hw: Add support for MT8196 The MT8196 SoC uses DVFS to set a desired target frequency for each CPU core. It also uses slightly different register offsets. Add support for it, which necessitates reworking how the mmio regs are acquired, as mt8196 has the fdvfs register before the performance domain registers. I've verified with both `sysbench cpu run` and `head -c 10G \ /dev/urandom | pigz -p 8 -c - | pv -ba > /dev/null` that we don't just get a higher reported clock frequency, but that the observed performance also increases, by a factor of 2.64 in an 8 thread sysbench test. Signed-off-by: Nicolas Frattaroli Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 70 ++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index 53611077d0d9a2..e4eadce6f937ce 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -24,6 +24,8 @@ #define POLL_USEC 1000 #define TIMEOUT_USEC 300000 +#define FDVFS_FDIV_HZ (26 * 1000) + enum { REG_FREQ_LUT_TABLE, REG_FREQ_ENABLE, @@ -36,7 +38,9 @@ enum { }; struct mtk_cpufreq_priv { + struct device *dev; const struct mtk_cpufreq_variant *variant; + void __iomem *fdvfs; }; struct mtk_cpufreq_domain { @@ -49,7 +53,9 @@ struct mtk_cpufreq_domain { }; struct mtk_cpufreq_variant { + int (*init)(struct mtk_cpufreq_priv *priv); const u16 reg_offsets[REG_ARRAY_SIZE]; + const bool is_hybrid_dvfs; }; static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { @@ -63,6 +69,29 @@ static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { }, }; +static int mtk_cpufreq_hw_mt8196_init(struct mtk_cpufreq_priv *priv) +{ + priv->fdvfs = devm_of_iomap(priv->dev, priv->dev->of_node, 0, NULL); + if (IS_ERR_OR_NULL(priv->fdvfs)) + return dev_err_probe(priv->dev, PTR_ERR(priv->fdvfs), + "failed to get fdvfs iomem\n"); + + return 0; +} + +static const struct mtk_cpufreq_variant cpufreq_mtk_mt8196_variant = { + .init = mtk_cpufreq_hw_mt8196_init, + .reg_offsets = { + [REG_FREQ_LUT_TABLE] = 0x0, + [REG_FREQ_ENABLE] = 0x84, + [REG_FREQ_PERF_STATE] = 0x88, + [REG_FREQ_HW_STATE] = 0x8c, + [REG_EM_POWER_TBL] = 0x90, + [REG_FREQ_LATENCY] = 0x114, + }, + .is_hybrid_dvfs = true, +}; + static int __maybe_unused mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, unsigned long *KHz) @@ -91,12 +120,31 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, return 0; } +static void mtk_cpufreq_hw_fdvfs_switch(unsigned int target_freq, + struct cpufreq_policy *policy) +{ + struct mtk_cpufreq_domain *data = policy->driver_data; + struct mtk_cpufreq_priv *priv = data->parent; + unsigned int cpu; + + target_freq = DIV_ROUND_UP(target_freq, FDVFS_FDIV_HZ); + for_each_cpu(cpu, policy->real_cpus) { + writel_relaxed(target_freq, priv->fdvfs + cpu * 4); + } +} + static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { struct mtk_cpufreq_domain *data = policy->driver_data; + unsigned int target_freq; - writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); + if (data->parent->fdvfs) { + target_freq = policy->freq_table[index].frequency; + mtk_cpufreq_hw_fdvfs_switch(target_freq, policy); + } else { + writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); + } return 0; } @@ -127,7 +175,10 @@ static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, index = cpufreq_table_find_index_dl(policy, target_freq, false); - writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); + if (data->parent->fdvfs) + mtk_cpufreq_hw_fdvfs_switch(target_freq, policy); + else + writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]); return policy->freq_table[index].frequency; } @@ -191,6 +242,13 @@ static int mtk_cpu_resources_init(struct platform_device *pdev, index = args.args[0]; of_node_put(args.np); + /* + * In a cpufreq with hybrid DVFS, such as the MT8196, the first declared + * register range is for FDVFS, followed by the frequency domain MMIOs. + */ + if (priv->variant->is_hybrid_dvfs) + index++; + data->parent = priv; res = platform_get_resource(pdev, IORESOURCE_MEM, index); @@ -339,6 +397,13 @@ static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) return -ENOMEM; priv->variant = data; + priv->dev = &pdev->dev; + + if (priv->variant->init) { + ret = priv->variant->init(priv); + if (ret) + return ret; + } platform_set_drvdata(pdev, priv); cpufreq_mtk_hw_driver.driver_data = pdev; @@ -357,6 +422,7 @@ static void mtk_cpufreq_hw_driver_remove(struct platform_device *pdev) static const struct of_device_id mtk_cpufreq_hw_match[] = { { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_base_variant }, + { .compatible = "mediatek,mt8196-cpufreq-hw", .data = &cpufreq_mtk_mt8196_variant }, {} }; MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match); From 8640689f17fd550c3e89d2b47ecb02536c58baf3 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 9 Aug 2025 13:28:30 +0200 Subject: [PATCH 0048/1292] cpufreq: airoha: Add support for AN7583 SoC New Airoha AN7583 SoC use the same exact logic to control the CPU frequency. Add the Device compatible to the block list for cpufreq-dt-plat and to the Airoha CPUFreq driver compatible list. Signed-off-by: Christian Marangi Signed-off-by: Viresh Kumar --- drivers/cpufreq/airoha-cpufreq.c | 1 + drivers/cpufreq/cpufreq-dt-platdev.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/cpufreq/airoha-cpufreq.c b/drivers/cpufreq/airoha-cpufreq.c index 4fe39eadd16337..b6b1cdc4d11d69 100644 --- a/drivers/cpufreq/airoha-cpufreq.c +++ b/drivers/cpufreq/airoha-cpufreq.c @@ -107,6 +107,7 @@ static struct platform_driver airoha_cpufreq_driver = { }; static const struct of_device_id airoha_cpufreq_match_list[] __initconst = { + { .compatible = "airoha,an7583" }, { .compatible = "airoha,en7581" }, {}, }; diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 015dd393eaba59..0f954b07dcb352 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -103,6 +103,7 @@ static const struct of_device_id allowlist[] __initconst = { * platforms using "operating-points-v2" property. */ static const struct of_device_id blocklist[] __initconst = { + { .compatible = "airoha,an7583", }, { .compatible = "airoha,en7581", }, { .compatible = "allwinner,sun50i-a100" }, From 17bd9599f07ff700b9fb7d15dfa1f1de42947a54 Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Sat, 9 Aug 2025 19:46:58 +0530 Subject: [PATCH 0049/1292] cpufreq: armada-37xx: use max() to calculate target_vm Use max() macro while calculating target_vm to simplify and improve the armada-37xx-cpufreq driver code. Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202503251256.rrl65HgY-lkp@intel.com/ Reported-by: Yang Ruibin <11162571@vivo.com> Closes: https://lore.kernel.org/lkml/2c55fb07-b29e-43e0-8697-f75d1f0df89a@vivo.com/ Signed-off-by: Akhilesh Patil Signed-off-by: Viresh Kumar --- drivers/cpufreq/armada-37xx-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index f28a4435fba71b..0efe403a59809c 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -265,7 +265,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, */ target_vm = avs_map[l0_vdd_min] - 100; - target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; + target_vm = max(target_vm, MIN_VOLT_MV); dvfs->avs[1] = armada_37xx_avs_val_match(target_vm); /* @@ -273,7 +273,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, * be larger than 1000mv */ target_vm = avs_map[l0_vdd_min] - 150; - target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; + target_vm = max(target_vm, MIN_VOLT_MV); dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm); /* From 16d39e2bf96075dc266fdcf0f2507fc075c33676 Mon Sep 17 00:00:00 2001 From: BowenYu Date: Wed, 30 Jul 2025 11:06:49 +0800 Subject: [PATCH 0050/1292] cpufreq: Remove unused parameter in cppc_perf_from_fbctrs() Remove the unused parameter cppc_cpudata* cpu_data in cppc_perf_from_fbctrs(). Signed-off-by: BowenYu Signed-off-by: Viresh Kumar --- drivers/cpufreq/cppc_cpufreq.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 4a17162a392da7..ecbeb12f46e64a 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -50,8 +50,7 @@ struct cppc_freq_invariance { static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv); static struct kthread_worker *kworker_fie; -static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, - struct cppc_perf_fb_ctrs *fb_ctrs_t0, +static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0, struct cppc_perf_fb_ctrs *fb_ctrs_t1); /** @@ -87,8 +86,7 @@ static void cppc_scale_freq_workfn(struct kthread_work *work) return; } - perf = cppc_perf_from_fbctrs(cpu_data, &cppc_fi->prev_perf_fb_ctrs, - &fb_ctrs); + perf = cppc_perf_from_fbctrs(&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs); if (!perf) return; @@ -684,8 +682,7 @@ static inline u64 get_delta(u64 t1, u64 t0) return (u32)t1 - (u32)t0; } -static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, - struct cppc_perf_fb_ctrs *fb_ctrs_t0, +static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0, struct cppc_perf_fb_ctrs *fb_ctrs_t1) { u64 delta_reference, delta_delivered; @@ -747,8 +744,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) return 0; } - delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0, - &fb_ctrs_t1); + delivered_perf = cppc_perf_from_fbctrs(&fb_ctrs_t0, &fb_ctrs_t1); if (!delivered_perf) goto out_invalid_counters; From f18c9e79bbe65627805fff6aac3ea96b6b55b53d Mon Sep 17 00:00:00 2001 From: Chukun Pan Date: Sun, 10 Aug 2025 18:00:19 +0800 Subject: [PATCH 0051/1292] arm64: dts: rockchip: mark eeprom as read-only for Radxa E52C The eeprom on the Radxa E52C SBC contains manufacturer data such as the mac address, so it should be marked as read-only. Fixes: 9be4171219b6 ("arm64: dts: rockchip: Add Radxa E52C") Signed-off-by: Chukun Pan Link: https://lore.kernel.org/r/20250810100020.445053-2-amadeus@jmu.edu.cn Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts b/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts index e04f21d8c831eb..431ff77d451803 100644 --- a/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts @@ -250,6 +250,7 @@ compatible = "belling,bl24c16a", "atmel,24c16"; reg = <0x50>; pagesize = <16>; + read-only; vcc-supply = <&vcc_3v3_pmu>; }; }; From 2b5066a3a19a2870f353f8783f1ee63e61b8e371 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Wed, 6 Aug 2025 16:58:06 +0530 Subject: [PATCH 0052/1292] cpufreq: qcom-nvmem: Enable cpufreq for ipq5424 IPQ5424 have different OPPs available for the CPU based on SoC variant. This can be determined through use of an eFuse register present in the silicon. Added support for ipq5424 on nvmem driver which helps to determine OPPs at runtime based on the eFuse register which has the CPU frequency limits. opp-supported-hw dt binding can be used to indicate the available OPPs for each limit. nvmem driver also creates the "cpufreq-dt" platform_device after passing the version matching data to the OPP framework so that the cpufreq-dt handles the actual cpufreq implementation. Signed-off-by: Md Sadre Alam Signed-off-by: Sricharan Ramabadhran Reviewed-by: Konrad Dybcio [ Changed '!=' based check to '==' based check ] Signed-off-by: Varadarajan Narayanan Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq-dt-platdev.c | 1 + drivers/cpufreq/qcom-cpufreq-nvmem.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 0f954b07dcb352..1a9d9d008002ca 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -192,6 +192,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "ti,am62p5", }, { .compatible = "qcom,ipq5332", }, + { .compatible = "qcom,ipq5424", }, { .compatible = "qcom,ipq6018", }, { .compatible = "qcom,ipq8064", }, { .compatible = "qcom,ipq8074", }, diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c index 54f8117103c850..765a5bb81829e1 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -200,6 +200,10 @@ static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, case QCOM_ID_IPQ9574: drv->versions = 1 << (unsigned int)(*speedbin); break; + case QCOM_ID_IPQ5424: + case QCOM_ID_IPQ5404: + drv->versions = (*speedbin == 0x3b) ? BIT(1) : BIT(0); + break; case QCOM_ID_MSM8996SG: case QCOM_ID_APQ8096SG: drv->versions = 1 << ((unsigned int)(*speedbin) + 4); @@ -591,6 +595,7 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst __maybe_u { .compatible = "qcom,msm8996", .data = &match_data_kryo }, { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, { .compatible = "qcom,ipq5332", .data = &match_data_kryo }, + { .compatible = "qcom,ipq5424", .data = &match_data_kryo }, { .compatible = "qcom,ipq6018", .data = &match_data_ipq6018 }, { .compatible = "qcom,ipq8064", .data = &match_data_ipq8064 }, { .compatible = "qcom,ipq8074", .data = &match_data_ipq8074 }, From d1f9c497618dece06a00e0b2995ed6b38fafe6b5 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Wed, 30 Jul 2025 11:21:26 +0100 Subject: [PATCH 0053/1292] arm64: dts: rockchip: Add vcc-supply to SPI flash on rk3399-pinebook-pro As described in the pinebookpro_v2.1_mainboard_schematic.pdf page 10, he SPI Flash's VCC connector is connected to VCC_3V0 power source. This fixes the following warning: spi-nor spi1.0: supply vcc not found, using dummy regulator Fixes: 5a65505a69884 ("arm64: dts: rockchip: Add initial support for Pinebook Pro") Signed-off-by: Peter Robinson Reviewed-by: Dragan Simic Link: https://lore.kernel.org/r/20250730102129.224468-1-pbrobinson@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts index 5a8551d9ffe47e..b33a1509a8e939 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts @@ -959,6 +959,7 @@ reg = <0>; m25p,fast-read; spi-max-frequency = <10000000>; + vcc-supply = <&vcc_3v0>; }; }; From 2c223f7239f376a90d71903ec474ba887cf21d94 Mon Sep 17 00:00:00 2001 From: Oreoluwa Babatunde Date: Wed, 6 Aug 2025 10:24:21 -0700 Subject: [PATCH 0054/1292] of: reserved_mem: Restructure call site for dma_contiguous_early_fixup() Restructure the call site for dma_contiguous_early_fixup() to where the reserved_mem nodes are being parsed from the DT so that dma_mmu_remap[] is populated before dma_contiguous_remap() is called. Fixes: 8a6e02d0c00e ("of: reserved_mem: Restructure how the reserved memory regions are processed") Signed-off-by: Oreoluwa Babatunde Tested-by: William Zhang Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20250806172421.2748302-1-oreoluwa.babatunde@oss.qualcomm.com --- drivers/of/of_reserved_mem.c | 16 ++++++++++++---- include/linux/dma-map-ops.h | 3 +++ kernel/dma/contiguous.c | 2 -- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 77016c0cc296e5..7350b23cb73418 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "of_private.h" @@ -175,13 +176,17 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, base = dt_mem_next_cell(dt_root_addr_cells, &prop); size = dt_mem_next_cell(dt_root_size_cells, &prop); - if (size && - early_init_dt_reserve_memory(base, size, nomap) == 0) + if (size && early_init_dt_reserve_memory(base, size, nomap) == 0) { + /* Architecture specific contiguous memory fixup. */ + if (of_flat_dt_is_compatible(node, "shared-dma-pool") && + of_get_flat_dt_prop(node, "reusable", NULL)) + dma_contiguous_early_fixup(base, size); pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); - else + } else { pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); + } len -= t_len; } @@ -472,7 +477,10 @@ static int __init __reserved_mem_alloc_size(unsigned long node, const char *unam uname, (unsigned long)(size / SZ_1M)); return -ENOMEM; } - + /* Architecture specific contiguous memory fixup. */ + if (of_flat_dt_is_compatible(node, "shared-dma-pool") && + of_get_flat_dt_prop(node, "reusable", NULL)) + dma_contiguous_early_fixup(base, size); /* Save region in the reserved_mem array */ fdt_reserved_mem_save_node(node, uname, base, size); return 0; diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h index f48e5fb88bd5dd..332b80c42b6f32 100644 --- a/include/linux/dma-map-ops.h +++ b/include/linux/dma-map-ops.h @@ -153,6 +153,9 @@ static inline void dma_free_contiguous(struct device *dev, struct page *page, { __free_pages(page, get_order(size)); } +static inline void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) +{ +} #endif /* CONFIG_DMA_CMA*/ #ifdef CONFIG_DMA_DECLARE_COHERENT diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c index 67af8a55185d99..d9b9dcba6ff7cf 100644 --- a/kernel/dma/contiguous.c +++ b/kernel/dma/contiguous.c @@ -483,8 +483,6 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem) pr_err("Reserved memory: unable to setup CMA region\n"); return err; } - /* Architecture specific contiguous memory fixup. */ - dma_contiguous_early_fixup(rmem->base, rmem->size); if (default_cma) dma_contiguous_default_area = cma; From 1db9df89a213318a48d958385dc1b17b379dc32b Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Sun, 3 Aug 2025 14:57:25 +0800 Subject: [PATCH 0055/1292] HID: intel-thc-hid: intel-quicki2c: Fix ACPI dsd ICRS/ISUB length The QuickI2C ACPI _DSD methods return ICRS and ISUB data with a trailing byte, making the actual length is one more byte than the structs defined. It caused stack-out-of-bounds and kernel crash: kernel: BUG: KASAN: stack-out-of-bounds in quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0 [intel_quicki2c] kernel: Write of size 12 at addr ffff888106d1f900 by task kworker/u33:2/75 kernel: kernel: CPU: 3 UID: 0 PID: 75 Comm: kworker/u33:2 Not tainted 6.16.0+ #3 PREEMPT(voluntary) kernel: Workqueue: async async_run_entry_fn kernel: Call Trace: kernel: kernel: dump_stack_lvl+0x76/0xa0 kernel: print_report+0xd1/0x660 kernel: ? __pfx__raw_spin_lock_irqsave+0x10/0x10 kernel: ? __kasan_slab_free+0x5d/0x80 kernel: ? kasan_addr_to_slab+0xd/0xb0 kernel: kasan_report+0xe1/0x120 kernel: ? quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0 [intel_quicki2c] kernel: ? quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0 [intel_quicki2c] kernel: kasan_check_range+0x11c/0x200 kernel: __asan_memcpy+0x3b/0x80 kernel: quicki2c_acpi_get_dsd_property.constprop.0+0x111/0x1b0 [intel_quicki2c] kernel: ? __pfx_quicki2c_acpi_get_dsd_property.constprop.0+0x10/0x10 [intel_quicki2c] kernel: quicki2c_get_acpi_resources+0x237/0x730 [intel_quicki2c] [...] kernel: kernel: kernel: The buggy address belongs to stack of task kworker/u33:2/75 kernel: and is located at offset 48 in frame: kernel: quicki2c_get_acpi_resources+0x0/0x730 [intel_quicki2c] kernel: kernel: This frame has 3 objects: kernel: [32, 36) 'hid_desc_addr' kernel: [48, 59) 'i2c_param' kernel: [80, 224) 'i2c_config' ACPI DSD methods return: \_SB.PC00.THC0.ICRS Buffer 000000003fdc947b 001 Len 0C = 0A 00 80 1A 06 00 00 00 00 00 00 00 \_SB.PC00.THC0.ISUB Buffer 00000000f2fcbdc4 001 Len 91 = 00 00 00 00 00 00 00 00 00 00 00 00 Adding reserved padding to quicki2c_subip_acpi_parameter/config. Fixes: 5282e45ccbfa9 ("HID: intel-thc-hid: intel-quicki2c: Add THC QuickI2C ACPI interfaces") Signed-off-by: Aaron Ma Reviewed-by: Even Xu Tested-by: Even Xu Signed-off-by: Jiri Kosina --- drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h index 93d6fa982d6091..d412eafcf9ea48 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h @@ -77,6 +77,7 @@ struct quicki2c_subip_acpi_parameter { u16 device_address; u64 connection_speed; u8 addressing_mode; + u8 reserved; } __packed; /** @@ -126,6 +127,7 @@ struct quicki2c_subip_acpi_config { u64 HMTD; u64 HMRD; u64 HMSL; + u8 reserved; }; /** From a7fc15ed629be89e51e09b743277c53e0a0168f5 Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Sun, 3 Aug 2025 14:57:26 +0800 Subject: [PATCH 0056/1292] HID: intel-thc-hid: intel-thc: Fix incorrect pointer arithmetic in I2C regs save Improper use of secondary pointer (&dev->i2c_subip_regs) caused kernel crash and out-of-bounds error: BUG: KASAN: slab-out-of-bounds in _regmap_bulk_read+0x449/0x510 Write of size 4 at addr ffff888136005dc0 by task kworker/u33:5/5107 CPU: 3 UID: 0 PID: 5107 Comm: kworker/u33:5 Not tainted 6.16.0+ #3 PREEMPT(voluntary) Workqueue: async async_run_entry_fn Call Trace: dump_stack_lvl+0x76/0xa0 print_report+0xd1/0x660 ? __pfx__raw_spin_lock_irqsave+0x10/0x10 ? kasan_complete_mode_report_info+0x26/0x200 kasan_report+0xe1/0x120 ? _regmap_bulk_read+0x449/0x510 ? _regmap_bulk_read+0x449/0x510 __asan_report_store4_noabort+0x17/0x30 _regmap_bulk_read+0x449/0x510 ? __pfx__regmap_bulk_read+0x10/0x10 regmap_bulk_read+0x270/0x3d0 pio_complete+0x1ee/0x2c0 [intel_thc] ? __pfx_pio_complete+0x10/0x10 [intel_thc] ? __pfx_pio_wait+0x10/0x10 [intel_thc] ? regmap_update_bits_base+0x13b/0x1f0 thc_i2c_subip_pio_read+0x117/0x270 [intel_thc] thc_i2c_subip_regs_save+0xc2/0x140 [intel_thc] ? __pfx_thc_i2c_subip_regs_save+0x10/0x10 [intel_thc] [...] The buggy address belongs to the object at ffff888136005d00 which belongs to the cache kmalloc-rnd-12-192 of size 192 The buggy address is located 0 bytes to the right of allocated 192-byte region [ffff888136005d00, ffff888136005dc0) Replaced with direct array indexing (&dev->i2c_subip_regs[i]) to ensure safe memory access. Fixes: 4228966def884 ("HID: intel-thc-hid: intel-thc: Add THC I2C config interfaces") Signed-off-by: Aaron Ma Reviewed-by: Even Xu Tested-by: Even Xu Signed-off-by: Jiri Kosina --- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 6f2263869b209a..e1cb9b117ebc53 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -1540,7 +1540,7 @@ int thc_i2c_subip_regs_save(struct thc_device *dev) for (int i = 0; i < ARRAY_SIZE(i2c_subip_regs); i++) { ret = thc_i2c_subip_pio_read(dev, i2c_subip_regs[i], - &read_size, (u32 *)&dev->i2c_subip_regs + i); + &read_size, &dev->i2c_subip_regs[i]); if (ret < 0) return ret; } @@ -1563,7 +1563,7 @@ int thc_i2c_subip_regs_restore(struct thc_device *dev) for (int i = 0; i < ARRAY_SIZE(i2c_subip_regs); i++) { ret = thc_i2c_subip_pio_write(dev, i2c_subip_regs[i], - write_size, (u32 *)&dev->i2c_subip_regs + i); + write_size, &dev->i2c_subip_regs[i]); if (ret < 0) return ret; } From d02d2c98d25793902f65803ab853b592c7a96b29 Mon Sep 17 00:00:00 2001 From: Jiufei Xue Date: Mon, 28 Jul 2025 18:07:15 +0800 Subject: [PATCH 0057/1292] fs: writeback: fix use-after-free in __mark_inode_dirty() An use-after-free issue occurred when __mark_inode_dirty() get the bdi_writeback that was in the progress of switching. CPU: 1 PID: 562 Comm: systemd-random- Not tainted 6.6.56-gb4403bd46a8e #1 ...... pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : __mark_inode_dirty+0x124/0x418 lr : __mark_inode_dirty+0x118/0x418 sp : ffffffc08c9dbbc0 ........ Call trace: __mark_inode_dirty+0x124/0x418 generic_update_time+0x4c/0x60 file_modified+0xcc/0xd0 ext4_buffered_write_iter+0x58/0x124 ext4_file_write_iter+0x54/0x704 vfs_write+0x1c0/0x308 ksys_write+0x74/0x10c __arm64_sys_write+0x1c/0x28 invoke_syscall+0x48/0x114 el0_svc_common.constprop.0+0xc0/0xe0 do_el0_svc+0x1c/0x28 el0_svc+0x40/0xe4 el0t_64_sync_handler+0x120/0x12c el0t_64_sync+0x194/0x198 Root cause is: systemd-random-seed kworker ---------------------------------------------------------------------- ___mark_inode_dirty inode_switch_wbs_work_fn spin_lock(&inode->i_lock); inode_attach_wb locked_inode_to_wb_and_lock_list get inode->i_wb spin_unlock(&inode->i_lock); spin_lock(&wb->list_lock) spin_lock(&inode->i_lock) inode_io_list_move_locked spin_unlock(&wb->list_lock) spin_unlock(&inode->i_lock) spin_lock(&old_wb->list_lock) inode_do_switch_wbs spin_lock(&inode->i_lock) inode->i_wb = new_wb spin_unlock(&inode->i_lock) spin_unlock(&old_wb->list_lock) wb_put_many(old_wb, nr_switched) cgwb_release old wb released wb_wakeup_delayed() accesses wb, then trigger the use-after-free issue Fix this race condition by holding inode spinlock until wb_wakeup_delayed() finished. Signed-off-by: Jiufei Xue Link: https://lore.kernel.org/20250728100715.3863241-1-jiufei.xue@samsung.com Reviewed-by: Jan Kara Signed-off-by: Christian Brauner --- fs/fs-writeback.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index cc57367fb641d7..a07b8cf73ae271 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -2608,10 +2608,6 @@ void __mark_inode_dirty(struct inode *inode, int flags) wakeup_bdi = inode_io_list_move_locked(inode, wb, dirty_list); - spin_unlock(&wb->list_lock); - spin_unlock(&inode->i_lock); - trace_writeback_dirty_inode_enqueue(inode); - /* * If this is the first dirty inode for this bdi, * we have to wake-up the corresponding bdi thread @@ -2621,6 +2617,11 @@ void __mark_inode_dirty(struct inode *inode, int flags) if (wakeup_bdi && (wb->bdi->capabilities & BDI_CAP_WRITEBACK)) wb_wakeup_delayed(wb); + + spin_unlock(&wb->list_lock); + spin_unlock(&inode->i_lock); + trace_writeback_dirty_inode_enqueue(inode); + return; } } From 9308366f062129d52e0ee3f7a019f7dd41db33df Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 8 Aug 2025 03:55:05 +1000 Subject: [PATCH 0058/1292] open_tree_attr: do not allow id-mapping changes without OPEN_TREE_CLONE As described in commit 7a54947e727b ('Merge patch series "fs: allow changing idmappings"'), open_tree_attr(2) was necessary in order to allow for a detached mount to be created and have its idmappings changed without the risk of any racing threads operating on it. For this reason, mount_setattr(2) still does not allow for id-mappings to be changed. However, there was a bug in commit 2462651ffa76 ("fs: allow changing idmappings") which allowed users to bypass this restriction by calling open_tree_attr(2) *without* OPEN_TREE_CLONE. can_idmap_mount() prevented this bug from allowing an attached mountpoint's id-mapping from being modified (thanks to an is_anon_ns() check), but this still allows for detached (but visible) mounts to have their be id-mapping changed. This risks the same UAF and locking issues as described in the merge commit, and was likely unintentional. Fixes: 2462651ffa76 ("fs: allow changing idmappings") Cc: stable@vger.kernel.org # v6.15+ Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/20250808-open_tree_attr-bugfix-idmap-v1-1-0ec7bc05646c@cyphar.com Signed-off-by: Christian Brauner --- fs/namespace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/namespace.c b/fs/namespace.c index ddfd4457d33837..ceb6b57e6a5793 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -5176,7 +5176,8 @@ SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename, int ret; struct mount_kattr kattr = {}; - kattr.kflags = MOUNT_KATTR_IDMAP_REPLACE; + if (flags & OPEN_TREE_CLONE) + kattr.kflags = MOUNT_KATTR_IDMAP_REPLACE; if (flags & AT_RECURSIVE) kattr.kflags |= MOUNT_KATTR_RECURSE; From 81e4b9cf365df4cde30157a85cc9f3d673946118 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 8 Aug 2025 03:55:06 +1000 Subject: [PATCH 0059/1292] selftests/mount_setattr: add smoke tests for open_tree_attr(2) bug There appear to be no other open_tree_attr(2) tests at the moment, but as a minimal solution just add some additional checks in the existing MOUNT_ATTR_IDMAP tests to make sure that open_tree_attr(2) cannot be used to bypass the tested restrictions that apply to mount_setattr(2). Signed-off-by: Aleksa Sarai Link: https://lore.kernel.org/20250808-open_tree_attr-bugfix-idmap-v1-2-0ec7bc05646c@cyphar.com Signed-off-by: Christian Brauner --- .../mount_setattr/mount_setattr_test.c | 77 +++++++++++++++---- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/mount_setattr/mount_setattr_test.c b/tools/testing/selftests/mount_setattr/mount_setattr_test.c index b1e4618399be67..a688871a98eba8 100644 --- a/tools/testing/selftests/mount_setattr/mount_setattr_test.c +++ b/tools/testing/selftests/mount_setattr/mount_setattr_test.c @@ -107,6 +107,26 @@ #endif #endif +#ifndef __NR_open_tree_attr + #if defined __alpha__ + #define __NR_open_tree_attr 577 + #elif defined _MIPS_SIM + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ + #define __NR_open_tree_attr (467 + 4000) + #endif + #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ + #define __NR_open_tree_attr (467 + 6000) + #endif + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_open_tree_attr (467 + 5000) + #endif + #elif defined __ia64__ + #define __NR_open_tree_attr (467 + 1024) + #else + #define __NR_open_tree_attr 467 + #endif +#endif + #ifndef MOUNT_ATTR_IDMAP #define MOUNT_ATTR_IDMAP 0x00100000 #endif @@ -121,6 +141,12 @@ static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flag return syscall(__NR_mount_setattr, dfd, path, flags, attr, size); } +static inline int sys_open_tree_attr(int dfd, const char *path, unsigned int flags, + struct mount_attr *attr, size_t size) +{ + return syscall(__NR_open_tree_attr, dfd, path, flags, attr, size); +} + static ssize_t write_nointr(int fd, const void *buf, size_t count) { ssize_t ret; @@ -1222,6 +1248,12 @@ TEST_F(mount_setattr_idmapped, attached_mount_inside_current_mount_namespace) attr.userns_fd = get_userns_fd(0, 10000, 10000); ASSERT_GE(attr.userns_fd, 0); ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); + /* + * Make sure that open_tree_attr() without OPEN_TREE_CLONE is not a way + * to bypass this mount_setattr() restriction. + */ + ASSERT_LT(sys_open_tree_attr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); + ASSERT_EQ(close(attr.userns_fd), 0); ASSERT_EQ(close(open_tree_fd), 0); } @@ -1255,6 +1287,12 @@ TEST_F(mount_setattr_idmapped, attached_mount_outside_current_mount_namespace) ASSERT_GE(attr.userns_fd, 0); ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); + /* + * Make sure that open_tree_attr() without OPEN_TREE_CLONE is not a way + * to bypass this mount_setattr() restriction. + */ + ASSERT_LT(sys_open_tree_attr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); + ASSERT_EQ(close(attr.userns_fd), 0); ASSERT_EQ(close(open_tree_fd), 0); } @@ -1321,6 +1359,19 @@ TEST_F(mount_setattr_idmapped, detached_mount_outside_current_mount_namespace) ASSERT_EQ(close(open_tree_fd), 0); } +static bool expected_uid_gid(int dfd, const char *path, int flags, + uid_t expected_uid, gid_t expected_gid) +{ + int ret; + struct stat st; + + ret = fstatat(dfd, path, &st, flags); + if (ret < 0) + return false; + + return st.st_uid == expected_uid && st.st_gid == expected_gid; +} + /** * Validate that currently changing the idmapping of an idmapped mount fails. */ @@ -1331,6 +1382,8 @@ TEST_F(mount_setattr_idmapped, change_idmapping) .attr_set = MOUNT_ATTR_IDMAP, }; + ASSERT_TRUE(expected_uid_gid(-EBADF, "/mnt/D", 0, 0, 0)); + if (!mount_setattr_supported()) SKIP(return, "mount_setattr syscall not supported"); @@ -1348,27 +1401,25 @@ TEST_F(mount_setattr_idmapped, change_idmapping) AT_EMPTY_PATH, &attr, sizeof(attr)), 0); ASSERT_EQ(close(attr.userns_fd), 0); + EXPECT_FALSE(expected_uid_gid(open_tree_fd, ".", 0, 0, 0)); + EXPECT_TRUE(expected_uid_gid(open_tree_fd, ".", 0, 10000, 10000)); + /* Change idmapping on a detached mount that is already idmapped. */ attr.userns_fd = get_userns_fd(0, 20000, 10000); ASSERT_GE(attr.userns_fd, 0); ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); + /* + * Make sure that open_tree_attr() without OPEN_TREE_CLONE is not a way + * to bypass this mount_setattr() restriction. + */ + EXPECT_LT(sys_open_tree_attr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); + EXPECT_FALSE(expected_uid_gid(open_tree_fd, ".", 0, 20000, 20000)); + EXPECT_TRUE(expected_uid_gid(open_tree_fd, ".", 0, 10000, 10000)); + ASSERT_EQ(close(attr.userns_fd), 0); ASSERT_EQ(close(open_tree_fd), 0); } -static bool expected_uid_gid(int dfd, const char *path, int flags, - uid_t expected_uid, gid_t expected_gid) -{ - int ret; - struct stat st; - - ret = fstatat(dfd, path, &st, flags); - if (ret < 0) - return false; - - return st.st_uid == expected_uid && st.st_gid == expected_gid; -} - TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid) { int open_tree_fd = -EBADF; From 6b65028e2b51c023a816eabffea88980fdd5564e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 30 Jul 2025 12:28:41 +0200 Subject: [PATCH 0060/1292] iomap: Fix broken data integrity guarantees for O_SYNC writes Commit d279c80e0bac ("iomap: inline iomap_dio_bio_opflags()") has broken the logic in iomap_dio_bio_iter() in a way that when the device does support FUA (or has no writeback cache) and the direct IO happens to freshly allocated or unwritten extents, we will *not* issue fsync after completing direct IO O_SYNC / O_DSYNC write because the IOMAP_DIO_WRITE_THROUGH flag stays mistakenly set. Fix the problem by clearing IOMAP_DIO_WRITE_THROUGH whenever we do not perform FUA write as it was originally intended. CC: John Garry CC: Ritesh Harjani (IBM) Fixes: d279c80e0bac ("iomap: inline iomap_dio_bio_opflags()") CC: stable@vger.kernel.org Signed-off-by: Jan Kara Link: https://lore.kernel.org/20250730102840.20470-2-jack@suse.cz Reviewed-by: Ritesh Harjani (IBM) Reviewed-by: John Garry Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Christian Brauner --- fs/iomap/direct-io.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index 6f25d4cfea9f7e..b84f6af2eb4c88 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -363,14 +363,14 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio) if (iomap->flags & IOMAP_F_SHARED) dio->flags |= IOMAP_DIO_COW; - if (iomap->flags & IOMAP_F_NEW) { + if (iomap->flags & IOMAP_F_NEW) need_zeroout = true; - } else if (iomap->type == IOMAP_MAPPED) { - if (iomap_dio_can_use_fua(iomap, dio)) - bio_opf |= REQ_FUA; - else - dio->flags &= ~IOMAP_DIO_WRITE_THROUGH; - } + else if (iomap->type == IOMAP_MAPPED && + iomap_dio_can_use_fua(iomap, dio)) + bio_opf |= REQ_FUA; + + if (!(bio_opf & REQ_FUA)) + dio->flags &= ~IOMAP_DIO_WRITE_THROUGH; /* * We can only do deferred completion for pure overwrites that From 542ede096e48436dbd70869640c0d88180565933 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 7 Aug 2025 10:50:15 -0700 Subject: [PATCH 0061/1292] fuse: keep inode->i_blkbits constant With fuse now using iomap for writeback handling, inode blkbits changes are problematic because iomap relies on inode->i_blkbits for its internal bitmap logic. Currently we change inode->i_blkbits in fuse to match the attr->blksize value passed in by the server. This commit keeps inode->i_blkbits constant in fuse. Any attr->blksize values passed in by the server will not update inode->i_blkbits. The client-side behavior for stat is unaffected, stat will still reflect the blocksize passed in by the server. Signed-off-by: Joanne Koong Link: https://lore.kernel.org/20250807175015.515192-1-joannelkoong@gmail.com Fixes: ef7e7cbb32 ("fuse: use iomap for writeback") Signed-off-by: Christian Brauner --- fs/fuse/inode.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ecb869e895ab1d..67c2318bfc4294 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -289,11 +289,6 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, } } - if (attr->blksize != 0) - inode->i_blkbits = ilog2(attr->blksize); - else - inode->i_blkbits = inode->i_sb->s_blocksize_bits; - /* * Don't set the sticky bit in i_mode, unless we want the VFS * to check permissions. This prevents failures due to the From 2319f9d0aa644eb9666c7be903078f50ecc2eb5b Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Mon, 11 Aug 2025 09:49:57 +0200 Subject: [PATCH 0062/1292] selftests/coredump: Remove the read() that fails the test Resolve a conflict between commit 6a68d28066b6 ("selftests/coredump: Fix "socket_detect_userspace_client" test failure") and commit 994dc26302ed ("selftests/coredump: fix build") The first commit adds a read() to wait for write() from another thread to finish. But the second commit removes the write(). Now that the two commits are in the same tree, the read() now gets EOF and the test fails. Remove this read() so that the test passes. Signed-off-by: Nam Cao Link: https://lore.kernel.org/20250811074957.4079616-1-namcao@linutronix.de Signed-off-by: Christian Brauner --- tools/testing/selftests/coredump/stackdump_test.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/coredump/stackdump_test.c b/tools/testing/selftests/coredump/stackdump_test.c index 5a5a7a5f7e1ddb..a4ac80bb10038d 100644 --- a/tools/testing/selftests/coredump/stackdump_test.c +++ b/tools/testing/selftests/coredump/stackdump_test.c @@ -446,9 +446,6 @@ TEST_F(coredump, socket_detect_userspace_client) if (info.coredump_mask & PIDFD_COREDUMPED) goto out; - if (read(fd_coredump, &c, 1) < 1) - goto out; - exit_code = EXIT_SUCCESS; out: if (fd_peer_pidfd >= 0) From 593d9e4c3d634c370f226f55453c376bf43b3684 Mon Sep 17 00:00:00 2001 From: Yuntao Wang Date: Mon, 11 Aug 2025 13:24:26 +0800 Subject: [PATCH 0063/1292] fs: fix incorrect lflags value in the move_mount syscall The lflags value used to look up from_path was overwritten by the one used to look up to_path. In other words, from_path was looked up with the wrong lflags value. Fix it. Fixes: f9fde814de37 ("fs: support getname_maybe_null() in move_mount()") Signed-off-by: Yuntao Wang Link: https://lore.kernel.org/20250811052426.129188-1-yuntao.wang@linux.dev [Christian Brauner : massage patch] Signed-off-by: Christian Brauner --- fs/namespace.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index ceb6b57e6a5793..43f32ee9f95c75 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -4551,20 +4551,10 @@ SYSCALL_DEFINE5(move_mount, if (flags & MOVE_MOUNT_SET_GROUP) mflags |= MNT_TREE_PROPAGATION; if (flags & MOVE_MOUNT_BENEATH) mflags |= MNT_TREE_BENEATH; - lflags = 0; - if (flags & MOVE_MOUNT_F_SYMLINKS) lflags |= LOOKUP_FOLLOW; - if (flags & MOVE_MOUNT_F_AUTOMOUNTS) lflags |= LOOKUP_AUTOMOUNT; uflags = 0; - if (flags & MOVE_MOUNT_F_EMPTY_PATH) uflags = AT_EMPTY_PATH; - from_name = getname_maybe_null(from_pathname, uflags); - if (IS_ERR(from_name)) - return PTR_ERR(from_name); + if (flags & MOVE_MOUNT_T_EMPTY_PATH) + uflags = AT_EMPTY_PATH; - lflags = 0; - if (flags & MOVE_MOUNT_T_SYMLINKS) lflags |= LOOKUP_FOLLOW; - if (flags & MOVE_MOUNT_T_AUTOMOUNTS) lflags |= LOOKUP_AUTOMOUNT; - uflags = 0; - if (flags & MOVE_MOUNT_T_EMPTY_PATH) uflags = AT_EMPTY_PATH; to_name = getname_maybe_null(to_pathname, uflags); if (IS_ERR(to_name)) return PTR_ERR(to_name); @@ -4577,11 +4567,24 @@ SYSCALL_DEFINE5(move_mount, to_path = fd_file(f_to)->f_path; path_get(&to_path); } else { + lflags = 0; + if (flags & MOVE_MOUNT_T_SYMLINKS) + lflags |= LOOKUP_FOLLOW; + if (flags & MOVE_MOUNT_T_AUTOMOUNTS) + lflags |= LOOKUP_AUTOMOUNT; ret = filename_lookup(to_dfd, to_name, lflags, &to_path, NULL); if (ret) return ret; } + uflags = 0; + if (flags & MOVE_MOUNT_F_EMPTY_PATH) + uflags = AT_EMPTY_PATH; + + from_name = getname_maybe_null(from_pathname, uflags); + if (IS_ERR(from_name)) + return PTR_ERR(from_name); + if (!from_name && from_dfd >= 0) { CLASS(fd_raw, f_from)(from_dfd); if (fd_empty(f_from)) @@ -4590,6 +4593,11 @@ SYSCALL_DEFINE5(move_mount, return vfs_move_mount(&fd_file(f_from)->f_path, &to_path, mflags); } + lflags = 0; + if (flags & MOVE_MOUNT_F_SYMLINKS) + lflags |= LOOKUP_FOLLOW; + if (flags & MOVE_MOUNT_F_AUTOMOUNTS) + lflags |= LOOKUP_AUTOMOUNT; ret = filename_lookup(from_dfd, from_name, lflags, &from_path, NULL); if (ret) return ret; From 6d3c3ca4c77e93660cce5819bf707f75df03e0c8 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Fri, 8 Aug 2025 15:28:47 +0200 Subject: [PATCH 0064/1292] module: Rename EXPORT_SYMBOL_GPL_FOR_MODULES to EXPORT_SYMBOL_FOR_MODULES Christoph suggested that the explicit _GPL_ can be dropped from the module namespace export macro, as it's intended for in-tree modules only. It would be possible to restrict it technically, but it was pointed out [2] that some cases of using an out-of-tree build of an in-tree module with the same name are legitimate. But in that case those also have to be GPL anyway so it's unnecessary to spell it out in the macro name. Link: https://lore.kernel.org/all/aFleJN_fE-RbSoFD@infradead.org/ [1] Link: https://lore.kernel.org/all/CAK7LNATRkZHwJGpojCnvdiaoDnP%2BaeUXgdey5sb_8muzdWTMkA@mail.gmail.com/ [2] Suggested-by: Christoph Hellwig Reviewed-by: Shivank Garg Acked-by: David Hildenbrand Acked-by: Nicolas Schier Reviewed-by: Daniel Gomez Reviewed-by: Christian Brauner Signed-off-by: Vlastimil Babka Link: https://lore.kernel.org/20250808-export_modules-v4-1-426945bcc5e1@suse.cz Signed-off-by: Christian Brauner --- Documentation/core-api/symbol-namespaces.rst | 11 ++++++----- drivers/tty/serial/8250/8250_rsa.c | 8 ++++---- fs/anon_inodes.c | 2 +- include/linux/export.h | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Documentation/core-api/symbol-namespaces.rst b/Documentation/core-api/symbol-namespaces.rst index 32fc73dc5529e8..034898e81ba201 100644 --- a/Documentation/core-api/symbol-namespaces.rst +++ b/Documentation/core-api/symbol-namespaces.rst @@ -76,20 +76,21 @@ unit as preprocessor statement. The above example would then read:: within the corresponding compilation unit before the #include for . Typically it's placed before the first #include statement. -Using the EXPORT_SYMBOL_GPL_FOR_MODULES() macro ------------------------------------------------ +Using the EXPORT_SYMBOL_FOR_MODULES() macro +------------------------------------------- Symbols exported using this macro are put into a module namespace. This -namespace cannot be imported. +namespace cannot be imported. These exports are GPL-only as they are only +intended for in-tree modules. The macro takes a comma separated list of module names, allowing only those modules to access this symbol. Simple tail-globs are supported. For example:: - EXPORT_SYMBOL_GPL_FOR_MODULES(preempt_notifier_inc, "kvm,kvm-*") + EXPORT_SYMBOL_FOR_MODULES(preempt_notifier_inc, "kvm,kvm-*") -will limit usage of this symbol to modules whoes name matches the given +will limit usage of this symbol to modules whose name matches the given patterns. How to use Symbols exported in Namespaces diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c index d34093cc03ad94..12a65b79583c03 100644 --- a/drivers/tty/serial/8250/8250_rsa.c +++ b/drivers/tty/serial/8250/8250_rsa.c @@ -147,7 +147,7 @@ void rsa_enable(struct uart_8250_port *up) if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) serial_out(up, UART_RSA_FRR, 0); } -EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_enable, "8250_base"); +EXPORT_SYMBOL_FOR_MODULES(rsa_enable, "8250_base"); /* * Attempts to turn off the RSA FIFO and resets the RSA board back to 115kbps compat mode. It is @@ -179,7 +179,7 @@ void rsa_disable(struct uart_8250_port *up) up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; uart_port_unlock_irq(&up->port); } -EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_disable, "8250_base"); +EXPORT_SYMBOL_FOR_MODULES(rsa_disable, "8250_base"); void rsa_autoconfig(struct uart_8250_port *up) { @@ -192,7 +192,7 @@ void rsa_autoconfig(struct uart_8250_port *up) if (__rsa_enable(up)) up->port.type = PORT_RSA; } -EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_autoconfig, "8250_base"); +EXPORT_SYMBOL_FOR_MODULES(rsa_autoconfig, "8250_base"); void rsa_reset(struct uart_8250_port *up) { @@ -201,7 +201,7 @@ void rsa_reset(struct uart_8250_port *up) serial_out(up, UART_RSA_FRR, 0); } -EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_reset, "8250_base"); +EXPORT_SYMBOL_FOR_MODULES(rsa_reset, "8250_base"); #ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS #ifndef MODULE diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 1d847a939f29a4..180a458fc4f742 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -129,7 +129,7 @@ struct inode *anon_inode_make_secure_inode(struct super_block *sb, const char *n } return inode; } -EXPORT_SYMBOL_GPL_FOR_MODULES(anon_inode_make_secure_inode, "kvm"); +EXPORT_SYMBOL_FOR_MODULES(anon_inode_make_secure_inode, "kvm"); static struct file *__anon_inode_getfile(const char *name, const struct file_operations *fops, diff --git a/include/linux/export.h b/include/linux/export.h index f35d03b4113b19..a686fd0ba40650 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -91,6 +91,6 @@ #define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", ns) #define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "GPL", ns) -#define EXPORT_SYMBOL_GPL_FOR_MODULES(sym, mods) __EXPORT_SYMBOL(sym, "GPL", "module:" mods) +#define EXPORT_SYMBOL_FOR_MODULES(sym, mods) __EXPORT_SYMBOL(sym, "GPL", "module:" mods) #endif /* _LINUX_EXPORT_H */ From d28b9d2925b4f773adb21b1fc20260ddc370fb13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Mon, 30 Jun 2025 11:00:53 +0200 Subject: [PATCH 0065/1292] drm/tests: Fix endian warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with sparse enabled, this warning is thrown: warning: incorrect type in argument 2 (different base types) expected restricted __le32 const [usertype] *buf got unsigned int [usertype] *[assigned] buf Add a cast to fix it. Fixes: 453114319699 ("drm/format-helper: Add KUnit tests for drm_fb_xrgb8888_to_xrgb2101010()") Signed-off-by: JosĆ© Expósito Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://lore.kernel.org/r/20250630090054.353246-1-jose.exposito89@gmail.com --- drivers/gpu/drm/tests/drm_format_helper_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index 7299fa8971ce5a..86829e1cb7f092 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -1033,7 +1033,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) NULL : &result->dst_pitch; drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); - buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32)); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); buf = dst.vaddr; /* restore original value of buf */ From 05663d88fd0b8ee1c54ab2d5fb36f9b6a3ed37f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Mon, 30 Jun 2025 11:00:54 +0200 Subject: [PATCH 0066/1292] drm/tests: Fix drm_test_fb_xrgb8888_to_xrgb2101010() on big-endian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix failures on big-endian architectures on tests cases single_pixel_source_buffer, single_pixel_clip_rectangle, well_known_colors and destination_pitch. Fixes: 15bda1f8de5d ("drm/tests: Add calls to drm_fb_blit() on supported format conversion tests") Signed-off-by: JosĆ© Expósito Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://lore.kernel.org/r/20250630090054.353246-2-jose.exposito89@gmail.com --- drivers/gpu/drm/tests/drm_format_helper_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index 86829e1cb7f092..981dada8f3a8f1 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -1040,6 +1040,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) memset(buf, 0, dst_size); drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip, &fmtcnv_state); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } From 5634c8cb298a7146b4e38873473e280b50e27a2c Mon Sep 17 00:00:00 2001 From: Nitin Gote Date: Fri, 18 Jul 2025 16:20:51 +0530 Subject: [PATCH 0067/1292] iosys-map: Fix undefined behavior in iosys_map_clear() The current iosys_map_clear() implementation reads the potentially uninitialized 'is_iomem' boolean field to decide which union member to clear. This causes undefined behavior when called on uninitialized structures, as 'is_iomem' may contain garbage values like 0xFF. UBSAN detects this as: UBSAN: invalid-load in include/linux/iosys-map.h:267 load of value 255 is not a valid value for type '_Bool' Fix by unconditionally clearing the entire structure with memset(), eliminating the need to read uninitialized data and ensuring all fields are set to known good values. Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14639 Fixes: 01fd30da0474 ("dma-buf: Add struct dma-buf-map for storing struct dma_buf.vaddr_ptr") Signed-off-by: Nitin Gote Reviewed-by: Andi Shyti Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://lore.kernel.org/r/20250718105051.2709487-1-nitin.r.gote@intel.com --- include/linux/iosys-map.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h index 4696abfd311cc1..3e85afe794c0aa 100644 --- a/include/linux/iosys-map.h +++ b/include/linux/iosys-map.h @@ -264,12 +264,7 @@ static inline bool iosys_map_is_set(const struct iosys_map *map) */ static inline void iosys_map_clear(struct iosys_map *map) { - if (map->is_iomem) { - map->vaddr_iomem = NULL; - map->is_iomem = false; - } else { - map->vaddr = NULL; - } + memset(map, 0, sizeof(*map)); } /** From f87d597e8393f7038de046ed7f13bb176a4ead55 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 8 Aug 2025 11:20:49 +0200 Subject: [PATCH 0068/1292] MAINTAINERS: entry for DRM GPUVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPUVM deserves a bit more coordination, also given the upcoming Rust work for GPUVM, hence add a dedicated maintainers entry for DRM GPUVM. Cc: Boris Brezillon Cc: Matthew Brost Cc: Thomas Hellstrƶm Cc: Alice Ryhl Acked-by: Thomas Hellstrƶm Acked-by: Matthew Brost Acked-by: Alice Ryhl Link: https://lore.kernel.org/r/20250808092432.461250-1-dakr@kernel.org Signed-off-by: Danilo Krummrich --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa457..20ffd334e0a78a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8426,6 +8426,17 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: drivers/gpu/drm/scheduler/ F: include/drm/gpu_scheduler.h +DRM GPUVM +M: Danilo Krummrich +R: Matthew Brost +R: Thomas Hellstrƶm +R: Alice Ryhl +L: dri-devel@lists.freedesktop.org +S: Supported +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: drivers/gpu/drm/drm_gpuvm.c +F: include/drm/drm_gpuvm.h + DRM LOG M: Jocelyn Falempe M: Javier Martinez Canillas From 4b0ad968717eb1862b74c1f549e4225bf95c286f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 11 Aug 2025 16:15:27 +0200 Subject: [PATCH 0069/1292] regulator: dt-bindings: infineon,ir38060: Add Guenter as maintainer from IBM The infineon,ir38060 binding never got maintainer and fake "Not Me" entry have been causing dt_binding_check warnings for 1.5 years now: regulator/infineon,ir38060.yaml: maintainers:0: 'Not Me.' does not match '@' Guenter agreed to keep an eye for this hardware and binding. Cc: Guenter Roeck Cc: Conor Dooley Cc: Andrew Jeffery Cc: Ninad Palsule Signed-off-by: Krzysztof Kozlowski Acked-by: Guenter Roeck Link: https://patch.msgid.link/20250811141526.168752-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/infineon,ir38060.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/regulator/infineon,ir38060.yaml b/Documentation/devicetree/bindings/regulator/infineon,ir38060.yaml index e6ffbc2a229884..57ff6bf1e18800 100644 --- a/Documentation/devicetree/bindings/regulator/infineon,ir38060.yaml +++ b/Documentation/devicetree/bindings/regulator/infineon,ir38060.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Infineon Buck Regulators with PMBUS interfaces maintainers: - - Not Me. + - Guenter Roeck allOf: - $ref: regulator.yaml# From ddf7233fcab6c247379d0928d46cc316ee122229 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Tue, 5 Aug 2025 10:59:11 +0200 Subject: [PATCH 0070/1292] sched/ext: Fix invalid task state transitions on class switch When enabling a sched_ext scheduler, we may trigger invalid task state transitions, resulting in warnings like the following (which can be easily reproduced by running the hotplug selftest in a loop): sched_ext: Invalid task state transition 0 -> 3 for fish[770] WARNING: CPU: 18 PID: 787 at kernel/sched/ext.c:3862 scx_set_task_state+0x7c/0xc0 ... RIP: 0010:scx_set_task_state+0x7c/0xc0 ... Call Trace: scx_enable_task+0x11f/0x2e0 switching_to_scx+0x24/0x110 scx_enable.isra.0+0xd14/0x13d0 bpf_struct_ops_link_create+0x136/0x1a0 __sys_bpf+0x1edd/0x2c30 __x64_sys_bpf+0x21/0x30 do_syscall_64+0xbb/0x370 entry_SYSCALL_64_after_hwframe+0x77/0x7f This happens because we skip initialization for tasks that are already dead (with their usage counter set to zero), but we don't exclude them during the scheduling class transition phase. Fix this by also skipping dead tasks during class swiching, preventing invalid task state transitions. Fixes: a8532fac7b5d2 ("sched_ext: TASK_DEAD tasks must be switched into SCX on ops_enable") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Andrea Righi Signed-off-by: Tejun Heo --- kernel/sched/ext.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 7dedc9a16281b3..4ae32ef179dd0f 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -5749,6 +5749,9 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link) __setscheduler_class(p->policy, p->prio); struct sched_enq_and_set_ctx ctx; + if (!tryget_task_struct(p)) + continue; + if (old_class != new_class && p->se.sched_delayed) dequeue_task(task_rq(p), p, DEQUEUE_SLEEP | DEQUEUE_DELAYED); @@ -5761,6 +5764,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link) sched_enq_and_set_task(&ctx); check_class_changed(task_rq(p), p, old_class, p->prio); + put_task_struct(p); } scx_task_iter_stop(&sti); percpu_up_write(&scx_fork_rwsem); From e69980bd16f264581c3f606bae987e54f0ba8c4a Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 25 Jul 2025 17:04:12 +0800 Subject: [PATCH 0071/1292] selftests/sched_ext: Remove duplicate sched.h header ./tools/testing/selftests/sched_ext/hotplug.c: sched.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=22941 Signed-off-by: Jiapeng Chong Acked-by: Andrea Righi Signed-off-by: Tejun Heo --- tools/testing/selftests/sched_ext/hotplug.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/testing/selftests/sched_ext/hotplug.c b/tools/testing/selftests/sched_ext/hotplug.c index 1c9ceb661c43ea..0cfbb111a2d09a 100644 --- a/tools/testing/selftests/sched_ext/hotplug.c +++ b/tools/testing/selftests/sched_ext/hotplug.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include From 4e5b705cc6147f0b9173c6219079f41416bdd3c0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 23 Jul 2025 10:29:12 -0500 Subject: [PATCH 0072/1292] iio: accel: sca3300: fix uninitialized iio scan data Fix potential leak of uninitialized stack data to userspace by ensuring that the `channels` array is zeroed before use. Fixes: edeb67fbbf4b ("iio: accel: sca3300: use IIO_DECLARE_BUFFER_WITH_TS") Signed-off-by: David Lechner Link: https://patch.msgid.link/20250723-iio-accel-sca3300-fix-uninitialized-iio-scan-data-v1-1-12dbfb3307b7@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/sca3300.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c index bda370c0f660b2..8380b237831cec 100644 --- a/drivers/iio/accel/sca3300.c +++ b/drivers/iio/accel/sca3300.c @@ -477,7 +477,7 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct sca3300_data *data = iio_priv(indio_dev); int bit, ret, val, i = 0; - IIO_DECLARE_BUFFER_WITH_TS(s16, channels, SCA3300_SCAN_MAX); + IIO_DECLARE_BUFFER_WITH_TS(s16, channels, SCA3300_SCAN_MAX) = { }; iio_for_each_active_channel(indio_dev, bit) { ret = sca3300_read_reg(data, indio_dev->channels[bit].address, &val); From de18e978d0cda23e4c102e18092b63a5b0b3a800 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 22 Jul 2025 15:54:21 -0500 Subject: [PATCH 0073/1292] iio: proximity: isl29501: fix buffered read on big-endian systems Fix passing a u32 value as a u16 buffer scan item. This works on little- endian systems, but not on big-endian systems. A new local variable is introduced for getting the register value and the array is changed to a struct to make the data layout more explicit rather than just changing the type and having to recalculate the proper length needed for the timestamp. Fixes: 1c28799257bc ("iio: light: isl29501: Add support for the ISL29501 ToF sensor.") Signed-off-by: David Lechner Link: https://patch.msgid.link/20250722-iio-use-more-iio_declare_buffer_with_ts-7-v2-1-d3ebeb001ed3@baylibre.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/isl29501.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index d1510fe2405088..f69db6f2f38031 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -938,12 +938,18 @@ static irqreturn_t isl29501_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct isl29501_private *isl29501 = iio_priv(indio_dev); const unsigned long *active_mask = indio_dev->active_scan_mask; - u32 buffer[4] __aligned(8) = {}; /* 1x16-bit + naturally aligned ts */ - - if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask)) - isl29501_register_read(isl29501, REG_DISTANCE, buffer); + u32 value; + struct { + u16 data; + aligned_s64 ts; + } scan = { }; + + if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask)) { + isl29501_register_read(isl29501, REG_DISTANCE, &value); + scan.data = value; + } - iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); + iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; From 1cfb22c277c7274f54babaa5b416dfbc00181e16 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 22 Jul 2025 14:20:07 -0500 Subject: [PATCH 0074/1292] iio: adc: ad7173: prevent scan if too many setups requested Add a check to ad7173_update_scan_mode() to ensure that we didn't exceed the maximum number of unique channel configurations. In the AD7173 family of chips, there are some chips that have 16 CHANNELx registers but only 8 setups (combination of CONFIGx, FILTERx, GAINx and OFFSETx registers). Since commit 92c247216918 ("iio: adc: ad7173: fix num_slots"), it is possible to have more than 8 channels enabled in a scan at the same time, so it is possible to get a bad configuration when more than 8 channels are using unique configurations. This happens because the algorithm to allocate the setup slots only takes into account which slot has been least recently used and doesn't know about the maximum number of slots available. Since the algorithm to allocate the setup slots is quite complex, it is simpler to check after the fact if the current state is valid or not. So this patch adds a check in ad7173_update_scan_mode() after setting up all of the configurations to make sure that the actual setup still matches the requested setup for each enabled channel. If not, we prevent the scan from being enabled and return an error. The setup comparison in ad7173_setup_equal() is refactored to a separate function since we need to call it in two places now. Fixes: 92c247216918 ("iio: adc: ad7173: fix num_slots") Signed-off-by: David Lechner Link: https://patch.msgid.link/20250722-iio-adc-ad7173-fix-setup-use-limits-v2-1-8e96bdb72a9c@baylibre.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 87 ++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 4413207be28f60..683146e83ab2d3 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -200,7 +200,7 @@ struct ad7173_channel_config { /* * Following fields are used to compare equality. If you * make adaptations in it, you most likely also have to adapt - * ad7173_find_live_config(), too. + * ad7173_is_setup_equal(), too. */ struct_group(config_props, bool bipolar; @@ -561,12 +561,19 @@ static void ad7173_reset_usage_cnts(struct ad7173_state *st) st->config_usage_counter = 0; } -static struct ad7173_channel_config * -ad7173_find_live_config(struct ad7173_state *st, struct ad7173_channel_config *cfg) +/** + * ad7173_is_setup_equal - Compare two channel setups + * @cfg1: First channel configuration + * @cfg2: Second channel configuration + * + * Compares all configuration options that affect the registers connected to + * SETUP_SEL, namely CONFIGx, FILTERx, GAINx and OFFSETx. + * + * Returns: true if the setups are identical, false otherwise + */ +static bool ad7173_is_setup_equal(const struct ad7173_channel_config *cfg1, + const struct ad7173_channel_config *cfg2) { - struct ad7173_channel_config *cfg_aux; - int i; - /* * This is just to make sure that the comparison is adapted after * struct ad7173_channel_config was changed. @@ -579,14 +586,22 @@ ad7173_find_live_config(struct ad7173_state *st, struct ad7173_channel_config *c u8 ref_sel; })); + return cfg1->bipolar == cfg2->bipolar && + cfg1->input_buf == cfg2->input_buf && + cfg1->odr == cfg2->odr && + cfg1->ref_sel == cfg2->ref_sel; +} + +static struct ad7173_channel_config * +ad7173_find_live_config(struct ad7173_state *st, struct ad7173_channel_config *cfg) +{ + struct ad7173_channel_config *cfg_aux; + int i; + for (i = 0; i < st->num_channels; i++) { cfg_aux = &st->channels[i].cfg; - if (cfg_aux->live && - cfg->bipolar == cfg_aux->bipolar && - cfg->input_buf == cfg_aux->input_buf && - cfg->odr == cfg_aux->odr && - cfg->ref_sel == cfg_aux->ref_sel) + if (cfg_aux->live && ad7173_is_setup_equal(cfg, cfg_aux)) return cfg_aux; } return NULL; @@ -1228,7 +1243,7 @@ static int ad7173_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct ad7173_state *st = iio_priv(indio_dev); - int i, ret; + int i, j, k, ret; for (i = 0; i < indio_dev->num_channels; i++) { if (test_bit(i, scan_mask)) @@ -1239,6 +1254,54 @@ static int ad7173_update_scan_mode(struct iio_dev *indio_dev, return ret; } + /* + * On some chips, there are more channels that setups, so if there were + * more unique setups requested than the number of available slots, + * ad7173_set_channel() will have written over some of the slots. We + * can detect this by making sure each assigned cfg_slot matches the + * requested configuration. If it doesn't, we know that the slot was + * overwritten by a different channel. + */ + for_each_set_bit(i, scan_mask, indio_dev->num_channels) { + const struct ad7173_channel_config *cfg1, *cfg2; + + cfg1 = &st->channels[i].cfg; + + for_each_set_bit(j, scan_mask, indio_dev->num_channels) { + cfg2 = &st->channels[j].cfg; + + /* + * Only compare configs that are assigned to the same + * SETUP_SEL slot and don't compare channel to itself. + */ + if (i == j || cfg1->cfg_slot != cfg2->cfg_slot) + continue; + + /* + * If we find two different configs trying to use the + * same SETUP_SEL slot, then we know that the that we + * have too many unique configurations requested for + * the available slots and at least one was overwritten. + */ + if (!ad7173_is_setup_equal(cfg1, cfg2)) { + /* + * At this point, there isn't a way to tell + * which setups are actually programmed in the + * ADC anymore, so we could read them back to + * see, but it is simpler to just turn off all + * of the live flags so that everything gets + * reprogramed on the next attempt read a sample. + */ + for (k = 0; k < st->num_channels; k++) + st->channels[k].cfg.live = false; + + dev_err(&st->sd.spi->dev, + "Too many unique channel configurations requested for scan\n"); + return -EINVAL; + } + } + } + return 0; } From ae5bc07ec9f73a41734270ef3f800c5c8a7e0ad3 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 21 Jul 2025 18:04:04 -0500 Subject: [PATCH 0075/1292] iio: temperature: maxim_thermocouple: use DMA-safe buffer for spi_read() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace using stack-allocated buffers with a DMA-safe buffer for use with spi_read(). This allows the driver to be safely used with DMA-enabled SPI controllers. The buffer array is also converted to a struct with a union to make the usage of the memory in the buffer more clear and ensure proper alignment. Fixes: 1f25ca11d84a ("iio: temperature: add support for Maxim thermocouple chips") Signed-off-by: David Lechner Reviewed-by: Nuno SĆ” Link: https://patch.msgid.link/20250721-iio-use-more-iio_declare_buffer_with_ts-3-v2-1-0c68d41ccf6c@baylibre.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/maxim_thermocouple.c | 26 ++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index cae8e84821d7fd..205939680fd4fc 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -121,8 +122,15 @@ struct maxim_thermocouple_data { struct spi_device *spi; const struct maxim_thermocouple_chip *chip; char tc_type; - - u8 buffer[16] __aligned(IIO_DMA_MINALIGN); + /* Buffer for reading up to 2 hardware channels. */ + struct { + union { + __be16 raw16; + __be32 raw32; + __be16 raw[2]; + }; + aligned_s64 timestamp; + } buffer __aligned(IIO_DMA_MINALIGN); }; static int maxim_thermocouple_read(struct maxim_thermocouple_data *data, @@ -130,18 +138,16 @@ static int maxim_thermocouple_read(struct maxim_thermocouple_data *data, { unsigned int storage_bytes = data->chip->read_size; unsigned int shift = chan->scan_type.shift + (chan->address * 8); - __be16 buf16; - __be32 buf32; int ret; switch (storage_bytes) { case 2: - ret = spi_read(data->spi, (void *)&buf16, storage_bytes); - *val = be16_to_cpu(buf16); + ret = spi_read(data->spi, &data->buffer.raw16, storage_bytes); + *val = be16_to_cpu(data->buffer.raw16); break; case 4: - ret = spi_read(data->spi, (void *)&buf32, storage_bytes); - *val = be32_to_cpu(buf32); + ret = spi_read(data->spi, &data->buffer.raw32, storage_bytes); + *val = be32_to_cpu(data->buffer.raw32); break; default: ret = -EINVAL; @@ -166,9 +172,9 @@ static irqreturn_t maxim_thermocouple_trigger_handler(int irq, void *private) struct maxim_thermocouple_data *data = iio_priv(indio_dev); int ret; - ret = spi_read(data->spi, data->buffer, data->chip->read_size); + ret = spi_read(data->spi, data->buffer.raw, data->chip->read_size); if (!ret) { - iio_push_to_buffers_with_ts(indio_dev, data->buffer, + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, sizeof(data->buffer), iio_get_time_ns(indio_dev)); } From 197e299aae42ffa19028eaea92b2f30dd9fb8445 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 26 Jul 2025 11:28:48 -0500 Subject: [PATCH 0076/1292] iio: adc: ad7124: fix channel lookup in syscalib functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix possible incorrect channel lookup in the syscalib functions by using the correct channel address instead of the channel number. In the ad7124 driver, the channel field of struct iio_chan_spec is the input pin number of the positive input of the channel. This can be, but is not always the same as the index in the channels array. The correct index in the channels array is stored in the address field (and also scan_index). We use the address field to perform the correct lookup. Fixes: 47036a03a303 ("iio: adc: ad7124: Implement internal calibration at probe time") Signed-off-by: David Lechner Reviewed-by: Nuno SĆ” Link: https://patch.msgid.link/20250726-iio-adc-ad7124-fix-channel-lookup-in-syscalib-v1-1-b9d14bb684af@baylibre.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 9808df2e924242..4d8c6bafd1c317 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -849,7 +849,7 @@ enum { static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan_spec *chan) { struct device *dev = &st->sd.spi->dev; - struct ad7124_channel *ch = &st->channels[chan->channel]; + struct ad7124_channel *ch = &st->channels[chan->address]; int ret; if (ch->syscalib_mode == AD7124_SYSCALIB_ZERO_SCALE) { @@ -865,8 +865,8 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan if (ret < 0) return ret; - dev_dbg(dev, "offset for channel %d after zero-scale calibration: 0x%x\n", - chan->channel, ch->cfg.calibration_offset); + dev_dbg(dev, "offset for channel %lu after zero-scale calibration: 0x%x\n", + chan->address, ch->cfg.calibration_offset); } else { ch->cfg.calibration_gain = st->gain_default; @@ -880,8 +880,8 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan if (ret < 0) return ret; - dev_dbg(dev, "gain for channel %d after full-scale calibration: 0x%x\n", - chan->channel, ch->cfg.calibration_gain); + dev_dbg(dev, "gain for channel %lu after full-scale calibration: 0x%x\n", + chan->address, ch->cfg.calibration_gain); } return 0; @@ -924,7 +924,7 @@ static int ad7124_set_syscalib_mode(struct iio_dev *indio_dev, { struct ad7124_state *st = iio_priv(indio_dev); - st->channels[chan->channel].syscalib_mode = mode; + st->channels[chan->address].syscalib_mode = mode; return 0; } @@ -934,7 +934,7 @@ static int ad7124_get_syscalib_mode(struct iio_dev *indio_dev, { struct ad7124_state *st = iio_priv(indio_dev); - return st->channels[chan->channel].syscalib_mode; + return st->channels[chan->address].syscalib_mode; } static const struct iio_enum ad7124_syscalib_mode_enum = { From dfdc31e7ccf3ac1d5ec01d5120c71e14745e3dd8 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Fri, 8 Aug 2025 09:40:10 +0200 Subject: [PATCH 0077/1292] iio: imu: inv_icm42600: change invalid data error to -EBUSY Temperature sensor returns the temperature of the mechanical parts of the chip. If both accel and gyro are off, the temperature sensor is also automatically turned off and returns invalid data. In this case, returning -EBUSY error code is better then -EINVAL and indicates userspace that it needs to retry reading temperature in another context. Fixes: bc3eb0207fb5 ("iio: imu: inv_icm42600: add temperature sensor support") Signed-off-by: Jean-Baptiste Maneyrol Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Reviewed-by: Sean Nyekjaer Link: https://patch.msgid.link/20250808-inv-icm42600-change-temperature-error-code-v1-1-986fbf63b77d@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c index 8b15afca498cb5..271a4788604ad5 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -32,8 +32,12 @@ static int inv_icm42600_temp_read(struct inv_icm42600_state *st, s16 *temp) goto exit; *temp = (s16)be16_to_cpup(raw); + /* + * Temperature data is invalid if both accel and gyro are off. + * Return -EBUSY in this case. + */ if (*temp == INV_ICM42600_DATA_INVALID) - ret = -EINVAL; + ret = -EBUSY; exit: mutex_unlock(&st->lock); From fde578c86281f27b182680c7642836a0dbbd0be7 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 31 Jul 2025 17:48:06 +0200 Subject: [PATCH 0078/1292] rust: alloc: replace aligned_size() with Kmalloc::aligned_layout() aligned_size() dates back to when Rust did support kmalloc() only, but is now used in ReallocFunc::call() and hence for all allocators. However, the additional padding applied by aligned_size() is only required by the kmalloc() allocator backend. Hence, replace aligned_size() with Kmalloc::aligned_layout() and use it for the affected allocators, i.e. kmalloc() and kvmalloc(), only. While at it, make Kmalloc::aligned_layout() public, such that Rust abstractions, which have to call subsystem specific kmalloc() based allocation primitives directly, can make use of it. Fixes: 8a799831fc63 ("rust: alloc: implement `ReallocFunc`") Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250731154919.4132-2-dakr@kernel.org [ Remove `const` from Kmalloc::aligned_layout(). - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/allocator.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index aa2dfa9dca4c30..2692cf90c9482d 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -43,17 +43,6 @@ pub struct Vmalloc; /// For more details see [self]. pub struct KVmalloc; -/// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. -fn aligned_size(new_layout: Layout) -> usize { - // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. - let layout = new_layout.pad_to_align(); - - // Note that `layout.size()` (after padding) is guaranteed to be a multiple of `layout.align()` - // which together with the slab guarantees means the `krealloc` will return a properly aligned - // object (see comments in `kmalloc()` for more information). - layout.size() -} - /// # Invariants /// /// One of the following: `krealloc`, `vrealloc`, `kvrealloc`. @@ -88,7 +77,7 @@ impl ReallocFunc { old_layout: Layout, flags: Flags, ) -> Result, AllocError> { - let size = aligned_size(layout); + let size = layout.size(); let ptr = match ptr { Some(ptr) => { if old_layout.size() == 0 { @@ -123,6 +112,17 @@ impl ReallocFunc { } } +impl Kmalloc { + /// Returns a [`Layout`] that makes [`Kmalloc`] fulfill the requested size and alignment of + /// `layout`. + pub fn aligned_layout(layout: Layout) -> Layout { + // Note that `layout.size()` (after padding) is guaranteed to be a multiple of + // `layout.align()` which together with the slab guarantees means that `Kmalloc` will return + // a properly aligned object (see comments in `kmalloc()` for more information). + layout.pad_to_align() + } +} + // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that // - memory remains valid until it is explicitly freed, // - passing a pointer to a valid memory allocation is OK, @@ -135,6 +135,8 @@ unsafe impl Allocator for Kmalloc { old_layout: Layout, flags: Flags, ) -> Result, AllocError> { + let layout = Kmalloc::aligned_layout(layout); + // SAFETY: `ReallocFunc::call` has the same safety requirements as `Allocator::realloc`. unsafe { ReallocFunc::KREALLOC.call(ptr, layout, old_layout, flags) } } @@ -176,6 +178,10 @@ unsafe impl Allocator for KVmalloc { old_layout: Layout, flags: Flags, ) -> Result, AllocError> { + // `KVmalloc` may use the `Kmalloc` backend, hence we have to enforce a `Kmalloc` + // compatible layout. + let layout = Kmalloc::aligned_layout(layout); + // TODO: Support alignments larger than PAGE_SIZE. if layout.align() > bindings::PAGE_SIZE { pr_warn!("KVmalloc does not support alignments larger than PAGE_SIZE yet.\n"); From 22ab0641b939967f630d108e33a3582841ad6846 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 31 Jul 2025 17:48:07 +0200 Subject: [PATCH 0079/1292] rust: drm: ensure kmalloc() compatible Layout drm::Device is allocated through __drm_dev_alloc() (which uses kmalloc()) and the driver private data, ::Data, is initialized in-place. Due to the order of fields in drm::Device pub struct Device { dev: Opaque, data: T::Data, } even with an arbitrary large alignment requirement of T::Data it can't happen that the size of Device is smaller than its alignment requirement. However, let's not rely on this subtle circumstance and create a proper kmalloc() compatible Layout. Fixes: 1e4b8896c0f3 ("rust: drm: add device abstraction") Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250731154919.4132-3-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/drm/device.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index 3bb7c83966cf2d..d19410deaf6c82 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -5,6 +5,7 @@ //! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h) use crate::{ + alloc::allocator::Kmalloc, bindings, device, drm, drm::driver::AllocImpl, error::from_err_ptr, @@ -12,7 +13,7 @@ use crate::{ prelude::*, types::{ARef, AlwaysRefCounted, Opaque}, }; -use core::{mem, ops::Deref, ptr, ptr::NonNull}; +use core::{alloc::Layout, mem, ops::Deref, ptr, ptr::NonNull}; #[cfg(CONFIG_DRM_LEGACY)] macro_rules! drm_legacy_fields { @@ -96,6 +97,10 @@ impl Device { /// Create a new `drm::Device` for a `drm::Driver`. pub fn new(dev: &device::Device, data: impl PinInit) -> Result> { + // `__drm_dev_alloc` uses `kmalloc()` to allocate memory, hence ensure a `kmalloc()` + // compatible `Layout`. + let layout = Kmalloc::aligned_layout(Layout::new::()); + // SAFETY: // - `VTABLE`, as a `const` is pinned to the read-only section of the compilation, // - `dev` is valid by its type invarants, @@ -103,7 +108,7 @@ impl Device { bindings::__drm_dev_alloc( dev.as_raw(), &Self::VTABLE, - mem::size_of::(), + layout.size(), mem::offset_of!(Self, dev), ) } From 0c04a81c1d0214d5b2025f805ccec1ac37c96b08 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 31 Jul 2025 17:48:08 +0200 Subject: [PATCH 0080/1292] rust: drm: remove pin annotations from drm::Device The #[pin_data] and #[pin] annotations are not necessary for drm::Device, since we don't use any pin-init macros, but only __pinned_init() on the impl PinInit argument of drm::Device::new(). Fixes: 1e4b8896c0f3 ("rust: drm: add device abstraction") Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250731154919.4132-4-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/drm/device.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index d19410deaf6c82..d0a9528121f15c 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -54,10 +54,8 @@ macro_rules! drm_legacy_fields { /// /// `self.dev` is a valid instance of a `struct device`. #[repr(C)] -#[pin_data] pub struct Device { dev: Opaque, - #[pin] data: T::Data, } From 360077278ba62e81310080f075a1a3028e778ef9 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 31 Jul 2025 17:48:09 +0200 Subject: [PATCH 0081/1292] rust: drm: don't pass the address of drm::Device to drm_dev_put() In drm_dev_put() call in AlwaysRefCounted::dec_ref() we rely on struct drm_device to be the first field in drm::Device, whereas everywhere else we correctly obtain the address of the actual struct drm_device. Analogous to the from_drm_device() helper, provide the into_drm_device() helper in order to address this. Fixes: 1e4b8896c0f3 ("rust: drm: add device abstraction") Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250731154919.4132-5-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/drm/device.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index d0a9528121f15c..d29c477e89a87d 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -120,9 +120,13 @@ impl Device { // - `raw_data` is a valid pointer to uninitialized memory. // - `raw_data` will not move until it is dropped. unsafe { data.__pinned_init(raw_data) }.inspect_err(|_| { - // SAFETY: `__drm_dev_alloc()` was successful, hence `raw_drm` must be valid and the + // SAFETY: `raw_drm` is a valid pointer to `Self`, given that `__drm_dev_alloc` was + // successful. + let drm_dev = unsafe { Self::into_drm_device(raw_drm) }; + + // SAFETY: `__drm_dev_alloc()` was successful, hence `drm_dev` must be valid and the // refcount must be non-zero. - unsafe { bindings::drm_dev_put(ptr::addr_of_mut!((*raw_drm.as_ptr()).dev).cast()) }; + unsafe { bindings::drm_dev_put(drm_dev) }; })?; // SAFETY: The reference count is one, and now we take ownership of that reference as a @@ -143,6 +147,14 @@ impl Device { unsafe { crate::container_of!(Opaque::cast_from(ptr), Self, dev) }.cast_mut() } + /// # Safety + /// + /// `ptr` must be a valid pointer to `Self`. + unsafe fn into_drm_device(ptr: NonNull) -> *mut bindings::drm_device { + // SAFETY: By the safety requirements of this function, `ptr` is a valid pointer to `Self`. + unsafe { &raw mut (*ptr.as_ptr()).dev }.cast() + } + /// Not intended to be called externally, except via declare_drm_ioctls!() /// /// # Safety @@ -192,8 +204,11 @@ unsafe impl AlwaysRefCounted for Device { } unsafe fn dec_ref(obj: NonNull) { + // SAFETY: `obj` is a valid pointer to `Self`. + let drm_dev = unsafe { Self::into_drm_device(obj) }; + // SAFETY: The safety requirements guarantee that the refcount is non-zero. - unsafe { bindings::drm_dev_put(obj.cast().as_ptr()) }; + unsafe { bindings::drm_dev_put(drm_dev) }; } } From 57e85e21b2729849407c9f851e30b2ff0f07523b Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Mon, 11 Aug 2025 14:51:01 -0700 Subject: [PATCH 0082/1292] MAINTAINERS: Add myself as virtual-cpufreq maintainer Forgot to update the MAINTAINERS file in the initial patch that landed the driver. Add myself as the maintainer for this driver. Signed-off-by: Saravana Kannan Signed-off-by: Viresh Kumar --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa457..6fac119a8e954c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6350,6 +6350,12 @@ F: kernel/sched/cpufreq*.c F: rust/kernel/cpufreq.rs F: tools/testing/selftests/cpufreq/ +CPU FREQUENCY DRIVERS - VIRTUAL MACHINE CPUFREQ +M: Saravana Kannan +L: linux-pm@vger.kernel.org +S: Maintained +F: drivers/cpufreq/virtual-cpufreq.c + CPU HOTPLUG M: Thomas Gleixner M: Peter Zijlstra From e98329896b5639f8437af8ff9316f20cb50d9187 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 2 Jul 2025 14:43:09 +0530 Subject: [PATCH 0083/1292] dt-bindings: cpufreq: cpufreq-qcom-hw: Add QCS615 compatible Document compatible for cpufreq hardware on Qualcomm QCS615 platform. Signed-off-by: Taniya Das Acked-by: Krzysztof Kozlowski Signed-off-by: Viresh Kumar --- Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml index e0242bed33420a..2d42fc3d8ef811 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml @@ -22,6 +22,7 @@ properties: items: - enum: - qcom,qcm2290-cpufreq-hw + - qcom,qcs615-cpufreq-hw - qcom,sc7180-cpufreq-hw - qcom,sc8180x-cpufreq-hw - qcom,sdm670-cpufreq-hw @@ -132,6 +133,7 @@ allOf: compatible: contains: enum: + - qcom,qcs615-cpufreq-hw - qcom,qdu1000-cpufreq-epss - qcom,sa8255p-cpufreq-epss - qcom,sa8775p-cpufreq-epss From 9af8f2b469c0438620832f3729a3c5c03853b56b Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Fri, 27 Jun 2025 14:38:19 +0200 Subject: [PATCH 0084/1292] drm/panic: Add a u64 divide by 10 for arm32 On 32bits ARM, u64 divided by a constant is not optimized to a multiply by inverse by the compiler [1]. So do the multiply by inverse explicitly for this architecture. Link: https://github.com/llvm/llvm-project/issues/37280 [1] Reported-by: Andrei Lalaev Closes: https://lore.kernel.org/dri-devel/c0a2771c-f3f5-4d4c-aa82-d673b3c5cb46@gmail.com/ Fixes: 675008f196ca ("drm/panic: Use a decimal fifo to avoid u64 by u64 divide") Reviewed-by: Alice Ryhl Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_panic_qr.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index 09a9b452e8b728..50c286c5cee8be 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -381,6 +381,26 @@ struct DecFifo { len: usize, } +// On arm32 architecture, dividing an `u64` by a constant will generate a call +// to `__aeabi_uldivmod` which is not present in the kernel. +// So use the multiply by inverse method for this architecture. +fn div10(val: u64) -> u64 { + if cfg!(target_arch = "arm") { + let val_h = val >> 32; + let val_l = val & 0xFFFFFFFF; + let b_h: u64 = 0x66666666; + let b_l: u64 = 0x66666667; + + let tmp1 = val_h * b_l + ((val_l * b_l) >> 32); + let tmp2 = val_l * b_h + (tmp1 & 0xffffffff); + let tmp3 = val_h * b_h + (tmp1 >> 32) + (tmp2 >> 32); + + tmp3 >> 2 + } else { + val / 10 + } +} + impl DecFifo { fn push(&mut self, data: u64, len: usize) { let mut chunk = data; @@ -389,7 +409,7 @@ impl DecFifo { } for i in 0..len { self.decimals[i] = (chunk % 10) as u8; - chunk /= 10; + chunk = div10(chunk); } self.len += len; } From d26a9f4f0a7745f0d5127344379a62007df68dcd Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 22 Jul 2025 20:38:41 +0200 Subject: [PATCH 0085/1292] platform/x86: dell-smbios-wmi: Stop touching WMI device ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Dell SMBIOS driver uses the "id" field inside struct device for prioritizing the WMI backend over the SMM backend. Because of this the WMI backend modifies the "id" field of the underlying WMI device. However the WMI core itself uses wdev->dev.id internally to track device IDs, so modifying this value will result in a resource leak. Fix this by not using the "id" field inside struct device for SMBIOS prioritization. Instead extend struct smbios_device with a separate "priority" field. Tested on a Dell Inspiron 3505. Fixes: 73f0f2b52c5e ("platform/x86: wmi: Fix WMI device naming issue") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20250722183841.9552-1-W_Armin@gmx.de Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/dell/dell-smbios-base.c | 19 +++++++++---------- drivers/platform/x86/dell/dell-smbios-smm.c | 3 +-- drivers/platform/x86/dell/dell-smbios-wmi.c | 4 +--- drivers/platform/x86/dell/dell-smbios.h | 2 +- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c index 01c72b91a50d44..444786102f020b 100644 --- a/drivers/platform/x86/dell/dell-smbios-base.c +++ b/drivers/platform/x86/dell/dell-smbios-base.c @@ -39,6 +39,7 @@ struct token_sysfs_data { struct smbios_device { struct list_head list; struct device *device; + int priority; int (*call_fn)(struct calling_interface_buffer *arg); }; @@ -145,7 +146,7 @@ int dell_smbios_error(int value) } EXPORT_SYMBOL_GPL(dell_smbios_error); -int dell_smbios_register_device(struct device *d, void *call_fn) +int dell_smbios_register_device(struct device *d, int priority, void *call_fn) { struct smbios_device *priv; @@ -154,6 +155,7 @@ int dell_smbios_register_device(struct device *d, void *call_fn) return -ENOMEM; get_device(d); priv->device = d; + priv->priority = priority; priv->call_fn = call_fn; mutex_lock(&smbios_mutex); list_add_tail(&priv->list, &smbios_device_list); @@ -292,28 +294,25 @@ EXPORT_SYMBOL_GPL(dell_smbios_call_filter); int dell_smbios_call(struct calling_interface_buffer *buffer) { - int (*call_fn)(struct calling_interface_buffer *) = NULL; - struct device *selected_dev = NULL; + struct smbios_device *selected = NULL; struct smbios_device *priv; int ret; mutex_lock(&smbios_mutex); list_for_each_entry(priv, &smbios_device_list, list) { - if (!selected_dev || priv->device->id >= selected_dev->id) { - dev_dbg(priv->device, "Trying device ID: %d\n", - priv->device->id); - call_fn = priv->call_fn; - selected_dev = priv->device; + if (!selected || priv->priority >= selected->priority) { + dev_dbg(priv->device, "Trying device ID: %d\n", priv->priority); + selected = priv; } } - if (!selected_dev) { + if (!selected) { ret = -ENODEV; pr_err("No dell-smbios drivers are loaded\n"); goto out_smbios_call; } - ret = call_fn(buffer); + ret = selected->call_fn(buffer); out_smbios_call: mutex_unlock(&smbios_mutex); diff --git a/drivers/platform/x86/dell/dell-smbios-smm.c b/drivers/platform/x86/dell/dell-smbios-smm.c index 4d375985c85f82..7055e2c40f3494 100644 --- a/drivers/platform/x86/dell/dell-smbios-smm.c +++ b/drivers/platform/x86/dell/dell-smbios-smm.c @@ -125,8 +125,7 @@ int init_dell_smbios_smm(void) if (ret) goto fail_platform_device_add; - ret = dell_smbios_register_device(&platform_device->dev, - &dell_smbios_smm_call); + ret = dell_smbios_register_device(&platform_device->dev, 0, &dell_smbios_smm_call); if (ret) goto fail_register; diff --git a/drivers/platform/x86/dell/dell-smbios-wmi.c b/drivers/platform/x86/dell/dell-smbios-wmi.c index ae9012549560c4..a7dca8c59d6027 100644 --- a/drivers/platform/x86/dell/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell/dell-smbios-wmi.c @@ -264,9 +264,7 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context) if (ret) return ret; - /* ID is used by dell-smbios to set priority of drivers */ - wdev->dev.id = 1; - ret = dell_smbios_register_device(&wdev->dev, &dell_smbios_wmi_call); + ret = dell_smbios_register_device(&wdev->dev, 1, &dell_smbios_wmi_call); if (ret) return ret; diff --git a/drivers/platform/x86/dell/dell-smbios.h b/drivers/platform/x86/dell/dell-smbios.h index 77baa15eb52365..f421b8533a9e1a 100644 --- a/drivers/platform/x86/dell/dell-smbios.h +++ b/drivers/platform/x86/dell/dell-smbios.h @@ -64,7 +64,7 @@ struct calling_interface_structure { struct calling_interface_token tokens[]; } __packed; -int dell_smbios_register_device(struct device *d, void *call_fn); +int dell_smbios_register_device(struct device *d, int priority, void *call_fn); void dell_smbios_unregister_device(struct device *d); int dell_smbios_error(int value); From 5b9e07551faa7bb2f26cb039cc6e8d00bc4d0831 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 24 Jul 2025 13:51:08 -0500 Subject: [PATCH 0086/1292] platform/x86/amd: pmc: Drop SMU F/W match for Cezanne MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chris reported that even on a BIOS that has a new enough SMU F/W version there is still a spurious IRQ1. Although the solution was added to SMU F/W 64.66.0 it turns out there needs to be a matching SBIOS change to activate it. Thus Linux shouldn't be avoiding the IRQ1 workaround on newer SMU F/W because there is no indication the BIOS change is in place. Drop the match for 64.66.0+ and instead match all RN/CZN/BRC (they all share same SMU F/W). Adjust the quirk infrastructure to allow quirking the workaround on or off and also adjust existing quirks to match properly. Unfortunately this may cause some systems that did have the SBIOS change in place to regress in keyboard wakeup but we don't have a way to know. If a user reports a keyboard wakeup regression they can run with amd_pmc.disable_workarounds=1 to deactivate the workaround and share DMI data so that their system can be quirked not to use the workaround in the upstream kernel. Reported-by: Chris Bainbridge Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4449 Tested-by: Chris Bainbridge Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20250724185156.1827592-1-superm1@kernel.org Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/amd/pmc/pmc-quirks.c | 54 ++++++++++++++--------- drivers/platform/x86/amd/pmc/pmc.c | 13 ------ 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/drivers/platform/x86/amd/pmc/pmc-quirks.c b/drivers/platform/x86/amd/pmc/pmc-quirks.c index ded4c84f5ed149..7ffc659b279441 100644 --- a/drivers/platform/x86/amd/pmc/pmc-quirks.c +++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c @@ -28,10 +28,15 @@ static struct quirk_entry quirk_spurious_8042 = { .spurious_8042 = true, }; +static struct quirk_entry quirk_s2idle_spurious_8042 = { + .s2idle_bug_mmio = FCH_PM_BASE + FCH_PM_SCRATCH, + .spurious_8042 = true, +}; + static const struct dmi_system_id fwbug_list[] = { { .ident = "L14 Gen2 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20X5"), @@ -39,7 +44,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "T14s Gen2 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20XF"), @@ -47,7 +52,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "X13 Gen2 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20XH"), @@ -55,7 +60,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "T14 Gen2 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20XK"), @@ -63,7 +68,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "T14 Gen1 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20UD"), @@ -71,7 +76,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "T14 Gen1 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20UE"), @@ -79,7 +84,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "T14s Gen1 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20UH"), @@ -87,7 +92,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "T14s Gen1 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20UJ"), @@ -95,7 +100,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "P14s Gen1 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "20Y1"), @@ -103,7 +108,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "P14s Gen2 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21A0"), @@ -111,7 +116,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "P14s Gen2 AMD", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21A1"), @@ -152,7 +157,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "IdeaPad 1 14AMN7", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82VF"), @@ -160,7 +165,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "IdeaPad 1 15AMN7", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82VG"), @@ -168,7 +173,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "IdeaPad 1 15AMN7", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82X5"), @@ -176,7 +181,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "IdeaPad Slim 3 14AMN8", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82XN"), @@ -184,7 +189,7 @@ static const struct dmi_system_id fwbug_list[] = { }, { .ident = "IdeaPad Slim 3 15AMN8", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82XQ"), @@ -193,7 +198,7 @@ static const struct dmi_system_id fwbug_list[] = { /* https://gitlab.freedesktop.org/drm/amd/-/issues/4434 */ { .ident = "Lenovo Yoga 6 13ALC6", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82ND"), @@ -202,7 +207,7 @@ static const struct dmi_system_id fwbug_list[] = { /* https://gitlab.freedesktop.org/drm/amd/-/issues/2684 */ { .ident = "HP Laptop 15s-eq2xxx", - .driver_data = &quirk_s2idle_bug, + .driver_data = &quirk_s2idle_spurious_8042, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15s-eq2xxx"), @@ -285,6 +290,16 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev) { const struct dmi_system_id *dmi_id; + /* + * IRQ1 may cause an interrupt during resume even without a keyboard + * press. + * + * Affects Renoir, Cezanne and Barcelo SoCs + * + * A solution is available in PMFW 64.66.0, but it must be activated by + * SBIOS. If SBIOS is known to have the fix a quirk can be added for + * a given system to avoid workaround. + */ if (dev->cpu_id == AMD_CPU_ID_CZN) dev->disable_8042_wakeup = true; @@ -295,6 +310,5 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev) if (dev->quirks->s2idle_bug_mmio) pr_info("Using s2idle quirk to avoid %s platform firmware bug\n", dmi_id->ident); - if (dev->quirks->spurious_8042) - dev->disable_8042_wakeup = true; + dev->disable_8042_wakeup = dev->quirks->spurious_8042; } diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index 0b9b23eb7c2c30..bd318fd02ccf4a 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -530,19 +530,6 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) static int amd_pmc_wa_irq1(struct amd_pmc_dev *pdev) { struct device *d; - int rc; - - /* cezanne platform firmware has a fix in 64.66.0 */ - if (pdev->cpu_id == AMD_CPU_ID_CZN) { - if (!pdev->major) { - rc = amd_pmc_get_smu_version(pdev); - if (rc) - return rc; - } - - if (pdev->major > 64 || (pdev->major == 64 && pdev->minor > 65)) - return 0; - } d = bus_find_device_by_name(&serio_bus, NULL, "serio0"); if (!d) From dff6f36878799a5ffabd15336ce993dc737374dc Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Sun, 27 Jul 2025 14:05:13 -0700 Subject: [PATCH 0087/1292] platform/x86/intel-uncore-freq: Check write blocked for ELC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the missing write_blocked check for updating sysfs related to uncore efficiency latency control (ELC). If write operation is blocked return error. Fixes: bb516dc79c4a ("platform/x86/intel-uncore-freq: Add support for efficiency latency control") Signed-off-by: Srinivas Pandruvada Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250727210513.2898630-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- .../x86/intel/uncore-frequency/uncore-frequency-tpmi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 6df55c8e16b793..bfcf92aa4d69dd 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -192,9 +192,14 @@ static int uncore_read_control_freq(struct uncore_data *data, unsigned int *valu static int write_eff_lat_ctrl(struct uncore_data *data, unsigned int val, enum uncore_index index) { struct tpmi_uncore_cluster_info *cluster_info; + struct tpmi_uncore_struct *uncore_root; u64 control; cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data); + uncore_root = cluster_info->uncore_root; + + if (uncore_root->write_blocked) + return -EPERM; if (cluster_info->root_domain) return -ENODATA; From 2c78fb287e1f430b929f2e49786518350d15605c Mon Sep 17 00:00:00 2001 From: Suma Hegde Date: Thu, 7 Aug 2025 10:06:37 +0000 Subject: [PATCH 0088/1292] platform/x86/amd/hsmp: Ensure sock->metric_tbl_addr is non-NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If metric table address is not allocated, accessing metrics_bin will result in a NULL pointer dereference, so add a check. Fixes: 5150542b8ec5 ("platform/x86/amd/hsmp: add support for metrics tbl") Signed-off-by: Suma Hegde Link: https://lore.kernel.org/r/20250807100637.952729-1-suma.hegde@amd.com Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/amd/hsmp/hsmp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c index 885e2f8136fd44..19f82c1d309059 100644 --- a/drivers/platform/x86/amd/hsmp/hsmp.c +++ b/drivers/platform/x86/amd/hsmp/hsmp.c @@ -356,6 +356,11 @@ ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size) if (!sock || !buf) return -EINVAL; + if (!sock->metric_tbl_addr) { + dev_err(sock->dev, "Metrics table address not available\n"); + return -ENOMEM; + } + /* Do not support lseek(), also don't allow more than the size of metric table */ if (size != sizeof(struct hsmp_metric_table)) { dev_err(sock->dev, "Wrong buffer size\n"); From de5cec220e4d45d7129e76f7d985c7b01f10f8d9 Mon Sep 17 00:00:00 2001 From: Suma Hegde Date: Mon, 4 Aug 2025 10:15:51 +0000 Subject: [PATCH 0089/1292] platform/x86/amd/hsmp: Ensure success even if hwmon registration fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even if hwmon registration fails, HSMP remains accessible through the device file, so the operation should return success. Signed-off-by: Suma Hegde Reviewed-by: Ilpo JƤrvinen Link: https://lore.kernel.org/r/20250804101551.89866-1-suma.hegde@amd.com Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/amd/hsmp/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c index 54986a752f7d40..a94009203e0191 100644 --- a/drivers/platform/x86/amd/hsmp/acpi.c +++ b/drivers/platform/x86/amd/hsmp/acpi.c @@ -504,7 +504,7 @@ static int init_acpi(struct device *dev) dev_set_drvdata(dev, &hsmp_pdev->sock[sock_ind]); - return ret; + return 0; } static const struct bin_attribute hsmp_metric_tbl_attr = { From 748f897511446c7578ca5f6d2ff099916bad6e28 Mon Sep 17 00:00:00 2001 From: Edip Hazuri Date: Mon, 28 Jul 2025 14:58:06 +0300 Subject: [PATCH 0090/1292] platform/x86: hp-wmi: mark Victus 16-r1xxx for victus_s fan and thermal profile support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds Victus 16-r1xxx laptop DMI board name into existing list. Tested on 16-r1077nt and works without any problem. Signed-off-by: Edip Hazuri Link: https://lore.kernel.org/r/20250728115805.20954-2-edip@medip.dev Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/hp/hp-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index db5fdee2109cef..60c8ac8d902c4f 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -92,9 +92,9 @@ static const char * const victus_thermal_profile_boards[] = { "8A25" }; -/* DMI Board names of Victus 16-s1000 laptops */ +/* DMI Board names of Victus 16-r1000 and Victus 16-s1000 laptops */ static const char * const victus_s_thermal_profile_boards[] = { - "8C9C" + "8C99", "8C9C" }; enum hp_wmi_radio { From dfbd535db74df0343ca39670e06326d7aee8c8f4 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Wed, 23 Jul 2025 09:31:32 +0800 Subject: [PATCH 0091/1292] HID: intel-ish-hid: Increase ISHTP resume ack timeout to 300ms During s2idle suspend/resume testing on some systems, occasional several tens of seconds delays were observed in HID sensor resume handling. Trace analysis revealed repeated "link not ready" timeout errors during set/get_report operations, which were traced to the hid_ishtp_cl_resume_handler() timing out while waiting for the ISHTP resume acknowledgment. The previous timeout was set to 50ms, which proved insufficient on affected machines. Empirical measurements on failing systems showed that the time from ISH resume initiation to receiving the ISHTP resume ack could be as long as 180ms. As a result, the 50ms timeout caused failures. To address this, increase the wait timeout for ISHTP resume ack from 50ms to 300ms, providing a safer margin for slower hardware. Additionally, add error logging when a timeout occurs to aid future debugging and issue triage. No functional changes are made beyond the timeout adjustment and improved error reporting. Signed-off-by: Zhang Lixu Reviewed-by: Andy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 3 --- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 3 +++ drivers/hid/intel-ish-hid/ishtp/bus.c | 3 --- drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h | 3 +++ 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index c57483224db6f3..9d150ce234f253 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -264,9 +264,6 @@ static void ish_shutdown(struct pci_dev *pdev) static struct device __maybe_unused *ish_resume_device; -/* 50ms to get resume response */ -#define WAIT_FOR_RESUME_ACK_MS 50 - /** * ish_resume_handler() - Work function to complete resume * @work: work struct diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index 6550ad5bfbb537..d8c3c54a8c0f2a 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -759,6 +759,9 @@ static void hid_ishtp_cl_resume_handler(struct work_struct *work) if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) { client_data->suspended = false; wake_up_interruptible(&client_data->ishtp_resume_wait); + } else { + hid_ishtp_trace(client_data, "hid client: wait for resume timed out"); + dev_err(cl_data_to_dev(client_data), "wait for resume timed out"); } } diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 5ac7d70a7c8435..93a0432e705814 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -852,9 +852,6 @@ EXPORT_SYMBOL(ishtp_device); */ bool ishtp_wait_resume(struct ishtp_device *dev) { - /* 50ms to get resume response */ - #define WAIT_FOR_RESUME_ACK_MS 50 - /* Waiting to get resume response */ if (dev->resume_flag) wait_event_interruptible_timeout(dev->resume_wait, diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h index ec9f6e87aaf233..23db97ecf21cd9 100644 --- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h +++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h @@ -47,6 +47,9 @@ #define MAX_DMA_DELAY 20 +/* 300ms to get resume response */ +#define WAIT_FOR_RESUME_ACK_MS 300 + /* ISHTP device states */ enum ishtp_dev_state { ISHTP_DEV_INITIALIZING = 0, From ac143d499479ca33b6f8d16395c32394089979cf Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jul 2025 12:11:18 +0100 Subject: [PATCH 0092/1292] HID: Kconfig: Fix spelling mistake "enthropy" -> "entropy" There is a spelling mistake in the HID_U2FZERO description. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a57901203aeb28..79997553d8f987 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1243,7 +1243,7 @@ config HID_U2FZERO U2F Zero supports custom commands for blinking the LED and getting data from the internal hardware RNG. - The internal hardware can be used to feed the enthropy pool. + The internal hardware can be used to feed the entropy pool. U2F Zero only supports blinking its LED, so this driver doesn't allow setting the brightness to anything but 1, which will From 0379eb8691b9c4477da0277ae0832036ca4410b4 Mon Sep 17 00:00:00 2001 From: Qasim Ijaz Date: Sun, 10 Aug 2025 19:09:24 +0100 Subject: [PATCH 0093/1292] HID: multitouch: fix slab out-of-bounds access in mt_report_fixup() A malicious HID device can trigger a slab out-of-bounds during mt_report_fixup() by passing in report descriptor smaller than 607 bytes. mt_report_fixup() attempts to patch byte offset 607 of the descriptor with 0x25 by first checking if byte offset 607 is 0x15 however it lacks bounds checks to verify if the descriptor is big enough before conducting this check. Fix this bug by ensuring the descriptor size is at least 608 bytes before accessing it. Below is the KASAN splat after the out of bounds access happens: [ 13.671954] ================================================================== [ 13.672667] BUG: KASAN: slab-out-of-bounds in mt_report_fixup+0x103/0x110 [ 13.673297] Read of size 1 at addr ffff888103df39df by task kworker/0:1/10 [ 13.673297] [ 13.673297] CPU: 0 UID: 0 PID: 10 Comm: kworker/0:1 Not tainted 6.15.0-00005-gec5d573d83f4-dirty #3 [ 13.673297] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.2-debian-1.16.2-1 04/04 [ 13.673297] Call Trace: [ 13.673297] [ 13.673297] dump_stack_lvl+0x5f/0x80 [ 13.673297] print_report+0xd1/0x660 [ 13.673297] kasan_report+0xe5/0x120 [ 13.673297] __asan_report_load1_noabort+0x18/0x20 [ 13.673297] mt_report_fixup+0x103/0x110 [ 13.673297] hid_open_report+0x1ef/0x810 [ 13.673297] mt_probe+0x422/0x960 [ 13.673297] hid_device_probe+0x2e2/0x6f0 [ 13.673297] really_probe+0x1c6/0x6b0 [ 13.673297] __driver_probe_device+0x24f/0x310 [ 13.673297] driver_probe_device+0x4e/0x220 [ 13.673297] __device_attach_driver+0x169/0x320 [ 13.673297] bus_for_each_drv+0x11d/0x1b0 [ 13.673297] __device_attach+0x1b8/0x3e0 [ 13.673297] device_initial_probe+0x12/0x20 [ 13.673297] bus_probe_device+0x13d/0x180 [ 13.673297] device_add+0xe3a/0x1670 [ 13.673297] hid_add_device+0x31d/0xa40 [...] Fixes: c8000deb6836 ("HID: multitouch: Add support for GT7868Q") Cc: stable@vger.kernel.org Signed-off-by: Qasim Ijaz Reviewed-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 294516a8f54149..22c6314a88436b 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1503,6 +1503,14 @@ static const __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (hdev->vendor == I2C_VENDOR_ID_GOODIX && (hdev->product == I2C_DEVICE_ID_GOODIX_01E8 || hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) { + if (*size < 608) { + dev_info( + &hdev->dev, + "GT7868Q fixup: report descriptor is only %u bytes, skipping\n", + *size); + return rdesc; + } + if (rdesc[607] == 0x15) { rdesc[607] = 0x25; dev_info( From 9fc51941d9e7793da969b2c66e6f8213c5b1237f Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sun, 10 Aug 2025 22:40:30 -0700 Subject: [PATCH 0094/1292] HID: wacom: Add a new Art Pen 2 Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 955b39d2252442..9b2c710f8da182 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -684,6 +684,7 @@ static bool wacom_is_art_pen(int tool_id) case 0x885: /* Intuos3 Marker Pen */ case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ + case 0x204: /* Art Pen 2 */ is_art_pen = true; break; } From 82b3644d3deab496cc09f29f3449ede6824b3e8e Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 22 Jul 2025 16:59:59 +0200 Subject: [PATCH 0095/1292] device: rust: expand documentation for DeviceContext Expand the documentation around DeviceContext states and types, in order to provide detailed information about their purpose and relationship with each other. Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Reviewed-by: Daniel Almeida Link: https://lore.kernel.org/r/20250722150110.23565-2-dakr@kernel.org [ Fix two minor typos. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 69 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index b8613289de8e7c..fe095a8eccb1c6 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -311,28 +311,75 @@ unsafe impl Send for Device {} // synchronization in `struct device`. unsafe impl Sync for Device {} -/// Marker trait for the context of a bus specific device. +/// Marker trait for the context or scope of a bus specific device. /// -/// Some functions of a bus specific device should only be called from a certain context, i.e. bus -/// callbacks, such as `probe()`. +/// [`DeviceContext`] is a marker trait for types representing the context of a bus specific +/// [`Device`]. /// -/// This is the marker trait for structures representing the context of a bus specific device. +/// The specific device context types are: [`CoreInternal`], [`Core`], [`Bound`] and [`Normal`]. +/// +/// [`DeviceContext`] types are hierarchical, which means that there is a strict hierarchy that +/// defines which [`DeviceContext`] type can be derived from another. For instance, any +/// [`Device`] can dereference to a [`Device`]. +/// +/// The following enumeration illustrates the dereference hierarchy of [`DeviceContext`] types. +/// +/// - [`CoreInternal`] => [`Core`] => [`Bound`] => [`Normal`] +/// +/// Bus devices can automatically implement the dereference hierarchy by using +/// [`impl_device_context_deref`]. +/// +/// Note that the guarantee for a [`Device`] reference to have a certain [`DeviceContext`] comes +/// from the specific scope the [`Device`] reference is valid in. +/// +/// [`impl_device_context_deref`]: kernel::impl_device_context_deref pub trait DeviceContext: private::Sealed {} -/// The [`Normal`] context is the context of a bus specific device when it is not an argument of -/// any bus callback. +/// The [`Normal`] context is the default [`DeviceContext`] of any [`Device`]. +/// +/// The normal context does not indicate any specific context. Any `Device` is also a valid +/// [`Device`]. It is the only [`DeviceContext`] for which it is valid to implement +/// [`AlwaysRefCounted`] for. +/// +/// [`AlwaysRefCounted`]: kernel::types::AlwaysRefCounted pub struct Normal; -/// The [`Core`] context is the context of a bus specific device when it is supplied as argument of -/// any of the bus callbacks, such as `probe()`. +/// The [`Core`] context is the context of a bus specific device when it appears as argument of +/// any bus specific callback, such as `probe()`. +/// +/// The core context indicates that the [`Device`] reference's scope is limited to the bus +/// callback it appears in. It is intended to be used for synchronization purposes. Bus device +/// implementations can implement methods for [`Device`], such that they can only be called +/// from bus callbacks. pub struct Core; -/// Semantically the same as [`Core`] but reserved for internal usage of the corresponding bus +/// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus +/// abstraction. +/// +/// The internal core context is intended to be used in exactly the same way as the [`Core`] +/// context, with the difference that this [`DeviceContext`] is internal to the corresponding bus /// abstraction. +/// +/// This context mainly exists to share generic [`Device`] infrastructure that should only be called +/// from bus callbacks with bus abstractions, but without making them accessible for drivers. pub struct CoreInternal; -/// The [`Bound`] context is the context of a bus specific device reference when it is guaranteed to -/// be bound for the duration of its lifetime. +/// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to +/// be bound to a driver. +/// +/// The bound context indicates that for the entire duration of the lifetime of a [`Device`] +/// reference, the [`Device`] is guaranteed to be bound to a driver. +/// +/// Some APIs, such as [`dma::CoherentAllocation`] or [`Devres`] rely on the [`Device`] to be bound, +/// which can be proven with the [`Bound`] device context. +/// +/// Any abstraction that can guarantee a scope where the corresponding bus device is bound, should +/// provide a [`Device`] reference to its users for this scope. This allows users to benefit +/// from optimizations for accessing device resources, see also [`Devres::access`]. +/// +/// [`Devres`]: kernel::devres::Devres +/// [`Devres::access`]: kernel::devres::Devres::access +/// [`dma::CoherentAllocation`]: kernel::dma::CoherentAllocation pub struct Bound; mod private { From d6e26c1ae4a602d8b7eeb39e23514f6f98d91eb5 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 22 Jul 2025 17:00:00 +0200 Subject: [PATCH 0096/1292] device: rust: expand documentation for Device The documentation for the generic Device type is outdated and deserves much more detail. Hence, expand the documentation and cover topics such as device types, device contexts, as well as information on how to use the generic device infrastructure to implement bus and class specific device types. Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250722150110.23565-3-dakr@kernel.org [ Add empty line after code blocks, "in" -> "within", remove unnecessary pin annotations in class device example. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 139 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 126 insertions(+), 13 deletions(-) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index fe095a8eccb1c6..5902b3714a1662 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -15,23 +15,130 @@ use crate::c_str; pub mod property; -/// A reference-counted device. +/// The core representation of a device in the kernel's driver model. /// -/// This structure represents the Rust abstraction for a C `struct device`. This implementation -/// abstracts the usage of an already existing C `struct device` within Rust code that we get -/// passed from the C side. +/// This structure represents the Rust abstraction for a C `struct device`. A [`Device`] can either +/// exist as temporary reference (see also [`Device::from_raw`]), which is only valid within a +/// certain scope or as [`ARef`], owning a dedicated reference count. /// -/// An instance of this abstraction can be obtained temporarily or permanent. +/// # Device Types /// -/// A temporary one is bound to the lifetime of the C `struct device` pointer used for creation. -/// A permanent instance is always reference-counted and hence not restricted by any lifetime -/// boundaries. +/// A [`Device`] can represent either a bus device or a class device. /// -/// For subsystems it is recommended to create a permanent instance to wrap into a subsystem -/// specific device structure (e.g. `pci::Device`). This is useful for passing it to drivers in -/// `T::probe()`, such that a driver can store the `ARef` (equivalent to storing a -/// `struct device` pointer in a C driver) for arbitrary purposes, e.g. allocating DMA coherent -/// memory. +/// ## Bus Devices +/// +/// A bus device is a [`Device`] that is associated with a physical or virtual bus. Examples of +/// buses include PCI, USB, I2C, and SPI. Devices attached to a bus are registered with a specific +/// bus type, which facilitates matching devices with appropriate drivers based on IDs or other +/// identifying information. Bus devices are visible in sysfs under `/sys/bus//devices/`. +/// +/// ## Class Devices +/// +/// A class device is a [`Device`] that is associated with a logical category of functionality +/// rather than a physical bus. Examples of classes include block devices, network interfaces, sound +/// cards, and input devices. Class devices are grouped under a common class and exposed to +/// userspace via entries in `/sys/class//`. +/// +/// # Device Context +/// +/// [`Device`] references are generic over a [`DeviceContext`], which represents the type state of +/// a [`Device`]. +/// +/// As the name indicates, this type state represents the context of the scope the [`Device`] +/// reference is valid in. For instance, the [`Bound`] context guarantees that the [`Device`] is +/// bound to a driver for the entire duration of the existence of a [`Device`] reference. +/// +/// Other [`DeviceContext`] types besides [`Bound`] are [`Normal`], [`Core`] and [`CoreInternal`]. +/// +/// Unless selected otherwise [`Device`] defaults to the [`Normal`] [`DeviceContext`], which by +/// itself has no additional requirements. +/// +/// It is always up to the caller of [`Device::from_raw`] to select the correct [`DeviceContext`] +/// type for the corresponding scope the [`Device`] reference is created in. +/// +/// All [`DeviceContext`] types other than [`Normal`] are intended to be used with +/// [bus devices](#bus-devices) only. +/// +/// # Implementing Bus Devices +/// +/// This section provides a guideline to implement bus specific devices, such as [`pci::Device`] or +/// [`platform::Device`]. +/// +/// A bus specific device should be defined as follows. +/// +/// ```ignore +/// #[repr(transparent)] +/// pub struct Device( +/// Opaque, +/// PhantomData, +/// ); +/// ``` +/// +/// Since devices are reference counted, [`AlwaysRefCounted`] should be implemented for `Device` +/// (i.e. `Device`). Note that [`AlwaysRefCounted`] must not be implemented for any other +/// [`DeviceContext`], since all other device context types are only valid within a certain scope. +/// +/// In order to be able to implement the [`DeviceContext`] dereference hierarchy, bus device +/// implementations should call the [`impl_device_context_deref`] macro as shown below. +/// +/// ```ignore +/// // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s +/// // generic argument. +/// kernel::impl_device_context_deref!(unsafe { Device }); +/// ``` +/// +/// In order to convert from a any [`Device`] to [`ARef`], bus devices can implement +/// the following macro call. +/// +/// ```ignore +/// kernel::impl_device_context_into_aref!(Device); +/// ``` +/// +/// Bus devices should also implement the following [`AsRef`] implementation, such that users can +/// easily derive a generic [`Device`] reference. +/// +/// ```ignore +/// impl AsRef> for Device { +/// fn as_ref(&self) -> &device::Device { +/// ... +/// } +/// } +/// ``` +/// +/// # Implementing Class Devices +/// +/// Class device implementations require less infrastructure and depend slightly more on the +/// specific subsystem. +/// +/// An example implementation for a class device could look like this. +/// +/// ```ignore +/// #[repr(C)] +/// pub struct Device { +/// dev: Opaque, +/// data: T::Data, +/// } +/// ``` +/// +/// This class device uses the sub-classing pattern to embed the driver's private data within the +/// allocation of the class device. For this to be possible the class device is generic over the +/// class specific `Driver` trait implementation. +/// +/// Just like any device, class devices are reference counted and should hence implement +/// [`AlwaysRefCounted`] for `Device`. +/// +/// Class devices should also implement the following [`AsRef`] implementation, such that users can +/// easily derive a generic [`Device`] reference. +/// +/// ```ignore +/// impl AsRef for Device { +/// fn as_ref(&self) -> &device::Device { +/// ... +/// } +/// } +/// ``` +/// +/// An example for a class device implementation is [`drm::Device`]. /// /// # Invariants /// @@ -42,6 +149,12 @@ pub mod property; /// /// `bindings::device::release` is valid to be called from any thread, hence `ARef` can be /// dropped from any thread. +/// +/// [`AlwaysRefCounted`]: kernel::types::AlwaysRefCounted +/// [`drm::Device`]: kernel::drm::Device +/// [`impl_device_context_deref`]: kernel::impl_device_context_deref +/// [`pci::Device`]: kernel::pci::Device +/// [`platform::Device`]: kernel::platform::Device #[repr(transparent)] pub struct Device(Opaque, PhantomData); From 970a7c68788e3fec237713eef22ace46507bcf9c Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 22 Jul 2025 17:00:01 +0200 Subject: [PATCH 0097/1292] driver: rust: expand documentation for driver infrastructure Add documentation about generic driver infrastructure, representing a guideline on how the generic driver infrastructure is intended to be used to implement bus specific driver APIs. This covers aspects such as the bus specific driver trait, adapter implementation, driver registration and custom device ID types. Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250722150110.23565-4-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/driver.rs | 89 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index a8f2675ba7a707..279e3af206822c 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -2,8 +2,93 @@ //! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.). //! -//! Each bus / subsystem is expected to implement [`RegistrationOps`], which allows drivers to -//! register using the [`Registration`] class. +//! This documentation describes how to implement a bus specific driver API and how to align it with +//! the design of (bus specific) devices. +//! +//! Note: Readers are expected to know the content of the documentation of [`Device`] and +//! [`DeviceContext`]. +//! +//! # Driver Trait +//! +//! The main driver interface is defined by a bus specific driver trait. For instance: +//! +//! ```ignore +//! pub trait Driver: Send { +//! /// The type holding information about each device ID supported by the driver. +//! type IdInfo: 'static; +//! +//! /// The table of OF device ids supported by the driver. +//! const OF_ID_TABLE: Option> = None; +//! +//! /// The table of ACPI device ids supported by the driver. +//! const ACPI_ID_TABLE: Option> = None; +//! +//! /// Driver probe. +//! fn probe(dev: &Device, id_info: &Self::IdInfo) -> Result>>; +//! +//! /// Driver unbind (optional). +//! fn unbind(dev: &Device, this: Pin<&Self>) { +//! let _ = (dev, this); +//! } +//! } +//! ``` +//! +//! For specific examples see [`auxiliary::Driver`], [`pci::Driver`] and [`platform::Driver`]. +//! +//! The `probe()` callback should return a `Result>>`, i.e. the driver's private +//! data. The bus abstraction should store the pointer in the corresponding bus device. The generic +//! [`Device`] infrastructure provides common helpers for this purpose on its +//! [`Device`] implementation. +//! +//! All driver callbacks should provide a reference to the driver's private data. Once the driver +//! is unbound from the device, the bus abstraction should take back the ownership of the driver's +//! private data from the corresponding [`Device`] and [`drop`] it. +//! +//! All driver callbacks should provide a [`Device`] reference (see also [`device::Core`]). +//! +//! # Adapter +//! +//! The adapter implementation of a bus represents the abstraction layer between the C bus +//! callbacks and the Rust bus callbacks. It therefore has to be generic over an implementation of +//! the [driver trait](#driver-trait). +//! +//! ```ignore +//! pub struct Adapter; +//! ``` +//! +//! There's a common [`Adapter`] trait that can be implemented to inherit common driver +//! infrastructure, such as finding the ID info from an [`of::IdTable`] or [`acpi::IdTable`]. +//! +//! # Driver Registration +//! +//! In order to register C driver types (such as `struct platform_driver`) the [adapter](#adapter) +//! should implement the [`RegistrationOps`] trait. +//! +//! This trait implementation can be used to create the actual registration with the common +//! [`Registration`] type. +//! +//! Typically, bus abstractions want to provide a bus specific `module_bus_driver!` macro, which +//! creates a kernel module with exactly one [`Registration`] for the bus specific adapter. +//! +//! The generic driver infrastructure provides a helper for this with the [`module_driver`] macro. +//! +//! # Device IDs +//! +//! Besides the common device ID types, such as [`of::DeviceId`] and [`acpi::DeviceId`], most buses +//! may need to implement their own device ID types. +//! +//! For this purpose the generic infrastructure in [`device_id`] should be used. +//! +//! [`auxiliary::Driver`]: kernel::auxiliary::Driver +//! [`Core`]: device::Core +//! [`Device`]: device::Device +//! [`Device`]: device::Device +//! [`Device`]: device::Device +//! [`DeviceContext`]: device::DeviceContext +//! [`device_id`]: kernel::device_id +//! [`module_driver`]: kernel::module_driver +//! [`pci::Driver`]: kernel::pci::Driver +//! [`platform::Driver`]: kernel::platform::Driver use crate::error::{Error, Result}; use crate::{acpi, device, of, str::CStr, try_pin_init, types::Opaque, ThisModule}; From 3f69f2e78799bf76e5dfe74f2eda4d67812d4edc Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Mon, 11 Aug 2025 07:41:44 +0200 Subject: [PATCH 0098/1292] PCI: xilinx: Fix NULL pointer dereference in xilinx_pcie_intr_handler() f29861aa301c5 ("PCI: xilinx: Switch to msi_create_parent_irq_domain()") changed xilinx_pcie::msi_domain from child devices' interrupt domain to Xilinx AXI bridge's interrupt domain. However, xilinx_pcie_intr_handler() wasn't changed and still reads Xilinx AXI bridge's interrupt domain from xilinx_pcie::msi_domain->parent. This pointer is NULL now. Update xilinx_pcie_intr_handler() to read the correct interrupt domain pointer. Fixes: f29861aa301c5 ("PCI: xilinx: Switch to msi_create_parent_irq_domain()") Signed-off-by: Nam Cao Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250811054144.4049448-1-namcao@linutronix.de --- drivers/pci/controller/pcie-xilinx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c index f121836c3cf4e4..937ea6ae1ac486 100644 --- a/drivers/pci/controller/pcie-xilinx.c +++ b/drivers/pci/controller/pcie-xilinx.c @@ -400,7 +400,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) if (val & XILINX_PCIE_RPIFR1_MSI_INTR) { val = pcie_read(pcie, XILINX_PCIE_REG_RPIFR2) & XILINX_PCIE_RPIFR2_MSG_DATA; - domain = pcie->msi_domain->parent; + domain = pcie->msi_domain; } else { val = (val & XILINX_PCIE_RPIFR1_INTR_MASK) >> XILINX_PCIE_RPIFR1_INTR_SHIFT; From 5149bbb56bdcf5c5f72904025fbb502217580b63 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Mon, 11 Aug 2025 07:39:35 +0200 Subject: [PATCH 0099/1292] PCI: vmd: Remove MSI-X check on child devices d7d8ab87e3e7 ("PCI: vmd: Switch to msi_create_parent_irq_domain()") added a WARN_ON sanity check that child devices support MSI-X, because VMD document says [1]: Intel VMD only supports MSIx Interrupts from child devices and therefore the BIOS must enable PCIe Hot Plug and MSIx interrups [sic]. However, the VMD device can't even tell the difference between a child device using MSI and one using MSI-X. Per 185a383ada2e ("x86/PCI: Add driver for Intel Volume Management Device (VMD)"), VMD does not support INTx interrupts, but does support child devices using either MSI or MSI-X. Remove the sanity check to avoid the WARN_ON and allow child devices to use MSI, reported by Ammar. Fixes: d7d8ab87e3e7 ("PCI: vmd: Switch to msi_create_parent_irq_domain()") Link: https://cdrdv2-public.intel.com/776857/VMD_White_Paper.pdf [1] Reported-by: Ammar Faizi Closes: https://lore.kernel.org/linux-pci/aJXYhfc%2F6DfcqfqF@linux.gnuweeb.org/ Signed-off-by: Nam Cao [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas Tested-by: Ammar Faizi Link: https://patch.msgid.link/20250811053935.4049211-1-namcao@linutronix.de --- drivers/pci/controller/vmd.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index b679c7f28f51c1..1bd5bf4a609793 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -306,9 +306,6 @@ static bool vmd_init_dev_msi_info(struct device *dev, struct irq_domain *domain, struct irq_domain *real_parent, struct msi_domain_info *info) { - if (WARN_ON_ONCE(info->bus_token != DOMAIN_BUS_PCI_DEVICE_MSIX)) - return false; - if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info)) return false; From 6563623e604e3e235b2cee71190a4972be8f986b Mon Sep 17 00:00:00 2001 From: Soham Metha Date: Wed, 13 Aug 2025 02:19:46 +0530 Subject: [PATCH 0100/1292] docs: cgroup: fixed spelling mistakes in documentation found/fixed the following typo - Availablity -> Availability in `Documentation/admin-guide/cgroup-v2.rst` Signed-off-by: Soham Metha Signed-off-by: Tejun Heo --- Documentation/admin-guide/cgroup-v2.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index d9d3cc7df3488e..51c0bc4c2dc534 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -435,8 +435,8 @@ both cgroups. Controlling Controllers ----------------------- -Availablity -~~~~~~~~~~~ +Availability +~~~~~~~~~~~~ A controller is available in a cgroup when it is supported by the kernel (i.e., compiled in, not disabled and not attached to a v1 hierarchy) and listed in the From 6a912e8aa2b2fba2519e93a2eac197d16f137c9a Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Thu, 3 Jul 2025 15:39:02 +0800 Subject: [PATCH 0101/1292] ext4: show the default enabled i_version option Display `i_version` in `/proc/fs/ext4/sdx/options`, even though it's default enabled. This aids users managing multi-version scenarios and simplifies debugging. Signed-off-by: Baokun Li Reviewed-by: Jan Kara Link: https://patch.msgid.link/20250703073903.6952-1-libaokun@huaweicloud.com Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c7d39da7e733b1..9203518786e402 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2975,6 +2975,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time); if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time); + if (nodefs && sb->s_flags & SB_I_VERSION) + SEQ_OPTS_PUTS("i_version"); if (nodefs || sbi->s_stripe) SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe); if (nodefs || EXT4_MOUNT_DATA_FLAGS & From f2326fd14a224e4cccbab89e14c52279ff79b7ec Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Thu, 3 Jul 2025 15:39:03 +0800 Subject: [PATCH 0102/1292] ext4: preserve SB_I_VERSION on remount IMA testing revealed that after an ext4 remount, file accesses triggered full measurements even without modifications, instead of skipping as expected when i_version is unchanged. Debugging showed `SB_I_VERSION` was cleared in reconfigure_super() during remount due to commit 1ff20307393e ("ext4: unconditionally enable the i_version counter") removing the fix from commit 960e0ab63b2e ("ext4: fix i_version handling on remount"). To rectify this, `SB_I_VERSION` is always set for `fc->sb_flags` in ext4_init_fs_context(), instead of `sb->s_flags` in __ext4_fill_super(), ensuring it persists across all mounts. Cc: stable@kernel.org Fixes: 1ff20307393e ("ext4: unconditionally enable the i_version counter") Signed-off-by: Baokun Li Reviewed-by: Jan Kara Link: https://patch.msgid.link/20250703073903.6952-2-libaokun@huaweicloud.com Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9203518786e402..ed1b36bd51c872 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1998,6 +1998,9 @@ int ext4_init_fs_context(struct fs_context *fc) fc->fs_private = ctx; fc->ops = &ext4_context_ops; + /* i_version is always enabled now */ + fc->sb_flags |= SB_I_VERSION; + return 0; } @@ -5316,9 +5319,6 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); - /* i_version is always enabled now */ - sb->s_flags |= SB_I_VERSION; - /* HSM events are allowed by default. */ sb->s_iflags |= SB_I_ALLOW_HSM; From b4cc4a4077268522e3d0d34de4b2dc144e2330fa Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Wed, 16 Jul 2025 19:36:42 -0600 Subject: [PATCH 0103/1292] ext4: check fast symlink for ea_inode correctly The check for a fast symlink in the presence of only an external xattr inode is incorrect. If a fast symlink does not have an xattr block (i_file_acl == 0), but does have an external xattr inode that increases inode i_blocks, then the check for a fast symlink will incorrectly fail and __ext4_iget()->ext4_ind_check_inode() will report the inode is corrupt when it "validates" i_data[] on the next read: # ln -s foo /mnt/tmp/bar # setfattr -h -n trusted.test \ -v "$(yes | head -n 4000)" /mnt/tmp/bar # umount /mnt/tmp # mount /mnt/tmp # ls -l /mnt/tmp ls: cannot access '/mnt/tmp/bar': Structure needs cleaning total 4 ? l?????????? ? ? ? ? ? bar # dmesg | tail -1 EXT4-fs error (device dm-8): __ext4_iget:5098: inode #24578: block 7303014: comm ls: invalid block (note that "block 7303014" = 0x6f6f66 = "foo" in LE order). ext4_inode_is_fast_symlink() should check the superblock EXT4_FEATURE_INCOMPAT_EA_INODE feature flag, not the inode EXT4_EA_INODE_FL, since the latter is only set on the xattr inode itself, and not on the inode that uses this xattr. Cc: stable@vger.kernel.org Fixes: fc82228a5e38 ("ext4: support fast symlinks from ext3 file systems") Signed-off-by: Andreas Dilger Reviewed-by: Li Dongyang Reviewed-by: Alex Zhuravlev Reviewed-by: Oleg Drokin Reviewed-on: https://review.whamcloud.com/59879 Lustre-bug-id: https://jira.whamcloud.com/browse/LU-19121 Link: https://patch.msgid.link/20250717063709.757077-1-adilger@dilger.ca Signed-off-by: Theodore Ts'o --- fs/ext4/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index eeccb6f588f995..731a800d9c148e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -146,7 +146,7 @@ static inline int ext4_begin_ordered_truncate(struct inode *inode, */ int ext4_inode_is_fast_symlink(struct inode *inode) { - if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) { + if (!ext4_has_feature_ea_inode(inode->i_sb)) { int ea_blocks = EXT4_I(inode)->i_file_acl ? EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0; From f3fbaa74d999c16b5caeca779e6d7e6e6e7feed8 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 21 Jul 2025 22:09:02 +0200 Subject: [PATCH 0104/1292] ext4: remove useless if check This if branch is only jumping to 'out' which is defined just after the branch itself. Hence this is if-check is a no-op and can be removed. Address-Coverity-ID: 1647981 ("Incorrect expression (IDENTICAL_BRANCHES)") Signed-off-by: Antonio Quartulli Link: https://patch.msgid.link/20250721200902.1071-1-antonio@mandelbit.com Signed-off-by: Theodore Ts'o --- fs/ext4/namei.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index d83f91b623174b..01f379f5fd04a1 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2984,8 +2984,6 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, return PTR_ERR(dir_block); de = (struct ext4_dir_entry_2 *)dir_block->b_data; err = ext4_init_dirblock(handle, inode, dir_block, dir->i_ino, NULL, 0); - if (err) - goto out; out: brelse(dir_block); return err; From 59d8731c887bf2f5bb8406ace26cbb6f6b36d6cc Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 31 Jul 2025 16:00:07 -0400 Subject: [PATCH 0105/1292] ext4: fix unused variable warning in ext4_init_new_dir Cc: stable@kernel.org Fixes: 90f097b1403f ("ext4: refactor the inline directory conversion and...") Signed-off-by: Theodore Ts'o --- fs/ext4/namei.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 01f379f5fd04a1..2cd36f59c9e363 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2965,7 +2965,6 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, struct inode *inode) { struct buffer_head *dir_block = NULL; - struct ext4_dir_entry_2 *de; ext4_lblk_t block = 0; int err; @@ -2982,7 +2981,6 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, dir_block = ext4_append(handle, inode, &block); if (IS_ERR(dir_block)) return PTR_ERR(dir_block); - de = (struct ext4_dir_entry_2 *)dir_block->b_data; err = ext4_init_dirblock(handle, inode, dir_block, dir->i_ino, NULL, 0); out: brelse(dir_block); From 4ba97589ed19210ff808929052696f5636139823 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 3 Aug 2025 18:22:41 +0800 Subject: [PATCH 0106/1292] ext4: remove redundant __GFP_NOWARN GFP_NOWAIT already includes __GFP_NOWARN, so let's remove the redundant __GFP_NOWARN. Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250803102243.623705-4-rongqianfeng@vivo.com Signed-off-by: Theodore Ts'o --- fs/ext4/page-io.c | 2 +- fs/ext4/super.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 3d8b0f6d2dea50..39abfeec5f36c6 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -547,7 +547,7 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio, * first page of the bio. Otherwise it can deadlock. */ if (io->io_bio) - gfp_flags = GFP_NOWAIT | __GFP_NOWARN; + gfp_flags = GFP_NOWAIT; retry_encrypt: bounce_page = fscrypt_encrypt_pagecache_blocks(folio, enc_bytes, 0, gfp_flags); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ed1b36bd51c872..b16ffa507b8425 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -268,7 +268,7 @@ struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb, void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block) { struct buffer_head *bh = bdev_getblk(sb->s_bdev, block, - sb->s_blocksize, GFP_NOWAIT | __GFP_NOWARN); + sb->s_blocksize, GFP_NOWAIT); if (likely(bh)) { if (trylock_buffer(bh)) From bae76c035bf0852844151e68098c9b7cd63ef238 Mon Sep 17 00:00:00 2001 From: Ojaswin Mujoo Date: Tue, 5 Aug 2025 14:00:30 +0530 Subject: [PATCH 0107/1292] ext4: fix fsmap end of range reporting with bigalloc With bigalloc enabled, the logic to report last extent has a bug since we try to use cluster units instead of block units. This can cause an issue where extra incorrect entries might be returned back to the user. This was flagged by generic/365 with 64k bs and -O bigalloc. ** Details of issue ** The issue was noticed on 5G 64k blocksize FS with -O bigalloc which has only 1 bg. $ xfs_io -c "fsmap -d" /mnt/scratch 0: 253:48 [0..127]: static fs metadata 128 /* sb */ 1: 253:48 [128..255]: special 102:1 128 /* gdt */ 3: 253:48 [256..383]: special 102:3 128 /* block bitmap */ 4: 253:48 [384..2303]: unknown 1920 /* flex bg empty space */ 5: 253:48 [2304..2431]: special 102:4 128 /* inode bitmap */ 6: 253:48 [2432..4351]: unknown 1920 /* flex bg empty space */ 7: 253:48 [4352..6911]: inodes 2560 8: 253:48 [6912..538623]: unknown 531712 9: 253:48 [538624..10485759]: free space 9947136 The issue can be seen with: $ xfs_io -c "fsmap -d 0 3" /mnt/scratch 0: 253:48 [0..127]: static fs metadata 128 1: 253:48 [384..2047]: unknown 1664 Only the first entry was expected to be returned but we get 2. This is because: ext4_getfsmap_datadev() first_cluster, last_cluster = 0 ... info->gfi_last = true; ext4_getfsmap_datadev_helper(sb, end_ag, last_cluster + 1, 0, info); fsb = C2B(1) = 16 fslen = 0 ... /* Merge in any relevant extents from the meta_list */ list_for_each_entry_safe(p, tmp, &info->gfi_meta_list, fmr_list) { ... // since fsb = 16, considers all metadata which starts before 16 blockno iter 1: error = ext4_getfsmap_helper(sb, info, p); // p = sb (0,1), nop info->gfi_next_fsblk = 1 iter 2: error = ext4_getfsmap_helper(sb, info, p); // p = gdt (1,2), nop info->gfi_next_fsblk = 2 iter 3: error = ext4_getfsmap_helper(sb, info, p); // p = blk bitmap (2,3), nop info->gfi_next_fsblk = 3 iter 4: error = ext4_getfsmap_helper(sb, info, p); // p = ino bitmap (18,19) if (rec_blk > info->gfi_next_fsblk) { // (18 > 3) // emits an extra entry ** BUG ** } } Fix this by directly calling ext4_getfsmap_datadev() with a dummy record that has fmr_physical set to (end_fsb + 1) instead of last_cluster + 1. By using the block instead of cluster we get the correct behavior. Replacing ext4_getfsmap_datadev_helper() with ext4_getfsmap_helper() is okay since the gfi_lastfree and metadata checks in ext4_getfsmap_datadev_helper() are anyways redundant when we only want to emit the last allocated block of the range, as we have already taken care of emitting metadata and any last free blocks. Cc: stable@kernel.org Reported-by: Disha Goel Fixes: 4a622e4d477b ("ext4: fix FS_IOC_GETFSMAP handling") Signed-off-by: Ojaswin Mujoo Reviewed-by: Darrick J. Wong Link: https://patch.msgid.link/e7472c8535c9c5ec10f425f495366864ea12c9da.1754377641.git.ojaswin@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/fsmap.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs/ext4/fsmap.c b/fs/ext4/fsmap.c index 383c6edea6dd31..9d63c39f6077b7 100644 --- a/fs/ext4/fsmap.c +++ b/fs/ext4/fsmap.c @@ -526,6 +526,7 @@ static int ext4_getfsmap_datadev(struct super_block *sb, ext4_group_t end_ag; ext4_grpblk_t first_cluster; ext4_grpblk_t last_cluster; + struct ext4_fsmap irec; int error = 0; bofs = le32_to_cpu(sbi->s_es->s_first_data_block); @@ -609,10 +610,18 @@ static int ext4_getfsmap_datadev(struct super_block *sb, goto err; } - /* Report any gaps at the end of the bg */ + /* + * The dummy record below will cause ext4_getfsmap_helper() to report + * any allocated blocks at the end of the range. + */ + irec.fmr_device = 0; + irec.fmr_physical = end_fsb + 1; + irec.fmr_length = 0; + irec.fmr_owner = EXT4_FMR_OWN_FREE; + irec.fmr_flags = 0; + info->gfi_last = true; - error = ext4_getfsmap_datadev_helper(sb, end_ag, last_cluster + 1, - 0, info); + error = ext4_getfsmap_helper(sb, info, &irec); if (error) goto err; From 3ffbdd1f1165f1b2d6a94d1b1aabef57120deaf7 Mon Sep 17 00:00:00 2001 From: Ojaswin Mujoo Date: Tue, 5 Aug 2025 14:00:31 +0530 Subject: [PATCH 0108/1292] ext4: fix reserved gdt blocks handling in fsmap In some cases like small FSes with no meta_bg and where the resize doesn't need extra gdt blocks as it can fit in the current one, s_reserved_gdt_blocks is set as 0, which causes fsmap to emit a 0 length entry, which is incorrect. $ mkfs.ext4 -b 65536 -O bigalloc /dev/sda 5G $ mount /dev/sda /mnt/scratch $ xfs_io -c "fsmap -d" /mnt/scartch 0: 253:48 [0..127]: static fs metadata 128 1: 253:48 [128..255]: special 102:1 128 2: 253:48 [256..255]: special 102:2 0 <---- 0 len entry 3: 253:48 [256..383]: special 102:3 128 Fix this by adding a check for this case. Cc: stable@kernel.org Fixes: 0c9ec4beecac ("ext4: support GETFSMAP ioctls") Signed-off-by: Ojaswin Mujoo Reviewed-by: Darrick J. Wong Link: https://patch.msgid.link/08781b796453a5770112aa96ad14c864fbf31935.1754377641.git.ojaswin@linux.ibm.com Signed-off-by: Theodore Ts'o --- fs/ext4/fsmap.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ext4/fsmap.c b/fs/ext4/fsmap.c index 9d63c39f6077b7..91185c40f755a5 100644 --- a/fs/ext4/fsmap.c +++ b/fs/ext4/fsmap.c @@ -393,6 +393,14 @@ static unsigned int ext4_getfsmap_find_sb(struct super_block *sb, /* Reserved GDT blocks */ if (!ext4_has_feature_meta_bg(sb) || metagroup < first_meta_bg) { len = le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); + + /* + * mkfs.ext4 can set s_reserved_gdt_blocks as 0 in some cases, + * check for that. + */ + if (!len) + return 0; + error = ext4_getfsmap_fill(meta_list, fsb, len, EXT4_FMR_OWN_RESV_GDT); if (error) From c5e104a91e7b6fa12c1dc2d8bf84abb7ef9b89ad Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 7 Aug 2025 09:35:20 -0400 Subject: [PATCH 0109/1292] ext4: don't try to clear the orphan_present feature block device is r/o When the file system is frozen in preparation for taking an LVM snapshot, the journal is checkpointed and if the orphan_file feature is enabled, and the orphan file is empty, we clear the orphan_present feature flag. But if there are pending inodes that need to be removed the orphan_present feature flag can't be cleared. The problem comes if the block device is read-only. In that case, we can't process the orphan inode list, so it is skipped in ext4_orphan_cleanup(). But then in ext4_mark_recovery_complete(), this results in the ext4 error "Orphan file not empty on read-only fs" firing and the file system mount is aborted. Fix this by clearing the needs_recovery flag in the block device is read-only. We do this after the call to ext4_load_and_init-journal() since there are some error checks need to be done in case the journal needs to be replayed and the block device is read-only, or if the block device containing the externa journal is read-only, etc. Cc: stable@kernel.org Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1108271 Cc: stable@vger.kernel.org Fixes: 02f310fcf47f ("ext4: Speedup ext4 orphan inode handling") Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b16ffa507b8425..699c15db28a82f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5416,6 +5416,8 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) err = ext4_load_and_init_journal(sb, es, ctx); if (err) goto failed_mount3a; + if (bdev_read_only(sb->s_bdev)) + needs_recovery = 0; } else if (test_opt(sb, NOLOAD) && !sb_rdonly(sb) && ext4_has_feature_journal_needs_recovery(sb)) { ext4_msg(sb, KERN_ERR, "required journal recovery " From 02c7f7219ac0e2277b3379a3a0e9841ef464b6d4 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Mon, 11 Aug 2025 14:45:32 +0800 Subject: [PATCH 0110/1292] ext4: fix hole length calculation overflow in non-extent inodes In a filesystem with a block size larger than 4KB, the hole length calculation for a non-extent inode in ext4_ind_map_blocks() can easily exceed INT_MAX. Then it could return a zero length hole and trigger the following waring and infinite in the iomap infrastructure. ------------[ cut here ]------------ WARNING: CPU: 3 PID: 434101 at fs/iomap/iter.c:34 iomap_iter_done+0x148/0x190 CPU: 3 UID: 0 PID: 434101 Comm: fsstress Not tainted 6.16.0-rc7+ #128 PREEMPT(voluntary) Hardware name: QEMU KVM Virtual Machine, BIOS unknown 2/2/2022 pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : iomap_iter_done+0x148/0x190 lr : iomap_iter+0x174/0x230 sp : ffff8000880af740 x29: ffff8000880af740 x28: ffff0000db8e6840 x27: 0000000000000000 x26: 0000000000000000 x25: ffff8000880af830 x24: 0000004000000000 x23: 0000000000000002 x22: 000001bfdbfa8000 x21: ffffa6a41c002e48 x20: 0000000000000001 x19: ffff8000880af808 x18: 0000000000000000 x17: 0000000000000000 x16: ffffa6a495ee6cd0 x15: 0000000000000000 x14: 00000000000003d4 x13: 00000000fa83b2da x12: 0000b236fc95f18c x11: ffffa6a4978b9c08 x10: 0000000000001da0 x9 : ffffa6a41c1a2a44 x8 : ffff8000880af5c8 x7 : 0000000001000000 x6 : 0000000000000000 x5 : 0000000000000004 x4 : 000001bfdbfa8000 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000004004030000 x0 : 0000000000000000 Call trace: iomap_iter_done+0x148/0x190 (P) iomap_iter+0x174/0x230 iomap_fiemap+0x154/0x1d8 ext4_fiemap+0x110/0x140 [ext4] do_vfs_ioctl+0x4b8/0xbc0 __arm64_sys_ioctl+0x8c/0x120 invoke_syscall+0x6c/0x100 el0_svc_common.constprop.0+0x48/0xf0 do_el0_svc+0x24/0x38 el0_svc+0x38/0x120 el0t_64_sync_handler+0x10c/0x138 el0t_64_sync+0x198/0x1a0 ---[ end trace 0000000000000000 ]--- Cc: stable@kernel.org Fixes: facab4d9711e ("ext4: return hole from ext4_map_blocks()") Reported-by: Qu Wenruo Closes: https://lore.kernel.org/linux-ext4/9b650a52-9672-4604-a765-bb6be55d1e4a@gmx.com/ Tested-by: Qu Wenruo Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20250811064532.1788289-1-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o --- fs/ext4/indirect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 7de327fa7b1c51..d45124318200d8 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -539,7 +539,7 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, int indirect_blks; int blocks_to_boundary = 0; int depth; - int count = 0; + u64 count = 0; ext4_fsblk_t first_block = 0; trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); @@ -588,7 +588,7 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, count++; /* Fill in size of a hole we found */ map->m_pblk = 0; - map->m_len = min_t(unsigned int, map->m_len, count); + map->m_len = umin(map->m_len, count); goto cleanup; } From 76dba1fe277f6befd6ef650e1946f626c547387a Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Mon, 11 Aug 2025 20:58:16 +0800 Subject: [PATCH 0111/1292] ext4: use kmalloc_array() for array space allocation Replace kmalloc(size * sizeof) with kmalloc_array() for safer memory allocation and overflow prevention. Cc: stable@kernel.org Signed-off-by: Liao Yuanhong Link: https://patch.msgid.link/20250811125816.570142-1-liaoyuanhong@vivo.com Signed-off-by: Theodore Ts'o --- fs/ext4/orphan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/orphan.c b/fs/ext4/orphan.c index 7c7f792ad6aba9..524d4658fa408d 100644 --- a/fs/ext4/orphan.c +++ b/fs/ext4/orphan.c @@ -589,8 +589,9 @@ int ext4_init_orphan_info(struct super_block *sb) } oi->of_blocks = inode->i_size >> sb->s_blocksize_bits; oi->of_csum_seed = EXT4_I(inode)->i_csum_seed; - oi->of_binfo = kmalloc(oi->of_blocks*sizeof(struct ext4_orphan_block), - GFP_KERNEL); + oi->of_binfo = kmalloc_array(oi->of_blocks, + sizeof(struct ext4_orphan_block), + GFP_KERNEL); if (!oi->of_binfo) { ret = -ENOMEM; goto out_put; From d045c3154080a04beb07726fa311b89d21608981 Mon Sep 17 00:00:00 2001 From: Pratyush Brahma Date: Wed, 13 Aug 2025 12:51:02 +0530 Subject: [PATCH 0112/1292] mm/numa_memblks: Use pr_debug instead of printk(KERN_DEBUG) Replace the direct usage of printk(KERN_DEBUG ...) with pr_debug(...) to align with the consistent `pr_*` API usage within the file. Reviewed-by: Joshua Hahn Signed-off-by: Pratyush Brahma Link: https://lore.kernel.org/r/20250813-numa-dbg-v3-1-1dcd1234fcc5@oss.qualcomm.com Signed-off-by: Mike Rapoport (Microsoft) --- mm/numa_memblks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/numa_memblks.c b/mm/numa_memblks.c index 541a99c4071a67..de626525a87c3e 100644 --- a/mm/numa_memblks.c +++ b/mm/numa_memblks.c @@ -76,7 +76,7 @@ static int __init numa_alloc_distance(void) for (j = 0; j < cnt; j++) numa_distance[i * cnt + j] = i == j ? LOCAL_DISTANCE : REMOTE_DISTANCE; - printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt); + pr_debug("NUMA: Initialized distance table, cnt=%d\n", cnt); return 0; } From b56cc41a3ae7323aa3c6165f93c32e020538b6d2 Mon Sep 17 00:00:00 2001 From: Arnaud Lecomte Date: Sat, 26 Jul 2025 23:09:31 +0100 Subject: [PATCH 0113/1292] hid: fix I2C read buffer overflow in raw_event() for mcp2221 As reported by syzbot, mcp2221_raw_event lacked validation of incoming I2C read data sizes, risking buffer overflows in mcp->rxbuf during multi-part transfers. As highlighted in the DS20005565B spec, p44, we have: "The number of read-back data bytes to follow in this packet: from 0 to a maximum of 60 bytes of read-back bytes." This patch enforces we don't exceed this limit. Reported-by: syzbot+52c1a7d3e5b361ccd346@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=52c1a7d3e5b361ccd346 Tested-by: syzbot+52c1a7d3e5b361ccd346@syzkaller.appspotmail.com Signed-off-by: Arnaud Lecomte Link: https://patch.msgid.link/20250726220931.7126-1-contact@arnaud-lcm.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-mcp2221.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index fcfe9370a8872d..157c363ea9ba6e 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -906,6 +906,10 @@ static int mcp2221_raw_event(struct hid_device *hdev, } if (data[2] == MCP2221_I2C_READ_COMPL || data[2] == MCP2221_I2C_READ_PARTIAL) { + if (!mcp->rxbuf || mcp->rxbuf_idx < 0 || data[3] > 60) { + mcp->status = -EINVAL; + break; + } buf = mcp->rxbuf; memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]); mcp->rxbuf_idx = mcp->rxbuf_idx + data[3]; From 89a2d212bdb4bc29bed8e7077abe054b801137ea Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 11 Aug 2025 13:17:59 -0500 Subject: [PATCH 0114/1292] dma/pool: Ensure DMA_DIRECT_REMAP allocations are decrypted When CONFIG_DMA_DIRECT_REMAP is enabled, atomic pool pages are remapped via dma_common_contiguous_remap() using the supplied pgprot. Currently, the mapping uses pgprot_dmacoherent(PAGE_KERNEL), which leaves the memory encrypted on systems with memory encryption enabled (e.g., ARM CCA Realms). This can cause the DMA layer to fail or crash when accessing the memory, as the underlying physical pages are not configured as expected. Fix this by requesting a decrypted mapping in the vmap() call: pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)) This ensures that atomic pool memory is consistently mapped unencrypted. Cc: stable@vger.kernel.org Signed-off-by: Shanker Donthineni Reviewed-by: Catalin Marinas Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20250811181759.998805-1-sdonthineni@nvidia.com --- kernel/dma/pool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c index 7b04f7575796b8..ee45dee33d4916 100644 --- a/kernel/dma/pool.c +++ b/kernel/dma/pool.c @@ -102,8 +102,8 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, #ifdef CONFIG_DMA_DIRECT_REMAP addr = dma_common_contiguous_remap(page, pool_size, - pgprot_dmacoherent(PAGE_KERNEL), - __builtin_return_address(0)); + pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)), + __builtin_return_address(0)); if (!addr) goto free_page; #else From d3af6ca9a8c34bbd8cff32b469b84c9021c9e7e4 Mon Sep 17 00:00:00 2001 From: Qasim Ijaz Date: Sun, 10 Aug 2025 19:10:41 +0100 Subject: [PATCH 0115/1292] HID: asus: fix UAF via HID_CLAIMED_INPUT validation After hid_hw_start() is called hidinput_connect() will eventually be called to set up the device with the input layer since the HID_CONNECT_DEFAULT connect mask is used. During hidinput_connect() all input and output reports are processed and corresponding hid_inputs are allocated and configured via hidinput_configure_usages(). This process involves slot tagging report fields and configuring usages by setting relevant bits in the capability bitmaps. However it is possible that the capability bitmaps are not set at all leading to the subsequent hidinput_has_been_populated() check to fail leading to the freeing of the hid_input and the underlying input device. This becomes problematic because a malicious HID device like a ASUS ROG N-Key keyboard can trigger the above scenario via a specially crafted descriptor which then leads to a user-after-free when the name of the freed input device is written to later on after hid_hw_start(). Below, report 93 intentionally utilises the HID_UP_UNDEFINED Usage Page which is skipped during usage configuration, leading to the frees. 0x05, 0x0D, // Usage Page (Digitizer) 0x09, 0x05, // Usage (Touch Pad) 0xA1, 0x01, // Collection (Application) 0x85, 0x0D, // Report ID (13) 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 0x09, 0xC5, // Usage (0xC5) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 0x95, 0x04, // Report Count (4) 0xB1, 0x02, // Feature (Data,Var,Abs) 0x85, 0x5D, // Report ID (93) 0x06, 0x00, 0x00, // Usage Page (Undefined) 0x09, 0x01, // Usage (0x01) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 0x95, 0x1B, // Report Count (27) 0x81, 0x02, // Input (Data,Var,Abs) 0xC0, // End Collection Below is the KASAN splat after triggering the UAF: [ 21.672709] ================================================================== [ 21.673700] BUG: KASAN: slab-use-after-free in asus_probe+0xeeb/0xf80 [ 21.673700] Write of size 8 at addr ffff88810a0ac000 by task kworker/1:2/54 [ 21.673700] [ 21.673700] CPU: 1 UID: 0 PID: 54 Comm: kworker/1:2 Not tainted 6.16.0-rc4-g9773391cf4dd-dirty #36 PREEMPT(voluntary) [ 21.673700] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 [ 21.673700] Call Trace: [ 21.673700] [ 21.673700] dump_stack_lvl+0x5f/0x80 [ 21.673700] print_report+0xd1/0x660 [ 21.673700] kasan_report+0xe5/0x120 [ 21.673700] __asan_report_store8_noabort+0x1b/0x30 [ 21.673700] asus_probe+0xeeb/0xf80 [ 21.673700] hid_device_probe+0x2ee/0x700 [ 21.673700] really_probe+0x1c6/0x6b0 [ 21.673700] __driver_probe_device+0x24f/0x310 [ 21.673700] driver_probe_device+0x4e/0x220 [...] [ 21.673700] [ 21.673700] Allocated by task 54: [ 21.673700] kasan_save_stack+0x3d/0x60 [ 21.673700] kasan_save_track+0x18/0x40 [ 21.673700] kasan_save_alloc_info+0x3b/0x50 [ 21.673700] __kasan_kmalloc+0x9c/0xa0 [ 21.673700] __kmalloc_cache_noprof+0x139/0x340 [ 21.673700] input_allocate_device+0x44/0x370 [ 21.673700] hidinput_connect+0xcb6/0x2630 [ 21.673700] hid_connect+0xf74/0x1d60 [ 21.673700] hid_hw_start+0x8c/0x110 [ 21.673700] asus_probe+0x5a3/0xf80 [ 21.673700] hid_device_probe+0x2ee/0x700 [ 21.673700] really_probe+0x1c6/0x6b0 [ 21.673700] __driver_probe_device+0x24f/0x310 [ 21.673700] driver_probe_device+0x4e/0x220 [...] [ 21.673700] [ 21.673700] Freed by task 54: [ 21.673700] kasan_save_stack+0x3d/0x60 [ 21.673700] kasan_save_track+0x18/0x40 [ 21.673700] kasan_save_free_info+0x3f/0x60 [ 21.673700] __kasan_slab_free+0x3c/0x50 [ 21.673700] kfree+0xcf/0x350 [ 21.673700] input_dev_release+0xab/0xd0 [ 21.673700] device_release+0x9f/0x220 [ 21.673700] kobject_put+0x12b/0x220 [ 21.673700] put_device+0x12/0x20 [ 21.673700] input_free_device+0x4c/0xb0 [ 21.673700] hidinput_connect+0x1862/0x2630 [ 21.673700] hid_connect+0xf74/0x1d60 [ 21.673700] hid_hw_start+0x8c/0x110 [ 21.673700] asus_probe+0x5a3/0xf80 [ 21.673700] hid_device_probe+0x2ee/0x700 [ 21.673700] really_probe+0x1c6/0x6b0 [ 21.673700] __driver_probe_device+0x24f/0x310 [ 21.673700] driver_probe_device+0x4e/0x220 [...] Fixes: 9ce12d8be12c ("HID: asus: Add i2c touchpad support") Cc: stable@vger.kernel.org Signed-off-by: Qasim Ijaz Link: https://patch.msgid.link/20250810181041.44874-1-qasdev00@gmail.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-asus.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 4b45e31f0bab2c..d27dcfb2b9e4e1 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -1213,7 +1213,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - if (!drvdata->input) { + /* + * Check that input registration succeeded. Checking that + * HID_CLAIMED_INPUT is set prevents a UAF when all input devices + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ + if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { hid_err(hdev, "Asus input not registered\n"); ret = -ENOMEM; goto err_stop_hw; From 3eb61d7cb74cea2ea697363669fa256937164758 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 15 Jul 2025 10:26:22 +0200 Subject: [PATCH 0116/1292] Revert "drm/amdgpu: Use dma_buf from GEM object instance" This reverts commit 515986100d176663d0a03219a3056e4252f729e6. The dma_buf field in struct drm_gem_object is not stable over the object instance's lifetime. The field becomes NULL when user space releases the final GEM handle on the buffer object. This resulted in a NULL-pointer deref. Workarounds in commit 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers") and commit f6bfc9afc751 ("drm/framebuffer: Acquire internal references on GEM handles") only solved the problem partially. They especially don't work for buffer objects without a DRM framebuffer associated. Hence, this revert to going back to using .import_attach->dmabuf. Signed-off-by: Thomas Zimmermann Reviewed-by: Simona Vetter Acked-by: Alex Deucher Link: https://lore.kernel.org/r/20250715082635.34974-1-tzimmermann@suse.de --- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index ff98c87b2e0b91..5743ebb2f1b7cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -514,7 +514,7 @@ bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev, return false; if (drm_gem_is_imported(obj)) { - struct dma_buf *dma_buf = obj->dma_buf; + struct dma_buf *dma_buf = obj->import_attach->dmabuf; if (dma_buf->ops != &amdgpu_dmabuf_ops) /* No XGMI with non AMD GPUs */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 6626a6e64ff5f8..d1ccbfcf21fa62 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -317,7 +317,8 @@ static int amdgpu_gem_object_open(struct drm_gem_object *obj, */ if (!vm->is_compute_context || !vm->process_info) return 0; - if (!drm_gem_is_imported(obj) || !dma_buf_is_dynamic(obj->dma_buf)) + if (!drm_gem_is_imported(obj) || + !dma_buf_is_dynamic(obj->import_attach->dmabuf)) return 0; mutex_lock_nested(&vm->process_info->lock, 1); if (!WARN_ON(!vm->process_info->eviction_fence)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 5cacf5717016aa..8777ed8facd6b5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1276,7 +1276,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, struct drm_gem_object *obj = &bo->tbo.base; if (drm_gem_is_imported(obj) && bo_va->is_xgmi) { - struct dma_buf *dma_buf = obj->dma_buf; + struct dma_buf *dma_buf = obj->import_attach->dmabuf; struct drm_gem_object *gobj = dma_buf->priv; struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj); From 3c3e9a9f2972b364e8c2cfbfdeb23c6d6be4f87f Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Fri, 25 Jul 2025 18:31:04 -0700 Subject: [PATCH 0117/1292] RDMA/rxe: Flush delayed SKBs while releasing RXE resources When skb packets are sent out, these skb packets still depends on the rxe resources, for example, QP, sk, when these packets are destroyed. If these rxe resources are released when the skb packets are destroyed, the call traces will appear. To avoid skb packets hang too long time in some network devices, a timestamp is added when these skb packets are created. If these skb packets hang too long time in network devices, these network devices can free these skb packets to release rxe resources. Reported-by: syzbot+8425ccfb599521edb153@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=8425ccfb599521edb153 Tested-by: syzbot+8425ccfb599521edb153@syzkaller.appspotmail.com Fixes: 1a633bdc8fd9 ("RDMA/rxe: Let destroy qp succeed with stuck packet") Signed-off-by: Zhu Yanjun Link: https://patch.msgid.link/20250726013104.463570-1-yanjun.zhu@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/rxe/rxe_net.c | 29 ++++++++--------------------- drivers/infiniband/sw/rxe/rxe_qp.c | 2 +- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 132a87e52d5c7e..ac0183a2ff7aa1 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -345,33 +345,15 @@ int rxe_prepare(struct rxe_av *av, struct rxe_pkt_info *pkt, static void rxe_skb_tx_dtor(struct sk_buff *skb) { - struct net_device *ndev = skb->dev; - struct rxe_dev *rxe; - unsigned int qp_index; - struct rxe_qp *qp; + struct rxe_qp *qp = skb->sk->sk_user_data; int skb_out; - rxe = rxe_get_dev_from_net(ndev); - if (!rxe && is_vlan_dev(ndev)) - rxe = rxe_get_dev_from_net(vlan_dev_real_dev(ndev)); - if (WARN_ON(!rxe)) - return; - - qp_index = (int)(uintptr_t)skb->sk->sk_user_data; - if (!qp_index) - return; - - qp = rxe_pool_get_index(&rxe->qp_pool, qp_index); - if (!qp) - goto put_dev; - skb_out = atomic_dec_return(&qp->skb_out); - if (qp->need_req_skb && skb_out < RXE_INFLIGHT_SKBS_PER_QP_LOW) + if (unlikely(qp->need_req_skb && + skb_out < RXE_INFLIGHT_SKBS_PER_QP_LOW)) rxe_sched_task(&qp->send_task); rxe_put(qp); -put_dev: - ib_device_put(&rxe->ib_dev); sock_put(skb->sk); } @@ -383,6 +365,7 @@ static int rxe_send(struct sk_buff *skb, struct rxe_pkt_info *pkt) sock_hold(sk); skb->sk = sk; skb->destructor = rxe_skb_tx_dtor; + rxe_get(pkt->qp); atomic_inc(&pkt->qp->skb_out); if (skb->protocol == htons(ETH_P_IP)) @@ -405,6 +388,7 @@ static int rxe_loopback(struct sk_buff *skb, struct rxe_pkt_info *pkt) sock_hold(sk); skb->sk = sk; skb->destructor = rxe_skb_tx_dtor; + rxe_get(pkt->qp); atomic_inc(&pkt->qp->skb_out); if (skb->protocol == htons(ETH_P_IP)) @@ -497,6 +481,9 @@ struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av, goto out; } + /* Add time stamp to skb. */ + skb->tstamp = ktime_get(); + skb_reserve(skb, hdr_len + LL_RESERVED_SPACE(ndev)); /* FIXME: hold reference to this netdev until life of this skb. */ diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index f2af3e0aef35b5..95f1c1c2949de7 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -244,7 +244,7 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk); if (err < 0) return err; - qp->sk->sk->sk_user_data = (void *)(uintptr_t)qp->elem.index; + qp->sk->sk->sk_user_data = qp; /* pick a source UDP port number for this QP based on * the source QPN. this spreads traffic for different QPs From d5c74713f0117d07f91eb48b10bc2ad44e23c9b9 Mon Sep 17 00:00:00 2001 From: Boshi Yu Date: Fri, 25 Jul 2025 13:53:55 +0800 Subject: [PATCH 0118/1292] RDMA/erdma: Fix ignored return value of init_kernel_qp The init_kernel_qp interface may fail. Check its return value and free related resources properly when it does. Fixes: 155055771704 ("RDMA/erdma: Add verbs implementation") Reviewed-by: Cheng Xu Signed-off-by: Boshi Yu Link: https://patch.msgid.link/20250725055410.67520-3-boshiyu@linux.alibaba.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/erdma/erdma_verbs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index 94c211df09d84a..2e01520ca3850f 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -1031,7 +1031,9 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, if (ret) goto err_out_cmd; } else { - init_kernel_qp(dev, qp, attrs); + ret = init_kernel_qp(dev, qp, attrs); + if (ret) + goto err_out_xa; } qp->attrs.max_send_sge = attrs->cap.max_send_sge; From d4ac86b47563c7895dae28658abd1879d266b2b4 Mon Sep 17 00:00:00 2001 From: Boshi Yu Date: Fri, 25 Jul 2025 13:53:56 +0800 Subject: [PATCH 0119/1292] RDMA/erdma: Fix unset QPN of GSI QP The QPN of the GSI QP was not set, which may cause issues. Set the QPN to 1 when creating the GSI QP. Fixes: 999a0a2e9b87 ("RDMA/erdma: Support UD QPs and UD WRs") Reviewed-by: Cheng Xu Signed-off-by: Boshi Yu Link: https://patch.msgid.link/20250725055410.67520-4-boshiyu@linux.alibaba.com Reviewed-by: Zhu Yanjun Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/erdma/erdma_verbs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index 2e01520ca3850f..fdeec33c71da20 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -994,6 +994,8 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, old_entry = xa_store(&dev->qp_xa, 1, qp, GFP_KERNEL); if (xa_is_err(old_entry)) ret = xa_err(old_entry); + else + qp->ibqp.qp_num = 1; } else { ret = xa_alloc_cyclic(&dev->qp_xa, &qp->ibqp.qp_num, qp, XA_LIMIT(1, dev->attrs.max_qp - 1), From f0ba0e7172a222ea6043b61ecd86723c46d7bcf2 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 23 Jul 2025 15:38:10 +0200 Subject: [PATCH 0120/1292] btrfs: zoned: skip ZONE FINISH of conventional zones Don't call ZONE FINISH for conventional zones as this will result in I/O errors. Instead check if the zone that needs finishing is a conventional zone and if yes skip it. Also factor out the actual handling of finishing a single zone into a helper function, as do_zone_finish() is growing ever bigger and the indentations levels are getting higher. Reviewed-by: Naohiro Aota Reviewed-by: Anand Jain Signed-off-by: Johannes Thumshirn Signed-off-by: David Sterba --- fs/btrfs/zoned.c | 55 ++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index db11b5b5f0e669..36de6d0d595f80 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -2245,6 +2245,40 @@ static void wait_eb_writebacks(struct btrfs_block_group *block_group) rcu_read_unlock(); } +static int call_zone_finish(struct btrfs_block_group *block_group, + struct btrfs_io_stripe *stripe) +{ + struct btrfs_device *device = stripe->dev; + const u64 physical = stripe->physical; + struct btrfs_zoned_device_info *zinfo = device->zone_info; + int ret; + + if (!device->bdev) + return 0; + + if (zinfo->max_active_zones == 0) + return 0; + + if (btrfs_dev_is_sequential(device, physical)) { + unsigned int nofs_flags; + + nofs_flags = memalloc_nofs_save(); + ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH, + physical >> SECTOR_SHIFT, + zinfo->zone_size >> SECTOR_SHIFT); + memalloc_nofs_restore(nofs_flags); + + if (ret) + return ret; + } + + if (!(block_group->flags & BTRFS_BLOCK_GROUP_DATA)) + zinfo->reserved_active_zones++; + btrfs_dev_clear_active_zone(device, physical); + + return 0; +} + static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_written) { struct btrfs_fs_info *fs_info = block_group->fs_info; @@ -2329,31 +2363,12 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ down_read(&dev_replace->rwsem); map = block_group->physical_map; for (i = 0; i < map->num_stripes; i++) { - struct btrfs_device *device = map->stripes[i].dev; - const u64 physical = map->stripes[i].physical; - struct btrfs_zoned_device_info *zinfo = device->zone_info; - unsigned int nofs_flags; - - if (!device->bdev) - continue; - - if (zinfo->max_active_zones == 0) - continue; - - nofs_flags = memalloc_nofs_save(); - ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH, - physical >> SECTOR_SHIFT, - zinfo->zone_size >> SECTOR_SHIFT); - memalloc_nofs_restore(nofs_flags); + ret = call_zone_finish(block_group, &map->stripes[i]); if (ret) { up_read(&dev_replace->rwsem); return ret; } - - if (!(block_group->flags & BTRFS_BLOCK_GROUP_DATA)) - zinfo->reserved_active_zones++; - btrfs_dev_clear_active_zone(device, physical); } up_read(&dev_replace->rwsem); From daa0fde322350b467bc62bc1b141bf62df6123f8 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Wed, 16 Jul 2025 16:59:53 +0900 Subject: [PATCH 0121/1292] btrfs: zoned: fix data relocation block group reservation btrfs_zoned_reserve_data_reloc_bg() is called on mount and at that point, all data block groups belong to the primary data space_info. So, we don't find anything in the data relocation space_info. Also, the condition "bg->used > 0" can select a block group with full of zone_unusable bytes for the candidate. As we cannot allocate from the block group, it is useless to reserve it as the data relocation block group. Furthermore, because of the space_info separation, we need to migrate the selected block group to the data relocation space_info. If not, the extent allocator cannot use the block group to do the allocation. This commit fixes these three issues. Fixes: e606ff985ec7 ("btrfs: zoned: reserve data_reloc block group on mount") Reviewed-by: Johannes Thumshirn Signed-off-by: Naohiro Aota Signed-off-by: David Sterba --- fs/btrfs/zoned.c | 55 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 36de6d0d595f80..7a3351b1b0c612 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -17,6 +17,7 @@ #include "accessors.h" #include "bio.h" #include "transaction.h" +#include "sysfs.h" /* Maximum number of zones to report per blkdev_report_zones() call */ #define BTRFS_REPORT_NR_ZONES 4096 @@ -2519,12 +2520,12 @@ void btrfs_clear_data_reloc_bg(struct btrfs_block_group *bg) void btrfs_zoned_reserve_data_reloc_bg(struct btrfs_fs_info *fs_info) { struct btrfs_space_info *data_sinfo = fs_info->data_sinfo; - struct btrfs_space_info *space_info = data_sinfo->sub_group[0]; + struct btrfs_space_info *space_info = data_sinfo; struct btrfs_trans_handle *trans; struct btrfs_block_group *bg; struct list_head *bg_list; u64 alloc_flags; - bool initial = false; + bool first = true; bool did_chunk_alloc = false; int index; int ret; @@ -2538,21 +2539,52 @@ void btrfs_zoned_reserve_data_reloc_bg(struct btrfs_fs_info *fs_info) if (sb_rdonly(fs_info->sb)) return; - ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_DATA_RELOC); alloc_flags = btrfs_get_alloc_profile(fs_info, space_info->flags); index = btrfs_bg_flags_to_raid_index(alloc_flags); - bg_list = &data_sinfo->block_groups[index]; + /* Scan the data space_info to find empty block groups. Take the second one. */ again: + bg_list = &space_info->block_groups[index]; list_for_each_entry(bg, bg_list, list) { - if (bg->used > 0) + if (bg->alloc_offset != 0) continue; - if (!initial) { - initial = true; + if (first) { + first = false; continue; } + if (space_info == data_sinfo) { + /* Migrate the block group to the data relocation space_info. */ + struct btrfs_space_info *reloc_sinfo = data_sinfo->sub_group[0]; + int factor; + + ASSERT(reloc_sinfo->subgroup_id == BTRFS_SUB_GROUP_DATA_RELOC); + factor = btrfs_bg_type_to_factor(bg->flags); + + down_write(&space_info->groups_sem); + list_del_init(&bg->list); + /* We can assume this as we choose the second empty one. */ + ASSERT(!list_empty(&space_info->block_groups[index])); + up_write(&space_info->groups_sem); + + spin_lock(&space_info->lock); + space_info->total_bytes -= bg->length; + space_info->disk_total -= bg->length * factor; + /* There is no allocation ever happened. */ + ASSERT(bg->used == 0); + ASSERT(bg->zone_unusable == 0); + /* No super block in a block group on the zoned setup. */ + ASSERT(bg->bytes_super == 0); + spin_unlock(&space_info->lock); + + bg->space_info = reloc_sinfo; + if (reloc_sinfo->block_group_kobjs[index] == NULL) + btrfs_sysfs_add_block_group_type(bg); + + btrfs_add_bg_to_space_info(fs_info, bg); + } + fs_info->data_reloc_bg = bg->start; set_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC, &bg->runtime_flags); btrfs_zone_activate(bg); @@ -2567,11 +2599,18 @@ void btrfs_zoned_reserve_data_reloc_bg(struct btrfs_fs_info *fs_info) if (IS_ERR(trans)) return; + /* Allocate new BG in the data relocation space_info. */ + space_info = data_sinfo->sub_group[0]; + ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_DATA_RELOC); ret = btrfs_chunk_alloc(trans, space_info, alloc_flags, CHUNK_ALLOC_FORCE); btrfs_end_transaction(trans); if (ret == 1) { + /* + * We allocated a new block group in the data relocation space_info. We + * can take that one. + */ + first = false; did_chunk_alloc = true; - bg_list = &space_info->block_groups[index]; goto again; } } From 5c4b93f4c8e5c53574c1a48d66a27a2c68b414af Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Wed, 16 Jul 2025 16:59:54 +0900 Subject: [PATCH 0122/1292] btrfs: zoned: fix write time activation failure for metadata block group Since commit 13bb483d32ab ("btrfs: zoned: activate metadata block group on write time"), we activate a metadata block group at the write time. If the zone capacity is small enough, we can allocate the entire region before the first write. Then, we hit the btrfs_zoned_bg_is_full() in btrfs_zone_activate() and the activation fails. For a data block group, we activate it at the allocation time and we should check the fullness condition in the caller side. Add, a WARN to check the fullness condition. For a metadata block group, we don't need the fullness check because we activate it at the write time. Instead, activating it once it is written should be invalid. Catch that with a WARN too. Fixes: 13bb483d32ab ("btrfs: zoned: activate metadata block group on write time") CC: stable@vger.kernel.org # 6.6+ Reviewed-by: Johannes Thumshirn Signed-off-by: Naohiro Aota Signed-off-by: David Sterba --- fs/btrfs/zoned.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 7a3351b1b0c612..ab6844dce8bc13 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -2169,10 +2169,15 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group) goto out_unlock; } - /* No space left */ - if (btrfs_zoned_bg_is_full(block_group)) { - ret = false; - goto out_unlock; + if (block_group->flags & BTRFS_BLOCK_GROUP_DATA) { + /* The caller should check if the block group is full. */ + if (WARN_ON_ONCE(btrfs_zoned_bg_is_full(block_group))) { + ret = false; + goto out_unlock; + } + } else { + /* Since it is already written, it should have been active. */ + WARN_ON_ONCE(block_group->meta_write_pointer != block_group->start); } for (i = 0; i < map->num_stripes; i++) { From 04147d8394e80acaaebf0365f112339e8b606c05 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Wed, 16 Jul 2025 16:59:55 +0900 Subject: [PATCH 0123/1292] btrfs: zoned: limit active zones to max_open_zones When there is no active zone limit, we can technically write into any number of zones at the same time. However, exceeding the max open zones can degrade performance. To prevent this, set the max_active_zones to bdev_max_open_zones() if there is no active zone limit. Reviewed-by: Johannes Thumshirn Signed-off-by: Naohiro Aota Signed-off-by: David Sterba --- fs/btrfs/zoned.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index ab6844dce8bc13..e0ee3aeabd2c89 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -43,6 +43,9 @@ /* Number of superblock log zones */ #define BTRFS_NR_SB_LOG_ZONES 2 +/* Default number of max active zones when the device has no limits. */ +#define BTRFS_DEFAULT_MAX_ACTIVE_ZONES 128 + /* * Minimum of active zones we need: * @@ -417,7 +420,10 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache) if (!IS_ALIGNED(nr_sectors, zone_sectors)) zone_info->nr_zones++; - max_active_zones = bdev_max_active_zones(bdev); + max_active_zones = min_not_zero(bdev_max_active_zones(bdev), + bdev_max_open_zones(bdev)); + if (!max_active_zones && zone_info->nr_zones > BTRFS_DEFAULT_MAX_ACTIVE_ZONES) + max_active_zones = BTRFS_DEFAULT_MAX_ACTIVE_ZONES; if (max_active_zones && max_active_zones < BTRFS_MIN_ACTIVE_ZONES) { btrfs_err(fs_info, "zoned: %s: max active zones %u is too small, need at least %u active zones", From 085a1b42e52750769a3fa29d4da6c05ab56f18f8 Mon Sep 17 00:00:00 2001 From: wenglianfa Date: Sat, 26 Jul 2025 15:53:45 +0800 Subject: [PATCH 0124/1292] RDMA/hns: Fix querying wrong SCC context for DIP algorithm When using DIP algorithm, all QPs establishing connections with the same destination IP share the same SCC, which is indexed by dip_idx, but dip_idx isn't necessarily equal to qpn. Therefore, dip_idx should be used to query SCC context instead of qpn. Fixes: 124a9fbe43aa ("RDMA/hns: Append SCC context to the raw dump of QPC") Signed-off-by: wenglianfa Signed-off-by: Junxian Huang Link: https://patch.msgid.link/20250726075345.846957-1-huangjunxian6@hisilicon.com Reviewed-by: Zhu Yanjun Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 4 ++-- drivers/infiniband/hw/hns/hns_roce_restrack.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 64bca08f3f1a74..244a4780d3a65d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -5476,7 +5476,7 @@ static int hns_roce_v2_query_srqc(struct hns_roce_dev *hr_dev, u32 srqn, return ret; } -static int hns_roce_v2_query_sccc(struct hns_roce_dev *hr_dev, u32 qpn, +static int hns_roce_v2_query_sccc(struct hns_roce_dev *hr_dev, u32 sccn, void *buffer) { struct hns_roce_v2_scc_context *context; @@ -5488,7 +5488,7 @@ static int hns_roce_v2_query_sccc(struct hns_roce_dev *hr_dev, u32 qpn, return PTR_ERR(mailbox); ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma, HNS_ROCE_CMD_QUERY_SCCC, - qpn); + sccn); if (ret) goto out; diff --git a/drivers/infiniband/hw/hns/hns_roce_restrack.c b/drivers/infiniband/hw/hns/hns_roce_restrack.c index f637b73b946e44..230187dda6a07b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_restrack.c +++ b/drivers/infiniband/hw/hns/hns_roce_restrack.c @@ -100,6 +100,7 @@ int hns_roce_fill_res_qp_entry_raw(struct sk_buff *msg, struct ib_qp *ib_qp) struct hns_roce_v2_qp_context qpc; struct hns_roce_v2_scc_context sccc; } context = {}; + u32 sccn = hr_qp->qpn; int ret; if (!hr_dev->hw->query_qpc) @@ -116,7 +117,13 @@ int hns_roce_fill_res_qp_entry_raw(struct sk_buff *msg, struct ib_qp *ib_qp) !hr_dev->hw->query_sccc) goto out; - ret = hr_dev->hw->query_sccc(hr_dev, hr_qp->qpn, &context.sccc); + if (hr_qp->cong_type == CONG_TYPE_DIP) { + if (!hr_qp->dip) + goto out; + sccn = hr_qp->dip->dip_idx; + } + + ret = hr_dev->hw->query_sccc(hr_dev, sccn, &context.sccc); if (ret) ibdev_warn_ratelimited(&hr_dev->ib_dev, "failed to query SCCC, ret = %d.\n", From 6296f9a5293ada28558f2867ac54c487e1e2b9f2 Mon Sep 17 00:00:00 2001 From: Kashyap Desai Date: Tue, 5 Aug 2025 15:39:57 +0530 Subject: [PATCH 0125/1292] RDMA/bnxt_re: Fix to do SRQ armena by default Whenever SRQ is created, make sure SRQ arm enable is always set. Driver is always ready to receive SRQ ASYNC event. Additional note - There is no need to do srq arm enable conditionally. See bnxt_qplib_armen_db in bnxt_qplib_create_cq(). Fixes: 37cb11acf1f7 ("RDMA/bnxt_re: Add SRQ support for Broadcom adapters") Signed-off-by: Kashyap Desai Signed-off-by: Saravanan Vajravel Link: https://patch.msgid.link/20250805101000.233310-2-kalesh-anakkur.purayil@broadcom.com Reviewed-by: Kalesh AP Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index dfe3177123e545..b2c1240775f4e5 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -705,8 +705,7 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, srq->dbinfo.db = srq->dpi->dbr; srq->dbinfo.max_slot = 1; srq->dbinfo.priv_db = res->dpi_tbl.priv_db; - if (srq->threshold) - bnxt_qplib_armen_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ_ARMENA); + bnxt_qplib_armen_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ_ARMENA); srq->arm_req = false; return 0; From 666bce0bd7e771127cb0cda125cc9d32d9f9f15d Mon Sep 17 00:00:00 2001 From: Kashyap Desai Date: Tue, 5 Aug 2025 15:39:58 +0530 Subject: [PATCH 0126/1292] RDMA/bnxt_re: Fix to remove workload check in SRQ limit path There should not be any checks of current workload to set srq_limit value to SRQ hw context. Remove all such workload checks and make a direct call to set srq_limit via doorbell SRQ_ARM. Fixes: 37cb11acf1f7 ("RDMA/bnxt_re: Add SRQ support for Broadcom adapters") Signed-off-by: Kashyap Desai Signed-off-by: Saravanan Vajravel Signed-off-by: Kalesh AP Link: https://patch.msgid.link/20250805101000.233310-3-kalesh-anakkur.purayil@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 8 ++----- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 27 ------------------------ drivers/infiniband/hw/bnxt_re/qplib_fp.h | 2 -- 3 files changed, 2 insertions(+), 35 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 37c2bc3bdba5e1..260dc67b8b87c9 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1921,7 +1921,6 @@ int bnxt_re_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr, struct bnxt_re_srq *srq = container_of(ib_srq, struct bnxt_re_srq, ib_srq); struct bnxt_re_dev *rdev = srq->rdev; - int rc; switch (srq_attr_mask) { case IB_SRQ_MAX_WR: @@ -1933,11 +1932,8 @@ int bnxt_re_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr, return -EINVAL; srq->qplib_srq.threshold = srq_attr->srq_limit; - rc = bnxt_qplib_modify_srq(&rdev->qplib_res, &srq->qplib_srq); - if (rc) { - ibdev_err(&rdev->ibdev, "Modify HW SRQ failed!"); - return rc; - } + bnxt_qplib_srq_arm_db(&srq->qplib_srq.dbinfo, srq->qplib_srq.threshold); + /* On success, update the shadow */ srq->srq_limit = srq_attr->srq_limit; /* No need to Build and send response back to udata */ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index b2c1240775f4e5..ee36b3d82cc0a5 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -706,7 +706,6 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, srq->dbinfo.max_slot = 1; srq->dbinfo.priv_db = res->dpi_tbl.priv_db; bnxt_qplib_armen_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ_ARMENA); - srq->arm_req = false; return 0; fail: @@ -716,24 +715,6 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, return rc; } -int bnxt_qplib_modify_srq(struct bnxt_qplib_res *res, - struct bnxt_qplib_srq *srq) -{ - struct bnxt_qplib_hwq *srq_hwq = &srq->hwq; - u32 count; - - count = __bnxt_qplib_get_avail(srq_hwq); - if (count > srq->threshold) { - srq->arm_req = false; - bnxt_qplib_srq_arm_db(&srq->dbinfo, srq->threshold); - } else { - /* Deferred arming */ - srq->arm_req = true; - } - - return 0; -} - int bnxt_qplib_query_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_srq *srq) { @@ -775,7 +756,6 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, struct bnxt_qplib_hwq *srq_hwq = &srq->hwq; struct rq_wqe *srqe; struct sq_sge *hw_sge; - u32 count = 0; int i, next; spin_lock(&srq_hwq->lock); @@ -807,15 +787,8 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, bnxt_qplib_hwq_incr_prod(&srq->dbinfo, srq_hwq, srq->dbinfo.max_slot); - spin_lock(&srq_hwq->lock); - count = __bnxt_qplib_get_avail(srq_hwq); - spin_unlock(&srq_hwq->lock); /* Ring DB */ bnxt_qplib_ring_prod_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ); - if (srq->arm_req == true && count > srq->threshold) { - srq->arm_req = false; - bnxt_qplib_srq_arm_db(&srq->dbinfo, srq->threshold); - } return 0; } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index ab125f1d949eed..4921a214c34c12 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -546,8 +546,6 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, srqn_handler_t srq_handler); int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_srq *srq); -int bnxt_qplib_modify_srq(struct bnxt_qplib_res *res, - struct bnxt_qplib_srq *srq); int bnxt_qplib_query_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_srq *srq); void bnxt_qplib_destroy_srq(struct bnxt_qplib_res *res, From ba60a1e8cbbd396c69ff9c8bc3242f5ab133e38a Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 5 Aug 2025 15:39:59 +0530 Subject: [PATCH 0127/1292] RDMA/bnxt_re: Fix a possible memory leak in the driver The GID context reuse logic requires the context memory to be not freed if and when DEL_GID firmware command fails. But, if there's no subsequent ADD_GID to reuse it, the context memory must be freed when the driver is unloaded. Otherwise it leads to a memory leak. Below is the kmemleak trace reported: unreferenced object 0xffff88817a4f34d0 (size 8): comm "insmod", pid 1072504, jiffies 4402561550 hex dump (first 8 bytes): 01 00 00 00 00 00 00 00 ........ backtrace (crc ccaa009e): __kmalloc_cache_noprof+0x33e/0x400 0xffffffffc2db9d48 add_modify_gid+0x5e0/0xb60 [ib_core] __ib_cache_gid_add+0x213/0x350 [ib_core] update_gid+0xf2/0x180 [ib_core] enum_netdev_ipv4_ips+0x3f3/0x690 [ib_core] enum_all_gids_of_dev_cb+0x125/0x1b0 [ib_core] ib_enum_roce_netdev+0x14b/0x250 [ib_core] ib_cache_setup_one+0x2e5/0x540 [ib_core] ib_register_device+0x82c/0xf10 [ib_core] 0xffffffffc2df5ad9 0xffffffffc2da8b07 0xffffffffc2db174d auxiliary_bus_probe+0xa5/0x120 really_probe+0x1e4/0x850 __driver_probe_device+0x18f/0x3d0 Fixes: 4a62c5e9e2e1 ("RDMA/bnxt_re: Do not free the ctx_tbl entry if delete GID fails") Signed-off-by: Kalesh AP Link: https://patch.msgid.link/20250805101000.233310-4-kalesh-anakkur.purayil@broadcom.com Reviewed-by: Sriharsha Basavapatna Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/main.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 293b0a96c8e3ec..df7cf8d68e273f 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -2017,6 +2017,28 @@ static void bnxt_re_free_nqr_mem(struct bnxt_re_dev *rdev) rdev->nqr = NULL; } +/* When DEL_GID fails, driver is not freeing GID ctx memory. + * To avoid the memory leak, free the memory during unload + */ +static void bnxt_re_free_gid_ctx(struct bnxt_re_dev *rdev) +{ + struct bnxt_qplib_sgid_tbl *sgid_tbl = &rdev->qplib_res.sgid_tbl; + struct bnxt_re_gid_ctx *ctx, **ctx_tbl; + int i; + + if (!sgid_tbl->active) + return; + + ctx_tbl = sgid_tbl->ctx; + for (i = 0; i < sgid_tbl->max; i++) { + if (sgid_tbl->hw_id[i] == 0xFFFF) + continue; + + ctx = ctx_tbl[i]; + kfree(ctx); + } +} + static void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev, u8 op_type) { u8 type; @@ -2030,6 +2052,7 @@ static void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev, u8 op_type) if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags)) cancel_delayed_work_sync(&rdev->worker); + bnxt_re_free_gid_ctx(rdev); if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED, &rdev->flags)) bnxt_re_cleanup_res(rdev); From 806b9f494f62791ee6d68f515a8056c615a0e7b2 Mon Sep 17 00:00:00 2001 From: Anantha Prabhu Date: Tue, 5 Aug 2025 15:40:00 +0530 Subject: [PATCH 0128/1292] RDMA/bnxt_re: Fix to initialize the PBL array memset the PBL page pointer and page map arrays before populating the SGL addresses of the HWQ. Fixes: 0c4dcd602817 ("RDMA/bnxt_re: Refactor hardware queue memory allocation") Signed-off-by: Anantha Prabhu Reviewed-by: Saravanan Vajravel Reviewed-by: Selvin Xavier Signed-off-by: Kalesh AP Link: https://patch.msgid.link/20250805101000.233310-5-kalesh-anakkur.purayil@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_res.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 6cd05207ffeddf..cc5c82d968395a 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -121,6 +121,7 @@ static int __alloc_pbl(struct bnxt_qplib_res *res, pbl->pg_arr = vmalloc_array(pages, sizeof(void *)); if (!pbl->pg_arr) return -ENOMEM; + memset(pbl->pg_arr, 0, pages * sizeof(void *)); pbl->pg_map_arr = vmalloc_array(pages, sizeof(dma_addr_t)); if (!pbl->pg_map_arr) { @@ -128,6 +129,7 @@ static int __alloc_pbl(struct bnxt_qplib_res *res, pbl->pg_arr = NULL; return -ENOMEM; } + memset(pbl->pg_map_arr, 0, pages * sizeof(dma_addr_t)); pbl->pg_count = 0; pbl->pg_size = sginfo->pgsize; From 2186e8c39eb156b3557a467ce4e5dc3f24826609 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 8 Aug 2025 10:56:01 -0700 Subject: [PATCH 0129/1292] MAINTAINERS: Remove bouncing irdma maintainer This maintainer's email no longer works. Remove it from MAINTAINERS. This still leaves one maintainer for the driver. Signed-off-by: Dave Hansen Cc: Tatyana Nikolova Cc: linux-rdma@vger.kernel.org Link: https://patch.msgid.link/20250808175601.EF0AF767@davehans-spike.ostc.intel.com Signed-off-by: Leon Romanovsky --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa457..b31fd6e7539c05 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12280,7 +12280,6 @@ F: include/linux/avf/virtchnl.h F: include/linux/net/intel/*/ INTEL ETHERNET PROTOCOL DRIVER FOR RDMA -M: Mustafa Ismail M: Tatyana Nikolova L: linux-rdma@vger.kernel.org S: Supported From 111aea0464c20f3eb25a48d5ff6c036e6b416123 Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Sun, 10 Aug 2025 23:21:58 +0530 Subject: [PATCH 0130/1292] RDMA/core: Free pfn_list with appropriate kvfree call Ensure that pfn_list allocated by kvcalloc() is freed using corresponding kvfree() function. Match memory allocation and free routines kvcalloc -> kvfree. Fixes: 259e9bd07c57 ("RDMA/core: Avoid hmm_dma_map_alloc() for virtual DMA devices") Signed-off-by: Akhilesh Patil Link: https://patch.msgid.link/aJjcPjL1BVh8QrMN@bhairav-test.ee.iitb.ac.in Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/umem_odp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index b1c44ec1a3f36d..572a91a62a7bea 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -115,7 +115,7 @@ static int ib_init_umem_odp(struct ib_umem_odp *umem_odp, out_free_map: if (ib_uses_virt_dma(dev)) - kfree(map->pfn_list); + kvfree(map->pfn_list); else hmm_dma_map_free(dev->dma_device, map); return ret; @@ -287,7 +287,7 @@ static void ib_umem_odp_free(struct ib_umem_odp *umem_odp) mutex_unlock(&umem_odp->umem_mutex); mmu_interval_notifier_remove(&umem_odp->notifier); if (ib_uses_virt_dma(dev)) - kfree(umem_odp->map.pfn_list); + kvfree(umem_odp->map.pfn_list); else hmm_dma_map_free(dev->dma_device, &umem_odp->map); } From 185c926283da67a72df20a63a5046b3b4631b7d9 Mon Sep 17 00:00:00 2001 From: Minjong Kim Date: Wed, 13 Aug 2025 19:30:22 +0900 Subject: [PATCH 0131/1292] HID: hid-ntrig: fix unable to handle page fault in ntrig_report_version() in ntrig_report_version(), hdev parameter passed from hid_probe(). sending descriptor to /dev/uhid can make hdev->dev.parent->parent to null if hdev->dev.parent->parent is null, usb_dev has invalid address(0xffffffffffffff58) that hid_to_usb_dev(hdev) returned when usb_rcvctrlpipe() use usb_dev,it trigger page fault error for address(0xffffffffffffff58) add null check logic to ntrig_report_version() before calling hid_to_usb_dev() Signed-off-by: Minjong Kim Link: https://patch.msgid.link/20250813-hid-ntrig-page-fault-fix-v2-1-f98581f35106@samsung.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-ntrig.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 2738ce947434f9..0f76e241e0afb4 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev) struct usb_device *usb_dev = hid_to_usb_dev(hdev); unsigned char *data = kmalloc(8, GFP_KERNEL); + if (!hid_is_usb(hdev)) + return; + if (!data) goto err_free; From fa2e2d31ee3b7212079323b4b09201ef68af3a97 Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Tue, 12 Aug 2025 20:26:02 +0800 Subject: [PATCH 0132/1292] RDMA/hns: Fix dip entries leak on devices newer than hip09 DIP algorithm is also supported on devices newer than hip09, so free dip entries too. Fixes: f91696f2f053 ("RDMA/hns: Support congestion control type selection according to the FW") Signed-off-by: Junxian Huang Link: https://patch.msgid.link/20250812122602.3524602-1-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 244a4780d3a65d..f82bdd46a9174a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3043,7 +3043,7 @@ static void hns_roce_v2_exit(struct hns_roce_dev *hr_dev) if (!hr_dev->is_vf) hns_roce_free_link_table(hr_dev); - if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP09) + if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) free_dip_entry(hr_dev); } From 25db5f284fb8f30222146ca15b3ab8265789da38 Mon Sep 17 00:00:00 2001 From: Xiao Ni Date: Wed, 13 Aug 2025 11:29:29 +0800 Subject: [PATCH 0133/1292] md: add legacy_async_del_gendisk mode commit 9e59d609763f ("md: call del_gendisk in control path") changes the async way to sync way of calling del_gendisk. But it breaks mdadm --assemble command. The assemble command runs like this: 1. create the array 2. stop the array 3. access the sysfs files after stopping The sync way calls del_gendisk in step 2, so all sysfs files are removed. Now to avoid breaking mdadm assemble command, this patch adds the parameter legacy_async_del_gendisk that can be used to choose which way. The default is async way. In future, we plan to change default to sync way in kernel 7.0. Then users need to upgrade to mdadm 4.5+ which removes step 2. Fixes: 9e59d609763f ("md: call del_gendisk in control path") Reported-by: Mikulas Patocka Closes: https://lore.kernel.org/linux-raid/CAMw=ZnQ=ET2St-+hnhsuq34rRPnebqcXqP1QqaHW5Bh4aaaZ4g@mail.gmail.com/T/#t Suggested-and-reviewed-by: Yu Kuai Signed-off-by: Xiao Ni Reviewed-by: Paul Menzel Link: https://lore.kernel.org/linux-raid/20250813032929.54978-1-xni@redhat.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 56 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index ac85ec73a409e7..772cffe02ff5c9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -339,6 +339,7 @@ static int start_readonly; * so all the races disappear. */ static bool create_on_open = true; +static bool legacy_async_del_gendisk = true; /* * We have a system wide 'event count' that is incremented @@ -877,15 +878,18 @@ void mddev_unlock(struct mddev *mddev) export_rdev(rdev, mddev); } - /* Call del_gendisk after release reconfig_mutex to avoid - * deadlock (e.g. call del_gendisk under the lock and an - * access to sysfs files waits the lock) - * And MD_DELETED is only used for md raid which is set in - * do_md_stop. dm raid only uses md_stop to stop. So dm raid - * doesn't need to check MD_DELETED when getting reconfig lock - */ - if (test_bit(MD_DELETED, &mddev->flags)) - del_gendisk(mddev->gendisk); + if (!legacy_async_del_gendisk) { + /* + * Call del_gendisk after release reconfig_mutex to avoid + * deadlock (e.g. call del_gendisk under the lock and an + * access to sysfs files waits the lock) + * And MD_DELETED is only used for md raid which is set in + * do_md_stop. dm raid only uses md_stop to stop. So dm raid + * doesn't need to check MD_DELETED when getting reconfig lock + */ + if (test_bit(MD_DELETED, &mddev->flags)) + del_gendisk(mddev->gendisk); + } } EXPORT_SYMBOL_GPL(mddev_unlock); @@ -5818,6 +5822,13 @@ static void md_kobj_release(struct kobject *ko) { struct mddev *mddev = container_of(ko, struct mddev, kobj); + if (legacy_async_del_gendisk) { + if (mddev->sysfs_state) + sysfs_put(mddev->sysfs_state); + if (mddev->sysfs_level) + sysfs_put(mddev->sysfs_level); + del_gendisk(mddev->gendisk); + } put_disk(mddev->gendisk); } @@ -6021,6 +6032,9 @@ static int md_alloc_and_put(dev_t dev, char *name) { struct mddev *mddev = md_alloc(dev, name); + if (legacy_async_del_gendisk) + pr_warn("md: async del_gendisk mode will be removed in future, please upgrade to mdadm-4.5+\n"); + if (IS_ERR(mddev)) return PTR_ERR(mddev); mddev_put(mddev); @@ -6431,10 +6445,22 @@ static void md_clean(struct mddev *mddev) mddev->persistent = 0; mddev->level = LEVEL_NONE; mddev->clevel[0] = 0; - /* if UNTIL_STOP is set, it's cleared here */ - mddev->hold_active = 0; - /* Don't clear MD_CLOSING, or mddev can be opened again. */ - mddev->flags &= BIT_ULL_MASK(MD_CLOSING); + + /* + * For legacy_async_del_gendisk mode, it can stop the array in the + * middle of assembling it, then it still can access the array. So + * it needs to clear MD_CLOSING. If not legacy_async_del_gendisk, + * it can't open the array again after stopping it. So it doesn't + * clear MD_CLOSING. + */ + if (legacy_async_del_gendisk && mddev->hold_active) { + clear_bit(MD_CLOSING, &mddev->flags); + } else { + /* if UNTIL_STOP is set, it's cleared here */ + mddev->hold_active = 0; + /* Don't clear MD_CLOSING, or mddev can be opened again. */ + mddev->flags &= BIT_ULL_MASK(MD_CLOSING); + } mddev->sb_flags = 0; mddev->ro = MD_RDWR; mddev->metadata_type[0] = 0; @@ -6658,7 +6684,8 @@ static int do_md_stop(struct mddev *mddev, int mode) export_array(mddev); md_clean(mddev); - set_bit(MD_DELETED, &mddev->flags); + if (!legacy_async_del_gendisk) + set_bit(MD_DELETED, &mddev->flags); } md_new_event(); sysfs_notify_dirent_safe(mddev->sysfs_state); @@ -10392,6 +10419,7 @@ module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR); module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR); module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR); module_param(create_on_open, bool, S_IRUSR|S_IWUSR); +module_param(legacy_async_del_gendisk, bool, 0600); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MD RAID framework"); From afa17a09c699410113199dc15256c6ea2b4133f7 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Wed, 6 Aug 2025 08:23:32 +0800 Subject: [PATCH 0134/1292] HID: intel-thc-hid: Intel-quicki2c: Enhance driver re-install flow After driver module is removed and during re-install stage, if there is continueous user touching on the screen, it is a risk impacting THC hardware initialization which causes driver installation failure. This patch enhances this flow by quiescing the external touch interrupt after driver is removed which keeps THC hardware ignore external interrupt during this remove and re-install stage. Signed-off-by: Even Xu Tested-by: Rui Zhang Fixes: 66b59bfce6d9 ("HID: intel-thc-hid: intel-quicki2c: Complete THC QuickI2C driver") Signed-off-by: Jiri Kosina --- drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c index e944a6ccb776cc..854926b3cfd455 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c @@ -419,6 +419,7 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io */ static void quicki2c_dev_deinit(struct quicki2c_device *qcdev) { + thc_interrupt_quiesce(qcdev->thc_hw, true); thc_interrupt_enable(qcdev->thc_hw, false); thc_ltr_unconfig(qcdev->thc_hw); thc_wot_unconfig(qcdev->thc_hw); From 4bcd3061e8154606af7f721cb75ca04ffe191a12 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 29 Jul 2025 19:01:45 +0930 Subject: [PATCH 0135/1292] btrfs: clear block dirty if submit_one_sector() failed [BUG] If submit_one_sector() failed, the block will be kept dirty, but with their corresponding range finished in the ordered extent. This means if a writeback happens later again, we can hit the following problems: - ASSERT(block_start != EXTENT_MAP_HOLE) in submit_one_sector() If the original extent map is a hole, then we can hit this case, as the new ordered extent failed, we will drop the new extent map and re-read one from the disk. - DEBUG_WARN() in btrfs_writepage_cow_fixup() This is because we no longer have an ordered extent for those dirty blocks. The original for them is already finished with error. [CAUSE] The function submit_one_sector() is not following the regular error handling of writeback. The common practice is to clear the folio dirty, start and finish the writeback for the block. This is normally done by extent_clear_unlock_delalloc() with PAGE_START_WRITEBACK | PAGE_END_WRITEBACK flags during run_delalloc_range(). So if we keep those failed blocks dirty, they will stay in the page cache and wait for the next writeback. And since the original ordered extent is already finished and removed, depending on the original extent map, we either hit the ASSERT() inside submit_one_sector(), or hit the DEBUG_WARN() in btrfs_writepage_cow_fixup(). [FIX] Follow the regular error handling to clear the dirty flag for the block, start and finish writeback for that block instead. Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index f23d75986947cc..741c2048009950 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1512,7 +1512,7 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode, /* * Return 0 if we have submitted or queued the sector for submission. - * Return <0 for critical errors. + * Return <0 for critical errors, and the sector will have its dirty flag cleared. * * Caller should make sure filepos < i_size and handle filepos >= i_size case. */ @@ -1535,8 +1535,17 @@ static int submit_one_sector(struct btrfs_inode *inode, ASSERT(filepos < i_size); em = btrfs_get_extent(inode, NULL, filepos, sectorsize); - if (IS_ERR(em)) + if (IS_ERR(em)) { + /* + * When submission failed, we should still clear the folio dirty. + * Or the folio will be written back again but without any + * ordered extent. + */ + btrfs_folio_clear_dirty(fs_info, folio, filepos, sectorsize); + btrfs_folio_set_writeback(fs_info, folio, filepos, sectorsize); + btrfs_folio_clear_writeback(fs_info, folio, filepos, sectorsize); return PTR_ERR(em); + } extent_offset = filepos - em->start; em_end = btrfs_extent_map_end(em); @@ -1666,8 +1675,8 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, * Here we set writeback and clear for the range. If the full folio * is no longer dirty then we clear the PAGECACHE_TAG_DIRTY tag. * - * If we hit any error, the corresponding sector will still be dirty - * thus no need to clear PAGECACHE_TAG_DIRTY. + * If we hit any error, the corresponding sector will have its dirty + * flag cleared and writeback finished, thus no need to handle the error case. */ if (!submitted_io && !error) { btrfs_folio_set_writeback(fs_info, folio, start, len); From 05b372862600e551bbf86e7f24a1caeed5e06150 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 29 Jul 2025 19:01:46 +0930 Subject: [PATCH 0136/1292] btrfs: clear block dirty if btrfs_writepage_cow_fixup() failed [BUG] If btrfs_writepage_cow_fixup() failed (returning value -EUCLEAN), the block will be kept dirty, but with its corresponding range finished in the ordered extent. Currently that error pattern is only possible for experimental builds, which places extra check to ensure we shouldn't hit a dirty block without a corresponding ordered extent. This means if later a writeback happens again, we can hit the following problems: - ASSERT(block_start != EXTENT_MAP_HOLE) in submit_one_sector() If the original extent map is a hole, then we can hit this case, as the new ordered extent failed, we will drop the new extent map and re-read one from the disk. - DEBUG_WARN() in btrfs_writepage_cow_fixup() This is because we no longer have an ordered extent for those dirty blocks. The original for them is already finished with error. [CAUSE] The function btrfs_writepage_cow_fixup() is not following the regular error handling of writeback. The common practice is to clear the folio dirty, start and finish the writeback for the block. This is normally done by extent_clear_unlock_delalloc() with PAGE_START_WRITEBACK | PAGE_END_WRITEBACK flags during run_delalloc_range(). So if we keep those failed blocks dirty, they will stay in the page cache and wait for the next writeback. And since the original ordered extent is already finished and removed, depending on the original extent map, we either hit the ASSERT() inside submit_one_sector(), or hit the DEBUG_WARN() in btrfs_writepage_cow_fixup() again (and very ironic). [FIX] Follow the regular error handling to clear the dirty flag for the block range, start and finish writeback for that block range instead. Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 741c2048009950..be9c9c80495229 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1618,8 +1618,12 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, folio_unlock(folio); return 1; } - if (ret < 0) + if (ret < 0) { + btrfs_folio_clear_dirty(fs_info, folio, start, len); + btrfs_folio_set_writeback(fs_info, folio, start, len); + btrfs_folio_clear_writeback(fs_info, folio, start, len); return ret; + } for (cur = start; cur < start + len; cur += fs_info->sectorsize) set_bit((cur - folio_start) >> fs_info->sectorsize_bits, &range_bitmap); From f022499f24e520706b9a8238746e1cacc37eb4e0 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 1 Aug 2025 16:39:49 +0100 Subject: [PATCH 0137/1292] btrfs: do not set mtime/ctime to current time when unlinking for log replay If we are doing an unlink for log replay, we are updating the directory's mtime and ctime to the current time, and this is incorrect since it should stay with the mtime and ctime that were set when the directory was logged. This is the same as when adding a link to an inode during log replay (with btrfs_add_link()), where we want the mtime and ctime to be the values that were in place when the inode was logged. This was found with generic/547 using LOAD_FACTOR=20 and TIME_FACTOR=20, where due to large log trees we have longer log replay times and fssum could detect a mismatch of the mtime and ctime of a directory. Fix this by skipping the mtime and ctime update at __btrfs_unlink_inode() if we are in log replay context (just like btrfs_add_link()). Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/inode.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d740910e071a32..9e4aec7330cb61 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4189,6 +4189,23 @@ int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, return ret; } +static void update_time_after_link_or_unlink(struct btrfs_inode *dir) +{ + struct timespec64 now; + + /* + * If we are replaying a log tree, we do not want to update the mtime + * and ctime of the parent directory with the current time, since the + * log replay procedure is responsible for setting them to their correct + * values (the ones it had when the fsync was done). + */ + if (test_bit(BTRFS_FS_LOG_RECOVERING, &dir->root->fs_info->flags)) + return; + + now = inode_set_ctime_current(&dir->vfs_inode); + inode_set_mtime_to_ts(&dir->vfs_inode, now); +} + /* * unlink helper that gets used here in inode.c and in the tree logging * recovery code. It remove a link in a directory with a given name, and @@ -4289,7 +4306,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, inode_inc_iversion(&inode->vfs_inode); inode_set_ctime_current(&inode->vfs_inode); inode_inc_iversion(&dir->vfs_inode); - inode_set_mtime_to_ts(&dir->vfs_inode, inode_set_ctime_current(&dir->vfs_inode)); + update_time_after_link_or_unlink(dir); return btrfs_update_inode(trans, dir); } @@ -6683,15 +6700,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, btrfs_i_size_write(parent_inode, parent_inode->vfs_inode.i_size + name->len * 2); inode_inc_iversion(&parent_inode->vfs_inode); - /* - * If we are replaying a log tree, we do not want to update the mtime - * and ctime of the parent directory with the current time, since the - * log replay procedure is responsible for setting them to their correct - * values (the ones it had when the fsync was done). - */ - if (!test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags)) - inode_set_mtime_to_ts(&parent_inode->vfs_inode, - inode_set_ctime_current(&parent_inode->vfs_inode)); + update_time_after_link_or_unlink(parent_inode); ret = btrfs_update_inode(trans, parent_inode); if (ret) From 1f3d56db694cce6dfbffba0f398a06a222204487 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 31 Jul 2025 08:20:01 +0930 Subject: [PATCH 0138/1292] btrfs: clear TAG_TOWRITE from buffer tree when submitting a tree block [POSSIBLE BUG] After commit 5e121ae687b8 ("btrfs: use buffer xarray for extent buffer writeback operations"), we have a dedicated xarray for extent buffers, and a lot of tags are migrated to that buffer tree, like PAGECACHE_TAG_TOWRITE/DIRTY/WRITEBACK. This frees us from the limits of page flags, but there is a new asymmetric behavior, we call buffer_tree_tag_for_writeback() to set PAGECACHE_TAG_TOWRITE for the involved ranges, but there is no one to clear that tag. Before that rework, we relied on the page cache tag which was cleared when folio_start_writeback() was called. Although this has its own problems (e.g. the first one calling folio_start_writeback() will clear the tag for the whole page), it at least cleared the tag. But now our real tags are stored in the buffer tree, no one is really clearing the PAGECACHE_TAG_TOWRITE tag now. [FIX] Thankfully this is not going to cause any real bug, but just some inefficiency iterating the extent buffers. As if we hit an extent buffer which is not dirty but still has the PAGECACHE_TAG_TOWRITE tag, lock_extent_buffer_for_io() will skip it so we won't writeback the extent buffer again. To properly fix the inefficiency, just clear the PAGECACHE_TAG_TOWRITE inside lock_extent_buffer_for_io(). There is no error path between lock_extent_buffer_for_io() and write_one_eb(), so we're safe to clear the tag there. Reviewed-by: Naohiro Aota Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index be9c9c80495229..c953297aa89a01 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1826,6 +1826,7 @@ static noinline_for_stack bool lock_extent_buffer_for_io(struct extent_buffer *e xas_load(&xas); xas_set_mark(&xas, PAGECACHE_TAG_WRITEBACK); xas_clear_mark(&xas, PAGECACHE_TAG_DIRTY); + xas_clear_mark(&xas, PAGECACHE_TAG_TOWRITE); xas_unlock_irqrestore(&xas, flags); btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); From b1511360c8ac882b0c52caa263620538e8d73220 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Thu, 31 Jul 2025 12:46:56 +0900 Subject: [PATCH 0139/1292] btrfs: subpage: keep TOWRITE tag until folio is cleaned btrfs_subpage_set_writeback() calls folio_start_writeback() the first time a folio is written back, and it also clears the PAGECACHE_TAG_TOWRITE tag even if there are still dirty blocks in the folio. This can break ordering guarantees, such as those required by btrfs_wait_ordered_extents(). That ordering breakage leads to a real failure. For example, running generic/464 on a zoned setup will hit the following ASSERT. This happens because the broken ordering fails to flush existing dirty pages before the file size is truncated. assertion failed: !list_empty(&ordered->list) :: 0, in fs/btrfs/zoned.c:1899 ------------[ cut here ]------------ kernel BUG at fs/btrfs/zoned.c:1899! Oops: invalid opcode: 0000 [#1] SMP NOPTI CPU: 2 UID: 0 PID: 1906169 Comm: kworker/u130:2 Kdump: loaded Not tainted 6.16.0-rc6-BTRFS-ZNS+ #554 PREEMPT(voluntary) Hardware name: Supermicro Super Server/H12SSL-NT, BIOS 2.0 02/22/2021 Workqueue: btrfs-endio-write btrfs_work_helper [btrfs] RIP: 0010:btrfs_finish_ordered_zoned.cold+0x50/0x52 [btrfs] RSP: 0018:ffffc9002efdbd60 EFLAGS: 00010246 RAX: 000000000000004c RBX: ffff88811923c4e0 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffffffff827e38b1 RDI: 00000000ffffffff RBP: ffff88810005d000 R08: 00000000ffffdfff R09: ffffffff831051c8 R10: ffffffff83055220 R11: 0000000000000000 R12: ffff8881c2458c00 R13: ffff88811923c540 R14: ffff88811923c5e8 R15: ffff8881c1bd9680 FS: 0000000000000000(0000) GS:ffff88a04acd0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f907c7a918c CR3: 0000000004024000 CR4: 0000000000350ef0 Call Trace: ? srso_return_thunk+0x5/0x5f btrfs_finish_ordered_io+0x4a/0x60 [btrfs] btrfs_work_helper+0xf9/0x490 [btrfs] process_one_work+0x204/0x590 ? srso_return_thunk+0x5/0x5f worker_thread+0x1d6/0x3d0 ? __pfx_worker_thread+0x10/0x10 kthread+0x118/0x230 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x205/0x260 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Consider process A calling writepages() with WB_SYNC_NONE. In zoned mode or for compressed writes, it locks several folios for delalloc and starts writing them out. Let's call the last locked folio folio X. Suppose the write range only partially covers folio X, leaving some pages dirty. Process A calls btrfs_subpage_set_writeback() when building a bio. This function call clears the TOWRITE tag of folio X, whose size = 8K and the block size = 4K. It is following state. 0 4K 8K |/////|/////| (flag: DIRTY, tag: DIRTY) <-----> Process A will write this range. Now suppose process B concurrently calls writepages() with WB_SYNC_ALL. It calls tag_pages_for_writeback() to tag dirty folios with PAGECACHE_TAG_TOWRITE. Since folio X is still dirty, it gets tagged. Then, B collects tagged folios using filemap_get_folios_tag() and must wait for folio X to be written before returning from writepages(). 0 4K 8K |/////|/////| (flag: DIRTY, tag: DIRTY|TOWRITE) However, between tagging and collecting, process A may call btrfs_subpage_set_writeback() and clear folio X's TOWRITE tag. 0 4K 8K | |/////| (flag: DIRTY|WRITEBACK, tag: DIRTY) As a result, process B won't see folio X in its batch, and returns without waiting for it. This breaks the WB_SYNC_ALL ordering requirement. Fix this by using btrfs_subpage_set_writeback_keepwrite(), which retains the TOWRITE tag. We now manually clear the tag only after the folio becomes clean, via the xas operation. Fixes: 3470da3b7d87 ("btrfs: subpage: introduce helpers for writeback status") CC: stable@vger.kernel.org # 6.12+ Reviewed-by: Qu Wenruo Reviewed-by: Johannes Thumshirn Signed-off-by: Naohiro Aota Signed-off-by: David Sterba --- fs/btrfs/subpage.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/subpage.c b/fs/btrfs/subpage.c index c9b3821957f73f..cb4f97833dc34a 100644 --- a/fs/btrfs/subpage.c +++ b/fs/btrfs/subpage.c @@ -448,8 +448,25 @@ void btrfs_subpage_set_writeback(const struct btrfs_fs_info *fs_info, spin_lock_irqsave(&bfs->lock, flags); bitmap_set(bfs->bitmaps, start_bit, len >> fs_info->sectorsize_bits); + + /* + * Don't clear the TOWRITE tag when starting writeback on a still-dirty + * folio. Doing so can cause WB_SYNC_ALL writepages() to overlook it, + * assume writeback is complete, and exit too early — violating sync + * ordering guarantees. + */ if (!folio_test_writeback(folio)) - folio_start_writeback(folio); + __folio_start_writeback(folio, true); + if (!folio_test_dirty(folio)) { + struct address_space *mapping = folio_mapping(folio); + XA_STATE(xas, &mapping->i_pages, folio->index); + unsigned long flags; + + xas_lock_irqsave(&xas, flags); + xas_load(&xas); + xas_clear_mark(&xas, PAGECACHE_TAG_TOWRITE); + xas_unlock_irqrestore(&xas, flags); + } spin_unlock_irqrestore(&bfs->lock, flags); } From dc61d97b0ba064fb21b01fbfa7436873948277bd Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Tue, 12 Aug 2025 01:32:58 +0900 Subject: [PATCH 0140/1292] btrfs: fix buffer index in wait_eb_writebacks() The commit f2cb97ee964a ("btrfs: index buffer_tree using node size") changed the index of buffer_tree from "start >> sectorsize_bits" to "start >> nodesize_bits". However, the change is not applied for wait_eb_writebacks() and caused IO failures by writing in a full zone. Use the index properly. Fixes: f2cb97ee964a ("btrfs: index buffer_tree using node size") Reviewed-by: Qu Wenruo Reviewed-by: Boris Burkov Signed-off-by: Naohiro Aota Signed-off-by: David Sterba --- fs/btrfs/zoned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index e0ee3aeabd2c89..ea662036f4413f 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -2242,7 +2242,7 @@ static void wait_eb_writebacks(struct btrfs_block_group *block_group) struct btrfs_fs_info *fs_info = block_group->fs_info; const u64 end = block_group->start + block_group->length; struct extent_buffer *eb; - unsigned long index, start = (block_group->start >> fs_info->sectorsize_bits); + unsigned long index, start = (block_group->start >> fs_info->nodesize_bits); rcu_read_lock(); xa_for_each_start(&fs_info->buffer_tree, index, eb, start) { From edf842abe4368ce3c423343cf4b23b210fcf1622 Mon Sep 17 00:00:00 2001 From: Kyoji Ogasawara Date: Wed, 23 Jul 2025 00:38:37 +0900 Subject: [PATCH 0141/1292] btrfs: fix incorrect log message for nobarrier mount option Fix a wrong log message that appears when the "nobarrier" mount option is unset. When "nobarrier" is unset, barrier is actually enabled. However, the log incorrectly stated "turning off barriers". Fixes: eddb1a433f26 ("btrfs: add reconfigure callback for fs_context") CC: stable@vger.kernel.org # 6.12+ Reviewed-by: Qu Wenruo Signed-off-by: Kyoji Ogasawara Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 466d0450269c20..768a2532fa4a57 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1462,7 +1462,7 @@ static void btrfs_emit_options(struct btrfs_fs_info *info, btrfs_info_if_unset(info, old, NODATACOW, "setting datacow"); btrfs_info_if_unset(info, old, SSD, "not using ssd optimizations"); btrfs_info_if_unset(info, old, SSD_SPREAD, "not using spread ssd allocation scheme"); - btrfs_info_if_unset(info, old, NOBARRIER, "turning off barriers"); + btrfs_info_if_unset(info, old, NOBARRIER, "turning on barriers"); btrfs_info_if_unset(info, old, NOTREELOG, "enabling tree log"); btrfs_info_if_unset(info, old, SPACE_CACHE, "disabling disk space caching"); btrfs_info_if_unset(info, old, FREE_SPACE_TREE, "disabling free space tree"); From b435ab556bea875c088485f271ef2709ca1d75f5 Mon Sep 17 00:00:00 2001 From: Kyoji Ogasawara Date: Wed, 13 Aug 2025 03:00:06 +0900 Subject: [PATCH 0142/1292] btrfs: restore mount option info messages during mount After the fsconfig migration in 6.8, mount option info messages are no longer displayed during mount operations because btrfs_emit_options() is only called during remount, not during initial mount. Fix this by calling btrfs_emit_options() in btrfs_fill_super() after open_ctree() succeeds. Additionally, prevent log duplication by ensuring btrfs_check_options() handles validation with warn-level and err-level messages, while btrfs_emit_options() provides info-level messages. Fixes: eddb1a433f26 ("btrfs: add reconfigure callback for fs_context") CC: stable@vger.kernel.org # 6.8+ Reviewed-by: Qu Wenruo Signed-off-by: Kyoji Ogasawara Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/super.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 768a2532fa4a57..8469f36ef0117d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -88,6 +88,9 @@ struct btrfs_fs_context { refcount_t refs; }; +static void btrfs_emit_options(struct btrfs_fs_info *info, + struct btrfs_fs_context *old); + enum { Opt_acl, Opt_clear_cache, @@ -698,12 +701,9 @@ bool btrfs_check_options(const struct btrfs_fs_info *info, if (!test_bit(BTRFS_FS_STATE_REMOUNTING, &info->fs_state)) { if (btrfs_raw_test_opt(*mount_opt, SPACE_CACHE)) { - btrfs_info(info, "disk space caching is enabled"); btrfs_warn(info, "space cache v1 is being deprecated and will be removed in a future release, please use -o space_cache=v2"); } - if (btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE)) - btrfs_info(info, "using free-space-tree"); } return ret; @@ -980,6 +980,8 @@ static int btrfs_fill_super(struct super_block *sb, return ret; } + btrfs_emit_options(fs_info, NULL); + inode = btrfs_iget(BTRFS_FIRST_FREE_OBJECTID, fs_info->fs_root); if (IS_ERR(inode)) { ret = PTR_ERR(inode); From 74857fdc5dd2cdcdeb6e99bdf26976fd9299d2bb Mon Sep 17 00:00:00 2001 From: Kyoji Ogasawara Date: Wed, 13 Aug 2025 03:00:07 +0900 Subject: [PATCH 0143/1292] btrfs: fix printing of mount info messages for NODATACOW/NODATASUM The NODATASUM message was printed twice by mistake and the NODATACOW was missing from the 'unset' part. Fix the duplication and make the output look the same. Fixes: eddb1a433f26 ("btrfs: add reconfigure callback for fs_context") CC: stable@vger.kernel.org # 6.8+ Reviewed-by: Qu Wenruo Signed-off-by: Kyoji Ogasawara Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 8469f36ef0117d..7f31f8bd63ba4d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1439,7 +1439,7 @@ static void btrfs_emit_options(struct btrfs_fs_info *info, { btrfs_info_if_set(info, old, NODATASUM, "setting nodatasum"); btrfs_info_if_set(info, old, DEGRADED, "allowing degraded mounts"); - btrfs_info_if_set(info, old, NODATASUM, "setting nodatasum"); + btrfs_info_if_set(info, old, NODATACOW, "setting nodatacow"); btrfs_info_if_set(info, old, SSD, "enabling ssd optimizations"); btrfs_info_if_set(info, old, SSD_SPREAD, "using spread ssd allocation scheme"); btrfs_info_if_set(info, old, NOBARRIER, "turning off barriers"); @@ -1461,6 +1461,7 @@ static void btrfs_emit_options(struct btrfs_fs_info *info, btrfs_info_if_set(info, old, IGNOREMETACSUMS, "ignoring meta csums"); btrfs_info_if_set(info, old, IGNORESUPERFLAGS, "ignoring unknown super block flags"); + btrfs_info_if_unset(info, old, NODATASUM, "setting datasum"); btrfs_info_if_unset(info, old, NODATACOW, "setting datacow"); btrfs_info_if_unset(info, old, SSD, "not using ssd optimizations"); btrfs_info_if_unset(info, old, SSD_SPREAD, "not using spread ssd allocation scheme"); From e664036cf36480414936cd91f4cfa2179a3d8367 Mon Sep 17 00:00:00 2001 From: Miao Li Date: Fri, 1 Aug 2025 16:27:28 +0800 Subject: [PATCH 0144/1292] usb: quirks: Add DELAY_INIT quick for another SanDisk 3.2Gen1 Flash Drive Another SanDisk 3.2Gen1 Flash Drive also need DELAY_INIT quick, or it will randomly work incorrectly on Huawei hisi platforms when doing reboot test. Signed-off-by: Miao Li Cc: stable Link: https://lore.kernel.org/r/20250801082728.469406-1-limiao870622@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ff0ff95d5cca8c..f5bc5387533012 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -371,6 +371,7 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM }, /* SanDisk Corp. SanDisk 3.2Gen1 */ + { USB_DEVICE(0x0781, 0x5596), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT }, /* SanDisk Extreme 55AE */ From 202ad1aaca777dc7fd24f459f5f808f5abd2bfda Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 1 Aug 2025 18:40:41 +0100 Subject: [PATCH 0145/1292] usb: gadget: tegra-xudc: fix PM use count underflow Upon resume from system suspend, the PM runtime core issues the following warning: tegra-xudc 3550000.usb: Runtime PM usage count underflow! This is because tegra_xudc_resume() unconditionally calls schedule_work(&xudc->usb_role_sw_work) whether or not anything has changed, which causes tegra_xudc_device_mode_off() to be called even when we're already in that mode. Keep track of the current state of "device_mode", and only schedule this work if it has changed from the hardware state on resume. Signed-off-by: "Russell King (Oracle)" Link: https://lore.kernel.org/r/E1uhtkH-007KDZ-JT@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/tegra-xudc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 2957316fd3d003..1d3085cc9d2228 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -502,6 +502,7 @@ struct tegra_xudc { struct clk_bulk_data *clks; bool device_mode; + bool current_device_mode; struct work_struct usb_role_sw_work; struct phy **usb3_phy; @@ -715,6 +716,8 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc) phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, USB_ROLE_DEVICE); + + xudc->current_device_mode = true; } static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) @@ -725,6 +728,8 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) dev_dbg(xudc->dev, "device mode off\n"); + xudc->current_device_mode = false; + connected = !!(xudc_readl(xudc, PORTSC) & PORTSC_CCS); reinit_completion(&xudc->disconnect_complete); @@ -4044,10 +4049,10 @@ static int __maybe_unused tegra_xudc_resume(struct device *dev) spin_lock_irqsave(&xudc->lock, flags); xudc->suspended = false; + if (xudc->device_mode != xudc->current_device_mode) + schedule_work(&xudc->usb_role_sw_work); spin_unlock_irqrestore(&xudc->lock, flags); - schedule_work(&xudc->usb_role_sw_work); - pm_runtime_enable(dev); return 0; From f9420f4757752f056144896024d5ea89e5a611f1 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 3 Aug 2025 00:55:20 +0200 Subject: [PATCH 0146/1292] usb: renesas-xhci: Fix External ROM access timeouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase the External ROM access timeouts to prevent failures during programming of External SPI EEPROM chips. The current timeouts are too short for some SPI EEPROMs used with uPD720201 controllers. The current timeout for Chip Erase in renesas_rom_erase() is 100 ms , the current timeout for Sector Erase issued by the controller before Page Program in renesas_fw_download_image() is also 100 ms. Neither timeout is sufficient for e.g. the Macronix MX25L5121E or MX25V5126F. MX25L5121E reference manual [1] page 35 section "ERASE AND PROGRAMMING PERFORMANCE" and page 23 section "Table 8. AC CHARACTERISTICS (Temperature = 0°C to 70°C for Commercial grade, VCC = 2.7V ~ 3.6V)" row "tCE" indicate that the maximum time required for Chip Erase opcode to complete is 2 s, and for Sector Erase it is 300 ms . MX25V5126F reference manual [2] page 47 section "13. ERASE AND PROGRAMMING PERFORMANCE (2.3V - 3.6V)" and page 42 section "Table 8. AC CHARACTERISTICS (Temperature = -40°C to 85°C for Industrial grade, VCC = 2.3V - 3.6V)" row "tCE" indicate that the maximum time required for Chip Erase opcode to complete is 3.2 s, and for Sector Erase it is 400 ms . Update the timeouts such, that Chip Erase timeout is set to 5 seconds, and Sector Erase timeout is set to 500 ms. Such lengthy timeouts ought to be sufficient for majority of SPI EEPROM chips. [1] https://www.macronix.com/Lists/Datasheet/Attachments/8634/MX25L5121E,%203V,%20512Kb,%20v1.3.pdf [2] https://www.macronix.com/Lists/Datasheet/Attachments/8750/MX25V5126F,%202.5V,%20512Kb,%20v1.1.pdf Fixes: 2478be82de44 ("usb: renesas-xhci: Add ROM loader for uPD720201") Cc: stable Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20250802225526.25431-1-marek.vasut+renesas@mailbox.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci-renesas.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c index 620f8f0febb84b..86df80399c9fdc 100644 --- a/drivers/usb/host/xhci-pci-renesas.c +++ b/drivers/usb/host/xhci-pci-renesas.c @@ -47,8 +47,9 @@ #define RENESAS_ROM_ERASE_MAGIC 0x5A65726F #define RENESAS_ROM_WRITE_MAGIC 0x53524F4D -#define RENESAS_RETRY 10000 -#define RENESAS_DELAY 10 +#define RENESAS_RETRY 50000 /* 50000 * RENESAS_DELAY ~= 500ms */ +#define RENESAS_CHIP_ERASE_RETRY 500000 /* 500000 * RENESAS_DELAY ~= 5s */ +#define RENESAS_DELAY 10 #define RENESAS_FW_NAME "renesas_usb_fw.mem" @@ -407,7 +408,7 @@ static void renesas_rom_erase(struct pci_dev *pdev) /* sleep a bit while ROM is erased */ msleep(20); - for (i = 0; i < RENESAS_RETRY; i++) { + for (i = 0; i < RENESAS_CHIP_ERASE_RETRY; i++) { retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); status &= RENESAS_ROM_STATUS_ERASE; From 8fe06185e11ae753414aa6117f0e798aa77567ff Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Wed, 6 Aug 2025 16:39:55 +0800 Subject: [PATCH 0147/1292] usb: core: hcd: fix accessing unmapped memory in SINGLE_STEP_SET_FEATURE test The USB core will unmap urb->transfer_dma after SETUP stage completes. Then the USB controller will access unmapped memory when it received device descriptor. If iommu is equipped, the entire test can't be completed due to the memory accessing is blocked. Fix it by calling map_urb_for_dma() again for IN stage. To reduce redundant map for urb->transfer_buffer, this will also set URB_NO_TRANSFER_DMA_MAP flag before first map_urb_for_dma() to skip dma map for urb->transfer_buffer and clear URB_NO_TRANSFER_DMA_MAP flag before second map_urb_for_dma(). Fixes: 216e0e563d81 ("usb: core: hcd: use map_urb_for_dma for single step set feature urb") Cc: stable Reviewed-by: Jun Li Signed-off-by: Xu Yang Acked-by: Alan Stern Link: https://lore.kernel.org/r/20250806083955.3325299-1-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 03771bbc6c01a6..c4a1875b5d3d0c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2166,7 +2166,7 @@ static struct urb *request_single_step_set_feature_urb( urb->complete = usb_ehset_completion; urb->status = -EINPROGRESS; urb->actual_length = 0; - urb->transfer_flags = URB_DIR_IN; + urb->transfer_flags = URB_DIR_IN | URB_NO_TRANSFER_DMA_MAP; usb_get_urb(urb); atomic_inc(&urb->use_count); atomic_inc(&urb->dev->urbnum); @@ -2230,9 +2230,15 @@ int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) /* Complete remaining DATA and STATUS stages using the same URB */ urb->status = -EINPROGRESS; + urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP; usb_get_urb(urb); atomic_inc(&urb->use_count); atomic_inc(&urb->dev->urbnum); + if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) { + usb_put_urb(urb); + goto out1; + } + retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0); if (!retval && !wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { From 6ca8af3c8fb584f3424a827f554ff74f898c27cd Mon Sep 17 00:00:00 2001 From: Mael GUERIN Date: Wed, 6 Aug 2025 18:44:03 +0200 Subject: [PATCH 0148/1292] USB: storage: Add unusual-devs entry for Novatek NTK96550-based camera Add the US_FL_BULK_IGNORE_TAG quirk for Novatek NTK96550-based camera to fix USB resets after sending SCSI vendor commands due to CBW and CSW tags difference, leading to undesired slowness while communicating with the device. Please find below the copy of /sys/kernel/debug/usb/devices with my device plugged in (listed as TechSys USB mass storage here, the underlying chipset being the Novatek NTK96550-based camera): T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=0603 ProdID=8611 Rev= 0.01 S: Manufacturer=TechSys S: Product=USB Mass Storage S: SerialNumber=966110000000100 C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Signed-off-by: Mael GUERIN Cc: stable Acked-by: Alan Stern Link: https://lore.kernel.org/r/20250806164406.43450-1-mael.guerin@murena.io Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 54f0b1c83317cd..bee9f1e8003d48 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -934,6 +934,13 @@ UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SANE_SENSE ), +/* Added by MaĆ«l GUERIN */ +UNUSUAL_DEV( 0x0603, 0x8611, 0x0000, 0xffff, + "Novatek", + "NTK96550-based camera", + USB_SC_SCSI, USB_PR_BULK, NULL, + US_FL_BULK_IGNORE_TAG ), + /* * Reported by Hanno Boeck * Taken from the Lycoris Kernel From 58577118cc7cec9eb7c1836bf88f865ff2c5e3a3 Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Thu, 7 Aug 2025 17:06:55 +0800 Subject: [PATCH 0149/1292] usb: dwc3: Ignore late xferNotReady event to prevent halt timeout During a device-initiated disconnect, the End Transfer command resets the event filter, allowing a new xferNotReady event to be generated before the controller is fully halted. Processing this late event incorrectly triggers a Start Transfer, which prevents the controller from halting and results in a DSTS.DEVCTLHLT bit polling timeout. Ignore the late xferNotReady event if the controller is already in a disconnected state. Fixes: 72246da40f37 ("usb: Introduce DesignWare USB3 DRD Driver") Cc: stable Signed-off-by: Kuen-Han Tsai Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20250807090700.2397190-1-khtsai@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 25db36c63951bf..68fa2813e5f4ea 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3777,6 +3777,15 @@ static void dwc3_gadget_endpoint_transfer_complete(struct dwc3_ep *dep, static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { + /* + * During a device-initiated disconnect, a late xferNotReady event can + * be generated after the End Transfer command resets the event filter, + * but before the controller is halted. Ignore it to prevent a new + * transfer from starting. + */ + if (!dep->dwc->connected) + return; + dwc3_gadget_endpoint_frame_from_event(dep, event); /* From 86f390ba59cd8d5755bafe2b163c3e6b89d6bbd9 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Tue, 12 Aug 2025 16:11:00 +0300 Subject: [PATCH 0150/1292] usb: dwc3: pci: add support for the Intel Wildcat Lake This patch adds the necessary PCI ID for Intel Wildcat Lake devices. Signed-off-by: Heikki Krogerus Cc: stable Link: https://lore.kernel.org/r/20250812131101.2930199-1-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 54a4ee2b90b7f4..39c72cb52ce76a 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -41,6 +41,7 @@ #define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee #define PCI_DEVICE_ID_INTEL_TGPH 0x43ee #define PCI_DEVICE_ID_INTEL_JSP 0x4dee +#define PCI_DEVICE_ID_INTEL_WCL 0x4d7e #define PCI_DEVICE_ID_INTEL_ADL 0x460e #define PCI_DEVICE_ID_INTEL_ADL_PCH 0x51ee #define PCI_DEVICE_ID_INTEL_ADLN 0x465e @@ -431,6 +432,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_DEVICE_DATA(INTEL, TGPLP, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, TGPH, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, JSP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, WCL, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, ADL, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, ADL_PCH, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, ADLN, &dwc3_pci_intel_swnode) }, From 9528d32873b38281ae105f2f5799e79ae9d086c2 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 11 Aug 2025 10:27:45 +0200 Subject: [PATCH 0151/1292] kcov, usb: Don't disable interrupts in kcov_remote_start_usb_softirq() kcov_remote_start_usb_softirq() the begin of urb's completion callback. HCDs marked HCD_BH will invoke this function from the softirq and in_serving_softirq() will detect this properly. Root-HUB (RH) requests will not be delayed to softirq but complete immediately in IRQ context. This will confuse kcov because in_serving_softirq() will report true if the softirq is served after the hardirq and if the softirq got interrupted by the hardirq in which currently runs. This was addressed by simply disabling interrupts in kcov_remote_start_usb_softirq() which avoided the interruption by the RH while a regular completion callback was invoked. This not only changes the behaviour while kconv is enabled but also breaks PREEMPT_RT because now sleeping locks can no longer be acquired. Revert the previous fix. Address the issue by invoking kcov_remote_start_usb() only if the context is just "serving softirqs" which is identified by checking in_serving_softirq() and in_hardirq() must be false. Fixes: f85d39dd7ed89 ("kcov, usb: disable interrupts in kcov_remote_start_usb_softirq") Cc: stable Reported-by: Yunseong Kim Closes: https://lore.kernel.org/all/20250725201400.1078395-2-ysk@kzalloc.com/ Tested-by: Yunseong Kim Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20250811082745.ycJqBXMs@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 12 +++++------ include/linux/kcov.h | 47 ++++++++---------------------------------- 2 files changed, 14 insertions(+), 45 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index c4a1875b5d3d0c..6270fbb5c69988 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1636,7 +1636,6 @@ static void __usb_hcd_giveback_urb(struct urb *urb) struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); struct usb_anchor *anchor = urb->anchor; int status = urb->unlinked; - unsigned long flags; urb->hcpriv = NULL; if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && @@ -1654,14 +1653,13 @@ static void __usb_hcd_giveback_urb(struct urb *urb) /* pass ownership to the completion handler */ urb->status = status; /* - * Only collect coverage in the softirq context and disable interrupts - * to avoid scenarios with nested remote coverage collection sections - * that KCOV does not support. - * See the comment next to kcov_remote_start_usb_softirq() for details. + * This function can be called in task context inside another remote + * coverage collection section, but kcov doesn't support that kind of + * recursion yet. Only collect coverage in softirq context for now. */ - flags = kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum); + kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum); urb->complete(urb); - kcov_remote_stop_softirq(flags); + kcov_remote_stop_softirq(); usb_anchor_resume_wakeups(anchor); atomic_dec(&urb->use_count); diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 75a2fb8b16c329..0143358874b07b 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -57,47 +57,21 @@ static inline void kcov_remote_start_usb(u64 id) /* * The softirq flavor of kcov_remote_*() functions is introduced as a temporary - * workaround for KCOV's lack of nested remote coverage sections support. - * - * Adding support is tracked in https://bugzilla.kernel.org/show_bug.cgi?id=210337. - * - * kcov_remote_start_usb_softirq(): - * - * 1. Only collects coverage when called in the softirq context. This allows - * avoiding nested remote coverage collection sections in the task context. - * For example, USB/IP calls usb_hcd_giveback_urb() in the task context - * within an existing remote coverage collection section. Thus, KCOV should - * not attempt to start collecting coverage within the coverage collection - * section in __usb_hcd_giveback_urb() in this case. - * - * 2. Disables interrupts for the duration of the coverage collection section. - * This allows avoiding nested remote coverage collection sections in the - * softirq context (a softirq might occur during the execution of a work in - * the BH workqueue, which runs with in_serving_softirq() > 0). - * For example, usb_giveback_urb_bh() runs in the BH workqueue with - * interrupts enabled, so __usb_hcd_giveback_urb() might be interrupted in - * the middle of its remote coverage collection section, and the interrupt - * handler might invoke __usb_hcd_giveback_urb() again. + * work around for kcov's lack of nested remote coverage sections support in + * task context. Adding support for nested sections is tracked in: + * https://bugzilla.kernel.org/show_bug.cgi?id=210337 */ -static inline unsigned long kcov_remote_start_usb_softirq(u64 id) +static inline void kcov_remote_start_usb_softirq(u64 id) { - unsigned long flags = 0; - - if (in_serving_softirq()) { - local_irq_save(flags); + if (in_serving_softirq() && !in_hardirq()) kcov_remote_start_usb(id); - } - - return flags; } -static inline void kcov_remote_stop_softirq(unsigned long flags) +static inline void kcov_remote_stop_softirq(void) { - if (in_serving_softirq()) { + if (in_serving_softirq() && !in_hardirq()) kcov_remote_stop(); - local_irq_restore(flags); - } } #ifdef CONFIG_64BIT @@ -131,11 +105,8 @@ static inline u64 kcov_common_handle(void) } static inline void kcov_remote_start_common(u64 id) {} static inline void kcov_remote_start_usb(u64 id) {} -static inline unsigned long kcov_remote_start_usb_softirq(u64 id) -{ - return 0; -} -static inline void kcov_remote_stop_softirq(unsigned long flags) {} +static inline void kcov_remote_start_usb_softirq(u64 id) {} +static inline void kcov_remote_stop_softirq(void) {} #endif /* CONFIG_KCOV */ #endif /* _LINUX_KCOV_H */ From 421255afa2a58eee2109dda56c137a7b61c4b05f Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Mon, 11 Aug 2025 18:08:33 +0800 Subject: [PATCH 0152/1292] usb: chipidea: imx: improve usbmisc_imx7d_pullup() When add workaround for ERR051725, the usbmisc will put PHY to Non-driving mode (OPMODE = 01) after stopping the device controller and put PHY back to Normal mode (OPMODE = 00) after starting the device controller. However, this will bring issue for host controller. Because the PHY may stay in Non-driving mode after switching the role from device to host. Then the port will not work if USB device is attached. To fix this issue, improving the workaround by putting PHY to Non-driving mode for a certain period and back to Normal mode finally. To make host detect a disconnect signal, the period should be at least 125us (a micro-frame time) for high-speed link. And only working as high-speed mode will need workaround for ERR051725. So this will also filter the pullup event for high-speed. Fixes: 11992b410083 ("usb: chipidea: imx: implement workaround for ERR051725") Reviewed-by: Jun Li Signed-off-by: Xu Yang Acked-by: Peter Chen Link: https://lore.kernel.org/r/20250811100833.862876-1-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 3 ++- drivers/usb/chipidea/usbmisc_imx.c | 23 ++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index e1ec9b38f5b9ba..d7c2a1a3c27159 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -338,7 +338,8 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) schedule_work(&ci->usb_phy->chg_work); break; case CI_HDRC_CONTROLLER_PULLUP_EVENT: - if (ci->role == CI_ROLE_GADGET) + if (ci->role == CI_ROLE_GADGET && + ci->gadget.speed == USB_SPEED_HIGH) imx_usbmisc_pullup(data->usbmisc_data, ci->gadget.connected); break; diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 3d20c5e76c6a74..b1418885707c88 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -1068,15 +1068,24 @@ static void usbmisc_imx7d_pullup(struct imx_usbmisc_data *data, bool on) unsigned long flags; u32 val; + if (on) + return; + spin_lock_irqsave(&usbmisc->lock, flags); val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); - if (!on) { - val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK; - val |= MX7D_USBNC_USB_CTRL2_OPMODE(1); - val |= MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN; - } else { - val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN; - } + val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK; + val |= MX7D_USBNC_USB_CTRL2_OPMODE(1); + val |= MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN; + writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2); + spin_unlock_irqrestore(&usbmisc->lock, flags); + + /* Last for at least 1 micro-frame to let host see disconnect signal */ + usleep_range(125, 150); + + spin_lock_irqsave(&usbmisc->lock, flags); + val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK; + val |= MX7D_USBNC_USB_CTRL2_OPMODE(0); + val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN; writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2); spin_unlock_irqrestore(&usbmisc->lock, flags); } From 98da66a70ad2396e5a508c4245367797ebc052ce Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 13 Aug 2025 16:52:49 +0200 Subject: [PATCH 0153/1292] usb: storage: realtek_cr: Use correct byte order for bcs->Residue Since 'bcs->Residue' has the data type '__le32', convert it to the correct byte order of the CPU using this driver when assigning it to the local variable 'residue'. Cc: stable Fixes: 50a6cb932d5c ("USB: usb_storage: add ums-realtek driver") Suggested-by: Alan Stern Acked-by: Alan Stern Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250813145247.184717-3-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/realtek_cr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 7dea28c2b8ee30..cb5bbb19060e79 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -252,7 +252,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, return USB_STOR_TRANSPORT_ERROR; } - residue = bcs->Residue; + residue = le32_to_cpu(bcs->Residue); if (bcs->Tag != us->tag) return USB_STOR_TRANSPORT_ERROR; From a5ba9ad417254c49ecf06ac5ab36ec4b12ee133f Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 4 Aug 2025 19:13:11 +0200 Subject: [PATCH 0154/1292] rust: faux: fix C header link Starting with Rust 1.91.0 (expected 2025-10-30), `rustdoc` has improved some false negatives around intra-doc links [1], and it found a broken intra-doc link we currently have: error: unresolved link to `include/linux/device/faux.h` --> rust/kernel/faux.rs:7:17 | 7 | //! C header: [`include/linux/device/faux.h`] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `include/linux/device/faux.h` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: `-D rustdoc::broken-intra-doc-links` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(rustdoc::broken_intra_doc_links)]` Our `srctree/` C header links are not intra-doc links, thus they need the link destination. Thus fix it. Cc: stable Link: https://github.com/rust-lang/rust/pull/132748 [1] Fixes: 78418f300d39 ("rust/kernel: Add faux device bindings") Signed-off-by: Miguel Ojeda Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250804171311.1186538-1-ojeda@kernel.org Signed-off-by: Greg Kroah-Hartman --- rust/kernel/faux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/faux.rs b/rust/kernel/faux.rs index 7a906099993f1b..7fe2dd197e3737 100644 --- a/rust/kernel/faux.rs +++ b/rust/kernel/faux.rs @@ -4,7 +4,7 @@ //! //! This module provides bindings for working with faux devices in kernel modules. //! -//! C header: [`include/linux/device/faux.h`] +//! C header: [`include/linux/device/faux.h`](srctree/include/linux/device/faux.h) use crate::{bindings, device, error::code::*, prelude::*}; use core::ptr::{addr_of_mut, null, null_mut, NonNull}; From 0b3ccb76b95bd06cf80124d8adda647c82a6cc0f Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 9 Jul 2025 16:08:36 +0200 Subject: [PATCH 0155/1292] drm/msm/dsi: Fix 14nm DSI PHY PLL Lock issue To configure and enable the DSI PHY PLL clocks, the MDSS AHB clock must be active for MMIO operations. Typically, this AHB clock is enabled as part of the DSI PHY interface enabling (dsi_phy_enable_resource). However, since these PLL clocks are registered as clock entities, they can be enabled independently of the DSI PHY interface, leading to enabling failures and subsequent warnings: ``` msm_dsi_phy 5e94400.phy: [drm:dsi_pll_14nm_vco_prepare] *ERROR* DSI PLL lock failed ------------[ cut here ]------------ dsi0pllbyte already disabled WARNING: CPU: 3 PID: 1 at drivers/clk/clk.c:1194 clk_core_disable+0xa4/0xac CPU: 3 UID: 0 PID: 1 Comm: swapper/0 Tainted: Tainted: [W]=WARN Hardware name: Qualcomm Technologies, Inc. Robotics RB1 (DT) pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [...] ``` This issue is particularly prevalent at boot time during the disabling of unused clocks (clk_disable_unused()) which includes enabling the parent clock(s) when CLK_OPS_PARENT_ENABLE flag is set (this is the case for the 14nm DSI PHY PLL consumers). To resolve this issue, we move the AHB clock as a PM dependency of the DSI PHY device (via pm_clk). Since the DSI PHY device is the parent of the PLL clocks, this resolves the PLL/AHB dependency. Now the AHB clock is enabled prior the PLL clk_prepare callback, as part of the runtime-resume chain. We also eliminate dsi_phy_[enable|disable]_resource functions, which are superseded by runtime PM. Note that it breaks compatibility with kernels before 6.0, as we do not support anymore the legacy `iface_clk` name. Signed-off-by: Loic Poulain Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/663239/ Link: https://lore.kernel.org/r/20250709140836.124143-1-loic.poulain@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 59 ++++++++------------------- drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 - 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 221f12db5f8b76..4ea681130dbafc 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include "dsi_phy.h" @@ -511,30 +513,6 @@ int msm_dsi_cphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing, return 0; } -static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) -{ - struct device *dev = &phy->pdev->dev; - int ret; - - ret = pm_runtime_resume_and_get(dev); - if (ret) - return ret; - - ret = clk_prepare_enable(phy->ahb_clk); - if (ret) { - DRM_DEV_ERROR(dev, "%s: can't enable ahb clk, %d\n", __func__, ret); - pm_runtime_put_sync(dev); - } - - return ret; -} - -static void dsi_phy_disable_resource(struct msm_dsi_phy *phy) -{ - clk_disable_unprepare(phy->ahb_clk); - pm_runtime_put(&phy->pdev->dev); -} - static const struct of_device_id dsi_phy_dt_match[] = { #ifdef CONFIG_DRM_MSM_DSI_28NM_PHY { .compatible = "qcom,dsi-phy-28nm-hpm", @@ -698,22 +676,20 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) if (ret) return ret; - phy->ahb_clk = msm_clk_get(pdev, "iface"); - if (IS_ERR(phy->ahb_clk)) - return dev_err_probe(dev, PTR_ERR(phy->ahb_clk), - "Unable to get ahb clk\n"); + platform_set_drvdata(pdev, phy); - ret = devm_pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(dev); if (ret) return ret; - /* PLL init will call into clk_register which requires - * register access, so we need to enable power and ahb clock. - */ - ret = dsi_phy_enable_resource(phy); + ret = devm_pm_clk_create(dev); if (ret) return ret; + ret = pm_clk_add(dev, "iface"); + if (ret < 0) + return dev_err_probe(dev, ret, "Unable to get iface clk\n"); + if (phy->cfg->ops.pll_init) { ret = phy->cfg->ops.pll_init(phy); if (ret) @@ -727,18 +703,19 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "Failed to register clk provider\n"); - dsi_phy_disable_resource(phy); - - platform_set_drvdata(pdev, phy); - return 0; } +static const struct dev_pm_ops dsi_phy_pm_ops = { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver dsi_phy_platform_driver = { .probe = dsi_phy_driver_probe, .driver = { .name = "msm_dsi_phy", .of_match_table = dsi_phy_dt_match, + .pm = &dsi_phy_pm_ops, }, }; @@ -764,9 +741,9 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, dev = &phy->pdev->dev; - ret = dsi_phy_enable_resource(phy); + ret = pm_runtime_resume_and_get(dev); if (ret) { - DRM_DEV_ERROR(dev, "%s: resource enable failed, %d\n", + DRM_DEV_ERROR(dev, "%s: resume failed, %d\n", __func__, ret); goto res_en_fail; } @@ -810,7 +787,7 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, phy_en_fail: regulator_bulk_disable(phy->cfg->num_regulators, phy->supplies); reg_en_fail: - dsi_phy_disable_resource(phy); + pm_runtime_put(dev); res_en_fail: return ret; } @@ -823,7 +800,7 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy) phy->cfg->ops.disable(phy); regulator_bulk_disable(phy->cfg->num_regulators, phy->supplies); - dsi_phy_disable_resource(phy); + pm_runtime_put(&phy->pdev->dev); } void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index c558f8df168479..3cbf0823149249 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -104,7 +104,6 @@ struct msm_dsi_phy { phys_addr_t lane_size; int id; - struct clk *ahb_clk; struct regulator_bulk_data *supplies; struct msm_dsi_dphy_timing timing; From 553666f839b86545300773954df7426a45c169c4 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 15 Jul 2025 18:50:37 +0300 Subject: [PATCH 0156/1292] drm/msm/kms: move snapshot init earlier in KMS init Various parts of the display driver can be triggering the display snapshot (including the IOMMU fault handlers). Move the call to msm_disp_snapshot_init() before KMS initialization, otherwise it is possible to ocassionally trigger the kernel fault during init: __lock_acquire+0x44/0x2798 (P) lock_acquire+0x114/0x25c _raw_spin_lock_irqsave+0x6c/0x90 kthread_queue_work+0x2c/0xac msm_disp_snapshot_state+0x2c/0x4c msm_kms_fault_handler+0x2c/0x74 msm_disp_fault_handler+0x30/0x48 report_iommu_fault+0x54/0x128 arm_smmu_context_fault+0x74/0x184 __handle_irq_event_percpu+0xa4/0x24c handle_irq_event_percpu+0x20/0x5c handle_irq_event+0x48/0x84 handle_fasteoi_irq+0xcc/0x170 generic_handle_domain_irq+0x48/0x70 gic_handle_irq+0x54/0x11c call_on_irq_stack+0x3c/0x50 do_interrupt_handler+0x54/0x78 el1_interrupt+0x3c/0x5c el1h_64_irq_handler+0x20/0x30 el1h_64_irq+0x6c/0x70 _raw_spin_unlock_irqrestore+0x44/0x68 (P) klist_next+0xc4/0x124 bus_for_each_drv+0x9c/0xe8 __device_attach+0xfc/0x190 device_initial_probe+0x1c/0x2c bus_probe_device+0x44/0xa0 device_add+0x204/0x3e4 platform_device_add+0x170/0x244 platform_device_register_full+0x130/0x138 drm_connector_hdmi_audio_init+0xc0/0x108 drm_bridge_connector_init+0x318/0x394 msm_dsi_manager_connector_init+0xac/0xdc msm_dsi_modeset_init+0x78/0xc0 _dpu_kms_drm_obj_init+0x198/0x75c dpu_kms_hw_init+0x2f8/0x494 msm_drm_kms_init+0xb0/0x230 msm_drm_init+0x218/0x250 msm_drm_bind+0x3c/0x4c try_to_bring_up_aggregate_device+0x208/0x2a4 __component_add+0xa8/0x188 component_add+0x1c/0x2c dsi_dev_attach+0x24/0x34 dsi_host_attach+0x68/0xa0 devm_mipi_dsi_attach+0x40/0xcc lt9611_attach_dsi+0x94/0x118 lt9611_probe+0x368/0x3c8 i2c_device_probe+0x2d0/0x3d8 really_probe+0x130/0x354 __driver_probe_device+0xac/0x110 driver_probe_device+0x44/0x110 __device_attach_driver+0xb0/0x138 bus_for_each_drv+0x90/0xe8 __device_attach+0xfc/0x190 device_initial_probe+0x1c/0x2c bus_probe_device+0x44/0xa0 deferred_probe_work_func+0xac/0x110 process_one_work+0x20c/0x51c process_scheduled_works+0x58/0x88 worker_thread+0x1ec/0x304 kthread+0x194/0x1d4 ret_from_fork+0x10/0x20 Reported-by: Konrad Dybcio Fixes: 98659487b845 ("drm/msm: add support to take dpu snapshot") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/664149/ Link: https://lore.kernel.org/r/20250715-msm-move-snapshot-init-v1-1-f39c396192ab@oss.qualcomm.com --- drivers/gpu/drm/msm/msm_kms.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_kms.c b/drivers/gpu/drm/msm/msm_kms.c index 6889f1c1e72121..56828d218e88a5 100644 --- a/drivers/gpu/drm/msm/msm_kms.c +++ b/drivers/gpu/drm/msm/msm_kms.c @@ -275,6 +275,12 @@ int msm_drm_kms_init(struct device *dev, const struct drm_driver *drv) if (ret) return ret; + ret = msm_disp_snapshot_init(ddev); + if (ret) { + DRM_DEV_ERROR(dev, "msm_disp_snapshot_init failed ret = %d\n", ret); + return ret; + } + ret = priv->kms_init(ddev); if (ret) { DRM_DEV_ERROR(dev, "failed to load kms\n"); @@ -327,10 +333,6 @@ int msm_drm_kms_init(struct device *dev, const struct drm_driver *drv) goto err_msm_uninit; } - ret = msm_disp_snapshot_init(ddev); - if (ret) - DRM_DEV_ERROR(dev, "msm_disp_snapshot_init failed ret = %d\n", ret); - drm_mode_config_reset(ddev); return 0; From 1a76b255eceb9c570c6228f6393e1d63d97a22ba Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 15 Jul 2025 20:28:18 +0300 Subject: [PATCH 0157/1292] drm/msm/dpu: correct dpu_plane_virtual_atomic_check() Fix c&p error in dpu_plane_virtual_atomic_check(), compare CRTC width too, in addition to CRTC height. Fixes: 8c62a31607f6 ("drm/msm/dpu: allow using two SSPP blocks for a single plane") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507150432.U0cALR6W-lkp@intel.com/ Signed-off-by: Dmitry Baryshkov Reviewed-by: Jessica Zhang Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/664170/ Link: https://lore.kernel.org/r/20250715-msm-fix-virt-atomic-check-v1-1-9bab02c9f952@oss.qualcomm.com --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 01171c535a27c8..c722f54e71b03b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1162,7 +1162,7 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, if (!old_plane_state || !old_plane_state->fb || old_plane_state->src_w != plane_state->src_w || old_plane_state->src_h != plane_state->src_h || - old_plane_state->src_w != plane_state->src_w || + old_plane_state->crtc_w != plane_state->crtc_w || old_plane_state->crtc_h != plane_state->crtc_h || msm_framebuffer_format(old_plane_state->fb) != msm_framebuffer_format(plane_state->fb)) From 494045c561e68945b1183ff416b8db8e37a122d6 Mon Sep 17 00:00:00 2001 From: Ayushi Makhija Date: Wed, 30 Jul 2025 18:09:38 +0530 Subject: [PATCH 0158/1292] drm/msm: update the high bitfield of certain DSI registers Currently, the high bitfield of certain DSI registers do not align with the configuration of the SWI registers description. This can lead to wrong programming these DSI registers, for example for 4k resloution where H_TOTAL is taking 13 bits but software is programming only 12 bits because of the incorrect bitmask for H_TOTAL bitfeild, this is causing DSI FIFO errors. To resolve this issue, increase the high bitfield of the DSI registers from 12 bits to 16 bits in dsi.xml to match the SWI register configuration. Signed-off-by: Ayushi Makhija Fixes: 4f52f5e63b62 ("drm/msm: import XML display registers database") Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/666229/ Link: https://lore.kernel.org/r/20250730123938.1038640-1-quic_amakhija@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/registers/display/dsi.xml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/registers/display/dsi.xml b/drivers/gpu/drm/msm/registers/display/dsi.xml index 501ffc585a9f69..c7a7b633d747bc 100644 --- a/drivers/gpu/drm/msm/registers/display/dsi.xml +++ b/drivers/gpu/drm/msm/registers/display/dsi.xml @@ -159,28 +159,28 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> - - + + - - + + - - + + - - + + - - + + - - + + @@ -209,8 +209,8 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> - - + + From daab47925c06a04792ca720d8438abd37775e357 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 15 Jul 2025 16:27:35 -0700 Subject: [PATCH 0159/1292] drm/msm/dpu: Initialize crtc_state to NULL in dpu_plane_virtual_atomic_check() After a recent change in clang to expose uninitialized warnings from const variables and pointers [1], there is a warning around crtc_state in dpu_plane_virtual_atomic_check(): drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1145:6: error: variable 'crtc_state' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized] 1145 | if (plane_state->crtc) | ^~~~~~~~~~~~~~~~~ drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1149:58: note: uninitialized use occurs here 1149 | ret = dpu_plane_atomic_check_nosspp(plane, plane_state, crtc_state); | ^~~~~~~~~~ drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1145:2: note: remove the 'if' if its condition is always true 1145 | if (plane_state->crtc) | ^~~~~~~~~~~~~~~~~~~~~~ 1146 | crtc_state = drm_atomic_get_new_crtc_state(state, drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:1139:35: note: initialize the variable 'crtc_state' to silence this warning 1139 | struct drm_crtc_state *crtc_state; | ^ | = NULL Initialize crtc_state to NULL like other places in the driver do, so that it is consistently initialized. Cc: stable@vger.kernel.org Closes: https://github.com/ClangBuiltLinux/linux/issues/2106 Fixes: 774bcfb73176 ("drm/msm/dpu: add support for virtual planes") Link: https://github.com/llvm/llvm-project/commit/2464313eef01c5b1edf0eccf57a32cdee01472c7 [1] Signed-off-by: Nathan Chancellor Reviewed-by: Jessica Zhang Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index c722f54e71b03b..6859e8ef6b0559 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1129,7 +1129,7 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state); - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; int ret; if (IS_ERR(plane_state)) From 197713d0cf018e7d58a63a83cc43035b56678a50 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 23 Jul 2025 16:33:43 +0300 Subject: [PATCH 0160/1292] soc: qcom: ubwc: provide no-UBWC configuration After the commit 45a2974157d2 ("drm/msm: Use the central UBWC config database") the MDSS driver errors out if UBWC database didn't provide it with the UBWC configuration. Make UBWC database return zero data for MSM8916 / APQ8016, MSM8974 / APQ8074, MSM8226 and MSM8939. Fixes: 1924272b9ce1 ("soc: qcom: Add UBWC config provider") Acked-by: Bjorn Andersson Reviewed-by: Rob Clark Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/665313/ Link: https://lore.kernel.org/r/20250723-ubwc-no-ubwc-v3-1-81bdb75685bf@oss.qualcomm.com --- drivers/soc/qcom/ubwc_config.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index bd0a98aad9f3b2..9002fc9373ce34 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -12,6 +12,10 @@ #include +static const struct qcom_ubwc_cfg_data no_ubwc_data = { + /* no UBWC, no HBB */ +}; + static const struct qcom_ubwc_cfg_data msm8937_data = { .ubwc_enc_version = UBWC_1_0, .ubwc_dec_version = UBWC_1_0, @@ -215,11 +219,18 @@ static const struct qcom_ubwc_cfg_data x1e80100_data = { }; static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { + { .compatible = "qcom,apq8016", .data = &no_ubwc_data }, + { .compatible = "qcom,apq8026", .data = &no_ubwc_data }, + { .compatible = "qcom,apq8074", .data = &no_ubwc_data }, { .compatible = "qcom,apq8096", .data = &msm8998_data }, + { .compatible = "qcom,msm8226", .data = &no_ubwc_data }, + { .compatible = "qcom,msm8916", .data = &no_ubwc_data }, { .compatible = "qcom,msm8917", .data = &msm8937_data }, { .compatible = "qcom,msm8937", .data = &msm8937_data }, + { .compatible = "qcom,msm8939", .data = &no_ubwc_data }, { .compatible = "qcom,msm8953", .data = &msm8937_data }, { .compatible = "qcom,msm8956", .data = &msm8937_data }, + { .compatible = "qcom,msm8974", .data = &no_ubwc_data }, { .compatible = "qcom,msm8976", .data = &msm8937_data }, { .compatible = "qcom,msm8996", .data = &msm8998_data }, { .compatible = "qcom,msm8998", .data = &msm8998_data }, From 0b6974bb4134ca6396752a0b122026b41300592f Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 23 Jul 2025 16:19:22 +0200 Subject: [PATCH 0161/1292] soc: qcom: ubwc: Add missing UBWC config for SM7225 SM7225 is a variation of SM6350, and also needs an entry in the table. Fixes: 1924272b9ce1 ("soc: qcom: Add UBWC config provider") Signed-off-by: Luca Weiss Reviewed-by: Dmitry Baryshkov Acked-by: Bjorn Andersson Signed-off-by: Dmitry Baryshkov --- drivers/soc/qcom/ubwc_config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 9002fc9373ce34..1490a7f63767bb 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -257,6 +257,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,sm6375", .data = &sm6350_data, }, { .compatible = "qcom,sm7125", .data = &sc7180_data }, { .compatible = "qcom,sm7150", .data = &sm7150_data, }, + { .compatible = "qcom,sm7225", .data = &sm6350_data, }, { .compatible = "qcom,sm8150", .data = &sm8150_data, }, { .compatible = "qcom,sm8250", .data = &sm8250_data, }, { .compatible = "qcom,sm8350", .data = &sm8350_data, }, From 757fc66da91b54d4fbc414bee5c440b52560d3b7 Mon Sep 17 00:00:00 2001 From: Baolin Liu Date: Tue, 12 Aug 2025 10:17:09 +0800 Subject: [PATCH 0162/1292] ext4: fix incorrect function name in comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 6b730a405037 ā€œext4: hoist ext4_block_write_begin and replace the __block_write_beginā€, the comment should be updated accordingly from "__block_write_begin" to "ext4_block_write_begin". Fixes: 6b730a405037 (ā€œext4: hoist ext4_block_write_begin and replace...") Signed-off-by: Baolin Liu Reviewed-by: Darrick J. Wong Link: https://patch.msgid.link/20250812021709.1120716-1-liubaolin12138@163.com Signed-off-by: Theodore Ts'o --- fs/ext4/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 731a800d9c148e..238a0f12a5c043 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3159,7 +3159,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, folio_unlock(folio); folio_put(folio); /* - * block_write_begin may have instantiated a few blocks + * ext4_block_write_begin may have instantiated a few blocks * outside i_size. Trim these off again. Don't need * i_size_read because we hold inode lock. */ From 9d98cf4632258720f18265a058e62fde120c0151 Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Tue, 12 Aug 2025 14:37:52 +0800 Subject: [PATCH 0163/1292] jbd2: prevent softlockup in jbd2_log_do_checkpoint() Both jbd2_log_do_checkpoint() and jbd2_journal_shrink_checkpoint_list() periodically release j_list_lock after processing a batch of buffers to avoid long hold times on the j_list_lock. However, since both functions contend for j_list_lock, the combined time spent waiting and processing can be significant. jbd2_journal_shrink_checkpoint_list() explicitly calls cond_resched() when need_resched() is true to avoid softlockups during prolonged operations. But jbd2_log_do_checkpoint() only exits its loop when need_resched() is true, relying on potentially sleeping functions like __flush_batch() or wait_on_buffer() to trigger rescheduling. If those functions do not sleep, the kernel may hit a softlockup. watchdog: BUG: soft lockup - CPU#3 stuck for 156s! [kworker/u129:2:373] CPU: 3 PID: 373 Comm: kworker/u129:2 Kdump: loaded Not tainted 6.6.0+ #10 Hardware name: Huawei TaiShan 2280 /BC11SPCD, BIOS 1.27 06/13/2017 Workqueue: writeback wb_workfn (flush-7:2) pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : native_queued_spin_lock_slowpath+0x358/0x418 lr : jbd2_log_do_checkpoint+0x31c/0x438 [jbd2] Call trace: native_queued_spin_lock_slowpath+0x358/0x418 jbd2_log_do_checkpoint+0x31c/0x438 [jbd2] __jbd2_log_wait_for_space+0xfc/0x2f8 [jbd2] add_transaction_credits+0x3bc/0x418 [jbd2] start_this_handle+0xf8/0x560 [jbd2] jbd2__journal_start+0x118/0x228 [jbd2] __ext4_journal_start_sb+0x110/0x188 [ext4] ext4_do_writepages+0x3dc/0x740 [ext4] ext4_writepages+0xa4/0x190 [ext4] do_writepages+0x94/0x228 __writeback_single_inode+0x48/0x318 writeback_sb_inodes+0x204/0x590 __writeback_inodes_wb+0x54/0xf8 wb_writeback+0x2cc/0x3d8 wb_do_writeback+0x2e0/0x2f8 wb_workfn+0x80/0x2a8 process_one_work+0x178/0x3e8 worker_thread+0x234/0x3b8 kthread+0xf0/0x108 ret_from_fork+0x10/0x20 So explicitly call cond_resched() in jbd2_log_do_checkpoint() to avoid softlockup. Cc: stable@kernel.org Signed-off-by: Baokun Li Link: https://patch.msgid.link/20250812063752.912130-1-libaokun@huaweicloud.com Signed-off-by: Theodore Ts'o --- fs/jbd2/checkpoint.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index b3971e91e8eb80..38861ca04899f0 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -285,6 +285,7 @@ int jbd2_log_do_checkpoint(journal_t *journal) retry: if (batch_count) __flush_batch(journal, &batch_count); + cond_resched(); spin_lock(&journal->j_list_lock); goto restart; } From 0c6b24d70da21201ed009a2aca740d2dfddc7ab5 Mon Sep 17 00:00:00 2001 From: Jason-JH Lin Date: Mon, 28 Jul 2025 10:48:50 +0800 Subject: [PATCH 0164/1292] drm/mediatek: Add error handling for old state CRTC in atomic_disable Introduce error handling to address an issue where, after a hotplug event, the cursor continues to update. This situation can lead to a kernel panic due to accessing the NULL `old_state->crtc`. E,g. Unable to handle kernel NULL pointer dereference at virtual address Call trace: mtk_crtc_plane_disable+0x24/0x140 mtk_plane_atomic_update+0x8c/0xa8 drm_atomic_helper_commit_planes+0x114/0x2c8 drm_atomic_helper_commit_tail_rpm+0x4c/0x158 commit_tail+0xa0/0x168 drm_atomic_helper_commit+0x110/0x120 drm_atomic_commit+0x8c/0xe0 drm_atomic_helper_update_plane+0xd4/0x128 __setplane_atomic+0xcc/0x110 drm_mode_cursor_common+0x250/0x440 drm_mode_cursor_ioctl+0x44/0x70 drm_ioctl+0x264/0x5d8 __arm64_sys_ioctl+0xd8/0x510 invoke_syscall+0x6c/0xe0 do_el0_svc+0x68/0xe8 el0_svc+0x34/0x60 el0t_64_sync_handler+0x1c/0xf8 el0t_64_sync+0x180/0x188 Adding NULL pointer checks to ensure stability by preventing operations on an invalid CRTC state. Fixes: d208261e9f7c ("drm/mediatek: Add wait_event_timeout when disabling plane") Signed-off-by: Jason-JH Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20250728025036.24953-1-jason-jh.lin@mediatek.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_plane.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c index cbc4f37da8ba81..02349bd4400176 100644 --- a/drivers/gpu/drm/mediatek/mtk_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_plane.c @@ -292,7 +292,8 @@ static void mtk_plane_atomic_disable(struct drm_plane *plane, wmb(); /* Make sure the above parameter is set before update */ mtk_plane_state->pending.dirty = true; - mtk_crtc_plane_disable(old_state->crtc, plane); + if (old_state && old_state->crtc) + mtk_crtc_plane_disable(old_state->crtc, plane); } static void mtk_plane_atomic_update(struct drm_plane *plane, From 75a7b151e808355a1fdf972e85da137612b8f2ae Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 12 Aug 2025 15:09:06 +0200 Subject: [PATCH 0165/1292] rust: devres: fix leaking call to devm_add_action() When the data argument of Devres::new() is Err(), we leak the preceding call to devm_add_action(). In order to fix this, call devm_add_action() in a unit type initializer in try_pin_init!() after the initializers of all other fields. Fixes: f5d3ef25d238 ("rust: devres: get rid of Devres' inner Arc") Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250812130928.11075-1-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/devres.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index da18091143a67f..d04e3fcebafbb3 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -115,10 +115,11 @@ pub struct Devres { /// Contains all the fields shared with [`Self::callback`]. // TODO: Replace with `UnsafePinned`, once available. // - // Subsequently, the `drop_in_place()` in `Devres::drop` and the explicit `Send` and `Sync' - // impls can be removed. + // Subsequently, the `drop_in_place()` in `Devres::drop` and `Devres::new` as well as the + // explicit `Send` and `Sync' impls can be removed. #[pin] inner: Opaque>, + _add_action: (), } impl Devres { @@ -140,7 +141,15 @@ impl Devres { dev: dev.into(), callback, // INVARIANT: `inner` is properly initialized. - inner <- { + inner <- Opaque::pin_init(try_pin_init!(Inner { + devm <- Completion::new(), + revoke <- Completion::new(), + data <- Revocable::new(data), + })), + // TODO: Replace with "initializer code blocks" [1] once available. + // + // [1] https://github.com/Rust-for-Linux/pin-init/pull/69 + _add_action: { // SAFETY: `this` is a valid pointer to uninitialized memory. let inner = unsafe { &raw mut (*this.as_ptr()).inner }; @@ -152,13 +161,13 @@ impl Devres { // live at least as long as the returned `impl PinInit`. to_result(unsafe { bindings::devm_add_action(dev.as_raw(), Some(callback), inner.cast()) - })?; + }).inspect_err(|_| { + let inner = Opaque::cast_into(inner); - Opaque::pin_init(try_pin_init!(Inner { - devm <- Completion::new(), - revoke <- Completion::new(), - data <- Revocable::new(data), - })) + // SAFETY: `inner` is a valid pointer to an `Inner` and valid for both reads + // and writes. + unsafe { core::ptr::drop_in_place(inner) }; + })?; }, }) } From daad2ef99145215fac1cab196811e3e03ef8bc9f Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 13 Aug 2025 07:54:31 +0000 Subject: [PATCH 0166/1292] rust: cpumask: rename CpumaskVar::as[_mut]_ref to from_raw[_mut] The prefix as_* shouldn't be used for constructors. For further motivation, see commit 2f5606afa4c2 ("device: rust: rename Device::as_ref() to Device::from_raw()"). Signed-off-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Yury Norov (NVIDIA) Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 2 +- rust/kernel/cpumask.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index afc15e72a7c37a..eea57ba95f241d 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -543,7 +543,7 @@ impl Policy { pub fn cpus(&mut self) -> &mut cpumask::Cpumask { // SAFETY: The pointer to `cpus` is valid for writing and remains valid for the lifetime of // the returned reference. - unsafe { cpumask::CpumaskVar::as_mut_ref(&mut self.as_mut_ref().cpus) } + unsafe { cpumask::CpumaskVar::from_raw_mut(&mut self.as_mut_ref().cpus) } } /// Sets clock for the [`Policy`]. diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs index 3fcbff43867054..e311ab9038dfda 100644 --- a/rust/kernel/cpumask.rs +++ b/rust/kernel/cpumask.rs @@ -270,7 +270,7 @@ impl CpumaskVar { /// /// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime /// of the returned reference. - pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self { + pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self { // SAFETY: Guaranteed by the safety requirements of the function. // // INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the @@ -284,7 +284,7 @@ impl CpumaskVar { /// /// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime /// of the returned reference. - pub unsafe fn as_ref<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self { + pub unsafe fn from_raw<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self { // SAFETY: Guaranteed by the safety requirements of the function. // // INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the From 23fca458f6ab18927e50c2134fb7b60297f18b4e Mon Sep 17 00:00:00 2001 From: Baptiste Lepers Date: Tue, 12 Aug 2025 16:42:11 +0200 Subject: [PATCH 0167/1292] rust: cpumask: Mark CpumaskVar as transparent Unsafe code in CpumaskVar's methods assumes that the type has the same layout as `bindings::cpumask_var_t`. This is not guaranteed by the default struct representation in Rust, but requires specifying the `transparent` representation. Fixes: 8961b8cb3099a ("rust: cpumask: Add initial abstractions") Signed-off-by: Baptiste Lepers Reviewed-by: Alice Ryhl Signed-off-by: Viresh Kumar --- rust/kernel/cpumask.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs index e311ab9038dfda..c1d17826ae7bb5 100644 --- a/rust/kernel/cpumask.rs +++ b/rust/kernel/cpumask.rs @@ -212,6 +212,7 @@ impl Cpumask { /// } /// assert_eq!(mask2.weight(), count); /// ``` +#[repr(transparent)] pub struct CpumaskVar { #[cfg(CONFIG_CPUMASK_OFFSTACK)] ptr: NonNull, From ea177a1b1efc6e42e73ee4a17581842cd254e006 Mon Sep 17 00:00:00 2001 From: Rudi Heitbaum Date: Tue, 12 Aug 2025 06:55:15 +0000 Subject: [PATCH 0168/1292] drm/rockchip: cdn-dp: select bridge for cdp-dp Select drm bridge connector when building cdp-dp. This was missed in previous commit causing build failure. Fixes: afbbca25d06e ("drm/rockchip: cdn-dp: Convert to drm bridge") Signed-off-by: Rudi Heitbaum Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/aJrlUzV1u4i65NRe@8eba3d7b3083 --- drivers/gpu/drm/rockchip/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index ab525668939a74..faf50d872be3d2 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -53,6 +53,7 @@ config ROCKCHIP_CDN_DP bool "Rockchip cdn DP" depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m) select DRM_DISPLAY_HELPER + select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_DP_HELPER help This selects support for Rockchip SoC specific extensions From a52dffaa46c2c5ff0b311c4dc1288581f7b9109e Mon Sep 17 00:00:00 2001 From: Piotr Zalewski Date: Sun, 6 Jul 2025 08:36:58 +0000 Subject: [PATCH 0169/1292] drm/rockchip: vop2: make vp registers nonvolatile Make video port registers nonvolatile. As DSP_CTRL register is written to twice due to gamma LUT enable bit which is set outside of the main DSP_CTRL initialization within atomic_enable (for rk356x case it is also necessary to always disable gamma LUT before writing a new LUT) there is a chance that DSP_CTRL value read-out in gamma LUT init/update code is not the one which was written by the preceding DSP_CTRL initialization code within atomic_enable. This might result in misconfigured DSP_CTRL which leads to no visual output[1]. Since DSP_CTRL write takes effect after VSYNC[1] the issue is not always present. When tested on Pinetab2 with kernel 6.14 it happenes only when DRM is compiled as a module[1]. In order to confirm that it is a timing issue I inserted 18ms udelay before vop2_crtc_atomic_try_set_gamma in atomic enable and compiled DRM as module - this has also fixed the issue. [1] https://lore.kernel.org/linux-rockchip/562b38e5.a496.1975f09f983.Coremail.andyshrk@163.com/ Reported-by: Diederik de Haas Closes: https://lore.kernel.org/linux-rockchip/DAEVDSTMWI1E.J454VZN0R9MA@cknow.org/ Suggested-by: Andy Yan Signed-off-by: Piotr Zalewski Tested-by: Diederik de Haas Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250706083629.140332-2-pZ010001011111@proton.me --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 186f6452a7d359..b50927a824b402 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2579,12 +2579,13 @@ static int vop2_win_init(struct vop2 *vop2) } /* - * The window registers are only updated when config done is written. - * Until that they read back the old value. As we read-modify-write - * these registers mark them as non-volatile. This makes sure we read - * the new values from the regmap register cache. + * The window and video port registers are only updated when config + * done is written. Until that they read back the old value. As we + * read-modify-write these registers mark them as non-volatile. This + * makes sure we read the new values from the regmap register cache. */ static const struct regmap_range vop2_nonvolatile_range[] = { + regmap_reg_range(RK3568_VP0_CTRL_BASE, RK3588_VP3_CTRL_BASE + 255), regmap_reg_range(0x1000, 0x23ff), }; From f5b1819193667bf62c3c99d3921b9429997a14b2 Mon Sep 17 00:00:00 2001 From: Louis-Alexis Eyraud Date: Tue, 1 Jul 2025 09:30:40 +0200 Subject: [PATCH 0170/1292] drm/mediatek: dsi: Fix DSI host and panel bridge pre-enable order Since commit c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable"), the bridge pre_enable callbacks are now called before crtc enable, and the bridge post_disable callbacks after the crtc disable. In the mediatek-drm driver, this change leads to transfer errors on mtk_dsi_host_transfer callback processing during the panel bridge pre-enable sequence because the DSI host bridge pre_enable and CRTC enable sequences, that are enabling the required clocks and PHY using mtk_dsi_poweron function, are called after. So, in order to fix this call order issue, request the DSI host bridge be pre-enabled before panel bridge by setting pre_enable_prev_first flag on DSI device bridge in the mtk_dsi_host_attach function. Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Signed-off-by: Louis-Alexis Eyraud Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20250701-mediatek-drm-fix-dsi-panel-init-v1-1-7af4adb9fdeb@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_dsi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index d7726091819c47..0e2bcd5f67b767 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -1002,6 +1002,12 @@ static int mtk_dsi_host_attach(struct mipi_dsi_host *host, return PTR_ERR(dsi->next_bridge); } + /* + * set flag to request the DSI host bridge be pre-enabled before device bridge + * in the chain, so the DSI host is ready when the device bridge is pre-enabled + */ + dsi->next_bridge->pre_enable_prev_first = true; + drm_bridge_add(&dsi->bridge); ret = component_add(host->dev, &mtk_dsi_component_ops); From 1548549e17e374a126e9a4e9edab8bb041fbd67e Mon Sep 17 00:00:00 2001 From: Alexandra Winter Date: Wed, 13 Aug 2025 13:16:33 +0200 Subject: [PATCH 0171/1292] MAINTAINERS: update s390/net Remove Thorsten Winkler as maintainer and add Aswin Karuvally as reviewer. Thank you Thorsten for your support, welcome Aswin! Signed-off-by: Alexandra Winter Acked-by: Thorsten Winkler Acked-by: Aswin Karuvally Link: https://patch.msgid.link/20250813111633.241111-1-wintera@linux.ibm.com Signed-off-by: Jakub Kicinski --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index daf520a13bdf6a..2720544cd91fda 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22174,7 +22174,7 @@ F: arch/s390/mm S390 NETWORK DRIVERS M: Alexandra Winter -M: Thorsten Winkler +R: Aswin Karuvally L: linux-s390@vger.kernel.org L: netdev@vger.kernel.org S: Supported From fd980bf6e9cdae885105685259421164f843ca55 Mon Sep 17 00:00:00 2001 From: Suraj Gupta Date: Wed, 13 Aug 2025 19:25:59 +0530 Subject: [PATCH 0172/1292] net: xilinx: axienet: Fix RX skb ring management in DMAengine mode Submit multiple descriptors in axienet_rx_cb() to fill Rx skb ring. This ensures the ring "catches up" on previously missed allocations. Increment Rx skb ring head pointer after BD is successfully allocated. Previously, head pointer was incremented before verifying if descriptor is successfully allocated and has valid entries, which could lead to ring state inconsistency if descriptor setup failed. These changes improve reliability by maintaining adequate descriptor availability and ensuring proper ring buffer state management. Fixes: 6a91b846af85 ("net: axienet: Introduce dmaengine support") Signed-off-by: Suraj Gupta Link: https://patch.msgid.link/20250813135559.1555652-1-suraj.gupta2@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 6011d7eae0c78a..0d8a05fe541afb 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1160,6 +1160,7 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result) struct axienet_local *lp = data; struct sk_buff *skb; u32 *app_metadata; + int i; skbuf_dma = axienet_get_rx_desc(lp, lp->rx_ring_tail++); skb = skbuf_dma->skb; @@ -1178,7 +1179,10 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result) u64_stats_add(&lp->rx_packets, 1); u64_stats_add(&lp->rx_bytes, rx_len); u64_stats_update_end(&lp->rx_stat_sync); - axienet_rx_submit_desc(lp->ndev); + + for (i = 0; i < CIRC_SPACE(lp->rx_ring_head, lp->rx_ring_tail, + RX_BUF_NUM_DEFAULT); i++) + axienet_rx_submit_desc(lp->ndev); dma_async_issue_pending(lp->rx_chan); } @@ -1457,7 +1461,6 @@ static void axienet_rx_submit_desc(struct net_device *ndev) if (!skbuf_dma) return; - lp->rx_ring_head++; skb = netdev_alloc_skb(ndev, lp->max_frm_size); if (!skb) return; @@ -1482,6 +1485,7 @@ static void axienet_rx_submit_desc(struct net_device *ndev) skbuf_dma->desc = dma_rx_desc; dma_rx_desc->callback_param = lp; dma_rx_desc->callback_result = axienet_dma_rx_cb; + lp->rx_ring_head++; dmaengine_submit(dma_rx_desc); return; From d1547bf460baec718b3398365f8de33d25c5f36f Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Wed, 13 Aug 2025 10:10:54 +0800 Subject: [PATCH 0173/1292] net: bridge: fix soft lockup in br_multicast_query_expired() When set multicast_query_interval to a large value, the local variable 'time' in br_multicast_send_query() may overflow. If the time is smaller than jiffies, the timer will expire immediately, and then call mod_timer() again, which creates a loop and may trigger the following soft lockup issue. watchdog: BUG: soft lockup - CPU#1 stuck for 221s! [rb_consumer:66] CPU: 1 UID: 0 PID: 66 Comm: rb_consumer Not tainted 6.16.0+ #259 PREEMPT(none) Call Trace: __netdev_alloc_skb+0x2e/0x3a0 br_ip6_multicast_alloc_query+0x212/0x1b70 __br_multicast_send_query+0x376/0xac0 br_multicast_send_query+0x299/0x510 br_multicast_query_expired.constprop.0+0x16d/0x1b0 call_timer_fn+0x3b/0x2a0 __run_timers+0x619/0x950 run_timer_softirq+0x11c/0x220 handle_softirqs+0x18e/0x560 __irq_exit_rcu+0x158/0x1a0 sysvec_apic_timer_interrupt+0x76/0x90 This issue can be reproduced with: ip link add br0 type bridge echo 1 > /sys/class/net/br0/bridge/multicast_querier echo 0xffffffffffffffff > /sys/class/net/br0/bridge/multicast_query_interval ip link set dev br0 up The multicast_startup_query_interval can also cause this issue. Similar to the commit 99b40610956a ("net: bridge: mcast: add and enforce query interval minimum"), add check for the query interval maximum to fix this issue. Link: https://lore.kernel.org/netdev/20250806094941.1285944-1-wangliang74@huawei.com/ Link: https://lore.kernel.org/netdev/20250812091818.542238-1-wangliang74@huawei.com/ Fixes: d902eee43f19 ("bridge: Add multicast count/interval sysfs entries") Suggested-by: Nikolay Aleksandrov Signed-off-by: Wang Liang Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250813021054.1643649-1-wangliang74@huawei.com Signed-off-by: Jakub Kicinski --- net/bridge/br_multicast.c | 16 ++++++++++++++++ net/bridge/br_private.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 1377f31b719cdd..8ce145938b02d9 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -4818,6 +4818,14 @@ void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx, intvl_jiffies = BR_MULTICAST_QUERY_INTVL_MIN; } + if (intvl_jiffies > BR_MULTICAST_QUERY_INTVL_MAX) { + br_info(brmctx->br, + "trying to set multicast query interval above maximum, setting to %lu (%ums)\n", + jiffies_to_clock_t(BR_MULTICAST_QUERY_INTVL_MAX), + jiffies_to_msecs(BR_MULTICAST_QUERY_INTVL_MAX)); + intvl_jiffies = BR_MULTICAST_QUERY_INTVL_MAX; + } + brmctx->multicast_query_interval = intvl_jiffies; } @@ -4834,6 +4842,14 @@ void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx, intvl_jiffies = BR_MULTICAST_STARTUP_QUERY_INTVL_MIN; } + if (intvl_jiffies > BR_MULTICAST_STARTUP_QUERY_INTVL_MAX) { + br_info(brmctx->br, + "trying to set multicast startup query interval above maximum, setting to %lu (%ums)\n", + jiffies_to_clock_t(BR_MULTICAST_STARTUP_QUERY_INTVL_MAX), + jiffies_to_msecs(BR_MULTICAST_STARTUP_QUERY_INTVL_MAX)); + intvl_jiffies = BR_MULTICAST_STARTUP_QUERY_INTVL_MAX; + } + brmctx->multicast_startup_query_interval = intvl_jiffies; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index b159aae594c0b0..8de0904b9627f7 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -31,6 +31,8 @@ #define BR_MULTICAST_DEFAULT_HASH_MAX 4096 #define BR_MULTICAST_QUERY_INTVL_MIN msecs_to_jiffies(1000) #define BR_MULTICAST_STARTUP_QUERY_INTVL_MIN BR_MULTICAST_QUERY_INTVL_MIN +#define BR_MULTICAST_QUERY_INTVL_MAX msecs_to_jiffies(86400000) /* 24 hours */ +#define BR_MULTICAST_STARTUP_QUERY_INTVL_MAX BR_MULTICAST_QUERY_INTVL_MAX #define BR_HWDOM_MAX BITS_PER_LONG From 52bf272636bda69587952b35ae97690b8dc89941 Mon Sep 17 00:00:00 2001 From: William Liu Date: Tue, 12 Aug 2025 23:57:57 +0000 Subject: [PATCH 0174/1292] net/sched: Fix backlog accounting in qdisc_dequeue_internal This issue applies for the following qdiscs: hhf, fq, fq_codel, and fq_pie, and occurs in their change handlers when adjusting to the new limit. The problem is the following in the values passed to the subsequent qdisc_tree_reduce_backlog call given a tbf parent: When the tbf parent runs out of tokens, skbs of these qdiscs will be placed in gso_skb. Their peek handlers are qdisc_peek_dequeued, which accounts for both qlen and backlog. However, in the case of qdisc_dequeue_internal, ONLY qlen is accounted for when pulling from gso_skb. This means that these qdiscs are missing a qdisc_qstats_backlog_dec when dropping packets to satisfy the new limit in their change handlers. One can observe this issue with the following (with tc patched to support a limit of 0): export TARGET=fq tc qdisc del dev lo root tc qdisc add dev lo root handle 1: tbf rate 8bit burst 100b latency 1ms tc qdisc replace dev lo handle 3: parent 1:1 $TARGET limit 1000 echo ''; echo 'add child'; tc -s -d qdisc show dev lo ping -I lo -f -c2 -s32 -W0.001 127.0.0.1 2>&1 >/dev/null echo ''; echo 'after ping'; tc -s -d qdisc show dev lo tc qdisc change dev lo handle 3: parent 1:1 $TARGET limit 0 echo ''; echo 'after limit drop'; tc -s -d qdisc show dev lo tc qdisc replace dev lo handle 2: parent 1:1 sfq echo ''; echo 'post graft'; tc -s -d qdisc show dev lo The second to last show command shows 0 packets but a positive number (74) of backlog bytes. The problem becomes clearer in the last show command, where qdisc_purge_queue triggers qdisc_tree_reduce_backlog with the positive backlog and causes an underflow in the tbf parent's backlog (4096 Mb instead of 0). To fix this issue, the codepath for all clients of qdisc_dequeue_internal has been simplified: codel, pie, hhf, fq, fq_pie, and fq_codel. qdisc_dequeue_internal handles the backlog adjustments for all cases that do not directly use the dequeue handler. The old fq_codel_change limit adjustment loop accumulated the arguments to the subsequent qdisc_tree_reduce_backlog call through the cstats field. However, this is confusing and error prone as fq_codel_dequeue could also potentially mutate this field (which qdisc_dequeue_internal calls in the non gso_skb case), so we have unified the code here with other qdiscs. Fixes: 2d3cbfd6d54a ("net_sched: Flush gso_skb list too during ->change()") Fixes: 4b549a2ef4be ("fq_codel: Fair Queue Codel AQM") Fixes: 10239edf86f1 ("net-qdisc-hhf: Heavy-Hitter Filter (HHF) qdisc") Signed-off-by: William Liu Reviewed-by: Savino Dicanosa Link: https://patch.msgid.link/20250812235725.45243-1-will@willsroot.io Signed-off-by: Jakub Kicinski --- include/net/sch_generic.h | 11 ++++++++--- net/sched/sch_codel.c | 12 +++++++----- net/sched/sch_fq.c | 12 +++++++----- net/sched/sch_fq_codel.c | 12 +++++++----- net/sched/sch_fq_pie.c | 12 +++++++----- net/sched/sch_hhf.c | 12 +++++++----- net/sched/sch_pie.c | 12 +++++++----- 7 files changed, 50 insertions(+), 33 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 638948be4c50e2..738cd5b13c62fb 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -1038,12 +1038,17 @@ static inline struct sk_buff *qdisc_dequeue_internal(struct Qdisc *sch, bool dir skb = __skb_dequeue(&sch->gso_skb); if (skb) { sch->q.qlen--; + qdisc_qstats_backlog_dec(sch, skb); return skb; } - if (direct) - return __qdisc_dequeue_head(&sch->q); - else + if (direct) { + skb = __qdisc_dequeue_head(&sch->q); + if (skb) + qdisc_qstats_backlog_dec(sch, skb); + return skb; + } else { return sch->dequeue(sch); + } } static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch) diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index c93761040c6e77..fa0314679e434a 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -101,9 +101,9 @@ static const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] = { static int codel_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { + unsigned int dropped_pkts = 0, dropped_bytes = 0; struct codel_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_CODEL_MAX + 1]; - unsigned int qlen, dropped = 0; int err; err = nla_parse_nested_deprecated(tb, TCA_CODEL_MAX, opt, @@ -142,15 +142,17 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt, WRITE_ONCE(q->params.ecn, !!nla_get_u32(tb[TCA_CODEL_ECN])); - qlen = sch->q.qlen; while (sch->q.qlen > sch->limit) { struct sk_buff *skb = qdisc_dequeue_internal(sch, true); - dropped += qdisc_pkt_len(skb); - qdisc_qstats_backlog_dec(sch, skb); + if (!skb) + break; + + dropped_pkts++; + dropped_bytes += qdisc_pkt_len(skb); rtnl_qdisc_drop(skb, sch); } - qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes); sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 902ff54706072b..fee922da2f99c0 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -1013,11 +1013,11 @@ static int fq_load_priomap(struct fq_sched_data *q, static int fq_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { + unsigned int dropped_pkts = 0, dropped_bytes = 0; struct fq_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_FQ_MAX + 1]; - int err, drop_count = 0; - unsigned drop_len = 0; u32 fq_log; + int err; err = nla_parse_nested_deprecated(tb, TCA_FQ_MAX, opt, fq_policy, NULL); @@ -1135,16 +1135,18 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt, err = fq_resize(sch, fq_log); sch_tree_lock(sch); } + while (sch->q.qlen > sch->limit) { struct sk_buff *skb = qdisc_dequeue_internal(sch, false); if (!skb) break; - drop_len += qdisc_pkt_len(skb); + + dropped_pkts++; + dropped_bytes += qdisc_pkt_len(skb); rtnl_kfree_skbs(skb, skb); - drop_count++; } - qdisc_tree_reduce_backlog(sch, drop_count, drop_len); + qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes); sch_tree_unlock(sch); return err; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 2a0f3a513bfaa1..a141423929394d 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -366,6 +366,7 @@ static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = { static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { + unsigned int dropped_pkts = 0, dropped_bytes = 0; struct fq_codel_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_FQ_CODEL_MAX + 1]; u32 quantum = 0; @@ -443,13 +444,14 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt, q->memory_usage > q->memory_limit) { struct sk_buff *skb = qdisc_dequeue_internal(sch, false); - q->cstats.drop_len += qdisc_pkt_len(skb); + if (!skb) + break; + + dropped_pkts++; + dropped_bytes += qdisc_pkt_len(skb); rtnl_kfree_skbs(skb, skb); - q->cstats.drop_count++; } - qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len); - q->cstats.drop_count = 0; - q->cstats.drop_len = 0; + qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes); sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c index b0e34daf1f7517..7b96bc3ff89184 100644 --- a/net/sched/sch_fq_pie.c +++ b/net/sched/sch_fq_pie.c @@ -287,10 +287,9 @@ static struct sk_buff *fq_pie_qdisc_dequeue(struct Qdisc *sch) static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { + unsigned int dropped_pkts = 0, dropped_bytes = 0; struct fq_pie_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_FQ_PIE_MAX + 1]; - unsigned int len_dropped = 0; - unsigned int num_dropped = 0; int err; err = nla_parse_nested(tb, TCA_FQ_PIE_MAX, opt, fq_pie_policy, extack); @@ -368,11 +367,14 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt, while (sch->q.qlen > sch->limit) { struct sk_buff *skb = qdisc_dequeue_internal(sch, false); - len_dropped += qdisc_pkt_len(skb); - num_dropped += 1; + if (!skb) + break; + + dropped_pkts++; + dropped_bytes += qdisc_pkt_len(skb); rtnl_kfree_skbs(skb, skb); } - qdisc_tree_reduce_backlog(sch, num_dropped, len_dropped); + qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes); sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 5aa434b4670738..2d4855e28a286f 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -508,9 +508,9 @@ static const struct nla_policy hhf_policy[TCA_HHF_MAX + 1] = { static int hhf_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { + unsigned int dropped_pkts = 0, dropped_bytes = 0; struct hhf_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_HHF_MAX + 1]; - unsigned int qlen, prev_backlog; int err; u64 non_hh_quantum; u32 new_quantum = q->quantum; @@ -561,15 +561,17 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt, usecs_to_jiffies(us)); } - qlen = sch->q.qlen; - prev_backlog = sch->qstats.backlog; while (sch->q.qlen > sch->limit) { struct sk_buff *skb = qdisc_dequeue_internal(sch, false); + if (!skb) + break; + + dropped_pkts++; + dropped_bytes += qdisc_pkt_len(skb); rtnl_kfree_skbs(skb, skb); } - qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, - prev_backlog - sch->qstats.backlog); + qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes); sch_tree_unlock(sch); return 0; diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index ad46ee3ed5a968..0a377313b6a9d2 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -141,9 +141,9 @@ static const struct nla_policy pie_policy[TCA_PIE_MAX + 1] = { static int pie_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { + unsigned int dropped_pkts = 0, dropped_bytes = 0; struct pie_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_PIE_MAX + 1]; - unsigned int qlen, dropped = 0; int err; err = nla_parse_nested_deprecated(tb, TCA_PIE_MAX, opt, pie_policy, @@ -193,15 +193,17 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt, nla_get_u32(tb[TCA_PIE_DQ_RATE_ESTIMATOR])); /* Drop excess packets if new limit is lower */ - qlen = sch->q.qlen; while (sch->q.qlen > sch->limit) { struct sk_buff *skb = qdisc_dequeue_internal(sch, true); - dropped += qdisc_pkt_len(skb); - qdisc_qstats_backlog_dec(sch, skb); + if (!skb) + break; + + dropped_pkts++; + dropped_bytes += qdisc_pkt_len(skb); rtnl_qdisc_drop(skb, sch); } - qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes); sch_tree_unlock(sch); return 0; From 8c06cbdcbaea34d7b96d76df4d6669275c1d291a Mon Sep 17 00:00:00 2001 From: William Liu Date: Tue, 12 Aug 2025 23:58:26 +0000 Subject: [PATCH 0175/1292] selftests/tc-testing: Check backlog stats in gso_skb case Add tests to ensure proper backlog accounting in hhf, codel, pie, fq, fq_pie, and fq_codel qdiscs. We check for the bug pattern originally found in fq, fq_pie, and fq_codel, which was an underflow in the tbf parent backlog stats upon child qdisc removal. Signed-off-by: William Liu Reviewed-by: Savino Dicanosa Link: https://patch.msgid.link/20250812235808.45281-1-will@willsroot.io Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/infra/qdiscs.json | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json b/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json index 23a61e5b99d024..998e5a2f457965 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json +++ b/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json @@ -185,6 +185,204 @@ "$IP addr del 10.10.10.10/24 dev $DUMMY || true" ] }, + { + "id": "34c0", + "name": "Test TBF with HHF Backlog Accounting in gso_skb case against underflow", + "category": [ + "qdisc", + "tbf", + "hhf" + ], + "plugins": { + "requires": [ + "nsPlugin" + ] + }, + "setup": [ + "$IP link set dev $DUMMY up || true", + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", + "$TC qdisc replace dev $DUMMY handle 2: parent 1:1 hhf limit 1000", + [ + "ping -I $DUMMY -c2 10.10.11.11", + 1 + ], + "$TC qdisc change dev $DUMMY handle 2: parent 1:1 hhf limit 1" + ], + "cmdUnderTest": "$TC qdisc del dev $DUMMY handle 2: parent 1:1", + "expExitCode": "0", + "verifyCmd": "$TC -s qdisc show dev $DUMMY", + "matchPattern": "backlog 0b 0p", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY handle 1: root" + ] + }, + { + "id": "fd68", + "name": "Test TBF with CODEL Backlog Accounting in gso_skb case against underflow", + "category": [ + "qdisc", + "tbf", + "codel" + ], + "plugins": { + "requires": [ + "nsPlugin" + ] + }, + "setup": [ + "$IP link set dev $DUMMY up || true", + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", + "$TC qdisc replace dev $DUMMY handle 2: parent 1:1 codel limit 1000", + [ + "ping -I $DUMMY -c2 10.10.11.11", + 1 + ], + "$TC qdisc change dev $DUMMY handle 2: parent 1:1 codel limit 1" + ], + "cmdUnderTest": "$TC qdisc del dev $DUMMY handle 2: parent 1:1", + "expExitCode": "0", + "verifyCmd": "$TC -s qdisc show dev $DUMMY", + "matchPattern": "backlog 0b 0p", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY handle 1: root" + ] + }, + { + "id": "514e", + "name": "Test TBF with PIE Backlog Accounting in gso_skb case against underflow", + "category": [ + "qdisc", + "tbf", + "pie" + ], + "plugins": { + "requires": [ + "nsPlugin" + ] + }, + "setup": [ + "$IP link set dev $DUMMY up || true", + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", + "$TC qdisc replace dev $DUMMY handle 2: parent 1:1 pie limit 1000", + [ + "ping -I $DUMMY -c2 10.10.11.11", + 1 + ], + "$TC qdisc change dev $DUMMY handle 2: parent 1:1 pie limit 1" + ], + "cmdUnderTest": "$TC qdisc del dev $DUMMY handle 2: parent 1:1", + "expExitCode": "0", + "verifyCmd": "$TC -s qdisc show dev $DUMMY", + "matchPattern": "backlog 0b 0p", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY handle 1: root" + ] + }, + { + "id": "6c97", + "name": "Test TBF with FQ Backlog Accounting in gso_skb case against underflow", + "category": [ + "qdisc", + "tbf", + "fq" + ], + "plugins": { + "requires": [ + "nsPlugin" + ] + }, + "setup": [ + "$IP link set dev $DUMMY up || true", + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", + "$TC qdisc replace dev $DUMMY handle 2: parent 1:1 fq limit 1000", + [ + "ping -I $DUMMY -c2 10.10.11.11", + 1 + ], + "$TC qdisc change dev $DUMMY handle 2: parent 1:1 fq limit 1" + ], + "cmdUnderTest": "$TC qdisc del dev $DUMMY handle 2: parent 1:1", + "expExitCode": "0", + "verifyCmd": "$TC -s qdisc show dev $DUMMY", + "matchPattern": "backlog 0b 0p", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY handle 1: root" + ] + }, + { + "id": "5d0b", + "name": "Test TBF with FQ_CODEL Backlog Accounting in gso_skb case against underflow", + "category": [ + "qdisc", + "tbf", + "fq_codel" + ], + "plugins": { + "requires": [ + "nsPlugin" + ] + }, + "setup": [ + "$IP link set dev $DUMMY up || true", + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", + "$TC qdisc replace dev $DUMMY handle 2: parent 1:1 fq_codel limit 1000", + [ + "ping -I $DUMMY -c2 10.10.11.11", + 1 + ], + "$TC qdisc change dev $DUMMY handle 2: parent 1:1 fq_codel limit 1" + ], + "cmdUnderTest": "$TC qdisc del dev $DUMMY handle 2: parent 1:1", + "expExitCode": "0", + "verifyCmd": "$TC -s qdisc show dev $DUMMY", + "matchPattern": "backlog 0b 0p", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY handle 1: root" + ] + }, + { + "id": "21c3", + "name": "Test TBF with FQ_PIE Backlog Accounting in gso_skb case against underflow", + "category": [ + "qdisc", + "tbf", + "fq_pie" + ], + "plugins": { + "requires": [ + "nsPlugin" + ] + }, + "setup": [ + "$IP link set dev $DUMMY up || true", + "$IP addr add 10.10.11.10/24 dev $DUMMY || true", + "$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 100ms", + "$TC qdisc replace dev $DUMMY handle 2: parent 1:1 fq_pie limit 1000", + [ + "ping -I $DUMMY -c2 10.10.11.11", + 1 + ], + "$TC qdisc change dev $DUMMY handle 2: parent 1:1 fq_pie limit 1" + ], + "cmdUnderTest": "$TC qdisc del dev $DUMMY handle 2: parent 1:1", + "expExitCode": "0", + "verifyCmd": "$TC -s qdisc show dev $DUMMY", + "matchPattern": "backlog 0b 0p", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY handle 1: root" + ] + }, { "id": "a4bb", "name": "Test FQ_CODEL with HTB parent - force packet drop with empty queue", From 065c31f2c6915b38f45b1c817b31f41f62eaa774 Mon Sep 17 00:00:00 2001 From: Justin Lai Date: Wed, 13 Aug 2025 15:16:31 +0800 Subject: [PATCH 0176/1292] rtase: Fix Rx descriptor CRC error bit definition The CRC error bit is located at bit 17 in the Rx descriptor, but the driver was incorrectly using bit 16. Fix it. Fixes: a36e9f5cfe9e ("rtase: Add support for a pci table in this module") Signed-off-by: Justin Lai Link: https://patch.msgid.link/20250813071631.7566-1-justinlai0215@realtek.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/rtase/rtase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/rtase/rtase.h b/drivers/net/ethernet/realtek/rtase/rtase.h index 20decdeb9fdbb7..b9209eb6ea7350 100644 --- a/drivers/net/ethernet/realtek/rtase/rtase.h +++ b/drivers/net/ethernet/realtek/rtase/rtase.h @@ -241,7 +241,7 @@ union rtase_rx_desc { #define RTASE_RX_RES BIT(20) #define RTASE_RX_RUNT BIT(19) #define RTASE_RX_RWT BIT(18) -#define RTASE_RX_CRC BIT(16) +#define RTASE_RX_CRC BIT(17) #define RTASE_RX_V6F BIT(31) #define RTASE_RX_V4F BIT(30) #define RTASE_RX_UDPT BIT(29) From d73915fdc0011d536c03856be7ec451f6a5fb4ff Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 31 Jul 2025 15:42:18 -0700 Subject: [PATCH 0177/1292] lib/crypto: sha: Update Kconfig help for SHA1 and SHA256 Update the help text for CRYPTO_LIB_SHA1 and CRYPTO_LIB_SHA256 to reflect the addition of HMAC support, and to be consistent with CRYPTO_LIB_SHA512. Link: https://lore.kernel.org/r/20250731224218.137947-1-ebiggers@kernel.org Signed-off-by: Eric Biggers --- lib/crypto/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig index c2b65b6a9bb6f3..1e6b008f8fca45 100644 --- a/lib/crypto/Kconfig +++ b/lib/crypto/Kconfig @@ -140,8 +140,8 @@ config CRYPTO_LIB_CHACHA20POLY1305 config CRYPTO_LIB_SHA1 tristate help - The SHA-1 library functions. Select this if your module uses any of - the functions from . + The SHA-1 and HMAC-SHA1 library functions. Select this if your module + uses any of the functions from . config CRYPTO_LIB_SHA1_ARCH bool @@ -157,9 +157,9 @@ config CRYPTO_LIB_SHA1_ARCH config CRYPTO_LIB_SHA256 tristate help - Enable the SHA-256 library interface. This interface may be fulfilled - by either the generic implementation or an arch-specific one, if one - is available and enabled. + The SHA-224, SHA-256, HMAC-SHA224, and HMAC-SHA256 library functions. + Select this if your module uses any of these functions from + . config CRYPTO_LIB_SHA256_ARCH bool From fd7e5de4b2eddd34e3567cd419812d8869ef4f13 Mon Sep 17 00:00:00 2001 From: Tal Zussman Date: Thu, 14 Aug 2025 02:51:57 -0400 Subject: [PATCH 0178/1292] lib/crypto: ensure generated *.S files are removed on make clean make clean does not check the kernel config when removing files. As such, additions to clean-files under CONFIG_ARM or CONFIG_ARM64 are not evaluated. For example, when building on arm64, this means that lib/crypto/arm64/sha{256,512}-core.S are left over after make clean. Set clean-files unconditionally to ensure that make clean removes these files. Fixes: e96cb9507f2d ("lib/crypto: sha256: Consolidate into single module") Fixes: 24c91b62ac50 ("lib/crypto: arm/sha512: Migrate optimized SHA-512 code to library") Fixes: 60e3f1e9b7a5 ("lib/crypto: arm64/sha512: Migrate optimized SHA-512 code to library") Signed-off-by: Tal Zussman Link: https://lore.kernel.org/r/20250814-crypto_clean-v2-1-659a2dc86302@columbia.edu Signed-off-by: Eric Biggers --- lib/crypto/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile index e4151be2ebd448..539d5d59a50e48 100644 --- a/lib/crypto/Makefile +++ b/lib/crypto/Makefile @@ -100,7 +100,6 @@ ifeq ($(CONFIG_ARM),y) libsha256-y += arm/sha256-ce.o arm/sha256-core.o $(obj)/arm/sha256-core.S: $(src)/arm/sha256-armv4.pl $(call cmd,perlasm) -clean-files += arm/sha256-core.S AFLAGS_arm/sha256-core.o += $(aflags-thumb2-y) endif @@ -108,7 +107,6 @@ ifeq ($(CONFIG_ARM64),y) libsha256-y += arm64/sha256-core.o $(obj)/arm64/sha256-core.S: $(src)/arm64/sha2-armv8.pl $(call cmd,perlasm_with_args) -clean-files += arm64/sha256-core.S libsha256-$(CONFIG_KERNEL_MODE_NEON) += arm64/sha256-ce.o endif @@ -132,7 +130,6 @@ ifeq ($(CONFIG_ARM),y) libsha512-y += arm/sha512-core.o $(obj)/arm/sha512-core.S: $(src)/arm/sha512-armv4.pl $(call cmd,perlasm) -clean-files += arm/sha512-core.S AFLAGS_arm/sha512-core.o += $(aflags-thumb2-y) endif @@ -140,7 +137,6 @@ ifeq ($(CONFIG_ARM64),y) libsha512-y += arm64/sha512-core.o $(obj)/arm64/sha512-core.S: $(src)/arm64/sha2-armv8.pl $(call cmd,perlasm_with_args) -clean-files += arm64/sha512-core.S libsha512-$(CONFIG_KERNEL_MODE_NEON) += arm64/sha512-ce-core.o endif @@ -167,3 +163,7 @@ obj-$(CONFIG_PPC) += powerpc/ obj-$(CONFIG_RISCV) += riscv/ obj-$(CONFIG_S390) += s390/ obj-$(CONFIG_X86) += x86/ + +# clean-files must be defined unconditionally +clean-files += arm/sha256-core.S arm/sha512-core.S +clean-files += arm64/sha256-core.S arm64/sha512-core.S From fad2cf04e91fd3c4310731537bf98d1f8a0b4137 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 12 Aug 2025 10:28:05 +0200 Subject: [PATCH 0179/1292] scsi: fnic: Remove a useless struct mempool forward declaration struct mempool doesn't currently exist, and thus also isn't used in fnic.h, remove it. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20250812082808.371119-1-hch@lst.de Reviewed-by: Karan Tilak Kumar Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index c2fdc6553e627a..1199d701c3f590 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -323,8 +323,6 @@ enum fnic_state { FNIC_IN_ETH_TRANS_FC_MODE, }; -struct mempool; - enum fnic_role_e { FNIC_ROLE_FCP_INITIATOR = 0, }; From 50a8c08b8b69399a09c2dbcad8ef3fef9d9349d2 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Wed, 6 Aug 2025 17:52:24 +0800 Subject: [PATCH 0180/1292] drm/bridge: analogix_dp: Fix bailout for devm_drm_bridge_alloc() devm_drm_bridge_alloc() returns ERR_PTR on failure instead of a NULL pointer, so use IS_ERR() to check the returned pointer. While at it, on failure, return ERR_CAST(dp) instead of ERR_PTR(-ENOMEM) in order not to depend on devm_drm_bridge_alloc() error code implementation. Fixes: 48f05c3b4b70 ("drm/bridge: analogix_dp: Use devm_drm_bridge_alloc() API") Signed-off-by: Liu Ying Reviewed-by: Luca Ceresoli Link: https://lore.kernel.org/r/20250806095224.527938-1-victor.liu@nxp.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index ed35e567d11729..efe534977d12de 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1474,8 +1474,8 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) dp = devm_drm_bridge_alloc(dev, struct analogix_dp_device, bridge, &analogix_dp_bridge_funcs); - if (!dp) - return ERR_PTR(-ENOMEM); + if (IS_ERR(dp)) + return ERR_CAST(dp); dp->dev = &pdev->dev; dp->dpms_mode = DRM_MODE_DPMS_OFF; From 823f95575d85454ccad7d5b684aec42e57b962f6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Aug 2025 16:02:59 +0300 Subject: [PATCH 0181/1292] scsi: ufs: ufs-pci: Add support for Intel Wildcat Lake Add PCI ID to support Intel Wildcat Lake, same as MTL. Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20250812130259.109645-1-adrian.hunter@intel.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufshcd-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c index b39239f641f21b..b87e037773955f 100644 --- a/drivers/ufs/host/ufshcd-pci.c +++ b/drivers/ufs/host/ufshcd-pci.c @@ -630,6 +630,7 @@ static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0xA847), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, { PCI_VDEVICE(INTEL, 0x7747), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, { PCI_VDEVICE(INTEL, 0xE447), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4D47), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, { } /* terminate list */ }; From 9dcf111dd3e7ed5fce82bb108e3a3fc001c07225 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Aug 2025 08:49:08 +0300 Subject: [PATCH 0182/1292] scsi: qla4xxx: Prevent a potential error pointer dereference The qla4xxx_get_ep_fwdb() function is supposed to return NULL on error, but qla4xxx_ep_connect() returns error pointers. Propagating the error pointers will lead to an Oops in the caller, so change the error pointers to NULL. Fixes: 13483730a13b ("[SCSI] qla4xxx: fix flash/ddb support") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/aJwnVKS9tHsw1tEu@stanley.mountain Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index a39f1da4ce474b..a761c0aa5127fe 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -6606,6 +6606,8 @@ static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, ep = qla4xxx_ep_connect(ha->host, (struct sockaddr *)dst_addr, 0); vfree(dst_addr); + if (IS_ERR(ep)) + return NULL; return ep; } From 8503d0fcb1086a7cfe26df67ca4bd9bd9e99bdec Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 4 Aug 2025 08:40:27 -0700 Subject: [PATCH 0183/1292] iommu/amd: Avoid stack buffer overflow from kernel cmdline While the kernel command line is considered trusted in most environments, avoid writing 1 byte past the end of "acpiid" if the "str" argument is maximum length. Reported-by: Simcha Kosman Closes: https://lore.kernel.org/all/AS8P193MB2271C4B24BCEDA31830F37AE84A52@AS8P193MB2271.EURP193.PROD.OUTLOOK.COM Fixes: b6b26d86c61c ("iommu/amd: Add a length limitation for the ivrs_acpihid command-line parameter") Signed-off-by: Kees Cook Reviewed-by: Ankit Soni Link: https://lore.kernel.org/r/20250804154023.work.970-kees@kernel.org Signed-off-by: Joerg Roedel --- drivers/iommu/amd/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 7b5af6176de990..8de689b2c5ed57 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -3638,7 +3638,7 @@ static int __init parse_ivrs_acpihid(char *str) { u32 seg = 0, bus, dev, fn; char *hid, *uid, *p, *addr; - char acpiid[ACPIID_LEN] = {0}; + char acpiid[ACPIID_LEN + 1] = { }; /* size with NULL terminator */ int i; addr = strchr(str, '@'); @@ -3664,7 +3664,7 @@ static int __init parse_ivrs_acpihid(char *str) /* We have the '@', make it the terminator to get just the acpiid */ *addr++ = 0; - if (strlen(str) > ACPIID_LEN + 1) + if (strlen(str) > ACPIID_LEN) goto not_found; if (sscanf(str, "=%s", acpiid) != 1) From 41f0200c718cf1826959a082a5374838c15bd242 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Thu, 14 Aug 2025 12:30:38 -0700 Subject: [PATCH 0184/1292] iommu/tegra241-cmdqv: Fix missing cpu_to_le64 at lvcmdq_err_map Sparse reported a warning: drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:305:47: sparse: expected restricted __le64 sparse: got unsigned long long Add cpu_to_le64() to fix that. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508142105.Jb5Smjsg-lkp@intel.com/ Suggested-by: Pranjal Shrivastava Signed-off-by: Nicolin Chen Link: https://lore.kernel.org/r/20250814193039.2265813-1-nicolinc@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c index be1aaaf8cd17c8..378104cd395e59 100644 --- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c @@ -301,9 +301,11 @@ static void tegra241_vintf_user_handle_error(struct tegra241_vintf *vintf) struct iommu_vevent_tegra241_cmdqv vevent_data; int i; - for (i = 0; i < LVCMDQ_ERR_MAP_NUM_64; i++) - vevent_data.lvcmdq_err_map[i] = - readq_relaxed(REG_VINTF(vintf, LVCMDQ_ERR_MAP_64(i))); + for (i = 0; i < LVCMDQ_ERR_MAP_NUM_64; i++) { + u64 err = readq_relaxed(REG_VINTF(vintf, LVCMDQ_ERR_MAP_64(i))); + + vevent_data.lvcmdq_err_map[i] = cpu_to_le64(err); + } iommufd_viommu_report_event(viommu, IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV, &vevent_data, sizeof(vevent_data)); From b64fdd422a85025b5e91ead794db9d3ef970e369 Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Tue, 12 Aug 2025 18:10:47 +0000 Subject: [PATCH 0185/1292] perf: Avoid undefined behavior from stopping/starting inactive events Calling pmu->start()/stop() on perf events in PERF_EVENT_STATE_OFF can leave event->hw.idx at -1. When PMU drivers later attempt to use this negative index as a shift exponent in bitwise operations, it leads to UBSAN shift-out-of-bounds reports. The issue is a logical flaw in how event groups handle throttling when some members are intentionally disabled. Based on the analysis and the reproducer provided by Mark Rutland (this issue on both arm64 and x86-64). The scenario unfolds as follows: 1. A group leader event is configured with a very aggressive sampling period (e.g., sample_period = 1). This causes frequent interrupts and triggers the throttling mechanism. 2. A child event in the same group is created in a disabled state (.disabled = 1). This event remains in PERF_EVENT_STATE_OFF. Since it hasn't been scheduled onto the PMU, its event->hw.idx remains initialized at -1. 3. When throttling occurs, perf_event_throttle_group() and later perf_event_unthrottle_group() iterate through all siblings, including the disabled child event. 4. perf_event_throttle()/unthrottle() are called on this inactive child event, which then call event->pmu->start()/stop(). 5. The PMU driver receives the event with hw.idx == -1 and attempts to use it as a shift exponent. e.g., in macros like PMCNTENSET(idx), leading to the UBSAN report. The throttling mechanism attempts to start/stop events that are not actively scheduled on the hardware. Move the state check into perf_event_throttle()/perf_event_unthrottle() so that inactive events are skipped entirely. This ensures only active events with a valid hw.idx are processed, preventing undefined behavior and silencing UBSAN warnings. The corrected check ensures true before proceeding with PMU operations. The problem can be reproduced with the syzkaller reproducer: Fixes: 9734e25fbf5a ("perf: Fix the throttle logic for a group") Signed-off-by: Yunseong Kim Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Kan Liang Link: https://lore.kernel.org/r/20250812181046.292382-2-ysk@kzalloc.com --- kernel/events/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index 8060c2857bb2b3..872122e074e5fe 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2665,6 +2665,9 @@ static void perf_log_itrace_start(struct perf_event *event); static void perf_event_unthrottle(struct perf_event *event, bool start) { + if (event->state != PERF_EVENT_STATE_ACTIVE) + return; + event->hw.interrupts = 0; if (start) event->pmu->start(event, 0); @@ -2674,6 +2677,9 @@ static void perf_event_unthrottle(struct perf_event *event, bool start) static void perf_event_throttle(struct perf_event *event) { + if (event->state != PERF_EVENT_STATE_ACTIVE) + return; + event->hw.interrupts = MAX_INTERRUPTS; event->pmu->stop(event, 0); if (event == event->group_leader) From de5d7d3f27ddd4046736f558a40e252ddda82013 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 28 Jul 2025 17:08:44 +0800 Subject: [PATCH 0186/1292] Bluetooth: hci_sync: Avoid adding default advertising on startup list_empty(&hdev->adv_instances) is always true during startup, so an advertising instance is added by default. Call trace: dump_backtrace+0x94/0xec show_stack+0x18/0x24 dump_stack_lvl+0x48/0x60 dump_stack+0x18/0x24 hci_setup_ext_adv_instance_sync+0x17c/0x328 hci_powered_update_adv_sync+0xb4/0x12c hci_powered_update_sync+0x54/0x70 hci_power_on_sync+0xe4/0x278 hci_set_powered_sync+0x28/0x34 set_powered_sync+0x40/0x58 hci_cmd_sync_work+0x94/0x100 process_one_work+0x168/0x444 worker_thread+0x378/0x3f4 kthread+0x108/0x10c ret_from_fork+0x10/0x20 Link: https://github.com/bluez/bluez/issues/1442 Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 2b4f21fbf9c144..7397b6b50ccbe6 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -3344,7 +3344,7 @@ static int hci_powered_update_adv_sync(struct hci_dev *hdev) * advertising data. This also applies to the case * where BR/EDR was toggled during the AUTO_OFF phase. */ - if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || + if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && list_empty(&hdev->adv_instances)) { if (ext_adv_capable(hdev)) { err = hci_setup_ext_adv_instance_sync(hdev, 0x00); From ca88be1a2725a42f8dbad579181611d9dcca8e88 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 24 Jul 2025 16:43:18 -0400 Subject: [PATCH 0187/1292] Bluetooth: hci_sync: Fix scan state after PA Sync has been established Passive scanning is used to program the address of the peer to be synchronized, so once HCI_EV_LE_PA_SYNC_ESTABLISHED is received it needs to be updated after clearing HCI_PA_SYNC then call hci_update_passive_scan_sync to return it to its original state. Fixes: 6d0417e4e1cf ("Bluetooth: hci_conn: Fix not setting conn_timeout for Broadcast Receiver") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 7397b6b50ccbe6..387c128f2ba0a6 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -6985,8 +6985,6 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) hci_dev_lock(hdev); - hci_dev_clear_flag(hdev, HCI_PA_SYNC); - if (!hci_conn_valid(hdev, conn)) clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); @@ -7080,6 +7078,11 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data) __hci_cmd_sync_status(hdev, HCI_OP_LE_PA_CREATE_SYNC_CANCEL, 0, NULL, HCI_CMD_TIMEOUT); + hci_dev_clear_flag(hdev, HCI_PA_SYNC); + + /* Update passive scan since HCI_PA_SYNC flag has been cleared */ + hci_update_passive_scan_sync(hdev); + return err; } From aee29c18a38d479c2f058c9b6a39b0527cf81d10 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 24 Jul 2025 16:36:27 -0400 Subject: [PATCH 0188/1292] Bluetooth: ISO: Fix getname not returning broadcast fields getname shall return iso_bc fields for both BIS_LINK and PA_LINK since the likes of bluetoothd do use the getpeername to retrieve the SID both when enumerating the broadcasters and when synchronizing. Fixes: a7bcffc673de ("Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/iso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 7bd3aa0a6db9ad..eaffd25570e3b0 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -1347,7 +1347,7 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr, bacpy(&sa->iso_bdaddr, &iso_pi(sk)->dst); sa->iso_bdaddr_type = iso_pi(sk)->dst_type; - if (hcon && hcon->type == BIS_LINK) { + if (hcon && (hcon->type == BIS_LINK || hcon->type == PA_LINK)) { sa->iso_bc->bc_sid = iso_pi(sk)->bc_sid; sa->iso_bc->bc_num_bis = iso_pi(sk)->bc_num_bis; memcpy(sa->iso_bc->bc_bis, iso_pi(sk)->bc_bis, From d36349ea73d805bb72cbc24ab90cb1da4ad5c379 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 28 Jul 2025 13:51:01 -0400 Subject: [PATCH 0189/1292] Bluetooth: hci_conn: Fix running bis_cleanup for hci_conn->type PA_LINK Connections with type of PA_LINK shall be considered temporary just to track the lifetime of PA Sync setup, once the BIG Sync is established and connection are created with BIS_LINK the existing PA_LINK connection shall not longer use bis_cleanup otherwise it terminates the PA Sync when that shall be left to BIS_LINK connection to do it. Fixes: a7bcffc673de ("Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 12 +++++++++++- net/bluetooth/hci_event.c | 7 ++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7d1e79f69cd1cb..f8b20b609a0394 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -830,7 +830,17 @@ static void bis_cleanup(struct hci_conn *conn) /* Check if ISO connection is a BIS and terminate advertising * set and BIG if there are no other connections using it. */ - bis = hci_conn_hash_lookup_big(hdev, conn->iso_qos.bcast.big); + bis = hci_conn_hash_lookup_big_state(hdev, + conn->iso_qos.bcast.big, + BT_CONNECTED, + HCI_ROLE_MASTER); + if (bis) + return; + + bis = hci_conn_hash_lookup_big_state(hdev, + conn->iso_qos.bcast.big, + BT_CONNECT, + HCI_ROLE_MASTER); if (bis) return; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8aa5039b975a28..4f0a6116291ef6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6957,9 +6957,14 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, continue; } - if (ev->status != 0x42) + if (ev->status != 0x42) { /* Mark PA sync as established */ set_bit(HCI_CONN_PA_SYNC, &bis->flags); + /* Reset cleanup callback of PA Sync so it doesn't + * terminate the sync when deleting the connection. + */ + conn->cleanup = NULL; + } bis->sync_handle = conn->sync_handle; bis->iso_qos.bcast.big = ev->handle; From 3ba486c5f3ce2c22ffd29c0103404cdbe21912b3 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 29 Jul 2025 12:11:09 -0400 Subject: [PATCH 0190/1292] Bluetooth: hci_conn: Fix not cleaning up Broadcaster/Broadcast Source This fixes Broadcaster/Broadcast Source not sending HCI_OP_LE_TERM_BIG because HCI_CONN_PER_ADV where not being set. Fixes: a7bcffc673de ("Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f8b20b609a0394..ab6fe5b0cc0fe1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2259,7 +2259,7 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, * the start periodic advertising and create BIG commands have * been queued */ - hci_conn_hash_list_state(hdev, bis_mark_per_adv, PA_LINK, + hci_conn_hash_list_state(hdev, bis_mark_per_adv, BIS_LINK, BT_BOUND, &data); /* Queue start periodic advertising and create BIG */ From 099799fa9b76c5c02b49e07005a85117a25b01ea Mon Sep 17 00:00:00 2001 From: Jiande Lu Date: Thu, 24 Jul 2025 16:51:17 +0800 Subject: [PATCH 0191/1292] Bluetooth: btmtk: Fix wait_on_bit_timeout interruption during shutdown During the shutdown process, an interrupt occurs that prematurely terminates the wait for the expected event. This change replaces TASK_INTERRUPTIBLE with TASK_UNINTERRUPTIBLE in the wait_on_bit_timeout call to ensure the shutdown process completes as intended without being interrupted by signals. Fixes: d019930b0049 ("Bluetooth: btmtk: move btusb_mtk_hci_wmt_sync to btmtk.c") Signed-off-by: Jiande Lu Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtk.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 4390fd571dbd15..a8c520dc09e19c 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -642,12 +642,7 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev, * WMT command. */ err = wait_on_bit_timeout(&data->flags, BTMTK_TX_WAIT_VND_EVT, - TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT); - if (err == -EINTR) { - bt_dev_err(hdev, "Execution of wmt command interrupted"); - clear_bit(BTMTK_TX_WAIT_VND_EVT, &data->flags); - goto err_free_wc; - } + TASK_UNINTERRUPTIBLE, HCI_INIT_TIMEOUT); if (err) { bt_dev_err(hdev, "Execution of wmt command timed out"); From 709788b154caf042874d765628ffa860f0bb0d1e Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 4 Aug 2025 09:54:05 -0400 Subject: [PATCH 0192/1292] Bluetooth: hci_core: Fix using {cis,bis}_capable for current settings {cis,bis}_capable only indicates the controller supports the feature since it doesn't check that LE is enabled so it shall not be used for current setting, instead this introduces {cis,bis}_enabled macros that can be used to indicate that these features are currently enabled. Fixes: 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections") Fixes: eca0ae4aea66 ("Bluetooth: Add initial implementation of BIS connections") Fixes: ae7533613133 ("Bluetooth: Check for ISO support in controller") Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 4 ++-- include/net/bluetooth/hci_core.h | 13 ++++++++++++- net/bluetooth/hci_sync.c | 4 ++-- net/bluetooth/iso.c | 14 +++++++------- net/bluetooth/mgmt.c | 10 +++++----- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index ada5b56a441350..e5751f3070b8e3 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -647,7 +647,7 @@ static inline void sco_exit(void) #if IS_ENABLED(CONFIG_BT_LE) int iso_init(void); int iso_exit(void); -bool iso_enabled(void); +bool iso_inited(void); #else static inline int iso_init(void) { @@ -659,7 +659,7 @@ static inline int iso_exit(void) return 0; } -static inline bool iso_enabled(void) +static inline bool iso_inited(void) { return false; } diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4dc11c66f7b819..bc29f2e2e16f0c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1915,6 +1915,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn); !hci_dev_test_flag(dev, HCI_RPA_EXPIRED)) #define adv_rpa_valid(adv) (bacmp(&adv->random_addr, BDADDR_ANY) && \ !adv->rpa_expired) +#define le_enabled(dev) (lmp_le_capable(dev) && \ + hci_dev_test_flag(dev, HCI_LE_ENABLED)) #define scan_1m(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_1M) || \ ((dev)->le_rx_def_phys & HCI_LE_SET_PHY_1M)) @@ -1981,14 +1983,23 @@ void hci_conn_del_sysfs(struct hci_conn *conn); /* CIS Master/Slave and BIS support */ #define iso_capable(dev) (cis_capable(dev) || bis_capable(dev)) +#define iso_enabled(dev) (le_enabled(dev) && iso_capable(dev)) #define cis_capable(dev) \ (cis_central_capable(dev) || cis_peripheral_capable(dev)) +#define cis_enabled(dev) (le_enabled(dev) && cis_capable(dev)) #define cis_central_capable(dev) \ ((dev)->le_features[3] & HCI_LE_CIS_CENTRAL) +#define cis_central_enabled(dev) \ + (le_enabled(dev) && cis_central_capable(dev)) #define cis_peripheral_capable(dev) \ ((dev)->le_features[3] & HCI_LE_CIS_PERIPHERAL) +#define cis_peripheral_enabled(dev) \ + (le_enabled(dev) && cis_peripheral_capable(dev)) #define bis_capable(dev) ((dev)->le_features[3] & HCI_LE_ISO_BROADCASTER) -#define sync_recv_capable(dev) ((dev)->le_features[3] & HCI_LE_ISO_SYNC_RECEIVER) +#define bis_enabled(dev) (le_enabled(dev) && bis_capable(dev)) +#define sync_recv_capable(dev) \ + ((dev)->le_features[3] & HCI_LE_ISO_SYNC_RECEIVER) +#define sync_recv_enabled(dev) (le_enabled(dev) && sync_recv_capable(dev)) #define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \ (!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG))) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 387c128f2ba0a6..aa7d7a8ec3ee64 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -4531,14 +4531,14 @@ static int hci_le_set_host_feature_sync(struct hci_dev *hdev) { struct hci_cp_le_set_host_feature cp; - if (!cis_capable(hdev)) + if (!iso_capable(hdev)) return 0; memset(&cp, 0, sizeof(cp)); /* Connected Isochronous Channels (Host Support) */ cp.bit_number = 32; - cp.bit_value = 1; + cp.bit_value = iso_enabled(hdev) ? 0x01 : 0x00; return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_HOST_FEATURE, sizeof(cp), &cp, HCI_CMD_TIMEOUT); diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index eaffd25570e3b0..5ce823ca3aaf44 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -2483,11 +2483,11 @@ static const struct net_proto_family iso_sock_family_ops = { .create = iso_sock_create, }; -static bool iso_inited; +static bool inited; -bool iso_enabled(void) +bool iso_inited(void) { - return iso_inited; + return inited; } int iso_init(void) @@ -2496,7 +2496,7 @@ int iso_init(void) BUILD_BUG_ON(sizeof(struct sockaddr_iso) > sizeof(struct sockaddr)); - if (iso_inited) + if (inited) return -EALREADY; err = proto_register(&iso_proto, 0); @@ -2524,7 +2524,7 @@ int iso_init(void) iso_debugfs = debugfs_create_file("iso", 0444, bt_debugfs, NULL, &iso_debugfs_fops); - iso_inited = true; + inited = true; return 0; @@ -2535,7 +2535,7 @@ int iso_init(void) int iso_exit(void) { - if (!iso_inited) + if (!inited) return -EALREADY; bt_procfs_cleanup(&init_net, "iso"); @@ -2549,7 +2549,7 @@ int iso_exit(void) proto_unregister(&iso_proto); - iso_inited = false; + inited = false; return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1ce682038b5193..c42dffe77daf44 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -922,16 +922,16 @@ static u32 get_current_settings(struct hci_dev *hdev) if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED)) settings |= MGMT_SETTING_WIDEBAND_SPEECH; - if (cis_central_capable(hdev)) + if (cis_central_enabled(hdev)) settings |= MGMT_SETTING_CIS_CENTRAL; - if (cis_peripheral_capable(hdev)) + if (cis_peripheral_enabled(hdev)) settings |= MGMT_SETTING_CIS_PERIPHERAL; - if (bis_capable(hdev)) + if (bis_enabled(hdev)) settings |= MGMT_SETTING_ISO_BROADCASTER; - if (sync_recv_capable(hdev)) + if (sync_recv_enabled(hdev)) settings |= MGMT_SETTING_ISO_SYNC_RECEIVER; if (ll_privacy_capable(hdev)) @@ -4513,7 +4513,7 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, } if (IS_ENABLED(CONFIG_BT_LE)) { - flags = iso_enabled() ? BIT(0) : 0; + flags = iso_inited() ? BIT(0) : 0; memcpy(rp->features[idx].uuid, iso_socket_uuid, 16); rp->features[idx].flags = cpu_to_le32(flags); idx++; From 3dcf7175f2c04bd3a7d50db3fa42a0bd933b6e23 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 4 Aug 2025 14:05:03 -0400 Subject: [PATCH 0193/1292] Bluetooth: hci_core: Fix using ll_privacy_capable for current settings ll_privacy_capable only indicates that the controller supports the feature but it doesnt' check that LE is enabled so it end up being marked as active in the current settings when it shouldn't. Fixes: ad383c2c65a5 ("Bluetooth: hci_sync: Enable advertising when LL privacy is enabled") Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/mgmt.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bc29f2e2e16f0c..bb30bde6f0e878 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1934,6 +1934,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); ((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED)) #define ll_privacy_capable(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY) +#define ll_privacy_enabled(dev) (le_enabled(dev) && ll_privacy_capable(dev)) #define privacy_mode_capable(dev) (ll_privacy_capable(dev) && \ ((dev)->commands[39] & 0x04)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c42dffe77daf44..3166f5fb876b11 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -934,7 +934,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (sync_recv_enabled(hdev)) settings |= MGMT_SETTING_ISO_SYNC_RECEIVER; - if (ll_privacy_capable(hdev)) + if (ll_privacy_enabled(hdev)) settings |= MGMT_SETTING_LL_PRIVACY; return settings; From 4d19cd228bbe8ff84a63fe7b11bc756b4b4370c7 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 7 Aug 2025 15:56:03 +0800 Subject: [PATCH 0194/1292] Bluetooth: hci_sync: Prevent unintended PA sync when SID is 0xFF After LE Extended Scan times out, conn->sid remains 0xFF, so the PA sync creation process should be aborted. Btmon snippet from PA sync with SID=0xFF: < HCI Command: LE Set Extended.. (0x08|0x0042) plen 6 #74726 [hci0] 863.107927 Extended scan: Enabled (0x01) Filter duplicates: Enabled (0x01) Duration: 0 msec (0x0000) Period: 0.00 sec (0x0000) > HCI Event: Command Complete (0x0e) plen 4 #74727 [hci0] 863.109389 LE Set Extended Scan Enable (0x08|0x0042) ncmd 1 Status: Success (0x00) < HCI Command: LE Periodic Ad.. (0x08|0x0044) plen 14 #74728 [hci0] 865.141168 Options: 0x0000 Use advertising SID, Advertiser Address Type and address Reporting initially enabled SID: 0xff Adv address type: Random (0x01) Adv address: 0D:D7:2C:E7:42:46 (Non-Resolvable) Skip: 0x0000 Sync timeout: 20000 msec (0x07d0) Sync CTE type: 0x0000 > HCI Event: Command Status (0x0f) plen 4 #74729 [hci0] 865.143223 LE Periodic Advertising Create Sync (0x08|0x0044) ncmd 1 Status: Success (0x00) Fixes: e2d471b7806b ("Bluetooth: ISO: Fix not using SID from adv report") Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_sync.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index aa7d7a8ec3ee64..31d72b9683ef52 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -7045,10 +7045,13 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data) /* SID has not been set listen for HCI_EV_LE_EXT_ADV_REPORT to update * it. */ - if (conn->sid == HCI_SID_INVALID) - __hci_cmd_sync_status_sk(hdev, HCI_OP_NOP, 0, NULL, - HCI_EV_LE_EXT_ADV_REPORT, - conn->conn_timeout, NULL); + if (conn->sid == HCI_SID_INVALID) { + err = __hci_cmd_sync_status_sk(hdev, HCI_OP_NOP, 0, NULL, + HCI_EV_LE_EXT_ADV_REPORT, + conn->conn_timeout, NULL); + if (err == -ETIMEDOUT) + goto done; + } memset(&cp, 0, sizeof(cp)); cp.options = qos->bcast.options; @@ -7078,6 +7081,7 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data) __hci_cmd_sync_status(hdev, HCI_OP_LE_PA_CREATE_SYNC_CANCEL, 0, NULL, HCI_CMD_TIMEOUT); +done: hci_dev_clear_flag(hdev, HCI_PA_SYNC); /* Update passive scan since HCI_PA_SYNC flag has been cleared */ From 0b3725dbf61b51e7c663834811b3691157ae17d6 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 9 Aug 2025 11:36:20 +0300 Subject: [PATCH 0195/1292] Bluetooth: hci_event: fix MTU for BN == 0 in CIS Established BN == 0x00 in CIS Established means no isochronous data for the corresponding direction (Core v6.1 pp. 2394). In this case SDU MTU should be 0. However, the specification does not say the Max_PDU_C_To_P or P_To_C are then zero. Intel AX210 in Framed CIS mode sets nonzero Max_PDU for direction with zero BN. This causes failure later when we try to LE Setup ISO Data Path for disabled direction, which is disallowed (Core v6.1 pp. 2750). Fix by setting SDU MTU to 0 if BN == 0. Fixes: 2be22f1941d5f ("Bluetooth: hci_event: Fix parsing of CIS Established Event") Signed-off-by: Pauli Virtanen Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4f0a6116291ef6..fe7cdd67ad2a20 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6745,8 +6745,8 @@ static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, qos->ucast.out.latency = DIV_ROUND_CLOSEST(get_unaligned_le24(ev->p_latency), 1000); - qos->ucast.in.sdu = le16_to_cpu(ev->c_mtu); - qos->ucast.out.sdu = le16_to_cpu(ev->p_mtu); + qos->ucast.in.sdu = ev->c_bn ? le16_to_cpu(ev->c_mtu) : 0; + qos->ucast.out.sdu = ev->p_bn ? le16_to_cpu(ev->p_mtu) : 0; qos->ucast.in.phy = ev->c_phy; qos->ucast.out.phy = ev->p_phy; break; @@ -6760,8 +6760,8 @@ static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, qos->ucast.in.latency = DIV_ROUND_CLOSEST(get_unaligned_le24(ev->p_latency), 1000); - qos->ucast.out.sdu = le16_to_cpu(ev->c_mtu); - qos->ucast.in.sdu = le16_to_cpu(ev->p_mtu); + qos->ucast.out.sdu = ev->c_bn ? le16_to_cpu(ev->c_mtu) : 0; + qos->ucast.in.sdu = ev->p_bn ? le16_to_cpu(ev->p_mtu) : 0; qos->ucast.out.phy = ev->c_phy; qos->ucast.in.phy = ev->p_phy; break; From b5ca88927e353185b3d9ac4362d33e5aeb25771f Mon Sep 17 00:00:00 2001 From: Thomas Bertschinger Date: Thu, 14 Aug 2025 17:54:28 -0600 Subject: [PATCH 0196/1292] fhandle: do_handle_open() should get FD with user flags In f07c7cc4684a, do_handle_open() was switched to use the automatic cleanup method for getting a FD. In that change it was also switched to pass O_CLOEXEC unconditionally to get_unused_fd_flags() instead of passing the user-specified flags. I don't see anything in that commit description that indicates this was intentional, so I am assuming it was an oversight. With this fix, the FD will again be opened with, or without, O_CLOEXEC according to what the user requested. Fixes: f07c7cc4684a ("fhandle: simplify error handling") Signed-off-by: Thomas Bertschinger Link: https://lore.kernel.org/20250814235431.995876-4-tahbertschinger@gmail.com Reviewed-by: Amir Goldstein Signed-off-by: Christian Brauner --- fs/fhandle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fhandle.c b/fs/fhandle.c index 7c236f64cdeac1..68a7d2861c58fe 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c @@ -402,7 +402,7 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh, if (retval) return retval; - CLASS(get_unused_fd, fd)(O_CLOEXEC); + CLASS(get_unused_fd, fd)(open_flag); if (fd < 0) return fd; From a3de58b12ce074ec05b8741fa28d62ccb1070468 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 14 Aug 2025 22:45:50 +0100 Subject: [PATCH 0197/1292] netfs: Fix unbuffered write error handling If all the subrequests in an unbuffered write stream fail, the subrequest collector doesn't update the stream->transferred value and it retains its initial LONG_MAX value. Unfortunately, if all active streams fail, then we take the smallest value of { LONG_MAX, LONG_MAX, ... } as the value to set in wreq->transferred - which is then returned from ->write_iter(). LONG_MAX was chosen as the initial value so that all the streams can be quickly assessed by taking the smallest value of all stream->transferred - but this only works if we've set any of them. Fix this by adding a flag to indicate whether the value in stream->transferred is valid and checking that when we integrate the values. stream->transferred can then be initialised to zero. This was found by running the generic/750 xfstest against cifs with cache=none. It splices data to the target file. Once (if) it has used up all the available scratch space, the writes start failing with ENOSPC. This causes ->write_iter() to fail. However, it was returning wreq->transferred, i.e. LONG_MAX, rather than an error (because it thought the amount transferred was non-zero) and iter_file_splice_write() would then try to clean up that amount of pipe bufferage - leading to an oops when it overran. The kernel log showed: CIFS: VFS: Send error in write = -28 followed by: BUG: kernel NULL pointer dereference, address: 0000000000000008 with: RIP: 0010:iter_file_splice_write+0x3a4/0x520 do_splice+0x197/0x4e0 or: RIP: 0010:pipe_buf_release (include/linux/pipe_fs_i.h:282) iter_file_splice_write (fs/splice.c:755) Also put a warning check into splice to announce if ->write_iter() returned that it had written more than it was asked to. Fixes: 288ace2f57c9 ("netfs: New writeback implementation") Reported-by: Xiaoli Feng Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220445 Signed-off-by: David Howells Link: https://lore.kernel.org/915443.1755207950@warthog.procyon.org.uk cc: Paulo Alcantara cc: Steve French cc: Shyam Prasad N cc: netfs@lists.linux.dev cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: stable@vger.kernel.org Signed-off-by: Christian Brauner --- fs/netfs/read_collect.c | 4 +++- fs/netfs/write_collect.c | 10 ++++++++-- fs/netfs/write_issue.c | 4 ++-- fs/splice.c | 3 +++ include/linux/netfs.h | 1 + 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c index 3e804da1e1eb10..a95e7aadafd072 100644 --- a/fs/netfs/read_collect.c +++ b/fs/netfs/read_collect.c @@ -281,8 +281,10 @@ static void netfs_collect_read_results(struct netfs_io_request *rreq) } else if (test_bit(NETFS_RREQ_SHORT_TRANSFER, &rreq->flags)) { notes |= MADE_PROGRESS; } else { - if (!stream->failed) + if (!stream->failed) { stream->transferred += transferred; + stream->transferred_valid = true; + } if (front->transferred < front->len) set_bit(NETFS_RREQ_SHORT_TRANSFER, &rreq->flags); notes |= MADE_PROGRESS; diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c index 0f3a36852a4dc1..cbf3d9194c7bf6 100644 --- a/fs/netfs/write_collect.c +++ b/fs/netfs/write_collect.c @@ -254,6 +254,7 @@ static void netfs_collect_write_results(struct netfs_io_request *wreq) if (front->start + front->transferred > stream->collected_to) { stream->collected_to = front->start + front->transferred; stream->transferred = stream->collected_to - wreq->start; + stream->transferred_valid = true; notes |= MADE_PROGRESS; } if (test_bit(NETFS_SREQ_FAILED, &front->flags)) { @@ -356,6 +357,7 @@ bool netfs_write_collection(struct netfs_io_request *wreq) { struct netfs_inode *ictx = netfs_inode(wreq->inode); size_t transferred; + bool transferred_valid = false; int s; _enter("R=%x", wreq->debug_id); @@ -376,12 +378,16 @@ bool netfs_write_collection(struct netfs_io_request *wreq) continue; if (!list_empty(&stream->subrequests)) return false; - if (stream->transferred < transferred) + if (stream->transferred_valid && + stream->transferred < transferred) { transferred = stream->transferred; + transferred_valid = true; + } } /* Okay, declare that all I/O is complete. */ - wreq->transferred = transferred; + if (transferred_valid) + wreq->transferred = transferred; trace_netfs_rreq(wreq, netfs_rreq_trace_write_done); if (wreq->io_streams[1].active && diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c index 50bee2c4130d1e..0584cba1a04392 100644 --- a/fs/netfs/write_issue.c +++ b/fs/netfs/write_issue.c @@ -118,12 +118,12 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping, wreq->io_streams[0].prepare_write = ictx->ops->prepare_write; wreq->io_streams[0].issue_write = ictx->ops->issue_write; wreq->io_streams[0].collected_to = start; - wreq->io_streams[0].transferred = LONG_MAX; + wreq->io_streams[0].transferred = 0; wreq->io_streams[1].stream_nr = 1; wreq->io_streams[1].source = NETFS_WRITE_TO_CACHE; wreq->io_streams[1].collected_to = start; - wreq->io_streams[1].transferred = LONG_MAX; + wreq->io_streams[1].transferred = 0; if (fscache_resources_valid(&wreq->cache_resources)) { wreq->io_streams[1].avail = true; wreq->io_streams[1].active = true; diff --git a/fs/splice.c b/fs/splice.c index 4d6df083e0c06a..f5094b6d00a09f 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -739,6 +739,9 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, sd.pos = kiocb.ki_pos; if (ret <= 0) break; + WARN_ONCE(ret > sd.total_len - left, + "Splice Exceeded! ret=%zd tot=%zu left=%zu\n", + ret, sd.total_len, left); sd.num_spliced += ret; sd.total_len -= ret; diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 185bd8196503d3..98c96d649bf90e 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -150,6 +150,7 @@ struct netfs_io_stream { bool active; /* T if stream is active */ bool need_retry; /* T if this stream needs retrying */ bool failed; /* T if this stream failed */ + bool transferred_valid; /* T is ->transferred is valid */ }; /* From 0b2d71a7c82628bb36fd43e80193bcc2693c239a Mon Sep 17 00:00:00 2001 From: "Adrian Huang (Lenovo)" Date: Thu, 14 Aug 2025 17:44:53 +0800 Subject: [PATCH 0198/1292] pidfs: Fix memory leak in pidfd_info() After running the program 'ioctl_pidfd03' of Linux Test Project (LTP) or the program 'pidfd_info_test' in 'tools/testing/selftests/pidfd' of the kernel source, kmemleak reports the following memory leaks: # cat /sys/kernel/debug/kmemleak unreferenced object 0xff110020e5988000 (size 8216): comm "ioctl_pidfd03", pid 10853, jiffies 4294800031 hex dump (first 32 bytes): 02 40 00 00 00 00 00 00 10 00 00 00 00 00 00 00 .@.............. 00 00 00 00 af 01 00 00 80 00 00 00 00 00 00 00 ................ backtrace (crc 69483047): kmem_cache_alloc_node_noprof+0x2fb/0x410 copy_process+0x178/0x1740 kernel_clone+0x99/0x3b0 __do_sys_clone3+0xbe/0x100 do_syscall_64+0x7b/0x2c0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ... unreferenced object 0xff11002097b70000 (size 8216): comm "pidfd_info_test", pid 11840, jiffies 4294889165 hex dump (first 32 bytes): 06 40 00 00 00 00 00 00 10 00 00 00 00 00 00 00 .@.............. 00 00 00 00 b5 00 00 00 80 00 00 00 00 00 00 00 ................ backtrace (crc a6286bb7): kmem_cache_alloc_node_noprof+0x2fb/0x410 copy_process+0x178/0x1740 kernel_clone+0x99/0x3b0 __do_sys_clone3+0xbe/0x100 do_syscall_64+0x7b/0x2c0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ... The leak occurs because pidfd_info() obtains a task_struct via get_pid_task() but never calls put_task_struct() to drop the reference, leaving task->usage unbalanced. Fix the issue by adding '__free(put_task) = NULL' to the local variable 'task', ensuring that put_task_struct() is automatically invoked when the variable goes out of scope. Fixes: 7477d7dce48a ("pidfs: allow to retrieve exit information") Signed-off-by: Adrian Huang (Lenovo) Link: https://lore.kernel.org/20250814094453.15232-1-adrianhuang0701@gmail.com Signed-off-by: Christian Brauner --- fs/pidfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pidfs.c b/fs/pidfs.c index edc35522d75c49..108e7527f837fd 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -296,12 +296,12 @@ static __u32 pidfs_coredump_mask(unsigned long mm_flags) static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg) { struct pidfd_info __user *uinfo = (struct pidfd_info __user *)arg; + struct task_struct *task __free(put_task) = NULL; struct pid *pid = pidfd_pid(file); size_t usize = _IOC_SIZE(cmd); struct pidfd_info kinfo = {}; struct pidfs_exit_info *exit_info; struct user_namespace *user_ns; - struct task_struct *task; struct pidfs_attr *attr; const struct cred *c; __u64 mask; From 0eaf7c7e85da7495c0e03a99375707fc954f5e7b Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Tue, 5 Aug 2025 22:14:51 +0300 Subject: [PATCH 0199/1292] Bluetooth: hci_conn: do return error from hci_enhanced_setup_sync() The commit e07a06b4eb41 ("Bluetooth: Convert SCO configure_datapath to hci_sync") missed to update the *return* statement under the *case* of BT_CODEC_TRANSPARENT in hci_enhanced_setup_sync(), which led to returning success (0) instead of the negative error code (-EINVAL). However, the result of hci_enhanced_setup_sync() seems to be ignored anyway, since NULL gets passed to hci_cmd_sync_queue() as the last argument in that case and the only function interested in that result is specified by that argument. Fixes: e07a06b4eb41 ("Bluetooth: Convert SCO configure_datapath to hci_sync") Signed-off-by: Sergey Shtylyov Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ab6fe5b0cc0fe1..7a879290dd28d5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -339,7 +339,8 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) case BT_CODEC_TRANSPARENT: if (!find_next_esco_param(conn, esco_param_msbc, ARRAY_SIZE(esco_param_msbc))) - return false; + return -EINVAL; + param = &esco_param_msbc[conn->attempt - 1]; cp.tx_coding_format.id = 0x03; cp.rx_coding_format.id = 0x03; From e489317d2fd9a51a81bdcbe15a73ddde8246e6d6 Mon Sep 17 00:00:00 2001 From: Neeraj Sanjay Kale Date: Mon, 4 Aug 2025 16:00:15 +0530 Subject: [PATCH 0200/1292] Bluetooth: btnxpuart: Uses threaded IRQ for host wakeup handling This replaces devm_request_irq() with devm_request_threaded_irq(). On iMX93 11x11 EVK platform, the BT chip's BT_WAKE_OUT pin is connected to an I2C GPIO expander instead of directly been connected to iMX GPIO. When I2C GPIO expander's (PCAL6524) host driver receives an interrupt on it's INTR line, the driver's interrupt handler needs to query the interrupt source with PCAL6524 first, and then call the actual interrupt handler, in this case the IRQ handler in BTNXPUART. In order to handle interrupts when such I2C GPIO expanders are between the host and interrupt source, devm_request_threaded_irq() is needed. This commit also removes the IRQF_TRIGGER_FALLING flag, to allow setting the IRQ trigger type from the device tree setting instead of hardcoding in the driver. Signed-off-by: Neeraj Sanjay Kale Reviewed-by: Sherry Sun Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btnxpuart.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 73a4a325c8671b..76e7f857fb7d9a 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -543,10 +543,10 @@ static int ps_setup(struct hci_dev *hdev) } if (psdata->wakeup_source) { - ret = devm_request_irq(&serdev->dev, psdata->irq_handler, - ps_host_wakeup_irq_handler, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - dev_name(&serdev->dev), nxpdev); + ret = devm_request_threaded_irq(&serdev->dev, psdata->irq_handler, + NULL, ps_host_wakeup_irq_handler, + IRQF_ONESHOT, + dev_name(&serdev->dev), nxpdev); if (ret) bt_dev_info(hdev, "error setting wakeup IRQ handler, ignoring\n"); disable_irq(psdata->irq_handler); From 9d4b01a0bf8d2163ae129c9c537cb0753ad5a2aa Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 14 Aug 2025 11:57:19 -0400 Subject: [PATCH 0201/1292] Bluetooth: hci_core: Fix not accounting for BIS/CIS/PA links separately This fixes the likes of hci_conn_num(CIS_LINK) returning the total of ISO connection which includes BIS_LINK as well, so this splits the iso_num into each link type and introduces hci_iso_num that can be used in places where the total number of ISO connection still needs to be used. Fixes: 23205562ffc8 ("Bluetooth: separate CIS_LINK and BIS_LINK link types") Fixes: a7bcffc673de ("Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections") Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bb30bde6f0e878..6906af7a8f2412 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -129,7 +129,9 @@ struct hci_conn_hash { struct list_head list; unsigned int acl_num; unsigned int sco_num; - unsigned int iso_num; + unsigned int cis_num; + unsigned int bis_num; + unsigned int pa_num; unsigned int le_num; unsigned int le_num_peripheral; }; @@ -1014,9 +1016,13 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) h->sco_num++; break; case CIS_LINK: + h->cis_num++; + break; case BIS_LINK: + h->bis_num++; + break; case PA_LINK: - h->iso_num++; + h->pa_num++; break; } } @@ -1042,9 +1048,13 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) h->sco_num--; break; case CIS_LINK: + h->cis_num--; + break; case BIS_LINK: + h->bis_num--; + break; case PA_LINK: - h->iso_num--; + h->pa_num--; break; } } @@ -1061,9 +1071,11 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) case ESCO_LINK: return h->sco_num; case CIS_LINK: + return h->cis_num; case BIS_LINK: + return h->bis_num; case PA_LINK: - return h->iso_num; + return h->pa_num; default: return 0; } @@ -1073,7 +1085,15 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev) { struct hci_conn_hash *c = &hdev->conn_hash; - return c->acl_num + c->sco_num + c->le_num + c->iso_num; + return c->acl_num + c->sco_num + c->le_num + c->cis_num + c->bis_num + + c->pa_num; +} + +static inline unsigned int hci_iso_count(struct hci_dev *hdev) +{ + struct hci_conn_hash *c = &hdev->conn_hash; + + return c->cis_num + c->bis_num; } static inline bool hci_conn_valid(struct hci_dev *hdev, struct hci_conn *conn) From eafae0fdd115a71b3a200ef1a31f86da04bac77f Mon Sep 17 00:00:00 2001 From: Evgeniy Harchenko Date: Fri, 15 Aug 2025 12:58:14 +0300 Subject: [PATCH 0202/1292] ALSA: hda/realtek: Add support for HP EliteBook x360 830 G6 and EliteBook 830 G6 The HP EliteBook x360 830 G6 and HP EliteBook 830 G6 have Realtek HDA codec ALC215. It needs the ALC285_FIXUP_HP_GPIO_LED quirk to enable the mute LED. Cc: Signed-off-by: Evgeniy Harchenko Link: https://patch.msgid.link/20250815095814.75845-1-evgeniyharchenko.dev@gmail.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index e90c4047ea62e4..db8e6352b94253 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -6368,6 +6368,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360), SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8548, "HP EliteBook x360 830 G6", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x854a, "HP EliteBook 830 G6", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11), SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360), SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT), From f604d3aaf64ff0d90cc875295474d3abf4155629 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 14 Aug 2025 15:06:40 +0200 Subject: [PATCH 0203/1292] mlxsw: spectrum: Forward packets with an IPv4 link-local source IP By default, the device does not forward IPv4 packets with a link-local source IP (i.e., 169.254.0.0/16). This behavior does not align with the kernel which does forward them. Fix by instructing the device to forward such packets instead of dropping them. Fixes: ca360db4b825 ("mlxsw: spectrum: Disable DIP_LINK_LOCAL check in hardware pipeline") Reported-by: Zoey Mertes Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Petr Machata Link: https://patch.msgid.link/6721e6b2c96feb80269e72ce8d0b426e2f32d99c.1755174341.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 ++ drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 618957d6566364..9a2d64a0a8588a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2375,6 +2375,8 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { ROUTER_EXP, false), MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_DIP_LINK_LOCAL, FORWARD, ROUTER_EXP, false), + MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_LINK_LOCAL, FORWARD, + ROUTER_EXP, false), /* Multicast Router Traps */ MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index 80ee5c4825dc96..9962dc1579019b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -94,6 +94,7 @@ enum { MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_SIP_BC = 0x16A, MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_DIP_LOCAL_NET = 0x16B, MLXSW_TRAP_ID_DISCARD_ING_ROUTER_DIP_LINK_LOCAL = 0x16C, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_SIP_LINK_LOCAL = 0x16D, MLXSW_TRAP_ID_DISCARD_ROUTER_IRIF_EN = 0x178, MLXSW_TRAP_ID_DISCARD_ROUTER_ERIF_EN = 0x179, MLXSW_TRAP_ID_DISCARD_ROUTER_LPM4 = 0x17B, From 5e0b2177bdba99c2487480e9864825f742b684ee Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 14 Aug 2025 15:06:41 +0200 Subject: [PATCH 0204/1292] selftest: forwarding: router: Add a test case for IPv4 link-local source IP Add a test case which checks that packets with an IPv4 link-local source IP are forwarded and not dropped. Signed-off-by: Ido Schimmel Signed-off-by: Petr Machata Link: https://patch.msgid.link/3c2e0b17d99530f57bef5ddff9af284fa0c9b667.1755174341.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../selftests/net/forwarding/router.sh | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/router.sh b/tools/testing/selftests/net/forwarding/router.sh index b98ea9449b8b26..dfb6646cb97bf4 100755 --- a/tools/testing/selftests/net/forwarding/router.sh +++ b/tools/testing/selftests/net/forwarding/router.sh @@ -18,6 +18,8 @@ # | 2001:db8:1::1/64 2001:db8:2::1/64 | # | | # +-----------------------------------------------------------------+ +# +#shellcheck disable=SC2034 # SC doesn't see our uses of global variables ALL_TESTS=" ping_ipv4 @@ -27,6 +29,7 @@ ALL_TESTS=" ipv4_sip_equal_dip ipv6_sip_equal_dip ipv4_dip_link_local + ipv4_sip_link_local " NUM_NETIFS=4 @@ -330,6 +333,32 @@ ipv4_dip_link_local() tc filter del dev $rp2 egress protocol ip pref 1 handle 101 flower } +ipv4_sip_link_local() +{ + local sip=169.254.1.1 + + RET=0 + + # Disable rpfilter to prevent packets to be dropped because of it. + sysctl_set net.ipv4.conf.all.rp_filter 0 + sysctl_set net.ipv4.conf."$rp1".rp_filter 0 + + tc filter add dev "$rp2" egress protocol ip pref 1 handle 101 \ + flower src_ip "$sip" action pass + + $MZ "$h1" -t udp "sp=54321,dp=12345" -c 5 -d 1msec -b "$rp1mac" \ + -A "$sip" -B 198.51.100.2 -q + + tc_check_packets "dev $rp2 egress" 101 5 + check_err $? "Packets were dropped" + + log_test "IPv4 source IP is link-local" + + tc filter del dev "$rp2" egress protocol ip pref 1 handle 101 flower + sysctl_restore net.ipv4.conf."$rp1".rp_filter + sysctl_restore net.ipv4.conf.all.rp_filter +} + trap cleanup EXIT setup_prepare From c87bd4dd43a624109c3cc42d843138378a7f4548 Mon Sep 17 00:00:00 2001 From: Thijs Raymakers Date: Mon, 4 Aug 2025 08:44:05 +0200 Subject: [PATCH 0205/1292] KVM: x86: use array_index_nospec with indices that come from guest min and dest_id are guest-controlled indices. Using array_index_nospec() after the bounds checks clamps these values to mitigate speculative execution side-channels. Signed-off-by: Thijs Raymakers Cc: stable@vger.kernel.org Cc: Sean Christopherson Cc: Paolo Bonzini Cc: Greg Kroah-Hartman Fixes: 715062970f37 ("KVM: X86: Implement PV sched yield hypercall") Fixes: bdf7ffc89922 ("KVM: LAPIC: Fix pv ipis out-of-bounds access") Fixes: 4180bf1b655a ("KVM: X86: Implement "send IPI" hypercall") Link: https://lore.kernel.org/r/20250804064405.4802-1-thijs@raymakers.nl Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 2 ++ arch/x86/kvm/x86.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 8172c2042dd687..5fc437341e03a9 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -810,6 +810,8 @@ static int __pv_send_ipi(unsigned long *ipi_bitmap, struct kvm_apic_map *map, if (min > map->max_apic_id) return 0; + min = array_index_nospec(min, map->max_apic_id + 1); + for_each_set_bit(i, ipi_bitmap, min((u32)BITS_PER_LONG, (map->max_apic_id - min + 1))) { if (map->phys_map[min + i]) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a1c49bc681c469..604490b1cb19c7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9908,8 +9908,11 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id) rcu_read_lock(); map = rcu_dereference(vcpu->kvm->arch.apic_map); - if (likely(map) && dest_id <= map->max_apic_id && map->phys_map[dest_id]) - target = map->phys_map[dest_id]->vcpu; + if (likely(map) && dest_id <= map->max_apic_id) { + dest_id = array_index_nospec(dest_id, map->max_apic_id + 1); + if (map->phys_map[dest_id]) + target = map->phys_map[dest_id]->vcpu; + } rcu_read_unlock(); From 989fe6771266bdb82a815d78802c5aa7c918fdfd Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 13 Aug 2025 20:54:04 +0800 Subject: [PATCH 0206/1292] drm/nouveau/gsp: fix mismatched alloc/free for kvmalloc() Replace kfree() with kvfree() for memory allocated by kvmalloc(). Compile-tested only. Cc: stable@vger.kernel.org Fixes: 8a8b1ec5261f ("drm/nouveau/gsp: split rpc handling out on its own") Signed-off-by: Qianfeng Rong Reviewed-by: Timur Tabi Acked-by: Zhi Wang Link: https://lore.kernel.org/r/20250813125412.96178-1-rongqianfeng@vivo.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c index 9d06ff722fea7c..0dc4782df8c0c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c @@ -325,7 +325,7 @@ r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries) rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), info.retries); if (IS_ERR_OR_NULL(rpc)) { - kfree(buf); + kvfree(buf); return rpc; } @@ -334,7 +334,7 @@ r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries) rpc = r535_gsp_msgq_recv_one_elem(gsp, &info); if (IS_ERR_OR_NULL(rpc)) { - kfree(buf); + kvfree(buf); return rpc; } From 6cc44e9618f03f1deb9a092698c0b0ce20990221 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Sun, 10 Aug 2025 17:07:06 +0200 Subject: [PATCH 0207/1292] drm: Add directive to format code in comment Add formatting directive line in function `drm_gpuvm_sm_map_exec_lock()` comment to clear warning messages shown bellow that appears generating documentation `make htmldocs`. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2444: Unexpected indentation. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2446: Block quote ends without a blank line; unexpected unindent. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2450: Definition list ends without a blank line; unexpected unindent. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2451: Definition list ends without a blank line; unexpected unindent. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2455: Unexpected indentation. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2456: Definition list ends without a blank line; unexpected unindent. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2457: Definition list ends without a blank line; unexpected unindent. Warning: ./drivers/gpu/drm/drm_gpuvm.c:2458: Definition list ends without a blank line; unexpected unindent. Fixes: 471920ce25d5 ("drm/gpuvm: Add locking helpers") Signed-off-by: Javier Garcia Reviewed-by: Bagas Sanjaya Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250810150706.305040-1-rampxxxx@gmail.com [ Fix typo in commit message. - Danilo ] Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/drm_gpuvm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index bbc7fecb6f4ab4..74d949995a72f3 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -2432,6 +2432,8 @@ static const struct drm_gpuvm_ops lock_ops = { * * The expected usage is: * + * .. code-block:: c + * * vm_bind { * struct drm_exec exec; * From d19c541d269eddd9702b687fd4ba587c7da497a2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 13 Aug 2025 17:37:47 +0100 Subject: [PATCH 0208/1292] KVM: arm64: Correctly populate FAR_EL2 on nested SEA injection vcpu_write_sys_reg()'s signature is not totally obvious, and it is rather easy to write something that looks correct, except that... Oh wait... Swap addr and FAR_EL2 to restore some sanity in the nested SEA department. Fixes: 9aba641b9ec2a ("KVM: arm64: nv: Respect exception routing rules for SEAs") Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20250813163747.2591317-1-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/emulate-nested.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 90cb4b7ae0ff74..af69c897c2c3ad 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -2833,7 +2833,7 @@ int kvm_inject_nested_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr) iabt ? ESR_ELx_EC_IABT_LOW : ESR_ELx_EC_DABT_LOW); esr |= ESR_ELx_FSC_EXTABT | ESR_ELx_IL; - vcpu_write_sys_reg(vcpu, FAR_EL2, addr); + vcpu_write_sys_reg(vcpu, addr, FAR_EL2); if (__vcpu_sys_reg(vcpu, SCTLR2_EL2) & SCTLR2_EL1_EASE) return kvm_inject_nested(vcpu, esr, except_type_serror); From 12da2b92ad50e6602b4c5e9073d71f2368b70b63 Mon Sep 17 00:00:00 2001 From: Chandra Mohan Sundar Date: Thu, 14 Aug 2025 22:00:10 +0530 Subject: [PATCH 0209/1292] net: libwx: Fix the size in RSS hash key population While trying to fill a random RSS key, the size of the pointer is being used rather than the actual size of the RSS key. Fix by passing an appropriate value of the RSS key. This issue was reported by static coverity analyser. Fixes: eb4898fde1de8 ("net: libwx: add wangxun vf common api") Signed-off-by: Chandra Mohan Sundar Link: https://patch.msgid.link/20250814163014.613004-1-chandramohan.explore@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c index 5d48df7a849f2d..3023ea2732ef2d 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c @@ -192,7 +192,7 @@ void wx_setup_vfmrqc_vf(struct wx *wx) u8 i, j; /* Fill out hash function seeds */ - netdev_rss_key_fill(wx->rss_key, sizeof(wx->rss_key)); + netdev_rss_key_fill(wx->rss_key, WX_RSS_KEY_SIZE); for (i = 0; i < WX_RSS_KEY_SIZE / 4; i++) wr32(wx, WX_VXRSSRK(i), wx->rss_key[i]); From db2e7bcee11cd57f95fef3c6cbb562d0577eb84a Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 24 Jul 2025 18:54:41 +0200 Subject: [PATCH 0210/1292] drm: nova-drm: fix 32-bit arm build In 32-bit arm, the build fails with: error[E0308]: mismatched types --> drivers/gpu/drm/nova/file.rs:42:28 | 42 | getparam.set_value(value); | --------- ^^^^^ expected `u64`, found `u32` | | | arguments to this method are incorrect | note: method defined here --> drivers/gpu/drm/nova/uapi.rs:29:12 | 29 | pub fn set_value(&self, v: u64) { | ^^^^^^^^^ ------ help: you can convert a `u32` to a `u64` | 42 | getparam.set_value(value.into()); | +++++++ The reason is that `Getparam::set_value` takes a `u64` (from the UAPI), but `pci::Device::resource_len()` returns a `resource_size_t`, which is a `phys_addr_t`, which may be 32- or 64-bit. Thus add an `into()` call to support the 32-bit case, while allowing the Clippy lint that complains in the 64-bit case where the type is the same. Fixes: cdeaeb9dd762 ("drm: nova-drm: add initial driver skeleton") Signed-off-by: Miguel Ojeda Reviewed-by: Christian Schrefl Link: https://lore.kernel.org/r/20250724165441.2105632-1-ojeda@kernel.org Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nova/file.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs index 7e59a34b830da3..4fe62cf98a23e9 100644 --- a/drivers/gpu/drm/nova/file.rs +++ b/drivers/gpu/drm/nova/file.rs @@ -39,7 +39,8 @@ impl File { _ => return Err(EINVAL), }; - getparam.set_value(value); + #[allow(clippy::useless_conversion)] + getparam.set_value(value.into()); Ok(0) } From 1f403699c40f0806a707a9a6eed3b8904224021a Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Tue, 12 Aug 2025 15:19:32 +0800 Subject: [PATCH 0211/1292] drm/mediatek: Fix device/node reference count leaks in mtk_drm_get_all_drm_priv Using device_find_child() and of_find_device_by_node() to locate devices could cause an imbalance in the device's reference count. device_find_child() and of_find_device_by_node() both call get_device() to increment the reference count of the found device before returning the pointer. In mtk_drm_get_all_drm_priv(), these references are never released through put_device(), resulting in permanent reference count increments. Additionally, the for_each_child_of_node() iterator fails to release node references in all code paths. This leaks device node references when loop termination occurs before reaching MAX_CRTC. These reference count leaks may prevent device/node resources from being properly released during driver unbind operations. As comment of device_find_child() says, 'NOTE: you will need to drop the reference with put_device() after use'. Cc: stable@vger.kernel.org Fixes: 1ef7ed48356c ("drm/mediatek: Modify mediatek-drm for mt8195 multi mmsys support") Signed-off-by: Ma Ke Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20250812071932.471730-1-make24@iscas.ac.cn/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index d5e6bab3641435..f8a817689e1626 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -387,19 +387,19 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) of_id = of_match_node(mtk_drm_of_ids, node); if (!of_id) - continue; + goto next_put_node; pdev = of_find_device_by_node(node); if (!pdev) - continue; + goto next_put_node; drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match); if (!drm_dev) - continue; + goto next_put_device_pdev_dev; temp_drm_priv = dev_get_drvdata(drm_dev); if (!temp_drm_priv) - continue; + goto next_put_device_drm_dev; if (temp_drm_priv->data->main_len) all_drm_priv[CRTC_MAIN] = temp_drm_priv; @@ -411,10 +411,17 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) if (temp_drm_priv->mtk_drm_bound) cnt++; - if (cnt == MAX_CRTC) { - of_node_put(node); +next_put_device_drm_dev: + put_device(drm_dev); + +next_put_device_pdev_dev: + put_device(&pdev->dev); + +next_put_node: + of_node_put(node); + + if (cnt == MAX_CRTC) break; - } } if (drm_priv->data->mmsys_dev_num == cnt) { From c27973211ffcdf0a092eec265d5993e64b89adaf Mon Sep 17 00:00:00 2001 From: Xiao Ni Date: Fri, 15 Aug 2025 12:00:28 +0800 Subject: [PATCH 0212/1292] md: keep recovery_cp in mdp_superblock_s commit 907a99c314a5 ("md: rename recovery_cp to resync_offset") replaces recovery_cp with resync_offset in mdp_superblock_s which is in md_p.h. md_p.h is used in userspace too. So mdadm building fails because of this. This patch revert this change. Fixes: 907a99c314a5 ("md: rename recovery_cp to resync_offset") Signed-off-by: Xiao Ni Link: https://lore.kernel.org/linux-raid/20250815040028.18085-1-xni@redhat.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 6 +++--- include/uapi/linux/raid/md_p.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 772cffe02ff5c9..3836fc7eff674d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1423,7 +1423,7 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *freshest, stru else { if (sb->events_hi == sb->cp_events_hi && sb->events_lo == sb->cp_events_lo) { - mddev->resync_offset = sb->resync_offset; + mddev->resync_offset = sb->recovery_cp; } else mddev->resync_offset = 0; } @@ -1551,13 +1551,13 @@ static void super_90_sync(struct mddev *mddev, struct md_rdev *rdev) mddev->minor_version = sb->minor_version; if (mddev->in_sync) { - sb->resync_offset = mddev->resync_offset; + sb->recovery_cp = mddev->resync_offset; sb->cp_events_hi = (mddev->events>>32); sb->cp_events_lo = (u32)mddev->events; if (mddev->resync_offset == MaxSector) sb->state = (1<< MD_SB_CLEAN); } else - sb->resync_offset = 0; + sb->recovery_cp = 0; sb->layout = mddev->layout; sb->chunk_size = mddev->chunk_sectors << 9; diff --git a/include/uapi/linux/raid/md_p.h b/include/uapi/linux/raid/md_p.h index b1394628727758..ac74133a476887 100644 --- a/include/uapi/linux/raid/md_p.h +++ b/include/uapi/linux/raid/md_p.h @@ -173,7 +173,7 @@ typedef struct mdp_superblock_s { #else #error unspecified endianness #endif - __u32 resync_offset; /* 11 resync checkpoint sector count */ + __u32 recovery_cp; /* 11 resync checkpoint sector count */ /* There are only valid for minor_version > 90 */ __u64 reshape_position; /* 12,13 next address in array-space for reshape */ __u32 new_level; /* 14 new level we are reshaping to */ From cb0780ad4333040a98e10f014b593ef738a3f31e Mon Sep 17 00:00:00 2001 From: Zheng Qixing Date: Sat, 16 Aug 2025 08:25:33 +0800 Subject: [PATCH 0213/1292] md: add helper rdev_needs_recovery() Add a helper for checking if an rdev needs recovery. Signed-off-by: Zheng Qixing Link: https://lore.kernel.org/linux-raid/20250816002534.1754356-2-zhengqixing@huaweicloud.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 3836fc7eff674d..abd327ade4bdf7 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4839,6 +4839,15 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len) static struct md_sysfs_entry md_metadata = __ATTR_PREALLOC(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store); +static bool rdev_needs_recovery(struct md_rdev *rdev, sector_t sectors) +{ + return rdev->raid_disk >= 0 && + !test_bit(Journal, &rdev->flags) && + !test_bit(Faulty, &rdev->flags) && + !test_bit(In_sync, &rdev->flags) && + rdev->recovery_offset < sectors; +} + enum sync_action md_sync_action(struct mddev *mddev) { unsigned long recovery = mddev->recovery; @@ -8995,11 +9004,7 @@ static sector_t md_sync_position(struct mddev *mddev, enum sync_action action) start = MaxSector; rcu_read_lock(); rdev_for_each_rcu(rdev, mddev) - if (rdev->raid_disk >= 0 && - !test_bit(Journal, &rdev->flags) && - !test_bit(Faulty, &rdev->flags) && - !test_bit(In_sync, &rdev->flags) && - rdev->recovery_offset < start) + if (rdev_needs_recovery(rdev, start)) start = rdev->recovery_offset; rcu_read_unlock(); @@ -9358,12 +9363,8 @@ void md_do_sync(struct md_thread *thread) test_bit(MD_RECOVERY_RECOVER, &mddev->recovery)) { rcu_read_lock(); rdev_for_each_rcu(rdev, mddev) - if (rdev->raid_disk >= 0 && - mddev->delta_disks >= 0 && - !test_bit(Journal, &rdev->flags) && - !test_bit(Faulty, &rdev->flags) && - !test_bit(In_sync, &rdev->flags) && - rdev->recovery_offset < mddev->curr_resync) + if (mddev->delta_disks >= 0 && + rdev_needs_recovery(rdev, mddev->curr_resync)) rdev->recovery_offset = mddev->curr_resync; rcu_read_unlock(); } From b7ee30f0efd12f42735ae233071015389407966c Mon Sep 17 00:00:00 2001 From: Zheng Qixing Date: Sat, 16 Aug 2025 08:25:34 +0800 Subject: [PATCH 0214/1292] md: fix sync_action incorrect display during resync During raid resync, if a disk becomes faulty, the operation is briefly interrupted. The MD_RECOVERY_RECOVER flag triggered by the disk failure causes sync_action to incorrectly show "recover" instead of "resync". The same issue affects reshape operations. Reproduction steps: mdadm -Cv /dev/md1 -l1 -n4 -e1.2 /dev/sd{a..d} // -> resync happened mdadm -f /dev/md1 /dev/sda // -> resync interrupted cat sync_action -> recover Add progress checks in md_sync_action() for resync/recover/reshape to ensure the interface correctly reports the actual operation type. Fixes: 4b10a3bc67c1 ("md: ensure resync is prioritized over recovery") Signed-off-by: Zheng Qixing Link: https://lore.kernel.org/linux-raid/20250816002534.1754356-3-zhengqixing@huaweicloud.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index abd327ade4bdf7..1baaf52c603c1c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4848,9 +4848,33 @@ static bool rdev_needs_recovery(struct md_rdev *rdev, sector_t sectors) rdev->recovery_offset < sectors; } +static enum sync_action md_get_active_sync_action(struct mddev *mddev) +{ + struct md_rdev *rdev; + bool is_recover = false; + + if (mddev->resync_offset < MaxSector) + return ACTION_RESYNC; + + if (mddev->reshape_position != MaxSector) + return ACTION_RESHAPE; + + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) { + if (rdev_needs_recovery(rdev, MaxSector)) { + is_recover = true; + break; + } + } + rcu_read_unlock(); + + return is_recover ? ACTION_RECOVER : ACTION_IDLE; +} + enum sync_action md_sync_action(struct mddev *mddev) { unsigned long recovery = mddev->recovery; + enum sync_action active_action; /* * frozen has the highest priority, means running sync_thread will be @@ -4874,8 +4898,17 @@ enum sync_action md_sync_action(struct mddev *mddev) !test_bit(MD_RECOVERY_NEEDED, &recovery)) return ACTION_IDLE; - if (test_bit(MD_RECOVERY_RESHAPE, &recovery) || - mddev->reshape_position != MaxSector) + /* + * Check if any sync operation (resync/recover/reshape) is + * currently active. This ensures that only one sync operation + * can run at a time. Returns the type of active operation, or + * ACTION_IDLE if none are active. + */ + active_action = md_get_active_sync_action(mddev); + if (active_action != ACTION_IDLE) + return active_action; + + if (test_bit(MD_RECOVERY_RESHAPE, &recovery)) return ACTION_RESHAPE; if (test_bit(MD_RECOVERY_RECOVER, &recovery)) From 715c7a36d59f54162a26fac1d1ed8dc087a24cf1 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 14 Aug 2025 12:43:23 -0700 Subject: [PATCH 0215/1292] selftests: tls: make the new data_steal test less flaky The CI has hit a couple of cases of: RUN global.data_steal ... tls.c:2762:data_steal:Expected recv(cfd, buf2, sizeof(buf2), MSG_DONTWAIT) (20000) == -1 (-1) data_steal: Test terminated by timeout FAIL global.data_steal Looks like the 2msec sleep is not long enough. Make the sleep longer, and then instead of second sleep wait for the thieving process to exit. That way we can be sure it called recv() before us. While at it also avoid trying to steal more than a record, this seems to be causing issues in manual testing as well. Fixes: d7e82594a45c ("selftests: tls: test TCP stealing data from under the TLS socket") Link: https://patch.msgid.link/20250814194323.2014650-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/tls.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index d8cfcf9bb82594..2b8387a83bc78e 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -2748,17 +2748,18 @@ TEST(data_steal) { pid = fork(); ASSERT_GE(pid, 0); if (!pid) { - EXPECT_EQ(recv(cfd, buf, sizeof(buf), MSG_WAITALL), - sizeof(buf)); + EXPECT_EQ(recv(cfd, buf, sizeof(buf) / 2, MSG_WAITALL), + sizeof(buf) / 2); exit(!__test_passed(_metadata)); } - usleep(2000); + usleep(10000); ASSERT_EQ(setsockopt(fd, SOL_TLS, TLS_TX, &tls, tls.len), 0); ASSERT_EQ(setsockopt(cfd, SOL_TLS, TLS_RX, &tls, tls.len), 0); EXPECT_EQ(send(fd, buf, sizeof(buf), 0), sizeof(buf)); - usleep(2000); + EXPECT_EQ(wait(&status), pid); + EXPECT_EQ(status, 0); EXPECT_EQ(recv(cfd, buf2, sizeof(buf2), MSG_DONTWAIT), -1); /* Don't check errno, the error will be different depending * on what random bytes TLS interpreted as the record length. @@ -2766,9 +2767,6 @@ TEST(data_steal) { close(fd); close(cfd); - - EXPECT_EQ(wait(&status), pid); - EXPECT_EQ(status, 0); } static void __attribute__((constructor)) fips_check(void) { From 39ca24675b7e351b8e681d924f417e455d4a7fc1 Mon Sep 17 00:00:00 2001 From: "Avizrat, Yaron" Date: Thu, 14 Aug 2025 10:44:07 +0000 Subject: [PATCH 0216/1292] MAINTAINERS: Change habanalabs maintainers I will be leaving Intel soon, Koby Elbaz & Konstantin Sinyuk will take the role of habanalabs driver maintainers. Signed-off-by: Yaron Avizrat Reviewed-by: Koby Elbaz Reviewed-by: Konstantin Sinyuk Link: https://patch.msgid.link/DM4PR11MB55491ACAA33DF29CEF3C67DAE935A@DM4PR11MB5549.namprd11.prod.outlook.com [lukas: wrap to 72 chars] Signed-off-by: Lukas Wunner --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 20ffd334e0a78a..433fc4e5e68efa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10666,7 +10666,8 @@ S: Maintained F: block/partitions/efi.* HABANALABS PCI DRIVER -M: Yaron Avizrat +M: Koby Elbaz +M: Konstantin Sinyuk L: dri-devel@lists.freedesktop.org S: Supported C: irc://irc.oftc.net/dri-devel From a44458dfd5bc0c79c6739c3f4c658361d3a5126b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 21 Aug 2024 01:10:28 +0200 Subject: [PATCH 0217/1292] accel/habanalabs/gaudi2: Use kvfree() for memory allocated with kvcalloc() Use kvfree() to fix the following Coccinelle/coccicheck warning reported by kfree_mismatch.cocci: WARNING kvmalloc is used to allocate this memory at line 10398 Fixes: f728c17fc97a ("accel/habanalabs/gaudi2: move HMMU page tables to device memory") Reported-by: Qianfeng Rong Closes: https://patch.msgid.link/20250808085530.233737-1-rongqianfeng@vivo.com Signed-off-by: Thorsten Blum [lukas: acknowledge Qianfeng, adjust Thorsten's domain, add Fixes tag] Signed-off-by: Lukas Wunner Reviewed-by: Tomer Tayar Cc: stable@vger.kernel.org # v6.9+ Link: https://patch.msgid.link/20240820231028.136126-1-thorsten.blum@toblux.com --- drivers/accel/habanalabs/gaudi2/gaudi2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/habanalabs/gaudi2/gaudi2.c b/drivers/accel/habanalabs/gaudi2/gaudi2.c index a38b88baadf2ba..5722e4128d3cee 100644 --- a/drivers/accel/habanalabs/gaudi2/gaudi2.c +++ b/drivers/accel/habanalabs/gaudi2/gaudi2.c @@ -10437,7 +10437,7 @@ static int gaudi2_memset_device_memory(struct hl_device *hdev, u64 addr, u64 siz (u64 *)(lin_dma_pkts_arr), DEBUGFS_WRITE64); WREG32(sob_addr, 0); - kfree(lin_dma_pkts_arr); + kvfree(lin_dma_pkts_arr); return rc; } From 8a6ededaad2d2dcaac8e545bffee1073dca9db95 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 13 Aug 2025 12:16:06 +0300 Subject: [PATCH 0218/1292] iio: adc: bd79124: Add GPIOLIB dependency The bd79124 has ADC inputs which can be muxed to be GPIOs. The driver supports this by registering a GPIO-chip for channels which aren't used as ADC. The Kconfig entry does not handle the dependency to GPIOLIB, which causes errors: ERROR: modpost: "devm_gpiochip_add_data_with_key" [drivers/iio/adc/rohm-bd79124.ko] undefined! ERROR: modpost: "gpiochip_get_data" [drivers/iio/adc/rohm-bd79124.ko] undefined! at linking phase if GPIOLIB is not configured to be used. Fix this by adding dependency to the GPIOLIB. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508131533.5sSkq80B-lkp@intel.com/ Fixes: 3f57a3b9ab74 ("iio: adc: Support ROHM BD79124 ADC") Signed-off-by: Matti Vaittinen Reviewed-by: Bartosz Golaszewski Link: https://patch.msgid.link/6837249bddf358924e67566293944506206d2d62.1755076369.git.mazziesaccount@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6de2abad0197bf..24f2572c487ea3 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1300,7 +1300,7 @@ config RN5T618_ADC config ROHM_BD79124 tristate "Rohm BD79124 ADC driver" - depends on I2C + depends on I2C && GPIOLIB select REGMAP_I2C select IIO_ADC_HELPER help From d1dfcdd30140c031ae091868fb5bed084132bca1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 17:50:14 +0200 Subject: [PATCH 0219/1292] pcmcia: omap_cf: Mark driver struct with __refdata to prevent section mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As described in the added code comment, a reference to .exit.text is ok for drivers registered via platform_driver_probe(). Make this explicit to prevent the following section mismatch warning WARNING: modpost: drivers/pcmcia/omap_cf: section mismatch in reference: omap_cf_driver+0x4 (section: .data) -> omap_cf_remove (section: .exit.text) that triggers on an omap1_defconfig + CONFIG_OMAP_CF=m build. Signed-off-by: Geert Uytterhoeven Acked-by: Aaro Koskinen Reviewed-by: Uwe Kleine-Kƶnig Signed-off-by: Dominik Brodowski --- drivers/pcmcia/omap_cf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 1b1dff56ec7b11..733777367c3b45 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -302,7 +302,13 @@ static void __exit omap_cf_remove(struct platform_device *pdev) kfree(cf); } -static struct platform_driver omap_cf_driver = { +/* + * omap_cf_remove() lives in .exit.text. For drivers registered via + * platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver omap_cf_driver __refdata = { .driver = { .name = driver_name, }, From 44822df89e8f3386871d9cad563ece8e2fd8f0e7 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Tue, 12 Aug 2025 15:25:09 +0800 Subject: [PATCH 0220/1292] pcmcia: Fix a NULL pointer dereference in __iodyn_find_io_region() In __iodyn_find_io_region(), pcmcia_make_resource() is assigned to res and used in pci_bus_alloc_resource(). There is a dereference of res in pci_bus_alloc_resource(), which could lead to a NULL pointer dereference on failure of pcmcia_make_resource(). Fix this bug by adding a check of res. Cc: stable@vger.kernel.org Fixes: 49b1153adfe1 ("pcmcia: move all pcmcia_resource_ops providers into one module") Signed-off-by: Ma Ke Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_iodyn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c index b04b16496b0c4b..2677b577c1f858 100644 --- a/drivers/pcmcia/rsrc_iodyn.c +++ b/drivers/pcmcia/rsrc_iodyn.c @@ -62,6 +62,9 @@ static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s, unsigned long min = base; int ret; + if (!res) + return NULL; + data.mask = align - 1; data.offset = base & data.mask; From b04e4551893fb8a06106a175ed7055d41a9279c4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 11 Aug 2025 13:32:31 -0500 Subject: [PATCH 0221/1292] iio: adc: ad7380: fix missing max_conversion_rate_hz on adaq4381-4 Add max_conversion_rate_hz to the chip info for "adaq4381-4". Without this, the driver fails to probe because it tries to set the initial sample rate to 0 Hz, which is not valid. Fixes: bbeaec81a03e ("iio: ad7380: add support for SPI offload") Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250811-iio-adc-ad7380-fix-missing-max_conversion_rate_hs-on-ad4381-4-v1-1-ffb728d7a71c@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7380.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index 6f7034b6c266bd..fa251dc1aae6ab 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -873,6 +873,7 @@ static const struct ad7380_chip_info adaq4381_4_chip_info = { .has_hardware_gain = true, .available_scan_masks = ad7380_4_channel_scan_masks, .timing_specs = &ad7380_4_timing, + .max_conversion_rate_hz = 4 * MEGA, }; static const struct spi_offload_config ad7380_offload_config = { From ce0e8efb8438469aedb94746603a66e2de91852b Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Mon, 11 Aug 2025 09:04:37 +0700 Subject: [PATCH 0222/1292] pcmcia: ds: Emphasize "really" epizeuxis pcmcia_dev_present() comment writes about small timeframe where the function returns NULL (racy condition), in epizeuxis device. In the past, it tripped contributors who misunderstood it for "really" duplicate ([1], [2]). Add comma between "really" words to emphasize the epizeuxis. Link: https://lore.kernel.org/all/YxT1As38WRZcyH0%2F@shine.dominikbrodowski.net/ [1] Link: https://lore.kernel.org/all/20220831083623.GA25639@isilmar-4.linta.de/ [2] Signed-off-by: Bagas Sanjaya Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index da6f66f357cc10..18f4eef28dbc5d 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1308,7 +1308,7 @@ static int pcmcia_bus_early_resume(struct pcmcia_socket *skt) * physically present, even if the call to this function returns * non-NULL. Furthermore, the device driver most likely is unbound * almost immediately, so the timeframe where pcmcia_dev_present - * returns NULL is probably really really small. + * returns NULL is probably really, really small. */ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) { From 4bf1541e41d0540f9fcce8a32424ab05ae26fdca Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Mon, 30 Jun 2025 11:32:56 +0200 Subject: [PATCH 0223/1292] pcmcia: remove PCCARD_IODYN The config PCCARD_IODYN was last used in the config option PCMCIA_M8XX with its m8xx_pcmcia driver. This driver was removed with commit 39eb56da2b53 ("pcmcia: Remove m8xx_pcmcia driver"), included in v3.17, back in 2014. Since then, the config PCCARD_IODYN is unused. Remove the config option, the corresponding file included with this config and the corresponding definition in the pcmcia header file. Signed-off-by: Lukas Bulwahn Signed-off-by: Dominik Brodowski --- drivers/pcmcia/Kconfig | 3 - drivers/pcmcia/Makefile | 1 - drivers/pcmcia/rsrc_iodyn.c | 171 ------------------------------------ include/pcmcia/ss.h | 8 +- 4 files changed, 1 insertion(+), 182 deletions(-) delete mode 100644 drivers/pcmcia/rsrc_iodyn.c diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index dddb235dd02024..660a95805524c5 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -250,7 +250,4 @@ config ELECTRA_CF config PCCARD_NONSTATIC bool -config PCCARD_IODYN - bool - endif # PCCARD diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index c9d51b150682fa..d16a0317ce4383 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_PCMCIA) += pcmcia.o pcmcia_rsrc-y += rsrc_mgr.o pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o -pcmcia_rsrc-$(CONFIG_PCCARD_IODYN) += rsrc_iodyn.o obj-$(CONFIG_PCCARD) += pcmcia_rsrc.o diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c deleted file mode 100644 index 2677b577c1f858..00000000000000 --- a/drivers/pcmcia/rsrc_iodyn.c +++ /dev/null @@ -1,171 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * rsrc_iodyn.c -- Resource management routines for MEM-static sockets. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - * (C) 1999 David A. Hinds - */ - -#include -#include -#include - -#include -#include -#include "cs_internal.h" - - -struct pcmcia_align_data { - unsigned long mask; - unsigned long offset; -}; - -static resource_size_t pcmcia_align(void *align_data, - const struct resource *res, - resource_size_t size, resource_size_t align) -{ - struct pcmcia_align_data *data = align_data; - resource_size_t start; - - start = (res->start & ~data->mask) + data->offset; - if (start < res->start) - start += data->mask + 1; - -#ifdef CONFIG_X86 - if (res->flags & IORESOURCE_IO) { - if (start & 0x300) - start = (start + 0x3ff) & ~0x3ff; - } -#endif - -#ifdef CONFIG_M68K - if (res->flags & IORESOURCE_IO) { - if ((res->start + size - 1) >= 1024) - start = res->end; - } -#endif - - return start; -} - - -static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s, - unsigned long base, int num, - unsigned long align) -{ - struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO, - dev_name(&s->dev)); - struct pcmcia_align_data data; - unsigned long min = base; - int ret; - - if (!res) - return NULL; - - data.mask = align - 1; - data.offset = base & data.mask; - -#ifdef CONFIG_PCI - if (s->cb_dev) { - ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, - min, 0, pcmcia_align, &data); - } else -#endif - ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, - 1, pcmcia_align, &data); - - if (ret != 0) { - kfree(res); - res = NULL; - } - return res; -} - -static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr, - unsigned int *base, unsigned int num, - unsigned int align, struct resource **parent) -{ - int i, ret = 0; - - /* Check for an already-allocated window that must conflict with - * what was asked for. It is a hack because it does not catch all - * potential conflicts, just the most obvious ones. - */ - for (i = 0; i < MAX_IO_WIN; i++) { - if (!s->io[i].res) - continue; - - if (!*base) - continue; - - if ((s->io[i].res->start & (align-1)) == *base) - return -EBUSY; - } - - for (i = 0; i < MAX_IO_WIN; i++) { - struct resource *res = s->io[i].res; - unsigned int try; - - if (res && (res->flags & IORESOURCE_BITS) != - (attr & IORESOURCE_BITS)) - continue; - - if (!res) { - if (align == 0) - align = 0x10000; - - res = s->io[i].res = __iodyn_find_io_region(s, *base, - num, align); - if (!res) - return -EINVAL; - - *base = res->start; - s->io[i].res->flags = - ((res->flags & ~IORESOURCE_BITS) | - (attr & IORESOURCE_BITS)); - s->io[i].InUse = num; - *parent = res; - return 0; - } - - /* Try to extend top of window */ - try = res->end + 1; - if ((*base == 0) || (*base == try)) { - if (adjust_resource(s->io[i].res, res->start, - resource_size(res) + num)) - continue; - *base = try; - s->io[i].InUse += num; - *parent = res; - return 0; - } - - /* Try to extend bottom of window */ - try = res->start - num; - if ((*base == 0) || (*base == try)) { - if (adjust_resource(s->io[i].res, - res->start - num, - resource_size(res) + num)) - continue; - *base = try; - s->io[i].InUse += num; - *parent = res; - return 0; - } - } - - return -EINVAL; -} - - -struct pccard_resource_ops pccard_iodyn_ops = { - .validate_mem = NULL, - .find_io = iodyn_find_io, - .find_mem = NULL, - .init = static_init, - .exit = NULL, -}; -EXPORT_SYMBOL(pccard_iodyn_ops); diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 7cf7dbbfa1316b..89aed99bfeaeca 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -227,12 +227,8 @@ struct pcmcia_socket { /* socket drivers must define the resource operations type they use. There - * are three options: + * are two options: * - pccard_static_ops iomem and ioport areas are assigned statically - * - pccard_iodyn_ops iomem areas is assigned statically, ioport - * areas dynamically - * If this option is selected, use - * "select PCCARD_IODYN" in Kconfig. * - pccard_nonstatic_ops iomem and ioport areas are assigned dynamically. * If this option is selected, use * "select PCCARD_NONSTATIC" in Kconfig. @@ -240,13 +236,11 @@ struct pcmcia_socket { */ extern struct pccard_resource_ops pccard_static_ops; #if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) -extern struct pccard_resource_ops pccard_iodyn_ops; extern struct pccard_resource_ops pccard_nonstatic_ops; #else /* If PCMCIA is not used, but only CARDBUS, these functions are not used * at all. Therefore, do not use the large (240K!) rsrc_nonstatic module */ -#define pccard_iodyn_ops pccard_static_ops #define pccard_nonstatic_ops pccard_static_ops #endif From 9e1ee333631a6d2b5f4ed9449ee2d595b6a87b81 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 11 Apr 2025 10:44:29 +0200 Subject: [PATCH 0224/1292] pcmcia: Use str_off_on() and str_yes_no() helpers Remove hard-coded strings by using the str_off_on() and str_yes_no() helper functions. Signed-off-by: Thorsten Blum Signed-off-by: Dominik Brodowski --- drivers/pcmcia/socket_sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index c7a906664c3696..4eadd04850662c 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -98,7 +99,7 @@ static ssize_t pccard_show_card_pm_state(struct device *dev, char *buf) { struct pcmcia_socket *s = to_socket(dev); - return sysfs_emit(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on"); + return sysfs_emit(buf, "%s\n", str_off_on(s->state & SOCKET_SUSPEND)); } static ssize_t pccard_store_card_pm_state(struct device *dev, @@ -177,7 +178,7 @@ static ssize_t pccard_show_resource(struct device *dev, struct device_attribute *attr, char *buf) { struct pcmcia_socket *s = to_socket(dev); - return sysfs_emit(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); + return sysfs_emit(buf, "%s\n", str_yes_no(s->resource_setup_done)); } static ssize_t pccard_store_resource(struct device *dev, From ecef14f70ec9344a10c817248d2ac6cddee5921e Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Thu, 20 Mar 2025 14:39:56 +0800 Subject: [PATCH 0225/1292] pcmcia: omap: Add missing check for platform_get_resource Add missing check for platform_get_resource() and return error if it fails to catch the error. Fixes: d87d44f7ab35 ("ARM: omap1: move CF chipselect setup to board file") Signed-off-by: Chen Ni Signed-off-by: Dominik Brodowski --- drivers/pcmcia/omap_cf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 733777367c3b45..d6f24c7d156227 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -215,6 +215,8 @@ static int __init omap_cf_probe(struct platform_device *pdev) return -EINVAL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; cf = kzalloc(sizeof *cf, GFP_KERNEL); if (!cf) From 750da5029fd914b647d3063dacdadf56b9a9a046 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 3 Mar 2025 01:01:25 +0000 Subject: [PATCH 0226/1292] pcmcia: cs: Remove unused pcmcia_get_socket_by_nr The last use of pcmcia_get_socket_by_nr() was removed in 2010 by commit 5716d415f8c5 ("pcmcia: remove obsolete ioctl") Remove it. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 17 ----------------- drivers/pcmcia/cs_internal.h | 1 - 2 files changed, 18 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index c75f55e1250a30..adbc486af2ea93 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -229,23 +229,6 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) EXPORT_SYMBOL(pcmcia_unregister_socket); -struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr) -{ - struct pcmcia_socket *s; - - down_read(&pcmcia_socket_list_rwsem); - list_for_each_entry(s, &pcmcia_socket_list, socket_list) - if (s->sock == nr) { - up_read(&pcmcia_socket_list_rwsem); - return s; - } - up_read(&pcmcia_socket_list_rwsem); - - return NULL; - -} -EXPORT_SYMBOL(pcmcia_get_socket_by_nr); - static int socket_reset(struct pcmcia_socket *skt) { int status, i; diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 02a83ca44e7750..5ac810ffda314d 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -116,7 +116,6 @@ extern struct list_head pcmcia_socket_list; extern const struct class pcmcia_socket_class; int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); -struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr); void pcmcia_parse_uevents(struct pcmcia_socket *socket, unsigned int events); #define PCMCIA_UEVENT_EJECT 0x0001 From 4a81f78caa53e0633cf311ca1526377d9bff7479 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Mon, 20 Jan 2025 21:10:06 +0800 Subject: [PATCH 0227/1292] pcmcia: Add error handling for add_interval() in do_validate_mem() In the do_validate_mem(), the call to add_interval() does not handle errors. If kmalloc() fails in add_interval(), it could result in a null pointer being inserted into the linked list, leading to illegal memory access when sub_interval() is called next. This patch adds an error handling for the add_interval(). If add_interval() returns an error, the function will return early with the error code. Fixes: 7b4884ca8853 ("pcmcia: validate late-added resources") Signed-off-by: Wentao Liang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_nonstatic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index bf9d070a44966d..da494fe451baf0 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -375,7 +375,9 @@ static int do_validate_mem(struct pcmcia_socket *s, if (validate && !s->fake_cis) { /* move it to the validated data set */ - add_interval(&s_data->mem_db_valid, base, size); + ret = add_interval(&s_data->mem_db_valid, base, size); + if (ret) + return ret; sub_interval(&s_data->mem_db, base, size); } From a3c6eabe3bbd6b0e7124d68b2d3bc32fed17362e Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Sun, 10 Aug 2025 15:33:27 +0300 Subject: [PATCH 0228/1292] iio: adc: rzg2l: Cleanup suspend/resume path There is no need to manually track the runtime PM status in the driver. The pm_runtime_force_suspend() and pm_runtime_force_resume() functions already call pm_runtime_status_suspended() to check the runtime PM state. Additionally, avoid calling pm_runtime_put_autosuspend() during the suspend/resume path, as this would decrease the usage counter of a potential user that had the ADC open before the suspend/resume cycle. Fixes: 563cf94f9329 ("iio: adc: rzg2l_adc: Add suspend/resume support") Reviewed-by: Ulf Hansson Reviewed-by: Lad Prabhakar Signed-off-by: Claudiu Beznea Link: https://patch.msgid.link/20250810123328.800104-2-claudiu.beznea.uj@bp.renesas.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rzg2l_adc.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 9674d48074c9a7..0cb5a67fd4973f 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -89,7 +89,6 @@ struct rzg2l_adc { struct completion completion; struct mutex lock; u16 last_val[RZG2L_ADC_MAX_CHANNELS]; - bool was_rpm_active; }; /** @@ -541,14 +540,9 @@ static int rzg2l_adc_suspend(struct device *dev) }; int ret; - if (pm_runtime_suspended(dev)) { - adc->was_rpm_active = false; - } else { - ret = pm_runtime_force_suspend(dev); - if (ret) - return ret; - adc->was_rpm_active = true; - } + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets); if (ret) @@ -557,9 +551,7 @@ static int rzg2l_adc_suspend(struct device *dev) return 0; rpm_restore: - if (adc->was_rpm_active) - pm_runtime_force_resume(dev); - + pm_runtime_force_resume(dev); return ret; } @@ -577,11 +569,9 @@ static int rzg2l_adc_resume(struct device *dev) if (ret) return ret; - if (adc->was_rpm_active) { - ret = pm_runtime_force_resume(dev); - if (ret) - goto resets_restore; - } + ret = pm_runtime_force_resume(dev); + if (ret) + goto resets_restore; ret = rzg2l_adc_hw_init(dev, adc); if (ret) @@ -590,10 +580,7 @@ static int rzg2l_adc_resume(struct device *dev) return 0; rpm_restore: - if (adc->was_rpm_active) { - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - } + pm_runtime_force_suspend(dev); resets_restore: reset_control_bulk_assert(ARRAY_SIZE(resets), resets); return ret; From c69e13965f26b8058f538ea8bdbd2d7718cf1fbe Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Sun, 10 Aug 2025 15:33:28 +0300 Subject: [PATCH 0229/1292] iio: adc: rzg2l_adc: Set driver data before enabling runtime PM When stress-testing the system by repeatedly unbinding and binding the ADC device in a loop, and the ADC is a supplier for another device (e.g., a thermal hardware block that reads temperature through the ADC), it may happen that the ADC device is runtime-resumed immediately after runtime PM is enabled, triggered by its consumer. At this point, since drvdata is not yet set and the driver's runtime PM callbacks rely on it, a crash can occur. To avoid this, set drvdata just after it was allocated. Fixes: 89ee8174e8c8 ("iio: adc: rzg2l_adc: Simplify the runtime PM code") Signed-off-by: Claudiu Beznea Link: https://patch.msgid.link/20250810123328.800104-3-claudiu.beznea.uj@bp.renesas.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rzg2l_adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 0cb5a67fd4973f..cadb0446bc2956 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -427,6 +427,8 @@ static int rzg2l_adc_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; + platform_set_drvdata(pdev, indio_dev); + adc = iio_priv(indio_dev); adc->hw_params = device_get_match_data(dev); @@ -459,8 +461,6 @@ static int rzg2l_adc_probe(struct platform_device *pdev) if (ret) return ret; - platform_set_drvdata(pdev, indio_dev); - ret = rzg2l_adc_hw_init(dev, adc); if (ret) return dev_err_probe(&pdev->dev, ret, From 433b99e922943efdfd62b9a8e3ad1604838181f2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:21 +0100 Subject: [PATCH 0230/1292] iio: light: as73211: Ensure buffer holes are zeroed Given that the buffer is copied to a kfifo that ultimately user space can read, ensure we zero it. Fixes: 403e5586b52e ("iio: light: as73211: New driver") Reviewed-by: Matti Vaittinen Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-2-jic23@kernel.org Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/light/as73211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c index 68f60dc3c79d53..32719f584c47a0 100644 --- a/drivers/iio/light/as73211.c +++ b/drivers/iio/light/as73211.c @@ -639,7 +639,7 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p) struct { __le16 chan[4]; aligned_s64 ts; - } scan; + } scan = { }; int data_result, ret; mutex_lock(&data->mutex); From 5eb4b9a4cdbb70d70377fe8fb2920b75910e5024 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 13 Aug 2025 15:21:59 +0200 Subject: [PATCH 0231/1292] params: Replace deprecated strcpy() with strscpy() and memcpy() strcpy() is deprecated; use strscpy() and memcpy() instead. In param_set_copystring(), we can safely use memcpy() because we already know the length of the source string 'val' and that it is guaranteed to be NUL-terminated within the first 'kps->maxlen' bytes. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Daniel Gomez Reviewed-by: Petr Pavlu Link: https://lore.kernel.org/r/20250813132200.184064-2-thorsten.blum@linux.dev Signed-off-by: Daniel Gomez --- kernel/params.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/params.c b/kernel/params.c index b92d64161b758d..b96cfd693c9968 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -513,13 +513,14 @@ EXPORT_SYMBOL(param_array_ops); int param_set_copystring(const char *val, const struct kernel_param *kp) { const struct kparam_string *kps = kp->str; + const size_t len = strnlen(val, kps->maxlen); - if (strnlen(val, kps->maxlen) == kps->maxlen) { + if (len == kps->maxlen) { pr_err("%s: string doesn't fit in %u chars.\n", kp->name, kps->maxlen-1); return -ENOSPC; } - strcpy(kps->string, val); + memcpy(kps->string, val, len + 1); return 0; } EXPORT_SYMBOL(param_set_copystring); @@ -841,7 +842,7 @@ static void __init param_sysfs_builtin(void) dot = strchr(kp->name, '.'); if (!dot) { /* This happens for core_param() */ - strcpy(modname, "kernel"); + strscpy(modname, "kernel"); name_len = 0; } else { name_len = dot - kp->name + 1; From 0f580d5d3d9d9cd0953695cd32e43aac3a946338 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sat, 16 Aug 2025 22:42:15 +0200 Subject: [PATCH 0232/1292] rust: alloc: fix `rusttest` by providing `Cmalloc::aligned_layout` too Commit fde578c86281 ("rust: alloc: replace aligned_size() with Kmalloc::aligned_layout()") provides a public `aligned_layout` function in `Kamlloc`, but not in `Cmalloc`, and thus uses of it will trigger an error in `rusttest`. Such a user appeared in the following commit 22ab0641b939 ("rust: drm: ensure kmalloc() compatible Layout"): error[E0599]: no function or associated item named `aligned_layout` found for struct `alloc::allocator_test::Cmalloc` in the current scope --> rust/kernel/drm/device.rs:100:31 | 100 | let layout = Kmalloc::aligned_layout(Layout::new::()); | ^^^^^^^^^^^^^^ function or associated item not found in `Cmalloc` | ::: rust/kernel/alloc/allocator_test.rs:19:1 | 19 | pub struct Cmalloc; | ------------------ function or associated item `aligned_layout` not found for this struct Thus add an equivalent one for `Cmalloc`. Fixes: fde578c86281 ("rust: alloc: replace aligned_size() with Kmalloc::aligned_layout()") Signed-off-by: Miguel Ojeda Link: https://lore.kernel.org/r/20250816204215.2719559-1-ojeda@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/allocator_test.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs index a3074480bd8d74..90dd987d40e452 100644 --- a/rust/kernel/alloc/allocator_test.rs +++ b/rust/kernel/alloc/allocator_test.rs @@ -22,6 +22,17 @@ pub type Kmalloc = Cmalloc; pub type Vmalloc = Kmalloc; pub type KVmalloc = Kmalloc; +impl Cmalloc { + /// Returns a [`Layout`] that makes [`Kmalloc`] fulfill the requested size and alignment of + /// `layout`. + pub fn aligned_layout(layout: Layout) -> Layout { + // Note that `layout.size()` (after padding) is guaranteed to be a multiple of + // `layout.align()` which together with the slab guarantees means that `Kmalloc` will return + // a properly aligned object (see comments in `kmalloc()` for more information). + layout.pad_to_align() + } +} + extern "C" { #[link_name = "aligned_alloc"] fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void; From a3dc32c635bae0ae569f489e00de0e8f015bfc25 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Thu, 14 Aug 2025 00:24:15 +0800 Subject: [PATCH 0233/1292] USB: storage: Ignore driver CD mode for Realtek multi-mode Wi-Fi dongles Many Realtek USB Wi-Fi dongles released in recent years have two modes: one is driver CD mode which has Windows driver onboard, another one is Wi-Fi mode. Add the US_FL_IGNORE_DEVICE quirk for these multi-mode devices. Otherwise, usb_modeswitch may fail to switch them to Wi-Fi mode. Currently there are only two USB IDs known to be used by these multi-mode Wi-Fi dongles: 0bda:1a2b and 0bda:a192. Information about Mercury MW310UH in /sys/kernel/debug/usb/devices. T: Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 12 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=0bda ProdID=a192 Rev= 2.00 S: Manufacturer=Realtek S: Product=DISK C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=(none) E: Ad=8a(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0b(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Information about D-Link AX9U rev. A1 in /sys/kernel/debug/usb/devices. T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 55 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=0bda ProdID=1a2b Rev= 0.00 S: Manufacturer=Realtek S: Product=DISK C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=(none) E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Cc: stable Signed-off-by: Zenm Chen Acked-by: Alan Stern Link: https://lore.kernel.org/r/20250813162415.2630-1-zenmchen@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index bee9f1e8003d48..dfa5276a5a43e2 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1501,6 +1501,28 @@ UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_WP_DETECT ), +/* + * Reported by Zenm Chen + * Ignore driver CD mode, otherwise usb_modeswitch may fail to switch + * the device into Wi-Fi mode. + */ +UNUSUAL_DEV( 0x0bda, 0x1a2b, 0x0000, 0xffff, + "Realtek", + "DISK", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE ), + +/* + * Reported by Zenm Chen + * Ignore driver CD mode, otherwise usb_modeswitch may fail to switch + * the device into Wi-Fi mode. + */ +UNUSUAL_DEV( 0x0bda, 0xa192, 0x0000, 0xffff, + "Realtek", + "DISK", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE ), + UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999, "Maxtor", "USB to SATA", From 45eae113dccaf8e502090ecf5b3d9e9b805add6f Mon Sep 17 00:00:00 2001 From: Selvarasu Ganesan Date: Fri, 8 Aug 2025 18:23:05 +0530 Subject: [PATCH 0234/1292] usb: dwc3: Remove WARN_ON for device endpoint command timeouts This commit addresses a rarely observed endpoint command timeout which causes kernel panic due to warn when 'panic_on_warn' is enabled and unnecessary call trace prints when 'panic_on_warn' is disabled. It is seen during fast software-controlled connect/disconnect testcases. The following is one such endpoint command timeout that we observed: 1. Connect ======= ->dwc3_thread_interrupt ->dwc3_ep0_interrupt ->configfs_composite_setup ->composite_setup ->usb_ep_queue ->dwc3_gadget_ep0_queue ->__dwc3_gadget_ep0_queue ->__dwc3_ep0_do_control_data ->dwc3_send_gadget_ep_cmd 2. Disconnect ========== ->dwc3_thread_interrupt ->dwc3_gadget_disconnect_interrupt ->dwc3_ep0_reset_state ->dwc3_ep0_end_control_data ->dwc3_send_gadget_ep_cmd In the issue scenario, in Exynos platforms, we observed that control transfers for the previous connect have not yet been completed and end transfer command sent as a part of the disconnect sequence and processing of USB_ENDPOINT_HALT feature request from the host timeout. This maybe an expected scenario since the controller is processing EP commands sent as a part of the previous connect. It maybe better to remove WARN_ON in all places where device endpoint commands are sent to avoid unnecessary kernel panic due to warn. Cc: stable Co-developed-by: Akash M Signed-off-by: Akash M Signed-off-by: Selvarasu Ganesan Acked-by: Thinh Nguyen Reviewed-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20250808125315.1607-1-selvarasu.g@samsung.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/ep0.c | 20 ++++++++++++++++---- drivers/usb/dwc3/gadget.c | 10 ++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 666ac432f52d67..b4229aa13f375b 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -288,7 +288,9 @@ void dwc3_ep0_out_start(struct dwc3 *dwc) dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8, DWC3_TRBCTL_CONTROL_SETUP, false); ret = dwc3_ep0_start_trans(dep); - WARN_ON(ret < 0); + if (ret < 0) + dev_err(dwc->dev, "ep0 out start transfer failed: %d\n", ret); + for (i = 2; i < DWC3_ENDPOINTS_NUM; i++) { struct dwc3_ep *dwc3_ep; @@ -1061,7 +1063,9 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ret = dwc3_ep0_start_trans(dep); } - WARN_ON(ret < 0); + if (ret < 0) + dev_err(dwc->dev, + "ep0 data phase start transfer failed: %d\n", ret); } static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) @@ -1078,7 +1082,12 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) { - WARN_ON(dwc3_ep0_start_control_status(dep)); + int ret; + + ret = dwc3_ep0_start_control_status(dep); + if (ret) + dev_err(dwc->dev, + "ep0 status phase start transfer failed: %d\n", ret); } static void dwc3_ep0_do_control_status(struct dwc3 *dwc, @@ -1121,7 +1130,10 @@ void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); - WARN_ON_ONCE(ret); + if (ret) + dev_err_ratelimited(dwc->dev, + "ep0 data phase end transfer failed: %d\n", ret); + dep->resource_index = 0; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 68fa2813e5f4ea..554f997eb8c4fb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1772,7 +1772,11 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int dep->flags |= DWC3_EP_DELAY_STOP; return 0; } - WARN_ON_ONCE(ret); + + if (ret) + dev_err_ratelimited(dep->dwc->dev, + "end transfer failed: %d\n", ret); + dep->resource_index = 0; if (!interrupt) @@ -4048,7 +4052,9 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) dep->flags &= ~DWC3_EP_STALL; ret = dwc3_send_clear_stall_ep_cmd(dep); - WARN_ON_ONCE(ret); + if (ret) + dev_err_ratelimited(dwc->dev, + "failed to clear STALL on %s\n", dep->name); } } From cabb6c5f4d9e7f49bdf8c0a13c74bd93ee35f45a Mon Sep 17 00:00:00 2001 From: Amit Sunil Dhamne Date: Fri, 15 Aug 2025 11:31:51 -0700 Subject: [PATCH 0235/1292] usb: typec: maxim_contaminant: disable low power mode when reading comparator values Low power mode is enabled when reading CC resistance as part of `max_contaminant_read_resistance_kohm()` and left in that state. However, it's supposed to work with 1uA current source. To read CC comparator values current source is changed to 80uA. This causes a storm of CC interrupts as it (falsely) detects a potential contaminant. To prevent this, disable low power mode current sourcing before reading comparator values. Fixes: 02b332a06397 ("usb: typec: maxim_contaminant: Implement check_contaminant callback") Cc: stable Signed-off-by: Amit Sunil Dhamne Reviewed-by: Badhri Jagan Sridharan Rule: add Link: https://lore.kernel.org/stable/20250814-fix-upstream-contaminant-v1-1-801ce8089031%40google.com Link: https://lore.kernel.org/r/20250815-fix-upstream-contaminant-v2-1-6c8d6c3adafb@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/maxim_contaminant.c | 5 +++++ drivers/usb/typec/tcpm/tcpci_maxim.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/usb/typec/tcpm/maxim_contaminant.c b/drivers/usb/typec/tcpm/maxim_contaminant.c index 0cdda06592fd3c..818cfe226ac771 100644 --- a/drivers/usb/typec/tcpm/maxim_contaminant.c +++ b/drivers/usb/typec/tcpm/maxim_contaminant.c @@ -188,6 +188,11 @@ static int max_contaminant_read_comparators(struct max_tcpci_chip *chip, u8 *ven if (ret < 0) return ret; + /* Disable low power mode */ + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL, + FIELD_PREP(CCLPMODESEL, + LOW_POWER_MODE_DISABLE)); + /* Sleep to allow comparators settle */ usleep_range(5000, 6000); ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC1); diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.h b/drivers/usb/typec/tcpm/tcpci_maxim.h index 76270d5c283880..b33540a42a953d 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim.h +++ b/drivers/usb/typec/tcpm/tcpci_maxim.h @@ -21,6 +21,7 @@ #define CCOVPDIS BIT(6) #define SBURPCTRL BIT(5) #define CCLPMODESEL GENMASK(4, 3) +#define LOW_POWER_MODE_DISABLE 0 #define ULTRA_LOW_POWER_MODE 1 #define CCRPCTRL GENMASK(2, 0) #define UA_1_SRC 1 From a381c6d6f646226924809d0ad01a9465786da463 Mon Sep 17 00:00:00 2001 From: Amit Sunil Dhamne Date: Fri, 15 Aug 2025 11:31:52 -0700 Subject: [PATCH 0236/1292] usb: typec: maxim_contaminant: re-enable cc toggle if cc is open and port is clean Presently in `max_contaminant_is_contaminant()` if there's no contaminant detected previously, CC is open & stopped toggling and no contaminant is currently present, TCPC.RC would be programmed to do DRP toggling. However, it didn't actively look for a connection. This would lead to Type-C not detect *any* new connections. Hence, in the above situation, re-enable toggling & program TCPC to look for a new connection. Also, return early if TCPC was looking for connection as this indicates TCPC has neither detected a potential connection nor a change in contaminant state. In addition, once dry detection is complete (port is dry), restart toggling. Fixes: 02b332a06397e ("usb: typec: maxim_contaminant: Implement check_contaminant callback") Cc: stable Signed-off-by: Amit Sunil Dhamne Reviewed-by: Badhri Jagan Sridharan Link: https://lore.kernel.org/r/20250815-fix-upstream-contaminant-v2-2-6c8d6c3adafb@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/maxim_contaminant.c | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/usb/typec/tcpm/maxim_contaminant.c b/drivers/usb/typec/tcpm/maxim_contaminant.c index 818cfe226ac771..af8da6dc60ae0b 100644 --- a/drivers/usb/typec/tcpm/maxim_contaminant.c +++ b/drivers/usb/typec/tcpm/maxim_contaminant.c @@ -329,6 +329,39 @@ static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip) return 0; } +static int max_contaminant_enable_toggling(struct max_tcpci_chip *chip) +{ + struct regmap *regmap = chip->data.regmap; + int ret; + + /* Disable dry detection if enabled. */ + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL, + FIELD_PREP(CCLPMODESEL, + LOW_POWER_MODE_DISABLE)); + if (ret) + return ret; + + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, 0); + if (ret) + return ret; + + ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP | + FIELD_PREP(TCPC_ROLE_CTRL_CC1, + TCPC_ROLE_CTRL_CC_RD) | + FIELD_PREP(TCPC_ROLE_CTRL_CC2, + TCPC_ROLE_CTRL_CC_RD)); + if (ret) + return ret; + + ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, + TCPC_TCPC_CTRL_EN_LK4CONN_ALRT, + TCPC_TCPC_CTRL_EN_LK4CONN_ALRT); + if (ret) + return ret; + + return max_tcpci_write8(chip, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION); +} + bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce, bool *cc_handled) { @@ -345,6 +378,12 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect if (ret < 0) return false; + if (cc_status & TCPC_CC_STATUS_TOGGLING) { + if (chip->contaminant_state == DETECTED) + return true; + return false; + } + if (chip->contaminant_state == NOT_DETECTED || chip->contaminant_state == SINK) { if (!disconnect_while_debounce) msleep(100); @@ -377,6 +416,12 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect max_contaminant_enable_dry_detection(chip); return true; } + + ret = max_contaminant_enable_toggling(chip); + if (ret) + dev_err(chip->dev, + "Failed to enable toggling, ret=%d", + ret); } } else if (chip->contaminant_state == DETECTED) { if (!(cc_status & TCPC_CC_STATUS_TOGGLING)) { @@ -384,6 +429,14 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect if (chip->contaminant_state == DETECTED) { max_contaminant_enable_dry_detection(chip); return true; + } else { + ret = max_contaminant_enable_toggling(chip); + if (ret) { + dev_err(chip->dev, + "Failed to enable toggling, ret=%d", + ret); + return true; + } } } } From ba6cc29351b1fa0cb9adce91b88b9f3c3cbe9c46 Mon Sep 17 00:00:00 2001 From: Charalampos Mitrodimas Date: Sat, 16 Aug 2025 14:14:37 +0000 Subject: [PATCH 0237/1292] debugfs: fix mount options not being applied Mount options (uid, gid, mode) are silently ignored when debugfs is mounted. This is a regression introduced during the conversion to the new mount API. When the mount API conversion was done, the parsed options were never applied to the superblock when it was reused. As a result, the mount options were ignored when debugfs was mounted. Fix this by following the same pattern as the tracefs fix in commit e4d32142d1de ("tracing: Fix tracefs mount options"). Call debugfs_reconfigure() in debugfs_get_tree() to apply the mount options to the superblock after it has been created or reused. As an example, with the bug the "mode" mount option is ignored: $ mount -o mode=0666 -t debugfs debugfs /tmp/debugfs_test $ mount | grep debugfs_test debugfs on /tmp/debugfs_test type debugfs (rw,relatime) $ ls -ld /tmp/debugfs_test drwx------ 25 root root 0 Aug 4 14:16 /tmp/debugfs_test With the fix applied, it works as expected: $ mount -o mode=0666 -t debugfs debugfs /tmp/debugfs_test $ mount | grep debugfs_test debugfs on /tmp/debugfs_test type debugfs (rw,relatime,mode=666) $ ls -ld /tmp/debugfs_test drw-rw-rw- 37 root root 0 Aug 2 17:28 /tmp/debugfs_test Fixes: a20971c18752 ("vfs: Convert debugfs to use the new mount API") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220406 Cc: stable Reviewed-by: Eric Sandeen Signed-off-by: Charalampos Mitrodimas Link: https://lore.kernel.org/r/20250816-debugfs-mount-opts-v3-1-d271dad57b5b@posteo.net Signed-off-by: Greg Kroah-Hartman --- fs/debugfs/inode.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index a0357b0cf362d8..c12d649df6a543 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -183,6 +183,9 @@ static int debugfs_reconfigure(struct fs_context *fc) struct debugfs_fs_info *sb_opts = sb->s_fs_info; struct debugfs_fs_info *new_opts = fc->s_fs_info; + if (!new_opts) + return 0; + sync_filesystem(sb); /* structure copy of new mount options to sb */ @@ -282,10 +285,16 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc) static int debugfs_get_tree(struct fs_context *fc) { + int err; + if (!(debugfs_allow & DEBUGFS_ALLOW_API)) return -EPERM; - return get_tree_single(fc, debugfs_fill_super); + err = get_tree_single(fc, debugfs_fill_super); + if (err) + return err; + + return debugfs_reconfigure(fc); } static void debugfs_free_fc(struct fs_context *fc) From d49172bbd7eb07e4ba5e52238eaa9caf692c1cea Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 14 Aug 2025 21:27:29 +0200 Subject: [PATCH 0238/1292] Documentation: clarify the expected collaboration with security bugs reporters Some bug reports sent to the security team sometimes lack any explanation, are only AI-generated without verification, or sometimes it can simply be difficult to have a conversation with an invisible reporter belonging to an opaque team. This fortunately remains rare but the trend has been steadily increasing over the last years and it seems important to clarify what developers expect from reporters to avoid frustration on any side and keep the process efficient. Signed-off-by: Willy Tarreau Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20250814192730.19252-1-w@1wt.eu Signed-off-by: Greg Kroah-Hartman --- Documentation/process/security-bugs.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/process/security-bugs.rst b/Documentation/process/security-bugs.rst index 56c560a00b37a6..7dcc034d3df8ed 100644 --- a/Documentation/process/security-bugs.rst +++ b/Documentation/process/security-bugs.rst @@ -19,6 +19,16 @@ that can speed up the process considerably. It is possible that the security team will bring in extra help from area maintainers to understand and fix the security vulnerability. +The security team and maintainers almost always require additional +information beyond what was initially provided in a report and rely on +active and efficient collaboration with the reporter to perform further +testing (e.g., verifying versions, configuration options, mitigations, or +patches). Before contacting the security team, the reporter must ensure +they are available to explain their findings, engage in discussions, and +run additional tests. Reports where the reporter does not respond promptly +or cannot effectively discuss their findings may be abandoned if the +communication does not quickly improve. + As it is with any bug, the more information provided the easier it will be to diagnose and fix. Please review the procedure outlined in 'Documentation/admin-guide/reporting-issues.rst' if you are unclear about what From 3a68841d1d9b6eb32b2652bbb83acd17d5eb9135 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 14 Aug 2025 21:27:30 +0200 Subject: [PATCH 0239/1292] Documentation: smooth the text flow in the security bug reporting process The text was presenting the team, the the e-mail address, then some of the expectations, then what form of e-mail is expected. By switching the e-mail paragraph two paragraphs later and dropping the "Contact" sub-section, we can have a more natural flow that presents the team, then its expectation, then how to best contribute, then where to send. And more importantly, it increases the chances that reporters have read the prerequisites before finding the e-mail address. Signed-off-by: Willy Tarreau Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20250814192730.19252-2-w@1wt.eu Signed-off-by: Greg Kroah-Hartman --- Documentation/process/security-bugs.rst | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Documentation/process/security-bugs.rst b/Documentation/process/security-bugs.rst index 7dcc034d3df8ed..84657e7d2e5b4b 100644 --- a/Documentation/process/security-bugs.rst +++ b/Documentation/process/security-bugs.rst @@ -8,17 +8,6 @@ like to know when a security bug is found so that it can be fixed and disclosed as quickly as possible. Please report security bugs to the Linux kernel security team. -Contact -------- - -The Linux kernel security team can be contacted by email at -. This is a private list of security officers -who will help verify the bug report and develop and release a fix. -If you already have a fix, please include it with your report, as -that can speed up the process considerably. It is possible that the -security team will bring in extra help from area maintainers to -understand and fix the security vulnerability. - The security team and maintainers almost always require additional information beyond what was initially provided in a report and rely on active and efficient collaboration with the reporter to perform further @@ -36,6 +25,14 @@ information is helpful. Any exploit code is very helpful and will not be released without consent from the reporter unless it has already been made public. +The Linux kernel security team can be contacted by email at +. This is a private list of security officers +who will help verify the bug report and develop and release a fix. +If you already have a fix, please include it with your report, as +that can speed up the process considerably. It is possible that the +security team will bring in extra help from area maintainers to +understand and fix the security vulnerability. + Please send plain text emails without attachments where possible. It is much harder to have a context-quoted discussion about a complex issue if all the details are hidden away in attachments. Think of it like a From e5f48bfa2ae0806d5f51fb8061afc619a73599a7 Mon Sep 17 00:00:00 2001 From: Baihan Li Date: Wed, 13 Aug 2025 17:42:28 +0800 Subject: [PATCH 0240/1292] drm/hisilicon/hibmc: fix the i2c device resource leak when vdac init failed Currently the driver missed to clean the i2c adapter when vdac init failed. It may cause resource leak. Fixes: a0d078d06e516 ("drm/hisilicon: Features to support reading resolutions from EDID") Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250813094238.3722345-2-shiyongbang@huawei.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 1 + drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c | 5 +++++ drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 11 ++++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index 274feabe7df007..ca8502e2760c12 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -69,6 +69,7 @@ int hibmc_de_init(struct hibmc_drm_private *priv); int hibmc_vdac_init(struct hibmc_drm_private *priv); int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_vdac *connector); +void hibmc_ddc_del(struct hibmc_vdac *vdac); int hibmc_dp_init(struct hibmc_drm_private *priv); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c index 99b3b77b5445f6..44860011855eb6 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c @@ -95,3 +95,8 @@ int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_vdac *vdac) return i2c_bit_add_bus(&vdac->adapter); } + +void hibmc_ddc_del(struct hibmc_vdac *vdac) +{ + i2c_del_adapter(&vdac->adapter); +} diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index e8a527ede85438..841e81f47b6862 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -53,7 +53,7 @@ static void hibmc_connector_destroy(struct drm_connector *connector) { struct hibmc_vdac *vdac = to_hibmc_vdac(connector); - i2c_del_adapter(&vdac->adapter); + hibmc_ddc_del(vdac); drm_connector_cleanup(connector); } @@ -110,7 +110,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) ret = drmm_encoder_init(dev, encoder, NULL, DRM_MODE_ENCODER_DAC, NULL); if (ret) { drm_err(dev, "failed to init encoder: %d\n", ret); - return ret; + goto err; } drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs); @@ -121,7 +121,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) &vdac->adapter); if (ret) { drm_err(dev, "failed to init connector: %d\n", ret); - return ret; + goto err; } drm_connector_helper_add(connector, &hibmc_connector_helper_funcs); @@ -131,4 +131,9 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; return 0; + +err: + hibmc_ddc_del(vdac); + + return ret; } From 8bed4ec42a4e0dc8113172696ff076d1eb6d8bcb Mon Sep 17 00:00:00 2001 From: Baihan Li Date: Wed, 13 Aug 2025 17:42:30 +0800 Subject: [PATCH 0241/1292] drm/hisilicon/hibmc: fix irq_request()'s irq name variable is local The local variable is passed in request_irq (), and there will be use after free problem, which will make request_irq failed. Using the global irq name instead of it to fix. Fixes: b11bc1ae4658 ("drm/hisilicon/hibmc: Add MSI irq getting and requesting for HPD") Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250813094238.3722345-4-shiyongbang@huawei.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 768b97f9e74afe..4cdcc34070ee9c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -32,7 +32,7 @@ DEFINE_DRM_GEM_FOPS(hibmc_fops); -static const char *g_irqs_names_map[HIBMC_MAX_VECTORS] = { "vblank", "hpd" }; +static const char *g_irqs_names_map[HIBMC_MAX_VECTORS] = { "hibmc-vblank", "hibmc-hpd" }; static irqreturn_t hibmc_interrupt(int irq, void *arg) { @@ -277,7 +277,6 @@ static void hibmc_unload(struct drm_device *dev) static int hibmc_msi_init(struct drm_device *dev) { struct pci_dev *pdev = to_pci_dev(dev->dev); - char name[32] = {0}; int valid_irq_num; int irq; int ret; @@ -292,9 +291,6 @@ static int hibmc_msi_init(struct drm_device *dev) valid_irq_num = ret; for (int i = 0; i < valid_irq_num; i++) { - snprintf(name, ARRAY_SIZE(name) - 1, "%s-%s-%s", - dev->driver->name, pci_name(pdev), g_irqs_names_map[i]); - irq = pci_irq_vector(pdev, i); if (i) @@ -302,10 +298,10 @@ static int hibmc_msi_init(struct drm_device *dev) ret = devm_request_threaded_irq(&pdev->dev, irq, hibmc_dp_interrupt, hibmc_dp_hpd_isr, - IRQF_SHARED, name, dev); + IRQF_SHARED, g_irqs_names_map[i], dev); else ret = devm_request_irq(&pdev->dev, irq, hibmc_interrupt, - IRQF_SHARED, name, dev); + IRQF_SHARED, g_irqs_names_map[i], dev); if (ret) { drm_err(dev, "install irq failed: %d\n", ret); return ret; From 93a08f856fcc5aaeeecad01f71bef3088588216a Mon Sep 17 00:00:00 2001 From: Baihan Li Date: Wed, 13 Aug 2025 17:42:31 +0800 Subject: [PATCH 0242/1292] drm/hisilicon/hibmc: fix the hibmc loaded failed bug When hibmc loaded failed, the driver use hibmc_unload to free the resource, but the mutexes in mode.config are not init, which will access an NULL pointer. Just change goto statement to return, because hibnc_hw_init() doesn't need to free anything. Fixes: b3df5e65cc03 ("drm/hibmc: Drop drm_vblank_cleanup") Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250813094238.3722345-5-shiyongbang@huawei.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 4cdcc34070ee9c..ac552c339671a4 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -319,13 +319,13 @@ static int hibmc_load(struct drm_device *dev) ret = hibmc_hw_init(priv); if (ret) - goto err; + return ret; ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (ret) { drm_err(dev, "Error initializing VRAM MM; %d\n", ret); - goto err; + return ret; } ret = hibmc_kms_init(priv); From 9f98b429ba67d430b873e06bcfb90afa22888978 Mon Sep 17 00:00:00 2001 From: Baihan Li Date: Wed, 13 Aug 2025 17:42:32 +0800 Subject: [PATCH 0243/1292] drm/hisilicon/hibmc: fix rare monitors cannot display problem In some case, the dp link training success at 8.1Gbps, but the sink's maximum supported rate is less than 8.1G. So change the default 8.1Gbps link rate to the rate that reads from devices' capabilities. Fixes: 54063d86e036 ("drm/hisilicon/hibmc: add dp link moduel in hibmc drivers") Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250813094238.3722345-6-shiyongbang@huawei.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c index 74f7832ea53eae..0726cb5b736e60 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c @@ -325,6 +325,17 @@ static int hibmc_dp_link_downgrade_training_eq(struct hibmc_dp_dev *dp) return hibmc_dp_link_reduce_rate(dp); } +static void hibmc_dp_update_caps(struct hibmc_dp_dev *dp) +{ + dp->link.cap.link_rate = dp->dpcd[DP_MAX_LINK_RATE]; + if (dp->link.cap.link_rate > DP_LINK_BW_8_1 || !dp->link.cap.link_rate) + dp->link.cap.link_rate = DP_LINK_BW_8_1; + + dp->link.cap.lanes = dp->dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + if (dp->link.cap.lanes > HIBMC_DP_LANE_NUM_MAX) + dp->link.cap.lanes = HIBMC_DP_LANE_NUM_MAX; +} + int hibmc_dp_link_training(struct hibmc_dp_dev *dp) { struct hibmc_dp_link *link = &dp->link; @@ -334,8 +345,7 @@ int hibmc_dp_link_training(struct hibmc_dp_dev *dp) if (ret) drm_err(dp->dev, "dp aux read dpcd failed, ret: %d\n", ret); - dp->link.cap.link_rate = dp->dpcd[DP_MAX_LINK_RATE]; - dp->link.cap.lanes = 0x2; + hibmc_dp_update_caps(dp); ret = hibmc_dp_get_serdes_rate_cfg(dp); if (ret < 0) From 3271faf42d135bcf569c3ff6af55c21858eec212 Mon Sep 17 00:00:00 2001 From: Baihan Li Date: Wed, 13 Aug 2025 17:42:34 +0800 Subject: [PATCH 0244/1292] drm/hisilicon/hibmc: fix dp and vga cannot show together If VGA and DP connected together, there will be only one can get crtc. Add encoder possible_clones to support two connectors enable. Fixes: 3c7623fb5bb6 ("drm/hisilicon/hibmc: Enable this hot plug detect of irq feature") Signed-off-by: Baihan Li Signed-off-by: Yongbang Shi Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250813094238.3722345-8-shiyongbang@huawei.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index ac552c339671a4..289304500ab097 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -115,6 +115,8 @@ static const struct drm_mode_config_funcs hibmc_mode_funcs = { static int hibmc_kms_init(struct hibmc_drm_private *priv) { struct drm_device *dev = &priv->dev; + struct drm_encoder *encoder; + u32 clone_mask = 0; int ret; ret = drmm_mode_config_init(dev); @@ -154,6 +156,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv) return ret; } + drm_for_each_encoder(encoder, dev) + clone_mask |= drm_encoder_mask(encoder); + + drm_for_each_encoder(encoder, dev) + encoder->possible_clones = clone_mask; + return 0; } From bac7b996d42e458a94578f4227795a0d4deef6fa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 12 Aug 2025 18:45:46 +0200 Subject: [PATCH 0245/1292] smb: server: split ksmbd_rdma_stop_listening() out of ksmbd_rdma_destroy() We can't call destroy_workqueue(smb_direct_wq); before stop_sessions()! Otherwise already existing connections try to use smb_direct_wq as a NULL pointer. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers") Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/connection.c | 3 ++- fs/smb/server/transport_rdma.c | 5 ++++- fs/smb/server/transport_rdma.h | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c index 3f04a2977ba86c..67c4f73398dfee 100644 --- a/fs/smb/server/connection.c +++ b/fs/smb/server/connection.c @@ -504,7 +504,8 @@ void ksmbd_conn_transport_destroy(void) { mutex_lock(&init_lock); ksmbd_tcp_destroy(); - ksmbd_rdma_destroy(); + ksmbd_rdma_stop_listening(); stop_sessions(); + ksmbd_rdma_destroy(); mutex_unlock(&init_lock); } diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 8d366db5f60547..5466aa8c39b1cd 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -2194,7 +2194,7 @@ int ksmbd_rdma_init(void) return 0; } -void ksmbd_rdma_destroy(void) +void ksmbd_rdma_stop_listening(void) { if (!smb_direct_listener.cm_id) return; @@ -2203,7 +2203,10 @@ void ksmbd_rdma_destroy(void) rdma_destroy_id(smb_direct_listener.cm_id); smb_direct_listener.cm_id = NULL; +} +void ksmbd_rdma_destroy(void) +{ if (smb_direct_wq) { destroy_workqueue(smb_direct_wq); smb_direct_wq = NULL; diff --git a/fs/smb/server/transport_rdma.h b/fs/smb/server/transport_rdma.h index 77aee4e5c9dcd8..a2291b77488a15 100644 --- a/fs/smb/server/transport_rdma.h +++ b/fs/smb/server/transport_rdma.h @@ -54,13 +54,15 @@ struct smb_direct_data_transfer { #ifdef CONFIG_SMB_SERVER_SMBDIRECT int ksmbd_rdma_init(void); +void ksmbd_rdma_stop_listening(void); void ksmbd_rdma_destroy(void); bool ksmbd_rdma_capable_netdev(struct net_device *netdev); void init_smbd_max_io_size(unsigned int sz); unsigned int get_smbd_max_read_write_size(void); #else static inline int ksmbd_rdma_init(void) { return 0; } -static inline int ksmbd_rdma_destroy(void) { return 0; } +static inline void ksmbd_rdma_stop_listening(void) { } +static inline void ksmbd_rdma_destroy(void) { } static inline bool ksmbd_rdma_capable_netdev(struct net_device *netdev) { return false; } static inline void init_smbd_max_io_size(unsigned int sz) { } static inline unsigned int get_smbd_max_read_write_size(void) { return 0; } From c0d41112f1a5828c194b59cca953114bc3776ef2 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 17 Aug 2025 09:48:40 +0900 Subject: [PATCH 0246/1292] ksmbd: extend the connection limiting mechanism to support IPv6 Update the connection tracking logic to handle both IPv4 and IPv6 address families. Cc: stable@vger.kernel.org Fixes: e6bb91939740 ("ksmbd: limit repeated connections from clients with the same IP") Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/connection.h | 7 ++++++- fs/smb/server/transport_tcp.c | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h index 31dd1caac1e8a8..2aa8084bb59302 100644 --- a/fs/smb/server/connection.h +++ b/fs/smb/server/connection.h @@ -46,7 +46,12 @@ struct ksmbd_conn { struct mutex srv_mutex; int status; unsigned int cli_cap; - __be32 inet_addr; + union { + __be32 inet_addr; +#if IS_ENABLED(CONFIG_IPV6) + u8 inet6_addr[16]; +#endif + }; char *request_buf; struct ksmbd_transport *transport; struct nls_table *local_nls; diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index b1df02e321b00a..4337df97987da3 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -85,7 +85,14 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk) return NULL; } +#if IS_ENABLED(CONFIG_IPV6) + if (client_sk->sk->sk_family == AF_INET6) + memcpy(&conn->inet6_addr, &client_sk->sk->sk_v6_daddr, 16); + else + conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr; +#else conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr; +#endif conn->transport = KSMBD_TRANS(t); KSMBD_TRANS(t)->conn = conn; KSMBD_TRANS(t)->ops = &ksmbd_tcp_transport_ops; @@ -229,7 +236,6 @@ static int ksmbd_kthread_fn(void *p) { struct socket *client_sk = NULL; struct interface *iface = (struct interface *)p; - struct inet_sock *csk_inet; struct ksmbd_conn *conn; int ret; @@ -252,13 +258,27 @@ static int ksmbd_kthread_fn(void *p) /* * Limits repeated connections from clients with the same IP. */ - csk_inet = inet_sk(client_sk->sk); down_read(&conn_list_lock); list_for_each_entry(conn, &conn_list, conns_list) - if (csk_inet->inet_daddr == conn->inet_addr) { +#if IS_ENABLED(CONFIG_IPV6) + if (client_sk->sk->sk_family == AF_INET6) { + if (memcmp(&client_sk->sk->sk_v6_daddr, + &conn->inet6_addr, 16) == 0) { + ret = -EAGAIN; + break; + } + } else if (inet_sk(client_sk->sk)->inet_daddr == + conn->inet_addr) { + ret = -EAGAIN; + break; + } +#else + if (inet_sk(client_sk->sk)->inet_daddr == + conn->inet_addr) { ret = -EAGAIN; break; } +#endif up_read(&conn_list_lock); if (ret == -EAGAIN) continue; From 89bb430f621124af39bb31763c4a8b504c9651e2 Mon Sep 17 00:00:00 2001 From: Ziyan Xu Date: Sat, 16 Aug 2025 10:20:05 +0900 Subject: [PATCH 0247/1292] ksmbd: fix refcount leak causing resource not released When ksmbd_conn_releasing(opinfo->conn) returns true,the refcount was not decremented properly, causing a refcount leak that prevents the count from reaching zero and the memory from being released. Cc: stable@vger.kernel.org Signed-off-by: Ziyan Xu Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/oplock.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index d7a8a580d01362..a04d5702820d07 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -1102,8 +1102,10 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, if (!atomic_inc_not_zero(&opinfo->refcount)) continue; - if (ksmbd_conn_releasing(opinfo->conn)) + if (ksmbd_conn_releasing(opinfo->conn)) { + opinfo_put(opinfo); continue; + } oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL); opinfo_put(opinfo); @@ -1139,8 +1141,11 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) if (!atomic_inc_not_zero(&opinfo->refcount)) continue; - if (ksmbd_conn_releasing(opinfo->conn)) + if (ksmbd_conn_releasing(opinfo->conn)) { + opinfo_put(opinfo); continue; + } + oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL); opinfo_put(opinfo); } @@ -1343,8 +1348,10 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, if (!atomic_inc_not_zero(&brk_op->refcount)) continue; - if (ksmbd_conn_releasing(brk_op->conn)) + if (ksmbd_conn_releasing(brk_op->conn)) { + opinfo_put(brk_op); continue; + } if (brk_op->is_lease && (brk_op->o_lease->state & (~(SMB2_LEASE_READ_CACHING_LE | From f52d6aa98379842fc255d93282655566f2114e0c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 11 Aug 2025 11:01:48 +0300 Subject: [PATCH 0248/1292] drm/i915/lnl+/tc: Fix handling of an enabled/disconnected dp-alt sink The TypeC PHY HW readout during driver loading and system resume determines which TypeC mode the PHY is in (legacy/DP-alt/TBT-alt) and whether the PHY is connected, based on the PHY's Owned and Ready flags. For the PHY to be in DP-alt or legacy mode and for the PHY to be in the connected state in these modes, both the Owned (set by the BIOS/driver) and the Ready (set by the HW) flags should be set. On ICL-MTL the HW kept the PHY's Ready flag set after the driver connected the PHY by acquiring the PHY ownership (by setting the Owned flag), until the driver disconnected the PHY by releasing the PHY ownership (by clearing the Owned flag). On LNL+ this has changed, in that the HW clears the Ready flag as soon as the sink gets disconnected, even if the PHY ownership was acquired already and hence the PHY is being used by the display. When inheriting the HW state from BIOS for a PHY connected in DP-alt mode on which the sink got disconnected - i.e. in a case where the sink was connected while BIOS/GOP was running and so the sink got enabled connecting the PHY, but the user disconnected the sink by the time the driver loaded - the PHY Owned but not Ready state must be accounted for on LNL+ according to the above. Do that by assuming on LNL+ that the PHY is connected in DP-alt mode whenever the PHY Owned flag is set, regardless of the PHY Ready flag. This fixes a problem on LNL+, where the PHY TypeC mode / connected state was detected incorrectly for a DP-alt sink, which got connected and then disconnected by the user in the above way. v2: Rename tc_phy_in_legacy_or_dp_alt_mode() to tc_phy_owned_by_display(). (Luca, Jani) Cc: Jani Nikula Cc: stable@vger.kernel.org # v6.8+ Reported-by: Charlton Lin Tested-by: Khaled Almahallawy Reviewed-by: Mika Kahola Reviewed-by: Luca Coelho [Imre: Add one-liner function documentation for tc_phy_owned_by_display()] Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250811080152.906216-2-imre.deak@intel.com (cherry picked from commit 89f4b196ee4b056e0e8c179b247b29d4a71a4e7e) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_tc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 3bc57579fe53e8..8208539bfe66ef 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -1226,14 +1226,19 @@ static void tc_phy_get_hw_state(struct intel_tc_port *tc) tc->phy_ops->get_hw_state(tc); } -static bool tc_phy_is_ready_and_owned(struct intel_tc_port *tc, - bool phy_is_ready, bool phy_is_owned) +/* Is the PHY owned by display i.e. is it in legacy or DP-alt mode? */ +static bool tc_phy_owned_by_display(struct intel_tc_port *tc, + bool phy_is_ready, bool phy_is_owned) { struct intel_display *display = to_intel_display(tc->dig_port); - drm_WARN_ON(display->drm, phy_is_owned && !phy_is_ready); + if (DISPLAY_VER(display) < 20) { + drm_WARN_ON(display->drm, phy_is_owned && !phy_is_ready); - return phy_is_ready && phy_is_owned; + return phy_is_ready && phy_is_owned; + } else { + return phy_is_owned; + } } static bool tc_phy_is_connected(struct intel_tc_port *tc, @@ -1244,7 +1249,7 @@ static bool tc_phy_is_connected(struct intel_tc_port *tc, bool phy_is_owned = tc_phy_is_owned(tc); bool is_connected; - if (tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned)) + if (tc_phy_owned_by_display(tc, phy_is_ready, phy_is_owned)) is_connected = port_pll_type == ICL_PORT_DPLL_MG_PHY; else is_connected = port_pll_type == ICL_PORT_DPLL_DEFAULT; @@ -1352,7 +1357,7 @@ tc_phy_get_current_mode(struct intel_tc_port *tc) phy_is_ready = tc_phy_is_ready(tc); phy_is_owned = tc_phy_is_owned(tc); - if (!tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned)) { + if (!tc_phy_owned_by_display(tc, phy_is_ready, phy_is_owned)) { mode = get_tc_mode_in_phy_not_owned_state(tc, live_mode); } else { drm_WARN_ON(display->drm, live_mode == TC_PORT_TBT_ALT); From 5fd35236546abe780eaadb7561e09953719d4fc3 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 11 Aug 2025 11:01:49 +0300 Subject: [PATCH 0249/1292] drm/i915/icl+/tc: Cache the max lane count value The PHY's pin assignment value in the TCSS_DDI_STATUS register - as set by the HW/FW based on the connected DP-alt sink's TypeC/PD pin assignment negotiation - gets cleared by the HW/FW on LNL+ as soon as the sink gets disconnected, even if the PHY ownership got acquired already by the driver (and hence the PHY itself is still connected and used by the display). This is similar to how the PHY Ready flag gets cleared on LNL+ in the same register. To be able to query the max lane count value on LNL+ - which is based on the above pin assignment - at all times even after the sink gets disconnected, the max lane count must be determined and cached during the PHY's HW readout and connect sequences. Do that here, leaving the actual use of the cached value to a follow-up change. v2: Don't read out the pin configuration if the PHY is disconnected. Cc: stable@vger.kernel.org # v6.8+ Reported-by: Charlton Lin Tested-by: Khaled Almahallawy Reviewed-by: Mika Kahola Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250811080152.906216-3-imre.deak@intel.com (cherry picked from commit 3e32438fc406761f81b1928d210b3d2a5e7501a0) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_tc.c | 57 +++++++++++++++++++++---- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 8208539bfe66ef..34435c4fc280b5 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -66,6 +66,7 @@ struct intel_tc_port { enum tc_port_mode init_mode; enum phy_fia phy_fia; u8 phy_fia_idx; + u8 max_lane_count; }; static enum intel_display_power_domain @@ -365,12 +366,12 @@ static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) } } -int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) +static int get_max_lane_count(struct intel_tc_port *tc) { - struct intel_display *display = to_intel_display(dig_port); - struct intel_tc_port *tc = to_tc_port(dig_port); + struct intel_display *display = to_intel_display(tc->dig_port); + struct intel_digital_port *dig_port = tc->dig_port; - if (!intel_encoder_is_tc(&dig_port->base) || tc->mode != TC_PORT_DP_ALT) + if (tc->mode != TC_PORT_DP_ALT) return 4; assert_tc_cold_blocked(tc); @@ -384,6 +385,21 @@ int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) return intel_tc_port_get_max_lane_count(dig_port); } +static void read_pin_configuration(struct intel_tc_port *tc) +{ + tc->max_lane_count = get_max_lane_count(tc); +} + +int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) +{ + struct intel_tc_port *tc = to_tc_port(dig_port); + + if (!intel_encoder_is_tc(&dig_port->base)) + return 4; + + return get_max_lane_count(tc); +} + void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes) { @@ -596,9 +612,12 @@ static void icl_tc_phy_get_hw_state(struct intel_tc_port *tc) tc_cold_wref = __tc_cold_block(tc, &domain); tc->mode = tc_phy_get_current_mode(tc); - if (tc->mode != TC_PORT_DISCONNECTED) + if (tc->mode != TC_PORT_DISCONNECTED) { tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + } + __tc_cold_unblock(tc, domain, tc_cold_wref); } @@ -656,8 +675,11 @@ static bool icl_tc_phy_connect(struct intel_tc_port *tc, tc->lock_wakeref = tc_cold_block(tc); - if (tc->mode == TC_PORT_TBT_ALT) + if (tc->mode == TC_PORT_TBT_ALT) { + read_pin_configuration(tc); + return true; + } if ((!tc_phy_is_ready(tc) || !icl_tc_phy_take_ownership(tc, true)) && @@ -668,6 +690,7 @@ static bool icl_tc_phy_connect(struct intel_tc_port *tc, goto out_unblock_tc_cold; } + read_pin_configuration(tc); if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes)) goto out_release_phy; @@ -858,9 +881,12 @@ static void adlp_tc_phy_get_hw_state(struct intel_tc_port *tc) port_wakeref = intel_display_power_get(display, port_power_domain); tc->mode = tc_phy_get_current_mode(tc); - if (tc->mode != TC_PORT_DISCONNECTED) + if (tc->mode != TC_PORT_DISCONNECTED) { tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + } + intel_display_power_put(display, port_power_domain, port_wakeref); } @@ -873,6 +899,9 @@ static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes) if (tc->mode == TC_PORT_TBT_ALT) { tc->lock_wakeref = tc_cold_block(tc); + + read_pin_configuration(tc); + return true; } @@ -894,6 +923,8 @@ static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes) tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes)) goto out_unblock_tc_cold; @@ -1124,9 +1155,12 @@ static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc) tc_cold_wref = __tc_cold_block(tc, &domain); tc->mode = tc_phy_get_current_mode(tc); - if (tc->mode != TC_PORT_DISCONNECTED) + if (tc->mode != TC_PORT_DISCONNECTED) { tc->lock_wakeref = tc_cold_block(tc); + read_pin_configuration(tc); + } + drm_WARN_ON(display->drm, (tc->mode == TC_PORT_DP_ALT || tc->mode == TC_PORT_LEGACY) && !xelpdp_tc_phy_tcss_power_is_enabled(tc)); @@ -1138,14 +1172,19 @@ static bool xelpdp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes) { tc->lock_wakeref = tc_cold_block(tc); - if (tc->mode == TC_PORT_TBT_ALT) + if (tc->mode == TC_PORT_TBT_ALT) { + read_pin_configuration(tc); + return true; + } if (!xelpdp_tc_phy_enable_tcss_power(tc, true)) goto out_unblock_tccold; xelpdp_tc_phy_take_ownership(tc, true); + read_pin_configuration(tc); + if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes)) goto out_release_phy; From c87514a0bb0a64507412a2d98264060dc0c1562a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 11 Aug 2025 11:01:50 +0300 Subject: [PATCH 0250/1292] drm/i915/lnl+/tc: Fix max lane count HW readout On LNL+ for a disconnected sink the pin assignment value gets cleared by the HW/FW as soon as the sink gets disconnected, even if the PHY ownership got acquired already by the BIOS/driver (and hence the PHY itself is still connected and used by the display). During HW readout this can result in detecting the PHY's max lane count as 0 - matching the above cleared aka NONE pin assignment HW state. For a connected PHY the driver in general (outside of intel_tc.c) expects the max lane count value to be valid for the video mode enabled on the corresponding output (1, 2 or 4). Ensure this by setting the max lane count to 4 in this case. Note, that it doesn't matter if this lane count happened to be more than the max lane count with which the PHY got connected and enabled, since the only thing the driver can do with such an output - where the DP-alt sink is disconnected - is to disable the output. v2: Rebased on change reading out the pin configuration only if the PHY is connected. Cc: stable@vger.kernel.org # v6.8+ Reported-by: Charlton Lin Tested-by: Khaled Almahallawy Reviewed-by: Mika Kahola Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250811080152.906216-4-imre.deak@intel.com (cherry picked from commit 33cf70bc0fe760224f892bc1854a33665f27d482) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_tc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 34435c4fc280b5..3f9842040bb014 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -23,6 +23,7 @@ #include "intel_modeset_lock.h" #include "intel_tc.h" +#define DP_PIN_ASSIGNMENT_NONE 0x0 #define DP_PIN_ASSIGNMENT_C 0x3 #define DP_PIN_ASSIGNMENT_D 0x4 #define DP_PIN_ASSIGNMENT_E 0x5 @@ -308,6 +309,8 @@ static int lnl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) REG_FIELD_GET(TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK, val); switch (pin_assignment) { + case DP_PIN_ASSIGNMENT_NONE: + return 0; default: MISSING_CASE(pin_assignment); fallthrough; @@ -1159,6 +1162,12 @@ static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc) tc->lock_wakeref = tc_cold_block(tc); read_pin_configuration(tc); + /* + * Set a valid lane count value for a DP-alt sink which got + * disconnected. The driver can only disable the output on this PHY. + */ + if (tc->max_lane_count == 0) + tc->max_lane_count = 4; } drm_WARN_ON(display->drm, From c5c2b4b3841666be3a45346d0ffa96b4b143504e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 11 Aug 2025 11:01:51 +0300 Subject: [PATCH 0251/1292] drm/i915/lnl+/tc: Use the cached max lane count value Use the cached max lane count value on LNL+, to account for scenarios where this value is queried after the HW cleared the corresponding pin assignment value in the TCSS_DDI_STATUS register after the sink got disconnected. For consistency, follow-up changes will use the cached max lane count value on other platforms as well and will also cache the pin assignment value in a similar way. Cc: stable@vger.kernel.org # v6.8+ Reported-by: Charlton Lin Tested-by: Khaled Almahallawy Reviewed-by: Mika Kahola Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250811080152.906216-5-imre.deak@intel.com (cherry picked from commit afc4e84388079f4d5ba05271632b7a4d8d85165c) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_tc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 3f9842040bb014..6a2442a0649ee0 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -395,12 +395,16 @@ static void read_pin_configuration(struct intel_tc_port *tc) int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) { + struct intel_display *display = to_intel_display(dig_port); struct intel_tc_port *tc = to_tc_port(dig_port); if (!intel_encoder_is_tc(&dig_port->base)) return 4; - return get_max_lane_count(tc); + if (DISPLAY_VER(display) < 20) + return get_max_lane_count(tc); + + return tc->max_lane_count; } void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, From d7fa5754e83cd36c4327eb2d806064e598a72ff6 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 11 Aug 2025 11:01:52 +0300 Subject: [PATCH 0252/1292] drm/i915/icl+/tc: Convert AUX powered WARN to a debug message The BIOS can leave the AUX power well enabled on an output, even if this isn't required (on platforms where the AUX power is only needed for an AUX access). This was observed at least on PTL. To avoid the WARN which would be triggered by this during the HW readout, convert the WARN to a debug message. Cc: stable@vger.kernel.org # v6.8+ Reported-by: Charlton Lin Tested-by: Khaled Almahallawy Reviewed-by: Mika Kahola Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250811080152.906216-6-imre.deak@intel.com (cherry picked from commit 6cb52cba474b2bec1a3018d3dbf75292059a29a1) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_tc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 6a2442a0649ee0..668ef139391b4f 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -1498,11 +1498,11 @@ static void intel_tc_port_reset_mode(struct intel_tc_port *tc, intel_display_power_flush_work(display); if (!intel_tc_cold_requires_aux_pw(dig_port)) { enum intel_display_power_domain aux_domain; - bool aux_powered; aux_domain = intel_aux_power_domain(dig_port); - aux_powered = intel_display_power_is_enabled(display, aux_domain); - drm_WARN_ON(display->drm, aux_powered); + if (intel_display_power_is_enabled(display, aux_domain)) + drm_dbg_kms(display->drm, "Port %s: AUX unexpectedly powered\n", + tc->port_name); } tc_phy_disconnect(tc); From 6347dc7fb967521a77f9ff0774d25ef0cca4c6cd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 11 Aug 2025 10:18:07 -0400 Subject: [PATCH 0253/1292] media: rkvdec: Fix a NULL vs IS_ERR() bug in probe() The iommu_paging_domain_alloc() function doesn't return NULL on error it returns error pointers. Update the check and then set ->empty_domain to NULL because the rest of the driver assumes it can be NULL. Fixes: ff8c5622f9f7 ("media: rkvdec: Restore iommu addresses on errors") Signed-off-by: Dan Carpenter Tested-by: Detlev Casanova Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index d707088ec0dc1f..1b7f27e4d96116 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -1162,8 +1162,10 @@ static int rkvdec_probe(struct platform_device *pdev) if (iommu_get_domain_for_dev(&pdev->dev)) { rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev); - if (!rkvdec->empty_domain) + if (IS_ERR(rkvdec->empty_domain)) { + rkvdec->empty_domain = NULL; dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); + } } vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); From 0d58a72b66ec4c24128395e408348c2c84221605 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 30 Jul 2025 20:24:44 +0200 Subject: [PATCH 0254/1292] media: rkvdec: Fix an error handling path in rkvdec_probe() If an error occurs after a successful iommu_paging_domain_alloc() call, it should be undone by a corresponding iommu_domain_free() call, as already done in the remove function. In order to fix the issue, move the corresponding call at the end of the function, because it is safe to allocate 'empty_domain' later. Fixes: ff8c5622f9f7 ("media: rkvdec: Restore iommu addresses on errors") Signed-off-by: Christophe JAILLET Reviewed-by: Nicolas Dufresne Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- .../media/platform/rockchip/rkvdec/rkvdec.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 1b7f27e4d96116..35265e32120361 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -1159,15 +1159,6 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; } - if (iommu_get_domain_for_dev(&pdev->dev)) { - rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev); - - if (IS_ERR(rkvdec->empty_domain)) { - rkvdec->empty_domain = NULL; - dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); - } - } - vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); irq = platform_get_irq(pdev, 0); @@ -1190,6 +1181,15 @@ static int rkvdec_probe(struct platform_device *pdev) if (ret) goto err_disable_runtime_pm; + if (iommu_get_domain_for_dev(&pdev->dev)) { + rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev); + + if (IS_ERR(rkvdec->empty_domain)) { + rkvdec->empty_domain = NULL; + dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); + } + } + return 0; err_disable_runtime_pm: From da3fa08a89dc1cb33ed57d097239b9c7cd9e7a60 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 11 Aug 2025 11:00:19 -0400 Subject: [PATCH 0255/1292] media: rkvdec: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Reviewed-by: Nicolas Dufresne Reviewed-by: Heiko Stuebner Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 35265e32120361..d3b31f461194fa 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -765,7 +765,6 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx, { struct rkvdec_dev *rkvdec = ctx->dev; - pm_runtime_mark_last_busy(rkvdec->dev); pm_runtime_put_autosuspend(rkvdec->dev); rkvdec_job_finish_no_pm(ctx, result); } From a032fe30cf09b6723ab61a05aee057311b00f9e1 Mon Sep 17 00:00:00 2001 From: Dongcheng Yan Date: Fri, 25 Apr 2025 18:43:30 +0800 Subject: [PATCH 0256/1292] platform/x86: int3472: add hpd pin support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typically HDMI to MIPI CSI-2 bridges have a pin to signal image data is being received. On the host side this is wired to a GPIO for polling or interrupts. This includes the Lontium HDMI to MIPI CSI-2 bridges lt6911uxe and lt6911uxc. The GPIO "hpd" is used already by other HDMI to CSI-2 bridges, use it here as well. Signed-off-by: Dongcheng Yan Reviewed-by: Sakari Ailus Acked-by: Ilpo JƤrvinen Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Fixes: 20244cbafbd6 ("media: i2c: change lt6911uxe irq_gpio name to "hpd"") Cc: stable@vger.kernel.org Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/platform/x86/intel/int3472/discrete.c | 6 ++++++ include/linux/platform_data/x86/int3472.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 4c0aed6e626f6b..bdfb8a800c5489 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -193,6 +193,10 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 *con_id = "privacy-led"; *gpio_flags = GPIO_ACTIVE_HIGH; break; + case INT3472_GPIO_TYPE_HOTPLUG_DETECT: + *con_id = "hpd"; + *gpio_flags = GPIO_ACTIVE_HIGH; + break; case INT3472_GPIO_TYPE_POWER_ENABLE: *con_id = "avdd"; *gpio_flags = GPIO_ACTIVE_HIGH; @@ -223,6 +227,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 * 0x0b Power enable * 0x0c Clock enable * 0x0d Privacy LED + * 0x13 Hotplug detect * * There are some known platform specific quirks where that does not quite * hold up; for example where a pin with type 0x01 (Power down) is mapped to @@ -292,6 +297,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, switch (type) { case INT3472_GPIO_TYPE_RESET: case INT3472_GPIO_TYPE_POWERDOWN: + case INT3472_GPIO_TYPE_HOTPLUG_DETECT: ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, con_id, gpio_flags); if (ret) err_msg = "Failed to map GPIO pin to sensor\n"; diff --git a/include/linux/platform_data/x86/int3472.h b/include/linux/platform_data/x86/int3472.h index 78276a11c48d6c..1571e9157fa50b 100644 --- a/include/linux/platform_data/x86/int3472.h +++ b/include/linux/platform_data/x86/int3472.h @@ -27,6 +27,7 @@ #define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c #define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d #define INT3472_GPIO_TYPE_HANDSHAKE 0x12 +#define INT3472_GPIO_TYPE_HOTPLUG_DETECT 0x13 #define INT3472_PDEV_MAX_NAME_LEN 23 #define INT3472_MAX_SENSOR_GPIOS 3 From 6f6fbd9a0c5a75eee0618c1499cf73cc770b3f52 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 9 Jul 2025 22:53:48 +0300 Subject: [PATCH 0257/1292] media: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Reviewed-by: Laurent Pinchart Acked-by: Thierry Reding (tegra-vde/h264.c) Acked-by: Tommaso Merciai (alvium-csi2.c) Reviewed-by: Dikshita Agarwal (iris_hfi_queue.c) Reviewed-by: Sean Young Acked-by: Dave Stevenson (imx219.c) Acked-by: Benjamin Mugnier Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/alvium-csi2.c | 1 - drivers/media/i2c/ccs/ccs-core.c | 7 +------ drivers/media/i2c/dw9768.c | 1 - drivers/media/i2c/gc0308.c | 3 --- drivers/media/i2c/gc2145.c | 3 --- drivers/media/i2c/imx219.c | 2 -- drivers/media/i2c/imx283.c | 3 --- drivers/media/i2c/imx290.c | 3 --- drivers/media/i2c/imx296.c | 1 - drivers/media/i2c/imx415.c | 1 - drivers/media/i2c/mt9m114.c | 6 ------ drivers/media/i2c/ov4689.c | 3 --- drivers/media/i2c/ov5640.c | 4 ---- drivers/media/i2c/ov5645.c | 3 --- drivers/media/i2c/ov64a40.c | 7 +------ drivers/media/i2c/ov8858.c | 2 -- drivers/media/i2c/st-mipid02.c | 2 -- drivers/media/i2c/tc358746.c | 5 ----- drivers/media/i2c/thp7312.c | 4 ---- drivers/media/i2c/vd55g1.c | 4 ---- drivers/media/i2c/vd56g3.c | 4 ---- drivers/media/i2c/video-i2c.c | 4 ---- drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c | 4 ---- drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 5 ----- drivers/media/platform/nvidia/tegra-vde/h264.c | 2 -- drivers/media/platform/qcom/iris/iris_hfi_queue.c | 1 - drivers/media/platform/raspberrypi/pisp_be/pisp_be.c | 2 -- drivers/media/platform/verisilicon/hantro_drv.c | 1 - drivers/media/rc/gpio-ir-recv.c | 4 +--- 29 files changed, 3 insertions(+), 89 deletions(-) diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index 05b708bd0a641c..1f088acecf367b 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -1841,7 +1841,6 @@ static int alvium_s_stream(struct v4l2_subdev *sd, int enable) } else { alvium_set_stream_mipi(alvium, enable); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 487bcabb4a199b..1c889c878abd3a 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -787,10 +787,8 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) rval = -EINVAL; } - if (pm_status > 0) { - pm_runtime_mark_last_busy(&client->dev); + if (pm_status > 0) pm_runtime_put_autosuspend(&client->dev); - } return rval; } @@ -1914,7 +1912,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) if (!enable) { ccs_stop_streaming(sensor); sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; @@ -1929,7 +1926,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) rval = ccs_start_streaming(sensor); if (rval < 0) { sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } @@ -2677,7 +2673,6 @@ nvm_show(struct device *dev, struct device_attribute *attr, char *buf) return -ENODEV; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); /* diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index 3a4d100b9199f3..d434721ba8edeb 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -374,7 +374,6 @@ static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_autosuspend(sd->dev); return 0; diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c index 069f42785b3c50..cbcda0e18ff10b 100644 --- a/drivers/media/i2c/gc0308.c +++ b/drivers/media/i2c/gc0308.c @@ -974,7 +974,6 @@ static int gc0308_s_ctrl(struct v4l2_ctrl *ctrl) if (ret) dev_err(gc0308->dev, "failed to set control: %d\n", ret); - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return ret; @@ -1157,14 +1156,12 @@ static int gc0308_start_stream(struct gc0308 *gc0308) return 0; disable_pm: - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return ret; } static int gc0308_stop_stream(struct gc0308 *gc0308) { - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return 0; } diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index ba02161d46e723..559a851669aaf5 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -963,7 +963,6 @@ static int gc2145_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -985,7 +984,6 @@ static int gc2145_disable_streams(struct v4l2_subdev *sd, if (ret) dev_err(&client->dev, "%s failed to write regs\n", __func__); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -1193,7 +1191,6 @@ static int gc2145_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 3b4f6854334227..3faf48f34af4d1 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -771,7 +771,6 @@ static int imx219_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -793,7 +792,6 @@ static int imx219_disable_streams(struct v4l2_subdev *sd, __v4l2_ctrl_grab(imx219->vflip, false); __v4l2_ctrl_grab(imx219->hflip, false); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c index da618c8cbadc3b..67e8bb432d1095 100644 --- a/drivers/media/i2c/imx283.c +++ b/drivers/media/i2c/imx283.c @@ -1143,7 +1143,6 @@ static int imx283_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return ret; @@ -1163,7 +1162,6 @@ static int imx283_disable_streams(struct v4l2_subdev *sd, if (ret) dev_err(imx283->dev, "Failed to stop stream\n"); - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return ret; @@ -1558,7 +1556,6 @@ static int imx283_probe(struct i2c_client *client) * Decrease the PM usage count. The device will get suspended after the * autosuspend delay, turning the power off. */ - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return 0; diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 4f3f386c53534a..ec172556612eea 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -869,7 +869,6 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); return ret; @@ -1099,7 +1098,6 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable) } } else { imx290_stop_streaming(imx290); - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); } @@ -1294,7 +1292,6 @@ static int imx290_subdev_init(struct imx290 *imx290) * will already be prevented even before the delay. */ v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); imx290->sd.internal_ops = &imx290_internal_ops; diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index f3bec16b527c44..61116f4e3f7614 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -604,7 +604,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { ret = imx296_stream_off(sensor); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); goto unlock; diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 278e743646ea15..276bf4d6f39d1c 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -952,7 +952,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { ret = imx415_stream_off(sensor); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); goto unlock; diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index 3f540ca40f3c8d..aa3fd6c6c76c80 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -974,7 +974,6 @@ static int mt9m114_start_streaming(struct mt9m114 *sensor, return 0; error: - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -988,7 +987,6 @@ static int mt9m114_stop_streaming(struct mt9m114 *sensor) ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1046,7 +1044,6 @@ static int mt9m114_pa_g_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1113,7 +1110,6 @@ static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1565,7 +1561,6 @@ static int mt9m114_ifp_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -2472,7 +2467,6 @@ static int mt9m114_probe(struct i2c_client *client) * Decrease the PM usage count. The device will get suspended after the * autosuspend delay, turning the power off. */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c index 1c3a449f935462..7d740ad3926f97 100644 --- a/drivers/media/i2c/ov4689.c +++ b/drivers/media/i2c/ov4689.c @@ -497,7 +497,6 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int on) } else { cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE, OV4689_MODE_SW_STANDBY, NULL); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } @@ -702,7 +701,6 @@ static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -999,7 +997,6 @@ static int ov4689_probe(struct i2c_client *client) goto err_clean_subdev_pm; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 0dae0438aa8085..84198613381d60 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3341,7 +3341,6 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return 0; @@ -3417,7 +3416,6 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return ret; @@ -3754,7 +3752,6 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) mutex_unlock(&sensor->lock); if (!enable || ret) { - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); } @@ -3965,7 +3962,6 @@ static int ov5640_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 004d0ee5c3f576..58c846a4437652 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -808,7 +808,6 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); return ret; @@ -979,7 +978,6 @@ static int ov5645_disable_streams(struct v4l2_subdev *sd, OV5645_SYSTEM_CTRL0_STOP); rpm_put: - pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); return ret; @@ -1196,7 +1194,6 @@ static int ov5645_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index a5da4fe47e0b09..2031cbd05c2697 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -2990,7 +2990,6 @@ static int ov64a40_start_streaming(struct ov64a40 *ov64a40, return 0; error_power_off: - pm_runtime_mark_last_busy(ov64a40->dev); pm_runtime_put_autosuspend(ov64a40->dev); return ret; @@ -3000,7 +2999,6 @@ static int ov64a40_stop_streaming(struct ov64a40 *ov64a40, struct v4l2_subdev_state *state) { cci_update_bits(ov64a40->cci, OV64A40_REG_SMIA, BIT(0), 0, NULL); - pm_runtime_mark_last_busy(ov64a40->dev); pm_runtime_put_autosuspend(ov64a40->dev); __v4l2_ctrl_grab(ov64a40->link_freq, false); @@ -3329,10 +3327,8 @@ static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl) break; } - if (pm_status > 0) { - pm_runtime_mark_last_busy(ov64a40->dev); + if (pm_status > 0) pm_runtime_put_autosuspend(ov64a40->dev); - } return ret; } @@ -3622,7 +3618,6 @@ static int ov64a40_probe(struct i2c_client *client) goto error_subdev_cleanup; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 95f9ae7948463e..6b7193eaea1f2a 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -1391,7 +1391,6 @@ static int ov8858_s_stream(struct v4l2_subdev *sd, int on) } } else { ov8858_stop_stream(ov8858); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } @@ -1945,7 +1944,6 @@ static int ov8858_probe(struct i2c_client *client) goto err_power_off; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index f4568e87f0187d..41ae25b0911f02 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -465,7 +465,6 @@ static int mipid02_disable_streams(struct v4l2_subdev *sd, if (ret) goto error; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); error: @@ -542,7 +541,6 @@ static int mipid02_enable_streams(struct v4l2_subdev *sd, cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, 0, &ret); cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index 143aa1359aba51..bcfc274cf89177 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -816,7 +816,6 @@ static int tc358746_s_stream(struct v4l2_subdev *sd, int enable) return 0; err_out: - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return err; @@ -838,7 +837,6 @@ static int tc358746_s_stream(struct v4l2_subdev *sd, int enable) if (err) return err; - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return v4l2_subdev_call(src, video, s_stream, 0); @@ -1016,7 +1014,6 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) err = tc358746_read(tc358746, reg->reg, &val); reg->val = val; - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return err; @@ -1032,7 +1029,6 @@ tc358746_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) tc358746_write(tc358746, (u32)reg->reg, (u32)reg->val); - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return 0; @@ -1395,7 +1391,6 @@ static int tc358746_init_hw(struct tc358746 *tc358746) } err = tc358746_read(tc358746, CHIPID_REG, &val); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); if (err) return -ENODEV; diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c index 8852c56431fe3f..775cfba188d81d 100644 --- a/drivers/media/i2c/thp7312.c +++ b/drivers/media/i2c/thp7312.c @@ -808,7 +808,6 @@ static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { thp7312_stream_enable(thp7312, false); - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); v4l2_subdev_unlock_state(sd_state); @@ -839,7 +838,6 @@ static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) goto finish_unlock; finish_pm: - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); finish_unlock: v4l2_subdev_unlock_state(sd_state); @@ -1147,7 +1145,6 @@ static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); return ret; @@ -2183,7 +2180,6 @@ static int thp7312_probe(struct i2c_client *client) * Decrease the PM usage count. The device will get suspended after the * autosuspend delay, turning the power off. */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); dev_info(dev, "THP7312 firmware version %02u.%02u\n", diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c index c0754fd03b1d5e..7c39183dd44bfe 100644 --- a/drivers/media/i2c/vd55g1.c +++ b/drivers/media/i2c/vd55g1.c @@ -1104,7 +1104,6 @@ static int vd55g1_disable_streams(struct v4l2_subdev *sd, vd55g1_grab_ctrls(sensor, false); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1338,7 +1337,6 @@ static int vd55g1_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1433,7 +1431,6 @@ static int vd55g1_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1895,7 +1892,6 @@ static int vd55g1_probe(struct i2c_client *client) pm_runtime_enable(dev); pm_runtime_set_autosuspend_delay(dev, 4000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); ret = vd55g1_subdev_init(sensor); diff --git a/drivers/media/i2c/vd56g3.c b/drivers/media/i2c/vd56g3.c index 5d951ad0b478fa..d66e21ba4498fb 100644 --- a/drivers/media/i2c/vd56g3.c +++ b/drivers/media/i2c/vd56g3.c @@ -493,7 +493,6 @@ static int vd56g3_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -577,7 +576,6 @@ static int vd56g3_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1021,7 +1019,6 @@ static int vd56g3_disable_streams(struct v4l2_subdev *sd, __v4l2_ctrl_grab(sensor->vflip_ctrl, false); __v4l2_ctrl_grab(sensor->patgen_ctrl, false); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1527,7 +1524,6 @@ static int vd56g3_probe(struct i2c_client *client) } /* Sensor could now be powered off (after the autosuspend delay) */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); dev_dbg(dev, "Successfully probe %s sensor\n", diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 0dd991d70d5380..1eee2d4f5b40ec 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -288,7 +288,6 @@ static int amg88xx_read(struct device *dev, enum hwmon_sensor_types type, return tmp; tmp = regmap_bulk_read(data->regmap, AMG88XX_REG_TTHL, &buf, 2); - pm_runtime_mark_last_busy(regmap_get_device(data->regmap)); pm_runtime_put_autosuspend(regmap_get_device(data->regmap)); if (tmp) return tmp; @@ -527,7 +526,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) return 0; error_rpm_put: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); error_del_list: video_i2c_del_list(vq, VB2_BUF_STATE_QUEUED); @@ -544,7 +542,6 @@ static void stop_streaming(struct vb2_queue *vq) kthread_stop(data->kthread_vid_cap); data->kthread_vid_cap = NULL; - pm_runtime_mark_last_busy(regmap_get_device(data->regmap)); pm_runtime_put_autosuspend(regmap_get_device(data->regmap)); video_i2c_del_list(vq, VB2_BUF_STATE_ERROR); @@ -853,7 +850,6 @@ static int video_i2c_probe(struct i2c_client *client) if (ret < 0) goto error_pm_disable; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index fd71f0c43ac37a..a9ce032cc5a223 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -451,7 +451,6 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst) if (q_status.report_queue_count == 0 && (q_status.instance_queue_count == 0 || dec_info.sequence_changed)) { dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } @@ -1364,7 +1363,6 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count } } - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); return ret; @@ -1498,7 +1496,6 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) else streamoff_capture(q); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); } @@ -1662,7 +1659,6 @@ static void wave5_vpu_dec_device_run(void *priv) finish_job_and_return: dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index 1e5fc5f8b856c5..35913a7de8348d 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -1391,12 +1391,10 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count if (ret) goto return_buffers; - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); return 0; return_buffers: wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); return ret; } @@ -1465,7 +1463,6 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) else streamoff_capture(inst, q); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); } @@ -1520,7 +1517,6 @@ static void wave5_vpu_enc_device_run(void *priv) break; } dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); return; default: @@ -1529,7 +1525,6 @@ static void wave5_vpu_enc_device_run(void *priv) break; } dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c index 0e56a4331b0d70..45f8f69048679f 100644 --- a/drivers/media/platform/nvidia/tegra-vde/h264.c +++ b/drivers/media/platform/nvidia/tegra-vde/h264.c @@ -585,7 +585,6 @@ static int tegra_vde_decode_begin(struct tegra_vde *vde, return 0; put_runtime_pm: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); unlock: @@ -612,7 +611,6 @@ static void tegra_vde_decode_abort(struct tegra_vde *vde) if (err) dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); mutex_unlock(&vde->lock); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/platform/qcom/iris/iris_hfi_queue.c index 221dcd09e1e109..b3ed06297953b9 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c @@ -142,7 +142,6 @@ int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size) } mutex_unlock(&core->lock); - pm_runtime_mark_last_busy(core->dev); pm_runtime_put_autosuspend(core->dev); return 0; diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c index b30891718d8df9..d60d92d2ffa1c8 100644 --- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c @@ -950,7 +950,6 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q) kfree(job); } - pm_runtime_mark_last_busy(pispbe->dev); pm_runtime_put_autosuspend(pispbe->dev); dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n", @@ -1742,7 +1741,6 @@ static int pispbe_probe(struct platform_device *pdev) if (ret) goto disable_devs_err; - pm_runtime_mark_last_busy(pispbe->dev); pm_runtime_put_autosuspend(pispbe->dev); return 0; diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 8542238e0fb1d2..fa972effd4a2cb 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -89,7 +89,6 @@ static void hantro_job_finish(struct hantro_dev *vpu, struct hantro_ctx *ctx, enum vb2_buffer_state result) { - pm_runtime_mark_last_busy(vpu->dev); pm_runtime_put_autosuspend(vpu->dev); clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index bf6d8fa983bfb4..a6418ef782bc2a 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -48,10 +48,8 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) if (val >= 0) ir_raw_event_store_edge(gpio_dev->rcdev, val == 1); - if (pmdev) { - pm_runtime_mark_last_busy(pmdev); + if (pmdev) pm_runtime_put_autosuspend(pmdev); - } return IRQ_HANDLED; } From bd7c2312128e31d056d30d34d60503de056e15f0 Mon Sep 17 00:00:00 2001 From: Alexey Gladkov Date: Thu, 14 Aug 2025 15:07:13 +0200 Subject: [PATCH 0258/1292] pinctrl: meson: Fix typo in device table macro The typo when using the MODULE_DEVICE_TABLE macro was not noticeable because the macro was defined only if the module was built as a separate module. Cc: Xianwei Zhao Cc: Linus Walleij Cc: Neil Armstrong Cc: Kevin Hilman Cc: linux-amlogic@lists.infradead.org Cc: linux-gpio@vger.kernel.org Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507220009.8HKbNP16-lkp@intel.com/ Signed-off-by: Alexey Gladkov Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/e548b7761302defec15aa2098172eabb1ce1ad4a.1755170493.git.legion@kernel.org Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c index e34e984c2b38a8..6132710aff6881 100644 --- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c +++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c @@ -1093,7 +1093,7 @@ static const struct of_device_id aml_pctl_of_match[] = { { .compatible = "amlogic,pinctrl-s6", .data = &s6_priv_data, }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, aml_pctl_dt_match); +MODULE_DEVICE_TABLE(of, aml_pctl_of_match); static struct platform_driver aml_pctl_driver = { .driver = { From c0ed3c2edc7692c6b8af7578b41012694dc8c671 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Sat, 16 Aug 2025 12:27:41 +0800 Subject: [PATCH 0259/1292] ALSA: hda/tas2781: Add name prefix tas2781 for tas2781's dvc_tlv and amp_vol_tlv With some new devices adding into the driver, dvc_tlv and amp_vol_tlv will cause confusion for customers on which devices they support. Fixes: 5be27f1e3ec9 ("ALSA: hda/tas2781: Add tas2781 HDA driver") Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20250816042741.1659-1-shenghao-ding@ti.com Signed-off-by: Takashi Iwai --- include/sound/tas2781-tlv.h | 6 +++--- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 2 +- sound/hda/codecs/side-codecs/tas2781_hda_spi.c | 6 ++++-- sound/soc/codecs/tas2781-i2c.c | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/sound/tas2781-tlv.h b/include/sound/tas2781-tlv.h index ef9b9f19d21205..273224df9282da 100644 --- a/include/sound/tas2781-tlv.h +++ b/include/sound/tas2781-tlv.h @@ -2,7 +2,7 @@ // // ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier // -// Copyright (C) 2022 - 2024 Texas Instruments Incorporated +// Copyright (C) 2022 - 2025 Texas Instruments Incorporated // https://www.ti.com // // The TAS2781 driver implements a flexible and configurable @@ -15,7 +15,7 @@ #ifndef __TAS2781_TLV_H__ #define __TAS2781_TLV_H__ -static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 50, 0); -static const __maybe_unused DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0); +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2781_dvc_tlv, -10000, 50, 0); +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2781_amp_tlv, 1100, 50, 0); #endif diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index 06c7bc2b9e9d59..b91fff3fde97fb 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -267,7 +267,7 @@ static const struct snd_kcontrol_new tas2770_snd_controls[] = { static const struct snd_kcontrol_new tas2781_snd_controls[] = { ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, - tas2781_amp_putvol, amp_vol_tlv), + tas2781_amp_putvol, tas2781_amp_tlv), ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, tas2781_force_fwload_get, tas2781_force_fwload_put), }; diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c index 09a5d0f131b2fd..b9a55672bf15d5 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c @@ -494,9 +494,11 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new tas2781_snd_ctls[] = { ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_AMP_LEVEL, 1, 0, 20, 0, - tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv), + tas2781_amp_getvol, tas2781_amp_putvol, + tas2781_amp_tlv), ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_DVC_LVL, 0, 0, 200, 1, - tas2781_digital_getvol, tas2781_digital_putvol, dvc_tlv), + tas2781_digital_getvol, tas2781_digital_putvol, + tas2781_dvc_tlv), ACARD_SINGLE_BOOL_EXT(NULL, 0, tas2781_force_fwload_get, tas2781_force_fwload_put), }; diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 676130f4cf3ecf..0e09d794516fc7 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -910,10 +910,10 @@ static const struct snd_kcontrol_new tasdevice_cali_controls[] = { static const struct snd_kcontrol_new tas2781_snd_controls[] = { SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, - tas2781_amp_putvol, amp_vol_tlv), + tas2781_amp_putvol, tas2781_amp_tlv), SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2781_DVC_LVL, 0, 0, 200, 1, tas2781_digital_getvol, - tas2781_digital_putvol, dvc_tlv), + tas2781_digital_putvol, tas2781_dvc_tlv), }; static const struct snd_kcontrol_new tas2781_cali_controls[] = { From dec8b38be4b35cae5f7fa086daf2631e2cfa09c1 Mon Sep 17 00:00:00 2001 From: Victor Shih Date: Thu, 31 Jul 2025 14:57:50 +0800 Subject: [PATCH 0260/1292] mmc: sdhci-pci-gli: Add a new function to simplify the code In preparation to fix replay timer timeout, add sdhci_gli_mask_replay_timer_timeout() function to simplify some of the code, allowing it to be re-used. Signed-off-by: Victor Shih Fixes: 1ae1d2d6e555 ("mmc: sdhci-pci-gli: Add Genesys Logic GL9763E support") Cc: stable@vger.kernel.org Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20250731065752.450231-2-victorshihgli@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-gli.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 4c2ae71770f782..f678c91f8d3eef 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -287,6 +287,20 @@ #define GLI_MAX_TUNING_LOOP 40 /* Genesys Logic chipset */ +static void sdhci_gli_mask_replay_timer_timeout(struct pci_dev *pdev) +{ + int aer; + u32 value; + + /* mask the replay timer timeout of AER */ + aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + if (aer) { + pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value); + value |= PCI_ERR_COR_REP_TIMER; + pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value); + } +} + static inline void gl9750_wt_on(struct sdhci_host *host) { u32 wt_value; @@ -607,7 +621,6 @@ static void gl9750_hw_setting(struct sdhci_host *host) { struct sdhci_pci_slot *slot = sdhci_priv(host); struct pci_dev *pdev; - int aer; u32 value; pdev = slot->chip->pdev; @@ -626,12 +639,7 @@ static void gl9750_hw_setting(struct sdhci_host *host) pci_set_power_state(pdev, PCI_D0); /* mask the replay timer timeout of AER */ - aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); - if (aer) { - pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value); - value |= PCI_ERR_COR_REP_TIMER; - pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value); - } + sdhci_gli_mask_replay_timer_timeout(pdev); gl9750_wt_off(host); } @@ -806,7 +814,6 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) static void gl9755_hw_setting(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; - int aer; u32 value; gl9755_wt_on(pdev); @@ -841,12 +848,7 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot) pci_set_power_state(pdev, PCI_D0); /* mask the replay timer timeout of AER */ - aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); - if (aer) { - pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value); - value |= PCI_ERR_COR_REP_TIMER; - pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value); - } + sdhci_gli_mask_replay_timer_timeout(pdev); gl9755_wt_off(pdev); } From 293ed0f5f34e1e9df888456af4b0a021f57b5f54 Mon Sep 17 00:00:00 2001 From: Victor Shih Date: Thu, 31 Jul 2025 14:57:51 +0800 Subject: [PATCH 0261/1292] mmc: sdhci-pci-gli: GL9763e: Rename the gli_set_gl9763e() for consistency In preparation to fix replay timer timeout, rename the gli_set_gl9763e() to gl9763e_hw_setting() for consistency. Signed-off-by: Victor Shih Fixes: 1ae1d2d6e555 ("mmc: sdhci-pci-gli: Add Genesys Logic GL9763E support") Cc: stable@vger.kernel.org Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20250731065752.450231-3-victorshihgli@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-gli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index f678c91f8d3eef..436f0460222f98 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -1753,7 +1753,7 @@ static int gl9763e_add_host(struct sdhci_pci_slot *slot) return ret; } -static void gli_set_gl9763e(struct sdhci_pci_slot *slot) +static void gl9763e_hw_setting(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; u32 value; @@ -1925,7 +1925,7 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) gli_pcie_enable_msi(slot); host->mmc_host_ops.hs400_enhanced_strobe = gl9763e_hs400_enhanced_strobe; - gli_set_gl9763e(slot); + gl9763e_hw_setting(slot); sdhci_enable_v4_mode(host); return 0; From 340be332e420ed37d15d4169a1b4174e912ad6cb Mon Sep 17 00:00:00 2001 From: Victor Shih Date: Thu, 31 Jul 2025 14:57:52 +0800 Subject: [PATCH 0262/1292] mmc: sdhci-pci-gli: GL9763e: Mask the replay timer timeout of AER Due to a flaw in the hardware design, the GL9763e replay timer frequently times out when ASPM is enabled. As a result, the warning messages will often appear in the system log when the system accesses the GL9763e PCI config. Therefore, the replay timer timeout must be masked. Signed-off-by: Victor Shih Fixes: 1ae1d2d6e555 ("mmc: sdhci-pci-gli: Add Genesys Logic GL9763E support") Cc: stable@vger.kernel.org Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20250731065752.450231-4-victorshihgli@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-gli.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 436f0460222f98..3a1de477e9af8d 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -1782,6 +1782,9 @@ static void gl9763e_hw_setting(struct sdhci_pci_slot *slot) value |= FIELD_PREP(GLI_9763E_HS400_RXDLY, GLI_9763E_HS400_RXDLY_5); pci_write_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, value); + /* mask the replay timer timeout of AER */ + sdhci_gli_mask_replay_timer_timeout(pdev); + pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); value &= ~GLI_9763E_VHS_REV; value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); From e251709aaddb3ee1e8ac1ed5e361a608a1cc92de Mon Sep 17 00:00:00 2001 From: Sai Krishna Potthuri Date: Wed, 30 Jul 2025 11:35:43 +0530 Subject: [PATCH 0263/1292] mmc: sdhci-of-arasan: Ensure CD logic stabilization before power-up During SD suspend/resume without a full card rescan (when using non-removable SD cards for rootfs), the SD card initialization may fail after resume. This occurs because, after a host controller reset, the card detect logic may take time to stabilize due to debounce logic. Without waiting for stabilization, the host may attempt powering up the card prematurely, leading to command timeouts during resume flow. Add sdhci_arasan_set_power_and_bus_voltage() to wait for the card detect stable bit before power up the card. Since the stabilization time is not fixed, a maximum timeout of one second is used to ensure sufficient wait time for the card detect signal to stabilize. Signed-off-by: Sai Krishna Potthuri Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250730060543.1735971-1-sai.krishna.potthuri@amd.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 33 ++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 42878474e56e52..60dbc815e5019f 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -99,6 +99,9 @@ #define HIWORD_UPDATE(val, mask, shift) \ ((val) << (shift) | (mask) << ((shift) + 16)) +#define CD_STABLE_TIMEOUT_US 1000000 +#define CD_STABLE_MAX_SLEEP_US 10 + /** * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map * @@ -206,12 +209,15 @@ struct sdhci_arasan_data { * 19MHz instead */ #define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2) +/* Enable CD stable check before power-up */ +#define SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE BIT(3) }; struct sdhci_arasan_of_data { const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; const struct sdhci_pltfm_data *pdata; const struct sdhci_arasan_clk_ops *clk_ops; + u32 quirks; }; static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { @@ -514,6 +520,24 @@ static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, return -EINVAL; } +static void sdhci_arasan_set_power_and_bus_voltage(struct sdhci_host *host, unsigned char mode, + unsigned short vdd) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + u32 reg; + + /* + * Ensure that the card detect logic has stabilized before powering up, this is + * necessary after a host controller reset. + */ + if (mode == MMC_POWER_UP && sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE) + read_poll_timeout(sdhci_readl, reg, reg & SDHCI_CD_STABLE, CD_STABLE_MAX_SLEEP_US, + CD_STABLE_TIMEOUT_US, false, host, SDHCI_PRESENT_STATE); + + sdhci_set_power_and_bus_voltage(host, mode, vdd); +} + static const struct sdhci_ops sdhci_arasan_ops = { .set_clock = sdhci_arasan_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, @@ -521,7 +545,7 @@ static const struct sdhci_ops sdhci_arasan_ops = { .set_bus_width = sdhci_set_bus_width, .reset = sdhci_arasan_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, - .set_power = sdhci_set_power_and_bus_voltage, + .set_power = sdhci_arasan_set_power_and_bus_voltage, .hw_reset = sdhci_arasan_hw_reset, }; @@ -570,7 +594,7 @@ static const struct sdhci_ops sdhci_arasan_cqe_ops = { .set_bus_width = sdhci_set_bus_width, .reset = sdhci_arasan_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, - .set_power = sdhci_set_power_and_bus_voltage, + .set_power = sdhci_arasan_set_power_and_bus_voltage, .irq = sdhci_arasan_cqhci_irq, }; @@ -1447,6 +1471,7 @@ static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = { static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = { .pdata = &sdhci_arasan_zynqmp_pdata, .clk_ops = &zynqmp_clk_ops, + .quirks = SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE, }; static const struct sdhci_arasan_clk_ops versal_clk_ops = { @@ -1457,6 +1482,7 @@ static const struct sdhci_arasan_clk_ops versal_clk_ops = { static struct sdhci_arasan_of_data sdhci_arasan_versal_data = { .pdata = &sdhci_arasan_zynqmp_pdata, .clk_ops = &versal_clk_ops, + .quirks = SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE, }; static const struct sdhci_arasan_clk_ops versal_net_clk_ops = { @@ -1467,6 +1493,7 @@ static const struct sdhci_arasan_clk_ops versal_net_clk_ops = { static struct sdhci_arasan_of_data sdhci_arasan_versal_net_data = { .pdata = &sdhci_arasan_versal_net_pdata, .clk_ops = &versal_net_clk_ops, + .quirks = SDHCI_ARASAN_QUIRK_ENSURE_CD_STABLE, }; static struct sdhci_arasan_of_data intel_keembay_emmc_data = { @@ -1937,6 +1964,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1")) sdhci_arasan_update_clockmultiplier(host, 0x0); + sdhci_arasan->quirks |= data->quirks; + if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") || of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { From 99d7ab8db9d8230b243f5ed20ba0229e54cc0dfa Mon Sep 17 00:00:00 2001 From: Jiayi Li Date: Mon, 4 Aug 2025 09:36:04 +0800 Subject: [PATCH 0264/1292] memstick: Fix deadlock by moving removing flag earlier The existing memstick core patch: commit 62c59a8786e6 ("memstick: Skip allocating card when removing host") sets host->removing in memstick_remove_host(),but still exists a critical time window where memstick_check can run after host->eject is set but before removing is set. In the rtsx_usb_ms driver, the problematic sequence is: rtsx_usb_ms_drv_remove: memstick_check: host->eject = true cancel_work_sync(handle_req) if(!host->removing) ... memstick_alloc_card() memstick_set_rw_addr() memstick_new_req() rtsx_usb_ms_request() if(!host->eject) skip schedule_work wait_for_completion() memstick_remove_host: [blocks indefinitely] host->removing = true flush_workqueue() [block] 1. rtsx_usb_ms_drv_remove sets host->eject = true 2. cancel_work_sync(&host->handle_req) runs 3. memstick_check work may be executed here <-- danger window 4. memstick_remove_host sets removing = 1 During this window (step 3), memstick_check calls memstick_alloc_card, which may indefinitely waiting for mrq_complete completion that will never occur because rtsx_usb_ms_request sees eject=true and skips scheduling work, memstick_set_rw_addr waits forever for completion. This causes a deadlock when memstick_remove_host tries to flush_workqueue, waiting for memstick_check to complete, while memstick_check is blocked waiting for mrq_complete completion. Fix this by setting removing=true at the start of rtsx_usb_ms_drv_remove, before any work cancellation. This ensures memstick_check will see the removing flag immediately and exit early, avoiding the deadlock. Fixes: 62c59a8786e6 ("memstick: Skip allocating card when removing host") Signed-off-by: Jiayi Li Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250804013604.1311218-1-lijiayi@kylinos.cn Signed-off-by: Ulf Hansson --- drivers/memstick/core/memstick.c | 1 - drivers/memstick/host/rtsx_usb_ms.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 7f3f47db4c98a5..e4275f8ee5db8a 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -555,7 +555,6 @@ EXPORT_SYMBOL(memstick_add_host); */ void memstick_remove_host(struct memstick_host *host) { - host->removing = 1; flush_workqueue(workqueue); mutex_lock(&host->lock); if (host->card) diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c index 3878136227e49c..5b5e9354fb2e4f 100644 --- a/drivers/memstick/host/rtsx_usb_ms.c +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -812,6 +812,7 @@ static void rtsx_usb_ms_drv_remove(struct platform_device *pdev) int err; host->eject = true; + msh->removing = true; cancel_work_sync(&host->handle_req); cancel_delayed_work_sync(&host->poll_card); From d8df126349dad855cdfedd6bbf315bad2e901c2f Mon Sep 17 00:00:00 2001 From: Tianxiang Peng Date: Mon, 23 Jun 2025 17:31:53 +0800 Subject: [PATCH 0265/1292] x86/cpu/hygon: Add missing resctrl_cpu_detect() in bsp_init helper Since 923f3a2b48bd ("x86/resctrl: Query LLC monitoring properties once during boot") resctrl_cpu_detect() has been moved from common CPU initialization code to the vendor-specific BSP init helper, while Hygon didn't put that call in their code. This triggers a division by zero fault during early booting stage on our machines with X86_FEATURE_CQM* supported, where get_rdt_mon_resources() tries to calculate mon_l3_config with uninitialized boot_cpu_data.x86_cache_occ_scale. Add the missing resctrl_cpu_detect() in the Hygon BSP init helper. [ bp: Massage commit message. ] Fixes: 923f3a2b48bd ("x86/resctrl: Query LLC monitoring properties once during boot") Signed-off-by: Tianxiang Peng Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Hui Li Cc: Link: https://lore.kernel.org/20250623093153.3016937-1-txpeng@tencent.com --- arch/x86/kernel/cpu/hygon.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c index 2154f12766fb5a..1fda6c3a2b65a7 100644 --- a/arch/x86/kernel/cpu/hygon.c +++ b/arch/x86/kernel/cpu/hygon.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "cpu.h" @@ -117,6 +118,8 @@ static void bsp_init_hygon(struct cpuinfo_x86 *c) x86_amd_ls_cfg_ssbd_mask = 1ULL << 10; } } + + resctrl_cpu_detect(c); } static void early_init_hygon(struct cpuinfo_x86 *c) From 89f0addeee3cb2dc49837599330ed9c4612f05b0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 18 Aug 2025 12:59:45 +0300 Subject: [PATCH 0266/1292] ALSA: usb-audio: Fix size validation in convert_chmap_v3() The "p" pointer is void so sizeof(*p) is 1. The intent was to check sizeof(*cs_desc), which is 3, instead. Fixes: ecfd41166b72 ("ALSA: usb-audio: Validate UAC3 cluster segment descriptors") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aKL5kftC1qGt6lpv@stanley.mountain Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index acf3dc2d79e09f..5c235a5ba7e1b1 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -349,7 +349,7 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor u16 cs_len; u8 cs_type; - if (len < sizeof(*p)) + if (len < sizeof(*cs_desc)) break; cs_len = le16_to_cpu(cs_desc->wLength); if (len < cs_len) From 5f1c8965e748c150d580a2ea8fbee1bd80d07a24 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 4 Aug 2025 22:11:28 +1000 Subject: [PATCH 0267/1292] ovl: use I_MUTEX_PARENT when locking parent in ovl_create_temp() ovl_create_temp() treats "workdir" as a parent in which it creates an object so it should use I_MUTEX_PARENT. Prior to the commit identified below the lock was taken by the caller which sometimes used I_MUTEX_PARENT and sometimes used I_MUTEX_NORMAL. The use of I_MUTEX_NORMAL was incorrect but unfortunately copied into ovl_create_temp(). Note to backporters: This patch only applies after the last Fixes given below (post v6.16). To fix the bug in v6.7 and later the inode_lock() call in ovl_copy_up_workdir() needs to nest using I_MUTEX_PARENT. Link: https://lore.kernel.org/all/67a72070.050a0220.3d72c.0022.GAE@google.com/ Cc: stable@vger.kernel.org Reported-by: syzbot+7836a68852a10ec3d790@syzkaller.appspotmail.com Tested-by: syzbot+7836a68852a10ec3d790@syzkaller.appspotmail.com Fixes: c63e56a4a652 ("ovl: do not open/llseek lower file with upper sb_writers held") Fixes: d2c995581c7c ("ovl: Call ovl_create_temp() without lock held.") Signed-off-by: NeilBrown Signed-off-by: Amir Goldstein --- fs/overlayfs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 70b8687dc45e8e..dbd63a74df4b1c 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -225,7 +225,7 @@ struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir, struct ovl_cattr *attr) { struct dentry *ret; - inode_lock(workdir->d_inode); + inode_lock_nested(workdir->d_inode, I_MUTEX_PARENT); ret = ovl_create_real(ofs, workdir, ovl_lookup_temp(ofs, workdir), attr); inode_unlock(workdir->d_inode); From e8bd877fb76bb9f35253e8f41ce0c772269934dd Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Mon, 18 Aug 2025 11:23:55 +0200 Subject: [PATCH 0268/1292] ovl: fix possible double unlink commit 9d23967b18c6 ("ovl: simplify an error path in ovl_copy_up_workdir()") introduced the helper ovl_cleanup_unlocked(), which is later used in several following patches to re-acquire the parent inode lock and unlink a dentry that was earlier found using lookup. This helper was eventually renamed to ovl_cleanup(). The helper ovl_parent_lock() is used to re-acquire the parent inode lock. After acquiring the parent inode lock, the helper verifies that the dentry has not since been moved to another parent, but it failed to verify that the dentry wasn't unlinked from the parent. This means that now every call to ovl_cleanup() could potentially race with another thread, unlinking the dentry to be cleaned up underneath overlayfs and trigger a vfs assertion. Reported-by: syzbot+ec9fab8b7f0386b98a17@syzkaller.appspotmail.com Tested-by: syzbot+ec9fab8b7f0386b98a17@syzkaller.appspotmail.com Fixes: 9d23967b18c6 ("ovl: simplify an error path in ovl_copy_up_workdir()") Suggested-by: NeilBrown Signed-off-by: Amir Goldstein --- fs/overlayfs/util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index a33115e7384c12..41033bac96cbbb 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1552,7 +1552,8 @@ void ovl_copyattr(struct inode *inode) int ovl_parent_lock(struct dentry *parent, struct dentry *child) { inode_lock_nested(parent->d_inode, I_MUTEX_PARENT); - if (!child || child->d_parent == parent) + if (!child || + (!d_unhashed(child) && child->d_parent == parent)) return 0; inode_unlock(parent->d_inode); From 0227af355b50c526bf83ca52d67aef5d102e9b07 Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Sun, 17 Aug 2025 15:06:05 +0530 Subject: [PATCH 0269/1292] selftests: ublk: Use ARRAY_SIZE() macro to improve code Use ARRAY_SIZE() macro while calculating size of an array to improve code readability and reduce potential sizing errors. Implement this suggestion given by spatch tool by running coccinelle script - scripts/coccinelle/misc/array_size.cocci Follow ARRAY_SIZE() macro usage pattern in ublk.c introduced by, commit ec120093180b9 ("selftests: ublk: fix ublk_find_tgt()") wherever appropriate to maintain consistency. Signed-off-by: Akhilesh Patil Reviewed-by: Ming Lei Link: https://lore.kernel.org/r/aKGihYui6/Pcijbk@bhairav-test.ee.iitb.ac.in Signed-off-by: Jens Axboe --- tools/testing/selftests/ublk/kublk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index 95188065b2e984..6512dfbdbce3a8 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1400,7 +1400,7 @@ static int cmd_dev_get_features(void) if (!((1ULL << i) & features)) continue; - if (i < sizeof(feat_map) / sizeof(feat_map[0])) + if (i < ARRAY_SIZE(feat_map)) feat = feat_map[i]; else feat = "unknown"; @@ -1477,7 +1477,7 @@ static void __cmd_create_help(char *exe, bool recovery) printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n"); printf("\tdefault: nthreads=nr_queues"); - for (i = 0; i < sizeof(tgt_ops_list) / sizeof(tgt_ops_list[0]); i++) { + for (i = 0; i < ARRAY_SIZE(tgt_ops_list); i++) { const struct ublk_tgt_ops *ops = tgt_ops_list[i]; if (ops->usage) From 447be50598c05499f7ccc2b1f6ddb3da30f8099a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 15 Aug 2025 12:52:09 +0800 Subject: [PATCH 0270/1292] regulator: pca9450: Use devm_register_sys_off_handler With module test, there is error dump: ------------[ cut here ]------------ notifier callback pca9450_i2c_restart_handler already registered WARNING: kernel/notifier.c:23 at notifier_chain_register+0x5c/0x88, CPU#0: kworker/u16:3/50 Call trace: notifier_chain_register+0x5c/0x88 (P) atomic_notifier_chain_register+0x30/0x58 register_restart_handler+0x1c/0x28 pca9450_i2c_probe+0x418/0x538 i2c_device_probe+0x220/0x3d0 really_probe+0x114/0x410 __driver_probe_device+0xa0/0x150 driver_probe_device+0x40/0x114 __device_attach_driver+0xd4/0x12c So use devm_register_sys_off_handler to let kernel handle the resource free to avoid kernel dump. Fixes: 6157e62b07d9 ("regulator: pca9450: Add restart handler") Signed-off-by: Peng Fan Link: https://patch.msgid.link/20250815-pca9450-v1-1-7748e362dc97@nxp.com Signed-off-by: Mark Brown --- drivers/regulator/pca9450-regulator.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index feadb21a8f3071..4be270f4d6c35a 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -40,7 +40,6 @@ struct pca9450 { struct device *dev; struct regmap *regmap; struct gpio_desc *sd_vsel_gpio; - struct notifier_block restart_nb; enum pca9450_chip_type type; unsigned int rcnt; int irq; @@ -1100,10 +1099,9 @@ static irqreturn_t pca9450_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int pca9450_i2c_restart_handler(struct notifier_block *nb, - unsigned long action, void *data) +static int pca9450_i2c_restart_handler(struct sys_off_data *data) { - struct pca9450 *pca9450 = container_of(nb, struct pca9450, restart_nb); + struct pca9450 *pca9450 = data->cb_data; struct i2c_client *i2c = container_of(pca9450->dev, struct i2c_client, dev); dev_dbg(&i2c->dev, "Restarting device..\n"); @@ -1261,10 +1259,9 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) pca9450->sd_vsel_fixed_low = of_property_read_bool(ldo5->dev.of_node, "nxp,sd-vsel-fixed-low"); - pca9450->restart_nb.notifier_call = pca9450_i2c_restart_handler; - pca9450->restart_nb.priority = PCA9450_RESTART_HANDLER_PRIORITY; - - if (register_restart_handler(&pca9450->restart_nb)) + if (devm_register_sys_off_handler(&i2c->dev, SYS_OFF_MODE_RESTART, + PCA9450_RESTART_HANDLER_PRIORITY, + pca9450_i2c_restart_handler, pca9450)) dev_warn(&i2c->dev, "Failed to register restart handler\n"); dev_info(&i2c->dev, "%s probed.\n", From 8ea815399c3fcce1889bd951fec25b5b9a3979c1 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 14 Apr 2025 16:41:07 +0200 Subject: [PATCH 0271/1292] compiler: remove __ADDRESSABLE_ASM{_STR,}() again __ADDRESSABLE_ASM_STR() is where the necessary stringification happens. As long as "sym" doesn't contain any odd characters, no quoting is required for its use with .quad / .long. In fact the quotation gets in the way with gas 2.25; it's only from 2.26 onwards that quoted symbols are half-way properly supported. However, assembly being different from C anyway, drop __ADDRESSABLE_ASM_STR() and its helper macro altogether. A simple .global directive will suffice to get the symbol "declared", i.e. into the symbol table. While there also stop open-coding STATIC_CALL_TRAMP() and STATIC_CALL_KEY(). Fixes: 0ef8047b737d ("x86/static-call: provide a way to do very early static-call updates") Signed-off-by: Jan Beulich Acked-by: Josh Poimboeuf Cc: stable@vger.kernel.org Signed-off-by: Juergen Gross Message-ID: <609d2c74-de13-4fae-ab1a-1ec44afb948d@suse.com> --- arch/x86/include/asm/xen/hypercall.h | 5 +++-- include/linux/compiler.h | 8 -------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index 59a62c3780a2f2..a16d4631547ce1 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -94,12 +94,13 @@ DECLARE_STATIC_CALL(xen_hypercall, xen_hypercall_func); #ifdef MODULE #define __ADDRESSABLE_xen_hypercall #else -#define __ADDRESSABLE_xen_hypercall __ADDRESSABLE_ASM_STR(__SCK__xen_hypercall) +#define __ADDRESSABLE_xen_hypercall \ + __stringify(.global STATIC_CALL_KEY(xen_hypercall);) #endif #define __HYPERCALL \ __ADDRESSABLE_xen_hypercall \ - "call __SCT__xen_hypercall" + __stringify(call STATIC_CALL_TRAMP(xen_hypercall)) #define __HYPERCALL_ENTRY(x) "a" (x) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 6f04a1d8c72094..64ff73c533e54e 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -288,14 +288,6 @@ static inline void *offset_to_ptr(const int *off) #define __ADDRESSABLE(sym) \ ___ADDRESSABLE(sym, __section(".discard.addressable")) -#define __ADDRESSABLE_ASM(sym) \ - .pushsection .discard.addressable,"aw"; \ - .align ARCH_SEL(8,4); \ - ARCH_SEL(.quad, .long) __stringify(sym); \ - .popsection; - -#define __ADDRESSABLE_ASM_STR(sym) __stringify(__ADDRESSABLE_ASM(sym)) - /* * This returns a constant expression while determining if an argument is * a constant expression, most importantly without evaluating the argument. From 75dbd4304afe574fcfc4118a5b78776a9f48fdc4 Mon Sep 17 00:00:00 2001 From: Sungbae Yoo Date: Wed, 6 Aug 2025 12:47:35 +0000 Subject: [PATCH 0272/1292] tee: optee: ffa: fix a typo of "optee_ffa_api_is_compatible" Fixes optee_ffa_api_is_compatbile() to optee_ffa_api_is_compatible() because compatbile is a typo of compatible. Fixes: 4615e5a34b95 ("optee: add FF-A support") Signed-off-by: Sungbae Yoo Reviewed-by: Sumit Garg Signed-off-by: Jens Wiklander --- drivers/tee/optee/ffa_abi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c index f9ef7d94cebd7a..a963eed70c1d4c 100644 --- a/drivers/tee/optee/ffa_abi.c +++ b/drivers/tee/optee/ffa_abi.c @@ -657,7 +657,7 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx, * with a matching configuration. */ -static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev, +static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev, const struct ffa_ops *ops) { const struct ffa_msg_ops *msg_ops = ops->msg_ops; @@ -908,7 +908,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) ffa_ops = ffa_dev->ops; notif_ops = ffa_ops->notifier_ops; - if (!optee_ffa_api_is_compatbile(ffa_dev, ffa_ops)) + if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops)) return -EINVAL; if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps, From 8fe8a092043f28d3c8e467cb2bbfe1e1ccf7f996 Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Sun, 10 Aug 2025 19:04:01 +0530 Subject: [PATCH 0273/1292] iommufd: viommu: free memory allocated by kvcalloc() using kvfree() Use kvfree() instead of kfree() to free pages allocated by kvcalloc() in iommufs_hw_queue_alloc_phys() to fix potential memory corruption. Ensure the memory is properly freed, as kvcalloc may internally use vmalloc or kmalloc depending on available memory in the system. Fixes: 2238ddc2b056 ("iommufd/viommu: Add IOMMUFD_CMD_HW_QUEUE_ALLOC ioctl") Link: https://patch.msgid.link/r/aJifyVV2PL6WGEs6@bhairav-test.ee.iitb.ac.in Signed-off-by: Akhilesh Patil Reviewed-by: Kevin Tian Reviewed-by: Nicolin Chen Reviewed-by: Pranjal Shrivastava Signed-off-by: Jason Gunthorpe --- drivers/iommu/iommufd/viommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/iommufd/viommu.c b/drivers/iommu/iommufd/viommu.c index 2ca5809b238bbe..462b457ffd0c42 100644 --- a/drivers/iommu/iommufd/viommu.c +++ b/drivers/iommu/iommufd/viommu.c @@ -339,7 +339,7 @@ iommufd_hw_queue_alloc_phys(struct iommu_hw_queue_alloc *cmd, } *base_pa = (page_to_pfn(pages[0]) << PAGE_SHIFT) + offset; - kfree(pages); + kvfree(pages); return access; out_unpin: @@ -349,7 +349,7 @@ iommufd_hw_queue_alloc_phys(struct iommu_hw_queue_alloc *cmd, out_destroy: iommufd_access_destroy_internal(viommu->ictx, access); out_free: - kfree(pages); + kvfree(pages); return ERR_PTR(rc); } From 447c6141e8ea68ef4e56c55144fd18f43e6c8dca Mon Sep 17 00:00:00 2001 From: Alessandro Ratti Date: Fri, 15 Aug 2025 17:37:26 +0200 Subject: [PATCH 0274/1292] iommufd: Fix spelling errors in iommufd.rst This patch corrects two minor spelling issues found in Documentation/userspace-api/iommufd.rst: - "primarly" -> "primarily" - "sharable" -> "shareable" Found using codespell(1). Link: https://patch.msgid.link/r/20250815153840.188213-2-alessandro@0x65c.net Signed-off-by: Alessandro Ratti Signed-off-by: Jason Gunthorpe --- Documentation/userspace-api/iommufd.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/userspace-api/iommufd.rst b/Documentation/userspace-api/iommufd.rst index 03f7510384d266..f1c4d21e5c5ee2 100644 --- a/Documentation/userspace-api/iommufd.rst +++ b/Documentation/userspace-api/iommufd.rst @@ -43,7 +43,7 @@ Following IOMMUFD objects are exposed to userspace: - IOMMUFD_OBJ_HWPT_PAGING, representing an actual hardware I/O page table (i.e. a single struct iommu_domain) managed by the iommu driver. "PAGING" - primarly indicates this type of HWPT should be linked to an IOAS. It also + primarily indicates this type of HWPT should be linked to an IOAS. It also indicates that it is backed by an iommu_domain with __IOMMU_DOMAIN_PAGING feature flag. This can be either an UNMANAGED stage-1 domain for a device running in the user space, or a nesting parent stage-2 domain for mappings @@ -76,7 +76,7 @@ Following IOMMUFD objects are exposed to userspace: * Security namespace for guest owned ID, e.g. guest-controlled cache tags * Non-device-affiliated event reporting, e.g. invalidation queue errors - * Access to a sharable nesting parent pagetable across physical IOMMUs + * Access to a shareable nesting parent pagetable across physical IOMMUs * Virtualization of various platforms IDs, e.g. RIDs and others * Delivery of paravirtualized invalidation * Direct assigned invalidation queues From e9576e078220c50ace9e9087355423de23e25fa5 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Mon, 21 Jul 2025 18:11:54 +0000 Subject: [PATCH 0275/1292] x86/CPU/AMD: Ignore invalid reset reason value The reset reason value may be "all bits set", e.g. 0xFFFFFFFF. This is a commonly used error response from hardware. This may occur due to a real hardware issue or when running in a VM. The user will see all reset reasons reported in this case. Check for an error response value and return early to avoid decoding invalid data. Also, adjust the data variable type to match the hardware register size. Fixes: ab8131028710 ("x86/CPU/AMD: Print the reason for the last reset") Reported-by: Libing He Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Mario Limonciello Cc: stable@vger.kernel.org Link: https://lore.kernel.org/20250721181155.3536023-1-yazen.ghannam@amd.com --- arch/x86/kernel/cpu/amd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index a5ece6ebe8a74a..a6f88ca1a6b495 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -1326,8 +1326,8 @@ static const char * const s5_reset_reason_txt[] = { static __init int print_s5_reset_status_mmio(void) { - unsigned long value; void __iomem *addr; + u32 value; int i; if (!cpu_feature_enabled(X86_FEATURE_ZEN)) @@ -1340,12 +1340,16 @@ static __init int print_s5_reset_status_mmio(void) value = ioread32(addr); iounmap(addr); + /* Value with "all bits set" is an error response and should be ignored. */ + if (value == U32_MAX) + return 0; + for (i = 0; i < ARRAY_SIZE(s5_reset_reason_txt); i++) { if (!(value & BIT(i))) continue; if (s5_reset_reason_txt[i]) { - pr_info("x86/amd: Previous system reset reason [0x%08lx]: %s\n", + pr_info("x86/amd: Previous system reset reason [0x%08x]: %s\n", value, s5_reset_reason_txt[i]); } } From 1ba9fbe40337e448b32e2831a7051191d61f0382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Aug 2025 09:44:42 +0200 Subject: [PATCH 0276/1292] drm/msm: Don't use %pK through printk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the past %pK was preferable to %p as it would not leak raw pointer values into the kernel log. Since commit ad67b74d2469 ("printk: hash addresses printed with %p") the regular %p has been improved to avoid this issue. Furthermore, restricted pointers ("%pK") were never meant to be used through printk(). They can still unintentionally leak raw pointers or acquire sleeping locks in atomic contexts. Switch to the regular pointer formatting which is safer and easier to reason about. Signed-off-by: Thomas Weißschuh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/667895/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c | 4 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 ++-- drivers/gpu/drm/msm/msm_mdss.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index d4b545448d7465..94912b4708fb5b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -596,7 +596,7 @@ static void _dpu_crtc_complete_flip(struct drm_crtc *crtc) spin_lock_irqsave(&dev->event_lock, flags); if (dpu_crtc->event) { - DRM_DEBUG_VBL("%s: send event: %pK\n", dpu_crtc->name, + DRM_DEBUG_VBL("%s: send event: %p\n", dpu_crtc->name, dpu_crtc->event); trace_dpu_crtc_complete_flip(DRMID(crtc)); drm_crtc_send_vblank_event(crtc, dpu_crtc->event); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c index 11fb1bc54fa92a..54b20faa0b697e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c @@ -31,14 +31,14 @@ static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx, u32 base; if (!ctx) { - DRM_ERROR("invalid ctx %pK\n", ctx); + DRM_ERROR("invalid ctx %p\n", ctx); return; } base = ctx->cap->sblk->pcc.base; if (!base) { - DRM_ERROR("invalid ctx %pK pcc base 0x%x\n", ctx, base); + DRM_ERROR("invalid ctx %p pcc base 0x%x\n", ctx, base); return; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 12dcb32b472497..a306077647c317 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1345,7 +1345,7 @@ static int dpu_kms_mmap_mdp5(struct dpu_kms *dpu_kms) dpu_kms->mmio = NULL; return ret; } - DRM_DEBUG("mapped dpu address space @%pK\n", dpu_kms->mmio); + DRM_DEBUG("mapped dpu address space @%p\n", dpu_kms->mmio); dpu_kms->vbif[VBIF_RT] = msm_ioremap_mdss(mdss_dev, dpu_kms->pdev, @@ -1380,7 +1380,7 @@ static int dpu_kms_mmap_dpu(struct dpu_kms *dpu_kms) dpu_kms->mmio = NULL; return ret; } - DRM_DEBUG("mapped dpu address space @%pK\n", dpu_kms->mmio); + DRM_DEBUG("mapped dpu address space @%p\n", dpu_kms->mmio); dpu_kms->vbif[VBIF_RT] = msm_ioremap(pdev, "vbif"); if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 1f5fe7811e0169..39885b333910bb 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -423,7 +423,7 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5 if (IS_ERR(msm_mdss->mmio)) return ERR_CAST(msm_mdss->mmio); - dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio); + dev_dbg(&pdev->dev, "mapped mdss address space @%p\n", msm_mdss->mmio); ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss); if (ret) From 4876b391654142dcf31ac6da619ace357b6b902d Mon Sep 17 00:00:00 2001 From: Antonino Maniscalco Date: Wed, 13 Aug 2025 15:04:44 +0200 Subject: [PATCH 0277/1292] drm/msm: skip re-emitting IBs for unusable VMs When a VM is marked as an usuable we disallow new submissions from it, however submissions that where already scheduled on the ring would still be re-sent. Since this can lead to further hangs, avoid emitting the actual IBs. Fixes: 6a4d287a1ae6 ("drm/msm: Mark VM as unusable on GPU hangs") Signed-off-by: Antonino Maniscalco Reviewed-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/668314/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gpu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 416d47185ef09e..26c5ce897cbbdc 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -558,8 +558,15 @@ static void recover_worker(struct kthread_work *work) unsigned long flags; spin_lock_irqsave(&ring->submit_lock, flags); - list_for_each_entry(submit, &ring->submits, node) + list_for_each_entry(submit, &ring->submits, node) { + /* + * If the submit uses an unusable vm make sure + * we don't actually run it + */ + if (to_msm_vm(submit->vm)->unusable) + submit->nr_cmds = 0; gpu->funcs->submit(gpu, submit); + } spin_unlock_irqrestore(&ring->submit_lock, flags); } } From 61ca3b891b4b9667334c1356a73f28954c92d43a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Aug 2025 06:54:50 +0200 Subject: [PATCH 0278/1292] block: handle pi_tuple_size in queue_limits_stack_integrity queue_limits_stack_integrity needs to handle the new pi_tuple_size field, otherwise stacking PI-capable devices will always fail. Fixes: 76e45252a4ce ("block: introduce pi_tuple_size field in blk_integrity") Signed-off-by: Christoph Hellwig Reviewed-by: Anuj Gupta Reviewed-by: Martin K. Petersen Link: https://lore.kernel.org/r/20250818045456.1482889-2-hch@lst.de Signed-off-by: Jens Axboe --- block/blk-settings.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/blk-settings.c b/block/blk-settings.c index 07874e9b609f6f..491c0c48d52b4d 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -972,6 +972,8 @@ bool queue_limits_stack_integrity(struct queue_limits *t, goto incompatible; if (ti->csum_type != bi->csum_type) goto incompatible; + if (ti->pi_tuple_size != bi->pi_tuple_size) + goto incompatible; if ((ti->flags & BLK_INTEGRITY_REF_TAG) != (bi->flags & BLK_INTEGRITY_REF_TAG)) goto incompatible; @@ -980,6 +982,7 @@ bool queue_limits_stack_integrity(struct queue_limits *t, ti->flags |= (bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) | (bi->flags & BLK_INTEGRITY_REF_TAG); ti->csum_type = bi->csum_type; + ti->pi_tuple_size = bi->pi_tuple_size; ti->metadata_size = bi->metadata_size; ti->pi_offset = bi->pi_offset; ti->interval_exp = bi->interval_exp; From f4ae1744033d54b63c31a3664a4fdf5cebec7f27 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Aug 2025 06:54:51 +0200 Subject: [PATCH 0279/1292] block: remove newlines from the warnings in blk_validate_integrity_limits Otherwise they are very hard to read in the kernel log. Signed-off-by: Christoph Hellwig Reviewed-by: Anuj Gupta Reviewed-by: Martin K. Petersen Link: https://lore.kernel.org/r/20250818045456.1482889-3-hch@lst.de Signed-off-by: Jens Axboe --- block/blk-settings.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index 491c0c48d52b4d..d6438e6c276dcc 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -157,16 +157,14 @@ static int blk_validate_integrity_limits(struct queue_limits *lim) switch (bi->csum_type) { case BLK_INTEGRITY_CSUM_NONE: if (bi->pi_tuple_size) { - pr_warn("pi_tuple_size must be 0 when checksum type \ - is none\n"); + pr_warn("pi_tuple_size must be 0 when checksum type is none\n"); return -EINVAL; } break; case BLK_INTEGRITY_CSUM_CRC: case BLK_INTEGRITY_CSUM_IP: if (bi->pi_tuple_size != sizeof(struct t10_pi_tuple)) { - pr_warn("pi_tuple_size mismatch for T10 PI: expected \ - %zu, got %u\n", + pr_warn("pi_tuple_size mismatch for T10 PI: expected %zu, got %u\n", sizeof(struct t10_pi_tuple), bi->pi_tuple_size); return -EINVAL; @@ -174,8 +172,7 @@ static int blk_validate_integrity_limits(struct queue_limits *lim) break; case BLK_INTEGRITY_CSUM_CRC64: if (bi->pi_tuple_size != sizeof(struct crc64_pi_tuple)) { - pr_warn("pi_tuple_size mismatch for CRC64 PI: \ - expected %zu, got %u\n", + pr_warn("pi_tuple_size mismatch for CRC64 PI: expected %zu, got %u\n", sizeof(struct crc64_pi_tuple), bi->pi_tuple_size); return -EINVAL; From 43c0f6456f801181a80b73d95def0e0fd134e1cc Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Mon, 18 Aug 2025 10:27:30 +0100 Subject: [PATCH 0280/1292] iio: pressure: bmp280: Use IS_ERR() in bmp280_common_probe() `devm_gpiod_get_optional()` may return non-NULL error pointer on failure. Check its return value using `IS_ERR()` and propagate the error if necessary. Fixes: df6e71256c84 ("iio: pressure: bmp280: Explicitly mark GPIO optional") Signed-off-by: Salah Triki Reviewed-by: David Lechner Link: https://patch.msgid.link/20250818092740.545379-2-salah.triki@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 74505c9ec1a08c..6cdc8ed5352047 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -3213,11 +3213,12 @@ int bmp280_common_probe(struct device *dev, /* Bring chip out of reset if there is an assigned GPIO line */ gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), "failed to get reset GPIO\n"); + /* Deassert the signal */ - if (gpiod) { - dev_info(dev, "release reset\n"); - gpiod_set_value(gpiod, 0); - } + dev_info(dev, "release reset\n"); + gpiod_set_value(gpiod, 0); data->regmap = regmap; From 22ec0faa0eda30acdd6dcb3c29c872629da677bb Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 09:41:22 -0700 Subject: [PATCH 0281/1292] perf test: Fix a build error in x86 topdown test There's an environment that caused the following build error. Include "debug.h" (under util directory) to fix it. arch/x86/tests/topdown.c: In function 'event_cb': arch/x86/tests/topdown.c:53:25: error: implicit declaration of function 'pr_debug' [-Werror=implicit-function-declaration] 53 | pr_debug("Broken topdown information for '%s'\n", evsel__name(evsel)); | ^~~~~~~~ cc1: all warnings being treated as errors Link: https://lore.kernel.org/r/20250815164122.289651-1-namhyung@kernel.org Fixes: 5b546de9cc177936 ("perf topdown: Use attribute to see an event is a topdown metic or slots") Reported-by: Naresh Kamboju Signed-off-by: Namhyung Kim --- tools/perf/arch/x86/tests/topdown.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c index 8d0ea7a4bbc1cd..1eba3b4594ef2b 100644 --- a/tools/perf/arch/x86/tests/topdown.c +++ b/tools/perf/arch/x86/tests/topdown.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "arch-tests.h" #include "../util/topdown.h" +#include "debug.h" #include "evlist.h" #include "parse-events.h" #include "pmu.h" From bd842ff41543af424c2473dc16c678ac8ba2b43f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0282/1292] tools headers: Sync KVM headers with the kernel source To pick up the changes in this cset: f55ce5a6cd33211c KVM: arm64: Expose new KVM cap for cacheable PFNMAP 28224ef02b56fcee KVM: TDX: Report supported optional TDVMCALLs in TDX capabilities 4580dbef5ce0f95a KVM: TDX: Exit to userspace for SetupEventNotifyInterrupt 25e8b1dd4883e6c2 KVM: TDX: Exit to userspace for GetTdVmCallInfo cf207eac06f661fb KVM: TDX: Handle TDG.VP.VMCALL This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/include/uapi/linux/kvm.h include/uapi/linux/kvm.h diff -u tools/arch/x86/include/uapi/asm/kvm.h arch/x86/include/uapi/asm/kvm.h Please see tools/include/uapi/README for further details. Cc: Paolo Bonzini Cc: kvm@vger.kernel.org Signed-off-by: Namhyung Kim --- tools/arch/x86/include/uapi/asm/kvm.h | 8 +++++++- tools/include/uapi/linux/kvm.h | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index 6f3499507c5efb..0f15d683817d6a 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -965,7 +965,13 @@ struct kvm_tdx_cmd { struct kvm_tdx_capabilities { __u64 supported_attrs; __u64 supported_xfam; - __u64 reserved[254]; + + __u64 kernel_tdvmcallinfo_1_r11; + __u64 user_tdvmcallinfo_1_r11; + __u64 kernel_tdvmcallinfo_1_r12; + __u64 user_tdvmcallinfo_1_r12; + + __u64 reserved[250]; /* Configurable CPUID bits for userspace */ struct kvm_cpuid2 cpuid; diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 7415a3863891c0..f0f0d49d254435 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -178,6 +178,7 @@ struct kvm_xen_exit { #define KVM_EXIT_NOTIFY 37 #define KVM_EXIT_LOONGARCH_IOCSR 38 #define KVM_EXIT_MEMORY_FAULT 39 +#define KVM_EXIT_TDX 40 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -447,6 +448,31 @@ struct kvm_run { __u64 gpa; __u64 size; } memory_fault; + /* KVM_EXIT_TDX */ + struct { + __u64 flags; + __u64 nr; + union { + struct { + __u64 ret; + __u64 data[5]; + } unknown; + struct { + __u64 ret; + __u64 gpa; + __u64 size; + } get_quote; + struct { + __u64 ret; + __u64 leaf; + __u64 r11, r12, r13, r14; + } get_tdvmcall_info; + struct { + __u64 ret; + __u64 vector; + } setup_event_notify; + }; + } tdx; /* Fix the size of the union. */ char padding[256]; }; @@ -935,6 +961,7 @@ struct kvm_enable_cap { #define KVM_CAP_ARM_EL2 240 #define KVM_CAP_ARM_EL2_E2H0 241 #define KVM_CAP_RISCV_MP_STATE_RESET 242 +#define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243 struct kvm_irq_routing_irqchip { __u32 irqchip; From 8aa5a3b68ad144da49a3d17f165e6561255e3529 Mon Sep 17 00:00:00 2001 From: Rajeev Mishra Date: Mon, 18 Aug 2025 18:48:20 +0000 Subject: [PATCH 0283/1292] loop: Consolidate size calculation logic into lo_calculate_size() Renamed get_size to lo_calculate_size and merged the logic from get_size and get_loop_size into a single function. Update all callers to use lo_calculate_size. This is done in preparation for improving the size detection logic. Signed-off-by: Rajeev Mishra Reviewed-by: Yu Kuai Link: https://lore.kernel.org/r/20250818184821.115033-2-rajeevm@hpe.com [axboe: massage commit message] Signed-off-by: Jens Axboe --- drivers/block/loop.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 1b6ee91f8eb987..0e1b9eb9db1060 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -137,20 +137,18 @@ static void loop_global_unlock(struct loop_device *lo, bool global) static int max_part; static int part_shift; -static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file) +static loff_t lo_calculate_size(struct loop_device *lo, struct file *file) { loff_t loopsize; - /* Compute loopsize in bytes */ loopsize = i_size_read(file->f_mapping->host); - if (offset > 0) - loopsize -= offset; + if (lo->lo_offset > 0) + loopsize -= lo->lo_offset; /* offset is beyond i_size, weird but possible */ if (loopsize < 0) return 0; - - if (sizelimit > 0 && sizelimit < loopsize) - loopsize = sizelimit; + if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize) + loopsize = lo->lo_sizelimit; /* * Unfortunately, if we want to do I/O on the device, * the number of 512-byte sectors has to fit into a sector_t. @@ -158,11 +156,6 @@ static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file) return loopsize >> 9; } -static loff_t get_loop_size(struct loop_device *lo, struct file *file) -{ - return get_size(lo->lo_offset, lo->lo_sizelimit, file); -} - /* * We support direct I/O only if lo_offset is aligned with the logical I/O size * of backing device, and the logical block size of loop is bigger than that of @@ -569,7 +562,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, error = -EINVAL; /* size of the new backing store needs to be the same */ - if (get_loop_size(lo, file) != get_loop_size(lo, old_file)) + if (lo_calculate_size(lo, file) != lo_calculate_size(lo, old_file)) goto out_err; /* @@ -1063,7 +1056,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode, loop_update_dio(lo); loop_sysfs_init(lo); - size = get_loop_size(lo, file); + size = lo_calculate_size(lo, file); loop_set_size(lo, size); /* Order wrt reading lo_state in loop_validate_file(). */ @@ -1255,8 +1248,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (partscan) clear_bit(GD_SUPPRESS_PART_SCAN, &lo->lo_disk->state); if (!err && size_changed) { - loff_t new_size = get_size(lo->lo_offset, lo->lo_sizelimit, - lo->lo_backing_file); + loff_t new_size = lo_calculate_size(lo, lo->lo_backing_file); loop_set_size(lo, new_size); } out_unlock: @@ -1399,7 +1391,7 @@ static int loop_set_capacity(struct loop_device *lo) if (unlikely(lo->lo_state != Lo_bound)) return -ENXIO; - size = get_loop_size(lo, lo->lo_backing_file); + size = lo_calculate_size(lo, lo->lo_backing_file); loop_set_size(lo, size); return 0; From 47b71abd58461a67cae71d2f2a9d44379e4e2fcf Mon Sep 17 00:00:00 2001 From: Rajeev Mishra Date: Mon, 18 Aug 2025 18:48:21 +0000 Subject: [PATCH 0284/1292] loop: use vfs_getattr_nosec for accurate file size Use vfs_getattr_nosec() in lo_calculate_size() for getting the file size, rather than just read the cached inode size via i_size_read(). This provides better results than cached inode data, particularly for network filesystems where metadata may be stale. Signed-off-by: Rajeev Mishra Reviewed-by: Yu Kuai Link: https://lore.kernel.org/r/20250818184821.115033-3-rajeevm@hpe.com [axboe: massage commit message] Signed-off-by: Jens Axboe --- drivers/block/loop.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 0e1b9eb9db1060..57263c273f0fb4 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -139,9 +139,20 @@ static int part_shift; static loff_t lo_calculate_size(struct loop_device *lo, struct file *file) { + struct kstat stat; loff_t loopsize; - /* Compute loopsize in bytes */ - loopsize = i_size_read(file->f_mapping->host); + int ret; + + /* + * Get the accurate file size. This provides better results than + * cached inode data, particularly for network filesystems where + * metadata may be stale. + */ + ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0); + if (ret) + return 0; + + loopsize = stat.size; if (lo->lo_offset > 0) loopsize -= lo->lo_offset; /* offset is beyond i_size, weird but possible */ From d0a2b527d8c32e46ccb8a34053468d4ff0c27e5c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Aug 2025 12:11:02 +0200 Subject: [PATCH 0285/1292] block: tone down bio_check_eod bdev_nr_sectors() == 0 is a pattern used for block devices that have been hot removed, don't spam the log about them. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20250818101102.1604551-1-hch@lst.de Signed-off-by: Jens Axboe --- block/blk-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-core.c b/block/blk-core.c index fdac48aec5efb3..4201504158a17e 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -557,7 +557,7 @@ static inline int bio_check_eod(struct bio *bio) sector_t maxsector = bdev_nr_sectors(bio->bi_bdev); unsigned int nr_sectors = bio_sectors(bio); - if (nr_sectors && + if (nr_sectors && maxsector && (nr_sectors > maxsector || bio->bi_iter.bi_sector > maxsector - nr_sectors)) { pr_info_ratelimited("%s: attempt to access beyond end of device\n" From 6cb8607934d937f4ad24ec9ad26aeb669e266937 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0286/1292] tools headers: Sync linux/bits.h with the kernel source To pick up the changes in this cset: 104ea1c84b91c9f4 bits: unify the non-asm GENMASK*() 6d4471252ccc1722 bits: split the definition of the asm and non-asm GENMASK*() This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/include/linux/bits.h include/linux/bits.h Please see tools/include/uapi/README for further details. Cc: Yury Norov Signed-off-by: Namhyung Kim --- tools/include/linux/bits.h | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/tools/include/linux/bits.h b/tools/include/linux/bits.h index 7ad05621911534..a40cc861b3a7c6 100644 --- a/tools/include/linux/bits.h +++ b/tools/include/linux/bits.h @@ -2,10 +2,8 @@ #ifndef __LINUX_BITS_H #define __LINUX_BITS_H -#include #include #include -#include #define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) @@ -50,10 +48,14 @@ (type_max(t) << (l) & \ type_max(t) >> (BITS_PER_TYPE(t) - 1 - (h))))) +#define GENMASK(h, l) GENMASK_TYPE(unsigned long, h, l) +#define GENMASK_ULL(h, l) GENMASK_TYPE(unsigned long long, h, l) + #define GENMASK_U8(h, l) GENMASK_TYPE(u8, h, l) #define GENMASK_U16(h, l) GENMASK_TYPE(u16, h, l) #define GENMASK_U32(h, l) GENMASK_TYPE(u32, h, l) #define GENMASK_U64(h, l) GENMASK_TYPE(u64, h, l) +#define GENMASK_U128(h, l) GENMASK_TYPE(u128, h, l) /* * Fixed-type variants of BIT(), with additional checks like GENMASK_TYPE(). The @@ -79,28 +81,9 @@ * BUILD_BUG_ON_ZERO is not available in h files included from asm files, * disable the input check if that is the case. */ -#define GENMASK_INPUT_CHECK(h, l) 0 +#define GENMASK(h, l) __GENMASK(h, l) +#define GENMASK_ULL(h, l) __GENMASK_ULL(h, l) #endif /* !defined(__ASSEMBLY__) */ -#define GENMASK(h, l) \ - (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l)) -#define GENMASK_ULL(h, l) \ - (GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l)) - -#if !defined(__ASSEMBLY__) -/* - * Missing asm support - * - * __GENMASK_U128() depends on _BIT128() which would not work - * in the asm code, as it shifts an 'unsigned __int128' data - * type instead of direct representation of 128 bit constants - * such as long and unsigned long. The fundamental problem is - * that a 128 bit constant will get silently truncated by the - * gcc compiler. - */ -#define GENMASK_U128(h, l) \ - (GENMASK_INPUT_CHECK(h, l) + __GENMASK_U128(h, l)) -#endif - #endif /* __LINUX_BITS_H */ From aa34642f6fc36a436de5ae5b30d414578b3622f5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0287/1292] tools headers: Sync linux/cfi_types.h with the kernel source To pick up the changes in this cset: 5ccaeedb489b41ce cfi: add C CFI type macro This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/include/linux/cfi_types.h include/linux/cfi_types.h Please see tools/include/uapi/README for further details. Cc: Mark Rutland Signed-off-by: Namhyung Kim --- tools/include/linux/cfi_types.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/include/linux/cfi_types.h b/tools/include/linux/cfi_types.h index 6b87136757655c..685f7181780f92 100644 --- a/tools/include/linux/cfi_types.h +++ b/tools/include/linux/cfi_types.h @@ -41,5 +41,28 @@ SYM_TYPED_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) #endif +#else /* __ASSEMBLY__ */ + +#ifdef CONFIG_CFI_CLANG +#define DEFINE_CFI_TYPE(name, func) \ + /* \ + * Force a reference to the function so the compiler generates \ + * __kcfi_typeid_. \ + */ \ + __ADDRESSABLE(func); \ + /* u32 name __ro_after_init = __kcfi_typeid_ */ \ + extern u32 name; \ + asm ( \ + " .pushsection .data..ro_after_init,\"aw\",\%progbits \n" \ + " .type " #name ",\%object \n" \ + " .globl " #name " \n" \ + " .p2align 2, 0x0 \n" \ + #name ": \n" \ + " .4byte __kcfi_typeid_" #func " \n" \ + " .size " #name ", 4 \n" \ + " .popsection \n" \ + ); +#endif + #endif /* __ASSEMBLY__ */ #endif /* _LINUX_CFI_TYPES_H */ From 619f55c859014e2235f83ba6cde8c59edc492f39 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0288/1292] tools headers: Sync x86 headers with the kernel source To pick up the changes in this cset: 7b306dfa326f7011 x86/sev: Evict cache lines during SNP memory validation 65f55a30176662ee x86/CPU/AMD: Add CPUID faulting support d8010d4ba43e9f79 x86/bugs: Add a Transient Scheduler Attacks mitigation a3c4f3396b82849a x86/msr-index: Add AMD workload classification MSRs 17ec2f965344ee3f KVM: VMX: Allow guest to set DEBUGCTL.RTM_DEBUG if RTM is supported This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/arch/x86/include/asm/cpufeatures.h arch/x86/include/asm/cpufeatures.h diff -u tools/arch/x86/include/asm/msr-index.h arch/x86/include/asm/msr-index.h Please see tools/include/uapi/README for further details. Cc: x86@kernel.org Signed-off-by: Namhyung Kim --- tools/arch/x86/include/asm/cpufeatures.h | 10 +++++++++- tools/arch/x86/include/asm/msr-index.h | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index ee176236c2be99..06fc0479a23f01 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -218,6 +218,7 @@ #define X86_FEATURE_FLEXPRIORITY ( 8*32+ 1) /* "flexpriority" Intel FlexPriority */ #define X86_FEATURE_EPT ( 8*32+ 2) /* "ept" Intel Extended Page Table */ #define X86_FEATURE_VPID ( 8*32+ 3) /* "vpid" Intel Virtual Processor ID */ +#define X86_FEATURE_COHERENCY_SFW_NO ( 8*32+ 4) /* SNP cache coherency software work around not needed */ #define X86_FEATURE_VMMCALL ( 8*32+15) /* "vmmcall" Prefer VMMCALL to VMCALL */ #define X86_FEATURE_XENPV ( 8*32+16) /* Xen paravirtual guest */ @@ -456,10 +457,14 @@ #define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0) /* No Nested Data Breakpoints */ #define X86_FEATURE_WRMSR_XX_BASE_NS (20*32+ 1) /* WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing */ #define X86_FEATURE_LFENCE_RDTSC (20*32+ 2) /* LFENCE always serializing / synchronizes RDTSC */ +#define X86_FEATURE_VERW_CLEAR (20*32+ 5) /* The memory form of VERW mitigates TSA */ #define X86_FEATURE_NULL_SEL_CLR_BASE (20*32+ 6) /* Null Selector Clears Base */ + #define X86_FEATURE_AUTOIBRS (20*32+ 8) /* Automatic IBRS */ #define X86_FEATURE_NO_SMM_CTL_MSR (20*32+ 9) /* SMM_CTL MSR is not present */ +#define X86_FEATURE_GP_ON_USER_CPUID (20*32+17) /* User CPUID faulting */ + #define X86_FEATURE_PREFETCHI (20*32+20) /* Prefetch Data/Instruction to Cache Level */ #define X86_FEATURE_SBPB (20*32+27) /* Selective Branch Prediction Barrier */ #define X86_FEATURE_IBPB_BRTYPE (20*32+28) /* MSR_PRED_CMD[IBPB] flushes all branch type predictions */ @@ -487,6 +492,9 @@ #define X86_FEATURE_PREFER_YMM (21*32+ 8) /* Avoid ZMM registers due to downclocking */ #define X86_FEATURE_APX (21*32+ 9) /* Advanced Performance Extensions */ #define X86_FEATURE_INDIRECT_THUNK_ITS (21*32+10) /* Use thunk for indirect branches in lower half of cacheline */ +#define X86_FEATURE_TSA_SQ_NO (21*32+11) /* AMD CPU not vulnerable to TSA-SQ */ +#define X86_FEATURE_TSA_L1_NO (21*32+12) /* AMD CPU not vulnerable to TSA-L1 */ +#define X86_FEATURE_CLEAR_CPU_BUF_VM (21*32+13) /* Clear CPU buffers using VERW before VMRUN */ /* * BUG word(s) @@ -542,5 +550,5 @@ #define X86_BUG_OLD_MICROCODE X86_BUG( 1*32+ 6) /* "old_microcode" CPU has old microcode, it is surely vulnerable to something */ #define X86_BUG_ITS X86_BUG( 1*32+ 7) /* "its" CPU is affected by Indirect Target Selection */ #define X86_BUG_ITS_NATIVE_ONLY X86_BUG( 1*32+ 8) /* "its_native_only" CPU is affected by ITS, VMX is not affected */ - +#define X86_BUG_TSA X86_BUG( 1*32+ 9) /* "tsa" CPU is affected by Transient Scheduler Attacks */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h index 5cfb5d74dd5f58..b65c3ba5fa1410 100644 --- a/tools/arch/x86/include/asm/msr-index.h +++ b/tools/arch/x86/include/asm/msr-index.h @@ -419,6 +419,7 @@ #define DEBUGCTLMSR_FREEZE_PERFMON_ON_PMI (1UL << 12) #define DEBUGCTLMSR_FREEZE_IN_SMM_BIT 14 #define DEBUGCTLMSR_FREEZE_IN_SMM (1UL << DEBUGCTLMSR_FREEZE_IN_SMM_BIT) +#define DEBUGCTLMSR_RTM_DEBUG BIT(15) #define MSR_PEBS_FRONTEND 0x000003f7 @@ -733,6 +734,11 @@ #define MSR_AMD64_PERF_CNTR_GLOBAL_CTL 0xc0000301 #define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR 0xc0000302 +/* AMD Hardware Feedback Support MSRs */ +#define MSR_AMD_WORKLOAD_CLASS_CONFIG 0xc0000500 +#define MSR_AMD_WORKLOAD_CLASS_ID 0xc0000501 +#define MSR_AMD_WORKLOAD_HRST 0xc0000502 + /* AMD Last Branch Record MSRs */ #define MSR_AMD64_LBR_SELECT 0xc000010e @@ -831,6 +837,7 @@ #define MSR_K7_HWCR_SMMLOCK BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT) #define MSR_K7_HWCR_IRPERF_EN_BIT 30 #define MSR_K7_HWCR_IRPERF_EN BIT_ULL(MSR_K7_HWCR_IRPERF_EN_BIT) +#define MSR_K7_HWCR_CPUID_USER_DIS_BIT 35 #define MSR_K7_FID_VID_CTL 0xc0010041 #define MSR_K7_FID_VID_STATUS 0xc0010042 #define MSR_K7_HWCR_CPB_DIS_BIT 25 From 14ec8ce45611c767656e4fa575f17b05344aa80a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0289/1292] tools headers: Sync arm64 headers with the kernel source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To pick up the changes in this cset: efe676a1a7554219 arm64: proton-pack: Add new CPUs 'k' values for branch mitigation e18c09b204e81702 arm64: Add support for HIP09 Spectre-BHB mitigation a9b5bd81b294d30a arm64: cputype: Add MIDR_CORTEX_A76AE 53a52a0ec7680287 arm64: cputype: Add comments about Qualcomm Kryo 5XX and 6XX cores 401c3333bb2396aa arm64: cputype: Add QCOM_CPU_PART_KRYO_3XX_GOLD 86edf6bdcf0571c0 smccc/kvm_guest: Enable errata based on implementation CPUs 0bc9a9e85fcf4ffb KVM: arm64: Work around x1e's CNTVOFF_EL2 bogosity This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/arch/arm64/include/asm/cputype.h arch/arm64/include/asm/cputype.h But the following two changes cannot be applied since they introduced new build errors in util/arm-spe.c. So it still has the warning after this change. c8c2647e69bedf80 arm64: Make Ā _midr_in_range_list() an exported function e3121298c7fcaf48 arm64: Modify _midr_range() functions to read MIDR/REVIDR internally Please see tools/include/uapi/README for further details. Cc: Catalin Marinas Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Namhyung Kim perf build: [WIP] Fix arm-spe build errors Signed-off-by: Namhyung Kim --- tools/arch/arm64/include/asm/cputype.h | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tools/arch/arm64/include/asm/cputype.h b/tools/arch/arm64/include/asm/cputype.h index 9a5d85cfd1fba6..139d5e87dc9593 100644 --- a/tools/arch/arm64/include/asm/cputype.h +++ b/tools/arch/arm64/include/asm/cputype.h @@ -75,11 +75,13 @@ #define ARM_CPU_PART_CORTEX_A76 0xD0B #define ARM_CPU_PART_NEOVERSE_N1 0xD0C #define ARM_CPU_PART_CORTEX_A77 0xD0D +#define ARM_CPU_PART_CORTEX_A76AE 0xD0E #define ARM_CPU_PART_NEOVERSE_V1 0xD40 #define ARM_CPU_PART_CORTEX_A78 0xD41 #define ARM_CPU_PART_CORTEX_A78AE 0xD42 #define ARM_CPU_PART_CORTEX_X1 0xD44 #define ARM_CPU_PART_CORTEX_A510 0xD46 +#define ARM_CPU_PART_CORTEX_X1C 0xD4C #define ARM_CPU_PART_CORTEX_A520 0xD80 #define ARM_CPU_PART_CORTEX_A710 0xD47 #define ARM_CPU_PART_CORTEX_A715 0xD4D @@ -119,9 +121,11 @@ #define QCOM_CPU_PART_KRYO 0x200 #define QCOM_CPU_PART_KRYO_2XX_GOLD 0x800 #define QCOM_CPU_PART_KRYO_2XX_SILVER 0x801 +#define QCOM_CPU_PART_KRYO_3XX_GOLD 0x802 #define QCOM_CPU_PART_KRYO_3XX_SILVER 0x803 #define QCOM_CPU_PART_KRYO_4XX_GOLD 0x804 #define QCOM_CPU_PART_KRYO_4XX_SILVER 0x805 +#define QCOM_CPU_PART_ORYON_X1 0x001 #define NVIDIA_CPU_PART_DENVER 0x003 #define NVIDIA_CPU_PART_CARMEL 0x004 @@ -129,6 +133,7 @@ #define FUJITSU_CPU_PART_A64FX 0x001 #define HISI_CPU_PART_TSV110 0xD01 +#define HISI_CPU_PART_HIP09 0xD02 #define HISI_CPU_PART_HIP12 0xD06 #define APPLE_CPU_PART_M1_ICESTORM 0x022 @@ -159,11 +164,13 @@ #define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76) #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1) #define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77) +#define MIDR_CORTEX_A76AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76AE) #define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1) #define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78) #define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE) #define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1) #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510) +#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C) #define MIDR_CORTEX_A520 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A520) #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710) #define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715) @@ -196,13 +203,26 @@ #define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) #define MIDR_QCOM_KRYO_2XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_GOLD) #define MIDR_QCOM_KRYO_2XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_SILVER) +#define MIDR_QCOM_KRYO_3XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_GOLD) #define MIDR_QCOM_KRYO_3XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_SILVER) #define MIDR_QCOM_KRYO_4XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_GOLD) #define MIDR_QCOM_KRYO_4XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_SILVER) +#define MIDR_QCOM_ORYON_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_ORYON_X1) + +/* + * NOTES: + * - Qualcomm Kryo 5XX Prime / Gold ID themselves as MIDR_CORTEX_A77 + * - Qualcomm Kryo 5XX Silver IDs itself as MIDR_QCOM_KRYO_4XX_SILVER + * - Qualcomm Kryo 6XX Prime IDs itself as MIDR_CORTEX_X1 + * - Qualcomm Kryo 6XX Gold IDs itself as ARM_CPU_PART_CORTEX_A78 + * - Qualcomm Kryo 6XX Silver IDs itself as MIDR_CORTEX_A55 + */ + #define MIDR_NVIDIA_DENVER MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER) #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL) #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX) #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110) +#define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09) #define MIDR_HISI_HIP12 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP12) #define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) #define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) @@ -291,6 +311,14 @@ static inline u32 __attribute_const__ read_cpuid_id(void) return read_cpuid(MIDR_EL1); } +struct target_impl_cpu { + u64 midr; + u64 revidr; + u64 aidr; +}; + +bool cpu_errata_set_target_impl(u64 num, void *impl_cpus); + static inline u64 __attribute_const__ read_cpuid_mpidr(void) { return read_cpuid(MPIDR_EL1); From c85538c4e3c7111958057d15ea8ee444116891c3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0290/1292] tools headers: Sync powerpc headers with the kernel source To pick up the changes in this cset: 69bf2053608423cb powerpc: Drop GPL boilerplate text with obsolete FSF address This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/arch/powerpc/include/uapi/asm/kvm.h arch/powerpc/include/uapi/asm/kvm.h Please see tools/include/uapi/README for further details. Cc: Madhavan Srinivasan Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Namhyung Kim --- tools/arch/powerpc/include/uapi/asm/kvm.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h index eaeda001784ebb..077c5437f5219b 100644 --- a/tools/arch/powerpc/include/uapi/asm/kvm.h +++ b/tools/arch/powerpc/include/uapi/asm/kvm.h @@ -1,18 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * * Copyright IBM Corp. 2007 * * Authors: Hollis Blanchard From 52174e0eb13876654f56701c26a672890aa5e7e3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0291/1292] tools headers: Sync syscall tables with the kernel source To pick up the changes in this cset: be7efb2d20d67f33 fs: introduce file_getattr and file_setattr syscalls This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/include/uapi/asm-generic/unistd.h include/uapi/asm-generic/unistd.h diff -u tools/scripts/syscall.tbl scripts/syscall.tbl diff -u tools/perf/arch/x86/entry/syscalls/syscall_32.tbl arch/x86/entry/syscalls/syscall_32.tbl diff -u tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl diff -u tools/perf/arch/powerpc/entry/syscalls/syscall.tbl arch/powerpc/kernel/syscalls/syscall.tbl diff -u tools/perf/arch/s390/entry/syscalls/syscall.tbl arch/s390/kernel/syscalls/syscall.tbl diff -u tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl arch/mips/kernel/syscalls/syscall_n64.tbl diff -u tools/perf/arch/arm/entry/syscalls/syscall.tbl arch/arm/tools/syscall.tbl diff -u tools/perf/arch/sh/entry/syscalls/syscall.tbl arch/sh/kernel/syscalls/syscall.tbl diff -u tools/perf/arch/sparc/entry/syscalls/syscall.tbl arch/sparc/kernel/syscalls/syscall.tbl diff -u tools/perf/arch/xtensa/entry/syscalls/syscall.tbl arch/xtensa/kernel/syscalls/syscall.tbl Please see tools/include/uapi/README for further details. Cc: Arnd Bergmann CC: linux-api@vger.kernel.org Signed-off-by: Namhyung Kim --- tools/include/uapi/asm-generic/unistd.h | 8 +++++++- tools/perf/arch/arm/entry/syscalls/syscall.tbl | 2 ++ tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl | 2 ++ tools/perf/arch/powerpc/entry/syscalls/syscall.tbl | 2 ++ tools/perf/arch/s390/entry/syscalls/syscall.tbl | 2 ++ tools/perf/arch/sh/entry/syscalls/syscall.tbl | 2 ++ tools/perf/arch/sparc/entry/syscalls/syscall.tbl | 2 ++ tools/perf/arch/x86/entry/syscalls/syscall_32.tbl | 2 ++ tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | 2 ++ tools/perf/arch/xtensa/entry/syscalls/syscall.tbl | 2 ++ tools/scripts/syscall.tbl | 2 ++ 11 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index 2892a45023af6d..04e0077fb4c97a 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -852,8 +852,14 @@ __SYSCALL(__NR_removexattrat, sys_removexattrat) #define __NR_open_tree_attr 467 __SYSCALL(__NR_open_tree_attr, sys_open_tree_attr) +/* fs/inode.c */ +#define __NR_file_getattr 468 +__SYSCALL(__NR_file_getattr, sys_file_getattr) +#define __NR_file_setattr 469 +__SYSCALL(__NR_file_setattr, sys_file_setattr) + #undef __NR_syscalls -#define __NR_syscalls 468 +#define __NR_syscalls 470 /* * 32 bit systems traditionally used different diff --git a/tools/perf/arch/arm/entry/syscalls/syscall.tbl b/tools/perf/arch/arm/entry/syscalls/syscall.tbl index 27c1d5ebcd91c8..b07e699aaa3c28 100644 --- a/tools/perf/arch/arm/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/arm/entry/syscalls/syscall.tbl @@ -482,3 +482,5 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr diff --git a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl index 1e8c44c7b61492..7a7049c2c30788 100644 --- a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl +++ b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl @@ -382,3 +382,5 @@ 465 n64 listxattrat sys_listxattrat 466 n64 removexattrat sys_removexattrat 467 n64 open_tree_attr sys_open_tree_attr +468 n64 file_getattr sys_file_getattr +469 n64 file_setattr sys_file_setattr diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl index 9a084bdb892694..b453e80dfc0037 100644 --- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl @@ -558,3 +558,5 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl index a4569b96ef06c5..8a6744d658db39 100644 --- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl @@ -470,3 +470,5 @@ 465 common listxattrat sys_listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr sys_file_setattr diff --git a/tools/perf/arch/sh/entry/syscalls/syscall.tbl b/tools/perf/arch/sh/entry/syscalls/syscall.tbl index 52a7652fcff639..5e9c9eff5539e2 100644 --- a/tools/perf/arch/sh/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/sh/entry/syscalls/syscall.tbl @@ -471,3 +471,5 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr diff --git a/tools/perf/arch/sparc/entry/syscalls/syscall.tbl b/tools/perf/arch/sparc/entry/syscalls/syscall.tbl index 83e45eb6c095a3..ebb7d06d1044fa 100644 --- a/tools/perf/arch/sparc/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/sparc/entry/syscalls/syscall.tbl @@ -513,3 +513,5 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl index ac007ea00979dc..4877e16da69a50 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl @@ -473,3 +473,5 @@ 465 i386 listxattrat sys_listxattrat 466 i386 removexattrat sys_removexattrat 467 i386 open_tree_attr sys_open_tree_attr +468 i386 file_getattr sys_file_getattr +469 i386 file_setattr sys_file_setattr diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index cfb5ca41e30de1..92cf0fe2291eb9 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl @@ -391,6 +391,8 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr # # Due to a historical design error, certain syscalls are numbered differently diff --git a/tools/perf/arch/xtensa/entry/syscalls/syscall.tbl b/tools/perf/arch/xtensa/entry/syscalls/syscall.tbl index f657a77314f866..374e4cb788d8a6 100644 --- a/tools/perf/arch/xtensa/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/xtensa/entry/syscalls/syscall.tbl @@ -438,3 +438,5 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr diff --git a/tools/scripts/syscall.tbl b/tools/scripts/syscall.tbl index 580b4e246aecd5..d1ae5e92c615b5 100644 --- a/tools/scripts/syscall.tbl +++ b/tools/scripts/syscall.tbl @@ -408,3 +408,5 @@ 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat 467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr From b18aabe283a10774977d698c075d2296a2336aef Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0292/1292] tools headers: Sync uapi/linux/fcntl.h with the kernel source To pick up the changes in this cset: 3941e37f62fe2c3c uapi/fcntl: add FD_PIDFS_ROOT cd5d2006327b6d84 uapi/fcntl: add FD_INVALID 67fcec2919e4ed31 fcntl/pidfd: redefine PIDFD_SELF_THREAD_GROUP a4c746f06853f91d uapi/fcntl: mark range as reserved This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/perf/trace/beauty/include/uapi/linux/fcntl.h include/uapi/linux/fcntl.h Please see tools/include/uapi/README for further details. Cc: Christian Brauner Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Namhyung Kim --- .../trace/beauty/include/uapi/linux/fcntl.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/perf/trace/beauty/include/uapi/linux/fcntl.h b/tools/perf/trace/beauty/include/uapi/linux/fcntl.h index a15ac2fa4b202f..f291ab4f94ebcc 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/fcntl.h +++ b/tools/perf/trace/beauty/include/uapi/linux/fcntl.h @@ -90,10 +90,28 @@ #define DN_ATTRIB 0x00000020 /* File changed attibutes */ #define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ +/* Reserved kernel ranges [-100], [-10000, -40000]. */ #define AT_FDCWD -100 /* Special value for dirfd used to indicate openat should use the current working directory. */ +/* + * The concept of process and threads in userland and the kernel is a confusing + * one - within the kernel every thread is a 'task' with its own individual PID, + * however from userland's point of view threads are grouped by a single PID, + * which is that of the 'thread group leader', typically the first thread + * spawned. + * + * To cut the Gideon knot, for internal kernel usage, we refer to + * PIDFD_SELF_THREAD to refer to the current thread (or task from a kernel + * perspective), and PIDFD_SELF_THREAD_GROUP to refer to the current thread + * group leader... + */ +#define PIDFD_SELF_THREAD -10000 /* Current thread. */ +#define PIDFD_SELF_THREAD_GROUP -10001 /* Current thread group leader. */ + +#define FD_PIDFS_ROOT -10002 /* Root of the pidfs filesystem */ +#define FD_INVALID -10009 /* Invalid file descriptor: -10000 - EBADF = -10009 */ /* Generic flags for the *at(2) family of syscalls. */ From 4a4083af03a7a75a86c392fd60cb37ce23ed87b6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0293/1292] tools headers: Sync uapi/linux/fs.h with the kernel source To pick up the changes in this cset: 76fdb7eb4e1c9108 uapi: export PROCFS_ROOT_INO ca115d7e754691c0 tree-wide: s/struct fileattr/struct file_kattr/g be7efb2d20d67f33 fs: introduce file_getattr and file_setattr syscalls 9eb22f7fedfc9eb1 fs: add ioctl to query metadata and protection info capabilities This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/perf/trace/beauty/include/uapi/linux/fs.h include/uapi/linux/fs.h Please see tools/include/uapi/README for further details. Cc: Christian Brauner Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Namhyung Kim --- .../perf/trace/beauty/include/uapi/linux/fs.h | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tools/perf/trace/beauty/include/uapi/linux/fs.h b/tools/perf/trace/beauty/include/uapi/linux/fs.h index 0098b0ce8ccb1f..0bd678a4a10ef8 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/fs.h +++ b/tools/perf/trace/beauty/include/uapi/linux/fs.h @@ -60,6 +60,17 @@ #define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ #define RENAME_WHITEOUT (1 << 2) /* Whiteout source */ +/* + * The root inode of procfs is guaranteed to always have the same inode number. + * For programs that make heavy use of procfs, verifying that the root is a + * real procfs root and using openat2(RESOLVE_{NO_{XDEV,MAGICLINKS},BENEATH}) + * will allow you to make sure you are never tricked into operating on the + * wrong procfs file. + */ +enum procfs_ino { + PROCFS_ROOT_INO = 1, +}; + struct file_clone_range { __s64 src_fd; __u64 src_offset; @@ -91,6 +102,63 @@ struct fs_sysfs_path { __u8 name[128]; }; +/* Protection info capability flags */ +#define LBMD_PI_CAP_INTEGRITY (1 << 0) +#define LBMD_PI_CAP_REFTAG (1 << 1) + +/* Checksum types for Protection Information */ +#define LBMD_PI_CSUM_NONE 0 +#define LBMD_PI_CSUM_IP 1 +#define LBMD_PI_CSUM_CRC16_T10DIF 2 +#define LBMD_PI_CSUM_CRC64_NVME 4 + +/* sizeof first published struct */ +#define LBMD_SIZE_VER0 16 + +/* + * Logical block metadata capability descriptor + * If the device does not support metadata, all the fields will be zero. + * Applications must check lbmd_flags to determine whether metadata is + * supported or not. + */ +struct logical_block_metadata_cap { + /* Bitmask of logical block metadata capability flags */ + __u32 lbmd_flags; + /* + * The amount of data described by each unit of logical block + * metadata + */ + __u16 lbmd_interval; + /* + * Size in bytes of the logical block metadata associated with each + * interval + */ + __u8 lbmd_size; + /* + * Size in bytes of the opaque block tag associated with each + * interval + */ + __u8 lbmd_opaque_size; + /* + * Offset in bytes of the opaque block tag within the logical block + * metadata + */ + __u8 lbmd_opaque_offset; + /* Size in bytes of the T10 PI tuple associated with each interval */ + __u8 lbmd_pi_size; + /* Offset in bytes of T10 PI tuple within the logical block metadata */ + __u8 lbmd_pi_offset; + /* T10 PI guard tag type */ + __u8 lbmd_guard_tag_type; + /* Size in bytes of the T10 PI application tag */ + __u8 lbmd_app_tag_size; + /* Size in bytes of the T10 PI reference tag */ + __u8 lbmd_ref_tag_size; + /* Size in bytes of the T10 PI storage tag */ + __u8 lbmd_storage_tag_size; + __u8 pad; +}; + /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */ #define FILE_DEDUPE_RANGE_SAME 0 #define FILE_DEDUPE_RANGE_DIFFERS 1 @@ -148,6 +216,24 @@ struct fsxattr { unsigned char fsx_pad[8]; }; +/* + * Variable size structure for file_[sg]et_attr(). + * + * Note. This is alternative to the structure 'struct file_kattr'/'struct fsxattr'. + * As this structure is passed to/from userspace with its size, this can + * be versioned based on the size. + */ +struct file_attr { + __u64 fa_xflags; /* xflags field value (get/set) */ + __u32 fa_extsize; /* extsize field value (get/set)*/ + __u32 fa_nextents; /* nextents field value (get) */ + __u32 fa_projid; /* project identifier (get/set) */ + __u32 fa_cowextsize; /* CoW extsize field value (get/set) */ +}; + +#define FILE_ATTR_SIZE_VER0 24 +#define FILE_ATTR_SIZE_LATEST FILE_ATTR_SIZE_VER0 + /* * Flags for the fsx_xflags field */ @@ -247,6 +333,8 @@ struct fsxattr { * also /sys/kernel/debug/ for filesystems with debugfs exports */ #define FS_IOC_GETFSSYSFSPATH _IOR(0x15, 1, struct fs_sysfs_path) +/* Get logical block metadata capability details */ +#define FS_IOC_GETLBMD_CAP _IOWR(0x15, 2, struct logical_block_metadata_cap) /* * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS) From e7e79e99726190a5a83d158576cd448896d68102 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0294/1292] tools headers: Sync uapi/linux/prctl.h with the kernel source To pick up the changes in this cset: b1fabef37bd504f3 prctl: Introduce PR_MTE_STORE_ONLY a2fc422ed75748ee syscall_user_dispatch: Add PR_SYS_DISPATCH_INCLUSIVE_ON This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/perf/trace/beauty/include/uapi/linux/prctl.h include/uapi/linux/prctl.h Please see tools/include/uapi/README for further details. Signed-off-by: Namhyung Kim --- tools/perf/trace/beauty/include/uapi/linux/prctl.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/perf/trace/beauty/include/uapi/linux/prctl.h b/tools/perf/trace/beauty/include/uapi/linux/prctl.h index 3b93fb906e3c51..ed3aed264aeb28 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/prctl.h +++ b/tools/perf/trace/beauty/include/uapi/linux/prctl.h @@ -244,6 +244,8 @@ struct prctl_mm_map { # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) /* Unused; kept only for source compatibility */ # define PR_MTE_TCF_SHIFT 1 +/* MTE tag check store only */ +# define PR_MTE_STORE_ONLY (1UL << 19) /* RISC-V pointer masking tag length */ # define PR_PMLEN_SHIFT 24 # define PR_PMLEN_MASK (0x7fUL << PR_PMLEN_SHIFT) @@ -255,7 +257,12 @@ struct prctl_mm_map { /* Dispatch syscalls to a userspace handler */ #define PR_SET_SYSCALL_USER_DISPATCH 59 # define PR_SYS_DISPATCH_OFF 0 -# define PR_SYS_DISPATCH_ON 1 +/* Enable dispatch except for the specified range */ +# define PR_SYS_DISPATCH_EXCLUSIVE_ON 1 +/* Enable dispatch for the specified range */ +# define PR_SYS_DISPATCH_INCLUSIVE_ON 2 +/* Legacy name for backwards compatibility */ +# define PR_SYS_DISPATCH_ON PR_SYS_DISPATCH_EXCLUSIVE_ON /* The control values for the user space selector when dispatch is enabled */ # define SYSCALL_DISPATCH_FILTER_ALLOW 0 # define SYSCALL_DISPATCH_FILTER_BLOCK 1 From f79a62f4b3c750759e60a402e8fe5180fc5771f0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 10:32:18 -0700 Subject: [PATCH 0295/1292] tools headers: Sync uapi/linux/vhost.h with the kernel source To pick up the changes in this cset: 7d9896e9f6d02d8a vhost: Reintroduce kthread API and add mode selection 333c515d189657c9 vhost-net: allow configuring extended features This addresses these perf build warnings: Warning: Kernel ABI header differences: diff -u tools/perf/trace/beauty/include/uapi/linux/vhost.h include/uapi/linux/vhost.h Please see tools/include/uapi/README for further details. Cc: "Michael S. Tsirkin" Cc: Jason Wang Cc: kvm@vger.kernel.org Cc: virtualization@lists.linux.dev Signed-off-by: Namhyung Kim --- .../trace/beauty/include/uapi/linux/vhost.h | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tools/perf/trace/beauty/include/uapi/linux/vhost.h b/tools/perf/trace/beauty/include/uapi/linux/vhost.h index d4b3e2ae1314d1..c57674a6aa0dbb 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/vhost.h +++ b/tools/perf/trace/beauty/include/uapi/linux/vhost.h @@ -235,4 +235,39 @@ */ #define VHOST_VDPA_GET_VRING_SIZE _IOWR(VHOST_VIRTIO, 0x82, \ struct vhost_vring_state) + +/* Extended features manipulation */ +#define VHOST_GET_FEATURES_ARRAY _IOR(VHOST_VIRTIO, 0x83, \ + struct vhost_features_array) +#define VHOST_SET_FEATURES_ARRAY _IOW(VHOST_VIRTIO, 0x83, \ + struct vhost_features_array) + +/* fork_owner values for vhost */ +#define VHOST_FORK_OWNER_KTHREAD 0 +#define VHOST_FORK_OWNER_TASK 1 + +/** + * VHOST_SET_FORK_FROM_OWNER - Set the fork_owner flag for the vhost device, + * This ioctl must called before VHOST_SET_OWNER. + * Only available when CONFIG_VHOST_ENABLE_FORK_OWNER_CONTROL=y + * + * @param fork_owner: An 8-bit value that determines the vhost thread mode + * + * When fork_owner is set to VHOST_FORK_OWNER_TASK(default value): + * - Vhost will create vhost worker as tasks forked from the owner, + * inheriting all of the owner's attributes. + * + * When fork_owner is set to VHOST_FORK_OWNER_KTHREAD: + * - Vhost will create vhost workers as kernel threads. + */ +#define VHOST_SET_FORK_FROM_OWNER _IOW(VHOST_VIRTIO, 0x84, __u8) + +/** + * VHOST_GET_FORK_OWNER - Get the current fork_owner flag for the vhost device. + * Only available when CONFIG_VHOST_ENABLE_FORK_OWNER_CONTROL=y + * + * @return: An 8-bit value indicating the current thread mode. + */ +#define VHOST_GET_FORK_FROM_OWNER _IOR(VHOST_VIRTIO, 0x85, __u8) + #endif From 923fcb3dbc0246fc5207093c0049af4c56f20e41 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Mon, 11 Aug 2025 16:30:39 -0400 Subject: [PATCH 0296/1292] KVM: SEV: don't check have_run_cpus in sev_writeback_caches() Drop KVM's check on an empty cpumask when flushing caches when memory is being reclaimed from an SEV VM, as smp_call_function_many_cond() naturally (and correctly) handles an empty cpumask. This avoids an extra O(n) lookup in the common case where at least one pCPU has enterred the guest, which could be noticeable in some setups, e.g. if a small VM is pinned to the last few pCPUs in the system. Fixes: 6f38f8c57464 ("KVM: SVM: Flush cache only on CPUs running SEV guest") Signed-off-by: Yury Norov (NVIDIA) [sean: rewrite changelog to capture performance angle] Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 2fbdebf79fbb24..0635bd71c10e78 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -718,13 +718,6 @@ static void sev_clflush_pages(struct page *pages[], unsigned long npages) static void sev_writeback_caches(struct kvm *kvm) { - /* - * Note, the caller is responsible for ensuring correctness if the mask - * can be modified, e.g. if a CPU could be doing VMRUN. - */ - if (cpumask_empty(to_kvm_sev_info(kvm)->have_run_cpus)) - return; - /* * Ensure that all dirty guest tagged cache entries are written back * before releasing the pages back to the system for use. CLFLUSH will @@ -739,6 +732,9 @@ static void sev_writeback_caches(struct kvm *kvm) * serializing multiple calls and having responding CPUs (to the IPI) * mark themselves as still running if they are running (or about to * run) a vCPU for the VM. + * + * Note, the caller is responsible for ensuring correctness if the mask + * can be modified, e.g. if a CPU could be doing VMRUN. */ wbnoinvd_on_cpus_mask(to_kvm_sev_info(kvm)->have_run_cpus); } From 0aa86640ebd98d77fb64acef5684e42fba517d2d Mon Sep 17 00:00:00 2001 From: Gabe Teeger Date: Wed, 9 Jul 2025 14:12:22 -0400 Subject: [PATCH 0297/1292] drm/amd/display: Revert Add HPO encoder support to Replay This reverts commits: commit 1f26214d268b ("drm/amd/display: Add HPO encoder support to Replay") commit 3bfce48b109f ("drm/amd/display: Add support for Panel Replay on DP1 eDP (panel_inst=1)") due to visual confirm issue. Reviewed-by: Nicholas Kazlauskas Signed-off-by: Gabe Teeger Signed-off-by: Wayne Lin Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 92f68f6a1b297633159a3f3759e4dfc7e5b58abb) --- .../gpu/drm/amd/display/dc/dce/dmub_replay.c | 43 ++----------------- .../gpu/drm/amd/display/dc/dce/dmub_replay.h | 2 +- .../link/protocols/link_edp_panel_control.c | 2 +- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 20 --------- 4 files changed, 5 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c index e7a318e26d38ac..fcd3d86ad5173a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c @@ -4,7 +4,6 @@ #include "dc.h" #include "dc_dmub_srv.h" -#include "dc_dp_types.h" #include "dmub/dmub_srv.h" #include "core_types.h" #include "dmub_replay.h" @@ -44,45 +43,21 @@ static void dmub_replay_get_state(struct dmub_replay *dmub, enum replay_state *s /* * Enable/Disable Replay. */ -static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, uint8_t panel_inst, - struct dc_link *link) +static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, uint8_t panel_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = dmub->ctx; uint32_t retry_count; enum replay_state state = REPLAY_STATE_0; - struct pipe_ctx *pipe_ctx = NULL; - struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx; - uint8_t i; memset(&cmd, 0, sizeof(cmd)); cmd.replay_enable.header.type = DMUB_CMD__REPLAY; cmd.replay_enable.data.panel_inst = panel_inst; cmd.replay_enable.header.sub_type = DMUB_CMD__REPLAY_ENABLE; - if (enable) { + if (enable) cmd.replay_enable.data.enable = REPLAY_ENABLE; - // hpo stream/link encoder assignments are not static, need to update everytime we try to enable replay - if (link->cur_link_settings.link_rate >= LINK_RATE_UHBR10) { - for (i = 0; i < MAX_PIPES; i++) { - if (res_ctx && - res_ctx->pipe_ctx[i].stream && - res_ctx->pipe_ctx[i].stream->link && - res_ctx->pipe_ctx[i].stream->link == link && - res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { - pipe_ctx = &res_ctx->pipe_ctx[i]; - //TODO: refactor for multi edp support - break; - } - } - - if (!pipe_ctx) - return; - - cmd.replay_enable.data.hpo_stream_enc_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; - cmd.replay_enable.data.hpo_link_enc_inst = pipe_ctx->link_res.hpo_dp_link_enc->inst; - } - } else + else cmd.replay_enable.data.enable = REPLAY_DISABLE; cmd.replay_enable.header.payload_bytes = sizeof(struct dmub_rb_cmd_replay_enable_data); @@ -174,17 +149,6 @@ static bool dmub_replay_copy_settings(struct dmub_replay *dmub, copy_settings_data->digbe_inst = replay_context->digbe_inst; copy_settings_data->digfe_inst = replay_context->digfe_inst; - if (link->cur_link_settings.link_rate >= LINK_RATE_UHBR10) { - if (pipe_ctx->stream_res.hpo_dp_stream_enc) - copy_settings_data->hpo_stream_enc_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; - else - copy_settings_data->hpo_stream_enc_inst = 0; - if (pipe_ctx->link_res.hpo_dp_link_enc) - copy_settings_data->hpo_link_enc_inst = pipe_ctx->link_res.hpo_dp_link_enc->inst; - else - copy_settings_data->hpo_link_enc_inst = 0; - } - if (pipe_ctx->plane_res.dpp) copy_settings_data->dpp_inst = pipe_ctx->plane_res.dpp->inst; else @@ -247,7 +211,6 @@ static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub, pCmd->header.type = DMUB_CMD__REPLAY; pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_COASTING_VTOTAL; pCmd->header.payload_bytes = sizeof(struct dmub_cmd_replay_set_coasting_vtotal_data); - pCmd->replay_set_coasting_vtotal_data.panel_inst = panel_inst; pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF); pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h index ccbe385e132c47..e6346c0ffc0e44 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h @@ -19,7 +19,7 @@ struct dmub_replay_funcs { void (*replay_get_state)(struct dmub_replay *dmub, enum replay_state *state, uint8_t panel_inst); void (*replay_enable)(struct dmub_replay *dmub, bool enable, bool wait, - uint8_t panel_inst, struct dc_link *link); + uint8_t panel_inst); bool (*replay_copy_settings)(struct dmub_replay *dmub, struct dc_link *link, struct replay_context *replay_context, uint8_t panel_inst); void (*replay_set_power_opt)(struct dmub_replay *dmub, unsigned int power_opt, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index e7927b8f5ba351..98ec9b5a559c80 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -944,7 +944,7 @@ bool edp_set_replay_allow_active(struct dc_link *link, const bool *allow_active, // TODO: Handle mux change case if force_static is set // If force_static is set, just change the replay_allow_active state directly if (replay != NULL && link->replay_settings.replay_feature_enabled) - replay->funcs->replay_enable(replay, *allow_active, wait, panel_inst, link); + replay->funcs->replay_enable(replay, *allow_active, wait, panel_inst); link->replay_settings.replay_allow_active = *allow_active; } diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index c587b3441e0709..6a69a788abe801 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -4047,14 +4047,6 @@ struct dmub_cmd_replay_copy_settings_data { * DIG BE HW instance. */ uint8_t digbe_inst; - /** - * @hpo_stream_enc_inst: HPO stream encoder instance - */ - uint8_t hpo_stream_enc_inst; - /** - * @hpo_link_enc_inst: HPO link encoder instance - */ - uint8_t hpo_link_enc_inst; /** * AUX HW instance. */ @@ -4159,18 +4151,6 @@ struct dmub_rb_cmd_replay_enable_data { * This does not support HDMI/DP2 for now. */ uint8_t phy_rate; - /** - * @hpo_stream_enc_inst: HPO stream encoder instance - */ - uint8_t hpo_stream_enc_inst; - /** - * @hpo_link_enc_inst: HPO link encoder instance - */ - uint8_t hpo_link_enc_inst; - /** - * @pad: Align structure to 4 byte boundary. - */ - uint8_t pad[2]; }; /** From 79e25cd06e85105c75701ef1773c6c64bb304091 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 8 Aug 2025 13:12:07 -0400 Subject: [PATCH 0298/1292] drm/amdgpu/swm14: Update power limit logic Take into account the limits from the vbios. Ported from the SMU13 code. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4352 Reviewed-by: Jesse Zhang Reviewed-by: Kenneth Feng Signed-off-by: Alex Deucher (cherry picked from commit 203cc7f1dd86f2c8de5c3c6182f19adac7c9c206) Cc: stable@vger.kernel.org --- .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 3aea32baea3da2..f32474af90b340 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -1697,9 +1697,11 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, uint32_t *min_power_limit) { struct smu_table_context *table_context = &smu->smu_table; + struct smu_14_0_2_powerplay_table *powerplay_table = + table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; CustomSkuTable_t *skutable = &pptable->CustomSkuTable; - uint32_t power_limit; + uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; if (smu_v14_0_get_current_power_limit(smu, &power_limit)) @@ -1712,11 +1714,29 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, if (default_power_limit) *default_power_limit = power_limit; - if (max_power_limit) - *max_power_limit = msg_limit; + if (powerplay_table) { + if (smu->od_enabled && + smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) { + od_percent_upper = pptable->SkuTable.OverDriveLimitsBasicMax.Ppt; + od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt; + } else if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) { + od_percent_upper = 0; + od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt; + } + } + + dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n", + od_percent_upper, od_percent_lower, power_limit); + + if (max_power_limit) { + *max_power_limit = msg_limit * (100 + od_percent_upper); + *max_power_limit /= 100; + } - if (min_power_limit) - *min_power_limit = 0; + if (min_power_limit) { + *min_power_limit = power_limit * (100 + od_percent_lower); + *min_power_limit /= 100; + } return 0; } From 07b93a5704b0b72002f0c4bd1076214af67dc661 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 24 Jul 2025 15:00:43 -0500 Subject: [PATCH 0299/1292] drm/amd/display: Avoid a NULL pointer dereference [WHY] Although unlikely drm_atomic_get_new_connector_state() or drm_atomic_get_old_connector_state() can return NULL. [HOW] Check returns before dereference. Cc: Mario Limonciello Cc: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Mario Limonciello Signed-off-by: Alex Hung Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 1e5e8d672fec9f2ab352be121be971877bff2af9) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index cd0e2976e268da..a0ca3b2c6bd878 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7792,6 +7792,9 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn, struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn); int ret; + if (WARN_ON(unlikely(!old_con_state || !new_con_state))) + return -EINVAL; + trace_amdgpu_dm_connector_atomic_check(new_con_state); if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { From 66af73a1c319336694a8610fe4c2943f7b33066c Mon Sep 17 00:00:00 2001 From: Tom Chung Date: Fri, 18 Jul 2025 18:25:08 +0800 Subject: [PATCH 0300/1292] drm/amd/display: Fix Xorg desktop unresponsive on Replay panel [WHY & HOW] IPS & self-fresh feature can cause vblank counter resets between vblank disable and enable. It may cause system stuck due to wait the vblank counter. Call the drm_crtc_vblank_restore() during vblank enable to estimate missed vblanks by using timestamps and update the vblank counter in DRM. It can make the vblank counter increase smoothly and resolve this issue. Cc: Mario Limonciello Cc: Alex Deucher Reviewed-by: Sun peng (Leo) Li Signed-off-by: Tom Chung Signed-off-by: Alex Hung Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 34d66bc7ff10e146a4cec76cf286979740a10954) Cc: stable@vger.kernel.org --- .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 010172f930aef9..45feb404b0979e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -299,6 +299,25 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable) irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id); if (enable) { + struct dc *dc = adev->dm.dc; + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); + struct psr_settings *psr = &acrtc_state->stream->link->psr_settings; + struct replay_settings *pr = &acrtc_state->stream->link->replay_settings; + bool sr_supported = (psr->psr_version != DC_PSR_VERSION_UNSUPPORTED) || + pr->config.replay_supported; + + /* + * IPS & self-refresh feature can cause vblank counter resets between + * vblank disable and enable. + * It may cause system stuck due to waiting for the vblank counter. + * Call this function to estimate missed vblanks by using timestamps and + * update the vblank counter in DRM. + */ + if (dc->caps.ips_support && + dc->config.disable_ips != DMUB_IPS_DISABLE_ALL && + sr_supported && vblank->config.disable_immediate) + drm_crtc_vblank_restore(crtc); + /* vblank irq on -> Only need vupdate irq in vrr mode */ if (amdgpu_dm_crtc_vrr_active(acrtc_state)) rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, true); From 7a2ca2ea64b1b63c8baa94a8f5deb70b2248d119 Mon Sep 17 00:00:00 2001 From: Chenyuan Yang Date: Wed, 23 Jul 2025 21:36:41 -0500 Subject: [PATCH 0301/1292] drm/amd/display: Add null pointer check in mod_hdcp_hdcp1_create_session() The function mod_hdcp_hdcp1_create_session() calls the function get_first_active_display(), but does not check its return value. The return value is a null pointer if the display list is empty. This will lead to a null pointer dereference. Add a null pointer check for get_first_active_display() and return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND if the function return null. This is similar to the commit c3e9826a2202 ("drm/amd/display: Add null pointer check for get_first_active_display()"). Fixes: 2deade5ede56 ("drm/amd/display: Remove hdcp display state with mst fix") Signed-off-by: Chenyuan Yang Reviewed-by: Alex Hung Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 5e43eb3cd731649c4f8b9134f857be62a416c893) --- drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index e58e7b93810be7..6b7db8ec9a53b2 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -260,6 +260,9 @@ enum mod_hdcp_status mod_hdcp_hdcp1_create_session(struct mod_hdcp *hdcp) return MOD_HDCP_STATUS_FAILURE; } + if (!display) + return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf; mutex_lock(&psp->hdcp_context.mutex); From cb7b7ae53b557d168b4af5cd8549f3eff920bfb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Thu, 31 Jul 2025 11:43:46 +0200 Subject: [PATCH 0302/1292] drm/amd/display: Don't overclock DCE 6 by 15% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extra 15% clock was added as a workaround for a Polaris issue which uses DCE 11, and should not have been used on DCE 6 which is already hardcoded to the highest possible display clock. Unfortunately, the extra 15% was mistakenly copied and kept even on code paths which don't affect Polaris. This commit fixes that and also adds a check to make sure not to exceed the maximum DCE 6 display clock. Fixes: 8cd61c313d8b ("drm/amd/display: Raise dispclk value for Polaris") Fixes: dc88b4a684d2 ("drm/amd/display: make clk mgr soc specific") Fixes: 3ecb3b794e2c ("drm/amd/display: dc/clk_mgr: add support for SI parts (v2)") Signed-off-by: Timur Kristóf Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 427980c1cbd22bb256b9385f5ce73c0937562408) Cc: stable@vger.kernel.org --- .../gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c index 0267644717b27a..cfd7309f2c6ace 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c @@ -123,11 +123,9 @@ static void dce60_update_clocks(struct clk_mgr *clk_mgr_base, { struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct dm_pp_power_level_change_request level_change_req; - int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz; - - /*TODO: W/A for dal3 linux, investigate why this works */ - if (!clk_mgr_dce->dfs_bypass_active) - patched_disp_clk = patched_disp_clk * 115 / 100; + const int max_disp_clk = + clk_mgr_dce->max_clks_by_state[DM_PP_CLOCKS_STATE_PERFORMANCE].display_clk_khz; + int patched_disp_clk = MIN(max_disp_clk, context->bw_ctx.bw.dce.dispclk_khz); level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context); /* get max clock state from PPLIB */ From 1fc931be2f47fde23ca5aff6f19421375c312fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Thu, 31 Jul 2025 11:43:47 +0200 Subject: [PATCH 0303/1292] drm/amd/display: Adjust DCE 8-10 clock, don't overclock by 15% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust the nominal (and performance) clocks for DCE 8-10, and set them to 625 MHz, which is the value used by the legacy display code in amdgpu_atombios_get_clock_info. This was tested with Hawaii, Tonga and Fiji. These GPUs can output 4K 60Hz (10-bit depth) at 625 MHz. The extra 15% clock was added as a workaround for a Polaris issue which uses DCE 11, and should not have been used on DCE 8-10 which are already hardcoded to the highest possible display clock. Unfortunately, the extra 15% was mistakenly copied and kept even on code paths which don't affect Polaris. This commit fixes that and also adds a check to make sure not to exceed the maximum DCE 8-10 display clock. Fixes: 8cd61c313d8b ("drm/amd/display: Raise dispclk value for Polaris") Fixes: dc88b4a684d2 ("drm/amd/display: make clk mgr soc specific") Signed-off-by: Timur Kristóf Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 1ae45b5d4f371af8ae51a3827d0ec9fe27eeb867) --- .../drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c index f5ad0a1770388c..a324dbd4543c65 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c @@ -72,9 +72,9 @@ static const struct state_dependent_clocks dce80_max_clks_by_state[] = { /* ClocksStateLow */ { .display_clk_khz = 352000, .pixel_clk_khz = 330000}, /* ClocksStateNominal */ -{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 }, +{ .display_clk_khz = 625000, .pixel_clk_khz = 400000 }, /* ClocksStatePerformance */ -{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } }; +{ .display_clk_khz = 625000, .pixel_clk_khz = 400000 } }; int dentist_get_divider_from_did(int did) { @@ -405,11 +405,9 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr_base, { struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct dm_pp_power_level_change_request level_change_req; - int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz; - - /*TODO: W/A for dal3 linux, investigate why this works */ - if (!clk_mgr_dce->dfs_bypass_active) - patched_disp_clk = patched_disp_clk * 115 / 100; + const int max_disp_clk = + clk_mgr_dce->max_clks_by_state[DM_PP_CLOCKS_STATE_PERFORMANCE].display_clk_khz; + int patched_disp_clk = MIN(max_disp_clk, context->bw_ctx.bw.dce.dispclk_khz); level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context); /* get max clock state from PPLIB */ From 669f73a26f6112eedbadac53a2f2707ac6d0b9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Thu, 31 Jul 2025 11:43:48 +0200 Subject: [PATCH 0304/1292] drm/amd/display: Find first CRTC and its line time in dce110_fill_display_configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dce110_fill_display_configs is shared between DCE 6-11, and finding the first CRTC and its line time is relevant to DCE 6 too. Move the code to find it from DCE 11 specific code. Signed-off-by: Timur Kristóf Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 4ab09785f8d5d03df052827af073d5c508ff5f63) Cc: stable@vger.kernel.org --- .../dc/clk_mgr/dce110/dce110_clk_mgr.c | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c index f8409453434c1c..baeac8f1c04f2a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c @@ -120,9 +120,12 @@ void dce110_fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg) { + struct dc *dc = context->clk_mgr->ctx->dc; int j; int num_cfgs = 0; + pp_display_cfg->crtc_index = dc->res_pool->res_cap->num_timing_generator; + for (j = 0; j < context->stream_count; j++) { int k; @@ -164,6 +167,23 @@ void dce110_fill_display_configs( cfg->v_refresh /= stream->timing.h_total; cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2) / stream->timing.v_total; + + /* Find first CRTC index and calculate its line time. + * This is necessary for DPM on SI GPUs. + */ + if (cfg->pipe_idx < pp_display_cfg->crtc_index) { + const struct dc_crtc_timing *timing = + &context->streams[0]->timing; + + pp_display_cfg->crtc_index = cfg->pipe_idx; + pp_display_cfg->line_time_in_us = + timing->h_total * 10000 / timing->pix_clk_100hz; + } + } + + if (!num_cfgs) { + pp_display_cfg->crtc_index = 0; + pp_display_cfg->line_time_in_us = 0; } pp_display_cfg->display_count = num_cfgs; @@ -232,16 +252,6 @@ void dce11_pplib_apply_display_requirements( dce110_fill_display_configs(context, pp_display_cfg); - /* TODO: is this still applicable?*/ - if (pp_display_cfg->display_count == 1) { - const struct dc_crtc_timing *timing = - &context->streams[0]->timing; - - pp_display_cfg->crtc_index = - pp_display_cfg->disp_configs[0].pipe_idx; - pp_display_cfg->line_time_in_us = timing->h_total * 10000 / timing->pix_clk_100hz; - } - if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0) dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg); } From 7d07140d37f792f01cfdb8ca9a6a792ab1d29126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Thu, 31 Jul 2025 11:43:49 +0200 Subject: [PATCH 0305/1292] drm/amd/display: Fill display clock and vblank time in dce110_fill_display_configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also needed by DCE 6. This way the code that gathers this info can be shared between different DCE versions and doesn't have to be repeated. Signed-off-by: Timur Kristóf Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 8107432dff37db26fcb641b6cebeae8981cd73a0) Cc: stable@vger.kernel.org --- .../drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c | 2 -- .../drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c | 10 +++------- .../drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c | 2 -- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c index a324dbd4543c65..dbd6ef1b60a0b7 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c @@ -391,8 +391,6 @@ static void dce_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context); - dce110_fill_display_configs(context, pp_display_cfg); if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c index baeac8f1c04f2a..13cf415e38e501 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c @@ -124,6 +124,9 @@ void dce110_fill_display_configs( int j; int num_cfgs = 0; + pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context); + pp_display_cfg->disp_clk_khz = dc->clk_mgr->clks.dispclk_khz; + pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0; pp_display_cfg->crtc_index = dc->res_pool->res_cap->num_timing_generator; for (j = 0; j < context->stream_count; j++) { @@ -243,13 +246,6 @@ void dce11_pplib_apply_display_requirements( pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw_ctx.bw.dce.sclk_deep_sleep_khz; - pp_display_cfg->avail_mclk_switch_time_us = - dce110_get_min_vblank_time_us(context); - /* TODO: dce11.2*/ - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0; - - pp_display_cfg->disp_clk_khz = dc->clk_mgr->clks.dispclk_khz; - dce110_fill_display_configs(context, pp_display_cfg); if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c index cfd7309f2c6ace..7044b437fe9d91 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c @@ -109,8 +109,6 @@ static void dce60_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context); - dce110_fill_display_configs(context, pp_display_cfg); if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0) From 8246147f1fbaed522b8bcc02ca34e4260747dcfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Thu, 31 Jul 2025 11:43:50 +0200 Subject: [PATCH 0306/1292] drm/amd/display: Don't warn when missing DCE encoder caps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some GPUs the VBIOS just doesn't have encoder caps, or maybe not for every encoder. This isn't really a problem and it's handled well, so let's not litter the logs with it. Signed-off-by: Timur Kristóf Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 33e0227ee96e62d034781e91f215e32fd0b1d512) --- drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 4a9d07c31bc5b1..0c50fe266c8a16 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -896,13 +896,13 @@ void dce110_link_encoder_construct( enc110->base.id, &bp_cap_info); /* Override features with DCE-specific values */ - if (BP_RESULT_OK == result) { + if (result == BP_RESULT_OK) { enc110->base.features.flags.bits.IS_HBR2_CAPABLE = bp_cap_info.DP_HBR2_EN; enc110->base.features.flags.bits.IS_HBR3_CAPABLE = bp_cap_info.DP_HBR3_EN; enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; - } else { + } else if (result != BP_RESULT_NORECORD) { DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", __func__, result); @@ -1798,13 +1798,13 @@ void dce60_link_encoder_construct( enc110->base.id, &bp_cap_info); /* Override features with DCE-specific values */ - if (BP_RESULT_OK == result) { + if (result == BP_RESULT_OK) { enc110->base.features.flags.bits.IS_HBR2_CAPABLE = bp_cap_info.DP_HBR2_EN; enc110->base.features.flags.bits.IS_HBR3_CAPABLE = bp_cap_info.DP_HBR3_EN; enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; - } else { + } else if (result != BP_RESULT_NORECORD) { DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", __func__, result); From f14ee2e7a86c5e57295b48b8e198cae7189b3b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Thu, 31 Jul 2025 11:43:51 +0200 Subject: [PATCH 0307/1292] drm/amd/display: Don't print errors for nonexistent connectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When getting the number of connectors, the VBIOS reports the number of valid indices, but it doesn't say which indices are valid, and not every valid index has an actual connector. If we don't find a connector on an index, that is not an error. Considering these are not actual errors, don't litter the logs. Fixes: 60df5628144b ("drm/amd/display: handle invalid connector indices") Signed-off-by: Timur Kristóf Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 249d4bc5f1935f04bb45b3b63c0f8922565124f7) --- drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 5 +---- drivers/gpu/drm/amd/display/dc/core/dc.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index 67f08495b7e6e2..154fd2c18e8848 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -174,11 +174,8 @@ static struct graphics_object_id bios_parser_get_connector_id( return object_id; } - if (tbl->ucNumberOfObjects <= i) { - dm_error("Can't find connector id %d in connector table of size %d.\n", - i, tbl->ucNumberOfObjects); + if (tbl->ucNumberOfObjects <= i) return object_id; - } id = le16_to_cpu(tbl->asObjects[i].usObjectID); object_id = object_id_from_bios_object_id(id); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 9ab0ee20ca6fe2..dcc48b5238e530 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -217,11 +217,24 @@ static bool create_links( connectors_num, num_virtual_links); - // condition loop on link_count to allow skipping invalid indices + /* When getting the number of connectors, the VBIOS reports the number of valid indices, + * but it doesn't say which indices are valid, and not every index has an actual connector. + * So, if we don't find a connector on an index, that is not an error. + * + * - There is no guarantee that the first N indices will be valid + * - VBIOS may report a higher amount of valid indices than there are actual connectors + * - Some VBIOS have valid configurations for more connectors than there actually are + * on the card. This may be because the manufacturer used the same VBIOS for different + * variants of the same card. + */ for (i = 0; dc->link_count < connectors_num && i < MAX_LINKS; i++) { + struct graphics_object_id connector_id = bios->funcs->get_connector_id(bios, i); struct link_init_data link_init_params = {0}; struct dc_link *link; + if (connector_id.id == CONNECTOR_ID_UNKNOWN) + continue; + DC_LOG_DC("BIOS object table - printing link object info for connector number: %d, link_index: %d", i, dc->link_count); link_init_params.ctx = dc->ctx; From 10507478468f165ea681605d133991ed05cdff62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Thu, 31 Jul 2025 11:43:52 +0200 Subject: [PATCH 0308/1292] drm/amd/display: Fix fractional fb divider in set_pixel_clock_v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For later VBIOS versions, the fractional feedback divider is calculated as the remainder of dividing the feedback divider by a factor, which is set to 1000000. For reference, see: - calculate_fb_and_fractional_fb_divider - calc_pll_max_vco_construct However, in case of old VBIOS versions that have set_pixel_clock_v3, they only have 1 byte available for the fractional feedback divider, and it's expected to be set to the remainder from dividing the feedback divider by 10. For reference see the legacy display code: - amdgpu_pll_compute - amdgpu_atombios_crtc_program_pll This commit fixes set_pixel_clock_v3 by dividing the fractional feedback divider passed to the function by 100000. Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") Signed-off-by: Timur Kristóf Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Reviewed-by: Alex Hung Signed-off-by: Alex Deucher (cherry picked from commit 027e7acc7e17802ebf28e1edb88a404836ad50d6) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/dc/bios/command_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c index 2bcae0643e61db..58e88778da7ffd 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c @@ -993,7 +993,7 @@ static enum bp_result set_pixel_clock_v3( allocation.sPCLKInput.usFbDiv = cpu_to_le16((uint16_t)bp_params->feedback_divider); allocation.sPCLKInput.ucFracFbDiv = - (uint8_t)bp_params->fractional_feedback_divider; + (uint8_t)(bp_params->fractional_feedback_divider / 100000); allocation.sPCLKInput.ucPostDiv = (uint8_t)bp_params->pixel_clock_post_divider; From 297a4833a68aac3316eb808b4123eb016ef242d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Sat, 2 Aug 2025 17:51:53 +0200 Subject: [PATCH 0309/1292] drm/amd/display: Fix DP audio DTO1 clock source on DCE 6. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On DCE 6, DP audio was not working. However, it worked when an HDMI monitor was also plugged in. Looking at dce_aud_wall_dto_setup it seems that the main difference is that we use DTO1 when only DP is plugged in. When programming DTO1, it uses audio_dto_source_clock_in_khz which is set from get_dp_ref_freq_khz The dce60_get_dp_ref_freq_khz implementation looks incorrect, because DENTIST_DISPCLK_CNTL seems to be always zero on DCE 6, so it isn't usable. I compared dce60_get_dp_ref_freq_khz to the legacy display code, specifically dce_v6_0_audio_set_dto, and it turns out that in case of DCE 6, it needs to use the display clock. With that, DP audio started working on Pitcairn, Oland and Cape Verde. However, it still didn't work on Tahiti. Despite having the same DCE version, Tahiti seems to have a different audio device. After some trial and error I realized that it works with the default display clock as reported by the VBIOS, not the current display clock. The patch was tested on all four SI GPUs: * Pitcairn (DCE 6.0) * Oland (DCE 6.4) * Cape Verde (DCE 6.0) * Tahiti (DCE 6.0 but different) The testing was done on Samsung Odyssey G7 LS28BG700EPXEN on each of the above GPUs, at the following settings: * 4K 60 Hz * 1080p 60 Hz * 1080p 144 Hz Acked-by: Alex Deucher Reviewed-by: Rodrigo Siqueira Signed-off-by: Timur Kristóf Signed-off-by: Alex Deucher (cherry picked from commit 645cc7863da5de700547d236697dffd6760cf051) Cc: stable@vger.kernel.org --- .../display/dc/clk_mgr/dce60/dce60_clk_mgr.c | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c index 7044b437fe9d91..a39641a0ff09ef 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c @@ -83,22 +83,13 @@ static const struct state_dependent_clocks dce60_max_clks_by_state[] = { static int dce60_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base) { struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); - int dprefclk_wdivider; - int dp_ref_clk_khz; - int target_div; + struct dc_context *ctx = clk_mgr_base->ctx; + int dp_ref_clk_khz = 0; - /* DCE6 has no DPREFCLK_CNTL to read DP Reference Clock source */ - - /* Read the mmDENTIST_DISPCLK_CNTL to get the currently - * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ - REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider); - - /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ - target_div = dentist_get_divider_from_did(dprefclk_wdivider); - - /* Calculate the current DFS clock, in kHz.*/ - dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR - * clk_mgr->base.dentist_vco_freq_khz) / target_div; + if (ASIC_REV_IS_TAHITI_P(ctx->asic_id.hw_internal_rev)) + dp_ref_clk_khz = ctx->dc_bios->fw_info.default_display_engine_pll_frequency; + else + dp_ref_clk_khz = clk_mgr_base->clks.dispclk_khz; return dce_adjust_dp_ref_freq_for_ss(clk_mgr, dp_ref_clk_khz); } From 864e3396976ef41de6cc7bc366276bf4e084fff2 Mon Sep 17 00:00:00 2001 From: Jakub Ramaseuski Date: Thu, 14 Aug 2025 12:51:19 +0200 Subject: [PATCH 0310/1292] net: gso: Forbid IPv6 TSO with extensions on devices with only IPV6_CSUM When performing Generic Segmentation Offload (GSO) on an IPv6 packet that contains extension headers, the kernel incorrectly requests checksum offload if the egress device only advertises NETIF_F_IPV6_CSUM feature, which has a strict contract: it supports checksum offload only for plain TCP or UDP over IPv6 and explicitly does not support packets with extension headers. The current GSO logic violates this contract by failing to disable the feature for packets with extension headers, such as those used in GREoIPv6 tunnels. This violation results in the device being asked to perform an operation it cannot support, leading to a `skb_warn_bad_offload` warning and a collapse of network throughput. While device TSO/USO is correctly bypassed in favor of software GSO for these packets, the GSO stack must be explicitly told not to request checksum offload. Mask NETIF_F_IPV6_CSUM, NETIF_F_TSO6 and NETIF_F_GSO_UDP_L4 in gso_features_check if the IPv6 header contains extension headers to compute checksum in software. The exception is a BIG TCP extension, which, as stated in commit 68e068cabd2c6c53 ("net: reenable NETIF_F_IPV6_CSUM offload for BIG TCP packets"): "The feature is only enabled on devices that support BIG TCP TSO. The header is only present for PF_PACKET taps like tcpdump, and not transmitted by physical devices." kernel log output (truncated): WARNING: CPU: 1 PID: 5273 at net/core/dev.c:3535 skb_warn_bad_offload+0x81/0x140 ... Call Trace: skb_checksum_help+0x12a/0x1f0 validate_xmit_skb+0x1a3/0x2d0 validate_xmit_skb_list+0x4f/0x80 sch_direct_xmit+0x1a2/0x380 __dev_xmit_skb+0x242/0x670 __dev_queue_xmit+0x3fc/0x7f0 ip6_finish_output2+0x25e/0x5d0 ip6_finish_output+0x1fc/0x3f0 ip6_tnl_xmit+0x608/0xc00 [ip6_tunnel] ip6gre_tunnel_xmit+0x1c0/0x390 [ip6_gre] dev_hard_start_xmit+0x63/0x1c0 __dev_queue_xmit+0x6d0/0x7f0 ip6_finish_output2+0x214/0x5d0 ip6_finish_output+0x1fc/0x3f0 ip6_xmit+0x2ca/0x6f0 ip6_finish_output+0x1fc/0x3f0 ip6_xmit+0x2ca/0x6f0 inet6_csk_xmit+0xeb/0x150 __tcp_transmit_skb+0x555/0xa80 tcp_write_xmit+0x32a/0xe90 tcp_sendmsg_locked+0x437/0x1110 tcp_sendmsg+0x2f/0x50 ... skb linear: 00000000: e4 3d 1a 7d ec 30 e4 3d 1a 7e 5d 90 86 dd 60 0e skb linear: 00000010: 00 0a 1b 34 3c 40 20 11 00 00 00 00 00 00 00 00 skb linear: 00000020: 00 00 00 00 00 12 20 11 00 00 00 00 00 00 00 00 skb linear: 00000030: 00 00 00 00 00 11 2f 00 04 01 04 01 01 00 00 00 skb linear: 00000040: 86 dd 60 0e 00 0a 1b 00 06 40 20 23 00 00 00 00 skb linear: 00000050: 00 00 00 00 00 00 00 00 00 12 20 23 00 00 00 00 skb linear: 00000060: 00 00 00 00 00 00 00 00 00 11 bf 96 14 51 13 f9 skb linear: 00000070: ae 27 a0 a8 2b e3 80 18 00 40 5b 6f 00 00 01 01 skb linear: 00000080: 08 0a 42 d4 50 d5 4b 70 f8 1a Fixes: 04c20a9356f283da ("net: skip offload for NETIF_F_IPV6_CSUM if ipv6 header contains extension") Reported-by: Tianhao Zhao Suggested-by: Michal Schmidt Suggested-by: Willem de Bruijn Signed-off-by: Jakub Ramaseuski Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20250814105119.1525687-1-jramaseu@redhat.com Signed-off-by: Jakub Kicinski --- net/core/dev.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 5a3c0f40a93ffb..93a25d87b86b66 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3779,6 +3779,18 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb, features &= ~NETIF_F_TSO_MANGLEID; } + /* NETIF_F_IPV6_CSUM does not support IPv6 extension headers, + * so neither does TSO that depends on it. + */ + if (features & NETIF_F_IPV6_CSUM && + (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6 || + (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && + vlan_get_protocol(skb) == htons(ETH_P_IPV6))) && + skb_transport_header_was_set(skb) && + skb_network_header_len(skb) != sizeof(struct ipv6hdr) && + !ipv6_has_hopopt_jumbo(skb)) + features &= ~(NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | NETIF_F_GSO_UDP_L4); + return features; } From 84967deee9d9870b15bc4c3acb50f1d401807902 Mon Sep 17 00:00:00 2001 From: Minhong He Date: Fri, 15 Aug 2025 14:38:45 +0800 Subject: [PATCH 0311/1292] ipv6: sr: validate HMAC algorithm ID in seg6_hmac_info_add The seg6_genl_sethmac() directly uses the algorithm ID provided by the userspace without verifying whether it is an HMAC algorithm supported by the system. If an unsupported HMAC algorithm ID is configured, packets using SRv6 HMAC will be dropped during encapsulation or decapsulation. Fixes: 4f4853dc1c9c ("ipv6: sr: implement API to control SR HMAC structure") Signed-off-by: Minhong He Reviewed-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250815063845.85426-1-heminhong@kylinos.cn Signed-off-by: Jakub Kicinski --- net/ipv6/seg6_hmac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c index f78ecb6ad83834..d77b52523b6a8a 100644 --- a/net/ipv6/seg6_hmac.c +++ b/net/ipv6/seg6_hmac.c @@ -304,6 +304,9 @@ int seg6_hmac_info_add(struct net *net, u32 key, struct seg6_hmac_info *hinfo) struct seg6_pernet_data *sdata = seg6_pernet(net); int err; + if (!__hmac_get_algo(hinfo->alg_id)) + return -EINVAL; + err = rhashtable_lookup_insert_fast(&sdata->hmac_infos, &hinfo->node, rht_params); From ccab044697980c6c01ab51f43f48f13b8a3e5c33 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Fri, 15 Aug 2025 19:28:19 +0200 Subject: [PATCH 0312/1292] mptcp: drop skb if MPTCP skb extension allocation fails When skb_ext_add(skb, SKB_EXT_MPTCP) fails in mptcp_incoming_options(), we used to return true, letting the segment proceed through the TCP receive path without a DSS mapping. Such segments can leave inconsistent mapping state and trigger a mid-stream fallback to TCP, which in testing collapsed (by artificially forcing failures in skb_ext_add) throughput to zero. Return false instead so the TCP input path drops the skb (see tcp_data_queue() and step-7 processing). This is the safer choice under memory pressure: it preserves MPTCP correctness and provides backpressure to the sender. Control packets remain unaffected: ACK updates and DATA_FIN handling happen before attempting the extension allocation, and tcp_reset() continues to ignore the return value. With this change, MPTCP continues to work at high throughput if we artificially inject failures into skb_ext_add. Fixes: 6787b7e350d3 ("mptcp: avoid processing packet if a subflow reset") Cc: stable@vger.kernel.org Signed-off-by: Christoph Paasch Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-1-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- net/mptcp/options.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 70c0ab0ecf905d..2a8ea28442b271 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1118,7 +1118,9 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk, return hmac == mp_opt->ahmac; } -/* Return false if a subflow has been reset, else return true */ +/* Return false in case of error (or subflow has been reset), + * else return true. + */ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); @@ -1222,7 +1224,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) mpext = skb_ext_add(skb, SKB_EXT_MPTCP); if (!mpext) - return true; + return false; memset(mpext, 0, sizeof(*mpext)); From 68fc0f4b0d25692940cdc85c68e366cae63e1757 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 15 Aug 2025 19:28:20 +0200 Subject: [PATCH 0313/1292] mptcp: pm: kernel: flush: do not reset ADD_ADDR limit A flush of the MPTCP endpoints should not affect the MPTCP limits. In other words, 'ip mptcp endpoint flush' should not change 'ip mptcp limits'. But it was the case: the MPTCP_PM_ATTR_RCV_ADD_ADDRS (add_addr_accepted) limit was reset by accident. Removing the reset of this counter during a flush fixes this issue. Fixes: 01cacb00b35c ("mptcp: add netlink-based PM") Cc: stable@vger.kernel.org Reported-by: Thomas Dreibholz Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/579 Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-2-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- net/mptcp/pm_kernel.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index d39e7c1784608d..667803d72b643a 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -1085,7 +1085,6 @@ static void __flush_addrs(struct list_head *list) static void __reset_counters(struct pm_nl_pernet *pernet) { WRITE_ONCE(pernet->add_addr_signal_max, 0); - WRITE_ONCE(pernet->add_addr_accept_max, 0); WRITE_ONCE(pernet->local_addr_max, 0); pernet->addrs = 0; } From 452690be7de2f91cc0de68cb9e95252875b33503 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 15 Aug 2025 19:28:21 +0200 Subject: [PATCH 0314/1292] selftests: mptcp: pm: check flush doesn't reset limits This modification is linked to the parent commit where the received ADD_ADDR limit was accidentally reset when the endpoints were flushed. To validate that, the test is now flushing endpoints after having set new limits, and before checking them. The 'Fixes' tag here below is the same as the one from the previous commit: this patch here is not fixing anything wrong in the selftests, but it validates the previous fix for an issue introduced by this commit ID. Fixes: 01cacb00b35c ("mptcp: add netlink-based PM") Cc: stable@vger.kernel.org Reviewed-by: Mat Martineau Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-3-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/pm_netlink.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/mptcp/pm_netlink.sh b/tools/testing/selftests/net/mptcp/pm_netlink.sh index 2e6648a2b2c0c6..ac7ec6f9402376 100755 --- a/tools/testing/selftests/net/mptcp/pm_netlink.sh +++ b/tools/testing/selftests/net/mptcp/pm_netlink.sh @@ -198,6 +198,7 @@ set_limits 1 9 2>/dev/null check "get_limits" "${default_limits}" "subflows above hard limit" set_limits 8 8 +flush_endpoint ## to make sure it doesn't affect the limits check "get_limits" "$(format_limits 8 8)" "set limits" flush_endpoint From 5d13349472ac8abcbcb94407969aa0fdc2e1f1be Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 15 Aug 2025 19:28:22 +0200 Subject: [PATCH 0315/1292] mptcp: remove duplicate sk_reset_timer call sk_reset_timer() was called twice in mptcp_pm_alloc_anno_list. Simplify the code by using a 'goto' statement to eliminate the duplication. Note that this is not a fix, but it will help backporting the following patch. The same "Fixes" tag has been added for this reason. Fixes: 93f323b9cccc ("mptcp: add a new sysctl add_addr_timeout") Cc: stable@vger.kernel.org Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-4-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- net/mptcp/pm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 420d416e2603de..c5f6a53ce5f1e1 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -353,9 +353,7 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, if (WARN_ON_ONCE(mptcp_pm_is_kernel(msk))) return false; - sk_reset_timer(sk, &add_entry->add_timer, - jiffies + mptcp_get_add_addr_timeout(net)); - return true; + goto reset_timer; } add_entry = kmalloc(sizeof(*add_entry), GFP_ATOMIC); @@ -369,6 +367,7 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, add_entry->retrans_times = 0; timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0); +reset_timer: sk_reset_timer(sk, &add_entry->add_timer, jiffies + mptcp_get_add_addr_timeout(net)); From f5ce0714623cffd00bf2a83e890d09c609b7f50a Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 15 Aug 2025 19:28:23 +0200 Subject: [PATCH 0316/1292] mptcp: disable add_addr retransmission when timeout is 0 When add_addr_timeout was set to 0, this caused the ADD_ADDR to be retransmitted immediately, which looks like a buggy behaviour. Instead, interpret 0 as "no retransmissions needed". The documentation is updated to explicitly state that setting the timeout to 0 disables retransmission. Fixes: 93f323b9cccc ("mptcp: add a new sysctl add_addr_timeout") Cc: stable@vger.kernel.org Suggested-by: Matthieu Baerts Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-5-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/mptcp-sysctl.rst | 2 ++ net/mptcp/pm.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/mptcp-sysctl.rst b/Documentation/networking/mptcp-sysctl.rst index 5bfab01eff5a9d..1683c139821e3b 100644 --- a/Documentation/networking/mptcp-sysctl.rst +++ b/Documentation/networking/mptcp-sysctl.rst @@ -12,6 +12,8 @@ add_addr_timeout - INTEGER (seconds) resent to an MPTCP peer that has not acknowledged a previous ADD_ADDR message. + Do not retransmit if set to 0. + The default value matches TCP_RTO_MAX. This is a per-namespace sysctl. diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index c5f6a53ce5f1e1..136a380602cae8 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -274,6 +274,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) add_timer); struct mptcp_sock *msk = entry->sock; struct sock *sk = (struct sock *)msk; + unsigned int timeout; pr_debug("msk=%p\n", msk); @@ -291,6 +292,10 @@ static void mptcp_pm_add_timer(struct timer_list *timer) goto out; } + timeout = mptcp_get_add_addr_timeout(sock_net(sk)); + if (!timeout) + goto out; + spin_lock_bh(&msk->pm.lock); if (!mptcp_pm_should_add_signal_addr(msk)) { @@ -302,7 +307,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (entry->retrans_times < ADD_ADDR_RETRANS_MAX) sk_reset_timer(sk, timer, - jiffies + mptcp_get_add_addr_timeout(sock_net(sk))); + jiffies + timeout); spin_unlock_bh(&msk->pm.lock); @@ -344,6 +349,7 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, struct mptcp_pm_add_entry *add_entry = NULL; struct sock *sk = (struct sock *)msk; struct net *net = sock_net(sk); + unsigned int timeout; lockdep_assert_held(&msk->pm.lock); @@ -368,8 +374,9 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0); reset_timer: - sk_reset_timer(sk, &add_entry->add_timer, - jiffies + mptcp_get_add_addr_timeout(net)); + timeout = mptcp_get_add_addr_timeout(net); + if (timeout) + sk_reset_timer(sk, &add_entry->add_timer, jiffies + timeout); return true; } From f92199f551e617fae028c5c5905ddd63e3616e18 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 15 Aug 2025 19:28:24 +0200 Subject: [PATCH 0317/1292] selftests: mptcp: disable add_addr retrans in endpoint_tests To prevent test instability in the "delete re-add signal" test caused by ADD_ADDR retransmissions, disable retransmissions for this test by setting net.mptcp.add_addr_timeout to 0. Suggested-by: Matthieu Baerts Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts (NGI0) Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-6-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index b8af65373b3ada..82cae37d9c2026 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -3842,6 +3842,7 @@ endpoint_tests() # remove and re-add if reset_with_events "delete re-add signal" && mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then + ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=0 pm_nl_set_limits $ns1 0 3 pm_nl_set_limits $ns2 3 3 pm_nl_add_endpoint $ns1 10.0.2.1 id 1 flags signal From 2eefbed30d46d5e68593baf6b52923e00e7678af Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 15 Aug 2025 19:28:25 +0200 Subject: [PATCH 0318/1292] selftests: mptcp: connect: fix C23 extension warning GCC was complaining about the new label: mptcp_connect.c:187:2: warning: label followed by a declaration is a C23 extension [-Wc23-extensions] 187 | int err = getaddrinfo(node, service, hints, res); | ^ Simply declare 'err' before the label to avoid this warning. Fixes: a862771d1aa4 ("selftests: mptcp: use IPPROTO_MPTCP for getaddrinfo") Cc: stable@vger.kernel.org Reviewed-by: Geliang Tang Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-7-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_connect.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c index ac1349c4b9e540..4f07ac9fa207cb 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -183,9 +183,10 @@ static void xgetaddrinfo(const char *node, const char *service, struct addrinfo *hints, struct addrinfo **res) { -again: - int err = getaddrinfo(node, service, hints, res); + int err; +again: + err = getaddrinfo(node, service, hints, res); if (err) { const char *errstr; From 3259889fd3c0cc165b7e9ee375c789875dd32326 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Fri, 15 Aug 2025 19:28:26 +0200 Subject: [PATCH 0319/1292] selftests: mptcp: sockopt: fix C23 extension warning GCC was complaining about the new label: mptcp_inq.c:79:2: warning: label followed by a declaration is a C23 extension [-Wc23-extensions] 79 | int err = getaddrinfo(node, service, hints, res); | ^ mptcp_sockopt.c:166:2: warning: label followed by a declaration is a C23 extension [-Wc23-extensions] 166 | int err = getaddrinfo(node, service, hints, res); | ^ Simply declare 'err' before the label to avoid this warning. Fixes: dd367e81b79a ("selftests: mptcp: sockopt: use IPPROTO_MPTCP for getaddrinfo") Cc: stable@vger.kernel.org Reviewed-by: Geliang Tang Signed-off-by: Matthieu Baerts (NGI0) Link: https://patch.msgid.link/20250815-net-mptcp-misc-fixes-6-17-rc2-v1-8-521fe9957892@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_inq.c | 5 +++-- tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_inq.c b/tools/testing/selftests/net/mptcp/mptcp_inq.c index 3cf1e2a612cef9..f3bcaa48df8f22 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_inq.c +++ b/tools/testing/selftests/net/mptcp/mptcp_inq.c @@ -75,9 +75,10 @@ static void xgetaddrinfo(const char *node, const char *service, struct addrinfo *hints, struct addrinfo **res) { -again: - int err = getaddrinfo(node, service, hints, res); + int err; +again: + err = getaddrinfo(node, service, hints, res); if (err) { const char *errstr; diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c index 9934a68df23708..e934dd26a59d9b 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -162,9 +162,10 @@ static void xgetaddrinfo(const char *node, const char *service, struct addrinfo *hints, struct addrinfo **res) { -again: - int err = getaddrinfo(node, service, hints, res); + int err; +again: + err = getaddrinfo(node, service, hints, res); if (err) { const char *errstr; From 89eb9a62aed77b409663ba1eac152e8f758815b7 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 15 Aug 2025 22:18:09 +0200 Subject: [PATCH 0320/1292] net: dsa: b53: fix reserved register access in b53_fdb_dump() When BCM5325 support was added in c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365"), the register used for ARL access was made conditional on the chip. But in b53_fdb_dump(), instead of the register argument the page argument was replaced, causing it to write to a reserved page 0x50 on !BCM5325*. Writing to this page seems to completely lock the switch up: [ 89.680000] b53-switch spi0.1 lan2: Link is Down [ 89.680000] WARNING: CPU: 1 PID: 26 at drivers/net/phy/phy.c:1350 _phy_state_machine+0x1bc/0x454 [ 89.720000] phy_check_link_status+0x0/0x114: returned: -5 [ 89.730000] Modules linked in: nft_fib_inet nf_flow_table_inet nft_reject_ipv6 nft_reject_ipv4 nft_reject_inet nft_reject nft_redir nft_quota nft_numgen nft_nat nft_masq nft_log nft_limit nft_hash nft_flow_offload nft_fib_ipv6 nft_fib_ipv4 nft_fib nft_ct nft_chain_nat nf_tables nf_nat nf_flow_table nf_conntrack nfnetlink nf_reject_ipv6 nf_reject_ipv4 nf_log_syslog nf_defrag_ipv6 nf_defrag_ipv4 cls_flower sch_tbf sch_ingress sch_htb sch_hfsc em_u32 cls_u32 cls_route cls_matchall cls_fw cls_flow cls_basic act_skbedit act_mirred act_gact vrf md5 crc32c_cryptoapi [ 89.780000] CPU: 1 UID: 0 PID: 26 Comm: kworker/u10:0 Tainted: G W 6.16.0-rc1+ #0 NONE [ 89.780000] Tainted: [W]=WARN [ 89.780000] Hardware name: Netgear DGND3700 v1 [ 89.780000] Workqueue: events_power_efficient phy_state_machine [ 89.780000] Stack : 809c762c 8006b050 00000001 820a9ce3 0000114c 000affff 805d22d0 8200ba00 [ 89.780000] 82005000 6576656e 74735f70 6f776572 5f656666 10008b00 820a9cb8 82088700 [ 89.780000] 00000000 00000000 809c762c 820a9a98 00000000 00000000 ffffefff 80a7a76c [ 89.780000] 80a70000 820a9af8 80a70000 80a70000 80a70000 00000000 809c762c 820a9dd4 [ 89.780000] 00000000 805d1494 80a029e4 80a70000 00000003 00000000 00000004 81a60004 [ 89.780000] ... [ 89.780000] Call Trace: [ 89.780000] [<800228b8>] show_stack+0x38/0x118 [ 89.780000] [<8001afc4>] dump_stack_lvl+0x6c/0xac [ 89.780000] [<80046b90>] __warn+0x9c/0x114 [ 89.780000] [<80046da8>] warn_slowpath_fmt+0x1a0/0x1b0 [ 89.780000] [<805d1494>] _phy_state_machine+0x1bc/0x454 [ 89.780000] [<805d22fc>] phy_state_machine+0x2c/0x70 [ 89.780000] [<80066b08>] process_one_work+0x1e8/0x3e0 [ 89.780000] [<80067a1c>] worker_thread+0x354/0x4e4 [ 89.780000] [<800706cc>] kthread+0x130/0x274 [ 89.780000] [<8001d808>] ret_from_kernel_thread+0x14/0x1c And any further accesses fail: [ 120.790000] b53-switch spi0.1: timeout waiting for ARL to finish: 0x81 [ 120.800000] b53-switch spi0.1: port 2 failed to add 2c:b0:5d:27:9a:bd vid 3 to fdb: -145 [ 121.010000] b53-switch spi0.1: timeout waiting for ARL to finish: 0xbf [ 121.020000] b53-switch spi0.1: port 3 failed to add 2c:b0:5d:27:9a:bd vid 3 to fdb: -145 Restore the correct page B53_ARLIO_PAGE again, and move the offset argument to the correct place. *On BCM5325, this became a write to the MIB page of Port 1. Still a reserved offset, but likely less brokenness from that write. Fixes: c45655386e53 ("net: dsa: b53: add support for FDB operations on 5325/5365") Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250815201809.549195-1-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 9942fb6f7f4b04..829b1f087e9e0e 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2078,7 +2078,7 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, /* Start search operation */ reg = ARL_SRCH_STDN; - b53_write8(priv, offset, B53_ARL_SRCH_CTL, reg); + b53_write8(priv, B53_ARLIO_PAGE, offset, reg); do { ret = b53_arl_search_wait(priv); From 4611d88a37cfc18cbabc6978aaf7325d1ae3f53a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 16 Aug 2025 11:38:50 -0700 Subject: [PATCH 0321/1292] bnxt_en: Fix lockdep warning during rmmod The commit under the Fixes tag added a netdev_assert_locked() in bnxt_free_ntp_fltrs(). The lock should be held during normal run-time but the assert will be triggered (see below) during bnxt_remove_one() which should not need the lock. The netdev is already unregistered by then. Fix it by calling netdev_assert_locked_or_invisible() which will not assert if the netdev is unregistered. WARNING: CPU: 5 PID: 2241 at ./include/net/netdev_lock.h:17 bnxt_free_ntp_fltrs+0xf8/0x100 [bnxt_en] Modules linked in: rpcrdma rdma_cm iw_cm ib_cm configfs ib_core bnxt_en(-) bridge stp llc x86_pkg_temp_thermal xfs tg3 [last unloaded: bnxt_re] CPU: 5 UID: 0 PID: 2241 Comm: rmmod Tainted: G S W 6.16.0 #2 PREEMPT(voluntary) Tainted: [S]=CPU_OUT_OF_SPEC, [W]=WARN Hardware name: Dell Inc. PowerEdge R730/072T6D, BIOS 2.4.3 01/17/2017 RIP: 0010:bnxt_free_ntp_fltrs+0xf8/0x100 [bnxt_en] Code: 41 5c 41 5d 41 5e 41 5f c3 cc cc cc cc 48 8b 47 60 be ff ff ff ff 48 8d b8 28 0c 00 00 e8 d0 cf 41 c3 85 c0 0f 85 2e ff ff ff <0f> 0b e9 27 ff ff ff 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 RSP: 0018:ffffa92082387da0 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff9e5b593d8000 RCX: 0000000000000001 RDX: 0000000000000001 RSI: ffffffff83dc9a70 RDI: ffffffff83e1a1cf RBP: ffff9e5b593d8c80 R08: 0000000000000000 R09: ffffffff8373a2b3 R10: 000000008100009f R11: 0000000000000001 R12: 0000000000000001 R13: ffffffffc01c4478 R14: dead000000000122 R15: dead000000000100 FS: 00007f3a8a52c740(0000) GS:ffff9e631ad1c000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055bb289419c8 CR3: 000000011274e001 CR4: 00000000003706f0 Call Trace: bnxt_remove_one+0x57/0x180 [bnxt_en] pci_device_remove+0x39/0xc0 device_release_driver_internal+0xa5/0x130 driver_detach+0x42/0x90 bus_remove_driver+0x61/0xc0 pci_unregister_driver+0x38/0x90 bnxt_exit+0xc/0x7d0 [bnxt_en] Fixes: 004b5008016a ("eth: bnxt: remove most dependencies on RTNL") Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20250816183850.4125033-1-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 2800a90fba1f37..207a8bb36ae5f4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5332,7 +5332,7 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) { int i; - netdev_assert_locked(bp->dev); + netdev_assert_locked_or_invisible(bp->dev); /* Under netdev instance lock and all our NAPIs have been disabled. * It's safe to delete the hash table. From eabcac808ca3ee9878223d4b49b750979029016b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 15 Aug 2025 08:58:23 -0700 Subject: [PATCH 0322/1292] scsi: ufs: core: Fix IRQ lock inversion for the SCSI host lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 3c7ac40d7322 ("scsi: ufs: core: Delegate the interrupt service routine to a threaded IRQ handler") introduced an IRQ lock inversion issue. Fix this lock inversion by changing the spin_lock_irq() calls into spin_lock_irqsave() calls in code that can be called either from interrupt context or from thread context. This patch fixes the following lockdep complaint: WARNING: possible irq lock inversion dependency detected 6.12.30-android16-5-maybe-dirty-4k #1 Tainted: G W OE -------------------------------------------------------- kworker/u28:0/12 just changed the state of lock: ffffff881e29dd60 (&hba->clk_gating.lock){-...}-{2:2}, at: ufshcd_release_scsi_cmd+0x60/0x110 but this lock took another, HARDIRQ-unsafe lock in the past: (shost->host_lock){+.+.}-{2:2} and interrupts could create inverse lock ordering between them. other info that might help us debug this: Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(shost->host_lock); local_irq_disable(); lock(&hba->clk_gating.lock); lock(shost->host_lock); lock(&hba->clk_gating.lock); *** DEADLOCK *** 4 locks held by kworker/u28:0/12: #0: ffffff8800ac6158 ((wq_completion)async){+.+.}-{0:0}, at: process_one_work+0x1bc/0x65c #1: ffffffc085c93d70 ((work_completion)(&entry->work)){+.+.}-{0:0}, at: process_one_work+0x1e4/0x65c #2: ffffff881e29c0e0 (&shost->scan_mutex){+.+.}-{3:3}, at: __scsi_add_device+0x74/0x120 #3: ffffff881960ea00 (&hwq->cq_lock){-...}-{2:2}, at: ufshcd_mcq_poll_cqe_lock+0x28/0x104 the shortest dependencies between 2nd lock and 1st lock: -> (shost->host_lock){+.+.}-{2:2} { HARDIRQ-ON-W at: lock_acquire+0x134/0x2b4 _raw_spin_lock+0x48/0x64 ufshcd_sl_intr+0x4c/0xa08 ufshcd_threaded_intr+0x70/0x12c irq_thread_fn+0x48/0xa8 irq_thread+0x130/0x1ec kthread+0x110/0x134 ret_from_fork+0x10/0x20 SOFTIRQ-ON-W at: lock_acquire+0x134/0x2b4 _raw_spin_lock+0x48/0x64 ufshcd_sl_intr+0x4c/0xa08 ufshcd_threaded_intr+0x70/0x12c irq_thread_fn+0x48/0xa8 irq_thread+0x130/0x1ec kthread+0x110/0x134 ret_from_fork+0x10/0x20 INITIAL USE at: lock_acquire+0x134/0x2b4 _raw_spin_lock+0x48/0x64 ufshcd_sl_intr+0x4c/0xa08 ufshcd_threaded_intr+0x70/0x12c irq_thread_fn+0x48/0xa8 irq_thread+0x130/0x1ec kthread+0x110/0x134 ret_from_fork+0x10/0x20 } ... key at: [] scsi_host_alloc.__key+0x0/0x10 ... acquired at: _raw_spin_lock_irqsave+0x5c/0x80 __ufshcd_release+0x78/0x118 ufshcd_send_uic_cmd+0xe4/0x118 ufshcd_dme_set_attr+0x88/0x1c8 ufs_google_phy_initialization+0x68/0x418 [ufs] ufs_google_link_startup_notify+0x78/0x27c [ufs] ufshcd_link_startup+0x84/0x720 ufshcd_init+0xf3c/0x1330 ufshcd_pltfrm_init+0x728/0x7d8 ufs_google_probe+0x30/0x84 [ufs] platform_probe+0xa0/0xe0 really_probe+0x114/0x454 __driver_probe_device+0xa4/0x160 driver_probe_device+0x44/0x23c __driver_attach_async_helper+0x60/0xd4 async_run_entry_fn+0x4c/0x17c process_one_work+0x26c/0x65c worker_thread+0x33c/0x498 kthread+0x110/0x134 ret_from_fork+0x10/0x20 -> (&hba->clk_gating.lock){-...}-{2:2} { IN-HARDIRQ-W at: lock_acquire+0x134/0x2b4 _raw_spin_lock_irqsave+0x5c/0x80 ufshcd_release_scsi_cmd+0x60/0x110 ufshcd_compl_one_cqe+0x2c0/0x3f4 ufshcd_mcq_poll_cqe_lock+0xb0/0x104 ufs_google_mcq_intr+0x80/0xa0 [ufs] __handle_irq_event_percpu+0x104/0x32c handle_irq_event+0x40/0x9c handle_fasteoi_irq+0x170/0x2e8 generic_handle_domain_irq+0x58/0x80 gic_handle_irq+0x48/0x104 call_on_irq_stack+0x3c/0x50 do_interrupt_handler+0x7c/0xd8 el1_interrupt+0x34/0x58 el1h_64_irq_handler+0x18/0x24 el1h_64_irq+0x68/0x6c _raw_spin_unlock_irqrestore+0x3c/0x6c debug_object_assert_init+0x16c/0x21c __mod_timer+0x4c/0x48c schedule_timeout+0xd4/0x16c io_schedule_timeout+0x48/0x70 do_wait_for_common+0x100/0x194 wait_for_completion_io_timeout+0x48/0x6c blk_execute_rq+0x124/0x17c scsi_execute_cmd+0x18c/0x3f8 scsi_probe_and_add_lun+0x204/0xd74 __scsi_add_device+0xbc/0x120 ufshcd_async_scan+0x80/0x3c0 async_run_entry_fn+0x4c/0x17c process_one_work+0x26c/0x65c worker_thread+0x33c/0x498 kthread+0x110/0x134 ret_from_fork+0x10/0x20 INITIAL USE at: lock_acquire+0x134/0x2b4 _raw_spin_lock_irqsave+0x5c/0x80 ufshcd_hold+0x34/0x14c ufshcd_send_uic_cmd+0x28/0x118 ufshcd_dme_set_attr+0x88/0x1c8 ufs_google_phy_initialization+0x68/0x418 [ufs] ufs_google_link_startup_notify+0x78/0x27c [ufs] ufshcd_link_startup+0x84/0x720 ufshcd_init+0xf3c/0x1330 ufshcd_pltfrm_init+0x728/0x7d8 ufs_google_probe+0x30/0x84 [ufs] platform_probe+0xa0/0xe0 really_probe+0x114/0x454 __driver_probe_device+0xa4/0x160 driver_probe_device+0x44/0x23c __driver_attach_async_helper+0x60/0xd4 async_run_entry_fn+0x4c/0x17c process_one_work+0x26c/0x65c worker_thread+0x33c/0x498 kthread+0x110/0x134 ret_from_fork+0x10/0x20 } ... key at: [] ufshcd_init.__key+0x0/0x10 ... acquired at: mark_lock+0x1c4/0x224 __lock_acquire+0x438/0x2e1c lock_acquire+0x134/0x2b4 _raw_spin_lock_irqsave+0x5c/0x80 ufshcd_release_scsi_cmd+0x60/0x110 ufshcd_compl_one_cqe+0x2c0/0x3f4 ufshcd_mcq_poll_cqe_lock+0xb0/0x104 ufs_google_mcq_intr+0x80/0xa0 [ufs] __handle_irq_event_percpu+0x104/0x32c handle_irq_event+0x40/0x9c handle_fasteoi_irq+0x170/0x2e8 generic_handle_domain_irq+0x58/0x80 gic_handle_irq+0x48/0x104 call_on_irq_stack+0x3c/0x50 do_interrupt_handler+0x7c/0xd8 el1_interrupt+0x34/0x58 el1h_64_irq_handler+0x18/0x24 el1h_64_irq+0x68/0x6c _raw_spin_unlock_irqrestore+0x3c/0x6c debug_object_assert_init+0x16c/0x21c __mod_timer+0x4c/0x48c schedule_timeout+0xd4/0x16c io_schedule_timeout+0x48/0x70 do_wait_for_common+0x100/0x194 wait_for_completion_io_timeout+0x48/0x6c blk_execute_rq+0x124/0x17c scsi_execute_cmd+0x18c/0x3f8 scsi_probe_and_add_lun+0x204/0xd74 __scsi_add_device+0xbc/0x120 ufshcd_async_scan+0x80/0x3c0 async_run_entry_fn+0x4c/0x17c process_one_work+0x26c/0x65c worker_thread+0x33c/0x498 kthread+0x110/0x134 ret_from_fork+0x10/0x20 stack backtrace: CPU: 6 UID: 0 PID: 12 Comm: kworker/u28:0 Tainted: G W OE 6.12.30-android16-5-maybe-dirty-4k #1 ccd4020fe444bdf629efc3b86df6be920b8df7d0 Tainted: [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Hardware name: Spacecraft board based on MALIBU (DT) Workqueue: async async_run_entry_fn Call trace: dump_backtrace+0xfc/0x17c show_stack+0x18/0x28 dump_stack_lvl+0x40/0xa0 dump_stack+0x18/0x24 print_irq_inversion_bug+0x2fc/0x304 mark_lock_irq+0x388/0x4fc mark_lock+0x1c4/0x224 __lock_acquire+0x438/0x2e1c lock_acquire+0x134/0x2b4 _raw_spin_lock_irqsave+0x5c/0x80 ufshcd_release_scsi_cmd+0x60/0x110 ufshcd_compl_one_cqe+0x2c0/0x3f4 ufshcd_mcq_poll_cqe_lock+0xb0/0x104 ufs_google_mcq_intr+0x80/0xa0 [ufs dd6f385554e109da094ab91d5f7be18625a2222a] __handle_irq_event_percpu+0x104/0x32c handle_irq_event+0x40/0x9c handle_fasteoi_irq+0x170/0x2e8 generic_handle_domain_irq+0x58/0x80 gic_handle_irq+0x48/0x104 call_on_irq_stack+0x3c/0x50 do_interrupt_handler+0x7c/0xd8 el1_interrupt+0x34/0x58 el1h_64_irq_handler+0x18/0x24 el1h_64_irq+0x68/0x6c _raw_spin_unlock_irqrestore+0x3c/0x6c debug_object_assert_init+0x16c/0x21c __mod_timer+0x4c/0x48c schedule_timeout+0xd4/0x16c io_schedule_timeout+0x48/0x70 do_wait_for_common+0x100/0x194 wait_for_completion_io_timeout+0x48/0x6c blk_execute_rq+0x124/0x17c scsi_execute_cmd+0x18c/0x3f8 scsi_probe_and_add_lun+0x204/0xd74 __scsi_add_device+0xbc/0x120 ufshcd_async_scan+0x80/0x3c0 async_run_entry_fn+0x4c/0x17c process_one_work+0x26c/0x65c worker_thread+0x33c/0x498 kthread+0x110/0x134 ret_from_fork+0x10/0x20 Cc: Neil Armstrong Cc: AndrĆ© Draszik Reviewed-by: Peter Wang Fixes: 3c7ac40d7322 ("scsi: ufs: core: Delegate the interrupt service routine to a threaded IRQ handler") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20250815155842.472867-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index efd7a811a002e9..b047325a3669a2 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5559,7 +5559,7 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) irqreturn_t retval = IRQ_NONE; struct uic_command *cmd; - spin_lock(hba->host->host_lock); + guard(spinlock_irqsave)(hba->host->host_lock); cmd = hba->active_uic_cmd; if (WARN_ON_ONCE(!cmd)) goto unlock; @@ -5586,8 +5586,6 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) ufshcd_add_uic_command_trace(hba, cmd, UFS_CMD_COMP); unlock: - spin_unlock(hba->host->host_lock); - return retval; } @@ -6920,7 +6918,7 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba, u32 intr_status) bool queue_eh_work = false; irqreturn_t retval = IRQ_NONE; - spin_lock(hba->host->host_lock); + guard(spinlock_irqsave)(hba->host->host_lock); hba->errors |= UFSHCD_ERROR_MASK & intr_status; if (hba->errors & INT_FATAL_ERRORS) { @@ -6979,7 +6977,7 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba, u32 intr_status) */ hba->errors = 0; hba->uic_error = 0; - spin_unlock(hba->host->host_lock); + return retval; } From e5203d89d59bfcbe1f348aa0d2dc4449a8ba644c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 15 Aug 2025 08:58:24 -0700 Subject: [PATCH 0323/1292] scsi: ufs: core: Remove WARN_ON_ONCE() call from ufshcd_uic_cmd_compl() The UIC completion interrupt may be disabled while an UIC command is being processed. When the UIC completion interrupt is reenabled, an UIC interrupt is triggered and the WARN_ON_ONCE(!cmd) statement is hit. Hence this patch that removes this kernel warning. Fixes: fcd8b0450a9a ("scsi: ufs: core: Make ufshcd_uic_cmd_compl() easier to analyze") Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20250815155842.472867-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index b047325a3669a2..2097efe3a99094 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5561,7 +5561,7 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) guard(spinlock_irqsave)(hba->host->host_lock); cmd = hba->active_uic_cmd; - if (WARN_ON_ONCE(!cmd)) + if (!cmd) goto unlock; if (ufshcd_is_auto_hibern8_error(hba, intr_status)) From 9ee35fd43f94bf19dbd27cffc213a31314b623d2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 15 Aug 2025 08:58:25 -0700 Subject: [PATCH 0324/1292] scsi: ufs: core: Fix the return value documentation ufshcd_wait_for_dev_cmd() and all its callers can return an OCS error. OCS errors are represented by positive integers. Remove the WARN_ONCE() statements that complain about positive error codes and update the documentation. Keep the behavior of ufshcd_wait_for_dev_cmd() because this return value may end be passed as the second argument of bsg_job_done() and bsg_job_done() handles positive and negative error codes differently. Cc: Peter Wang Fixes: cc59f3b68542 ("scsi: ufs: core: Improve return value documentation") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20250815155842.472867-4-bvanassche@acm.org Reviewed-by: Peter Wang Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 62 ++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 2097efe3a99094..f471288a5c707a 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3199,7 +3199,8 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) } /* - * Return: 0 upon success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int max_timeout) @@ -3275,7 +3276,6 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, } } - WARN_ONCE(err > 0, "Incorrect return value %d > 0\n", err); return err; } @@ -3294,7 +3294,8 @@ static void ufshcd_dev_man_unlock(struct ufs_hba *hba) } /* - * Return: 0 upon success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ static int ufshcd_issue_dev_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, const u32 tag, int timeout) @@ -3317,7 +3318,8 @@ static int ufshcd_issue_dev_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, * @cmd_type: specifies the type (NOP, Query...) * @timeout: timeout in milliseconds * - * Return: 0 upon success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. * * NOTE: Since there is only one available tag for device management commands, * it is expected you hold the hba->dev_cmd.lock mutex. @@ -3363,6 +3365,10 @@ static inline void ufshcd_init_query(struct ufs_hba *hba, (*request)->upiu_req.selector = selector; } +/* + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. + */ static int ufshcd_query_flag_retry(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res) { @@ -3383,7 +3389,6 @@ static int ufshcd_query_flag_retry(struct ufs_hba *hba, dev_err(hba->dev, "%s: query flag, opcode %d, idn %d, failed with error %d after %d retries\n", __func__, opcode, idn, ret, retries); - WARN_ONCE(ret > 0, "Incorrect return value %d > 0\n", ret); return ret; } @@ -3395,7 +3400,8 @@ static int ufshcd_query_flag_retry(struct ufs_hba *hba, * @index: flag index to access * @flag_res: the flag value after the query request completes * - * Return: 0 for success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res) @@ -3451,7 +3457,6 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, out_unlock: ufshcd_dev_man_unlock(hba); - WARN_ONCE(err > 0, "Incorrect return value %d > 0\n", err); return err; } @@ -3464,8 +3469,9 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, * @selector: selector field * @attr_val: the attribute value after the query request completes * - * Return: 0 upon success; < 0 upon failure. -*/ + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. + */ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) { @@ -3513,7 +3519,6 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, out_unlock: ufshcd_dev_man_unlock(hba); - WARN_ONCE(err > 0, "Incorrect return value %d > 0\n", err); return err; } @@ -3528,8 +3533,9 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, * @attr_val: the attribute value after the query request * completes * - * Return: 0 for success; < 0 upon failure. -*/ + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. + */ int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) @@ -3551,12 +3557,12 @@ int ufshcd_query_attr_retry(struct ufs_hba *hba, dev_err(hba->dev, "%s: query attribute, idn %d, failed with error %d after %d retries\n", __func__, idn, ret, QUERY_REQ_RETRIES); - WARN_ONCE(ret > 0, "Incorrect return value %d > 0\n", ret); return ret; } /* - * Return: 0 if successful; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ static int __ufshcd_query_descriptor(struct ufs_hba *hba, enum query_opcode opcode, enum desc_idn idn, u8 index, @@ -3615,7 +3621,6 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, out_unlock: hba->dev_cmd.query.descriptor = NULL; ufshcd_dev_man_unlock(hba); - WARN_ONCE(err > 0, "Incorrect return value %d > 0\n", err); return err; } @@ -3632,7 +3637,8 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, * The buf_len parameter will contain, on return, the length parameter * received on the response. * - * Return: 0 for success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode, @@ -3650,7 +3656,6 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, break; } - WARN_ONCE(err > 0, "Incorrect return value %d > 0\n", err); return err; } @@ -3663,7 +3668,8 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, * @param_read_buf: pointer to buffer where parameter would be read * @param_size: sizeof(param_read_buf) * - * Return: 0 in case of success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, @@ -3730,7 +3736,6 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, out: if (is_kmalloc) kfree(desc_buf); - WARN_ONCE(ret > 0, "Incorrect return value %d > 0\n", ret); return ret; } @@ -4781,7 +4786,8 @@ EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode); * * Set fDeviceInit flag and poll until device toggles it. * - * Return: 0 upon success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ static int ufshcd_complete_dev_init(struct ufs_hba *hba) { @@ -5135,7 +5141,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba) * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations. * - * Return: 0 upon success; < 0 upon failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ static int ufshcd_verify_dev_init(struct ufs_hba *hba) { @@ -5867,7 +5874,8 @@ static inline int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask) * as the device is allowed to manage its own way of handling background * operations. * - * Return: zero on success, non-zero on failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba) { @@ -5906,7 +5914,8 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba) * host is idle so that BKOPS are managed effectively without any negative * impacts. * - * Return: zero on success, non-zero on failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) { @@ -6056,6 +6065,10 @@ static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba) __func__, err); } +/* + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. + */ int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id) { struct utp_upiu_query_v4_0 *upiu_resp; @@ -7452,7 +7465,8 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, * @sg_list: Pointer to SG list when DATA IN/OUT UPIU is required in ARPMB operation * @dir: DMA direction * - * Return: zero on success, non-zero on failure. + * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; + * < 0 if another error occurred. */ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, struct utp_upiu_req *rsp_upiu, struct ufs_ehs *req_ehs, From 09d57d68ba9a36117eadb75d3ecf817a3c091acc Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 15 Aug 2025 08:58:26 -0700 Subject: [PATCH 0325/1292] scsi: ufs: core: Rename ufshcd_wait_for_doorbell_clr() The name ufshcd_wait_for_doorbell_clr() refers to legacy mode. Commit 8d077ede48c1 ("scsi: ufs: Optimize the command queueing code") added support for MCQ mode in this function. Since then the name of this function is misleading. Hence change the name of this function into something that is appropriate for both legacy and MCQ mode. Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20250815155842.472867-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f471288a5c707a..9a43102b2b21e8 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1303,7 +1303,7 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba) * * Return: 0 upon success; -EBUSY upon timeout. */ -static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, +static int ufshcd_wait_for_pending_cmds(struct ufs_hba *hba, u64 wait_timeout_us) { int ret = 0; @@ -1431,7 +1431,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us) down_write(&hba->clk_scaling_lock); if (!hba->clk_scaling.is_allowed || - ufshcd_wait_for_doorbell_clr(hba, timeout_us)) { + ufshcd_wait_for_pending_cmds(hba, timeout_us)) { ret = -EBUSY; up_write(&hba->clk_scaling_lock); mutex_unlock(&hba->wb_mutex); From 6300d5c5438724c0876828da2f6e2c1a661871fc Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Mon, 11 Aug 2025 13:03:30 +0530 Subject: [PATCH 0326/1292] scsi: ufs: ufs-qcom: Fix ESI null pointer dereference ESI/MSI is a performance optimization feature that provides dedicated interrupts per MCQ hardware queue. This is optional feature and UFS MCQ should work with and without ESI feature. Commit e46a28cea29a ("scsi: ufs: qcom: Remove the MSI descriptor abuse") brings a regression in ESI (Enhanced System Interrupt) configuration that causes a null pointer dereference when Platform MSI allocation fails. The issue occurs in when platform_device_msi_init_and_alloc_irqs() in ufs_qcom_config_esi() fails (returns -EINVAL) but the current code uses __free() macro for automatic cleanup free MSI resources that were never successfully allocated. Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 Call trace: mutex_lock+0xc/0x54 (P) platform_device_msi_free_irqs_all+0x1c/0x40 ufs_qcom_config_esi+0x1d0/0x220 [ufs_qcom] ufshcd_config_mcq+0x28/0x104 ufshcd_init+0xa3c/0xf40 ufshcd_pltfrm_init+0x504/0x7d4 ufs_qcom_probe+0x20/0x58 [ufs_qcom] Fix by restructuring the ESI configuration to try MSI allocation first, before any other resource allocation and instead use explicit cleanup instead of __free() macro to avoid cleanup of unallocated resources. Tested on SM8750 platform with MCQ enabled, both with and without Platform ESI support. Fixes: e46a28cea29a ("scsi: ufs: qcom: Remove the MSI descriptor abuse") Cc: Manivannan Sadhasivam Cc: Thomas Gleixner Cc: James Bottomley Signed-off-by: Nitin Rawat Link: https://lore.kernel.org/r/20250811073330.20230-1-quic_nitirawa@quicinc.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 39 ++++++++++++++----------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 76fc70503a62eb..9574fdc2bb0fda 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -2070,17 +2070,6 @@ static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data) return IRQ_HANDLED; } -static void ufs_qcom_irq_free(struct ufs_qcom_irq *uqi) -{ - for (struct ufs_qcom_irq *q = uqi; q->irq; q++) - devm_free_irq(q->hba->dev, q->irq, q->hba); - - platform_device_msi_free_irqs_all(uqi->hba->dev); - devm_kfree(uqi->hba->dev, uqi); -} - -DEFINE_FREE(ufs_qcom_irq, struct ufs_qcom_irq *, if (_T) ufs_qcom_irq_free(_T)) - static int ufs_qcom_config_esi(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -2095,18 +2084,18 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) */ nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL]; - struct ufs_qcom_irq *qi __free(ufs_qcom_irq) = - devm_kcalloc(hba->dev, nr_irqs, sizeof(*qi), GFP_KERNEL); - if (!qi) - return -ENOMEM; - /* Preset so __free() has a pointer to hba in all error paths */ - qi[0].hba = hba; - ret = platform_device_msi_init_and_alloc_irqs(hba->dev, nr_irqs, ufs_qcom_write_msi_msg); if (ret) { - dev_err(hba->dev, "Failed to request Platform MSI %d\n", ret); - return ret; + dev_warn(hba->dev, "Platform MSI not supported or failed, continuing without ESI\n"); + return ret; /* Continue without ESI */ + } + + struct ufs_qcom_irq *qi = devm_kcalloc(hba->dev, nr_irqs, sizeof(*qi), GFP_KERNEL); + + if (!qi) { + platform_device_msi_free_irqs_all(hba->dev); + return -ENOMEM; } for (int idx = 0; idx < nr_irqs; idx++) { @@ -2117,15 +2106,17 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) ret = devm_request_irq(hba->dev, qi[idx].irq, ufs_qcom_mcq_esi_handler, IRQF_SHARED, "qcom-mcq-esi", qi + idx); if (ret) { - dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n", + dev_err(hba->dev, "%s: Failed to request IRQ for %d, err = %d\n", __func__, qi[idx].irq, ret); - qi[idx].irq = 0; + /* Free previously allocated IRQs */ + for (int j = 0; j < idx; j++) + devm_free_irq(hba->dev, qi[j].irq, qi + j); + platform_device_msi_free_irqs_all(hba->dev); + devm_kfree(hba->dev, qi); return ret; } } - retain_and_null_ptr(qi); - if (host->hw_ver.major >= 6) { ufshcd_rmwl(hba, ESI_VEC_MASK, FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1), REG_UFS_CFG3); From cd5d4621ba846dad9b2e6b0c2d1518d083fcfa13 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 18 Aug 2025 08:50:48 -0700 Subject: [PATCH 0327/1292] cpufreq: scmi: Account for malformed DT in scmi_dev_used_by_cpus() Broadcom STB platforms were early adopters (2017) of the SCMI framework and as a result, not all deployed systems have a Device Tree entry where SCMI protocol 0x13 (PERFORMANCE) is declared as a clock provider, nor are the CPU Device Tree node(s) referencing protocol 0x13 as their clock provider. This was clarified in commit e11c480b6df1 ("dt-bindings: firmware: arm,scmi: Extend bindings for protocol@13") in 2023. For those platforms, we allow the checks done by scmi_dev_used_by_cpus() to continue, and in the event of not having done an early return, we key off the documented compatible string and give them a pass to continue to use scmi-cpufreq. Fixes: 6c9bb8692272 ("cpufreq: scmi: Skip SCMI devices that aren't used by the CPUs") Signed-off-by: Florian Fainelli Reviewed-by: Sudeep Holla Signed-off-by: Viresh Kumar --- drivers/cpufreq/scmi-cpufreq.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index ef078426bfd51a..38c165d526d144 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -424,6 +425,15 @@ static bool scmi_dev_used_by_cpus(struct device *scmi_dev) return true; } + /* + * Older Broadcom STB chips had a "clocks" property for CPU node(s) + * that did not match the SCMI performance protocol node, if we got + * there, it means we had such an older Device Tree, therefore return + * true to preserve backwards compatibility. + */ + if (of_machine_is_compatible("brcm,brcmstb")) + return true; + return false; } From 018f659753fd38bb6fdba7fa8c751121b495e1f4 Mon Sep 17 00:00:00 2001 From: Vasiliy Kovalev Date: Mon, 18 Aug 2025 23:42:43 +0300 Subject: [PATCH 0328/1292] ALSA: hda/realtek: Fix headset mic on ASUS Zenbook 14 Add a PCI quirk to enable microphone input on the headphone jack on the ASUS Zenbook 14 UM3406HA laptop. This model uses an ALC294 codec with CS35L41 amplifiers over I2C, and the existing fixup for it did not enable the headset microphone. A new fix is introduced to get the mic working while keeping the amplifier settings correct. Fixes: 61cbc08fdb04 ("ALSA: hda/realtek: Add quirks for ASUS 2024 Zenbooks") Signed-off-by: Vasiliy Kovalev Link: https://patch.msgid.link/20250818204243.247297-1-kovalev@altlinux.org Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index db8e6352b94253..6c78a286172c52 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -3579,6 +3579,7 @@ enum { ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE, ALC294_FIXUP_ASUS_MIC, ALC294_FIXUP_ASUS_HEADSET_MIC, + ALC294_FIXUP_ASUS_I2C_HEADSET_MIC, ALC294_FIXUP_ASUS_SPK, ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE, ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE, @@ -4889,6 +4890,15 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MIC }, + [ALC294_FIXUP_ASUS_I2C_HEADSET_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a19020 }, /* use as headset mic */ + { } + }, + .chained = true, + .chain_id = ALC287_FIXUP_CS35L41_I2C_2 + }, [ALC294_FIXUP_ASUS_SPK] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -6730,7 +6740,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1b13, "ASUS U41SV/GA403U", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1b93, "ASUS G614JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x1c03, "ASUS UM3406HA", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1c03, "ASUS UM3406HA", ALC294_FIXUP_ASUS_I2C_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x1c33, "ASUS UX5304MA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2), From f4b3cef55f5f96fdb4e7f9ca90b7d6213689faeb Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 19 Aug 2025 14:03:44 +0800 Subject: [PATCH 0329/1292] ALSA: hda/realtek: Audio disappears on HP 15-fc000 after warm boot again There was a similar bug in the past (Bug 217440), which was fixed for this laptop. The same issue is occurring again as of kernel v.6.12.2. The symptoms are very similar - initially audio works but after a warm reboot, the audio completely disappears until the computer is powered off (there is no audio output at all). The issue is also related by caused by a different change now. By bisecting different kernel versions, I found that reverting cc3d0b5dd989 in patch_realtek.c[*] restores the sound and it works fine after the reboot. [*] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/sound/pci/hda/patch_realtek.c?h=v6.12.2&id=4ed7f16070a8475c088ff423b2eb11ba15eb89b6 [ patch description reformatted by tiwai ] Fixes: cc3d0b5dd989 ("ALSA: hda/realtek: Update ALC256 depop procedure") Link: https://bugzilla.kernel.org/show_bug.cgi?id=220109 Signed-off-by: Kailang Yang Link: https://lore.kernel.org/5317ca723c82447a938414fcca85cbf5@realtek.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 6c78a286172c52..0323606b3d6d9b 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -510,6 +510,15 @@ static void alc256_shutup(struct hda_codec *codec) hp_pin = 0x21; alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ + + /* 3k pull low control for Headset jack. */ + /* NOTE: call this before clearing the pin, otherwise codec stalls */ + /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly + * when booting with headset plugged. So skip setting it for the codec alc257 + */ + if (spec->en_3kpull_low) + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); if (hp_pin_sense) { @@ -520,14 +529,6 @@ static void alc256_shutup(struct hda_codec *codec) msleep(75); - /* 3k pull low control for Headset jack. */ - /* NOTE: call this before clearing the pin, otherwise codec stalls */ - /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly - * when booting with headset plugged. So skip setting it for the codec alc257 - */ - if (spec->en_3kpull_low) - alc_update_coef_idx(codec, 0x46, 0, 3 << 12); - if (!spec->no_shutup_pins) snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); From ff646d033783068cc5b38924873cab4a536b17c1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 5 Aug 2025 14:56:56 +0300 Subject: [PATCH 0330/1292] drm/i915: silence rpm wakeref asserts on GEN11_GU_MISC_IIR access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 8d9908e8fe9c ("drm/i915/display: remove small micro-optimizations in irq handling") not only removed the optimizations, it also enabled wakeref asserts for the GEN11_GU_MISC_IIR access. Silence the asserts by wrapping the access inside intel_display_rpm_assert_{block,unblock}(). Reported-by: "Jason A. Donenfeld" Closes: https://lore.kernel.org/r/aG0tWkfmxWtxl_xc@zx2c4.com Fixes: 8d9908e8fe9c ("drm/i915/display: remove small micro-optimizations in irq handling") Cc: stable@vger.kernel.org # v6.13+ Suggested-by: Ville SyrjƤlƤ Reviewed-by: Jouni Hƶgander Link: https://lore.kernel.org/r/20250805115656.832235-1-jani.nikula@intel.com Signed-off-by: Jani Nikula (cherry picked from commit cbd3baeffbc08052ce7dc53f11bf5524b4411056) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_display_irq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index fb25ec8adae3ff..68157f177b6a28 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -1506,10 +1506,14 @@ u32 gen11_gu_misc_irq_ack(struct intel_display *display, const u32 master_ctl) if (!(master_ctl & GEN11_GU_MISC_IRQ)) return 0; + intel_display_rpm_assert_block(display); + iir = intel_de_read(display, GEN11_GU_MISC_IIR); if (likely(iir)) intel_de_write(display, GEN11_GU_MISC_IIR, iir); + intel_display_rpm_assert_unblock(display); + return iir; } From 8236820fd767f400d1baefb71bc7e36e37730a1e Mon Sep 17 00:00:00 2001 From: Sebastian Brzezinka Date: Mon, 11 Aug 2025 09:12:31 +0000 Subject: [PATCH 0331/1292] drm/i915/gt: Relocate compression repacking WA for JSL/EHL CACHE_MODE_0 registers should be saved and restored as part of the context, not during engine reset. Move the related workaround (Disable Repacking for Compression) from rcs_engine_wa_init() to icl_ctx_workarounds_init() for Jasper Lake and Elkhart Lake platforms. This ensures the WA is applied during context initialisation. BSPEC: 11322 Fixes: 0ddae025ab6c ("drm/i915: Disable compression tricks on JSL") Closes: Fixes: 0ddae025ab6c ("drm/i915: Disable compression tricks on JSL") Signed-off-by: Sebastian Brzezinka Cc: stable@vger.kernel.org # v6.13+ Reviewed-by: Andi Shyti Reviewed-by: Krzysztof Karas Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/4feaa24094e019e000ceb6011d8cd419b0361b3f.1754902406.git.sebastian.brzezinka@intel.com (cherry picked from commit c9932f0d604e4c8f2c6018e598a322acb43c68a2) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index b37e400f74e536..5a95f06900b5d3 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -634,6 +634,8 @@ static void cfl_ctx_workarounds_init(struct intel_engine_cs *engine, static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { + struct drm_i915_private *i915 = engine->i915; + /* Wa_1406697149 (WaDisableBankHangMode:icl) */ wa_write(wal, GEN8_L3CNTLREG, GEN8_ERRDETBCTRL); @@ -669,6 +671,15 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, /* Wa_1406306137:icl,ehl */ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU); + + if (IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) { + /* + * Disable Repacking for Compression (masked R/W access) + * before rendering compressed surfaces for display. + */ + wa_masked_en(wal, CACHE_MODE_0_GEN7, + DISABLE_REPACKING_FOR_COMPRESSION); + } } /* @@ -2306,15 +2317,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN8_RC_SEMA_IDLE_MSG_DISABLE); } - if (IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) { - /* - * "Disable Repacking for Compression (masked R/W access) - * before rendering compressed surfaces for display." - */ - wa_masked_en(wal, CACHE_MODE_0_GEN7, - DISABLE_REPACKING_FOR_COMPRESSION); - } - if (GRAPHICS_VER(i915) == 11) { /* This is not an Wa. Enable for better image quality */ wa_masked_en(wal, From d4932a1b148bb6121121e56bad312c4339042d70 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Tue, 19 Aug 2025 10:33:56 +0800 Subject: [PATCH 0332/1292] x86/bugs: Fix GDS mitigation selecting when mitigation is off The current GDS mitigation logic incorrectly returns early when the attack vector mitigation is turned off, which leads to two problems: 1. CPUs without ARCH_CAP_GDS_CTRL support are incorrectly marked with GDS_MITIGATION_OFF when they should be marked as GDS_MITIGATION_UCODE_NEEDED. 2. The mitigation state checks and locking verification that follow are skipped, which means: - fail to detect if the mitigation was locked - miss the warning when trying to disable a locked mitigation Remove the early return to ensure proper mitigation state handling. This allows: - Proper mitigation classification for non-ARCH_CAP_GDS_CTRL CPUs - Complete mitigation state verification This also addresses the failed MSR 0x123 write attempt at boot on non-ARCH_CAP_GDS_CTRL CPUs: unchecked MSR access error: WRMSR to 0x123 (tried to write 0x0000000000000010) at rIP: ... (update_gds_msr) Call Trace: identify_secondary_cpu start_secondary common_startup_64 WARNING: CPU: 1 PID: 0 at arch/x86/kernel/cpu/bugs.c:1053 update_gds_msr [ bp: Massage, zap superfluous braces. ] Fixes: 8c7261abcb7ad ("x86/bugs: Add attack vector controls for GDS") Suggested-by: Pawan Gupta Signed-off-by: Li RongQing Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Pawan Gupta Link: https://lore.kernel.org/20250819023356.2012-1-lirongqing@baidu.com --- arch/x86/kernel/cpu/bugs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 2186a771b9fc3d..49ef1b832c1a55 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -1068,10 +1068,8 @@ static void __init gds_select_mitigation(void) if (gds_mitigation == GDS_MITIGATION_AUTO) { if (should_mitigate_vuln(X86_BUG_GDS)) gds_mitigation = GDS_MITIGATION_FULL; - else { + else gds_mitigation = GDS_MITIGATION_OFF; - return; - } } /* No microcode */ From 62c30c544359aa18b8fb2734166467a07d435c2d Mon Sep 17 00:00:00 2001 From: Qingfang Deng Date: Thu, 14 Aug 2025 09:25:57 +0800 Subject: [PATCH 0333/1292] net: ethernet: mtk_ppe: add RCU lock around dev_fill_forward_path Ensure ndo_fill_forward_path() is called with RCU lock held. Fixes: 2830e314778d ("net: ethernet: mtk-ppe: fix traffic offload with bridged wlan") Signed-off-by: Qingfang Deng Link: https://patch.msgid.link/20250814012559.3705-1-dqfext@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mediatek/mtk_ppe_offload.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c index c855fb799ce145..e9bd3274198379 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c @@ -101,7 +101,9 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) return -1; + rcu_read_lock(); err = dev_fill_forward_path(dev, addr, &stack); + rcu_read_unlock(); if (err) return err; From 0417adf367a0af11adf7ace849af4638cfb573f7 Mon Sep 17 00:00:00 2001 From: Qingfang Deng Date: Thu, 14 Aug 2025 09:25:58 +0800 Subject: [PATCH 0334/1292] ppp: fix race conditions in ppp_fill_forward_path ppp_fill_forward_path() has two race conditions: 1. The ppp->channels list can change between list_empty() and list_first_entry(), as ppp_lock() is not held. If the only channel is deleted in ppp_disconnect_channel(), list_first_entry() may access an empty head or a freed entry, and trigger a panic. 2. pch->chan can be NULL. When ppp_unregister_channel() is called, pch->chan is set to NULL before pch is removed from ppp->channels. Fix these by using a lockless RCU approach: - Use list_first_or_null_rcu() to safely test and access the first list entry. - Convert list modifications on ppp->channels to their RCU variants and add synchronize_net() after removal. - Check for a NULL pch->chan before dereferencing it. Fixes: f6efc675c9dd ("net: ppp: resolve forwarding path for bridge pppoe devices") Signed-off-by: Qingfang Deng Link: https://patch.msgid.link/20250814012559.3705-2-dqfext@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ppp/ppp_generic.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 8c98cbd4b06de9..824c8dc4120b33 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1598,11 +1599,14 @@ static int ppp_fill_forward_path(struct net_device_path_ctx *ctx, if (ppp->flags & SC_MULTILINK) return -EOPNOTSUPP; - if (list_empty(&ppp->channels)) + pch = list_first_or_null_rcu(&ppp->channels, struct channel, clist); + if (!pch) + return -ENODEV; + + chan = READ_ONCE(pch->chan); + if (!chan) return -ENODEV; - pch = list_first_entry(&ppp->channels, struct channel, clist); - chan = pch->chan; if (!chan->ops->fill_forward_path) return -EOPNOTSUPP; @@ -2994,7 +2998,7 @@ ppp_unregister_channel(struct ppp_channel *chan) */ down_write(&pch->chan_sem); spin_lock_bh(&pch->downl); - pch->chan = NULL; + WRITE_ONCE(pch->chan, NULL); spin_unlock_bh(&pch->downl); up_write(&pch->chan_sem); ppp_disconnect_channel(pch); @@ -3515,7 +3519,7 @@ ppp_connect_channel(struct channel *pch, int unit) hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ if (hdrlen > ppp->dev->hard_header_len) ppp->dev->hard_header_len = hdrlen; - list_add_tail(&pch->clist, &ppp->channels); + list_add_tail_rcu(&pch->clist, &ppp->channels); ++ppp->n_channels; pch->ppp = ppp; refcount_inc(&ppp->file.refcnt); @@ -3545,10 +3549,11 @@ ppp_disconnect_channel(struct channel *pch) if (ppp) { /* remove it from the ppp unit's list */ ppp_lock(ppp); - list_del(&pch->clist); + list_del_rcu(&pch->clist); if (--ppp->n_channels == 0) wake_up_interruptible(&ppp->file.rwait); ppp_unlock(ppp); + synchronize_net(); if (refcount_dec_and_test(&ppp->file.refcnt)) ppp_destroy_interface(ppp); err = 0; From 01792bc3e5bdafa171dd83c7073f00e7de93a653 Mon Sep 17 00:00:00 2001 From: MD Danish Anwar Date: Thu, 14 Aug 2025 16:21:06 +0530 Subject: [PATCH 0335/1292] net: ti: icssg-prueth: Fix HSR and switch offload Enablement during firwmare reload. To enable HSR / Switch offload, certain configurations are needed. Currently they are done inside icssg_change_mode(). This function only gets called if we move from one mode to another without bringing the links up / down. Once in HSR / Switch mode, if we bring the links down and bring it back up again. The callback sequence is, - emac_ndo_stop() Firmwares are stopped - emac_ndo_open() Firmwares are loaded In this path icssg_change_mode() doesn't get called and as a result the configurations needed for HSR / Switch is not done. To fix this, put all these configurations in a separate function icssg_enable_fw_offload() and call this from both icssg_change_mode() and emac_ndo_open() Fixes: 56375086d093 ("net: ti: icssg-prueth: Enable HSR Tx duplication, Tx Tag and Rx Tag offload") Signed-off-by: MD Danish Anwar Link: https://patch.msgid.link/20250814105106.1491871-1-danishanwar@ti.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/ti/icssg/icssg_prueth.c | 72 +++++++++++--------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c index 6c7d776ae4eed7..dadce6009791bc 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c @@ -203,6 +203,44 @@ static void prueth_emac_stop(struct prueth *prueth) } } +static void icssg_enable_fw_offload(struct prueth *prueth) +{ + struct prueth_emac *emac; + int mac; + + for (mac = PRUETH_MAC0; mac < PRUETH_NUM_MACS; mac++) { + emac = prueth->emac[mac]; + if (prueth->is_hsr_offload_mode) { + if (emac->ndev->features & NETIF_F_HW_HSR_TAG_RM) + icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE); + else + icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE); + } + + if (prueth->is_switch_mode || prueth->is_hsr_offload_mode) { + if (netif_running(emac->ndev)) { + icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan, + ICSSG_FDB_ENTRY_P0_MEMBERSHIP | + ICSSG_FDB_ENTRY_P1_MEMBERSHIP | + ICSSG_FDB_ENTRY_P2_MEMBERSHIP | + ICSSG_FDB_ENTRY_BLOCK, + true); + icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID, + BIT(emac->port_id) | DEFAULT_PORT_MASK, + BIT(emac->port_id) | DEFAULT_UNTAG_MASK, + true); + if (prueth->is_hsr_offload_mode) + icssg_vtbl_modify(emac, DEFAULT_VID, + DEFAULT_PORT_MASK, + DEFAULT_UNTAG_MASK, true); + icssg_set_pvid(prueth, emac->port_vlan, emac->port_id); + if (prueth->is_switch_mode) + icssg_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE); + } + } + } +} + static int prueth_emac_common_start(struct prueth *prueth) { struct prueth_emac *emac; @@ -753,6 +791,7 @@ static int emac_ndo_open(struct net_device *ndev) ret = prueth_emac_common_start(prueth); if (ret) goto free_rx_irq; + icssg_enable_fw_offload(prueth); } flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET; @@ -1360,8 +1399,7 @@ static int prueth_emac_restart(struct prueth *prueth) static void icssg_change_mode(struct prueth *prueth) { - struct prueth_emac *emac; - int mac, ret; + int ret; ret = prueth_emac_restart(prueth); if (ret) { @@ -1369,35 +1407,7 @@ static void icssg_change_mode(struct prueth *prueth) return; } - for (mac = PRUETH_MAC0; mac < PRUETH_NUM_MACS; mac++) { - emac = prueth->emac[mac]; - if (prueth->is_hsr_offload_mode) { - if (emac->ndev->features & NETIF_F_HW_HSR_TAG_RM) - icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE); - else - icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE); - } - - if (netif_running(emac->ndev)) { - icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan, - ICSSG_FDB_ENTRY_P0_MEMBERSHIP | - ICSSG_FDB_ENTRY_P1_MEMBERSHIP | - ICSSG_FDB_ENTRY_P2_MEMBERSHIP | - ICSSG_FDB_ENTRY_BLOCK, - true); - icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID, - BIT(emac->port_id) | DEFAULT_PORT_MASK, - BIT(emac->port_id) | DEFAULT_UNTAG_MASK, - true); - if (prueth->is_hsr_offload_mode) - icssg_vtbl_modify(emac, DEFAULT_VID, - DEFAULT_PORT_MASK, - DEFAULT_UNTAG_MASK, true); - icssg_set_pvid(prueth, emac->port_vlan, emac->port_id); - if (prueth->is_switch_mode) - icssg_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE); - } - } + icssg_enable_fw_offload(prueth); } static int prueth_netdevice_port_link(struct net_device *ndev, From 70fb252a84a47430240d924528a40e84c2b027e4 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 18 Aug 2025 10:59:07 -0400 Subject: [PATCH 0336/1292] USB: core: Update kerneldoc for usb_hcd_giveback_urb() The kerneldoc added for usb_hcd_giveback_urb() by commit 41631d3616c3 ("usb: core: Replace in_interrupt() in comments") is unclear and incorrect. Update the text for greater clarity and to say that URBs for a root hub will always use a BH context for their completion. Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/41eaae05-116a-4568-940c-eeb94ab6baa0@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6270fbb5c69988..9dd79769cad112 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1717,10 +1717,10 @@ static void usb_giveback_urb_bh(struct work_struct *work) * @urb: urb being returned to the USB device driver. * @status: completion status code for the URB. * - * Context: atomic. The completion callback is invoked in caller's context. - * For HCDs with HCD_BH flag set, the completion callback is invoked in BH - * context (except for URBs submitted to the root hub which always complete in - * caller's context). + * Context: atomic. The completion callback is invoked either in a work queue + * (BH) context or in the caller's context, depending on whether the HCD_BH + * flag is set in the @hcd structure, except that URBs submitted to the + * root hub always complete in BH context. * * This hands the URB from HCD to its USB device driver, using its * completion function. The HCD has freed all per-urb resources From 309b6341d5570fb2b41b923de2fc9bb147106b80 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 18 Aug 2025 18:50:19 +0200 Subject: [PATCH 0337/1292] usb: typec: fusb302: Revert incorrect threaded irq fix The fusb302 irq handler has been carefully optimized by Hans de Goede in commit 207338ec5a27 ("usb: typec: fusb302: Improve suspend/resume handling"). A recent 'fix' undid most of that work to avoid a virtio-gpio driver bug. This reverts the incorrect fix, since it is of very low quality. It reverts the quirks from Hans change (and thus reintroduces the problems fixed by Hans) while keeping the overhead from the original change. The proper fix to support using fusb302 with an interrupt line provided by virtio-gpio must be implemented in the virtio driver instead, which should support disabling the IRQ from the fusb302 interrupt routine. Cc: Hans de Goede Cc: Yongbo Zhang Fixes: 1c2d81bded19 ("usb: typec: fusb302: fix scheduling while atomic when using virtio-gpio") Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20250818-fusb302-unthreaded-irq-v1-1-3a9a11a9f56f@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/fusb302.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index a4ff2403ddd66f..870a71f953f6cd 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -1485,6 +1485,9 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) struct fusb302_chip *chip = dev_id; unsigned long flags; + /* Disable our level triggered IRQ until our irq_work has cleared it */ + disable_irq_nosync(chip->gpio_int_n_irq); + spin_lock_irqsave(&chip->irq_lock, flags); if (chip->irq_suspended) chip->irq_while_suspended = true; @@ -1627,6 +1630,7 @@ static void fusb302_irq_work(struct work_struct *work) } done: mutex_unlock(&chip->lock); + enable_irq(chip->gpio_int_n_irq); } static int init_gpio(struct fusb302_chip *chip) @@ -1751,10 +1755,9 @@ static int fusb302_probe(struct i2c_client *client) goto destroy_workqueue; } - ret = devm_request_threaded_irq(dev, chip->gpio_int_n_irq, - NULL, fusb302_irq_intn, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "fsc_interrupt_int_n", chip); + ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "fsc_interrupt_int_n", chip); if (ret < 0) { dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); goto tcpm_unregister_port; @@ -1779,6 +1782,7 @@ static void fusb302_remove(struct i2c_client *client) struct fusb302_chip *chip = i2c_get_clientdata(client); disable_irq_wake(chip->gpio_int_n_irq); + free_irq(chip->gpio_int_n_irq, chip); cancel_work_sync(&chip->irq_work); cancel_delayed_work_sync(&chip->bc_lvl_handler); tcpm_unregister_port(chip->tcpm_port); From 1ca61060de92a4320d73adfe5dc8d335653907ac Mon Sep 17 00:00:00 2001 From: Xu Yilun Date: Wed, 6 Aug 2025 15:06:05 +0800 Subject: [PATCH 0338/1292] fpga: zynq_fpga: Fix the wrong usage of dma_map_sgtable() dma_map_sgtable() returns only 0 or the error code. Read sgt->nents to get the number of mapped segments. Fixes: 37e00703228a ("zynq_fpga: use sgtable-based scatterlist wrappers") Reported-by: Pavel Pisa Closes: https://lore.kernel.org/linux-fpga/202508041548.22955.pisa@fel.cvut.cz/ Reviewed-by: Jason Gunthorpe Reviewed-by: Marek Szyprowski Signed-off-by: Xu Yilun Tested-by: Pavel Pisa Link: https://lore.kernel.org/r/20250806070605.1920909-2-yilun.xu@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/zynq-fpga.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 0be0d569589d5c..b7629a0e481340 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -405,12 +405,12 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr, struct sg_table *sgt) } } - priv->dma_nelms = - dma_map_sgtable(mgr->dev.parent, sgt, DMA_TO_DEVICE, 0); - if (priv->dma_nelms == 0) { + err = dma_map_sgtable(mgr->dev.parent, sgt, DMA_TO_DEVICE, 0); + if (err) { dev_err(&mgr->dev, "Unable to DMA map (TO_DEVICE)\n"); - return -ENOMEM; + return err; } + priv->dma_nelms = sgt->nents; /* enable clock */ err = clk_enable(priv->clk); From 300a0cfe9f375b2843bcb331bcfa7503475ef5dd Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 6 Aug 2025 11:05:09 +0200 Subject: [PATCH 0339/1292] cdx: Fix off-by-one error in cdx_rpmsg_probe() In cdx_rpmsg_probe(), strscpy() is incorrectly called with the length of the source string (excluding the NUL terminator) rather than the size of the destination buffer. This results in one character less being copied from 'cdx_rpmsg_id_table[0].name' to 'chinfo.name'. Use the destination buffer size instead to ensure the name is copied correctly. Cc: stable Fixes: 2a226927d9b8 ("cdx: add rpmsg communication channel for CDX") Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250806090512.121260-2-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/controller/cdx_rpmsg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cdx/controller/cdx_rpmsg.c b/drivers/cdx/controller/cdx_rpmsg.c index 04b578a0be17c2..61f1a290ff0890 100644 --- a/drivers/cdx/controller/cdx_rpmsg.c +++ b/drivers/cdx/controller/cdx_rpmsg.c @@ -129,8 +129,7 @@ static int cdx_rpmsg_probe(struct rpmsg_device *rpdev) chinfo.src = RPMSG_ADDR_ANY; chinfo.dst = rpdev->dst; - strscpy(chinfo.name, cdx_rpmsg_id_table[0].name, - strlen(cdx_rpmsg_id_table[0].name)); + strscpy(chinfo.name, cdx_rpmsg_id_table[0].name, sizeof(chinfo.name)); cdx_mcdi->ept = rpmsg_create_ept(rpdev, cdx_rpmsg_cb, NULL, chinfo); if (!cdx_mcdi->ept) { From 96cb948408b3adb69df7e451ba7da9d21f814d00 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Mon, 7 Jul 2025 20:39:58 +0800 Subject: [PATCH 0340/1292] comedi: pcl726: Prevent invalid irq number The reproducer passed in an irq number(0x80008000) that was too large, which triggered the oob. Added an interrupt number check to prevent users from passing in an irq number that was too large. If `it->options[1]` is 31, then `1 << it->options[1]` is still invalid because it shifts a 1-bit into the sign bit (which is UB in C). Possible solutions include reducing the upper bound on the `it->options[1]` value to 30 or lower, or using `1U << it->options[1]`. The old code would just not attempt to request the IRQ if the `options[1]` value were invalid. And it would still configure the device without interrupts even if the call to `request_irq` returned an error. So it would be better to combine this test with the test below. Fixes: fff46207245c ("staging: comedi: pcl726: enable the interrupt support code") Cc: stable # 5.13+ Reported-by: syzbot+5cd373521edd68bebcb3@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=5cd373521edd68bebcb3 Tested-by: syzbot+5cd373521edd68bebcb3@syzkaller.appspotmail.com Signed-off-by: Edward Adam Davis Reviewed-by: Ian Abbott Link: https://lore.kernel.org/r/tencent_3C66983CC1369E962436264A50759176BF09@qq.com Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/pcl726.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/comedi/drivers/pcl726.c b/drivers/comedi/drivers/pcl726.c index 0430630e6ebb90..b542896fa0e427 100644 --- a/drivers/comedi/drivers/pcl726.c +++ b/drivers/comedi/drivers/pcl726.c @@ -328,7 +328,8 @@ static int pcl726_attach(struct comedi_device *dev, * Hook up the external trigger source interrupt only if the * user config option is valid and the board supports interrupts. */ - if (it->options[1] && (board->irq_mask & (1 << it->options[1]))) { + if (it->options[1] > 0 && it->options[1] < 16 && + (board->irq_mask & (1U << it->options[1]))) { ret = request_irq(it->options[1], pcl726_interrupt, 0, dev->board_name, dev); if (ret == 0) { From 3cd212e895ca2d58963fdc6422502b10dd3966bb Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 25 Jul 2025 13:53:24 +0100 Subject: [PATCH 0341/1292] comedi: Fix use of uninitialized memory in do_insn_ioctl() and do_insnlist_ioctl() syzbot reports a KMSAN kernel-infoleak in `do_insn_ioctl()`. A kernel buffer is allocated to hold `insn->n` samples (each of which is an `unsigned int`). For some instruction types, `insn->n` samples are copied back to user-space, unless an error code is being returned. The problem is that not all the instruction handlers that need to return data to userspace fill in the whole `insn->n` samples, so that there is an information leak. There is a similar syzbot report for `do_insnlist_ioctl()`, although it does not have a reproducer for it at the time of writing. One culprit is `insn_rw_emulate_bits()` which is used as the handler for `INSN_READ` or `INSN_WRITE` instructions for subdevices that do not have a specific handler for that instruction, but do have an `INSN_BITS` handler. For `INSN_READ` it only fills in at most 1 sample, so if `insn->n` is greater than 1, the remaining `insn->n - 1` samples copied to userspace will be uninitialized kernel data. Another culprit is `vm80xx_ai_insn_read()` in the "vm80xx" driver. It never returns an error, even if it fails to fill the buffer. Fix it in `do_insn_ioctl()` and `do_insnlist_ioctl()` by making sure that uninitialized parts of the allocated buffer are zeroed before handling each instruction. Thanks to Arnaud Lecomte for their fix to `do_insn_ioctl()`. That fix replaced the call to `kmalloc_array()` with `kcalloc()`, but it is not always necessary to clear the whole buffer. Fixes: ed9eccbe8970 ("Staging: add comedi core") Reported-by: syzbot+a5e45f768aab5892da5d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=a5e45f768aab5892da5d Reported-by: syzbot+fb4362a104d45ab09cf9@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=fb4362a104d45ab09cf9 Cc: stable # 5.13+ Cc: Arnaud Lecomte Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20250725125324.80276-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/comedi_fops.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c index 23b7178522ae03..7e2f2b1a1c362e 100644 --- a/drivers/comedi/comedi_fops.c +++ b/drivers/comedi/comedi_fops.c @@ -1587,6 +1587,9 @@ static int do_insnlist_ioctl(struct comedi_device *dev, memset(&data[n], 0, (MIN_SAMPLES - n) * sizeof(unsigned int)); } + } else { + memset(data, 0, max_t(unsigned int, n, MIN_SAMPLES) * + sizeof(unsigned int)); } ret = parse_insn(dev, insns + i, data, file); if (ret < 0) @@ -1670,6 +1673,8 @@ static int do_insn_ioctl(struct comedi_device *dev, memset(&data[insn->n], 0, (MIN_SAMPLES - insn->n) * sizeof(unsigned int)); } + } else { + memset(data, 0, n_data * sizeof(unsigned int)); } ret = parse_insn(dev, insn, data, file); if (ret < 0) From 7afba9221f70d4cbce0f417c558879cba0eb5e66 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 25 Jul 2025 15:10:34 +0100 Subject: [PATCH 0342/1292] comedi: Make insn_rw_emulate_bits() do insn->n samples The `insn_rw_emulate_bits()` function is used as a default handler for `INSN_READ` instructions for subdevices that have a handler for `INSN_BITS` but not for `INSN_READ`. Similarly, it is used as a default handler for `INSN_WRITE` instructions for subdevices that have a handler for `INSN_BITS` but not for `INSN_WRITE`. It works by emulating the `INSN_READ` or `INSN_WRITE` instruction handling with a constructed `INSN_BITS` instruction. However, `INSN_READ` and `INSN_WRITE` instructions are supposed to be able read or write multiple samples, indicated by the `insn->n` value, but `insn_rw_emulate_bits()` currently only handles a single sample. For `INSN_READ`, the comedi core will copy `insn->n` samples back to user-space. (That triggered KASAN kernel-infoleak errors when `insn->n` was greater than 1, but that is being fixed more generally elsewhere in the comedi core.) Make `insn_rw_emulate_bits()` either handle `insn->n` samples, or return an error, to conform to the general expectation for `INSN_READ` and `INSN_WRITE` handlers. Fixes: ed9eccbe8970 ("Staging: add comedi core") Cc: stable # 5.13+ Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20250725141034.87297-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/comedi/drivers.c b/drivers/comedi/drivers.c index f1dc854928c176..c9ebaadc5e82af 100644 --- a/drivers/comedi/drivers.c +++ b/drivers/comedi/drivers.c @@ -620,11 +620,9 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, unsigned int chan = CR_CHAN(insn->chanspec); unsigned int base_chan = (chan < 32) ? 0 : chan; unsigned int _data[2]; + unsigned int i; int ret; - if (insn->n == 0) - return 0; - memset(_data, 0, sizeof(_data)); memset(&_insn, 0, sizeof(_insn)); _insn.insn = INSN_BITS; @@ -635,18 +633,21 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, if (insn->insn == INSN_WRITE) { if (!(s->subdev_flags & SDF_WRITABLE)) return -EINVAL; - _data[0] = 1U << (chan - base_chan); /* mask */ - _data[1] = data[0] ? (1U << (chan - base_chan)) : 0; /* bits */ + _data[0] = 1U << (chan - base_chan); /* mask */ } + for (i = 0; i < insn->n; i++) { + if (insn->insn == INSN_WRITE) + _data[1] = data[i] ? _data[0] : 0; /* bits */ - ret = s->insn_bits(dev, s, &_insn, _data); - if (ret < 0) - return ret; + ret = s->insn_bits(dev, s, &_insn, _data); + if (ret < 0) + return ret; - if (insn->insn == INSN_READ) - data[0] = (_data[1] >> (chan - base_chan)) & 1; + if (insn->insn == INSN_READ) + data[i] = (_data[1] >> (chan - base_chan)) & 1; + } - return 1; + return insn->n; } static int __comedi_device_postconfig_async(struct comedi_device *dev, From b47b493d6387ae437098112936f32be27f73516c Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 4 Aug 2025 12:29:55 +0400 Subject: [PATCH 0343/1292] most: core: Drop device reference after usage in get_channel() In get_channel(), the reference obtained by bus_find_device_by_name() was dropped via put_device() before accessing the device's driver data Move put_device() after usage to avoid potential issues. Fixes: 2485055394be ("staging: most: core: drop device reference") Cc: stable Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20250804082955.3621026-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/most/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/most/core.c b/drivers/most/core.c index a635d5082ebb64..da319d108ea1df 100644 --- a/drivers/most/core.c +++ b/drivers/most/core.c @@ -538,8 +538,8 @@ static struct most_channel *get_channel(char *mdev, char *mdev_ch) dev = bus_find_device_by_name(&mostbus, NULL, mdev); if (!dev) return NULL; - put_device(dev); iface = dev_get_drvdata(dev); + put_device(dev); list_for_each_entry_safe(c, tmp, &iface->p->channel_list, list) { if (!strcmp(dev_name(&c->dev), mdev_ch)) return c; From 7375f22495e7cd1c5b3b5af9dcc4f6dffe34ce49 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Mon, 11 Aug 2025 22:18:30 +0800 Subject: [PATCH 0344/1292] fs/buffer: fix use-after-free when call bh_read() helper There's issue as follows: BUG: KASAN: stack-out-of-bounds in end_buffer_read_sync+0xe3/0x110 Read of size 8 at addr ffffc9000168f7f8 by task swapper/3/0 CPU: 3 UID: 0 PID: 0 Comm: swapper/3 Not tainted 6.16.0-862.14.0.6.x86_64 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) Call Trace: dump_stack_lvl+0x55/0x70 print_address_description.constprop.0+0x2c/0x390 print_report+0xb4/0x270 kasan_report+0xb8/0xf0 end_buffer_read_sync+0xe3/0x110 end_bio_bh_io_sync+0x56/0x80 blk_update_request+0x30a/0x720 scsi_end_request+0x51/0x2b0 scsi_io_completion+0xe3/0x480 ? scsi_device_unbusy+0x11e/0x160 blk_complete_reqs+0x7b/0x90 handle_softirqs+0xef/0x370 irq_exit_rcu+0xa5/0xd0 sysvec_apic_timer_interrupt+0x6e/0x90 Above issue happens when do ntfs3 filesystem mount, issue may happens as follows: mount IRQ ntfs_fill_super read_cache_page do_read_cache_folio filemap_read_folio mpage_read_folio do_mpage_readpage ntfs_get_block_vbo bh_read submit_bh wait_on_buffer(bh); blk_complete_reqs scsi_io_completion scsi_end_request blk_update_request end_bio_bh_io_sync end_buffer_read_sync __end_buffer_read_notouch unlock_buffer wait_on_buffer(bh);--> return will return to caller put_bh --> trigger stack-out-of-bounds In the mpage_read_folio() function, the stack variable 'map_bh' is passed to ntfs_get_block_vbo(). Once unlock_buffer() unlocks and wait_on_buffer() returns to continue processing, the stack variable is likely to be reclaimed. Consequently, during the end_buffer_read_sync() process, calling put_bh() may result in stack overrun. If the bh is not allocated on the stack, it belongs to a folio. Freeing a buffer head which belongs to a folio is done by drop_buffers() which will fail to free buffers which are still locked. So it is safe to call put_bh() before __end_buffer_read_notouch(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Ye Bin Link: https://lore.kernel.org/20250811141830.343774-1-yebin@huaweicloud.com Reviewed-by: Matthew Wilcox (Oracle) Signed-off-by: Christian Brauner --- fs/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/buffer.c b/fs/buffer.c index ead4dc85debdd6..6a8752f7bbedba 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -157,8 +157,8 @@ static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate) */ void end_buffer_read_sync(struct buffer_head *bh, int uptodate) { - __end_buffer_read_notouch(bh, uptodate); put_bh(bh); + __end_buffer_read_notouch(bh, uptodate); } EXPORT_SYMBOL(end_buffer_read_sync); From 589c12edcd8a7b3b24f407b58443bab3560125e4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Aug 2025 12:41:15 +0300 Subject: [PATCH 0345/1292] coredump: Fix return value in coredump_parse() The coredump_parse() function is bool type. It should return true on success and false on failure. The cn_printf() returns zero on success or negative error codes. This mismatch means that when "return err;" here, it is treated as success instead of failure. Change it to return false instead. Fixes: a5715af549b2 ("coredump: make coredump_parse() return bool") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/aKRGu14w5vPSZLgv@stanley.mountain Signed-off-by: Christian Brauner --- fs/coredump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/coredump.c b/fs/coredump.c index fedbead956ed16..5dce257c67fc8b 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -345,7 +345,7 @@ static bool coredump_parse(struct core_name *cn, struct coredump_params *cprm, was_space = false; err = cn_printf(cn, "%c", '\0'); if (err) - return err; + return false; (*argv)[(*argc)++] = cn->used; } } From c237aa9884f238e1480897463ca034877ca7530b Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 19 Aug 2025 12:08:58 +0200 Subject: [PATCH 0346/1292] kernfs: don't fail listing extended attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Userspace doesn't expect a failure to list extended attributes: $ ls -lA /sys/ ls: /sys/: No data available ls: /sys/kernel: No data available ls: /sys/power: No data available ls: /sys/class: No data available ls: /sys/devices: No data available ls: /sys/dev: No data available ls: /sys/hypervisor: No data available ls: /sys/fs: No data available ls: /sys/bus: No data available ls: /sys/firmware: No data available ls: /sys/block: No data available ls: /sys/module: No data available total 0 drwxr-xr-x 2 root root 0 Jan 1 1970 block drwxr-xr-x 52 root root 0 Jan 1 1970 bus drwxr-xr-x 88 root root 0 Jan 1 1970 class drwxr-xr-x 4 root root 0 Jan 1 1970 dev drwxr-xr-x 11 root root 0 Jan 1 1970 devices drwxr-xr-x 3 root root 0 Jan 1 1970 firmware drwxr-xr-x 10 root root 0 Jan 1 1970 fs drwxr-xr-x 2 root root 0 Jul 2 09:43 hypervisor drwxr-xr-x 14 root root 0 Jan 1 1970 kernel drwxr-xr-x 251 root root 0 Jan 1 1970 module drwxr-xr-x 3 root root 0 Jul 2 09:43 power Fix it by simply reporting success when no extended attributes are available instead of reporting ENODATA. Link: https://lore.kernel.org/78b13bcdae82ade95e88f315682966051f461dde.camel@linaro.org Fixes: d1f4e9026007 ("kernfs: remove iattr_mutex") # mainline only Reported-by: AndrĆ© Draszik Link: https://lore.kernel.org/20250819-ahndung-abgaben-524a535f8101@brauner Signed-off-by: Christian Brauner --- fs/kernfs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 3c293a5a21b1ce..457f91c412d483 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -142,9 +142,9 @@ ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size) struct kernfs_node *kn = kernfs_dentry_node(dentry); struct kernfs_iattrs *attrs; - attrs = kernfs_iattrs_noalloc(kn); + attrs = kernfs_iattrs(kn); if (!attrs) - return -ENODATA; + return -ENOMEM; return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size); } From a2c1f82618b0b65f1ef615aa9cfdac8122537d69 Mon Sep 17 00:00:00 2001 From: "Adrian Huang (Lenovo)" Date: Mon, 18 Aug 2025 21:43:10 +0800 Subject: [PATCH 0347/1292] signal: Fix memory leak for PIDFD_SELF* sentinels Commit f08d0c3a7111 ("pidfd: add PIDFD_SELF* sentinels to refer to own thread/process") introduced a leak by acquiring a pid reference through get_task_pid(), which increments pid->count but never drops it with put_pid(). As a result, kmemleak reports unreferenced pid objects after running tools/testing/selftests/pidfd/pidfd_test, for example: unreferenced object 0xff1100206757a940 (size 160): comm "pidfd_test", pid 16965, jiffies 4294853028 hex dump (first 32 bytes): 01 00 00 00 00 00 00 00 00 00 00 00 fd 57 50 04 .............WP. 5e 44 00 00 00 00 00 00 18 de 34 17 01 00 11 ff ^D........4..... backtrace (crc cd8844d4): kmem_cache_alloc_noprof+0x2f4/0x3f0 alloc_pid+0x54/0x3d0 copy_process+0xd58/0x1740 kernel_clone+0x99/0x3b0 __do_sys_clone3+0xbe/0x100 do_syscall_64+0x7b/0x2c0 entry_SYSCALL_64_after_hwframe+0x76/0x7e Fix this by calling put_pid() after do_pidfd_send_signal() returns. Fixes: f08d0c3a7111 ("pidfd: add PIDFD_SELF* sentinels to refer to own thread/process") Signed-off-by: Adrian Huang (Lenovo) Link: https://lore.kernel.org/20250818134310.12273-1-adrianhuang0701@gmail.com Tested-by: Lorenzo Stoakes Reviewed-by: Lorenzo Stoakes Signed-off-by: Christian Brauner --- kernel/signal.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/signal.c b/kernel/signal.c index e2c928de7d2c14..fe9190d84f281e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -4067,6 +4067,7 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig, { struct pid *pid; enum pid_type type; + int ret; /* Enforce flags be set to 0 until we add an extension. */ if (flags & ~PIDFD_SEND_SIGNAL_FLAGS) @@ -4108,7 +4109,10 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig, } } - return do_pidfd_send_signal(pid, sig, type, info, flags); + ret = do_pidfd_send_signal(pid, sig, type, info, flags); + put_pid(pid); + + return ret; } static int From 23800ad1265f10c2bc6f42154ce4d20e59f2900e Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Thu, 14 Aug 2025 13:34:29 -0500 Subject: [PATCH 0348/1292] gpiolib: acpi: Add quirk for ASUS ProArt PX13 The ASUS ProArt PX13 has a spurious wakeup event from the touchpad a few moments after entering hardware sleep. This can be avoided by preventing the touchpad from being a wake source. Add to the wakeup ignore list. Reported-by: Amit Chaudhari Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4482 Tested-by: Amit Chaudhari Signed-off-by: Mario Limonciello (AMD) Reviewed-by: Mika Westerberg Link: https://lore.kernel.org/20250814183430.3887973-1-superm1@kernel.org Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi-quirks.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi-quirks.c b/drivers/gpio/gpiolib-acpi-quirks.c index c13545dce3492d..bfb04e67c4bc87 100644 --- a/drivers/gpio/gpiolib-acpi-quirks.c +++ b/drivers/gpio/gpiolib-acpi-quirks.c @@ -344,6 +344,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_interrupt = "AMDI0030:00@8", }, }, + { + /* + * Spurious wakeups from TP_ATTN# pin + * Found in BIOS 5.35 + * https://gitlab.freedesktop.org/drm/amd/-/issues/4482 + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt PX13"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "ASCP1A00:00@8", + }, + }, {} /* Terminating entry */ }; From 9ce43caa4b7be707638d49ad4fb358b6ff646e91 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Tue, 12 Aug 2025 11:55:19 +0900 Subject: [PATCH 0349/1292] xfs: Default XFS_RT to Y if CONFIG_BLK_DEV_ZONED is enabled XFS support for zoned block devices requires the realtime subvolume support (XFS_RT) to be enabled. Change the default configuration value of XFS_RT from N to CONFIG_BLK_DEV_ZONED to align with this requirement. This change still allows the user to disable XFS_RT if this feature is not desired for the user use case. Suggested-by: Christoph Hellwig Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig Reviewed-by: Carlos Maiolino Signed-off-by: Carlos Maiolino --- fs/xfs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig index ae0ca68584963a..065953475cf5eb 100644 --- a/fs/xfs/Kconfig +++ b/fs/xfs/Kconfig @@ -105,6 +105,7 @@ config XFS_POSIX_ACL config XFS_RT bool "XFS Realtime subvolume support" depends on XFS_FS + default BLK_DEV_ZONED help If you say Y here you will be able to mount and use XFS filesystems which contain a realtime subvolume. The realtime subvolume is a From d004d70d6cdf03928da0d05c8c15c2ccc15657cd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Aug 2025 07:06:43 +0200 Subject: [PATCH 0350/1292] xfs: remove xfs_last_used_zone This was my first attempt at caching the last used zone. But it turns out for O_DIRECT or RWF_DONTCACHE that operate concurrently or in very short sequence, the bmap btree does not record a written extent yet, so it fails. Because it then still finds the last written zone it can lead to a weird ping-pong around a few zones with writers seeing different values. Remove it entirely as the later added xfs_cached_zone actually does a much better job enforcing the locality as the zone is associated with the inode in the MRU cache as soon as the zone is selected. Fixes: 4e4d52075577 ("xfs: add the zoned space allocator") Signed-off-by: Christoph Hellwig Tested-by: Damien Le Moal Reviewed-by: Hans Holmberg Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_zone_alloc.c | 45 ++--------------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/fs/xfs/xfs_zone_alloc.c b/fs/xfs/xfs_zone_alloc.c index f8bd6d74175541..f28214c28ab545 100644 --- a/fs/xfs/xfs_zone_alloc.c +++ b/fs/xfs/xfs_zone_alloc.c @@ -374,44 +374,6 @@ xfs_zone_free_blocks( return 0; } -/* - * Check if the zone containing the data just before the offset we are - * writing to is still open and has space. - */ -static struct xfs_open_zone * -xfs_last_used_zone( - struct iomap_ioend *ioend) -{ - struct xfs_inode *ip = XFS_I(ioend->io_inode); - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t offset_fsb = XFS_B_TO_FSB(mp, ioend->io_offset); - struct xfs_rtgroup *rtg = NULL; - struct xfs_open_zone *oz = NULL; - struct xfs_iext_cursor icur; - struct xfs_bmbt_irec got; - - xfs_ilock(ip, XFS_ILOCK_SHARED); - if (!xfs_iext_lookup_extent_before(ip, &ip->i_df, &offset_fsb, - &icur, &got)) { - xfs_iunlock(ip, XFS_ILOCK_SHARED); - return NULL; - } - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - rtg = xfs_rtgroup_grab(mp, xfs_rtb_to_rgno(mp, got.br_startblock)); - if (!rtg) - return NULL; - - xfs_ilock(rtg_rmap(rtg), XFS_ILOCK_SHARED); - oz = READ_ONCE(rtg->rtg_open_zone); - if (oz && (oz->oz_is_gc || !atomic_inc_not_zero(&oz->oz_ref))) - oz = NULL; - xfs_iunlock(rtg_rmap(rtg), XFS_ILOCK_SHARED); - - xfs_rtgroup_rele(rtg); - return oz; -} - static struct xfs_group * xfs_find_free_zone( struct xfs_mount *mp, @@ -918,12 +880,9 @@ xfs_zone_alloc_and_submit( goto out_error; /* - * If we don't have a cached zone in this write context, see if the - * last extent before the one we are writing to points to an active - * zone. If so, just continue writing to it. + * If we don't have a locally cached zone in this write context, see if + * the inode is still associated with a zone and use that if so. */ - if (!*oz && ioend->io_offset) - *oz = xfs_last_used_zone(ioend); if (!*oz) *oz = xfs_cached_zone(mp, ip); From 7d523255f524c95208cefef4edaed149615ff96c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Aug 2025 07:06:44 +0200 Subject: [PATCH 0351/1292] xfs: kick off inodegc when failing to reserve zoned blocks XFS processes truncating unlinked inodes asynchronously and thus the free space pool only sees them with a delay. The non-zoned write path thus calls into inodegc to accelerate this processing before failing an allocation due the lack of free blocks. Do the same for the zoned space reservation. Fixes: 0bb2193056b5 ("xfs: add support for zoned space reservations") Signed-off-by: Christoph Hellwig Reviewed-by: Hans Holmberg Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_zone_space_resv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/xfs/xfs_zone_space_resv.c b/fs/xfs/xfs_zone_space_resv.c index 1313c55b8cbe51..9cd38716fd25f6 100644 --- a/fs/xfs/xfs_zone_space_resv.c +++ b/fs/xfs/xfs_zone_space_resv.c @@ -10,6 +10,7 @@ #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_rtbitmap.h" +#include "xfs_icache.h" #include "xfs_zone_alloc.h" #include "xfs_zone_priv.h" #include "xfs_zones.h" @@ -230,6 +231,11 @@ xfs_zoned_space_reserve( error = xfs_dec_freecounter(mp, XC_FREE_RTEXTENTS, count_fsb, flags & XFS_ZR_RESERVED); + if (error == -ENOSPC && !(flags & XFS_ZR_NOWAIT)) { + xfs_inodegc_flush(mp); + error = xfs_dec_freecounter(mp, XC_FREE_RTEXTENTS, count_fsb, + flags & XFS_ZR_RESERVED); + } if (error == -ENOSPC && (flags & XFS_ZR_GREEDY) && count_fsb > 1) error = xfs_zoned_reserve_extents_greedy(mp, &count_fsb, flags); if (error) From 8e5a2441e18640fb22a25fd097368957bf5cab91 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Aug 2025 07:06:45 +0200 Subject: [PATCH 0352/1292] xfs: reject swapon for inodes on a zoned file system earlier No point in going down into the iomap mapping loop when we know it will be rejected. Signed-off-by: Christoph Hellwig Reviewed-by: Damien Le Moal Reviewed-by: Hans Holmberg Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_aops.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 1ee4f835ac3c37..a26f798155331f 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -760,6 +760,9 @@ xfs_vm_swap_activate( { struct xfs_inode *ip = XFS_I(file_inode(swap_file)); + if (xfs_is_zoned_inode(ip)) + return -EINVAL; + /* * Swap file activation can race against concurrent shared extent * removal in files that have been cloned. If this happens, From 2eb03376151bb8585caa23ed2673583107bb5193 Mon Sep 17 00:00:00 2001 From: Weitao Wang Date: Tue, 19 Aug 2025 15:58:43 +0300 Subject: [PATCH 0353/1292] usb: xhci: Fix slot_id resource race conflict xHC controller may immediately reuse a slot_id after it's disabled, giving it to a new enumerating device before the xhci driver freed all resources related to the disabled device. In such a scenario, device-A with slot_id equal to 1 is disconnecting while device-B is enumerating, device-B will fail to enumerate in the follow sequence. 1.[device-A] send disable slot command 2.[device-B] send enable slot command 3.[device-A] disable slot command completed and wakeup waiting thread 4.[device-B] enable slot command completed with slot_id equal to 1 and wakeup waiting thread 5.[device-B] driver checks that slot_id is still in use (by device-A) in xhci_alloc_virt_device, and fail to enumerate due to this conflict 6.[device-A] xhci->devs[slot_id] set to NULL in xhci_free_virt_device To fix driver's slot_id resources conflict, clear xhci->devs[slot_id] and xhci->dcbba->dev_context_ptrs[slot_id] pointers in the interrupt context when disable slot command completes successfully. Simultaneously, adjust function xhci_free_virt_device to accurately handle device release. [minor smatch warning and commit message fix -Mathias] Cc: stable@vger.kernel.org Fixes: 7faac1953ed1 ("xhci: avoid race between disable slot command and host runtime suspend") Signed-off-by: Weitao Wang Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250819125844.2042452-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 3 +-- drivers/usb/host/xhci-mem.c | 22 +++++++++++----------- drivers/usb/host/xhci-ring.c | 9 +++++++-- drivers/usb/host/xhci.c | 21 ++++++++++++++------- drivers/usb/host/xhci.h | 3 ++- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 92bb84f8132a97..b3a59ce1b3f41f 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -704,8 +704,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci, if (!xhci->devs[i]) continue; - retval = xhci_disable_slot(xhci, i); - xhci_free_virt_device(xhci, i); + retval = xhci_disable_and_free_slot(xhci, i); if (retval) xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n", i, retval); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 07289333a1e8f1..81eaad87a3d9d0 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -865,21 +865,20 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci, * will be manipulated by the configure endpoint, allocate device, or update * hub functions while this function is removing the TT entries from the list. */ -void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) +void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, + int slot_id) { - struct xhci_virt_device *dev; int i; int old_active_eps = 0; /* Slot ID 0 is reserved */ - if (slot_id == 0 || !xhci->devs[slot_id]) + if (slot_id == 0 || !dev) return; - dev = xhci->devs[slot_id]; - - xhci->dcbaa->dev_context_ptrs[slot_id] = 0; - if (!dev) - return; + /* If device ctx array still points to _this_ device, clear it */ + if (dev->out_ctx && + xhci->dcbaa->dev_context_ptrs[slot_id] == cpu_to_le64(dev->out_ctx->dma)) + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; trace_xhci_free_virt_device(dev); @@ -920,8 +919,9 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) dev->udev->slot_id = 0; if (dev->rhub_port && dev->rhub_port->slot_id == slot_id) dev->rhub_port->slot_id = 0; - kfree(xhci->devs[slot_id]); - xhci->devs[slot_id] = NULL; + if (xhci->devs[slot_id] == dev) + xhci->devs[slot_id] = NULL; + kfree(dev); } /* @@ -962,7 +962,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i out: /* we are now at a leaf device */ xhci_debugfs_remove_slot(xhci, slot_id); - xhci_free_virt_device(xhci, slot_id); + xhci_free_virt_device(xhci, vdev, slot_id); } int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ecd757d482c582..4f8f5aab109d0c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1592,7 +1592,8 @@ static void xhci_handle_cmd_enable_slot(int slot_id, struct xhci_command *comman command->slot_id = 0; } -static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) +static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id, + u32 cmd_comp_code) { struct xhci_virt_device *virt_dev; struct xhci_slot_ctx *slot_ctx; @@ -1607,6 +1608,10 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) /* Delete default control endpoint resources */ xhci_free_device_endpoint_resources(xhci, virt_dev, true); + if (cmd_comp_code == COMP_SUCCESS) { + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; + xhci->devs[slot_id] = NULL; + } } static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id) @@ -1856,7 +1861,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, xhci_handle_cmd_enable_slot(slot_id, cmd, cmd_comp_code); break; case TRB_DISABLE_SLOT: - xhci_handle_cmd_disable_slot(xhci, slot_id); + xhci_handle_cmd_disable_slot(xhci, slot_id, cmd_comp_code); break; case TRB_CONFIG_EP: if (!cmd->completion) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 47151ca527bfaf..0e03691f03bfe5 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3932,8 +3932,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, * Obtaining a new device slot to inform the xHCI host that * the USB device has been reset. */ - ret = xhci_disable_slot(xhci, udev->slot_id); - xhci_free_virt_device(xhci, udev->slot_id); + ret = xhci_disable_and_free_slot(xhci, udev->slot_id); if (!ret) { ret = xhci_alloc_dev(hcd, udev); if (ret == 1) @@ -4090,7 +4089,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) xhci_disable_slot(xhci, udev->slot_id); spin_lock_irqsave(&xhci->lock, flags); - xhci_free_virt_device(xhci, udev->slot_id); + xhci_free_virt_device(xhci, virt_dev, udev->slot_id); spin_unlock_irqrestore(&xhci->lock, flags); } @@ -4139,6 +4138,16 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) return 0; } +int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id) +{ + struct xhci_virt_device *vdev = xhci->devs[slot_id]; + int ret; + + ret = xhci_disable_slot(xhci, slot_id); + xhci_free_virt_device(xhci, vdev, slot_id); + return ret; +} + /* * Checks if we have enough host controller resources for the default control * endpoint. @@ -4245,8 +4254,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) return 1; disable_slot: - xhci_disable_slot(xhci, udev->slot_id); - xhci_free_virt_device(xhci, udev->slot_id); + xhci_disable_and_free_slot(xhci, udev->slot_id); return 0; } @@ -4382,8 +4390,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, dev_warn(&udev->dev, "Device not responding to setup %s.\n", act); mutex_unlock(&xhci->mutex); - ret = xhci_disable_slot(xhci, udev->slot_id); - xhci_free_virt_device(xhci, udev->slot_id); + ret = xhci_disable_and_free_slot(xhci, udev->slot_id); if (!ret) { if (xhci_alloc_dev(hcd, udev) == 1) xhci_setup_addressable_virt_dev(xhci, udev); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a20f4e7cd43a80..85d5b964bf1e9b 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1791,7 +1791,7 @@ void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *), /* xHCI memory management */ void xhci_mem_cleanup(struct xhci_hcd *xhci); int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); -void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); +void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, int slot_id); int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, @@ -1888,6 +1888,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); +int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id); int xhci_ext_cap_init(struct xhci_hcd *xhci); int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup); From ff9a09b3e09c7b794b56f2f5858f5ce42ba46cb3 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Tue, 19 Aug 2025 15:58:44 +0300 Subject: [PATCH 0354/1292] usb: xhci: fix host not responding after suspend and resume Partially revert commit e1db856bd288 ("usb: xhci: remove '0' write to write-1-to-clear register") because the patch cleared the Interrupt Pending bit during interrupt enabling and disabling. The Interrupt Pending bit should only be cleared when the driver has handled the interrupt. Ideally, all interrupts should be handled before disabling the interrupt; consequently, no interrupt should be pending when enabling the interrupt. For this reason, keep the debug message informing if an interrupt is still pending when an interrupt is disabled. Because the Interrupt Pending bit is write-1-to-clear, writing '0' to it ensures that the state does not change. Link: https://lore.kernel.org/linux-usb/20250818231103.672ec7ed@foxbook Fixes: e1db856bd288 ("usb: xhci: remove '0' write to write-1-to-clear register") Closes: https://bbs.archlinux.org/viewtopic.php?id=307641 cc: stable@vger.kernel.org # 6.16+ Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250819125844.2042452-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 0e03691f03bfe5..742c23826e173a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -309,6 +309,7 @@ int xhci_enable_interrupter(struct xhci_interrupter *ir) return -EINVAL; iman = readl(&ir->ir_set->iman); + iman &= ~IMAN_IP; iman |= IMAN_IE; writel(iman, &ir->ir_set->iman); @@ -325,6 +326,7 @@ int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) return -EINVAL; iman = readl(&ir->ir_set->iman); + iman &= ~IMAN_IP; iman &= ~IMAN_IE; writel(iman, &ir->ir_set->iman); From 658a1c8e0a66d0777e0e37a11ba19f27a81e77f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C3=B3rkowski?= Date: Mon, 11 Aug 2025 12:43:57 +0200 Subject: [PATCH 0355/1292] drm/xe: Assign ioctl xe file handler to vm in xe_vm_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In several code paths, such as xe_pt_create(), the vm->xef field is used to determine whether a VM originates from userspace or the kernel. Previously, this handler was only assigned in xe_vm_create_ioctl(), after the VM was created by xe_vm_create(). However, xe_vm_create() triggers page table creation, and that function assumes vm->xef should be already set. This could lead to incorrect origin detection. To fix this problem and ensure consistency in the initialization of the VM object, let's move the assignment of this handler to xe_vm_create. v2: - take reference to the xe file object only when xef is not NULL - release the reference to the xe file object on the error path (Matthew) Fixes: 7f387e6012b6 ("drm/xe: add XE_BO_FLAG_PINNED_LATE_RESTORE") Signed-off-by: Piotr Piórkowski Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://lore.kernel.org/r/20250811104358.2064150-2-piotr.piorkowski@intel.com Signed-off-by: Michał Winiarski (cherry picked from commit 9337166fa1d80f7bb7c7d3a8f901f21c348c0f2a) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_migrate.c | 2 +- drivers/gpu/drm/xe/xe_pxp_submit.c | 2 +- drivers/gpu/drm/xe/xe_vm.c | 11 ++++++----- drivers/gpu/drm/xe/xe_vm.h | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index 7d20ac4bb63336..84f412fd3c5d2a 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -408,7 +408,7 @@ struct xe_migrate *xe_migrate_init(struct xe_tile *tile) /* Special layout, prepared below.. */ vm = xe_vm_create(xe, XE_VM_FLAG_MIGRATION | - XE_VM_FLAG_SET_TILE_ID(tile)); + XE_VM_FLAG_SET_TILE_ID(tile), NULL); if (IS_ERR(vm)) return ERR_CAST(vm); diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.c b/drivers/gpu/drm/xe/xe_pxp_submit.c index d92ec0f515b034..ca95f2a4d4ef5d 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.c +++ b/drivers/gpu/drm/xe/xe_pxp_submit.c @@ -101,7 +101,7 @@ static int allocate_gsc_client_resources(struct xe_gt *gt, xe_assert(xe, hwe); /* PXP instructions must be issued from PPGTT */ - vm = xe_vm_create(xe, XE_VM_FLAG_GSC); + vm = xe_vm_create(xe, XE_VM_FLAG_GSC, NULL); if (IS_ERR(vm)) return PTR_ERR(vm); diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 2035604121e626..5bff317e335a03 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1640,7 +1640,7 @@ static void xe_vm_free_scratch(struct xe_vm *vm) } } -struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) +struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef) { struct drm_gem_object *vm_resv_obj; struct xe_vm *vm; @@ -1661,9 +1661,10 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) vm->xe = xe; vm->size = 1ull << xe->info.va_bits; - vm->flags = flags; + if (xef) + vm->xef = xe_file_get(xef); /** * GSC VMs are kernel-owned, only used for PXP ops and can sometimes be * manipulated under the PXP mutex. However, the PXP mutex can be taken @@ -1814,6 +1815,8 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) for_each_tile(tile, xe, id) xe_range_fence_tree_fini(&vm->rftree[id]); ttm_lru_bulk_move_fini(&xe->ttm, &vm->lru_bulk_move); + if (vm->xef) + xe_file_put(vm->xef); kfree(vm); if (flags & XE_VM_FLAG_LR_MODE) xe_pm_runtime_put(xe); @@ -2097,7 +2100,7 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, if (args->flags & DRM_XE_VM_CREATE_FLAG_FAULT_MODE) flags |= XE_VM_FLAG_FAULT_MODE; - vm = xe_vm_create(xe, flags); + vm = xe_vm_create(xe, flags, xef); if (IS_ERR(vm)) return PTR_ERR(vm); @@ -2113,8 +2116,6 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, vm->usm.asid = asid; } - vm->xef = xe_file_get(xef); - /* Record BO memory for VM pagetable created against client */ for_each_tile(tile, xe, id) if (vm->pt_root[id]) diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h index 3475a118f66654..2f213737c7e518 100644 --- a/drivers/gpu/drm/xe/xe_vm.h +++ b/drivers/gpu/drm/xe/xe_vm.h @@ -26,7 +26,7 @@ struct xe_sync_entry; struct xe_svm_range; struct drm_exec; -struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags); +struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef); struct xe_vm *xe_vm_lookup(struct xe_file *xef, u32 id); int xe_vma_cmp_vma_cb(const void *key, const struct rb_node *node); From 11cd7a5c21db020b8001aedcae27bd3fa9e1e901 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Aug 2025 12:40:41 +0300 Subject: [PATCH 0356/1292] regulator: tps65219: regulator: tps65219: Fix error codes in probe() There is a copy and paste error and we accidentally use "PTR_ERR(rdev)" instead of "error". The "rdev" pointer is valid at this point. Also there is no need to print the error code in the error message because dev_err_probe() already prints that. So clean up the error message a bit. Fixes: 38c9f98db20a ("regulator: tps65219: Add support for TPS65215 Regulator IRQs") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aKRGmVdbvT1HBvm8@stanley.mountain Signed-off-by: Mark Brown --- drivers/regulator/tps65219-regulator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/tps65219-regulator.c b/drivers/regulator/tps65219-regulator.c index 5e67fdc88f49e6..d77ca486879fd6 100644 --- a/drivers/regulator/tps65219-regulator.c +++ b/drivers/regulator/tps65219-regulator.c @@ -454,9 +454,9 @@ static int tps65219_regulator_probe(struct platform_device *pdev) irq_type->irq_name, irq_data); if (error) - return dev_err_probe(tps->dev, PTR_ERR(rdev), - "Failed to request %s IRQ %d: %d\n", - irq_type->irq_name, irq, error); + return dev_err_probe(tps->dev, error, + "Failed to request %s IRQ %d\n", + irq_type->irq_name, irq); } for (i = 0; i < pmic->dev_irq_size; ++i) { @@ -477,9 +477,9 @@ static int tps65219_regulator_probe(struct platform_device *pdev) irq_type->irq_name, irq_data); if (error) - return dev_err_probe(tps->dev, PTR_ERR(rdev), - "Failed to request %s IRQ %d: %d\n", - irq_type->irq_name, irq, error); + return dev_err_probe(tps->dev, error, + "Failed to request %s IRQ %d\n", + irq_type->irq_name, irq); } return 0; From 0ddfb62f5d018edcb571a3d8ea30ad5332cf2a69 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 15 Aug 2025 15:38:14 -0400 Subject: [PATCH 0357/1292] fix the softlockups in attach_recursive_mnt() In case when we mounting something on top of a large stack of overmounts, all of them being peers of each other, we get quadratic time by the depth of overmount stack. Easily fixed by doing commit_tree() before reparenting the overmount; simplifies commit_tree() as well - it doesn't need to skip the already mounted stuff that had been reparented on top of the new mounts. Since we are holding mount_lock through both reparenting and call of commit_tree(), the order does not matter from the mount hash point of view. Reported-by: "Lai, Yi" Tested-by: "Lai, Yi" Reviewed-by: Christian Brauner Fixes: 663206854f02 "copy_tree(): don't link the mounts via mnt_list" Signed-off-by: Al Viro --- fs/namespace.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index ddfd4457d33837..1c97f93d18655e 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1197,10 +1197,7 @@ static void commit_tree(struct mount *mnt) if (!mnt_ns_attached(mnt)) { for (struct mount *m = mnt; m; m = next_mnt(m, mnt)) - if (unlikely(mnt_ns_attached(m))) - m = skip_mnt_tree(m); - else - mnt_add_to_ns(n, m); + mnt_add_to_ns(n, m); n->nr_mounts += n->pending_mounts; n->pending_mounts = 0; } @@ -2704,6 +2701,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, lock_mnt_tree(child); q = __lookup_mnt(&child->mnt_parent->mnt, child->mnt_mountpoint); + commit_tree(child); if (q) { struct mountpoint *mp = root.mp; struct mount *r = child; @@ -2713,7 +2711,6 @@ static int attach_recursive_mnt(struct mount *source_mnt, mp = shorter; mnt_change_mountpoint(r, mp, q); } - commit_tree(child); } unpin_mountpoint(&root); unlock_mount_hash(); From da025cdb97a23c1916d8491925b878f3e1de0bca Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 14 Aug 2025 23:32:26 -0400 Subject: [PATCH 0358/1292] propagate_umount(): only surviving overmounts should be reparented ... as the comments in reparent() clearly say. As it is, we reparent *all* overmounts of the mounts being taken out, including those that are taken out themselves. It's not only a potentially massive slowdown (on a pathological setup we might end up with O(N^2) time for N mounts being kicked out), it can end up with incorrect ->overmount in the surviving mounts. Fixes: f0d0ba19985d "Rewrite of propagate_umount()" Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/pnode.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/pnode.c b/fs/pnode.c index 81f7599bdac4fc..1c789f88b3d26c 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -637,10 +637,11 @@ void propagate_umount(struct list_head *set) } // now to_umount consists of all acceptable candidates - // deal with reparenting of remaining overmounts on those + // deal with reparenting of surviving overmounts on those list_for_each_entry(m, &to_umount, mnt_list) { - if (m->overmount) - reparent(m->overmount); + struct mount *over = m->overmount; + if (over && !will_be_unmounted(over)) + reparent(over); } // and fold them into the set From cffd0441872e7f6b1fce5e78fb1c99187a291330 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 14 Aug 2025 01:44:31 -0400 Subject: [PATCH 0359/1292] use uniform permission checks for all mount propagation changes do_change_type() and do_set_group() are operating on different aspects of the same thing - propagation graph. The latter asks for mounts involved to be mounted in namespace(s) the caller has CAP_SYS_ADMIN for. The former is a mess - originally it didn't even check that mount *is* mounted. That got fixed, but the resulting check turns out to be too strict for userland - in effect, we check that mount is in our namespace, having already checked that we have CAP_SYS_ADMIN there. What we really need (in both cases) is * only touch mounts that are mounted. That's a must-have constraint - data corruption happens if it get violated. * don't allow to mess with a namespace unless you already have enough permissions to do so (i.e. CAP_SYS_ADMIN in its userns). That's an equivalent of what do_set_group() does; let's extract that into a helper (may_change_propagation()) and use it in both do_set_group() and do_change_type(). Fixes: 12f147ddd6de "do_change_type(): refuse to operate on unmounted/not ours mounts" Acked-by: Andrei Vagin Reviewed-by: Pavel Tikhomirov Tested-by: Pavel Tikhomirov Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/namespace.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 1c97f93d18655e..88db5806191998 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2859,6 +2859,19 @@ static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp) return attach_recursive_mnt(mnt, p, mp); } +static int may_change_propagation(const struct mount *m) +{ + struct mnt_namespace *ns = m->mnt_ns; + + // it must be mounted in some namespace + if (IS_ERR_OR_NULL(ns)) // is_mounted() + return -EINVAL; + // and the caller must be admin in userns of that namespace + if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + /* * Sanity check the flags to change_mnt_propagation. */ @@ -2895,10 +2908,10 @@ static int do_change_type(struct path *path, int ms_flags) return -EINVAL; namespace_lock(); - if (!check_mnt(mnt)) { - err = -EINVAL; + err = may_change_propagation(mnt); + if (err) goto out_unlock; - } + if (type == MS_SHARED) { err = invent_group_ids(mnt, recurse); if (err) @@ -3344,18 +3357,11 @@ static int do_set_group(struct path *from_path, struct path *to_path) namespace_lock(); - err = -EINVAL; - /* To and From must be mounted */ - if (!is_mounted(&from->mnt)) - goto out; - if (!is_mounted(&to->mnt)) - goto out; - - err = -EPERM; - /* We should be allowed to modify mount namespaces of both mounts */ - if (!ns_capable(from->mnt_ns->user_ns, CAP_SYS_ADMIN)) + err = may_change_propagation(from); + if (err) goto out; - if (!ns_capable(to->mnt_ns->user_ns, CAP_SYS_ADMIN)) + err = may_change_propagation(to); + if (err) goto out; err = -EINVAL; From fb924b7b8669503582e003dd7b7340ee49029801 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 15 Aug 2025 15:23:08 -0400 Subject: [PATCH 0360/1292] change_mnt_propagation(): calculate propagation source only if we'll need it We only need it when mount in question was sending events downstream (then recepients need to switch to new master) or the mount is being turned into slave (then we need a new master for it). That wouldn't be a big deal, except that it causes quite a bit of work when umount_tree() is taking a large peer group out. Adding a trivial "don't bother calling propagation_source() unless we are going to use its results" logics improves the things quite a bit. We are still doing unnecessary work on bulk removals from propagation graph, but the full solution for that will have to wait for the next merge window. Fixes: 955336e204ab "do_make_slave(): choose new master sanely" Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/pnode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/pnode.c b/fs/pnode.c index 1c789f88b3d26c..6f7d02f3fa985f 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -111,7 +111,8 @@ void change_mnt_propagation(struct mount *mnt, int type) return; } if (IS_MNT_SHARED(mnt)) { - m = propagation_source(mnt); + if (type == MS_SLAVE || !hlist_empty(&mnt->mnt_slave_list)) + m = propagation_source(mnt); if (list_empty(&mnt->mnt_share)) { mnt_release_group_id(mnt); } else { From 453a6d2a68e54a483d67233c6e1e24c4095ee4be Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 19 Aug 2025 16:27:36 +0100 Subject: [PATCH 0361/1292] cifs: Fix oops due to uninitialised variable Fix smb3_init_transform_rq() to initialise buffer to NULL before calling netfs_alloc_folioq_buffer() as netfs assumes it can append to the buffer it is given. Setting it to NULL means it should start a fresh buffer, but the value is currently undefined. Fixes: a2906d3316fc ("cifs: Switch crypto buffer to use a folio_queue rather than an xarray") Signed-off-by: David Howells cc: Steve French cc: Paulo Alcantara cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org Signed-off-by: Steve French --- fs/smb/client/smb2ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 3b251de874ec2b..94b1d7a395d50a 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4496,7 +4496,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, for (int i = 1; i < num_rqst; i++) { struct smb_rqst *old = &old_rq[i - 1]; struct smb_rqst *new = &new_rq[i]; - struct folio_queue *buffer; + struct folio_queue *buffer = NULL; size_t size = iov_iter_count(&old->rq_iter); orig_len += smb_rqst_len(server, old); From 76d2e3890fb169168c73f2e4f8375c7cc24a765e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 16 Aug 2025 07:25:20 -0700 Subject: [PATCH 0362/1292] NFS: Fix a race when updating an existing write After nfs_lock_and_join_requests() tests for whether the request is still attached to the mapping, nothing prevents a call to nfs_inode_remove_request() from succeeding until we actually lock the page group. The reason is that whoever called nfs_inode_remove_request() doesn't necessarily have a lock on the page group head. So in order to avoid races, let's take the page group lock earlier in nfs_lock_and_join_requests(), and hold it across the removal of the request in nfs_inode_remove_request(). Reported-by: Jeff Layton Tested-by: Joe Quanaim Tested-by: Andrew Steffen Reviewed-by: Jeff Layton Fixes: bd37d6fce184 ("NFSv4: Convert nfs_lock_and_join_requests() to use nfs_page_find_head_request()") Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 9 +++++---- fs/nfs/write.c | 29 ++++++++++------------------- include/linux/nfs_page.h | 1 + 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 11968dcb724317..6e69ce43a13ff7 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -253,13 +253,14 @@ nfs_page_group_unlock(struct nfs_page *req) nfs_page_clear_headlock(req); } -/* - * nfs_page_group_sync_on_bit_locked +/** + * nfs_page_group_sync_on_bit_locked - Test if all requests have @bit set + * @req: request in page group + * @bit: PG_* bit that is used to sync page group * * must be called with page group lock held */ -static bool -nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit) +bool nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit) { struct nfs_page *head = req->wb_head; struct nfs_page *tmp; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index fa5c41d0989ad1..8b7c0473796755 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -153,20 +153,10 @@ nfs_page_set_inode_ref(struct nfs_page *req, struct inode *inode) } } -static int -nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode) +static void nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode) { - int ret; - - if (!test_bit(PG_REMOVE, &req->wb_flags)) - return 0; - ret = nfs_page_group_lock(req); - if (ret) - return ret; if (test_and_clear_bit(PG_REMOVE, &req->wb_flags)) nfs_page_set_inode_ref(req, inode); - nfs_page_group_unlock(req); - return 0; } /** @@ -585,19 +575,18 @@ static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio) } } + ret = nfs_page_group_lock(head); + if (ret < 0) + goto out_unlock; + /* Ensure that nobody removed the request before we locked it */ if (head != folio->private) { + nfs_page_group_unlock(head); nfs_unlock_and_release_request(head); goto retry; } - ret = nfs_cancel_remove_inode(head, inode); - if (ret < 0) - goto out_unlock; - - ret = nfs_page_group_lock(head); - if (ret < 0) - goto out_unlock; + nfs_cancel_remove_inode(head, inode); /* lock each request in the page group */ for (subreq = head->wb_this_page; @@ -786,7 +775,8 @@ static void nfs_inode_remove_request(struct nfs_page *req) { struct nfs_inode *nfsi = NFS_I(nfs_page_to_inode(req)); - if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) { + nfs_page_group_lock(req); + if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) { struct folio *folio = nfs_page_to_folio(req->wb_head); struct address_space *mapping = folio->mapping; @@ -798,6 +788,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) } spin_unlock(&mapping->i_private_lock); } + nfs_page_group_unlock(req); if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) { atomic_long_dec(&nfsi->nrequests); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 169b4ae30ff479..9aed39abc94bc3 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -160,6 +160,7 @@ extern void nfs_join_page_group(struct nfs_page *head, extern int nfs_page_group_lock(struct nfs_page *); extern void nfs_page_group_unlock(struct nfs_page *); extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); +extern bool nfs_page_group_sync_on_bit_locked(struct nfs_page *, unsigned int); extern int nfs_page_set_headlock(struct nfs_page *req); extern void nfs_page_clear_headlock(struct nfs_page *req); extern bool nfs_async_iocounter_wait(struct rpc_task *, struct nfs_lock_context *); From d41e327582e172f30e4e15f9124796a10fd1b0f9 Mon Sep 17 00:00:00 2001 From: Devyn Liu Date: Tue, 19 Aug 2025 10:03:49 +0800 Subject: [PATCH 0363/1292] MAINTAINERS: i2c: Update i2c_hisi entry Because Yicong Yang will no longer work on i2c_hisi driver, update the maintainer information for i2c_hisi. Signed-off-by: Devyn Liu Acked-by: Yicong Yang Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250819020349.4027842-1-liudingyuan@h-partners.com --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index daf520a13bdf6a..9d1270ddcbff73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11013,7 +11013,7 @@ F: Documentation/admin-guide/perf/hns3-pmu.rst F: drivers/perf/hisilicon/hns3_pmu.c HISILICON I2C CONTROLLER DRIVER -M: Yicong Yang +M: Devyn Liu L: linux-i2c@vger.kernel.org S: Maintained W: https://www.hisilicon.com From 57f312b955938fc4663f430cb57a71f2414f601b Mon Sep 17 00:00:00 2001 From: Alex Guo Date: Sun, 10 Aug 2025 20:05:13 +0200 Subject: [PATCH 0364/1292] i2c: rtl9300: Fix out-of-bounds bug in rtl9300_i2c_smbus_xfer The data->block[0] variable comes from user. Without proper check, the variable may be very large to cause an out-of-bounds bug. Fix this bug by checking the value of data->block[0] first. 1. commit 39244cc75482 ("i2c: ismt: Fix an out-of-bounds bug in ismt_access()") 2. commit 92fbb6d1296f ("i2c: xgene-slimpro: Fix out-of-bounds bug in xgene_slimpro_i2c_xfer()") Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") Signed-off-by: Alex Guo Cc: # v6.13+ Reviewed-by: Chris Packham Tested-by: Chris Packham Reviewed-by: Wolfram Sang Signed-off-by: Sven Eckelmann Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-1-cd9dca0db722@narfation.org --- drivers/i2c/busses/i2c-rtl9300.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index e064e8a4a1f082..568495720810b3 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -281,6 +281,10 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); if (ret) goto out_unlock; + if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) { + ret = -EINVAL; + goto out_unlock; + } ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); if (ret) goto out_unlock; From d67b740b9edfa46310355e2b68050f79ebf05a4c Mon Sep 17 00:00:00 2001 From: Harshal Gohel Date: Sun, 10 Aug 2025 20:05:14 +0200 Subject: [PATCH 0365/1292] i2c: rtl9300: Fix multi-byte I2C write The RTL93xx I2C controller has 4 32 bit registers to store the bytes for the upcoming I2C transmission. The first byte is stored in the least-significant byte of the first register. And the last byte in the most significant byte of the last register. A map of the transferred bytes to their order in the registers is: reg 0: 0x04_03_02_01 reg 1: 0x08_07_06_05 reg 2: 0x0c_0b_0a_09 reg 3: 0x10_0f_0e_0d The i2c_read() function basically demonstrates how the hardware would pick up bytes from this register set. But the i2c_write() function was just pushing bytes one after another to the least significant byte of a register AFTER shifting the last one to the next more significant byte position. If you would then have tried to send a buffer with numbers 1-11 using i2c_write(), you would have ended up with following register content: reg 0: 0x01_02_03_04 reg 1: 0x05_06_07_08 reg 2: 0x00_09_0a_0b reg 3: 0x00_00_00_00 On the wire, you would then have seen: Sr Addr Wr [A] 04 A 03 A 02 A 01 A 08 A 07 A 06 A 05 A 0b A 0a A 09 A P But the correct data transmission was expected to be Sr Addr Wr [A] 01 A 02 A 03 A 04 A 05 A 06 A 07 A 08 A 09 A 0a A 0b A P Because of this multi-byte ordering problem, only single byte i2c_write() operations were executed correctly (on the wire). By shifting the byte directly to the correct end position in the register, it is possible to avoid this incorrect byte ordering and fix multi-byte transmissions. The second initialization (to 0) of vals was also be dropped because this array is initialized to 0 on the stack by using `= {};`. This makes the fix a lot more readable. Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") Signed-off-by: Harshal Gohel Cc: # v6.13+ Co-developed-by: Sven Eckelmann Signed-off-by: Sven Eckelmann Reviewed-by: Chris Packham Tested-by: Chris Packham Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-2-cd9dca0db722@narfation.org --- drivers/i2c/busses/i2c-rtl9300.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index 568495720810b3..4a538b2660802c 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -143,10 +143,10 @@ static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len) return -EIO; for (i = 0; i < len; i++) { - if (i % 4 == 0) - vals[i/4] = 0; - vals[i/4] <<= 8; - vals[i/4] |= buf[i]; + unsigned int shift = (i % 4) * 8; + unsigned int reg = i / 4; + + vals[reg] |= buf[i] << shift; } return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, From ceee7776c010c5f09d30985c9e5223b363a6172a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 10 Aug 2025 20:05:15 +0200 Subject: [PATCH 0366/1292] i2c: rtl9300: Increase timeout for transfer polling The timeout for transfers was only set to 2ms. Because of this relatively low limit, 12-byte read operations to the frontend MCU of a RTL8239 POE PSE chip cluster was consistently resulting in a timeout. The original OpenWrt downstream driver [1] was not using any timeout limit at all. This is also possible by setting the timeout_us parameter of regmap_read_poll_timeout() to 0. But since the driver currently implements the ETIMEDOUT error, it is more sensible to increase the timeout in such a way that communication with the (quite common) Realtek I2C-connected POE management solution is possible. [1] https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob;f=target/linux/realtek/files-6.12/drivers/i2c/busses/i2c-rtl9300.c;h=c4d973195ef39dc56d6207e665d279745525fcac#l202 Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") Signed-off-by: Sven Eckelmann Cc: # v6.13+ Reviewed-by: Chris Packham Tested-by: Chris Packham Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-3-cd9dca0db722@narfation.org --- drivers/i2c/busses/i2c-rtl9300.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index 4a538b2660802c..4a282d57e2c1a7 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -175,7 +175,7 @@ static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write, return ret; ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, - val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 2000); + val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 100000); if (ret) return ret; From 82b350dd8185ce790e61555c436f90b6501af23c Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 10 Aug 2025 20:05:16 +0200 Subject: [PATCH 0367/1292] i2c: rtl9300: Add missing count byte for SMBus Block Ops The expected on-wire format of an SMBus Block Write is S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P Everything starting from the Count byte is provided by the I2C subsystem in the array data->block. But the driver was skipping the Count byte (data->block[0]) when sending it to the RTL93xx I2C controller. Only the actual data could be seen on the wire: S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P This wire format is not SMBus Block Write compatible but matches the format of an I2C Block Write. Simply adding the count byte to the buffer for the I2C controller is enough to fix the transmission. This also affects read because the I2C controller must receive the count byte + $count * data bytes. Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") Signed-off-by: Sven Eckelmann Cc: # v6.13+ Reviewed-by: Chris Packham Tested-by: Chris Packham Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-4-cd9dca0db722@narfation.org --- drivers/i2c/busses/i2c-rtl9300.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index 4a282d57e2c1a7..cfafe089102aa2 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -285,15 +285,15 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s ret = -EINVAL; goto out_unlock; } - ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0] + 1); if (ret) goto out_unlock; if (read_write == I2C_SMBUS_WRITE) { - ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]); + ret = rtl9300_i2c_write(i2c, &data->block[0], data->block[0] + 1); if (ret) goto out_unlock; } - len = data->block[0]; + len = data->block[0] + 1; break; default: From 63b17b653df30e90f95338083cb44c35d64bcae4 Mon Sep 17 00:00:00 2001 From: Pasha Tatashin Date: Fri, 8 Aug 2025 20:18:02 +0000 Subject: [PATCH 0368/1292] kho: init new_physxa->phys_bits to fix lockdep Patch series "Several KHO Hotfixes". Three unrelated fixes for Kexec Handover. This patch (of 3): Lockdep shows the following warning: INFO: trying to register non-static key. The code is fine but needs lockdep annotation, or maybe you didn't initialize this object before use? turning off the locking correctness validator. [] dump_stack_lvl+0x66/0xa0 [] assign_lock_key+0x10c/0x120 [] register_lock_class+0xf4/0x2f0 [] __lock_acquire+0x7f/0x2c40 [] ? __pfx_hlock_conflict+0x10/0x10 [] ? native_flush_tlb_global+0x8e/0xa0 [] ? __flush_tlb_all+0x4e/0xa0 [] ? __kernel_map_pages+0x112/0x140 [] ? xa_load_or_alloc+0x67/0xe0 [] lock_acquire+0xe6/0x280 [] ? xa_load_or_alloc+0x67/0xe0 [] _raw_spin_lock+0x30/0x40 [] ? xa_load_or_alloc+0x67/0xe0 [] xa_load_or_alloc+0x67/0xe0 [] kho_preserve_folio+0x90/0x100 [] __kho_finalize+0xcf/0x400 [] kho_finalize+0x34/0x70 This is becase xa has its own lock, that is not initialized in xa_load_or_alloc. Modifiy __kho_preserve_order(), to properly call xa_init(&new_physxa->phys_bits); Link: https://lkml.kernel.org/r/20250808201804.772010-2-pasha.tatashin@soleen.com Fixes: fc33e4b44b27 ("kexec: enable KHO support for memory preservation") Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) Cc: Alexander Graf Cc: Arnd Bergmann Cc: Baoquan He Cc: Changyuan Lyu Cc: Coiby Xu Cc: Dave Vasilevsky Cc: Eric Biggers Cc: Kees Cook Cc: Pratyush Yadav Cc: Signed-off-by: Andrew Morton --- kernel/kexec_handover.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c index e49743ae52c52f..65145972d6d6ad 100644 --- a/kernel/kexec_handover.c +++ b/kernel/kexec_handover.c @@ -144,14 +144,34 @@ static int __kho_preserve_order(struct kho_mem_track *track, unsigned long pfn, unsigned int order) { struct kho_mem_phys_bits *bits; - struct kho_mem_phys *physxa; + struct kho_mem_phys *physxa, *new_physxa; const unsigned long pfn_high = pfn >> order; might_sleep(); - physxa = xa_load_or_alloc(&track->orders, order, sizeof(*physxa)); - if (IS_ERR(physxa)) - return PTR_ERR(physxa); + physxa = xa_load(&track->orders, order); + if (!physxa) { + int err; + + new_physxa = kzalloc(sizeof(*physxa), GFP_KERNEL); + if (!new_physxa) + return -ENOMEM; + + xa_init(&new_physxa->phys_bits); + physxa = xa_cmpxchg(&track->orders, order, NULL, new_physxa, + GFP_KERNEL); + + err = xa_err(physxa); + if (err || physxa) { + xa_destroy(&new_physxa->phys_bits); + kfree(new_physxa); + + if (err) + return err; + } else { + physxa = new_physxa; + } + } bits = xa_load_or_alloc(&physxa->phys_bits, pfn_high / PRESERVE_BITS, sizeof(*bits)); From 8b66ed2c3f42cc462e05704af6b94e6a7bad2f5e Mon Sep 17 00:00:00 2001 From: Pasha Tatashin Date: Fri, 8 Aug 2025 20:18:03 +0000 Subject: [PATCH 0369/1292] kho: mm: don't allow deferred struct page with KHO KHO uses struct pages for the preserved memory early in boot, however, with deferred struct page initialization, only a small portion of memory has properly initialized struct pages. This problem was detected where vmemmap is poisoned, and illegal flag combinations are detected. Don't allow them to be enabled together, and later we will have to teach KHO to work properly with deferred struct page init kernel feature. Link: https://lkml.kernel.org/r/20250808201804.772010-3-pasha.tatashin@soleen.com Fixes: 4e1d010e3bda ("kexec: add config option for KHO") Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) Acked-by: Pratyush Yadav Cc: Alexander Graf Cc: Arnd Bergmann Cc: Baoquan He Cc: Changyuan Lyu Cc: Coiby Xu Cc: Dave Vasilevsky Cc: Eric Biggers Cc: Kees Cook Cc: Signed-off-by: Andrew Morton --- kernel/Kconfig.kexec | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec index 2ee603a98813e2..1224dd937df0c4 100644 --- a/kernel/Kconfig.kexec +++ b/kernel/Kconfig.kexec @@ -97,6 +97,7 @@ config KEXEC_JUMP config KEXEC_HANDOVER bool "kexec handover" depends on ARCH_SUPPORTS_KEXEC_HANDOVER && ARCH_SUPPORTS_KEXEC_FILE + depends on !DEFERRED_STRUCT_PAGE_INIT select MEMBLOCK_KHO_SCRATCH select KEXEC_FILE select DEBUG_FS From 44958f2025ed3f29fc3e93bb1f6c16121d7847ad Mon Sep 17 00:00:00 2001 From: Pasha Tatashin Date: Fri, 8 Aug 2025 20:18:04 +0000 Subject: [PATCH 0370/1292] kho: warn if KHO is disabled due to an error During boot scratch area is allocated based on command line parameters or auto calculated. However, scratch area may fail to allocate, and in that case KHO is disabled. Currently, no warning is printed that KHO is disabled, which makes it confusing for the end user to figure out why KHO is not available. Add the missing warning message. Link: https://lkml.kernel.org/r/20250808201804.772010-4-pasha.tatashin@soleen.com Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) Acked-by: Pratyush Yadav Cc: Alexander Graf Cc: Arnd Bergmann Cc: Baoquan He Cc: Changyuan Lyu Cc: Coiby Xu Cc: Dave Vasilevsky Cc: Eric Biggers Cc: Kees Cook Cc: Signed-off-by: Andrew Morton --- kernel/kexec_handover.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c index 65145972d6d6ad..ecd1ac210dbd74 100644 --- a/kernel/kexec_handover.c +++ b/kernel/kexec_handover.c @@ -564,6 +564,7 @@ static void __init kho_reserve_scratch(void) err_free_scratch_desc: memblock_free(kho_scratch, kho_scratch_cnt * sizeof(*kho_scratch)); err_disable_kho: + pr_warn("Failed to reserve scratch area, disabling kexec handover\n"); kho_enable = false; } From b64700d41bdc4e9f82f1346c15a3678ebb91a89c Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Mon, 11 Aug 2025 23:37:40 +0100 Subject: [PATCH 0371/1292] squashfs: fix memory leak in squashfs_fill_super If sb_min_blocksize returns 0, squashfs_fill_super exits without freeing allocated memory (sb->s_fs_info). Fix this by moving the call to sb_min_blocksize to before memory is allocated. Link: https://lkml.kernel.org/r/20250811223740.110392-1-phillip@squashfs.org.uk Fixes: 734aa85390ea ("Squashfs: check return result of sb_min_blocksize") Signed-off-by: Phillip Lougher Reported-by: Scott GUO Closes: https://lore.kernel.org/all/20250811061921.3807353-1-scott_gzh@163.com Cc: Signed-off-by: Andrew Morton --- fs/squashfs/super.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 992ea0e372572f..4465cf05603a8f 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -187,10 +187,15 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc) unsigned short flags; unsigned int fragments; u64 lookup_table_start, xattr_id_table_start, next_table; - int err; + int err, devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE); TRACE("Entered squashfs_fill_superblock\n"); + if (!devblksize) { + errorf(fc, "squashfs: unable to set blocksize\n"); + return -EINVAL; + } + sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL); if (sb->s_fs_info == NULL) { ERROR("Failed to allocate squashfs_sb_info\n"); @@ -201,12 +206,7 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc) msblk->panic_on_errors = (opts->errors == Opt_errors_panic); - msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE); - if (!msblk->devblksize) { - errorf(fc, "squashfs: unable to set blocksize\n"); - return -EINVAL; - } - + msblk->devblksize = devblksize; msblk->devblksize_log2 = ffz(~msblk->devblksize); mutex_init(&msblk->meta_index_mutex); From dde30854bddfb5d69f30022b53c5955a41088b33 Mon Sep 17 00:00:00 2001 From: "Herton R. Krzesinski" Date: Thu, 31 Jul 2025 18:40:51 -0300 Subject: [PATCH 0372/1292] mm/debug_vm_pgtable: clear page table entries at destroy_args() The mm/debug_vm_pagetable test allocates manually page table entries for the tests it runs, using also its manually allocated mm_struct. That in itself is ok, but when it exits, at destroy_args() it fails to clear those entries with the *_clear functions. The problem is that leaves stale entries. If another process allocates an mm_struct with a pgd at the same address, it may end up running into the stale entry. This is happening in practice on a debug kernel with CONFIG_DEBUG_VM_PGTABLE=y, for example this is the output with some extra debugging I added (it prints a warning trace if pgtables_bytes goes negative, in addition to the warning at check_mm() function): [ 2.539353] debug_vm_pgtable: [get_random_vaddr ]: random_vaddr is 0x7ea247140000 [ 2.539366] kmem_cache info [ 2.539374] kmem_cachep 0x000000002ce82385 - freelist 0x0000000000000000 - offset 0x508 [ 2.539447] debug_vm_pgtable: [init_args ]: args->mm is 0x000000002267cc9e (...) [ 2.552800] WARNING: CPU: 5 PID: 116 at include/linux/mm.h:2841 free_pud_range+0x8bc/0x8d0 [ 2.552816] Modules linked in: [ 2.552843] CPU: 5 UID: 0 PID: 116 Comm: modprobe Not tainted 6.12.0-105.debug_vm2.el10.ppc64le+debug #1 VOLUNTARY [ 2.552859] Hardware name: IBM,9009-41A POWER9 (architected) 0x4e0202 0xf000005 of:IBM,FW910.00 (VL910_062) hv:phyp pSeries [ 2.552872] NIP: c0000000007eef3c LR: c0000000007eef30 CTR: c0000000003d8c90 [ 2.552885] REGS: c0000000622e73b0 TRAP: 0700 Not tainted (6.12.0-105.debug_vm2.el10.ppc64le+debug) [ 2.552899] MSR: 800000000282b033 CR: 24002822 XER: 0000000a [ 2.552954] CFAR: c0000000008f03f0 IRQMASK: 0 [ 2.552954] GPR00: c0000000007eef30 c0000000622e7650 c000000002b1ac00 0000000000000001 [ 2.552954] GPR04: 0000000000000008 0000000000000000 c0000000007eef30 ffffffffffffffff [ 2.552954] GPR08: 00000000ffff00f5 0000000000000001 0000000000000048 0000000000004000 [ 2.552954] GPR12: 00000003fa440000 c000000017ffa300 c0000000051d9f80 ffffffffffffffdb [ 2.552954] GPR16: 0000000000000000 0000000000000008 000000000000000a 60000000000000e0 [ 2.552954] GPR20: 4080000000000000 c0000000113af038 00007fffcf130000 0000700000000000 [ 2.552954] GPR24: c000000062a6a000 0000000000000001 8000000062a68000 0000000000000001 [ 2.552954] GPR28: 000000000000000a c000000062ebc600 0000000000002000 c000000062ebc760 [ 2.553170] NIP [c0000000007eef3c] free_pud_range+0x8bc/0x8d0 [ 2.553185] LR [c0000000007eef30] free_pud_range+0x8b0/0x8d0 [ 2.553199] Call Trace: [ 2.553207] [c0000000622e7650] [c0000000007eef30] free_pud_range+0x8b0/0x8d0 (unreliable) [ 2.553229] [c0000000622e7750] [c0000000007f40b4] free_pgd_range+0x284/0x3b0 [ 2.553248] [c0000000622e7800] [c0000000007f4630] free_pgtables+0x450/0x570 [ 2.553274] [c0000000622e78e0] [c0000000008161c0] exit_mmap+0x250/0x650 [ 2.553292] [c0000000622e7a30] [c0000000001b95b8] __mmput+0x98/0x290 [ 2.558344] [c0000000622e7a80] [c0000000001d1018] exit_mm+0x118/0x1b0 [ 2.558361] [c0000000622e7ac0] [c0000000001d141c] do_exit+0x2ec/0x870 [ 2.558376] [c0000000622e7b60] [c0000000001d1ca8] do_group_exit+0x88/0x150 [ 2.558391] [c0000000622e7bb0] [c0000000001d1db8] sys_exit_group+0x48/0x50 [ 2.558407] [c0000000622e7be0] [c00000000003d810] system_call_exception+0x1e0/0x4c0 [ 2.558423] [c0000000622e7e50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec (...) [ 2.558892] ---[ end trace 0000000000000000 ]--- [ 2.559022] BUG: Bad rss-counter state mm:000000002267cc9e type:MM_ANONPAGES val:1 [ 2.559037] BUG: non-zero pgtables_bytes on freeing mm: -6144 Here the modprobe process ended up with an allocated mm_struct from the mm_struct slab that was used before by the debug_vm_pgtable test. That is not a problem, since the mm_struct is initialized again etc., however, if it ends up using the same pgd table, it bumps into the old stale entry when clearing/freeing the page table entries, so it tries to free an entry already gone (that one which was allocated by the debug_vm_pgtable test), which also explains the negative pgtables_bytes since it's accounting for not allocated entries in the current process. As far as I looked pgd_{alloc,free} etc. does not clear entries, and clearing of the entries is explicitly done in the free_pgtables-> free_pgd_range->free_p4d_range->free_pud_range->free_pmd_range-> free_pte_range path. However, the debug_vm_pgtable test does not call free_pgtables, since it allocates mm_struct and entries manually for its test and eg. not goes through page faults. So it also should clear manually the entries before exit at destroy_args(). This problem was noticed on a reboot X number of times test being done on a powerpc host, with a debug kernel with CONFIG_DEBUG_VM_PGTABLE enabled. Depends on the system, but on a 100 times reboot loop the problem could manifest once or twice, if a process ends up getting the right mm->pgd entry with the stale entries used by mm/debug_vm_pagetable. After using this patch, I couldn't reproduce/experience the problems anymore. I was able to reproduce the problem as well on latest upstream kernel (6.16). I also modified destroy_args() to use mmput() instead of mmdrop(), there is no reason to hold mm_users reference and not release the mm_struct entirely, and in the output above with my debugging prints I already had patched it to use mmput, it did not fix the problem, but helped in the debugging as well. Link: https://lkml.kernel.org/r/20250731214051.4115182-1-herton@redhat.com Fixes: 3c9b84f044a9 ("mm/debug_vm_pgtable: introduce struct pgtable_debug_args") Signed-off-by: Herton R. Krzesinski Cc: Anshuman Khandual Cc: Christophe Leroy Cc: Gavin Shan Cc: Gerald Schaefer Cc: Signed-off-by: Andrew Morton --- mm/debug_vm_pgtable.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c index d19031f275a3f8..830107b6dd0866 100644 --- a/mm/debug_vm_pgtable.c +++ b/mm/debug_vm_pgtable.c @@ -990,29 +990,34 @@ static void __init destroy_args(struct pgtable_debug_args *args) /* Free page table entries */ if (args->start_ptep) { + pmd_clear(args->pmdp); pte_free(args->mm, args->start_ptep); mm_dec_nr_ptes(args->mm); } if (args->start_pmdp) { + pud_clear(args->pudp); pmd_free(args->mm, args->start_pmdp); mm_dec_nr_pmds(args->mm); } if (args->start_pudp) { + p4d_clear(args->p4dp); pud_free(args->mm, args->start_pudp); mm_dec_nr_puds(args->mm); } - if (args->start_p4dp) + if (args->start_p4dp) { + pgd_clear(args->pgdp); p4d_free(args->mm, args->start_p4dp); + } /* Free vma and mm struct */ if (args->vma) vm_area_free(args->vma); if (args->mm) - mmdrop(args->mm); + mmput(args->mm); } static struct page * __init From 9a6a6a3191574a01dcf7a7d9385246d7bc8736bc Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 11 Aug 2025 06:26:54 +0100 Subject: [PATCH 0373/1292] tools/testing: add linux/args.h header and fix radix, VMA tests Commit 857d18f23ab1 ("cleanup: Introduce ACQUIRE() and ACQUIRE_ERR() for conditional locks") accidentally broke the radix tree, VMA userland tests by including linux/args.h which is not present in the tools/include directory. This patch copies this over and adds an #ifdef block to avoid duplicate __CONCAT declaration in conflict with system headers when we ultimately include this. Link: https://lkml.kernel.org/r/20250811052654.33286-1-lorenzo.stoakes@oracle.com Fixes: 857d18f23ab1 ("cleanup: Introduce ACQUIRE() and ACQUIRE_ERR() for conditional locks") Signed-off-by: Lorenzo Stoakes Cc: Jann Horn Cc: John Hubbard Cc: Liam Howlett Cc: Sidhartha Kumar Cc: Vlastimil Babka Cc: Dan Williams Cc: Peter Zijlstra Signed-off-by: Andrew Morton --- tools/include/linux/args.h | 28 ++++++++++++++++++++++++++++ tools/testing/shared/linux/idr.h | 4 ++++ 2 files changed, 32 insertions(+) create mode 100644 tools/include/linux/args.h diff --git a/tools/include/linux/args.h b/tools/include/linux/args.h new file mode 100644 index 00000000000000..2e8e65d975c778 --- /dev/null +++ b/tools/include/linux/args.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_ARGS_H +#define _LINUX_ARGS_H + +/* + * How do these macros work? + * + * In __COUNT_ARGS() _0 to _12 are just placeholders from the start + * in order to make sure _n is positioned over the correct number + * from 12 to 0 (depending on X, which is a variadic argument list). + * They serve no purpose other than occupying a position. Since each + * macro parameter must have a distinct identifier, those identifiers + * are as good as any. + * + * In COUNT_ARGS() we use actual integers, so __COUNT_ARGS() returns + * that as _n. + */ + +/* This counts to 15. Any more, it will return 16th argument. */ +#define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _n, X...) _n +#define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +/* Concatenate two parameters, but allow them to be expanded beforehand. */ +#define __CONCAT(a, b) a ## b +#define CONCATENATE(a, b) __CONCAT(a, b) + +#endif /* _LINUX_ARGS_H */ diff --git a/tools/testing/shared/linux/idr.h b/tools/testing/shared/linux/idr.h index 4e342f2e37cfb8..676c5564e33f84 100644 --- a/tools/testing/shared/linux/idr.h +++ b/tools/testing/shared/linux/idr.h @@ -1 +1,5 @@ +/* Avoid duplicate definitions due to system headers. */ +#ifdef __CONCAT +#undef __CONCAT +#endif #include "../../../../include/linux/idr.h" From 63f5dec16760f2cd7d3f9034d18fc1fa0d83652f Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Sun, 10 Aug 2025 21:42:01 +0900 Subject: [PATCH 0374/1292] mm/damon/core: fix commit_ops_filters by using correct nth function damos_commit_ops_filters() incorrectly uses damos_nth_filter() which iterates core_filters. As a result, performing a commit unintentionally corrupts ops_filters. Add damos_nth_ops_filter() which iterates ops_filters. Use this function to fix issues caused by wrong iteration. Link: https://lkml.kernel.org/r/20250810124201.15743-1-ekffu200098@gmail.com Fixes: 3607cc590f18 ("mm/damon/core: support committing ops_filters") # 6.15.x Signed-off-by: Sang-Heon Jeon Reviewed-by: SeongJae Park Cc: Signed-off-by: Andrew Morton --- mm/damon/core.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mm/damon/core.c b/mm/damon/core.c index 52a48c9316bc20..467c2d78126fa4 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -845,6 +845,18 @@ static struct damos_filter *damos_nth_filter(int n, struct damos *s) return NULL; } +static struct damos_filter *damos_nth_ops_filter(int n, struct damos *s) +{ + struct damos_filter *filter; + int i = 0; + + damos_for_each_ops_filter(filter, s) { + if (i++ == n) + return filter; + } + return NULL; +} + static void damos_commit_filter_arg( struct damos_filter *dst, struct damos_filter *src) { @@ -908,7 +920,7 @@ static int damos_commit_ops_filters(struct damos *dst, struct damos *src) int i = 0, j = 0; damos_for_each_ops_filter_safe(dst_filter, next, dst) { - src_filter = damos_nth_filter(i++, src); + src_filter = damos_nth_ops_filter(i++, src); if (src_filter) damos_commit_filter(dst_filter, src_filter); else From 7c91e0b91aaa3fa1f897efb06565af0ceb75195c Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Sun, 3 Aug 2025 12:11:21 +0100 Subject: [PATCH 0375/1292] mm/mremap: allow multi-VMA move when filesystem uses thp_get_unmapped_area The multi-VMA move functionality introduced in commit d23cb648e365 ("mm/mremap: permit mremap() move of multiple VMA") doesn't allow moves of file-backed mappings which specify a custom f_op->get_unmapped_area handler excepting hugetlb and shmem. We expand this to include thp_get_unmapped_area to support file-backed mappings for filesystems which use large folios. Additionally, when the first VMA in a range is not compatible with a multi-VMA move, instead of moving the first VMA and returning an error, this series results in us not moving anything and returning an error immediately. Examining this second change in detail: The semantics of multi-VMA moves in mremap() very clearly indicate that a failure can result in a partial move of VMAs. This is in line with other aggregate operations within the kernel, which share these semantics. There are two classes of failures we're concerned with - eligiblity for mutli-VMA move, and transient failures that would occur even if the user individually moved each VMA. The latter is due to out-of-memory conditions (which, given the allocations involved are small, would likely be fatal in any case), or hitting the mapping limit. Regardless of the cause, transient issues would be fatal anyway, so it isn't really material which VMAs succeeded at being moved or not. However with when it comes to multi-VMA move eligiblity, we face another issue - we must allow a single VMA to succeed regardless of this eligiblity (as, of course, it is not a multi-VMA move) - but we must then fail multi-VMA operations. The two means by which VMAs may fail the eligbility test are - the VMAs being UFFD-armed, or the VMA being file-backed and providing its own f_op->get_unmapped_area() helper (because this may result in MREMAP_FIXED being disregarded), excepting those known to correctly handle MREMAP_FIXED. It is therefore conceivable that a user could erroneously try to use this functionality in these instances, and would prefer to not perform any move at all should that occur. This series therefore avoids any move of subsequent VMAs should the first be multi-VMA move ineligble and the input span exceeds that of the first VMA. We also add detailed test logic to assert that multi VMA move with ineligible VMAs functions as expected. This patch (of 3): We currently restrict multi-VMA move to avoid filesystems or drivers which provide a custom f_op->get_unmapped_area handler unless it is known to correctly handle MREMAP_FIXED. We do this so we do not get unexpected result when moving from one area to another (for instance, if the handler would align things resulting in the moved VMAs having different gaps than the original mapping). More and more filesystems are moving to using large folios, and typically do so (in part) by setting f_op->get_unmapped_area to thp_get_unmapped_area. When mremap() invokes the file system's get_unmapped MREMAP_FIXED, it does so via get_unmapped_area(), called in vrm_set_new_addr(). In order to do so, it converts the MREMAP_FIXED flag to a MAP_FIXED flag and passes this to the unmapped area handler. The __get_unmapped_area() function (called by get_unmapped_area()) in turn invokes the filesystem or driver's f_op->get_unmapped_area() handler. Therefore this is a point at which thp_get_unmapped_area() may be called (also, this is the case for anonymous mappings where the size is huge page aligned). thp_get_unmapped_area() calls thp_get_unmapped_area_vmflags() and __thp_get_unmapped_area() in turn (falling back to mm_get_unmapped_area_vm_flags() which is known to handle MAP_FIXED correctly). The __thp_get_unmapped_area() function in turn does nothing to change the address hint, nor the MAP_FIXED flag, only adjusting alignment parameters. It hten calls mm_get_unmapped_area_vmflags(), and in turn arch-specific unmapped area functions, all of which honour MAP_FIXED correctly. Therefore, we can safely add thp_get_unmapped_area to the known-good handlers. Link: https://lkml.kernel.org/r/cover.1754218667.git.lorenzo.stoakes@oracle.com Link: https://lkml.kernel.org/r/4f2542340c29c84d3d470b0c605e916b192f6c81.1754218667.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes Reviewed-by: Vlastimil Babka Cc: David Hildenbrand Cc: Jann Horn Cc: Liam Howlett Cc: Michal Hocko Cc: Mike Rapoport Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton --- mm/mremap.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/mm/mremap.c b/mm/mremap.c index 9afa8cd524f5f8..eb37d1668770a9 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -1620,7 +1620,7 @@ static void notify_uffd(struct vma_remap_struct *vrm, bool failed) static bool vma_multi_allowed(struct vm_area_struct *vma) { - struct file *file; + struct file *file = vma->vm_file; /* * We can't support moving multiple uffd VMAs as notify requires @@ -1633,15 +1633,17 @@ static bool vma_multi_allowed(struct vm_area_struct *vma) * Custom get unmapped area might result in MREMAP_FIXED not * being obeyed. */ - file = vma->vm_file; - if (file && !vma_is_shmem(vma) && !is_vm_hugetlb_page(vma)) { - const struct file_operations *fop = file->f_op; - - if (fop->get_unmapped_area) - return false; - } + if (!file || !file->f_op->get_unmapped_area) + return true; + /* Known good. */ + if (vma_is_shmem(vma)) + return true; + if (is_vm_hugetlb_page(vma)) + return true; + if (file->f_op->get_unmapped_area == thp_get_unmapped_area) + return true; - return true; + return false; } static int check_prep_vma(struct vma_remap_struct *vrm) From d5f416c7c36456676c2cf5ab98776db2e7601f27 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Sun, 3 Aug 2025 12:11:22 +0100 Subject: [PATCH 0376/1292] mm/mremap: catch invalid multi VMA moves earlier Previously, any attempt to solely move a VMA would require that the span specified reside within the span of that single VMA, with no gaps before or afterwards. After commit d23cb648e365 ("mm/mremap: permit mremap() move of multiple VMAs"), the multi VMA move permitted a gap to exist only after VMAs. This was done to provide maximum flexibility. However, We have consequently permitted this behaviour for the move of a single VMA including those not eligible for multi VMA move. The change introduced here means that we no longer permit non-eligible VMAs from being moved in this way. This is consistent, as it means all eligible VMA moves are treated the same, and all non-eligible moves are treated as they were before. This change does not break previous behaviour, which equally would have disallowed such a move (only in all cases). [lorenzo.stoakes@oracle.com: do not incorrectly reference invalid VMA in VM_WARN_ON_ONCE()] Link: https://lkml.kernel.org/r/b6dbda20-667e-4053-abae-8ed4fa84bb6c@lucifer.local Link: https://lkml.kernel.org/r/2b5aad5681573be85b5b8fac61399af6fb6b68b6.1754218667.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes Reviewed-by: Vlastimil Babka Cc: David Hildenbrand Cc: Jann Horn Cc: Liam Howlett Cc: Michal Hocko Cc: Mike Rapoport Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton --- mm/mremap.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/mm/mremap.c b/mm/mremap.c index eb37d1668770a9..33b642076205db 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -1820,10 +1820,11 @@ static unsigned long remap_move(struct vma_remap_struct *vrm) unsigned long start = vrm->addr; unsigned long end = vrm->addr + vrm->old_len; unsigned long new_addr = vrm->new_addr; - bool allowed = true, seen_vma = false; unsigned long target_addr = new_addr; unsigned long res = -EFAULT; unsigned long last_end; + bool seen_vma = false; + VMA_ITERATOR(vmi, current->mm, start); /* @@ -1836,9 +1837,7 @@ static unsigned long remap_move(struct vma_remap_struct *vrm) unsigned long addr = max(vma->vm_start, start); unsigned long len = min(end, vma->vm_end) - addr; unsigned long offset, res_vma; - - if (!allowed) - return -EFAULT; + bool multi_allowed; /* No gap permitted at the start of the range. */ if (!seen_vma && start < vma->vm_start) @@ -1867,9 +1866,15 @@ static unsigned long remap_move(struct vma_remap_struct *vrm) vrm->new_addr = target_addr + offset; vrm->old_len = vrm->new_len = len; - allowed = vma_multi_allowed(vma); - if (seen_vma && !allowed) - return -EFAULT; + multi_allowed = vma_multi_allowed(vma); + if (!multi_allowed) { + /* This is not the first VMA, abort immediately. */ + if (seen_vma) + return -EFAULT; + /* This is the first, but there are more, abort. */ + if (vma->vm_end < end) + return -EFAULT; + } res_vma = check_prep_vma(vrm); if (!res_vma) @@ -1878,7 +1883,7 @@ static unsigned long remap_move(struct vma_remap_struct *vrm) return res_vma; if (!seen_vma) { - VM_WARN_ON_ONCE(allowed && res_vma != new_addr); + VM_WARN_ON_ONCE(multi_allowed && res_vma != new_addr); res = res_vma; } From 742d3663a5775cb7b957f4ca2ddb4ccd26badb94 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Sun, 3 Aug 2025 12:11:23 +0100 Subject: [PATCH 0377/1292] selftests/mm: add test for invalid multi VMA operations We can use UFFD to easily assert invalid multi VMA moves, so do so, asserting expected behaviour when VMAs invalid for a multi VMA operation are encountered. We assert both that such operations are not permitted, and that we do not even attempt to move the first VMA under these circumstances. We also assert that we can still move a single VMA regardless. We then assert that a partial failure can occur if the invalid VMA appears later in the range of multiple VMAs, both at the very next VMA, and also at the end of the range. As part of this change, we are using the is_range_valid() helper more aggressively. Therefore, fix a bug where stale buffered data would hang around on success, causing subsequent calls to is_range_valid() to potentially give invalid results. We simply have to fflush() the stream on success to resolve this issue. Link: https://lkml.kernel.org/r/c4fb86dd5ba37610583ad5fc0e0c2306ddf318b9.1754218667.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes Cc: David Hildenbrand Cc: Jann Horn Cc: Liam Howlett Cc: Michal Hocko Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Vlastimil Babka Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/mremap_test.c | 264 ++++++++++++++++++++++- 1 file changed, 261 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c index fccf9e797a0c02..5bd52a951cbd61 100644 --- a/tools/testing/selftests/mm/mremap_test.c +++ b/tools/testing/selftests/mm/mremap_test.c @@ -5,10 +5,14 @@ #define _GNU_SOURCE #include +#include +#include #include #include #include +#include #include +#include #include #include @@ -168,6 +172,7 @@ static bool is_range_mapped(FILE *maps_fp, unsigned long start, if (first_val <= start && second_val >= end) { success = true; + fflush(maps_fp); break; } } @@ -175,6 +180,15 @@ static bool is_range_mapped(FILE *maps_fp, unsigned long start, return success; } +/* Check if [ptr, ptr + size) mapped in /proc/self/maps. */ +static bool is_ptr_mapped(FILE *maps_fp, void *ptr, unsigned long size) +{ + unsigned long start = (unsigned long)ptr; + unsigned long end = start + size; + + return is_range_mapped(maps_fp, start, end); +} + /* * Returns the start address of the mapping on success, else returns * NULL on failure. @@ -733,6 +747,249 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed, dont_unmap ? " [dontunnmap]" : ""); } +#ifdef __NR_userfaultfd +static void mremap_move_multi_invalid_vmas(FILE *maps_fp, + unsigned long page_size) +{ + char *test_name = "mremap move multiple invalid vmas"; + const size_t size = 10 * page_size; + bool success = true; + char *ptr, *tgt_ptr; + int uffd, err, i; + void *res; + struct uffdio_api api = { + .api = UFFD_API, + .features = UFFD_EVENT_PAGEFAULT, + }; + + uffd = syscall(__NR_userfaultfd, O_NONBLOCK); + if (uffd == -1) { + err = errno; + perror("userfaultfd"); + if (err == EPERM) { + ksft_test_result_skip("%s - missing uffd", test_name); + return; + } + success = false; + goto out; + } + if (ioctl(uffd, UFFDIO_API, &api)) { + perror("ioctl UFFDIO_API"); + success = false; + goto out_close_uffd; + } + + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (ptr == MAP_FAILED) { + perror("mmap"); + success = false; + goto out_close_uffd; + } + + tgt_ptr = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (tgt_ptr == MAP_FAILED) { + perror("mmap"); + success = false; + goto out_close_uffd; + } + if (munmap(tgt_ptr, size)) { + perror("munmap"); + success = false; + goto out_unmap; + } + + /* + * Unmap so we end up with: + * + * 0 2 4 6 8 10 offset in buffer + * |*| |*| |*| |*| |*| + * |*| |*| |*| |*| |*| + * + * Additionally, register each with UFFD. + */ + for (i = 0; i < 10; i += 2) { + void *unmap_ptr = &ptr[(i + 1) * page_size]; + unsigned long start = (unsigned long)&ptr[i * page_size]; + struct uffdio_register reg = { + .range = { + .start = start, + .len = page_size, + }, + .mode = UFFDIO_REGISTER_MODE_MISSING, + }; + + if (ioctl(uffd, UFFDIO_REGISTER, ®) == -1) { + perror("ioctl UFFDIO_REGISTER"); + success = false; + goto out_unmap; + } + if (munmap(unmap_ptr, page_size)) { + perror("munmap"); + success = false; + goto out_unmap; + } + } + + /* + * Now try to move the entire range which is invalid for multi VMA move. + * + * This will fail, and no VMA should be moved, as we check this ahead of + * time. + */ + res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); + err = errno; + if (res != MAP_FAILED) { + fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n"); + success = false; + goto out_unmap; + } + if (err != EFAULT) { + errno = err; + perror("mrmeap() unexpected error"); + success = false; + goto out_unmap; + } + if (is_ptr_mapped(maps_fp, tgt_ptr, page_size)) { + fprintf(stderr, + "Invalid uffd-armed VMA at start of multi range moved\n"); + success = false; + goto out_unmap; + } + + /* + * Now try to move a single VMA, this should succeed as not multi VMA + * move. + */ + res = mremap(ptr, page_size, page_size, + MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); + if (res == MAP_FAILED) { + perror("mremap single invalid-multi VMA"); + success = false; + goto out_unmap; + } + + /* + * Unmap the VMA, and remap a non-uffd registered (therefore, multi VMA + * move valid) VMA at the start of ptr range. + */ + if (munmap(tgt_ptr, page_size)) { + perror("munmap"); + success = false; + goto out_unmap; + } + res = mmap(ptr, page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if (res == MAP_FAILED) { + perror("mmap"); + success = false; + goto out_unmap; + } + + /* + * Now try to move the entire range, we should succeed in moving the + * first VMA, but no others, and report a failure. + */ + res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); + err = errno; + if (res != MAP_FAILED) { + fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n"); + success = false; + goto out_unmap; + } + if (err != EFAULT) { + errno = err; + perror("mrmeap() unexpected error"); + success = false; + goto out_unmap; + } + if (!is_ptr_mapped(maps_fp, tgt_ptr, page_size)) { + fprintf(stderr, "Valid VMA not moved\n"); + success = false; + goto out_unmap; + } + + /* + * Unmap the VMA, and map valid VMA at start of ptr range, and replace + * all existing multi-move invalid VMAs, except the last, with valid + * multi-move VMAs. + */ + if (munmap(tgt_ptr, page_size)) { + perror("munmap"); + success = false; + goto out_unmap; + } + if (munmap(ptr, size - 2 * page_size)) { + perror("munmap"); + success = false; + goto out_unmap; + } + for (i = 0; i < 8; i += 2) { + res = mmap(&ptr[i * page_size], page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if (res == MAP_FAILED) { + perror("mmap"); + success = false; + goto out_unmap; + } + } + + /* + * Now try to move the entire range, we should succeed in moving all but + * the last VMA, and report a failure. + */ + res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); + err = errno; + if (res != MAP_FAILED) { + fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n"); + success = false; + goto out_unmap; + } + if (err != EFAULT) { + errno = err; + perror("mrmeap() unexpected error"); + success = false; + goto out_unmap; + } + + for (i = 0; i < 10; i += 2) { + bool is_mapped = is_ptr_mapped(maps_fp, + &tgt_ptr[i * page_size], page_size); + + if (i < 8 && !is_mapped) { + fprintf(stderr, "Valid VMA not moved at %d\n", i); + success = false; + goto out_unmap; + } else if (i == 8 && is_mapped) { + fprintf(stderr, "Invalid VMA moved at %d\n", i); + success = false; + goto out_unmap; + } + } + +out_unmap: + if (munmap(tgt_ptr, size)) + perror("munmap tgt"); + if (munmap(ptr, size)) + perror("munmap src"); +out_close_uffd: + close(uffd); +out: + if (success) + ksft_test_result_pass("%s\n", test_name); + else + ksft_test_result_fail("%s\n", test_name); +} +#else +static void mremap_move_multi_invalid_vmas(FILE *maps_fp, unsigned long page_size) +{ + char *test_name = "mremap move multiple invalid vmas"; + + ksft_test_result_skip("%s - missing uffd", test_name); +} +#endif /* __NR_userfaultfd */ + /* Returns the time taken for the remap on success else returns -1. */ static long long remap_region(struct config c, unsigned int threshold_mb, char *rand_addr) @@ -1074,7 +1331,7 @@ int main(int argc, char **argv) char *rand_addr; size_t rand_size; int num_expand_tests = 2; - int num_misc_tests = 8; + int num_misc_tests = 9; struct test test_cases[MAX_TEST] = {}; struct test perf_test_cases[MAX_PERF_TEST]; int page_size; @@ -1197,8 +1454,6 @@ int main(int argc, char **argv) mremap_expand_merge(maps_fp, page_size); mremap_expand_merge_offset(maps_fp, page_size); - fclose(maps_fp); - mremap_move_within_range(pattern_seed, rand_addr); mremap_move_1mb_from_start(pattern_seed, rand_addr); mremap_shrink_multiple_vmas(page_size, /* inplace= */true); @@ -1207,6 +1462,9 @@ int main(int argc, char **argv) mremap_move_multiple_vmas(pattern_seed, page_size, /* dontunmap= */ true); mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ false); mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ true); + mremap_move_multi_invalid_vmas(maps_fp, page_size); + + fclose(maps_fp); if (run_perf_tests) { ksft_print_msg("\n%s\n", From 8b26f0a8b4f220c1ec410e1350e8594911ec5742 Mon Sep 17 00:00:00 2001 From: Easwar Hariharan Date: Tue, 12 Aug 2025 18:02:14 +0000 Subject: [PATCH 0378/1292] .mailmap: add entry for Easwar Hariharan Map my old, obsolete work email address to my current one. Link: https://lkml.kernel.org/r/20250812180218.92755-1-easwar.hariharan@linux.microsoft.com Signed-off-by: Easwar Hariharan Cc: Carlos Bilbao Cc: Jarkko Sakkinen Cc: Shannon Nelson Cc: Dmitry Baryshkov Cc: Hans Verkuil Signed-off-by: Andrew Morton --- .mailmap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mailmap b/.mailmap index d9fa1b55511652..a124aeed52a2a3 100644 --- a/.mailmap +++ b/.mailmap @@ -226,6 +226,8 @@ Domen Puncer Douglas Gilbert Drew Fustini +Easwar Hariharan +Easwar Hariharan Ed L. Cashin Elliot Berman Enric Balletbo i Serra From 0cc2a4880ced1486acc34898cd85edc6ee109c4c Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Tue, 12 Aug 2025 23:00:46 +0900 Subject: [PATCH 0379/1292] selftests/damon: fix selftests by installing drgn related script drgn_dump_damon_status is not installed during kselftest setup. It can break other tests which depend on drgn_dump_damon_status. Install drgn_dump_damon_status files to fix broken test. Link: https://lkml.kernel.org/r/20250812140046.660486-1-ekffu200098@gmail.com Fixes: f3e8e1e51362 ("selftests/damon: add drgn script for extracting damon status") Signed-off-by: Sang-Heon Jeon Reviewed-by: SeongJae Park Cc: Alexandre Ghiti Cc: Honggyu Kim Signed-off-by: Andrew Morton --- tools/testing/selftests/damon/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile index 5b230deb19e8ee..9a3499827d4b50 100644 --- a/tools/testing/selftests/damon/Makefile +++ b/tools/testing/selftests/damon/Makefile @@ -4,6 +4,7 @@ TEST_GEN_FILES += access_memory access_memory_even TEST_FILES = _damon_sysfs.py +TEST_FILES += drgn_dump_damon_status.py # functionality tests TEST_PROGS += sysfs.sh From 808471ddb0fa785559c3e7aee59be20a13b46ef5 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 13 Aug 2025 15:04:55 +0900 Subject: [PATCH 0380/1292] iov_iter: iterate_folioq: fix handling of offset >= folio size It's apparently possible to get an iov advanced all the way up to the end of the current page we're looking at, e.g. (gdb) p *iter $24 = {iter_type = 4 '\004', nofault = false, data_source = false, iov_offset = 4096, {__ubuf_iovec = { iov_base = 0xffff88800f5bc000, iov_len = 655}, {{__iov = 0xffff88800f5bc000, kvec = 0xffff88800f5bc000, bvec = 0xffff88800f5bc000, folioq = 0xffff88800f5bc000, xarray = 0xffff88800f5bc000, ubuf = 0xffff88800f5bc000}, count = 655}}, {nr_segs = 2, folioq_slot = 2 '\002', xarray_start = 2}} Where iov_offset is 4k with 4k-sized folios This should have been fine because we're only in the 2nd slot and there's another one after this, but iterate_folioq should not try to map a folio that skips the whole size, and more importantly part here does not end up zero (because 'PAGE_SIZE - skip % PAGE_SIZE' ends up PAGE_SIZE and not zero..), so skip forward to the "advance to next folio" code Link: https://lkml.kernel.org/r/20250813-iot_iter_folio-v3-0-a0ffad2b665a@codewreck.org Link: https://lkml.kernel.org/r/20250813-iot_iter_folio-v3-1-a0ffad2b665a@codewreck.org Signed-off-by: Dominique Martinet Fixes: db0aa2e9566f ("mm: Define struct folio_queue and ITER_FOLIOQ to handle a sequence of folios") Reported-by: Maximilian Bosch Reported-by: Ryan Lahfa Reported-by: Christian Theune Reported-by: Arnout Engelen Link: https://lkml.kernel.org/r/D4LHHUNLG79Y.12PI0X6BEHRHW@mbosch.me/ Acked-by: David Howells Cc: Al Viro Cc: Christian Brauner Cc: Matthew Wilcox (Oracle) Cc: [6.12+] Signed-off-by: Andrew Morton --- include/linux/iov_iter.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/linux/iov_iter.h b/include/linux/iov_iter.h index c4aa58032faf87..f9a17fbbd3980b 100644 --- a/include/linux/iov_iter.h +++ b/include/linux/iov_iter.h @@ -160,7 +160,7 @@ size_t iterate_folioq(struct iov_iter *iter, size_t len, void *priv, void *priv2 do { struct folio *folio = folioq_folio(folioq, slot); - size_t part, remain, consumed; + size_t part, remain = 0, consumed; size_t fsize; void *base; @@ -168,14 +168,16 @@ size_t iterate_folioq(struct iov_iter *iter, size_t len, void *priv, void *priv2 break; fsize = folioq_folio_size(folioq, slot); - base = kmap_local_folio(folio, skip); - part = umin(len, PAGE_SIZE - skip % PAGE_SIZE); - remain = step(base, progress, part, priv, priv2); - kunmap_local(base); - consumed = part - remain; - len -= consumed; - progress += consumed; - skip += consumed; + if (skip < fsize) { + base = kmap_local_folio(folio, skip); + part = umin(len, PAGE_SIZE - skip % PAGE_SIZE); + remain = step(base, progress, part, priv, priv2); + kunmap_local(base); + consumed = part - remain; + len -= consumed; + progress += consumed; + skip += consumed; + } if (skip >= fsize) { skip = 0; slot++; From c7b70f76db0703a93b39a85b540d5b3911e166e8 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 14 Aug 2025 07:54:54 +0000 Subject: [PATCH 0381/1292] mm: rust: add page.rs to MEMORY MANAGEMENT - RUST The page.rs file currently isn't included anywhere, and I think it's a good fit for the MEMORY MANAGEMENT - RUST entry. The file was originally added for use by Rust Binder, but I believe there is also work to use it in the upcoming scatterlist abstractions. Link: https://lkml.kernel.org/r/20250814075454.1596482-1-aliceryhl@google.com Signed-off-by: Alice Ryhl Acked-by: Danilo Krummrich Cc: Danilo Krummrich Cc: Liam Howlett Cc: "Uladzislau Rezki (Sony)" Cc: Vlastimil Babka Signed-off-by: Andrew Morton --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index daf520a13bdf6a..afd7663c367f76 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16248,8 +16248,10 @@ S: Maintained W: http://www.linux-mm.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm F: rust/helpers/mm.c +F: rust/helpers/page.c F: rust/kernel/mm.rs F: rust/kernel/mm/ +F: rust/kernel/page.rs MEMORY MAPPING M: Andrew Morton From 44958000badae5488d91431de194f747acc5dcac Mon Sep 17 00:00:00 2001 From: Axel Rasmussen Date: Fri, 15 Aug 2025 14:59:14 -0700 Subject: [PATCH 0382/1292] MAINTAINERS: mark MGLRU as maintained The three folks being added here are actively working on MGLRU within Google, so we can review patches for this feature and plan to contribute some improvements / extensions to it on an ongoing basis. With three of us we may have some hope filling Yu Zhao's shoes, since he has moved on to other projects these days. Link: https://lkml.kernel.org/r/20250815215914.3671925-1-axelrasmussen@google.com Signed-off-by: Axel Rasmussen Cc: Lorenzo Stoakes Cc: Axel Rasmussen Cc: Shakeel Butt Cc: Wei Xu Cc: Yuanchu Xie Cc: Yu Zhao Signed-off-by: Andrew Morton --- MAINTAINERS | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index afd7663c367f76..64e6a25b3aa29d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16058,6 +16058,23 @@ F: mm/mempolicy.c F: mm/migrate.c F: mm/migrate_device.c +MEMORY MANAGEMENT - MGLRU (MULTI-GEN LRU) +M: Andrew Morton +M: Axel Rasmussen +M: Yuanchu Xie +R: Wei Xu +L: linux-mm@kvack.org +S: Maintained +W: http://www.linux-mm.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm +F: Documentation/admin-guide/mm/multigen_lru.rst +F: Documentation/mm/multigen_lru.rst +F: include/linux/mm_inline.h +F: include/linux/mmzone.h +F: mm/swap.c +F: mm/vmscan.c +F: mm/workingset.c + MEMORY MANAGEMENT - MISC M: Andrew Morton M: David Hildenbrand From 2e6053fea379806269c4f7f5e36b523c9c0fb35c Mon Sep 17 00:00:00 2001 From: Jinjiang Tu Date: Fri, 15 Aug 2025 15:32:09 +0800 Subject: [PATCH 0383/1292] mm/memory-failure: fix infinite UCE for VM_PFNMAP pfn When memory_failure() is called for a already hwpoisoned pfn, kill_accessing_process() will be called to kill current task. However, if the vma of the accessing vaddr is VM_PFNMAP, walk_page_range() will skip the vma in walk_page_test() and return 0. Before commit aaf99ac2ceb7 ("mm/hwpoison: do not send SIGBUS to processes with recovered clean pages"), kill_accessing_process() will return EFAULT. For x86, the current task will be killed in kill_me_maybe(). However, after this commit, kill_accessing_process() simplies return 0, that means UCE is handled properly, but it doesn't actually. In such case, the user task will trigger UCE infinitely. To fix it, add .test_walk callback for hwpoison_walk_ops to scan all vmas. Link: https://lkml.kernel.org/r/20250815073209.1984582-1-tujinjiang@huawei.com Fixes: aaf99ac2ceb7 ("mm/hwpoison: do not send SIGBUS to processes with recovered clean pages") Signed-off-by: Jinjiang Tu Acked-by: David Hildenbrand Acked-by: Miaohe Lin Reviewed-by: Jane Chu Cc: Kefeng Wang Cc: Naoya Horiguchi Cc: Oscar Salvador Cc: Shuai Xue Cc: Zi Yan Cc: Signed-off-by: Andrew Morton --- mm/memory-failure.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index e2e685b971bbaf..fc30ca4804bf47 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -853,9 +853,17 @@ static int hwpoison_hugetlb_range(pte_t *ptep, unsigned long hmask, #define hwpoison_hugetlb_range NULL #endif +static int hwpoison_test_walk(unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + /* We also want to consider pages mapped into VM_PFNMAP. */ + return 0; +} + static const struct mm_walk_ops hwpoison_walk_ops = { .pmd_entry = hwpoison_pte_range, .hugetlb_entry = hwpoison_hugetlb_range, + .test_walk = hwpoison_test_walk, .walk_lock = PGWALK_RDLOCK, }; From b3dee902b6c26b7d8031a4df19753e27dcfcba01 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Sat, 16 Aug 2025 10:51:16 +0900 Subject: [PATCH 0384/1292] mm/damon/core: fix damos_commit_filter not changing allow Current damos_commit_filter() does not persist the `allow' value of the filter. As a result, changing the `allow' value of a filter and committing doesn't change the `allow' value. Add the missing `allow' value update, so committing the filter persistently changes the `allow' value well. Link: https://lkml.kernel.org/r/20250816015116.194589-1-ekffu200098@gmail.com Fixes: fe6d7fdd6249 ("mm/damon/core: add damos_filter->allow field") Signed-off-by: Sang-Heon Jeon Reviewed-by: SeongJae Park Cc: [6.14.x] Signed-off-by: Andrew Morton --- mm/damon/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/damon/core.c b/mm/damon/core.c index 467c2d78126fa4..70eff5cbe6ee11 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -883,6 +883,7 @@ static void damos_commit_filter( { dst->type = src->type; dst->matching = src->matching; + dst->allow = src->allow; damos_commit_filter_arg(dst, src); } From 053c8ebe74f7e1f4c072e59428da80b9d78bc4b7 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sun, 17 Aug 2025 23:17:59 +0800 Subject: [PATCH 0385/1292] mm/migrate: fix NULL movable_ops if CONFIG_ZSMALLOC=m After commit 84caf98838a3e5f4bdb34 ("mm: stop storing migration_ops in page->mapping") we get such an error message if CONFIG_ZSMALLOC=m: WARNING: CPU: 3 PID: 42 at mm/migrate.c:142 isolate_movable_ops_page+0xa8/0x1c0 CPU: 3 UID: 0 PID: 42 Comm: kcompactd0 Not tainted 6.16.0-rc5+ #2133 PREEMPT pc 9000000000540bd8 ra 9000000000540b84 tp 9000000100420000 sp 9000000100423a60 a0 9000000100193a80 a1 000000000000000c a2 000000000000001b a3 ffffffffffffffff a4 ffffffffffffffff a5 0000000000000267 a6 0000000000000000 a7 9000000100423ae0 t0 00000000000000f1 t1 00000000000000f6 t2 0000000000000000 t3 0000000000000001 t4 ffffff00010eb834 t5 0000000000000040 t6 900000010c89d380 t7 90000000023fcc70 t8 0000000000000018 u0 0000000000000000 s9 ffffff00010eb800 s0 ffffff00010eb800 s1 000000000000000c s2 0000000000043ae0 s3 0000800000000000 s4 900000000219cc40 s5 0000000000000000 s6 ffffff00010eb800 s7 0000000000000001 s8 90000000025b4000 ra: 9000000000540b84 isolate_movable_ops_page+0x54/0x1c0 ERA: 9000000000540bd8 isolate_movable_ops_page+0xa8/0x1c0 CRMD: 000000b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE) PRMD: 00000004 (PPLV0 +PIE -PWE) EUEN: 00000000 (-FPE -SXE -ASXE -BTE) ECFG: 00071c1d (LIE=0,2-4,10-12 VS=7) ESTAT: 000c0000 [BRK] (IS= ECode=12 EsubCode=0) PRID: 0014c010 (Loongson-64bit, Loongson-3A5000) CPU: 3 UID: 0 PID: 42 Comm: kcompactd0 Not tainted 6.16.0-rc5+ #2133 PREEMPT Stack : 90000000021fd000 0000000000000000 9000000000247720 9000000100420000 90000001004236a0 90000001004236a8 0000000000000000 90000001004237e8 90000001004237e0 90000001004237e0 9000000100423550 0000000000000001 0000000000000001 90000001004236a8 725a84864a19e2d9 90000000023fcc58 9000000100420000 90000000024c6848 9000000002416848 0000000000000001 0000000000000000 000000000000000a 0000000007fe0000 ffffff00010eb800 0000000000000000 90000000021fd000 0000000000000000 900000000205cf30 000000000000008e 0000000000000009 ffffff00010eb800 0000000000000001 90000000025b4000 0000000000000000 900000000024773c 00007ffff103d748 00000000000000b0 0000000000000004 0000000000000000 0000000000071c1d ... Call Trace: [<900000000024773c>] show_stack+0x5c/0x190 [<90000000002415e0>] dump_stack_lvl+0x70/0x9c [<90000000004abe6c>] isolate_migratepages_block+0x3bc/0x16e0 [<90000000004af408>] compact_zone+0x558/0x1000 [<90000000004b0068>] compact_node+0xa8/0x1e0 [<90000000004b0aa4>] kcompactd+0x394/0x410 [<90000000002b3c98>] kthread+0x128/0x140 [<9000000001779148>] ret_from_kernel_thread+0x28/0xc0 [<9000000000245528>] ret_from_kernel_thread_asm+0x10/0x88 The reason is that defined(CONFIG_ZSMALLOC) evaluates to 1 only when CONFIG_ZSMALLOC=y, we should use IS_ENABLED(CONFIG_ZSMALLOC) instead. But when I use IS_ENABLED(CONFIG_ZSMALLOC), page_movable_ops() cannot access zsmalloc_mops because zsmalloc_mops is in a module. To solve this problem, we define a set_movable_ops() interface to register and unregister offline_movable_ops / zsmalloc_movable_ops in mm/migrate.c, and call them at mm/balloon_compaction.c & mm/zsmalloc.c. Since offline_movable_ops / zsmalloc_movable_ops are always accessible, all #ifdef / #endif are removed in page_movable_ops(). Link: https://lkml.kernel.org/r/20250817151759.2525174-1-chenhuacai@loongson.cn Fixes: 84caf98838a3 ("mm: stop storing migration_ops in page->mapping") Signed-off-by: Huacai Chen Acked-by: Zi Yan Acked-by: David Hildenbrand Cc: Huacai Chen Cc: Huacai Chen Cc: Lorenzo Stoakes Cc: "Michael S. Tsirkin" Cc: Minchan Kim Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton --- include/linux/migrate.h | 5 +++++ mm/balloon_compaction.c | 6 ++++++ mm/migrate.c | 38 ++++++++++++++++++++++++++++++-------- mm/zsmalloc.c | 10 ++++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/include/linux/migrate.h b/include/linux/migrate.h index acadd41e0b5cf8..9009e27b5f44c1 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -79,6 +79,7 @@ void migration_entry_wait_on_locked(swp_entry_t entry, spinlock_t *ptl) void folio_migrate_flags(struct folio *newfolio, struct folio *folio); int folio_migrate_mapping(struct address_space *mapping, struct folio *newfolio, struct folio *folio, int extra_count); +int set_movable_ops(const struct movable_operations *ops, enum pagetype type); #else @@ -100,6 +101,10 @@ static inline int migrate_huge_page_move_mapping(struct address_space *mapping, { return -ENOSYS; } +static inline int set_movable_ops(const struct movable_operations *ops, enum pagetype type) +{ + return -ENOSYS; +} #endif /* CONFIG_MIGRATION */ diff --git a/mm/balloon_compaction.c b/mm/balloon_compaction.c index 2a4a649805c11c..03c5dbabb1565d 100644 --- a/mm/balloon_compaction.c +++ b/mm/balloon_compaction.c @@ -254,4 +254,10 @@ const struct movable_operations balloon_mops = { .putback_page = balloon_page_putback, }; +static int __init balloon_init(void) +{ + return set_movable_ops(&balloon_mops, PGTY_offline); +} +core_initcall(balloon_init); + #endif /* CONFIG_BALLOON_COMPACTION */ diff --git a/mm/migrate.c b/mm/migrate.c index 425401b2d4e145..9e5ef39ce73af0 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -43,8 +43,6 @@ #include #include #include -#include -#include #include @@ -53,6 +51,33 @@ #include "internal.h" #include "swap.h" +static const struct movable_operations *offline_movable_ops; +static const struct movable_operations *zsmalloc_movable_ops; + +int set_movable_ops(const struct movable_operations *ops, enum pagetype type) +{ + /* + * We only allow for selected types and don't handle concurrent + * registration attempts yet. + */ + switch (type) { + case PGTY_offline: + if (offline_movable_ops && ops) + return -EBUSY; + offline_movable_ops = ops; + break; + case PGTY_zsmalloc: + if (zsmalloc_movable_ops && ops) + return -EBUSY; + zsmalloc_movable_ops = ops; + break; + default: + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL_GPL(set_movable_ops); + static const struct movable_operations *page_movable_ops(struct page *page) { VM_WARN_ON_ONCE_PAGE(!page_has_movable_ops(page), page); @@ -62,15 +87,12 @@ static const struct movable_operations *page_movable_ops(struct page *page) * it as movable, the page type must be sticky until the page gets freed * back to the buddy. */ -#ifdef CONFIG_BALLOON_COMPACTION if (PageOffline(page)) /* Only balloon compaction sets PageOffline pages movable. */ - return &balloon_mops; -#endif /* CONFIG_BALLOON_COMPACTION */ -#if defined(CONFIG_ZSMALLOC) && defined(CONFIG_COMPACTION) + return offline_movable_ops; if (PageZsmalloc(page)) - return &zsmalloc_mops; -#endif /* defined(CONFIG_ZSMALLOC) && defined(CONFIG_COMPACTION) */ + return zsmalloc_movable_ops; + return NULL; } diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 2c5e56a653544c..805a10b41266a0 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -2246,8 +2246,15 @@ EXPORT_SYMBOL_GPL(zs_destroy_pool); static int __init zs_init(void) { + int rc __maybe_unused; + #ifdef CONFIG_ZPOOL zpool_register_driver(&zs_zpool_driver); +#endif +#ifdef CONFIG_COMPACTION + rc = set_movable_ops(&zsmalloc_mops, PGTY_zsmalloc); + if (rc) + return rc; #endif zs_stat_init(); return 0; @@ -2257,6 +2264,9 @@ static void __exit zs_exit(void) { #ifdef CONFIG_ZPOOL zpool_unregister_driver(&zs_zpool_driver); +#endif +#ifdef CONFIG_COMPACTION + set_movable_ops(NULL, PGTY_zsmalloc); #endif zs_stat_exit(); } From ba1dd7ac735d604249f1e614d997dc66b30844ab Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sat, 16 Aug 2025 09:55:59 -0700 Subject: [PATCH 0386/1292] mm/damon/sysfs-schemes: put damos dests dir after removing its files damon_sysfs_scheme_rm_dirs() puts dests directory kobject before removing its internal files. Sincee putting the kobject frees its container struct, and the internal files removal accesses the container, use-after-free happens. Fix it by putting the reference _after_ removing the files. Link: https://lkml.kernel.org/r/20250816165559.2601-1-sj@kernel.org Fixes: 2cd0bf85a203 ("mm/damon/sysfs-schemes: implement DAMOS action destinations directory") Signed-off-by: SeongJae Park Reported-by: Alexandre Ghiti Closes: https://lore.kernel.org/2d39a734-320d-4341-8f8a-4019eec2dbf2@ghiti.fr Tested-by: Alexandre Ghiti Signed-off-by: Andrew Morton --- mm/damon/sysfs-schemes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index 74056bcd6a2c58..6536f16006c90f 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -2158,8 +2158,8 @@ static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme) { damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern); kobject_put(&scheme->access_pattern->kobj); - kobject_put(&scheme->dests->kobj); damos_sysfs_dests_rm_dirs(scheme->dests); + kobject_put(&scheme->dests->kobj); damon_sysfs_quotas_rm_dirs(scheme->quotas); kobject_put(&scheme->quotas->kobj); kobject_put(&scheme->watermarks->kobj); From 772e5b4a5e8360743645b9a466842d16092c4f94 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 18 Aug 2025 19:53:58 +0200 Subject: [PATCH 0387/1292] mm/mremap: fix WARN with uffd that has remap events disabled Registering userfaultd on a VMA that spans at least one PMD and then mremap()'ing that VMA can trigger a WARN when recovering from a failed page table move due to a page table allocation error. The code ends up doing the right thing (recurse, avoiding moving actual page tables), but triggering that WARN is unpleasant: WARNING: CPU: 2 PID: 6133 at mm/mremap.c:357 move_normal_pmd mm/mremap.c:357 [inline] WARNING: CPU: 2 PID: 6133 at mm/mremap.c:357 move_pgt_entry mm/mremap.c:595 [inline] WARNING: CPU: 2 PID: 6133 at mm/mremap.c:357 move_page_tables+0x3832/0x44a0 mm/mremap.c:852 Modules linked in: CPU: 2 UID: 0 PID: 6133 Comm: syz.0.19 Not tainted 6.17.0-rc1-syzkaller-00004-g53e760d89498 #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 RIP: 0010:move_normal_pmd mm/mremap.c:357 [inline] RIP: 0010:move_pgt_entry mm/mremap.c:595 [inline] RIP: 0010:move_page_tables+0x3832/0x44a0 mm/mremap.c:852 Code: ... RSP: 0018:ffffc900037a76d8 EFLAGS: 00010293 RAX: 0000000000000000 RBX: 0000000032930007 RCX: ffffffff820c6645 RDX: ffff88802e56a440 RSI: ffffffff820c7201 RDI: 0000000000000007 RBP: ffff888037728fc0 R08: 0000000000000007 R09: 0000000000000000 R10: 0000000032930007 R11: 0000000000000000 R12: 0000000000000000 R13: ffffc900037a79a8 R14: 0000000000000001 R15: dffffc0000000000 FS: 000055556316a500(0000) GS:ffff8880d68bc000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b30863fff CR3: 0000000050171000 CR4: 0000000000352ef0 Call Trace: copy_vma_and_data+0x468/0x790 mm/mremap.c:1215 move_vma+0x548/0x1780 mm/mremap.c:1282 mremap_to+0x1b7/0x450 mm/mremap.c:1406 do_mremap+0xfad/0x1f80 mm/mremap.c:1921 __do_sys_mremap+0x119/0x170 mm/mremap.c:1977 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xcd/0x4c0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f00d0b8ebe9 Code: ... RSP: 002b:00007ffe5ea5ee98 EFLAGS: 00000246 ORIG_RAX: 0000000000000019 RAX: ffffffffffffffda RBX: 00007f00d0db5fa0 RCX: 00007f00d0b8ebe9 RDX: 0000000000400000 RSI: 0000000000c00000 RDI: 0000200000000000 RBP: 00007ffe5ea5eef0 R08: 0000200000c00000 R09: 0000000000000000 R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000002 R13: 00007f00d0db5fa0 R14: 00007f00d0db5fa0 R15: 0000000000000005 The underlying issue is that we recurse during the original page table move, but not during the recovery move. Fix it by checking for both VMAs and performing the check before the pmd_none() sanity check. Add a new helper where we perform+document that check for the PMD and PUD level. Thanks to Harry for bisecting. Link: https://lkml.kernel.org/r/20250818175358.1184757-1-david@redhat.com Fixes: 0cef0bb836e3 ("mm: clear uffd-wp PTE/PMD state on mremap()") Signed-off-by: David Hildenbrand Reported-by: syzbot+4d9a13f0797c46a29e42@syzkaller.appspotmail.com Closes: https://lkml.kernel.org/r/689bb893.050a0220.7f033.013a.GAE@google.com Tested-by: Harry Yoo Cc: "Liam R. Howlett" Cc: Lorenzo Stoakes Cc: Vlastimil Babka Cc: Jann Horn Cc: Pedro Falcato Cc: Signed-off-by: Andrew Morton --- mm/mremap.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/mm/mremap.c b/mm/mremap.c index 33b642076205db..e618a706aff5a6 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -323,6 +323,25 @@ static inline bool arch_supports_page_table_move(void) } #endif +static inline bool uffd_supports_page_table_move(struct pagetable_move_control *pmc) +{ + /* + * If we are moving a VMA that has uffd-wp registered but with + * remap events disabled (new VMA will not be registered with uffd), we + * need to ensure that the uffd-wp state is cleared from all pgtables. + * This means recursing into lower page tables in move_page_tables(). + * + * We might get called with VMAs reversed when recovering from a + * failed page table move. In that case, the + * "old"-but-actually-"originally new" VMA during recovery will not have + * a uffd context. Recursing into lower page tables during the original + * move but not during the recovery move will cause trouble, because we + * run into already-existing page tables. So check both VMAs. + */ + return !vma_has_uffd_without_event_remap(pmc->old) && + !vma_has_uffd_without_event_remap(pmc->new); +} + #ifdef CONFIG_HAVE_MOVE_PMD static bool move_normal_pmd(struct pagetable_move_control *pmc, pmd_t *old_pmd, pmd_t *new_pmd) @@ -335,6 +354,8 @@ static bool move_normal_pmd(struct pagetable_move_control *pmc, if (!arch_supports_page_table_move()) return false; + if (!uffd_supports_page_table_move(pmc)) + return false; /* * The destination pmd shouldn't be established, free_pgtables() * should have released it. @@ -361,15 +382,6 @@ static bool move_normal_pmd(struct pagetable_move_control *pmc, if (WARN_ON_ONCE(!pmd_none(*new_pmd))) return false; - /* If this pmd belongs to a uffd vma with remap events disabled, we need - * to ensure that the uffd-wp state is cleared from all pgtables. This - * means recursing into lower page tables in move_page_tables(), and we - * can reuse the existing code if we simply treat the entry as "not - * moved". - */ - if (vma_has_uffd_without_event_remap(vma)) - return false; - /* * We don't have to worry about the ordering of src and dst * ptlocks because exclusive mmap_lock prevents deadlock. @@ -418,6 +430,8 @@ static bool move_normal_pud(struct pagetable_move_control *pmc, if (!arch_supports_page_table_move()) return false; + if (!uffd_supports_page_table_move(pmc)) + return false; /* * The destination pud shouldn't be established, free_pgtables() * should have released it. @@ -425,15 +439,6 @@ static bool move_normal_pud(struct pagetable_move_control *pmc, if (WARN_ON_ONCE(!pud_none(*new_pud))) return false; - /* If this pud belongs to a uffd vma with remap events disabled, we need - * to ensure that the uffd-wp state is cleared from all pgtables. This - * means recursing into lower page tables in move_page_tables(), and we - * can reuse the existing code if we simply treat the entry as "not - * moved". - */ - if (vma_has_uffd_without_event_remap(vma)) - return false; - /* * We don't have to worry about the ordering of src and dst * ptlocks because exclusive mmap_lock prevents deadlock. From 4a73a36cb704813f588af13d9842d0ba5a185758 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 14 Aug 2025 17:42:14 +0200 Subject: [PATCH 0388/1292] cdc_ncm: Flag Intel OEM version of Fibocom L850-GL as WWAN This lets NetworkManager/ModemManager know that this is a modem and needs to be connected first. Signed-off-by: Lubomir Rintel Link: https://patch.msgid.link/20250814154214.250103-1-lkundrak@v3.sk Signed-off-by: Jakub Kicinski --- drivers/net/usb/cdc_ncm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index ea0e5e276cd6d1..5d123df0a866b8 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -2087,6 +2087,13 @@ static const struct usb_device_id cdc_devs[] = { .driver_info = (unsigned long)&wwan_info, }, + /* Intel modem (label from OEM reads Fibocom L850-GL) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x8087, 0x095a, + USB_CLASS_COMM, + USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, + }, + /* DisplayLink docking stations */ { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_VENDOR, From 26ebba25e210116053609f4c7ee701bffa7ebd7d Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Fri, 8 Aug 2025 12:05:26 +0800 Subject: [PATCH 0389/1292] tools/latency-collector: Check pkg-config install The tool pkg-config used to check libtraceevent and libtracefs, if not installed, it will report the libs not found, even though they have already been installed. Before: libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel libtracefs is missing. Please install libtracefs-dev/libtracefs-devel After: Makefile.config:10: *** Error: pkg-config needed by libtraceevent/libtracefs is missing on this system, please install it. Link: https://lore.kernel.org/20250808040527.2036023-1-chen.dylane@linux.dev Fixes: 9d56c88e5225 ("tools/tracing: Use tools/build makefiles on latency-collector") Signed-off-by: Tao Chen Signed-off-by: Steven Rostedt (Google) --- tools/tracing/latency/Makefile.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/tracing/latency/Makefile.config b/tools/tracing/latency/Makefile.config index 0fe6b50f029bf7..6efa13e3ca93fd 100644 --- a/tools/tracing/latency/Makefile.config +++ b/tools/tracing/latency/Makefile.config @@ -1,7 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only +include $(srctree)/tools/scripts/utilities.mak + STOP_ERROR := +ifndef ($(NO_LIBTRACEEVENT),1) + ifeq ($(call get-executable,$(PKG_CONFIG)),) + $(error Error: $(PKG_CONFIG) needed by libtraceevent/libtracefs is missing on this system, please install it) + endif +endif + define lib_setup $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)")) $(eval LDFLAGS += $(shell sh -c "$(PKG_CONFIG) --libs-only-L lib$(1)")) From 7b128f1d53dcaa324d4aa05d821a6bf4a7b203e7 Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Fri, 8 Aug 2025 12:05:27 +0800 Subject: [PATCH 0390/1292] rtla: Check pkg-config install The tool pkg-config used to check libtraceevent and libtracefs, if not installed, it will report the libs not found, even though they have already been installed. Before: libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel libtracefs is missing. Please install libtracefs-dev/libtracefs-devel After: Makefile.config:10: *** Error: pkg-config needed by libtraceevent/libtracefs is missing on this system, please install it. Link: https://lore.kernel.org/20250808040527.2036023-2-chen.dylane@linux.dev Fixes: 01474dc706ca ("tools/rtla: Use tools/build makefiles to build rtla") Signed-off-by: Tao Chen Signed-off-by: Steven Rostedt (Google) --- tools/tracing/rtla/Makefile.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/tracing/rtla/Makefile.config b/tools/tracing/rtla/Makefile.config index 5f2231d8d62666..07ff5e8f3006e6 100644 --- a/tools/tracing/rtla/Makefile.config +++ b/tools/tracing/rtla/Makefile.config @@ -1,10 +1,18 @@ # SPDX-License-Identifier: GPL-2.0-only +include $(srctree)/tools/scripts/utilities.mak + STOP_ERROR := LIBTRACEEVENT_MIN_VERSION = 1.5 LIBTRACEFS_MIN_VERSION = 1.6 +ifndef ($(NO_LIBTRACEEVENT),1) + ifeq ($(call get-executable,$(PKG_CONFIG)),) + $(error Error: $(PKG_CONFIG) needed by libtraceevent/libtracefs is missing on this system, please install it) + endif +endif + define lib_setup $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)")) $(eval LDFLAGS += $(shell sh -c "$(PKG_CONFIG) --libs-only-L lib$(1)")) From f179f5bc158f07693b74c264f8933c8b0f07503f Mon Sep 17 00:00:00 2001 From: Victor Nogueira Date: Fri, 15 Aug 2025 10:53:17 -0300 Subject: [PATCH 0391/1292] net/sched: sch_dualpi2: Run prob update timer in softirq to avoid deadlock When a user creates a dualpi2 qdisc it automatically sets a timer. This timer will run constantly and update the qdisc's probability field. The issue is that the timer acquires the qdisc root lock and runs in hardirq. The qdisc root lock is also acquired in dev.c whenever a packet arrives for this qdisc. Since the dualpi2 timer callback runs in hardirq, it may interrupt the packet processing running in softirq. If that happens and it runs on the same CPU, it will acquire the same lock and cause a deadlock. The following splat shows up when running a kernel compiled with lock debugging: [ +0.000224] WARNING: inconsistent lock state [ +0.000224] 6.16.0+ #10 Not tainted [ +0.000169] -------------------------------- [ +0.000029] inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage. [ +0.000000] ping/156 [HC0[0]:SC0[2]:HE1:SE0] takes: [ +0.000000] ffff897841242110 (&sch->root_lock_key){?.-.}-{3:3}, at: __dev_queue_xmit+0x86d/0x1140 [ +0.000000] {IN-HARDIRQ-W} state was registered at: [ +0.000000] lock_acquire.part.0+0xb6/0x220 [ +0.000000] _raw_spin_lock+0x31/0x80 [ +0.000000] dualpi2_timer+0x6f/0x270 [ +0.000000] __hrtimer_run_queues+0x1c5/0x360 [ +0.000000] hrtimer_interrupt+0x115/0x260 [ +0.000000] __sysvec_apic_timer_interrupt+0x6d/0x1a0 [ +0.000000] sysvec_apic_timer_interrupt+0x6e/0x80 [ +0.000000] asm_sysvec_apic_timer_interrupt+0x1a/0x20 [ +0.000000] pv_native_safe_halt+0xf/0x20 [ +0.000000] default_idle+0x9/0x10 [ +0.000000] default_idle_call+0x7e/0x1e0 [ +0.000000] do_idle+0x1e8/0x250 [ +0.000000] cpu_startup_entry+0x29/0x30 [ +0.000000] rest_init+0x151/0x160 [ +0.000000] start_kernel+0x6f3/0x700 [ +0.000000] x86_64_start_reservations+0x24/0x30 [ +0.000000] x86_64_start_kernel+0xc8/0xd0 [ +0.000000] common_startup_64+0x13e/0x148 [ +0.000000] irq event stamp: 6884 [ +0.000000] hardirqs last enabled at (6883): [] neigh_resolve_output+0x223/0x270 [ +0.000000] hardirqs last disabled at (6882): [] neigh_resolve_output+0x1e8/0x270 [ +0.000000] softirqs last enabled at (6880): [] neigh_resolve_output+0x1db/0x270 [ +0.000000] softirqs last disabled at (6884): [] __dev_queue_xmit+0x73/0x1140 [ +0.000000] other info that might help us debug this: [ +0.000000] Possible unsafe locking scenario: [ +0.000000] CPU0 [ +0.000000] ---- [ +0.000000] lock(&sch->root_lock_key); [ +0.000000] [ +0.000000] lock(&sch->root_lock_key); [ +0.000000] *** DEADLOCK *** [ +0.000000] 4 locks held by ping/156: [ +0.000000] #0: ffff897842332e08 (sk_lock-AF_INET){+.+.}-{0:0}, at: raw_sendmsg+0x41e/0xf40 [ +0.000000] #1: ffffffffa816f880 (rcu_read_lock){....}-{1:3}, at: ip_output+0x2c/0x190 [ +0.000000] #2: ffffffffa816f880 (rcu_read_lock){....}-{1:3}, at: ip_finish_output2+0xad/0x950 [ +0.000000] #3: ffffffffa816f840 (rcu_read_lock_bh){....}-{1:3}, at: __dev_queue_xmit+0x73/0x1140 I am able to reproduce it consistently when running the following: tc qdisc add dev lo handle 1: root dualpi2 ping -f 127.0.0.1 To fix it, make the timer run in softirq. Fixes: 320d031ad6e4 ("sched: Struct definition and parsing of dualpi2 qdisc") Reviewed-by: Jamal Hadi Salim Signed-off-by: Victor Nogueira Link: https://patch.msgid.link/20250815135317.664993-1-victor@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/sch_dualpi2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c index 845375ebd4eaad..4b975feb52b1f3 100644 --- a/net/sched/sch_dualpi2.c +++ b/net/sched/sch_dualpi2.c @@ -927,7 +927,8 @@ static int dualpi2_init(struct Qdisc *sch, struct nlattr *opt, q->sch = sch; dualpi2_reset_default(sch); - hrtimer_setup(&q->pi2_timer, dualpi2_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); + hrtimer_setup(&q->pi2_timer, dualpi2_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_ABS_PINNED_SOFT); if (opt && nla_len(opt)) { err = dualpi2_change(sch, opt, extack); @@ -937,7 +938,7 @@ static int dualpi2_init(struct Qdisc *sch, struct nlattr *opt, } hrtimer_start(&q->pi2_timer, next_pi2_timeout(q), - HRTIMER_MODE_ABS_PINNED); + HRTIMER_MODE_ABS_PINNED_SOFT); return 0; } From bc1a59cff9f797bfbf8f3104507584d89e9ecf2e Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Mon, 18 Aug 2025 10:10:29 +0200 Subject: [PATCH 0392/1292] phy: mscc: Fix timestamping for vsc8584 There was a problem when we received frames and the frames were timestamped. The driver is configured to store the nanosecond part of the timestmap in the ptp reserved bits and it would take the second part by reading the LTC. The problem is that when reading the LTC we are in atomic context and to read the second part will go over mdio bus which might sleep, so we get an error. The fix consists in actually put all the frames in a queue and start the aux work and in that work to read the LTC and then calculate the full received time. Fixes: 7d272e63e0979d ("net: phy: mscc: timestamping and PHC support") Signed-off-by: Horatiu Vultur Reviewed-by: Vadim Fedorenko Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20250818081029.1300780-1-horatiu.vultur@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc/mscc.h | 12 ++++++++ drivers/net/phy/mscc/mscc_main.c | 12 ++++++++ drivers/net/phy/mscc/mscc_ptp.c | 49 ++++++++++++++++++++++++-------- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h index 6a3d8a754eb8de..58c6d47fbe046d 100644 --- a/drivers/net/phy/mscc/mscc.h +++ b/drivers/net/phy/mscc/mscc.h @@ -362,6 +362,13 @@ struct vsc85xx_hw_stat { u16 mask; }; +struct vsc8531_skb_cb { + u32 ns; +}; + +#define VSC8531_SKB_CB(skb) \ + ((struct vsc8531_skb_cb *)((skb)->cb)) + struct vsc8531_private { int rate_magic; u16 supp_led_modes; @@ -410,6 +417,11 @@ struct vsc8531_private { */ struct mutex ts_lock; struct mutex phc_lock; + + /* list of skbs that were received and need timestamp information but it + * didn't received it yet + */ + struct sk_buff_head rx_skbs_list; }; /* Shared structure between the PHYs of the same package. diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index 7ed6522fb0ef74..f1c9ce351ab42c 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2335,6 +2335,13 @@ static int vsc85xx_probe(struct phy_device *phydev) return vsc85xx_dt_led_modes_get(phydev, default_mode); } +static void vsc85xx_remove(struct phy_device *phydev) +{ + struct vsc8531_private *priv = phydev->priv; + + skb_queue_purge(&priv->rx_skbs_list); +} + /* Microsemi VSC85xx PHYs */ static struct phy_driver vsc85xx_driver[] = { { @@ -2589,6 +2596,7 @@ static struct phy_driver vsc85xx_driver[] = { .config_intr = &vsc85xx_config_intr, .suspend = &genphy_suspend, .resume = &genphy_resume, + .remove = &vsc85xx_remove, .probe = &vsc8574_probe, .set_wol = &vsc85xx_wol_set, .get_wol = &vsc85xx_wol_get, @@ -2614,6 +2622,7 @@ static struct phy_driver vsc85xx_driver[] = { .config_intr = &vsc85xx_config_intr, .suspend = &genphy_suspend, .resume = &genphy_resume, + .remove = &vsc85xx_remove, .probe = &vsc8574_probe, .set_wol = &vsc85xx_wol_set, .get_wol = &vsc85xx_wol_get, @@ -2639,6 +2648,7 @@ static struct phy_driver vsc85xx_driver[] = { .config_intr = &vsc85xx_config_intr, .suspend = &genphy_suspend, .resume = &genphy_resume, + .remove = &vsc85xx_remove, .probe = &vsc8584_probe, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, @@ -2662,6 +2672,7 @@ static struct phy_driver vsc85xx_driver[] = { .config_intr = &vsc85xx_config_intr, .suspend = &genphy_suspend, .resume = &genphy_resume, + .remove = &vsc85xx_remove, .probe = &vsc8584_probe, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, @@ -2685,6 +2696,7 @@ static struct phy_driver vsc85xx_driver[] = { .config_intr = &vsc85xx_config_intr, .suspend = &genphy_suspend, .resume = &genphy_resume, + .remove = &vsc85xx_remove, .probe = &vsc8584_probe, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c index 275706de5847cd..de6c7312e8f290 100644 --- a/drivers/net/phy/mscc/mscc_ptp.c +++ b/drivers/net/phy/mscc/mscc_ptp.c @@ -1194,9 +1194,7 @@ static bool vsc85xx_rxtstamp(struct mii_timestamper *mii_ts, { struct vsc8531_private *vsc8531 = container_of(mii_ts, struct vsc8531_private, mii_ts); - struct skb_shared_hwtstamps *shhwtstamps = NULL; struct vsc85xx_ptphdr *ptphdr; - struct timespec64 ts; unsigned long ns; if (!vsc8531->ptp->configured) @@ -1206,27 +1204,52 @@ static bool vsc85xx_rxtstamp(struct mii_timestamper *mii_ts, type == PTP_CLASS_NONE) return false; - vsc85xx_gettime(&vsc8531->ptp->caps, &ts); - ptphdr = get_ptp_header_rx(skb, vsc8531->ptp->rx_filter); if (!ptphdr) return false; - shhwtstamps = skb_hwtstamps(skb); - memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); - ns = ntohl(ptphdr->rsrvd2); - /* nsec is in reserved field */ - if (ts.tv_nsec < ns) - ts.tv_sec--; + VSC8531_SKB_CB(skb)->ns = ns; + skb_queue_tail(&vsc8531->rx_skbs_list, skb); - shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ns); - netif_rx(skb); + ptp_schedule_worker(vsc8531->ptp->ptp_clock, 0); return true; } +static long vsc85xx_do_aux_work(struct ptp_clock_info *info) +{ + struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps); + struct skb_shared_hwtstamps *shhwtstamps = NULL; + struct phy_device *phydev = ptp->phydev; + struct vsc8531_private *priv = phydev->priv; + struct sk_buff_head received; + struct sk_buff *rx_skb; + struct timespec64 ts; + unsigned long flags; + + __skb_queue_head_init(&received); + spin_lock_irqsave(&priv->rx_skbs_list.lock, flags); + skb_queue_splice_tail_init(&priv->rx_skbs_list, &received); + spin_unlock_irqrestore(&priv->rx_skbs_list.lock, flags); + + vsc85xx_gettime(info, &ts); + while ((rx_skb = __skb_dequeue(&received)) != NULL) { + shhwtstamps = skb_hwtstamps(rx_skb); + memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); + + if (ts.tv_nsec < VSC8531_SKB_CB(rx_skb)->ns) + ts.tv_sec--; + + shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, + VSC8531_SKB_CB(rx_skb)->ns); + netif_rx(rx_skb); + } + + return -1; +} + static const struct ptp_clock_info vsc85xx_clk_caps = { .owner = THIS_MODULE, .name = "VSC85xx timer", @@ -1240,6 +1263,7 @@ static const struct ptp_clock_info vsc85xx_clk_caps = { .adjfine = &vsc85xx_adjfine, .gettime64 = &vsc85xx_gettime, .settime64 = &vsc85xx_settime, + .do_aux_work = &vsc85xx_do_aux_work, }; static struct vsc8531_private *vsc8584_base_priv(struct phy_device *phydev) @@ -1567,6 +1591,7 @@ int vsc8584_ptp_probe(struct phy_device *phydev) mutex_init(&vsc8531->phc_lock); mutex_init(&vsc8531->ts_lock); + skb_queue_head_init(&vsc8531->rx_skbs_list); /* Retrieve the shared load/save GPIO. Request it as non exclusive as * the same GPIO can be requested by all the PHYs of the same package. From 24ef2f53c07f273bad99173e27ee88d44d135b1c Mon Sep 17 00:00:00 2001 From: Yuichiro Tsuji Date: Mon, 18 Aug 2025 17:45:07 +0900 Subject: [PATCH 0393/1292] net: usb: asix_devices: Fix PHY address mask in MDIO bus initialization Syzbot reported shift-out-of-bounds exception on MDIO bus initialization. The PHY address should be masked to 5 bits (0-31). Without this mask, invalid PHY addresses could be used, potentially causing issues with MDIO bus operations. Fix this by masking the PHY address with 0x1f (31 decimal) to ensure it stays within the valid range. Fixes: 4faff70959d5 ("net: usb: asix_devices: add phy_mask for ax88772 mdio bus") Reported-by: syzbot+20537064367a0f98d597@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=20537064367a0f98d597 Tested-by: syzbot+20537064367a0f98d597@syzkaller.appspotmail.com Signed-off-by: Yuichiro Tsuji Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250818084541.1958-1-yuichtsu@amazon.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/asix_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index d9f5942ccc447b..792ddda1ad493d 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -676,7 +676,7 @@ static int ax88772_init_mdio(struct usbnet *dev) priv->mdio->read = &asix_mdio_bus_read; priv->mdio->write = &asix_mdio_bus_write; priv->mdio->name = "Asix MDIO Bus"; - priv->mdio->phy_mask = ~(BIT(priv->phy_addr) | BIT(AX_EMBD_PHY_ADDR)); + priv->mdio->phy_mask = ~(BIT(priv->phy_addr & 0x1f) | BIT(AX_EMBD_PHY_ADDR)); /* mii bus name is usb-- */ snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d", dev->udev->bus->busnum, dev->udev->devnum); From 75a9a46d67f46d608205888f9b34e315c1786345 Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Mon, 18 Aug 2025 14:12:45 -0700 Subject: [PATCH 0394/1292] gve: prevent ethtool ops after shutdown A crash can occur if an ethtool operation is invoked after shutdown() is called. shutdown() is invoked during system shutdown to stop DMA operations without performing expensive deallocations. It is discouraged to unregister the netdev in this path, so the device may still be visible to userspace and kernel helpers. In gve, shutdown() tears down most internal data structures. If an ethtool operation is dispatched after shutdown(), it will dereference freed or NULL pointers, leading to a kernel panic. While graceful shutdown normally quiesces userspace before invoking the reboot syscall, forced shutdowns (as observed on GCP VMs) can still trigger this path. Fix by calling netif_device_detach() in shutdown(). This marks the device as detached so the ethtool ioctl handler will skip dispatching operations to the driver. Fixes: 974365e51861 ("gve: Implement suspend/resume/shutdown") Signed-off-by: Jordan Rhee Signed-off-by: Jeroen de Borst Link: https://patch.msgid.link/20250818211245.1156919-1-jeroendb@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 1f411d7c4373a9..1be1b1ef31ee30 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -2870,6 +2870,8 @@ static void gve_shutdown(struct pci_dev *pdev) struct gve_priv *priv = netdev_priv(netdev); bool was_up = netif_running(priv->dev); + netif_device_detach(netdev); + rtnl_lock(); netdev_lock(netdev); if (was_up && gve_close(priv->dev)) { From 6d6714bf0c4e8eb2274081b4b023dfa01581c123 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Fri, 15 Aug 2025 10:48:03 +0000 Subject: [PATCH 0395/1292] net: stmmac: thead: Enable TX clock before MAC initialization The clk_tx_i clock must be supplied to the MAC for successful initialization. On TH1520 SoC, the clock is provided by an internal divider configured through GMAC_PLLCLK_DIV register when using RGMII interface. However, currently we don't setup the divider before initialization of the MAC, resulting in DMA reset failures if the bootloader/firmware doesn't enable the divider, [ 7.839601] thead-dwmac ffe7060000.ethernet eth0: Register MEM_TYPE_PAGE_POOL RxQ-0 [ 7.938338] thead-dwmac ffe7060000.ethernet eth0: PHY [stmmac-0:02] driver [RTL8211F Gigabit Ethernet] (irq=POLL) [ 8.160746] thead-dwmac ffe7060000.ethernet eth0: Failed to reset the dma [ 8.170118] thead-dwmac ffe7060000.ethernet eth0: stmmac_hw_setup: DMA engine initialization failed [ 8.179384] thead-dwmac ffe7060000.ethernet eth0: __stmmac_open: Hw setup failed Let's simply write GMAC_PLLCLK_DIV_EN to GMAC_PLLCLK_DIV to enable the divider before MAC initialization. Note that for reconfiguring the divisor, the divider must be disabled first and re-enabled later to make sure the new divisor take effect. The exact clock rate doesn't affect MAC's initialization according to my test. It's set to the speed required by RGMII when the linkspeed is 1Gbps and could be reclocked later after link is up if necessary. Fixes: 33a1a01e3afa ("net: stmmac: Add glue layer for T-HEAD TH1520 SoC") Signed-off-by: Yao Zi Reviewed-by: Drew Fustini Link: https://patch.msgid.link/20250815104803.55294-1-ziyao@disroot.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c index f2946bea0bc268..6c6c49e4b66fae 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c @@ -152,7 +152,7 @@ static int thead_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) { struct thead_dwmac *dwmac = plat->bsp_priv; - u32 reg; + u32 reg, div; switch (plat->mac_interface) { case PHY_INTERFACE_MODE_MII: @@ -164,6 +164,13 @@ static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: /* use pll */ + div = clk_get_rate(plat->stmmac_clk) / rgmii_clock(SPEED_1000); + reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) | + FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div); + + writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV); + writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV); + writel(GMAC_GTXCLK_SEL_PLL, dwmac->apb_base + GMAC_GTXCLK_SEL); reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN | GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN; From d9cef55ed49117bd63695446fb84b4b91815c0b4 Mon Sep 17 00:00:00 2001 From: "D. Wythe" Date: Mon, 18 Aug 2025 13:46:18 +0800 Subject: [PATCH 0396/1292] net/smc: fix UAF on smcsk after smc_listen_out() BPF CI testing report a UAF issue: [ 16.446633] BUG: kernel NULL pointer dereference, address: 000000000000003 0 [ 16.447134] #PF: supervisor read access in kernel mod e [ 16.447516] #PF: error_code(0x0000) - not-present pag e [ 16.447878] PGD 0 P4D 0 [ 16.448063] Oops: Oops: 0000 [#1] PREEMPT SMP NOPT I [ 16.448409] CPU: 0 UID: 0 PID: 9 Comm: kworker/0:1 Tainted: G OE 6.13.0-rc3-g89e8a75fda73-dirty #4 2 [ 16.449124] Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODUL E [ 16.449502] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/201 4 [ 16.450201] Workqueue: smc_hs_wq smc_listen_wor k [ 16.450531] RIP: 0010:smc_listen_work+0xc02/0x159 0 [ 16.452158] RSP: 0018:ffffb5ab40053d98 EFLAGS: 0001024 6 [ 16.452526] RAX: 0000000000000001 RBX: 0000000000000002 RCX: 000000000000030 0 [ 16.452994] RDX: 0000000000000280 RSI: 00003513840053f0 RDI: 000000000000000 0 [ 16.453492] RBP: ffffa097808e3800 R08: ffffa09782dba1e0 R09: 000000000000000 5 [ 16.453987] R10: 0000000000000000 R11: 0000000000000000 R12: ffffa0978274640 0 [ 16.454497] R13: 0000000000000000 R14: 0000000000000000 R15: ffffa09782d4092 0 [ 16.454996] FS: 0000000000000000(0000) GS:ffffa097bbc00000(0000) knlGS:000000000000000 0 [ 16.455557] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003 3 [ 16.455961] CR2: 0000000000000030 CR3: 0000000102788004 CR4: 0000000000770ef 0 [ 16.456459] PKRU: 5555555 4 [ 16.456654] Call Trace : [ 16.456832] [ 16.456989] ? __die+0x23/0x7 0 [ 16.457215] ? page_fault_oops+0x180/0x4c 0 [ 16.457508] ? __lock_acquire+0x3e6/0x249 0 [ 16.457801] ? exc_page_fault+0x68/0x20 0 [ 16.458080] ? asm_exc_page_fault+0x26/0x3 0 [ 16.458389] ? smc_listen_work+0xc02/0x159 0 [ 16.458689] ? smc_listen_work+0xc02/0x159 0 [ 16.458987] ? lock_is_held_type+0x8f/0x10 0 [ 16.459284] process_one_work+0x1ea/0x6d 0 [ 16.459570] worker_thread+0x1c3/0x38 0 [ 16.459839] ? __pfx_worker_thread+0x10/0x1 0 [ 16.460144] kthread+0xe0/0x11 0 [ 16.460372] ? __pfx_kthread+0x10/0x1 0 [ 16.460640] ret_from_fork+0x31/0x5 0 [ 16.460896] ? __pfx_kthread+0x10/0x1 0 [ 16.461166] ret_from_fork_asm+0x1a/0x3 0 [ 16.461453] [ 16.461616] Modules linked in: bpf_testmod(OE) [last unloaded: bpf_testmod(OE) ] [ 16.462134] CR2: 000000000000003 0 [ 16.462380] ---[ end trace 0000000000000000 ]--- [ 16.462710] RIP: 0010:smc_listen_work+0xc02/0x1590 The direct cause of this issue is that after smc_listen_out_connected(), newclcsock->sk may be NULL since it will releases the smcsk. Therefore, if the application closes the socket immediately after accept, newclcsock->sk can be NULL. A possible execution order could be as follows: smc_listen_work | userspace ----------------------------------------------------------------- lock_sock(sk) | smc_listen_out_connected() | | \- smc_listen_out | | | \- release_sock | | |- sk->sk_data_ready() | | fd = accept(); | close(fd); | \- socket->sk = NULL; /* newclcsock->sk is NULL now */ SMC_STAT_SERV_SUCC_INC(sock_net(newclcsock->sk)) Since smc_listen_out_connected() will not fail, simply swapping the order of the code can easily fix this issue. Fixes: 3b2dec2603d5 ("net/smc: restructure client and server code in af_smc") Signed-off-by: D. Wythe Reviewed-by: Guangguan Wang Reviewed-by: Alexandra Winter Reviewed-by: Dust Li Link: https://patch.msgid.link/20250818054618.41615-1-alibuda@linux.alibaba.com Signed-off-by: Jakub Kicinski --- net/smc/af_smc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 9311c38f7abe54..e0e48f24cd6174 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -2568,8 +2568,9 @@ static void smc_listen_work(struct work_struct *work) goto out_decl; } - smc_listen_out_connected(new_smc); SMC_STAT_SERV_SUCC_INC(sock_net(newclcsock->sk), ini); + /* smc_listen_out() will release smcsk */ + smc_listen_out_connected(new_smc); goto out_free; out_unlock: From 2462c1b9217246a889ec318b3894d84e4dd709c6 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Sun, 17 Aug 2025 23:23:17 +0300 Subject: [PATCH 0397/1292] net/mlx5: HWS, fix bad parameter in CQ creation 'cqe_sz' valid value should be 0 for 64-byte CQE. Fixes: 2ca62599aa0b ("net/mlx5: HWS, added send engine and context handling") Signed-off-by: Yevgeny Kliteynik Reviewed-by: Vlad Dogaru Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250817202323.308604-2-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c index c4b22be19a9b10..b0595c9b09e421 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c @@ -964,7 +964,6 @@ static int hws_send_ring_open_cq(struct mlx5_core_dev *mdev, return -ENOMEM; MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index); - MLX5_SET(cqc, cqc_data, cqe_sz, queue->num_entries); MLX5_SET(cqc, cqc_data, log_cq_size, ilog2(queue->num_entries)); err = hws_send_ring_alloc_cq(mdev, numa_node, queue, cqc_data, cq); From 615b690612b7785ab8632f6a5a941550622e4e36 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Sun, 17 Aug 2025 23:23:18 +0300 Subject: [PATCH 0398/1292] net/mlx5: HWS, fix simple rules rehash error flow Moving rules from matcher to matcher should not fail. However, if it does fail due to various reasons, the error flow should allow the kernel to continue functioning (albeit with broken steering rules) instead of going into series of soft lock-ups or some other problematic behaviour. This patch fixes the error flow for moving simple rules: - If new rule creation fails before it was even enqeued, do not poll for completion - If TIMEOUT happened while moving the rule, no point trying to poll for completions for other rules. Something is broken, completion won't come, just abort the rehash sequence. - If some other completion with error received, don't give up. Continue handling rest of the rules to minimize the damage. - Make sure that the first error code that was received will be actually returned to the caller instead of replacing it with the generic error code. All the aforementioned issues stem from the same bad error flow, so no point fixing them one by one and leaving partially broken code - fixing them in one patch. Fixes: ef94799a8741 ("net/mlx5: HWS, rework rehash loop") Signed-off-by: Yevgeny Kliteynik Reviewed-by: Vlad Dogaru Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250817202323.308604-3-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../mellanox/mlx5/core/steering/hws/bwc.c | 61 +++++++++++++------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c index 92de4b761a8340..0219a49b23264d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c @@ -74,9 +74,9 @@ static void hws_bwc_matcher_init_attr(struct mlx5hws_bwc_matcher *bwc_matcher, static int hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) { - bool move_error = false, poll_error = false, drain_error = false; struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; struct mlx5hws_matcher *matcher = bwc_matcher->matcher; + int drain_error = 0, move_error = 0, poll_error = 0; u16 bwc_queues = mlx5hws_bwc_queues(ctx); struct mlx5hws_rule_attr rule_attr; struct mlx5hws_bwc_rule *bwc_rule; @@ -99,11 +99,15 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) ret = mlx5hws_matcher_resize_rule_move(matcher, bwc_rule->rule, &rule_attr); - if (unlikely(ret && !move_error)) { - mlx5hws_err(ctx, - "Moving BWC rule: move failed (%d), attempting to move rest of the rules\n", - ret); - move_error = true; + if (unlikely(ret)) { + if (!move_error) { + mlx5hws_err(ctx, + "Moving BWC rule: move failed (%d), attempting to move rest of the rules\n", + ret); + move_error = ret; + } + /* Rule wasn't queued, no need to poll */ + continue; } pending_rules++; @@ -111,11 +115,19 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) rule_attr.queue_id, &pending_rules, false); - if (unlikely(ret && !poll_error)) { - mlx5hws_err(ctx, - "Moving BWC rule: poll failed (%d), attempting to move rest of the rules\n", - ret); - poll_error = true; + if (unlikely(ret)) { + if (ret == -ETIMEDOUT) { + mlx5hws_err(ctx, + "Moving BWC rule: timeout polling for completions (%d), aborting rehash\n", + ret); + return ret; + } + if (!poll_error) { + mlx5hws_err(ctx, + "Moving BWC rule: polling for completions failed (%d), attempting to move rest of the rules\n", + ret); + poll_error = ret; + } } } @@ -126,17 +138,30 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) rule_attr.queue_id, &pending_rules, true); - if (unlikely(ret && !drain_error)) { - mlx5hws_err(ctx, - "Moving BWC rule: drain failed (%d), attempting to move rest of the rules\n", - ret); - drain_error = true; + if (unlikely(ret)) { + if (ret == -ETIMEDOUT) { + mlx5hws_err(ctx, + "Moving bwc rule: timeout draining completions (%d), aborting rehash\n", + ret); + return ret; + } + if (!drain_error) { + mlx5hws_err(ctx, + "Moving bwc rule: drain failed (%d), attempting to move rest of the rules\n", + ret); + drain_error = ret; + } } } } - if (move_error || poll_error || drain_error) - ret = -EINVAL; + /* Return the first error that happened */ + if (unlikely(move_error)) + return move_error; + if (unlikely(poll_error)) + return poll_error; + if (unlikely(drain_error)) + return drain_error; return ret; } From 4a842b1bf18a32ee0c25dd6dd98728b786a76fe4 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Sun, 17 Aug 2025 23:23:19 +0300 Subject: [PATCH 0399/1292] net/mlx5: HWS, fix complex rules rehash error flow Moving rules from matcher to matcher should not fail. However, if it does fail due to various reasons, the error flow should allow the kernel to continue functioning (albeit with broken steering rules) instead of going into series of soft lock-ups or some other problematic behaviour. Similar to the simple rules, complex rules rehash logic suffers from the same problems. This patch fixes the error flow for moving complex rules: - If new rule creation fails before it was even enqeued, do not poll for completion - If TIMEOUT happened while moving the rule, no point trying to poll for completions for other rules. Something is broken, completion won't come, just abort the rehash sequence. - If some other completion with error received, don't give up. Continue handling rest of the rules to minimize the damage. - Make sure that the first error code that was received will be actually returned to the caller instead of replacing it with the generic error code. All the aforementioned issues stem from the same bad error flow, so no point fixing them one by one and leaving partially broken code - fixing them in one patch. Fixes: 17e0accac577 ("net/mlx5: HWS, support complex matchers") Signed-off-by: Yevgeny Kliteynik Reviewed-by: Vlad Dogaru Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250817202323.308604-4-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../mlx5/core/steering/hws/bwc_complex.c | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c index ca7501c5746886..14e79579c719c2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c @@ -1328,11 +1328,11 @@ mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher) { struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; struct mlx5hws_matcher *matcher = bwc_matcher->matcher; - bool move_error = false, poll_error = false; u16 bwc_queues = mlx5hws_bwc_queues(ctx); struct mlx5hws_bwc_rule *tmp_bwc_rule; struct mlx5hws_rule_attr rule_attr; struct mlx5hws_table *isolated_tbl; + int move_error = 0, poll_error = 0; struct mlx5hws_rule *tmp_rule; struct list_head *rules_list; u32 expected_completions = 1; @@ -1391,11 +1391,15 @@ mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher) ret = mlx5hws_matcher_resize_rule_move(matcher, tmp_rule, &rule_attr); - if (unlikely(ret && !move_error)) { - mlx5hws_err(ctx, - "Moving complex BWC rule failed (%d), attempting to move rest of the rules\n", - ret); - move_error = true; + if (unlikely(ret)) { + if (!move_error) { + mlx5hws_err(ctx, + "Moving complex BWC rule: move failed (%d), attempting to move rest of the rules\n", + ret); + move_error = ret; + } + /* Rule wasn't queued, no need to poll */ + continue; } expected_completions = 1; @@ -1403,11 +1407,19 @@ mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher) rule_attr.queue_id, &expected_completions, true); - if (unlikely(ret && !poll_error)) { - mlx5hws_err(ctx, - "Moving complex BWC rule: poll failed (%d), attempting to move rest of the rules\n", - ret); - poll_error = true; + if (unlikely(ret)) { + if (ret == -ETIMEDOUT) { + mlx5hws_err(ctx, + "Moving complex BWC rule: timeout polling for completions (%d), aborting rehash\n", + ret); + return ret; + } + if (!poll_error) { + mlx5hws_err(ctx, + "Moving complex BWC rule: polling for completions failed (%d), attempting to move rest of the rules\n", + ret); + poll_error = ret; + } } /* Done moving the rule to the new matcher, @@ -1422,8 +1434,11 @@ mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher) } } - if (move_error || poll_error) - ret = -EINVAL; + /* Return the first error that happened */ + if (unlikely(move_error)) + return move_error; + if (unlikely(poll_error)) + return poll_error; return ret; } From 1a72298d27ce4d41b3fd405f6921e8711815767a Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Sun, 17 Aug 2025 23:23:20 +0300 Subject: [PATCH 0400/1292] net/mlx5: HWS, prevent rehash from filling up the queues While moving the rules during rehash, CQ is not drained. The flush and drain happens only when all the rules of a certain queue have been moved. This behaviour can lead to accumulating large quantity of rules that haven't got their completion yet, and eventually will fill up the queue and will cause the rehash to fail. Fix this problem by requiring drain once the number of outstanding completions reaches a certain threshold. Fixes: ef94799a8741 ("net/mlx5: HWS, rework rehash loop") Signed-off-by: Yevgeny Kliteynik Reviewed-by: Vlad Dogaru Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250817202323.308604-5-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c index 0219a49b23264d..2a59be11fe5511 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c @@ -84,6 +84,7 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) struct list_head *rules_list; u32 pending_rules; int i, ret = 0; + bool drain; mlx5hws_bwc_rule_fill_attr(bwc_matcher, 0, 0, &rule_attr); @@ -111,10 +112,12 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) } pending_rules++; + drain = pending_rules >= + hws_bwc_get_burst_th(ctx, rule_attr.queue_id); ret = mlx5hws_bwc_queue_poll(ctx, rule_attr.queue_id, &pending_rules, - false); + drain); if (unlikely(ret)) { if (ret == -ETIMEDOUT) { mlx5hws_err(ctx, From 7c60952f83584bc4950057cfed2cc3c87343b5db Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Sun, 17 Aug 2025 23:23:21 +0300 Subject: [PATCH 0401/1292] net/mlx5: HWS, don't rehash on every kind of insertion failure If rule creation failed due to a full queue, due to timeout in polling for completion, or due to matcher being in resize, don't try to initiate rehash sequence - rehash would have failed anyway. Fixes: 2111bb970c78 ("net/mlx5: HWS, added backward-compatible API handling") Signed-off-by: Yevgeny Kliteynik Reviewed-by: Vlad Dogaru Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250817202323.308604-6-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../mellanox/mlx5/core/steering/hws/bwc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c index 2a59be11fe5511..adeccc588e5d18 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c @@ -1063,6 +1063,21 @@ int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, return 0; /* rule inserted successfully */ } + /* Rule insertion could fail due to queue being full, timeout, or + * matcher in resize. In such cases, no point in trying to rehash. + */ + if (ret == -EBUSY || ret == -ETIMEDOUT || ret == -EAGAIN) { + mutex_unlock(queue_lock); + mlx5hws_err(ctx, + "BWC rule insertion failed - %s (%d)\n", + ret == -EBUSY ? "queue is full" : + ret == -ETIMEDOUT ? "timeout" : + ret == -EAGAIN ? "matcher in resize" : "N/A", + ret); + hws_bwc_rule_cnt_dec(bwc_rule); + return ret; + } + /* At this point the rule wasn't added. * It could be because there was collision, or some other problem. * Try rehash by size and insert rule again - last chance. From 8a51507320ebddaab32610199774f69cd7d53e78 Mon Sep 17 00:00:00 2001 From: Alex Vesker Date: Sun, 17 Aug 2025 23:23:22 +0300 Subject: [PATCH 0402/1292] net/mlx5: HWS, Fix table creation UID During table creation, caller passes a UID using ft_attr. The UID value was ignored, which leads to problems when the caller sets the UID to a non-zero value, such as SHARED_RESOURCE_UID (0xffff) - the internal FT objects will be created with UID=0. Fixes: 0869701cba3d ("net/mlx5: HWS, added FW commands handling") Signed-off-by: Alex Vesker Reviewed-by: Yevgeny Kliteynik Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250817202323.308604-7-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlx5/core/steering/hws/cmd.c | 1 + .../ethernet/mellanox/mlx5/core/steering/hws/cmd.h | 1 + .../mellanox/mlx5/core/steering/hws/fs_hws.c | 1 + .../mellanox/mlx5/core/steering/hws/matcher.c | 5 ++++- .../mellanox/mlx5/core/steering/hws/mlx5hws.h | 1 + .../mellanox/mlx5/core/steering/hws/table.c | 13 ++++++++++--- .../mellanox/mlx5/core/steering/hws/table.h | 3 ++- 7 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c index 9c83753e459243..0bdcab2e5cf3a6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c @@ -55,6 +55,7 @@ int mlx5hws_cmd_flow_table_create(struct mlx5_core_dev *mdev, MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE); MLX5_SET(create_flow_table_in, in, table_type, ft_attr->type); + MLX5_SET(create_flow_table_in, in, uid, ft_attr->uid); ft_ctx = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context); MLX5_SET(flow_table_context, ft_ctx, level, ft_attr->level); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h index fa6bff210266cb..122ccc671628de 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h @@ -36,6 +36,7 @@ struct mlx5hws_cmd_set_fte_attr { struct mlx5hws_cmd_ft_create_attr { u8 type; u8 level; + u16 uid; bool rtc_valid; bool decap_en; bool reformat_en; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c index 57592b92e24b41..131e74b2b77435 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c @@ -267,6 +267,7 @@ static int mlx5_cmd_hws_create_flow_table(struct mlx5_flow_root_namespace *ns, tbl_attr.type = MLX5HWS_TABLE_TYPE_FDB; tbl_attr.level = ft_attr->level; + tbl_attr.uid = ft_attr->uid; tbl = mlx5hws_table_create(ctx, &tbl_attr); if (!tbl) { mlx5_core_err(ns->dev, "Failed creating hws flow_table\n"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c index f3ea09caba2b68..32f87fdf32136e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c @@ -85,6 +85,7 @@ static int hws_matcher_create_end_ft_isolated(struct mlx5hws_matcher *matcher) ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, + 0, &matcher->end_ft_id); if (ret) { mlx5hws_err(tbl->ctx, "Isolated matcher: failed to create end flow table\n"); @@ -112,7 +113,9 @@ static int hws_matcher_create_end_ft(struct mlx5hws_matcher *matcher) if (mlx5hws_matcher_is_isolated(matcher)) ret = hws_matcher_create_end_ft_isolated(matcher); else - ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, + ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, + tbl, + 0, &matcher->end_ft_id); if (ret) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h index 59c14745ed0cb6..2498ceff2060fd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h @@ -75,6 +75,7 @@ struct mlx5hws_context_attr { struct mlx5hws_table_attr { enum mlx5hws_table_type type; u32 level; + u16 uid; }; enum mlx5hws_matcher_flow_src { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c index 568f691733f349..6113383ae47bbc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c @@ -9,6 +9,7 @@ u32 mlx5hws_table_get_id(struct mlx5hws_table *tbl) } static void hws_table_init_next_ft_attr(struct mlx5hws_table *tbl, + u16 uid, struct mlx5hws_cmd_ft_create_attr *ft_attr) { ft_attr->type = tbl->fw_ft_type; @@ -16,7 +17,9 @@ static void hws_table_init_next_ft_attr(struct mlx5hws_table *tbl, ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1; else ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1; + ft_attr->rtc_valid = true; + ft_attr->uid = uid; } static void hws_table_set_cap_attr(struct mlx5hws_table *tbl, @@ -119,12 +122,12 @@ static int hws_table_connect_to_default_miss_tbl(struct mlx5hws_table *tbl, u32 int mlx5hws_table_create_default_ft(struct mlx5_core_dev *mdev, struct mlx5hws_table *tbl, - u32 *ft_id) + u16 uid, u32 *ft_id) { struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; int ret; - hws_table_init_next_ft_attr(tbl, &ft_attr); + hws_table_init_next_ft_attr(tbl, uid, &ft_attr); hws_table_set_cap_attr(tbl, &ft_attr); ret = mlx5hws_cmd_flow_table_create(mdev, &ft_attr, ft_id); @@ -189,7 +192,10 @@ static int hws_table_init(struct mlx5hws_table *tbl) } mutex_lock(&ctx->ctrl_lock); - ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, &tbl->ft_id); + ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, + tbl, + tbl->uid, + &tbl->ft_id); if (ret) { mlx5hws_err(tbl->ctx, "Failed to create flow table object\n"); mutex_unlock(&ctx->ctrl_lock); @@ -239,6 +245,7 @@ struct mlx5hws_table *mlx5hws_table_create(struct mlx5hws_context *ctx, tbl->ctx = ctx; tbl->type = attr->type; tbl->level = attr->level; + tbl->uid = attr->uid; ret = hws_table_init(tbl); if (ret) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h index 0400cce0c317f7..1246f9bd84222f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h @@ -18,6 +18,7 @@ struct mlx5hws_table { enum mlx5hws_table_type type; u32 fw_ft_type; u32 level; + u16 uid; struct list_head matchers_list; struct list_head tbl_list_node; struct mlx5hws_default_miss default_miss; @@ -47,7 +48,7 @@ u32 mlx5hws_table_get_res_fw_ft_type(enum mlx5hws_table_type tbl_type, int mlx5hws_table_create_default_ft(struct mlx5_core_dev *mdev, struct mlx5hws_table *tbl, - u32 *ft_id); + u16 uid, u32 *ft_id); void mlx5hws_table_destroy_default_ft(struct mlx5hws_table *tbl, u32 ft_id); From d2d6f950cb43be6845a41cac5956cb2a10e657e5 Mon Sep 17 00:00:00 2001 From: Vlad Dogaru Date: Sun, 17 Aug 2025 23:23:23 +0300 Subject: [PATCH 0403/1292] net/mlx5: CT: Use the correct counter offset Specifying the counter action is not enough, as it is used by multiple counters that were allocated in a bulk. By omitting the offset, rules will be associated with a different counter from the same bulk. Subsequently, the CT subsystem checks the correct counter, assumes that no traffic has triggered the rule, and ages out the rule. The end result is intermittent offloading of long lived connections, as rules are aged out then promptly re-added. Fix this by specifying the correct offset along with the counter rule. Fixes: 34eea5b12a10 ("net/mlx5e: CT: Add initial support for Hardware Steering") Signed-off-by: Vlad Dogaru Reviewed-by: Yevgeny Kliteynik Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250817202323.308604-8-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_hmfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_hmfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_hmfs.c index a4263137fef5a0..01d522b0294707 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_hmfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_hmfs.c @@ -173,6 +173,8 @@ static void mlx5_ct_fs_hmfs_fill_rule_actions(struct mlx5_ct_fs_hmfs *fs_hmfs, memset(rule_actions, 0, NUM_CT_HMFS_RULES * sizeof(*rule_actions)); rule_actions[0].action = mlx5_fc_get_hws_action(fs_hmfs->ctx, attr->counter); + rule_actions[0].counter.offset = + attr->counter->id - attr->counter->bulk->base_id; /* Modify header is special, it may require extra arguments outside the action itself. */ if (mh_action->mh_data) { rule_actions[1].modify_header.offset = mh_action->mh_data->offset; From 1683fd1b2fa79864d3c7a951d9cea0a9ba1a1923 Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Mon, 18 Aug 2025 11:35:13 +0530 Subject: [PATCH 0404/1292] microchip: lan865x: fix missing netif_start_queue() call on device open This fixes an issue where the transmit queue is started implicitly only the very first time the device is registered. When the device is taken down and brought back up again (using `ip` or `ifconfig`), the transmit queue is not restarted, causing packet transmission to hang. Adding an explicit call to netif_start_queue() in lan865x_net_open() ensures the transmit queue is properly started every time the device is reopened. Fixes: 5cd2340cb6a3 ("microchip: lan865x: add driver support for Microchip's LAN865X MAC-PHY") Signed-off-by: Parthiban Veerasooran Link: https://patch.msgid.link/20250818060514.52795-2-parthiban.veerasooran@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan865x/lan865x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net/ethernet/microchip/lan865x/lan865x.c index dd436bdff0f86d..d03f5a8de58d18 100644 --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c @@ -311,6 +311,8 @@ static int lan865x_net_open(struct net_device *netdev) phy_start(netdev->phydev); + netif_start_queue(netdev); + return 0; } From 2cd58fec912acec273cb155911ab8f06ddbb131a Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Mon, 18 Aug 2025 11:35:14 +0530 Subject: [PATCH 0405/1292] microchip: lan865x: fix missing Timer Increment config for Rev.B0/B1 Fix missing configuration for LAN865x silicon revisions B0 and B1 as per Microchip Application Note AN1760 (Rev F, June 2024). The Timer Increment register was not being set, which is required for accurate timestamping. As per the application note, configure the MAC to set timestamping at the end of the Start of Frame Delimiter (SFD), and set the Timer Increment register to 40 ns (corresponding to a 25 MHz internal clock). Link: https://www.microchip.com/en-us/application-notes/an1760 Fixes: 5cd2340cb6a3 ("microchip: lan865x: add driver support for Microchip's LAN865X MAC-PHY") Signed-off-by: Parthiban Veerasooran Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20250818060514.52795-3-parthiban.veerasooran@microchip.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/microchip/lan865x/lan865x.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net/ethernet/microchip/lan865x/lan865x.c index d03f5a8de58d18..84c41f19356126 100644 --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c @@ -32,6 +32,10 @@ /* MAC Specific Addr 1 Top Reg */ #define LAN865X_REG_MAC_H_SADDR1 0x00010023 +/* MAC TSU Timer Increment Register */ +#define LAN865X_REG_MAC_TSU_TIMER_INCR 0x00010077 +#define MAC_TSU_TIMER_INCR_COUNT_NANOSECONDS 0x0028 + struct lan865x_priv { struct work_struct multicast_work; struct net_device *netdev; @@ -346,6 +350,21 @@ static int lan865x_probe(struct spi_device *spi) goto free_netdev; } + /* LAN865x Rev.B0/B1 configuration parameters from AN1760 + * As per the Configuration Application Note AN1760 published in the + * link, https://www.microchip.com/en-us/application-notes/an1760 + * Revision F (DS60001760G - June 2024), configure the MAC to set time + * stamping at the end of the Start of Frame Delimiter (SFD) and set the + * Timer Increment reg to 40 ns to be used as a 25 MHz internal clock. + */ + ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_TSU_TIMER_INCR, + MAC_TSU_TIMER_INCR_COUNT_NANOSECONDS); + if (ret) { + dev_err(&spi->dev, "Failed to config TSU Timer Incr reg: %d\n", + ret); + goto oa_tc6_exit; + } + /* As per the point s3 in the below errata, SPI receive Ethernet frame * transfer may halt when starting the next frame in the same data block * (chunk) as the end of a previous frame. The RFA field should be From 72907ea795e0bf261def10595d19ded441b90d9f Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Tue, 19 Aug 2025 13:21:42 +0200 Subject: [PATCH 0406/1292] cpufreq: mediatek-hw: don't use error path on NULL fdvfs The IS_ERR_OR_NULL check for priv->fdvfs is inappropriate, and should be an IS_ERR check instead, as a NULL value here would propagate it to PTR_ERR. In practice, there is no problem here, as devm_of_iomap cannot return NULL in any circumstance. However, it causes a Smatch static checker warning. Fix the warning by changing the check from IS_ERR_OR_NULL to IS_ERR. Fixes: 32e0d669f3ac ("cpufreq: mediatek-hw: Add support for MT8196") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-pm/aKQubSEXH1TXQpnR@stanley.mountain/ Signed-off-by: Nicolas Frattaroli Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq-hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index e4eadce6f937ce..fce5aa5ceea033 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -72,7 +72,7 @@ static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = { static int mtk_cpufreq_hw_mt8196_init(struct mtk_cpufreq_priv *priv) { priv->fdvfs = devm_of_iomap(priv->dev, priv->dev->of_node, 0, NULL); - if (IS_ERR_OR_NULL(priv->fdvfs)) + if (IS_ERR(priv->fdvfs)) return dev_err_probe(priv->dev, PTR_ERR(priv->fdvfs), "failed to get fdvfs iomem\n"); From e88ef677623eaf7a4c30b5fe905e7138838d13d2 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Fri, 15 Aug 2025 23:15:21 +0530 Subject: [PATCH 0407/1292] rust: opp: update ARef and AlwaysRefCounted imports from sync::aref Update call sites in `opp.rs` to import ARef and AlwaysRefCounted from sync::aref instead of types. This aligns with the ongoing effort to move ARef and AlwaysRefCounted to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Reviewed-by: Benno Lossin Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index 08126035d2c66f..29be7d14025e54 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -16,7 +16,8 @@ use crate::{ ffi::c_ulong, prelude::*, str::CString, - types::{ARef, AlwaysRefCounted, Opaque}, + sync::aref::{ARef, AlwaysRefCounted}, + types::Opaque, }; #[cfg(CONFIG_CPU_FREQ)] @@ -162,7 +163,7 @@ impl From for c_ulong { /// use kernel::device::Device; /// use kernel::error::Result; /// use kernel::opp::{Data, MicroVolt, Token}; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn create_opp(dev: &ARef, freq: Hertz, volt: MicroVolt, level: u32) -> Result { /// let data = Data::new(freq, volt, level, false); @@ -211,7 +212,7 @@ impl Drop for Token { /// use kernel::device::Device; /// use kernel::error::Result; /// use kernel::opp::{Data, MicroVolt, Token}; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn create_opp(dev: &ARef, freq: Hertz, volt: MicroVolt, level: u32) -> Result { /// let data = Data::new(freq, volt, level, false); @@ -262,7 +263,7 @@ impl Data { /// use kernel::clk::Hertz; /// use kernel::error::Result; /// use kernel::opp::{OPP, SearchType, Table}; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn find_opp(table: &Table, freq: Hertz) -> Result> { /// let opp = table.opp_from_freq(freq, Some(true), None, SearchType::Exact)?; @@ -335,7 +336,7 @@ impl Drop for ConfigToken { /// use kernel::error::Result; /// use kernel::opp::{Config, ConfigOps, ConfigToken}; /// use kernel::str::CString; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// use kernel::macros::vtable; /// /// #[derive(Default)] @@ -581,7 +582,7 @@ impl Config { /// use kernel::device::Device; /// use kernel::error::Result; /// use kernel::opp::Table; -/// use kernel::types::ARef; +/// use kernel::sync::aref::ARef; /// /// fn get_table(dev: &ARef, mask: &mut Cpumask, freq: Hertz) -> Result { /// let mut opp_table = Table::from_of_cpumask(dev, mask)?; From 3f4422e7c9436abf81a00270be7e4d6d3760ec0e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Aug 2025 07:19:01 +0200 Subject: [PATCH 0408/1292] ALSA: hda: tas2781: Fix wrong reference of tasdevice_priv During the conversion to unify the calibration data management, the reference to tasdevice_priv was wrongly set to h->hda_priv instead of h->priv. This resulted in memory corruption and crashes eventually. Unfortunately it's a void pointer, hence the compiler couldn't know that it's wrong. Fixes: 4fe238513407 ("ALSA: hda/tas2781: Move and unified the calibrated-data getting function for SPI and I2C into the tas2781_hda lib") Link: https://bugzilla.suse.com/show_bug.cgi?id=1248270 Cc: Link: https://patch.msgid.link/20250820051902.4523-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index b91fff3fde97fb..e34b17f0c9b9e2 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -305,7 +305,7 @@ static int tas2563_save_calibration(struct tas2781_hda *h) efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX]; unsigned long max_size = TAS2563_CAL_DATA_SIZE; unsigned char var8[TAS2563_CAL_VAR_NAME_MAX]; - struct tasdevice_priv *p = h->hda_priv; + struct tasdevice_priv *p = h->priv; struct calidata *cd = &p->cali_data; struct cali_reg *r = &cd->cali_reg_array; unsigned int offset = 0; From 02c1b0824eb1873b15676257cf1dc80070927e1e Mon Sep 17 00:00:00 2001 From: Andrew Donnellan Date: Wed, 6 Aug 2025 15:56:07 +1000 Subject: [PATCH 0409/1292] KVM: PPC: Fix misleading interrupts comment in kvmppc_prepare_to_enter() Until commit 6c85f52b10fd ("kvm/ppc: IRQ disabling cleanup"), kvmppc_prepare_to_enter() was called with interrupts already disabled by the caller, which was documented in the comment above the function. Post-cleanup, the function is now called with interrupts enabled, and disables interrupts itself. Fix the comment to reflect the current behaviour. Fixes: 6c85f52b10fd ("kvm/ppc: IRQ disabling cleanup") Signed-off-by: Andrew Donnellan Reviewed-by: Amit Machhiwal Reviewed-by: Gautam Menghani Reviewed-by: Shrikanth Hegde [Fixed the double colon in Reviewed-by line] Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250806055607.17081-1-ajd@linux.ibm.com --- arch/powerpc/kvm/powerpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 153587741864ce..2ba057171ebe0c 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -69,7 +69,7 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) /* * Common checks before entering the guest world. Call with interrupts - * disabled. + * enabled. * * returns: * From b018bb26c42049e05d3d65b057cc1250d17d9b0a Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 23 Jul 2025 08:28:42 +0200 Subject: [PATCH 0410/1292] powerpc: Use dev_fwnode() irq_domain_create_simple() takes fwnode as the first argument. It can be extracted from the struct device using dev_fwnode() helper instead of using of_node with of_fwnode_handle(). So use the dev_fwnode() helper. Signed-off-by: Jiri Slaby (SUSE) Acked-by: Christophe Leroy Link: https://lore.kernel.org/all/4bc0e1ca-a523-424a-8759-59e353317fba@kernel.org/ Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250723062842.1831271-1-jirislaby@kernel.org --- arch/powerpc/platforms/8xx/cpm1-ic.c | 3 +-- arch/powerpc/sysdev/fsl_msi.c | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/8xx/cpm1-ic.c b/arch/powerpc/platforms/8xx/cpm1-ic.c index a49d4a9ab3bc0f..3292071e4da326 100644 --- a/arch/powerpc/platforms/8xx/cpm1-ic.c +++ b/arch/powerpc/platforms/8xx/cpm1-ic.c @@ -110,8 +110,7 @@ static int cpm_pic_probe(struct platform_device *pdev) out_be32(&data->reg->cpic_cimr, 0); - data->host = irq_domain_create_linear(of_fwnode_handle(dev->of_node), - 64, &cpm_pic_host_ops, data); + data->host = irq_domain_create_linear(dev_fwnode(dev), 64, &cpm_pic_host_ops, data); if (!data->host) return -ENODEV; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 4fe8a7b1b288e0..2a007bfb038d01 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -412,9 +412,8 @@ static int fsl_of_msi_probe(struct platform_device *dev) } platform_set_drvdata(dev, msi); - msi->irqhost = irq_domain_create_linear(of_fwnode_handle(dev->dev.of_node), - NR_MSI_IRQS_MAX, &fsl_msi_host_ops, msi); - + msi->irqhost = irq_domain_create_linear(dev_fwnode(&dev->dev), NR_MSI_IRQS_MAX, + &fsl_msi_host_ops, msi); if (msi->irqhost == NULL) { dev_err(&dev->dev, "No memory for MSI irqhost\n"); err = -ENOMEM; From 8b5d86a63bc9510e094a15d7268c60bd4347b95c Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Fri, 1 Aug 2025 11:59:08 +0800 Subject: [PATCH 0411/1292] powerpc/64: Drop unnecessary 'rc' variable Simplify the code to enhance readability and maintain a consistent coding style. Signed-off-by: Xichao Zhao Acked-by: Gautam Menghani Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250801035908.370463-1-zhao.xichao@vivo.com --- arch/powerpc/kernel/setup_64.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 7284c8021eeb53..8fd7cbf3bd0480 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -141,10 +141,7 @@ void __init check_smt_enabled(void) smt_enabled_at_boot = 0; else { int smt; - int rc; - - rc = kstrtoint(smt_enabled_cmdline, 10, &smt); - if (!rc) + if (!kstrtoint(smt_enabled_cmdline, 10, &smt)) smt_enabled_at_boot = min(threads_per_core, smt); } From eb59d4c5948d93e940b5dde9d1bf3b33367fbcb8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 3 Jun 2025 01:32:24 +0900 Subject: [PATCH 0412/1292] powerpc: use always-y instead of extra-y in Makefiles The extra-y syntax is planned for deprecation because it is similar to always-y. When building the boot wrapper, always-y and extra-y are equivalent. Use always-y instead. In arch/powerpc/kernel/Makefile, I added ifdef KBUILD_BUILTIN to keep the current behavior: prom_init_check is skipped when building only modular objects. Signed-off-by: Masahiro Yamada Acked-by: Michael Ellerman Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250602163302.478765-1-masahiroy@kernel.org --- arch/powerpc/boot/Makefile | 6 +++--- arch/powerpc/kernel/Makefile | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index a7ab087d412c18..c47b78c1d3e7ef 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -243,13 +243,13 @@ $(obj)/wrapper.a: $(obj-wlib) FORCE hostprogs := addnote hack-coff mktree targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a) zImage.lds -extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ +always-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ $(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds dtstree := $(src)/dts wrapper := $(src)/wrapper -wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) \ +wrapperbits := $(always-y) $(addprefix $(obj)/,addnote hack-coff mktree) \ $(wrapper) FORCE ############# @@ -456,7 +456,7 @@ WRAPPER_DTSDIR := /usr/lib/kernel-wrapper/dts WRAPPER_BINDIR := /usr/sbin INSTALL := install -extra-installed := $(patsubst $(obj)/%, $(DESTDIR)$(WRAPPER_OBJDIR)/%, $(extra-y)) +extra-installed := $(patsubst $(obj)/%, $(DESTDIR)$(WRAPPER_OBJDIR)/%, $(always-y)) hostprogs-installed := $(patsubst %, $(DESTDIR)$(WRAPPER_BINDIR)/%, $(hostprogs)) wrapper-installed := $(DESTDIR)$(WRAPPER_BINDIR)/wrapper dts-installed := $(patsubst $(dtstree)/%, $(DESTDIR)$(WRAPPER_DTSDIR)/%, $(wildcard $(dtstree)/*.dts)) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index fb2b95267022cc..2f0a2e69c607bc 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -199,7 +199,9 @@ obj-$(CONFIG_ALTIVEC) += vector.o obj-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init.o obj64-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_entry_64.o -extra-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init_check +ifdef KBUILD_BUILTIN +always-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init_check +endif obj-$(CONFIG_PPC64) += $(obj64-y) obj-$(CONFIG_PPC32) += $(obj32-y) From 6a859f1a19d1f8756ffb097f5973dfebbca4811a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 7 Jun 2025 19:13:51 +0900 Subject: [PATCH 0413/1292] powerpc: unify two CONFIG_POWERPC64_CPU entries in the same choice block There are two CONFIG_POWERPC64_CPU entries in the "CPU selection" choice block. I guess the intent is to display a different prompt depending on CPU_LITTLE_ENDIAN: "Generic (POWER5 and PowerPC 970 and above)" for big endian, and "Generic (POWER8 and above)" for little endian. I stumbled on this tricky use case, and worked around it on Kconfig with commit 4d46b5b623e0 ("kconfig: fix infinite loop in sym_calc_choice()"). However, I doubt that supporting multiple entries with the same symbol in a choice block is worth the complexity - this is the only such case in the kernel tree. This commit merges the two entries. Once this cleanup is accepted in the powerpc subsystem, I will proceed to refactor the Kconfig parser. Signed-off-by: Masahiro Yamada Reviewed-by: Christophe Leroy Acked-by: Michael Ellerman Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250607102005.1965409-1-masahiroy@kernel.org --- arch/powerpc/platforms/Kconfig.cputype | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 613b383ed8b3f1..7b527d18aa5eeb 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -122,16 +122,11 @@ choice If unsure, select Generic. config POWERPC64_CPU - bool "Generic (POWER5 and PowerPC 970 and above)" - depends on PPC_BOOK3S_64 && !CPU_LITTLE_ENDIAN - select PPC_64S_HASH_MMU - -config POWERPC64_CPU - bool "Generic (POWER8 and above)" - depends on PPC_BOOK3S_64 && CPU_LITTLE_ENDIAN - select ARCH_HAS_FAST_MULTIPLIER + bool "Generic 64 bits powerpc" + depends on PPC_BOOK3S_64 + select ARCH_HAS_FAST_MULTIPLIER if CPU_LITTLE_ENDIAN select PPC_64S_HASH_MMU - select PPC_HAS_LBARX_LHARX + select PPC_HAS_LBARX_LHARX if CPU_LITTLE_ENDIAN config POWERPC_CPU bool "Generic 32 bits powerpc" From 88688a2c8ac6c8036d983ad8b34ce191c46a10aa Mon Sep 17 00:00:00 2001 From: Madhavan Srinivasan Date: Sun, 18 May 2025 10:11:04 +0530 Subject: [PATCH 0414/1292] powerpc/kvm: Fix ifdef to remove build warning When compiling for pseries or powernv defconfig with "make C=1", these warning were reported bu sparse tool in powerpc/kernel/kvm.c arch/powerpc/kernel/kvm.c:635:9: warning: switch with no cases arch/powerpc/kernel/kvm.c:646:9: warning: switch with no cases Currently #ifdef were added after the switch case which are specific for BOOKE and PPC_BOOK3S_32. These are not enabled in pseries/powernv defconfig. Fix it by moving the #ifdef before switch(){} Fixes: cbe487fac7fc0 ("KVM: PPC: Add mtsrin PV code") Tested-by: Venkat Rao Bagalkote Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250518044107.39928-1-maddy@linux.ibm.com --- arch/powerpc/kernel/kvm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index 5b3c093611baf1..7209d00a9c2576 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c @@ -632,19 +632,19 @@ static void __init kvm_check_ins(u32 *inst, u32 features) #endif } - switch (inst_no_rt & ~KVM_MASK_RB) { #ifdef CONFIG_PPC_BOOK3S_32 + switch (inst_no_rt & ~KVM_MASK_RB) { case KVM_INST_MTSRIN: if (features & KVM_MAGIC_FEAT_SR) { u32 inst_rb = _inst & KVM_MASK_RB; kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb); } break; -#endif } +#endif - switch (_inst) { #ifdef CONFIG_BOOKE + switch (_inst) { case KVM_INST_WRTEEI_0: kvm_patch_ins_wrteei_0(inst); break; @@ -652,8 +652,8 @@ static void __init kvm_check_ins(u32 *inst, u32 features) case KVM_INST_WRTEEI_1: kvm_patch_ins_wrtee(inst, 0, 1); break; -#endif } +#endif } extern u32 kvm_template_start[]; From d40ae9033418095642f65f4fd54dc5a7d292ee39 Mon Sep 17 00:00:00 2001 From: Madhavan Srinivasan Date: Sun, 18 May 2025 10:11:06 +0530 Subject: [PATCH 0415/1292] powerpc/prom_init: Fix shellcheck warnings Fix "Double quote to prevent globbing and word splitting." warning from shellcheck Tested-by: Venkat Rao Bagalkote Reviewed-by: Stephen Rothwell Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250518044107.39928-3-maddy@linux.ibm.com --- arch/powerpc/kernel/prom_init_check.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index 69623b9045d556..3090b97258ae02 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh @@ -15,8 +15,8 @@ has_renamed_memintrinsics() { - grep -q "^CONFIG_KASAN=y$" ${KCONFIG_CONFIG} && \ - ! grep -q "^CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y" ${KCONFIG_CONFIG} + grep -q "^CONFIG_KASAN=y$" "${KCONFIG_CONFIG}" && \ + ! grep -q "^CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y" "${KCONFIG_CONFIG}" } if has_renamed_memintrinsics @@ -42,15 +42,15 @@ check_section() { file=$1 section=$2 - size=$(objdump -h -j $section $file 2>/dev/null | awk "\$2 == \"$section\" {print \$3}") + size=$(objdump -h -j "$section" "$file" 2>/dev/null | awk "\$2 == \"$section\" {print \$3}") size=${size:-0} - if [ $size -ne 0 ]; then + if [ "$size" -ne 0 ]; then ERROR=1 echo "Error: Section $section not empty in prom_init.c" >&2 fi } -for UNDEF in $($NM -u $OBJ | awk '{print $2}') +for UNDEF in $($NM -u "$OBJ" | awk '{print $2}') do # On 64-bit nm gives us the function descriptors, which have # a leading . on the name, so strip it off here. @@ -87,8 +87,8 @@ do fi done -check_section $OBJ .data -check_section $OBJ .bss -check_section $OBJ .init.data +check_section "$OBJ" .data +check_section "$OBJ" .bss +check_section "$OBJ" .init.data exit $ERROR From 8763d2257f5231cfdfd8a53594647927dbf8bb06 Mon Sep 17 00:00:00 2001 From: Madhavan Srinivasan Date: Sun, 18 May 2025 10:11:07 +0530 Subject: [PATCH 0416/1292] powerpc/boot/install.sh: Fix shellcheck warnings Fix shellcheck warning such as "Double quote to prevent globbing and word splitting." and Use $(...) notation instead of legacy backticks `...`. Tested-by: Venkat Rao Bagalkote Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20250518044107.39928-4-maddy@linux.ibm.com --- arch/powerpc/boot/install.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/boot/install.sh b/arch/powerpc/boot/install.sh index 101fcb397a0fe6..c3df6c27ce754f 100755 --- a/arch/powerpc/boot/install.sh +++ b/arch/powerpc/boot/install.sh @@ -19,19 +19,19 @@ set -e # this should work for both the pSeries zImage and the iSeries vmlinux.sm -image_name=`basename $2` +image_name=$(basename "$2") echo "Warning: '${INSTALLKERNEL}' command not available... Copying" \ "directly to $4/$image_name-$1" >&2 -if [ -f $4/$image_name-$1 ]; then - mv $4/$image_name-$1 $4/$image_name-$1.old +if [ -f "$4"/"$image_name"-"$1" ]; then + mv "$4"/"$image_name"-"$1" "$4"/"$image_name"-"$1".old fi -if [ -f $4/System.map-$1 ]; then - mv $4/System.map-$1 $4/System-$1.old +if [ -f "$4"/System.map-"$1" ]; then + mv "$4"/System.map-"$1" "$4"/System-"$1".old fi -cat $2 > $4/$image_name-$1 -cp $3 $4/System.map-$1 +cat "$2" > "$4"/"$image_name"-"$1" +cp "$3" "$4"/System.map-"$1" From fa40cbe1c86b6626d548cf2eb555bee4eea7566c Mon Sep 17 00:00:00 2001 From: Paresh Bhagat Date: Wed, 20 Aug 2025 14:03:30 +0530 Subject: [PATCH 0417/1292] cpufreq: dt-platdev: Blacklist ti,am62d2 SoC Add ti,am62d2 SoC to the blacklist as the ti-cpufreq driver will handle creating the cpufreq-dt platform device after it completes and ensure it is not created twice. Signed-off-by: Paresh Bhagat Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq-dt-platdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 1a9d9d008002ca..cd1816a12bb996 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -189,6 +189,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "ti,omap3", }, { .compatible = "ti,am625", }, { .compatible = "ti,am62a7", }, + { .compatible = "ti,am62d2", }, { .compatible = "ti,am62p5", }, { .compatible = "qcom,ipq5332", }, From b5af45302ebc141662b2b60c713c9202e88c943c Mon Sep 17 00:00:00 2001 From: Paresh Bhagat Date: Wed, 20 Aug 2025 14:03:31 +0530 Subject: [PATCH 0418/1292] cpufreq: ti: Add support for AM62D2 Add support for TI K3 AM62D2 SoC to read speed and revision values from hardware and pass to OPP layer. AM62D shares the same configuations as AM62A so use existing am62a7_soc_data. Signed-off-by: Paresh Bhagat Signed-off-by: Viresh Kumar --- drivers/cpufreq/ti-cpufreq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 5a5147277cd0ab..9a912d30931539 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -310,6 +310,7 @@ static const struct soc_device_attribute k3_cpufreq_soc[] = { { .family = "AM62X", .revision = "SR1.0" }, { .family = "AM62AX", .revision = "SR1.0" }, { .family = "AM62PX", .revision = "SR1.0" }, + { .family = "AM62DX", .revision = "SR1.0" }, { /* sentinel */ } }; @@ -457,6 +458,7 @@ static const struct of_device_id ti_cpufreq_of_match[] __maybe_unused = { { .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, }, { .compatible = "ti,am625", .data = &am625_soc_data, }, { .compatible = "ti,am62a7", .data = &am62a7_soc_data, }, + { .compatible = "ti,am62d2", .data = &am62a7_soc_data, }, { .compatible = "ti,am62p5", .data = &am62p5_soc_data, }, /* legacy */ { .compatible = "ti,omap3430", .data = &omap34xx_soc_data, }, From 6a909ea83f226803ea0e718f6e88613df9234d58 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Wed, 13 Aug 2025 04:02:32 +0000 Subject: [PATCH 0419/1292] tracing: Limit access to parser->buffer when trace_get_user failed When the length of the string written to set_ftrace_filter exceeds FTRACE_BUFF_MAX, the following KASAN alarm will be triggered: BUG: KASAN: slab-out-of-bounds in strsep+0x18c/0x1b0 Read of size 1 at addr ffff0000d00bd5ba by task ash/165 CPU: 1 UID: 0 PID: 165 Comm: ash Not tainted 6.16.0-g6bcdbd62bd56-dirty Hardware name: linux,dummy-virt (DT) Call trace: show_stack+0x34/0x50 (C) dump_stack_lvl+0xa0/0x158 print_address_description.constprop.0+0x88/0x398 print_report+0xb0/0x280 kasan_report+0xa4/0xf0 __asan_report_load1_noabort+0x20/0x30 strsep+0x18c/0x1b0 ftrace_process_regex.isra.0+0x100/0x2d8 ftrace_regex_release+0x484/0x618 __fput+0x364/0xa58 ____fput+0x28/0x40 task_work_run+0x154/0x278 do_notify_resume+0x1f0/0x220 el0_svc+0xec/0xf0 el0t_64_sync_handler+0xa0/0xe8 el0t_64_sync+0x1ac/0x1b0 The reason is that trace_get_user will fail when processing a string longer than FTRACE_BUFF_MAX, but not set the end of parser->buffer to 0. Then an OOB access will be triggered in ftrace_regex_release-> ftrace_process_regex->strsep->strpbrk. We can solve this problem by limiting access to parser->buffer when trace_get_user failed. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/20250813040232.1344527-1-pulehui@huaweicloud.com Fixes: 8c9af478c06b ("ftrace: Handle commands when closing set_ftrace_filter file") Signed-off-by: Pu Lehui Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace.c | 18 ++++++++++++------ kernel/trace/trace.h | 8 +++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 4283ed4e8f592f..8d8935ed416d7d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1816,7 +1816,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf, ret = get_user(ch, ubuf++); if (ret) - return ret; + goto fail; read++; cnt--; @@ -1830,7 +1830,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf, while (cnt && isspace(ch)) { ret = get_user(ch, ubuf++); if (ret) - return ret; + goto fail; read++; cnt--; } @@ -1848,12 +1848,14 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf, while (cnt && !isspace(ch) && ch) { if (parser->idx < parser->size - 1) parser->buffer[parser->idx++] = ch; - else - return -EINVAL; + else { + ret = -EINVAL; + goto fail; + } ret = get_user(ch, ubuf++); if (ret) - return ret; + goto fail; read++; cnt--; } @@ -1868,11 +1870,15 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf, /* Make sure the parsed string always terminates with '\0'. */ parser->buffer[parser->idx] = 0; } else { - return -EINVAL; + ret = -EINVAL; + goto fail; } *ppos += read; return read; +fail: + trace_parser_fail(parser); + return ret; } /* TODO add a seq_buf_to_buffer() */ diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 1dbf1d3cf2f1d4..be6654899cae6b 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -1292,6 +1292,7 @@ bool ftrace_event_is_function(struct trace_event_call *call); */ struct trace_parser { bool cont; + bool fail; char *buffer; unsigned idx; unsigned size; @@ -1299,7 +1300,7 @@ struct trace_parser { static inline bool trace_parser_loaded(struct trace_parser *parser) { - return (parser->idx != 0); + return !parser->fail && parser->idx != 0; } static inline bool trace_parser_cont(struct trace_parser *parser) @@ -1313,6 +1314,11 @@ static inline void trace_parser_clear(struct trace_parser *parser) parser->idx = 0; } +static inline void trace_parser_fail(struct trace_parser *parser) +{ + parser->fail = true; +} + extern int trace_parser_get_init(struct trace_parser *parser, int size); extern void trace_parser_put(struct trace_parser *parser); extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf, From cd6e4faba96fe41d6b686e144b96dad5e6f2e771 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 13 Aug 2025 17:51:14 +0800 Subject: [PATCH 0420/1292] ring-buffer: Remove redundant semicolons Remove unnecessary semicolons. Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Link: https://lore.kernel.org/20250813095114.559530-1-liaoyuanhong@vivo.com Signed-off-by: Liao Yuanhong Signed-off-by: Steven Rostedt (Google) --- kernel/trace/ring_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index bb71a0dc9d69c5..43460949ad3fda 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -7666,7 +7666,7 @@ static __init int test_ringbuffer(void) rb_test_started = true; set_current_state(TASK_INTERRUPTIBLE); - /* Just run for 10 seconds */; + /* Just run for 10 seconds */ schedule_timeout(10 * HZ); kthread_stop(rb_hammer); From edede7a6dcd7435395cf757d053974aaab6ab1c2 Mon Sep 17 00:00:00 2001 From: Ye Weihua Date: Mon, 18 Aug 2025 07:33:32 +0000 Subject: [PATCH 0421/1292] trace/fgraph: Fix the warning caused by missing unregister notifier This warning was triggered during testing on v6.16: notifier callback ftrace_suspend_notifier_call already registered WARNING: CPU: 2 PID: 86 at kernel/notifier.c:23 notifier_chain_register+0x44/0xb0 ... Call Trace: blocking_notifier_chain_register+0x34/0x60 register_ftrace_graph+0x330/0x410 ftrace_profile_write+0x1e9/0x340 vfs_write+0xf8/0x420 ? filp_flush+0x8a/0xa0 ? filp_close+0x1f/0x30 ? do_dup2+0xaf/0x160 ksys_write+0x65/0xe0 do_syscall_64+0xa4/0x260 entry_SYSCALL_64_after_hwframe+0x77/0x7f When writing to the function_profile_enabled interface, the notifier was not unregistered after start_graph_tracing failed, causing a warning the next time function_profile_enabled was written. Fixed by adding unregister_pm_notifier in the exception path. Link: https://lore.kernel.org/20250818073332.3890629-1-yeweihua4@huawei.com Fixes: 4a2b8dda3f870 ("tracing/function-graph-tracer: fix a regression while suspend to disk") Acked-by: Masami Hiramatsu (Google) Signed-off-by: Ye Weihua Signed-off-by: Steven Rostedt (Google) --- kernel/trace/fgraph.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c index f4d200f0c610e3..2a42c1036ea87c 100644 --- a/kernel/trace/fgraph.c +++ b/kernel/trace/fgraph.c @@ -1397,6 +1397,7 @@ int register_ftrace_graph(struct fgraph_ops *gops) ftrace_graph_active--; gops->saved_func = NULL; fgraph_lru_release_index(i); + unregister_pm_notifier(&ftrace_suspend_notifier); } return ret; } From 4647c4deadcc17f40858be06bcf416369a8f1d57 Mon Sep 17 00:00:00 2001 From: Pratyush Brahma Date: Wed, 20 Aug 2025 06:29:34 +0530 Subject: [PATCH 0422/1292] mm: numa,memblock: Use SZ_1M macro to denote bytes to MB conversion Replace the manual bitwise conversion of bytes to MB with SZ_1M macro, a standard macro used within the mm subsystem, to improve readability. Signed-off-by: Pratyush Brahma Link: https://lore.kernel.org/r/20250820-numa-memblks-refac-v2-1-43bf1af02acd@oss.qualcomm.com Signed-off-by: Mike Rapoport (Microsoft) --- mm/memblock.c | 4 ++-- mm/numa_emulation.c | 4 ++-- mm/numa_memblks.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index 154f1d73b61f22..8a0ed3074af4b4 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -780,9 +780,9 @@ bool __init_memblock memblock_validate_numa_coverage(unsigned long threshold_byt } if ((nr_pages << PAGE_SHIFT) > threshold_bytes) { - mem_size_mb = memblock_phys_mem_size() >> 20; + mem_size_mb = memblock_phys_mem_size() / SZ_1M; pr_err("NUMA: no nodes coverage for %luMB of %luMB RAM\n", - (nr_pages << PAGE_SHIFT) >> 20, mem_size_mb); + (nr_pages << PAGE_SHIFT) / SZ_1M, mem_size_mb); return false; } diff --git a/mm/numa_emulation.c b/mm/numa_emulation.c index 9d55679d99ceea..703c8fa0504801 100644 --- a/mm/numa_emulation.c +++ b/mm/numa_emulation.c @@ -73,7 +73,7 @@ static int __init emu_setup_memblk(struct numa_meminfo *ei, } printk(KERN_INFO "Faking node %d at [mem %#018Lx-%#018Lx] (%LuMB)\n", - nid, eb->start, eb->end - 1, (eb->end - eb->start) >> 20); + nid, eb->start, eb->end - 1, (eb->end - eb->start) / SZ_1M); return 0; } @@ -264,7 +264,7 @@ static int __init split_nodes_size_interleave_uniform(struct numa_meminfo *ei, min_size = ALIGN(max(min_size, FAKE_NODE_MIN_SIZE), FAKE_NODE_MIN_SIZE); if (size < min_size) { pr_err("Fake node size %LuMB too small, increasing to %LuMB\n", - size >> 20, min_size >> 20); + size / SZ_1M, min_size / SZ_1M); size = min_size; } size = ALIGN_DOWN(size, FAKE_NODE_MIN_SIZE); diff --git a/mm/numa_memblks.c b/mm/numa_memblks.c index de626525a87c3e..5b009a9cd8b4c2 100644 --- a/mm/numa_memblks.c +++ b/mm/numa_memblks.c @@ -427,9 +427,9 @@ static int __init numa_register_meminfo(struct numa_meminfo *mi) unsigned long pfn_align = node_map_pfn_alignment(); if (pfn_align && pfn_align < PAGES_PER_SECTION) { - unsigned long node_align_mb = PFN_PHYS(pfn_align) >> 20; + unsigned long node_align_mb = PFN_PHYS(pfn_align) / SZ_1M; - unsigned long sect_align_mb = PFN_PHYS(PAGES_PER_SECTION) >> 20; + unsigned long sect_align_mb = PFN_PHYS(PAGES_PER_SECTION) / SZ_1M; pr_warn("Node alignment %luMB < min %luMB, rejecting NUMA config\n", node_align_mb, sect_align_mb); From efdaa61d73a1deb066ccc3b4d56257cc63ab5be9 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 15 Aug 2025 09:40:52 +0200 Subject: [PATCH 0423/1292] drivers/xen/xenbus: remove quirk for Xen 3.x The kernel is not supported to run as a Xen guest on Xen versions older than 4.0. Remove xen_strict_xenbus_quirk() which is testing the Xen version to be at least 4.0. Acked-by: Stefano Stabellini Reviewed-by: Jason Andryuk Signed-off-by: Juergen Gross Message-ID: <20250815074052.13792-1-jgross@suse.com> --- drivers/xen/xenbus/xenbus_xs.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 3c9da446b85dfa..528682bf0c7f24 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -718,26 +718,6 @@ int xs_watch_msg(struct xs_watch_event *event) return 0; } -/* - * Certain older XenBus toolstack cannot handle reading values that are - * not populated. Some Xen 3.4 installation are incapable of doing this - * so if we are running on anything older than 4 do not attempt to read - * control/platform-feature-xs_reset_watches. - */ -static bool xen_strict_xenbus_quirk(void) -{ -#ifdef CONFIG_X86 - uint32_t eax, ebx, ecx, edx, base; - - base = xen_cpuid_base(); - cpuid(base + 1, &eax, &ebx, &ecx, &edx); - - if ((eax >> 16) < 4) - return true; -#endif - return false; - -} static void xs_reset_watches(void) { int err; @@ -745,9 +725,6 @@ static void xs_reset_watches(void) if (!xen_hvm_domain() || xen_initial_domain()) return; - if (xen_strict_xenbus_quirk()) - return; - if (!xenbus_read_unsigned("control", "platform-feature-xs_reset_watches", 0)) return; From a47bc954cf0eb51f2828e1607d169d487df7f11f Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Wed, 20 Aug 2025 22:23:15 +0800 Subject: [PATCH 0424/1292] objtool/LoongArch: Get table size correctly if LTO is enabled When compiling with LLVM and CONFIG_LTO_CLANG is set, there exist many objtool warnings "sibling call from callable instruction with modified stack frame". For this special case, the related object file shows that there is no generated relocation section '.rela.discard.tablejump_annotate' for the table jump instruction jirl, thus objtool can not know that what is the actual destination address. It needs to do something on the LLVM side to make sure that there is the relocation section '.rela.discard.tablejump_annotate' if LTO is enabled, but in order to maintain compatibility for the current LLVM compiler, this can be done in the kernel Makefile for now. Ensure it is aware of linker with LTO, '--loongarch-annotate-tablejump' needs to be passed via '-mllvm' to ld.lld. Before doing the above changes, it should handle the special case of the relocation section '.rela.discard.tablejump_annotate' to get the correct table size first, otherwise there are many objtool warnings and errors if LTO is enabled. There are many different rodata for each function if LTO is enabled, it is necessary to enhance get_rodata_table_size_by_table_annotate(). Fixes: b95f852d3af2 ("objtool/LoongArch: Add support for switch table") Closes: https://lore.kernel.org/loongarch/20250731175655.GA1455142@ax162/ Reported-by: Nathan Chancellor Tested-by: Nathan Chancellor Signed-off-by: Tiezhu Yang Signed-off-by: Huacai Chen --- tools/objtool/arch/loongarch/special.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c index e39f86d97002b9..a80b75f7b061f7 100644 --- a/tools/objtool/arch/loongarch/special.c +++ b/tools/objtool/arch/loongarch/special.c @@ -27,6 +27,7 @@ static void get_rodata_table_size_by_table_annotate(struct objtool_file *file, struct table_info *next_table; unsigned long tmp_insn_offset; unsigned long tmp_rodata_offset; + bool is_valid_list = false; rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate"); if (!rsec) @@ -35,6 +36,12 @@ static void get_rodata_table_size_by_table_annotate(struct objtool_file *file, INIT_LIST_HEAD(&table_list); for_each_reloc(rsec, reloc) { + if (reloc->sym->sec->rodata) + continue; + + if (strcmp(insn->sec->name, reloc->sym->sec->name)) + continue; + orig_table = malloc(sizeof(struct table_info)); if (!orig_table) { WARN("malloc failed"); @@ -49,6 +56,22 @@ static void get_rodata_table_size_by_table_annotate(struct objtool_file *file, if (reloc_idx(reloc) + 1 == sec_num_entries(rsec)) break; + + if (strcmp(insn->sec->name, (reloc + 1)->sym->sec->name)) { + list_for_each_entry(orig_table, &table_list, jump_info) { + if (orig_table->insn_offset == insn->offset) { + is_valid_list = true; + break; + } + } + + if (!is_valid_list) { + list_del_init(&table_list); + continue; + } + + break; + } } list_for_each_entry(orig_table, &table_list, jump_info) { From 5dfea6644d201bfeffaa7e0d79d62309856613b7 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Wed, 20 Aug 2025 22:23:15 +0800 Subject: [PATCH 0425/1292] LoongArch: Pass annotate-tablejump option if LTO is enabled When compiling with LLVM and CONFIG_LTO_CLANG is set, there exist many objtool warnings "sibling call from callable instruction with modified stack frame". For this special case, the related object file shows that there is no generated relocation section '.rela.discard.tablejump_annotate' for the table jump instruction jirl, thus objtool can not know that what is the actual destination address. It needs to do something on the LLVM side to make sure that there is the relocation section '.rela.discard.tablejump_annotate' if LTO is enabled, but in order to maintain compatibility for the current LLVM compiler, this can be done in the kernel Makefile for now. Ensure it is aware of linker with LTO, '--loongarch-annotate-tablejump' needs to be passed via '-mllvm' to ld.lld. Note that it should also pass the compiler option -mannotate-tablejump rather than only pass '-mllvm --loongarch-annotate-tablejump' to ld.lld if LTO is enabled, otherwise there are no jump info for some table jump instructions. Fixes: e20ab7d454ee ("LoongArch: Enable jump table for objtool") Closes: https://lore.kernel.org/loongarch/20250731175655.GA1455142@ax162/ Reported-by: Nathan Chancellor Tested-by: Nathan Chancellor Co-developed-by: WANG Rui Signed-off-by: WANG Rui Signed-off-by: Tiezhu Yang Signed-off-by: Huacai Chen --- arch/loongarch/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index b0703a4e02a253..a3a9759414f40f 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -102,7 +102,13 @@ KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma) ifdef CONFIG_OBJTOOL ifdef CONFIG_CC_HAS_ANNOTATE_TABLEJUMP +# The annotate-tablejump option can not be passed to LLVM backend when LTO is enabled. +# Ensure it is aware of linker with LTO, '--loongarch-annotate-tablejump' also needs to +# be passed via '-mllvm' to ld.lld. KBUILD_CFLAGS += -mannotate-tablejump +ifdef CONFIG_LTO_CLANG +KBUILD_LDFLAGS += -mllvm --loongarch-annotate-tablejump +endif else KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers endif From f7794a4d92ade518c813de69a01b27ca6d8d86f3 Mon Sep 17 00:00:00 2001 From: Ming Wang Date: Wed, 20 Aug 2025 22:23:16 +0800 Subject: [PATCH 0426/1292] LoongArch: Increase COMMAND_LINE_SIZE up to 4096 The default COMMAND_LINE_SIZE of 512, inherited from asm-generic, is too small for modern use cases. For example, kdump configurations or extensive debugging parameters can easily exceed this limit. Therefore, increase the command line size to 4096 bytes, aligning LoongArch with the MIPS architecture. This change follows a broader trend among architectures to raise this limit to support modern needs; for instance, PowerPC increased its value for similar reasons in the commit a5980d064fe2 ("powerpc: Bump COMMAND_LINE_SIZE to 2048"). Similar to the change made for RISC-V in the commit 61fc1ee8be26 ("riscv: Bump COMMAND_LINE_SIZE value to 1024"), this is considered a safe change. The broader kernel community has reached a consensus that modifying COMMAND_LINE_SIZE from UAPI headers does not constitute a uABI breakage, as well-behaved userspace applications should not rely on this macro. Suggested-by: Huang Cun Signed-off-by: Ming Wang Signed-off-by: Huacai Chen --- arch/loongarch/include/uapi/asm/setup.h | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 arch/loongarch/include/uapi/asm/setup.h diff --git a/arch/loongarch/include/uapi/asm/setup.h b/arch/loongarch/include/uapi/asm/setup.h new file mode 100644 index 00000000000000..d46363ce3e024c --- /dev/null +++ b/arch/loongarch/include/uapi/asm/setup.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef _UAPI_ASM_LOONGARCH_SETUP_H +#define _UAPI_ASM_LOONGARCH_SETUP_H + +#define COMMAND_LINE_SIZE 4096 + +#endif /* _UAPI_ASM_LOONGARCH_SETUP_H */ From 8ef7f3132e4005a103b382e71abea7ad01fbeb86 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Wed, 20 Aug 2025 22:23:44 +0800 Subject: [PATCH 0427/1292] LoongArch: Add cpuhotplug hooks to fix high cpu usage of vCPU threads When the CPU is offline, the timer of LoongArch is not correctly closed. This is harmless for real machines, but resulting in an excessively high cpu usage rate of the offline vCPU thread in the virtual machines. To correctly close the timer, we have made the following modifications: Register the cpu hotplug event (CPUHP_AP_LOONGARCH_ARCH_TIMER_STARTING) for LoongArch. This event's hooks will be called to close the timer when the CPU is offline. Clear the timer interrupt when the timer is turned off. Since before the timer is turned off, there may be a timer interrupt that has already been in the pending state due to the interruption of the disabled, which also affects the halt state of the offline vCPU. Signed-off-by: Xianglai Li Signed-off-by: Huacai Chen --- arch/loongarch/kernel/time.c | 22 ++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + 2 files changed, 23 insertions(+) diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index 367906b10f810a..f3092f2de8b501 100644 --- a/arch/loongarch/kernel/time.c +++ b/arch/loongarch/kernel/time.c @@ -5,6 +5,7 @@ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ #include +#include #include #include #include @@ -102,6 +103,23 @@ static int constant_timer_next_event(unsigned long delta, struct clock_event_dev return 0; } +static int arch_timer_starting(unsigned int cpu) +{ + set_csr_ecfg(ECFGF_TIMER); + + return 0; +} + +static int arch_timer_dying(unsigned int cpu) +{ + constant_set_state_shutdown(this_cpu_ptr(&constant_clockevent_device)); + + /* Clear Timer Interrupt */ + write_csr_tintclear(CSR_TINTCLR_TI); + + return 0; +} + static unsigned long get_loops_per_jiffy(void) { unsigned long lpj = (unsigned long)const_clock_freq; @@ -172,6 +190,10 @@ int constant_clockevent_init(void) lpj_fine = get_loops_per_jiffy(); pr_info("Constant clock event device register\n"); + cpuhp_setup_state(CPUHP_AP_LOONGARCH_ARCH_TIMER_STARTING, + "clockevents/loongarch/timer:starting", + arch_timer_starting, arch_timer_dying); + return 0; } diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index edfa61d8070222..62cd7b35a29c94 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -168,6 +168,7 @@ enum cpuhp_state { CPUHP_AP_QCOM_TIMER_STARTING, CPUHP_AP_TEGRA_TIMER_STARTING, CPUHP_AP_ARMADA_TIMER_STARTING, + CPUHP_AP_LOONGARCH_ARCH_TIMER_STARTING, CPUHP_AP_MIPS_GIC_TIMER_STARTING, CPUHP_AP_ARC_TIMER_STARTING, CPUHP_AP_REALTEK_TIMER_STARTING, From 63dbd8fb2af3a89466538599a9acb2d11ef65c06 Mon Sep 17 00:00:00 2001 From: Kanglong Wang Date: Wed, 20 Aug 2025 22:23:44 +0800 Subject: [PATCH 0428/1292] LoongArch: Optimize module load time by optimizing PLT/GOT counting When enabling CONFIG_KASAN, CONFIG_PREEMPT_VOLUNTARY_BUILD and CONFIG_PREEMPT_VOLUNTARY at the same time, there will be soft deadlock, the relevant logs are as follows: rcu: INFO: rcu_sched self-detected stall on CPU ... Call Trace: [<900000000024f9e4>] show_stack+0x5c/0x180 [<90000000002482f4>] dump_stack_lvl+0x94/0xbc [<9000000000224544>] rcu_dump_cpu_stacks+0x1fc/0x280 [<900000000037ac80>] rcu_sched_clock_irq+0x720/0xf88 [<9000000000396c34>] update_process_times+0xb4/0x150 [<90000000003b2474>] tick_nohz_handler+0xf4/0x250 [<9000000000397e28>] __hrtimer_run_queues+0x1d0/0x428 [<9000000000399b2c>] hrtimer_interrupt+0x214/0x538 [<9000000000253634>] constant_timer_interrupt+0x64/0x80 [<9000000000349938>] __handle_irq_event_percpu+0x78/0x1a0 [<9000000000349a78>] handle_irq_event_percpu+0x18/0x88 [<9000000000354c00>] handle_percpu_irq+0x90/0xf0 [<9000000000348c74>] handle_irq_desc+0x94/0xb8 [<9000000001012b28>] handle_cpu_irq+0x68/0xa0 [<9000000001def8c0>] handle_loongarch_irq+0x30/0x48 [<9000000001def958>] do_vint+0x80/0xd0 [<9000000000268a0c>] kasan_mem_to_shadow.part.0+0x2c/0x2a0 [<90000000006344f4>] __asan_load8+0x4c/0x120 [<900000000025c0d0>] module_frob_arch_sections+0x5c8/0x6b8 [<90000000003895f0>] load_module+0x9e0/0x2958 [<900000000038b770>] __do_sys_init_module+0x208/0x2d0 [<9000000001df0c34>] do_syscall+0x94/0x190 [<900000000024d6fc>] handle_syscall+0xbc/0x158 After analysis, this is because the slow speed of loading the amdgpu module leads to the long time occupation of the cpu and then the soft deadlock. When loading a module, module_frob_arch_sections() tries to figure out the number of PLTs/GOTs that will be needed to handle all the RELAs. It will call the count_max_entries() to find in an out-of-order date which counting algorithm has O(n^2) complexity. To make it faster, we sort the relocation list by info and addend. That way, to check for a duplicate relocation, it just needs to compare with the previous entry. This reduces the complexity of the algorithm to O(n log n), as done in commit d4e0340919fb ("arm64/module: Optimize module load time by optimizing PLT counting"). This gives sinificant reduction in module load time for modules with large number of relocations. After applying this patch, the soft deadlock problem has been solved, and the kernel starts normally without "Call Trace". Using the default configuration to test some modules, the results are as follows: Module Size ip_tables 36K fat 143K radeon 2.5MB amdgpu 16MB Without this patch: Module Module load time (ms) Count(PLTs/GOTs) ip_tables 18 59/6 fat 0 162/14 radeon 54 1221/84 amdgpu 1411 4525/1098 With this patch: Module Module load time (ms) Count(PLTs/GOTs) ip_tables 18 59/6 fat 0 162/14 radeon 22 1221/84 amdgpu 45 4525/1098 Fixes: fcdfe9d22bed ("LoongArch: Add ELF and module support") Signed-off-by: Kanglong Wang Signed-off-by: Huacai Chen --- arch/loongarch/kernel/module-sections.c | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c index e2f30ff9afde82..a43ba7f9f9872a 100644 --- a/arch/loongarch/kernel/module-sections.c +++ b/arch/loongarch/kernel/module-sections.c @@ -8,6 +8,7 @@ #include #include #include +#include Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val) { @@ -61,39 +62,38 @@ Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr v return (Elf_Addr)&plt[nr]; } -static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y) -{ - return x->r_info == y->r_info && x->r_addend == y->r_addend; -} +#define cmp_3way(a, b) ((a) < (b) ? -1 : (a) > (b)) -static bool duplicate_rela(const Elf_Rela *rela, int idx) +static int compare_rela(const void *x, const void *y) { - int i; + int ret; + const Elf_Rela *rela_x = x, *rela_y = y; - for (i = 0; i < idx; i++) { - if (is_rela_equal(&rela[i], &rela[idx])) - return true; - } + ret = cmp_3way(rela_x->r_info, rela_y->r_info); + if (ret == 0) + ret = cmp_3way(rela_x->r_addend, rela_y->r_addend); - return false; + return ret; } static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts, unsigned int *gots) { - unsigned int i, type; + unsigned int i; + + sort(relas, num, sizeof(Elf_Rela), compare_rela, NULL); for (i = 0; i < num; i++) { - type = ELF_R_TYPE(relas[i].r_info); - switch (type) { + if (i && !compare_rela(&relas[i-1], &relas[i])) + continue; + + switch (ELF_R_TYPE(relas[i].r_info)) { case R_LARCH_SOP_PUSH_PLT_PCREL: case R_LARCH_B26: - if (!duplicate_rela(relas, i)) - (*plts)++; + (*plts)++; break; case R_LARCH_GOT_PC_HI20: - if (!duplicate_rela(relas, i)) - (*gots)++; + (*gots)++; break; default: break; /* Do nothing. */ From 112ca94f6c3b3e0b2002a240de43c487a33e0234 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 20 Aug 2025 22:23:44 +0800 Subject: [PATCH 0429/1292] LoongArch: Save LBT before FPU in setup_sigcontext() Now if preemption happens between protected_save_fpu_context() and protected_save_lbt_context(), FTOP context is lost. Because FTOP is saved by protected_save_lbt_context() but protected_save_fpu_context() disables TM before that. So save LBT before FPU in setup_sigcontext() to avoid this potential risk. Signed-off-by: Hanlu Li Signed-off-by: Huacai Chen --- arch/loongarch/kernel/signal.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/loongarch/kernel/signal.c b/arch/loongarch/kernel/signal.c index 4740cb5b238898..c9f7ca778364ed 100644 --- a/arch/loongarch/kernel/signal.c +++ b/arch/loongarch/kernel/signal.c @@ -677,6 +677,11 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, for (i = 1; i < 32; i++) err |= __put_user(regs->regs[i], &sc->sc_regs[i]); +#ifdef CONFIG_CPU_HAS_LBT + if (extctx->lbt.addr) + err |= protected_save_lbt_context(extctx); +#endif + if (extctx->lasx.addr) err |= protected_save_lasx_context(extctx); else if (extctx->lsx.addr) @@ -684,11 +689,6 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, else if (extctx->fpu.addr) err |= protected_save_fpu_context(extctx); -#ifdef CONFIG_CPU_HAS_LBT - if (extctx->lbt.addr) - err |= protected_save_lbt_context(extctx); -#endif - /* Set the "end" magic */ info = (struct sctx_info *)extctx->end.addr; err |= __put_user(0, &info->magic); From 0078e94a4733454d1ffa3888afe88bf19c81b91c Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 20 Aug 2025 22:23:44 +0800 Subject: [PATCH 0430/1292] LoongArch: Rename GCC_PLUGIN_STACKLEAK to KSTACK_ERASE Commit 57fbad15c2eee772 ("stackleak: Rename STACKLEAK to KSTACK_ERASE") misses the stackframe.h part for LoongArch, so fix it. Fixes: 57fbad15c2eee772 ("stackleak: Rename STACKLEAK to KSTACK_ERASE") Signed-off-by: Huacai Chen --- arch/loongarch/include/asm/stackframe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h index 3eda298702b199..5cb568a60cf8ef 100644 --- a/arch/loongarch/include/asm/stackframe.h +++ b/arch/loongarch/include/asm/stackframe.h @@ -58,7 +58,7 @@ .endm .macro STACKLEAK_ERASE -#ifdef CONFIG_GCC_PLUGIN_STACKLEAK +#ifdef CONFIG_KSTACK_ERASE bl stackleak_erase_on_task_stack #endif .endm From eb173ce0e23502e397eae75453936b3ecfb1fd84 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 14 Aug 2025 10:48:52 +0200 Subject: [PATCH 0431/1292] s390/configs: Update defconfigs The usual defconfig updates. Notable changes: - Enable ZONE_DEVICE, and with that DEV_DAX, FS_DAX, and FUSE_DAX - Enable CRYPTO_SELFTESTS_FULL for debug_defconfig - Enable CRASH_DM_CRYPT - Disable legacy IP_NF_FILTER Signed-off-by: Heiko Carstens Signed-off-by: Alexander Gordeev --- arch/s390/configs/debug_defconfig | 33 ++++++++++++++-------------- arch/s390/configs/defconfig | 32 ++++++++++++--------------- arch/s390/configs/zfcpdump_defconfig | 1 + 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 6b33429f1c4d4b..5e616bc988ac35 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -5,6 +5,7 @@ CONFIG_WATCH_QUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_POSIX_AUX_CLOCKS=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y CONFIG_BPF_JIT_ALWAYS_ON=y @@ -19,6 +20,7 @@ CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_SCHED_PROXY_EXEC=y CONFIG_NUMA_BALANCING=y CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y @@ -42,6 +44,7 @@ CONFIG_PROFILING=y CONFIG_KEXEC=y CONFIG_KEXEC_FILE=y CONFIG_KEXEC_SIG=y +CONFIG_CRASH_DM_CRYPT=y CONFIG_LIVEPATCH=y CONFIG_MARCH_Z13=y CONFIG_NR_CPUS=512 @@ -105,6 +108,7 @@ CONFIG_CMA_AREAS=7 CONFIG_MEM_SOFT_DIRTY=y CONFIG_DEFERRED_STRUCT_PAGE_INIT=y CONFIG_IDLE_PAGE_TRACKING=y +CONFIG_ZONE_DEVICE=y CONFIG_PERCPU_STATS=y CONFIG_GUP_TEST=y CONFIG_ANON_VMA_NAME=y @@ -223,17 +227,19 @@ CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m CONFIG_NETFILTER_XT_TARGET_CT=m CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HL=m CONFIG_NETFILTER_XT_TARGET_HMARK=m CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m CONFIG_NETFILTER_XT_TARGET_LOG=m CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m CONFIG_NETFILTER_XT_TARGET_NETMAP=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m CONFIG_NETFILTER_XT_TARGET_TEE=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m @@ -248,6 +254,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m CONFIG_NETFILTER_XT_MATCH_DSCP=m CONFIG_NETFILTER_XT_MATCH_ESP=m @@ -318,16 +325,8 @@ CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_RPFILTER=m CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_SECURITY=m -CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NFT_FIB_IPV6=m CONFIG_IP6_NF_IPTABLES=m @@ -340,15 +339,9 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_MH=m CONFIG_IP6_NF_MATCH_RPFILTER=m CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_RAW=m -CONFIG_IP6_NF_SECURITY=m -CONFIG_IP6_NF_NAT=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_IP_SCTP=m CONFIG_RDS=m CONFIG_RDS_RDMA=m CONFIG_RDS_TCP=m @@ -383,6 +376,7 @@ CONFIG_NET_SCH_FQ_CODEL=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_SCH_PLUG=m CONFIG_NET_SCH_ETS=m +CONFIG_NET_SCH_DUALPI2=m CONFIG_NET_CLS_BASIC=m CONFIG_NET_CLS_ROUTE4=m CONFIG_NET_CLS_FW=m @@ -504,6 +498,7 @@ CONFIG_DM_VDO=m CONFIG_NETDEVICES=y CONFIG_BONDING=m CONFIG_DUMMY=m +CONFIG_OVPN=m CONFIG_EQUALIZER=m CONFIG_IFB=m CONFIG_MACVLAN=m @@ -641,6 +636,7 @@ CONFIG_VP_VDPA=m CONFIG_VHOST_NET=m CONFIG_VHOST_VSOCK=m CONFIG_VHOST_VDPA=m +CONFIG_DEV_DAX=m CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y @@ -665,6 +661,7 @@ CONFIG_NILFS2_FS=m CONFIG_BCACHEFS_FS=y CONFIG_BCACHEFS_QUOTA=y CONFIG_BCACHEFS_POSIX_ACL=y +CONFIG_FS_DAX=y CONFIG_EXPORTFS_BLOCK_OPS=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_VERITY=y @@ -755,6 +752,8 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_SELFTESTS=y +CONFIG_CRYPTO_SELFTESTS_FULL=y +CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_PCRYPT=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_BENCHMARK=m @@ -783,7 +782,6 @@ CONFIG_CRYPTO_HCTR2=m CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_AEGIS128=m -CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_SEQIV=y CONFIG_CRYPTO_MD4=m @@ -822,6 +820,7 @@ CONFIG_SYSTEM_BLACKLIST_KEYRING=y CONFIG_CRYPTO_KRB5=m CONFIG_CRYPTO_KRB5_SELFTESTS=y CONFIG_CORDIC=m +CONFIG_TRACE_MMIO_ACCESS=y CONFIG_RANDOM32_SELFTEST=y CONFIG_XZ_DEC_MICROLZMA=y CONFIG_DMA_CMA=y diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index b75eb277585072..28f025051cdfb4 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -4,6 +4,7 @@ CONFIG_WATCH_QUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_POSIX_AUX_CLOCKS=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y CONFIG_BPF_JIT_ALWAYS_ON=y @@ -17,6 +18,7 @@ CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_SCHED_PROXY_EXEC=y CONFIG_NUMA_BALANCING=y CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y @@ -40,6 +42,7 @@ CONFIG_PROFILING=y CONFIG_KEXEC=y CONFIG_KEXEC_FILE=y CONFIG_KEXEC_SIG=y +CONFIG_CRASH_DM_CRYPT=y CONFIG_LIVEPATCH=y CONFIG_MARCH_Z13=y CONFIG_NR_CPUS=512 @@ -97,6 +100,7 @@ CONFIG_CMA_AREAS=7 CONFIG_MEM_SOFT_DIRTY=y CONFIG_DEFERRED_STRUCT_PAGE_INIT=y CONFIG_IDLE_PAGE_TRACKING=y +CONFIG_ZONE_DEVICE=y CONFIG_PERCPU_STATS=y CONFIG_ANON_VMA_NAME=y CONFIG_USERFAULTFD=y @@ -214,17 +218,19 @@ CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m CONFIG_NETFILTER_XT_TARGET_CT=m CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HL=m CONFIG_NETFILTER_XT_TARGET_HMARK=m CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m CONFIG_NETFILTER_XT_TARGET_LOG=m CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m CONFIG_NETFILTER_XT_TARGET_NETMAP=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m CONFIG_NETFILTER_XT_TARGET_TEE=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_SECMARK=m CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m @@ -239,6 +245,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m CONFIG_NETFILTER_XT_MATCH_DSCP=m CONFIG_NETFILTER_XT_MATCH_ESP=m @@ -309,16 +316,8 @@ CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_RPFILTER=m CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_SECURITY=m -CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NFT_FIB_IPV6=m CONFIG_IP6_NF_IPTABLES=m @@ -331,15 +330,9 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_MH=m CONFIG_IP6_NF_MATCH_RPFILTER=m CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_RAW=m -CONFIG_IP6_NF_SECURITY=m -CONFIG_IP6_NF_NAT=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_IP_SCTP=m CONFIG_RDS=m CONFIG_RDS_RDMA=m CONFIG_RDS_TCP=m @@ -373,6 +366,7 @@ CONFIG_NET_SCH_FQ_CODEL=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_SCH_PLUG=m CONFIG_NET_SCH_ETS=m +CONFIG_NET_SCH_DUALPI2=m CONFIG_NET_CLS_BASIC=m CONFIG_NET_CLS_ROUTE4=m CONFIG_NET_CLS_FW=m @@ -494,6 +488,7 @@ CONFIG_DM_VDO=m CONFIG_NETDEVICES=y CONFIG_BONDING=m CONFIG_DUMMY=m +CONFIG_OVPN=m CONFIG_EQUALIZER=m CONFIG_IFB=m CONFIG_MACVLAN=m @@ -631,6 +626,7 @@ CONFIG_VP_VDPA=m CONFIG_VHOST_NET=m CONFIG_VHOST_VSOCK=m CONFIG_VHOST_VDPA=m +CONFIG_DEV_DAX=m CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y @@ -652,6 +648,7 @@ CONFIG_NILFS2_FS=m CONFIG_BCACHEFS_FS=m CONFIG_BCACHEFS_QUOTA=y CONFIG_BCACHEFS_POSIX_ACL=y +CONFIG_FS_DAX=y CONFIG_EXPORTFS_BLOCK_OPS=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_VERITY=y @@ -683,7 +680,6 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_TMPFS_INODE64=y CONFIG_TMPFS_QUOTA=y CONFIG_HUGETLBFS=y -CONFIG_CONFIGFS_FS=m CONFIG_ECRYPT_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m @@ -741,6 +737,7 @@ CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_CRYPTO_FIPS=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_SELFTESTS=y +CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_PCRYPT=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_BENCHMARK=m @@ -769,7 +766,6 @@ CONFIG_CRYPTO_HCTR2=m CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_AEGIS128=m -CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_SEQIV=y CONFIG_CRYPTO_MD4=m diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index 8163c1702720bc..23dd55dc41a3b9 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -1,5 +1,6 @@ CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_POSIX_AUX_CLOCKS=y CONFIG_BPF_SYSCALL=y # CONFIG_CPU_ISOLATION is not set # CONFIG_UTS_NS is not set From fcc43a7e294f877021c4fa71276920f543e8e298 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 14 Aug 2025 10:48:53 +0200 Subject: [PATCH 0432/1292] s390/configs: Set HZ=1000 Similar to powerpc set HZ to 1000. See also commit a206d2334012 ("powerpc/defconfigs: Set HZ=1000 on ppc64 and powernv defconfigs"). Besides other this will reduce the latency seen with synchronize_rcu(). Signed-off-by: Heiko Carstens Signed-off-by: Alexander Gordeev --- arch/s390/configs/defconfig | 2 +- arch/s390/configs/zfcpdump_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index 28f025051cdfb4..094599cdaf4d9b 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -47,7 +47,7 @@ CONFIG_LIVEPATCH=y CONFIG_MARCH_Z13=y CONFIG_NR_CPUS=512 CONFIG_NUMA=y -CONFIG_HZ_100=y +CONFIG_HZ_1000=y CONFIG_CERT_STORE=y CONFIG_EXPOLINE=y CONFIG_EXPOLINE_AUTO=y diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index 23dd55dc41a3b9..ed0b137353ad13 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -12,7 +12,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KEXEC=y CONFIG_MARCH_Z13=y CONFIG_NR_CPUS=2 -CONFIG_HZ_100=y +CONFIG_HZ_1000=y # CONFIG_CHSC_SCH is not set # CONFIG_SCM_BUS is not set # CONFIG_AP is not set From 430fa71027b6ac9bb0ce5532b8d0676777d4219a Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 18 Aug 2025 12:21:52 +0200 Subject: [PATCH 0433/1292] s390/sclp: Fix SCCB present check Tracing code called by the SCLP interrupt handler contains early exits if the SCCB address associated with an interrupt is NULL. This check is performed after physical to virtual address translation. If the kernel identity mapping does not start at address zero, the resulting virtual address is never zero, so that the NULL checks won't work. Subsequently this may result in incorrect accesses to the first page of the identity mapping. Fix this by introducing a function that handles the NULL case before address translation. Fixes: ada1da31ce34 ("s390/sclp: sort out physical vs virtual pointers usage") Cc: stable@vger.kernel.org Reviewed-by: Alexander Gordeev Signed-off-by: Peter Oberparleiter Signed-off-by: Alexander Gordeev --- drivers/s390/char/sclp.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index f2e42c1d51aaa6..98e334724a6275 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -77,6 +77,13 @@ unsigned long sclp_console_full; /* The currently active SCLP command word. */ static sclp_cmdw_t active_cmd; +static inline struct sccb_header *sclpint_to_sccb(u32 sccb_int) +{ + if (sccb_int) + return __va(sccb_int); + return NULL; +} + static inline void sclp_trace(int prio, char *id, u32 a, u64 b, bool err) { struct sclp_trace_entry e; @@ -620,7 +627,7 @@ __sclp_find_req(u32 sccb) static bool ok_response(u32 sccb_int, sclp_cmdw_t cmd) { - struct sccb_header *sccb = (struct sccb_header *)__va(sccb_int); + struct sccb_header *sccb = sclpint_to_sccb(sccb_int); struct evbuf_header *evbuf; u16 response; @@ -659,7 +666,7 @@ static void sclp_interrupt_handler(struct ext_code ext_code, /* INT: Interrupt received (a=intparm, b=cmd) */ sclp_trace_sccb(0, "INT", param32, active_cmd, active_cmd, - (struct sccb_header *)__va(finished_sccb), + sclpint_to_sccb(finished_sccb), !ok_response(finished_sccb, active_cmd)); if (finished_sccb) { From 93f616ff870a1fb7e84d472cad0af651b18f9f87 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 7 Aug 2025 17:04:27 +0200 Subject: [PATCH 0434/1292] s390/mm: Do not map lowcore with identity mapping Since the identity mapping is pinned to address zero the lowcore is always also mapped to address zero, this happens regardless of the relocate_lowcore command line option. If the option is specified the lowcore is mapped twice, instead of only once. This means that NULL pointer accesses will succeed instead of causing an exception (low address protection still applies, but covers only parts). To fix this never map the first two pages of physical memory with the identity mapping. Fixes: 32db401965f1 ("s390/mm: Pin identity mapping base to zero") Reviewed-by: Alexander Gordeev Signed-off-by: Heiko Carstens Signed-off-by: Alexander Gordeev --- arch/s390/boot/vmem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/boot/vmem.c b/arch/s390/boot/vmem.c index 1d073acd05a7b8..cea3de4dce8c32 100644 --- a/arch/s390/boot/vmem.c +++ b/arch/s390/boot/vmem.c @@ -530,6 +530,9 @@ void setup_vmem(unsigned long kernel_start, unsigned long kernel_end, unsigned l lowcore_address + sizeof(struct lowcore), POPULATE_LOWCORE); for_each_physmem_usable_range(i, &start, &end) { + /* Do not map lowcore with identity mapping */ + if (!start) + start = sizeof(struct lowcore); pgtable_populate((unsigned long)__identity_va(start), (unsigned long)__identity_va(end), POPULATE_IDENTITY); From ec879e1a0be8007aa232ffedcf6a6445dfc1a3d7 Mon Sep 17 00:00:00 2001 From: "Masami Hiramatsu (Google)" Date: Sat, 16 Aug 2025 23:10:51 +0900 Subject: [PATCH 0435/1292] tracing: fprobe-event: Sanitize wildcard for fprobe event name Fprobe event accepts wildcards for the target functions, but unless user specifies its event name, it makes an event with the wildcards. /sys/kernel/tracing # echo 'f mutex*' >> dynamic_events /sys/kernel/tracing # cat dynamic_events f:fprobes/mutex*__entry mutex* /sys/kernel/tracing # ls events/fprobes/ enable filter mutex*__entry To fix this, replace the wildcard ('*') with an underscore. Link: https://lore.kernel.org/all/175535345114.282990.12294108192847938710.stgit@devnote2/ Fixes: 334e5519c375 ("tracing/probes: Add fprobe events for tracing function entry and exit.") Signed-off-by: Masami Hiramatsu (Google) Cc: stable@vger.kernel.org --- kernel/trace/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 1dbf1d3cf2f1d4..5a6688832da84d 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -2204,7 +2204,7 @@ static inline bool is_good_system_name(const char *name) static inline void sanitize_event_name(char *name) { while (*name++ != '\0') - if (*name == ':' || *name == '.') + if (*name == ':' || *name == '.' || *name == '*') *name = '_'; } From 4be8cefc132606b4a6e851f37f8e8c40c406c910 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 20 Aug 2025 22:51:14 +0800 Subject: [PATCH 0436/1292] LoongArch: KVM: Make function kvm_own_lbt() robust Add the flag KVM_LARCH_LBT checking in function kvm_own_lbt(), so that it can be called safely rather than duplicated enabling again. Cc: stable@vger.kernel.org Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/vcpu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index d1b8c50941ca23..ce478151466c00 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -1283,9 +1283,11 @@ int kvm_own_lbt(struct kvm_vcpu *vcpu) return -EINVAL; preempt_disable(); - set_csr_euen(CSR_EUEN_LBTEN); - _restore_lbt(&vcpu->arch.lbt); - vcpu->arch.aux_inuse |= KVM_LARCH_LBT; + if (!(vcpu->arch.aux_inuse & KVM_LARCH_LBT)) { + set_csr_euen(CSR_EUEN_LBTEN); + _restore_lbt(&vcpu->arch.lbt); + vcpu->arch.aux_inuse |= KVM_LARCH_LBT; + } preempt_enable(); return 0; From 5c68549c81bcca70fc464e305ffeefd9af968287 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 20 Aug 2025 22:51:15 +0800 Subject: [PATCH 0437/1292] LoongArch: KVM: Fix stack protector issue in send_ipi_data() Function kvm_io_bus_read() is called in function send_ipi_data(), buffer size of parameter *val should be at least 8 bytes. Since some emulation functions like loongarch_ipi_readl() and kvm_eiointc_read() will write the buffer *val with 8 bytes signed extension regardless parameter len. Otherwise there will be buffer overflow issue when CONFIG_STACKPROTECTOR is enabled. The bug report is shown as follows: Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: send_ipi_data+0x194/0x1a0 [kvm] CPU: 11 UID: 107 PID: 2692 Comm: CPU 0/KVM Not tainted 6.17.0-rc1+ #102 PREEMPT(full) Stack : 9000000005901568 0000000000000000 9000000003af371c 900000013c68c000 900000013c68f850 900000013c68f858 0000000000000000 900000013c68f998 900000013c68f990 900000013c68f990 900000013c68f6c0 fffffffffffdb058 fffffffffffdb0e0 900000013c68f858 911e1d4d39cf0ec2 9000000105657a00 0000000000000001 fffffffffffffffe 0000000000000578 282049464555206e 6f73676e6f6f4c20 0000000000000001 00000000086b4000 0000000000000000 0000000000000000 0000000000000000 9000000005709968 90000000058f9000 900000013c68fa68 900000013c68fab4 90000000029279f0 900000010153f940 900000010001f360 0000000000000000 9000000003af3734 000000004390000c 00000000000000b0 0000000000000004 0000000000000000 0000000000071c1d ... Call Trace: [<9000000003af3734>] show_stack+0x5c/0x180 [<9000000003aed168>] dump_stack_lvl+0x6c/0x9c [<9000000003ad0ab0>] vpanic+0x108/0x2c4 [<9000000003ad0ca8>] panic+0x3c/0x40 [<9000000004eb0a1c>] __stack_chk_fail+0x14/0x18 [] send_ipi_data+0x190/0x1a0 [kvm] [] __kvm_io_bus_write+0xa4/0xe8 [kvm] [] kvm_io_bus_write+0x54/0x90 [kvm] [] kvm_emu_iocsr+0x180/0x310 [kvm] [] kvm_handle_gspr+0x280/0x478 [kvm] [] kvm_handle_exit+0xc0/0x130 [kvm] Cc: stable@vger.kernel.org Fixes: daee2f9cae551 ("LoongArch: KVM: Add IPI read and write function") Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/ipi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index e658d5b37c044e..7925651d2ccf1e 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -99,7 +99,7 @@ static void write_mailbox(struct kvm_vcpu *vcpu, int offset, uint64_t data, int static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) { int i, idx, ret; - uint32_t val = 0, mask = 0; + uint64_t val = 0, mask = 0; /* * Bit 27-30 is mask for byte writing. @@ -108,7 +108,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) if ((data >> 27) & 0xf) { /* Read the old val */ idx = srcu_read_lock(&vcpu->kvm->srcu); - ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val); + ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, 4, &val); srcu_read_unlock(&vcpu->kvm->srcu, idx); if (unlikely(ret)) { kvm_err("%s: : read data from addr %llx failed\n", __func__, addr); @@ -124,7 +124,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) } val |= ((uint32_t)(data >> 32) & ~mask); idx = srcu_read_lock(&vcpu->kvm->srcu); - ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val); + ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, 4, &val); srcu_read_unlock(&vcpu->kvm->srcu, idx); if (unlikely(ret)) kvm_err("%s: : write data to addr %llx failed\n", __func__, addr); From 0dfd9ea7bf80fabe11f5b775d762a5cd168cdf41 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Wed, 20 Aug 2025 22:51:15 +0800 Subject: [PATCH 0438/1292] LoongArch: KVM: Use kvm_get_vcpu_by_id() instead of kvm_get_vcpu() Since using kvm_get_vcpu() may fail to retrieve the vCPU context, kvm_get_vcpu_by_id() should be used instead. Fixes: 8e3054261bc3 ("LoongArch: KVM: Add IPI user mode read and write function") Fixes: 3956a52bc05b ("LoongArch: KVM: Add EIOINTC read and write functions") Reviewed-by: Yanteng Si Signed-off-by: Song Gao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/eiointc.c | 7 ++++++- arch/loongarch/kvm/intc/ipi.c | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c index a3a12af9ecbff8..026b139dcff2de 100644 --- a/arch/loongarch/kvm/intc/eiointc.c +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -45,7 +45,12 @@ static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level) } cpu = s->sw_coremap[irq]; - vcpu = kvm_get_vcpu(s->kvm, cpu); + vcpu = kvm_get_vcpu_by_id(s->kvm, cpu); + if (unlikely(vcpu == NULL)) { + kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + return; + } + if (level) { /* if not enable return false */ if (!test_bit(irq, (unsigned long *)s->enable.reg_u32)) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 7925651d2ccf1e..5a8481dda052e6 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -298,7 +298,7 @@ static int kvm_ipi_regs_access(struct kvm_device *dev, cpu = (attr->attr >> 16) & 0x3ff; addr = attr->attr & 0xff; - vcpu = kvm_get_vcpu(dev->kvm, cpu); + vcpu = kvm_get_vcpu_by_id(dev->kvm, cpu); if (unlikely(vcpu == NULL)) { kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); return -EINVAL; From 538c06e3964a8e94b645686cc58ccc4a06fa6330 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 20 Aug 2025 22:51:15 +0800 Subject: [PATCH 0439/1292] LoongArch: KVM: Add address alignment check in pch_pic register access With pch_pic device, its register is based on MMIO address space, different access size 1/2/4/8 is supported. And base address should be naturally aligned with its access size, here add alignment check in its register access emulation function. Cc: stable@vger.kernel.org Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/pch_pic.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index 6f00ffe05c544e..119290bcea79ab 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -195,6 +195,11 @@ static int kvm_pch_pic_read(struct kvm_vcpu *vcpu, return -EINVAL; } + if (addr & (len - 1)) { + kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); + return -EINVAL; + } + /* statistics of pch pic reading */ vcpu->stat.pch_pic_read_exits++; ret = loongarch_pch_pic_read(s, addr, len, val); @@ -302,6 +307,11 @@ static int kvm_pch_pic_write(struct kvm_vcpu *vcpu, return -EINVAL; } + if (addr & (len - 1)) { + kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); + return -EINVAL; + } + /* statistics of pch pic writing */ vcpu->stat.pch_pic_write_exits++; ret = loongarch_pch_pic_write(s, addr, len, val); From dce1b33ed7430c7189b8cc1567498f9e6bf12731 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 24 Jun 2025 16:19:30 -0700 Subject: [PATCH 0440/1292] selftests: harness: Rename is_signed_type() to avoid collision with overflow.h Rename is_signed_type() to is_signed_var() to avoid colliding with a macro of the same name defined by tools' linux/overflow.h. This fixes warnings (and presumably potential test failures) in tests that utilize the selftests harness and happen to (indirectly) include overflow.h. In file included from tools/include/linux/bits.h:34, from tools/include/linux/bitops.h:14, from tools/include/linux/hashtable.h:13, from include/kvm_util.h:11, from x86/userspace_msr_exit_test.c:11: tools/include/linux/overflow.h:31:9: error: "is_signed_type" redefined [-Werror] 31 | #define is_signed_type(type) (((type)(-1)) < (type)1) | ^~~~~~~~~~~~~~ In file included from include/kvm_test_harness.h:11, from x86/userspace_msr_exit_test.c:9: ../kselftest_harness.h:754:9: note: this is the location of the previous definition 754 | #define is_signed_type(var) (!!(((__typeof__(var))(-1)) < (__typeof__(var))1)) | ^~~~~~~~~~~~~~ Use a separate definition, at least for now, as many selftests build without tools/include in their include path. Fixes: fc92099902fb ("tools headers: Synchronize linux/bits.h with the kernel sources") Cc: Vincent Mailhol Cc: Arnaldo Carvalho de Melo Cc: Mark Brown Link: https://lore.kernel.org/r/20250624231930.583689-1-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kselftest_harness.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 2925e47db995d7..8516e8434bc45c 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -751,7 +751,7 @@ for (; _metadata->trigger; _metadata->trigger = \ __bail(_assert, _metadata)) -#define is_signed_type(var) (!!(((__typeof__(var))(-1)) < (__typeof__(var))1)) +#define is_signed_var(var) (!!(((__typeof__(var))(-1)) < (__typeof__(var))1)) #define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \ /* Avoid multiple evaluation of the cases */ \ @@ -759,7 +759,7 @@ __typeof__(_seen) __seen = (_seen); \ if (!(__exp _t __seen)) { \ /* Report with actual signedness to avoid weird output. */ \ - switch (is_signed_type(__exp) * 2 + is_signed_type(__seen)) { \ + switch (is_signed_var(__exp) * 2 + is_signed_var(__seen)) { \ case 0: { \ uintmax_t __exp_print = (uintmax_t)__exp; \ uintmax_t __seen_print = (uintmax_t)__seen; \ From a82231b2a8712d0218fc286a9b0da328d419a3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 14 Aug 2025 12:39:39 +0200 Subject: [PATCH 0441/1292] HID: input: rename hidinput_set_battery_charge_status() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for a patch fixing a bug affecting hidinput_set_battery_charge_status(), rename the function to hidinput_update_battery_charge_status() and move it up so it can be used by hidinput_update_battery(). Refactor, no functional changes. Tested-by: 卢国宏 Signed-off-by: JosĆ© Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-input-test.c | 10 +++++----- drivers/hid/hid-input.c | 38 ++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c index 77c2d45ac62a7f..6f5c71660d823b 100644 --- a/drivers/hid/hid-input-test.c +++ b/drivers/hid/hid-input-test.c @@ -7,7 +7,7 @@ #include -static void hid_test_input_set_battery_charge_status(struct kunit *test) +static void hid_test_input_update_battery_charge_status(struct kunit *test) { struct hid_device *dev; bool handled; @@ -15,15 +15,15 @@ static void hid_test_input_set_battery_charge_status(struct kunit *test) dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); - handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0); + handled = hidinput_update_battery_charge_status(dev, HID_DG_HEIGHT, 0); KUNIT_EXPECT_FALSE(test, handled); KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN); - handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0); + handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 0); KUNIT_EXPECT_TRUE(test, handled); KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING); - handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1); + handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 1); KUNIT_EXPECT_TRUE(test, handled); KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING); } @@ -63,7 +63,7 @@ static void hid_test_input_get_battery_property(struct kunit *test) } static struct kunit_case hid_input_tests[] = { - KUNIT_CASE(hid_test_input_set_battery_charge_status), + KUNIT_CASE(hid_test_input_update_battery_charge_status), KUNIT_CASE(hid_test_input_get_battery_property), { } }; diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index ff1784b5c2a477..262787e6eb2044 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -595,6 +595,20 @@ static void hidinput_cleanup_battery(struct hid_device *dev) dev->battery = NULL; } +static bool hidinput_update_battery_charge_status(struct hid_device *dev, + unsigned int usage, int value) +{ + switch (usage) { + case HID_BAT_CHARGING: + dev->battery_charge_status = value ? + POWER_SUPPLY_STATUS_CHARGING : + POWER_SUPPLY_STATUS_DISCHARGING; + return true; + } + + return false; +} + static void hidinput_update_battery(struct hid_device *dev, int value) { int capacity; @@ -617,20 +631,6 @@ static void hidinput_update_battery(struct hid_device *dev, int value) power_supply_changed(dev->battery); } } - -static bool hidinput_set_battery_charge_status(struct hid_device *dev, - unsigned int usage, int value) -{ - switch (usage) { - case HID_BAT_CHARGING: - dev->battery_charge_status = value ? - POWER_SUPPLY_STATUS_CHARGING : - POWER_SUPPLY_STATUS_DISCHARGING; - return true; - } - - return false; -} #else /* !CONFIG_HID_BATTERY_STRENGTH */ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field, bool is_percentage) @@ -642,14 +642,14 @@ static void hidinput_cleanup_battery(struct hid_device *dev) { } -static void hidinput_update_battery(struct hid_device *dev, int value) +static bool hidinput_update_battery_charge_status(struct hid_device *dev, + unsigned int usage, int value) { + return false; } -static bool hidinput_set_battery_charge_status(struct hid_device *dev, - unsigned int usage, int value) +static void hidinput_update_battery(struct hid_device *dev, int value) { - return false; } #endif /* CONFIG_HID_BATTERY_STRENGTH */ @@ -1515,7 +1515,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; if (usage->type == EV_PWR) { - bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value); + bool handled = hidinput_update_battery_charge_status(hid, usage->hid, value); if (!handled) hidinput_update_battery(hid, value); From e94536e1d1818b0989aa19b443b7089f50133c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 14 Aug 2025 12:39:40 +0200 Subject: [PATCH 0442/1292] HID: input: report battery status changes immediately MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the battery status (charging/discharging) was not reported immediately to user-space.Ā  For most input devices, this wasn't problematic because changing their battery status requires connecting them to a different bus. For example, a gamepad would report aĀ discharging status while connected viaĀ Bluetooth and a charging status while connected via USB. However, certain devices are not connected or disconnected when their battery status changes. For example, a phone battery changes its status without connecting or disconnecting it. In these cases, the battery status was not reported immediatelyĀ to user space. ReportĀ battery status changesĀ immediately to user space to support these kinds of devices. Fixes: a608dc1c0639 ("HID: input: map battery system charging") Reported-by: 卢国宏 Closes: https://lore.kernel.org/linux-input/aI49Im0sGb6fpgc8@fedora/T/ Tested-by: 卢国宏 Signed-off-by: JosĆ© Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 262787e6eb2044..f45f856a127fe7 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -609,13 +609,19 @@ static bool hidinput_update_battery_charge_status(struct hid_device *dev, return false; } -static void hidinput_update_battery(struct hid_device *dev, int value) +static void hidinput_update_battery(struct hid_device *dev, unsigned int usage, + int value) { int capacity; if (!dev->battery) return; + if (hidinput_update_battery_charge_status(dev, usage, value)) { + power_supply_changed(dev->battery); + return; + } + if (value == 0 || value < dev->battery_min || value > dev->battery_max) return; @@ -642,13 +648,8 @@ static void hidinput_cleanup_battery(struct hid_device *dev) { } -static bool hidinput_update_battery_charge_status(struct hid_device *dev, - unsigned int usage, int value) -{ - return false; -} - -static void hidinput_update_battery(struct hid_device *dev, int value) +static void hidinput_update_battery(struct hid_device *dev, unsigned int usage, + int value) { } #endif /* CONFIG_HID_BATTERY_STRENGTH */ @@ -1515,11 +1516,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; if (usage->type == EV_PWR) { - bool handled = hidinput_update_battery_charge_status(hid, usage->hid, value); - - if (!handled) - hidinput_update_battery(hid, value); - + hidinput_update_battery(hid, usage->hid, value); return; } From ab1bb82f3db20e23eace06db52031b1164a110c2 Mon Sep 17 00:00:00 2001 From: Matt Coffin Date: Wed, 20 Aug 2025 01:49:51 -0600 Subject: [PATCH 0443/1292] HID: logitech: Add ids for G PRO 2 LIGHTSPEED Adds support for the G PRO 2 LIGHTSPEED Wireless via it's nano receiver or directly. This nano receiver appears to work identically to the 1_1 receiver for the case I've verified, which is the battery status through lg-hidpp. The same appears to be the case wired, sharing much with the Pro X Superlight 2; differences seemed to lie in userland configuration rather than in interfaces used by hid_logitech_hidpp on the kernel side. I verified the sysfs interface for battery charge/discharge status, and capacity read to be working on my 910-007290 device (white). Signed-off-by: Matt Coffin Reviewed-by: Bastien Nocera Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-logitech-dj.c | 4 ++++ drivers/hid/hid-logitech-hidpp.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5a1096283855ba..37dc423803737c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -907,6 +907,7 @@ #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f +#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc543 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a #define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548 #define USB_DEVICE_ID_SPACETRAVELLER 0xc623 diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 34fa71ceec2b20..cce54dd9884a3e 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -1983,6 +1983,10 @@ static const struct hid_device_id logi_dj_receivers[] = { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1), .driver_data = recvr_type_gaming_hidpp}, + { /* Logitech lightspeed receiver (0xc543) */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, + USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2), + .driver_data = recvr_type_gaming_hidpp}, { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 10a3bc5f931b43..aaef405a717ee9 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -4596,6 +4596,8 @@ static const struct hid_device_id hidpp_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) }, { /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) }, + { /* Logitech G PRO 2 LIGHTSPEED Wireless Mouse over USB */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xc09a) }, { /* G935 Gaming Headset */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87), From 729dc340a4ed1267774fc8518284e976e2210bdc Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 17 Aug 2025 16:21:46 +0200 Subject: [PATCH 0444/1292] bootconfig: Fix negative seeks on 32-bit with LFS enabled Commit 26dda5769509 "tools/bootconfig: Cleanup bootconfig footer size calculations" replaced some expressions of type int with the BOOTCONFIG_FOOTER_SIZE macro, which expands to an expression of type size_t, which is unsigned. On 32-bit architectures with LFS enabled (i.e. off_t is 64-bit), the seek offset of -BOOTCONFIG_FOOTER_SIZE now turns into a positive value. Fix this by casting the size to off_t before negating it. Just in case someone changes BOOTCONFIG_MAGIC_LEN to have type size_t later, do the same thing to the seek offset of -BOOTCONFIG_MAGIC_LEN. Link: https://lore.kernel.org/all/aKHlevxeg6Y7UQrz@decadent.org.uk/ Fixes: 26dda5769509 ("tools/bootconfig: Cleanup bootconfig footer size calculations") Signed-off-by: Ben Hutchings Signed-off-by: Masami Hiramatsu (Google) --- tools/bootconfig/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c index 57c669d2aa90f5..55d59ed507d541 100644 --- a/tools/bootconfig/main.c +++ b/tools/bootconfig/main.c @@ -193,7 +193,7 @@ static int load_xbc_from_initrd(int fd, char **buf) if (stat.st_size < BOOTCONFIG_FOOTER_SIZE) return 0; - if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) + if (lseek(fd, -(off_t)BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) return pr_errno("Failed to lseek for magic", -errno); if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0) @@ -203,7 +203,7 @@ static int load_xbc_from_initrd(int fd, char **buf) if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0) return 0; - if (lseek(fd, -BOOTCONFIG_FOOTER_SIZE, SEEK_END) < 0) + if (lseek(fd, -(off_t)BOOTCONFIG_FOOTER_SIZE, SEEK_END) < 0) return pr_errno("Failed to lseek for size", -errno); if (read(fd, &size, sizeof(uint32_t)) < 0) From c81f6ce16785cc07ae81f53deb07b662ed0bb3a5 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Mon, 18 Aug 2025 08:22:21 -0700 Subject: [PATCH 0445/1292] of: dynamic: Fix memleak when of_pci_add_properties() failed When of_pci_add_properties() failed, of_changeset_destroy() is called to free the changeset. And of_changeset_destroy() puts device tree node in each entry but does not free property in the entry. This leads to memory leak in the failure case. In of_changeset_add_prop_helper(), add the property to the device tree node deadprops list. Thus, the property will also be freed along with device tree node. Fixes: b544fc2b8606 ("of: dynamic: Add interfaces for creating device node dynamically") Reported-by: Lorenzo Pieralisi Closes: https://lore.kernel.org/all/aJms+YT8TnpzpCY8@lpieralisi/ Tested-by: Lorenzo Pieralisi Signed-off-by: Lizhi Hou Link: https://lore.kernel.org/r/20250818152221.3685724-1-lizhi.hou@amd.com Signed-off-by: Rob Herring (Arm) --- drivers/of/dynamic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 0aba760f7577ef..dd30b7d8b5e469 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -938,6 +938,9 @@ static int of_changeset_add_prop_helper(struct of_changeset *ocs, if (ret) __of_prop_free(new_pp); + new_pp->next = np->deadprops; + np->deadprops = new_pp; + return ret; } From 4d4d9ef9dfee877d494e5418f68a1016ef08cad6 Mon Sep 17 00:00:00 2001 From: Jason Xing Date: Tue, 19 Aug 2025 15:19:57 -0700 Subject: [PATCH 0446/1292] ixgbe: xsk: resolve the negative overflow of budget in ixgbe_xmit_zc Resolve the budget negative overflow which leads to returning true in ixgbe_xmit_zc even when the budget of descs are thoroughly consumed. Before this patch, when the budget is decreased to zero and finishes sending the last allowed desc in ixgbe_xmit_zc, it will always turn back and enter into the while() statement to see if it should keep processing packets, but in the meantime it unexpectedly decreases the value again to 'unsigned int (0--)', namely, UINT_MAX. Finally, the ixgbe_xmit_zc returns true, showing 'we complete cleaning the budget'. That also means 'clean_complete = true' in ixgbe_poll. The true theory behind this is if that budget number of descs are consumed, it implies that we might have more descs to be done. So we should return false in ixgbe_xmit_zc to tell napi poll to find another chance to start polling to handle the rest of descs. On the contrary, returning true here means job done and we know we finish all the possible descs this time and we don't intend to start a new napi poll. It is apparently against our expectations. Please also see how ixgbe_clean_tx_irq() handles the problem: it uses do..while() statement to make sure the budget can be decreased to zero at most and the negative overflow never happens. The patch adds 'likely' because we rarely would not hit the loop condition since the standard budget is 256. Fixes: 8221c5eba8c1 ("ixgbe: add AF_XDP zero-copy Tx support") Signed-off-by: Jason Xing Reviewed-by: Larysa Zaremba Reviewed-by: Paul Menzel Reviewed-by: Aleksandr Loktionov Tested-by: Priya Singh Signed-off-by: Tony Nguyen Link: https://patch.msgid.link/20250819222000.3504873-4-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c index ac58964b2f087e..7b941505a9d024 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c @@ -398,7 +398,7 @@ static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget) dma_addr_t dma; u32 cmd_type; - while (budget-- > 0) { + while (likely(budget)) { if (unlikely(!ixgbe_desc_unused(xdp_ring))) { work_done = false; break; @@ -433,6 +433,8 @@ static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget) xdp_ring->next_to_use++; if (xdp_ring->next_to_use == xdp_ring->count) xdp_ring->next_to_use = 0; + + budget--; } if (tx_desc) { From f3d9f7fa7f5dbfd4fdb1e69c25fc5627700d19dd Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Tue, 19 Aug 2025 15:19:58 -0700 Subject: [PATCH 0447/1292] ixgbe: fix ndo_xdp_xmit() workloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently ixgbe driver checks periodically in its watchdog subtask if there is anything to be transmitted (considering both Tx and XDP rings) under state of carrier not being 'ok'. Such event is interpreted as Tx hang and therefore results in interface reset. This is currently problematic for ndo_xdp_xmit() as it is allowed to produce descriptors when interface is going through reset or its carrier is turned off. Furthermore, XDP rings should not really be objects of Tx hang detection. This mechanism is rather a matter of ndo_tx_timeout() being called from dev_watchdog against Tx rings exposed to networking stack. Taking into account issues described above, let us have a two fold fix - do not respect XDP rings in local ixgbe watchdog and do not produce Tx descriptors in ndo_xdp_xmit callback when there is some problem with carrier currently. For now, keep the Tx hang checks in clean Tx irq routine, but adjust it to not execute for XDP rings. Cc: Tobias Bƶhm Reported-by: Marcus Wichelmann Closes: https://lore.kernel.org/netdev/eca1880f-253a-4955-afe6-732d7c6926ee@hetzner-cloud.de/ Fixes: 6453073987ba ("ixgbe: add initial support for xdp redirect") Fixes: 33fdc82f0883 ("ixgbe: add support for XDP_TX action") Reviewed-by: Aleksandr Loktionov Tested-by: Marcus Wichelmann Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Link: https://patch.msgid.link/20250819222000.3504873-5-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6122a0abb41f54..80e6a2ef1350e3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -968,10 +968,6 @@ static void ixgbe_update_xoff_rx_lfc(struct ixgbe_adapter *adapter) for (i = 0; i < adapter->num_tx_queues; i++) clear_bit(__IXGBE_HANG_CHECK_ARMED, &adapter->tx_ring[i]->state); - - for (i = 0; i < adapter->num_xdp_queues; i++) - clear_bit(__IXGBE_HANG_CHECK_ARMED, - &adapter->xdp_ring[i]->state); } static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter) @@ -1214,7 +1210,7 @@ static void ixgbe_pf_handle_tx_hang(struct ixgbe_ring *tx_ring, struct ixgbe_adapter *adapter = netdev_priv(tx_ring->netdev); struct ixgbe_hw *hw = &adapter->hw; - e_err(drv, "Detected Tx Unit Hang%s\n" + e_err(drv, "Detected Tx Unit Hang\n" " Tx Queue <%d>\n" " TDH, TDT <%x>, <%x>\n" " next_to_use <%x>\n" @@ -1222,16 +1218,14 @@ static void ixgbe_pf_handle_tx_hang(struct ixgbe_ring *tx_ring, "tx_buffer_info[next_to_clean]\n" " time_stamp <%lx>\n" " jiffies <%lx>\n", - ring_is_xdp(tx_ring) ? " (XDP)" : "", tx_ring->queue_index, IXGBE_READ_REG(hw, IXGBE_TDH(tx_ring->reg_idx)), IXGBE_READ_REG(hw, IXGBE_TDT(tx_ring->reg_idx)), tx_ring->next_to_use, next, tx_ring->tx_buffer_info[next].time_stamp, jiffies); - if (!ring_is_xdp(tx_ring)) - netif_stop_subqueue(tx_ring->netdev, - tx_ring->queue_index); + netif_stop_subqueue(tx_ring->netdev, + tx_ring->queue_index); } /** @@ -1451,6 +1445,9 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, total_bytes); adapter->tx_ipsec += total_ipsec; + if (ring_is_xdp(tx_ring)) + return !!budget; + if (check_for_tx_hang(tx_ring) && ixgbe_check_tx_hang(tx_ring)) { if (adapter->hw.mac.type == ixgbe_mac_e610) ixgbe_handle_mdd_event(adapter, tx_ring); @@ -1468,9 +1465,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, return true; } - if (ring_is_xdp(tx_ring)) - return !!budget; - #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) txq = netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index); if (!__netif_txq_completed_wake(txq, total_packets, total_bytes, @@ -7974,12 +7968,9 @@ static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter) return; /* Force detection of hung controller */ - if (netif_carrier_ok(adapter->netdev)) { + if (netif_carrier_ok(adapter->netdev)) for (i = 0; i < adapter->num_tx_queues; i++) set_check_for_tx_hang(adapter->tx_ring[i]); - for (i = 0; i < adapter->num_xdp_queues; i++) - set_check_for_tx_hang(adapter->xdp_ring[i]); - } if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { /* @@ -8199,13 +8190,6 @@ static bool ixgbe_ring_tx_pending(struct ixgbe_adapter *adapter) return true; } - for (i = 0; i < adapter->num_xdp_queues; i++) { - struct ixgbe_ring *ring = adapter->xdp_ring[i]; - - if (ring->next_to_use != ring->next_to_clean) - return true; - } - return false; } @@ -11005,6 +10989,10 @@ static int ixgbe_xdp_xmit(struct net_device *dev, int n, if (unlikely(test_bit(__IXGBE_DOWN, &adapter->state))) return -ENETDOWN; + if (!netif_carrier_ok(adapter->netdev) || + !netif_running(adapter->netdev)) + return -ENETDOWN; + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) return -EINVAL; From 1468c1f97cf32418e34dbb40b784ed9333b9e123 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Tue, 19 Aug 2025 15:19:59 -0700 Subject: [PATCH 0448/1292] igc: fix disabling L1.2 PCI-E link substate on I226 on init Device ID comparison in igc_is_device_id_i226 is performed before the ID is set, resulting in always failing check on init. Before the patch: * L1.2 is not disabled on init * L1.2 is properly disabled after suspend-resume cycle With the patch: * L1.2 is properly disabled both on init and after suspend-resume How to test: Connect to the 1G link with 300+ mbit/s Internet speed, and run the download speed test, such as: curl -o /dev/null http://speedtest.selectel.ru/1GB Without L1.2 disabled, the speed would be no more than ~200 mbit/s. With L1.2 disabled, the speed would reach 1 gbit/s. Note: it's required that the latency between your host and the remote be around 3-5 ms, the test inside LAN (<1 ms latency) won't trigger the issue. Link: https://lore.kernel.org/intel-wired-lan/15248b4f-3271-42dd-8e35-02bfc92b25e1@intel.com Fixes: 0325143b59c6 ("igc: disable L1.2 PCI-E link substate to avoid performance issue") Signed-off-by: ValdikSS Reviewed-by: Vitaly Lifshits Reviewed-by: Paul Menzel Signed-off-by: Tony Nguyen Link: https://patch.msgid.link/20250819222000.3504873-6-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/igc/igc_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 458e5eaa92e56e..e79b14d50b2405 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -7149,6 +7149,13 @@ static int igc_probe(struct pci_dev *pdev, adapter->port_num = hw->bus.func; adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); + /* PCI config space info */ + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->revision_id = pdev->revision; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + /* Disable ASPM L1.2 on I226 devices to avoid packet loss */ if (igc_is_device_id_i226(hw)) pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2); @@ -7175,13 +7182,6 @@ static int igc_probe(struct pci_dev *pdev, netdev->mem_start = pci_resource_start(pdev, 0); netdev->mem_end = pci_resource_end(pdev, 0); - /* PCI config space info */ - hw->vendor_id = pdev->vendor; - hw->device_id = pdev->device; - hw->revision_id = pdev->revision; - hw->subsystem_vendor_id = pdev->subsystem_vendor; - hw->subsystem_device_id = pdev->subsystem_device; - /* Copy the default MAC and PHY function pointers */ memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops)); From e318cd6714592fb762fcab59c5684a442243a12f Mon Sep 17 00:00:00 2001 From: Tristram Ha Date: Mon, 18 Aug 2025 18:04:57 -0700 Subject: [PATCH 0449/1292] net: dsa: microchip: Fix KSZ9477 HSR port setup issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ksz9477_hsr_join() is called once to setup the HSR port membership, but the port can be enabled later, or disabled and enabled back and the port membership is not set correctly inside ksz_update_port_member(). The added code always use the correct HSR port membership for HSR port that is enabled. Fixes: 2d61298fdd7b ("net: dsa: microchip: Enable HSR offloading for KSZ9477") Reported-by: Frieder Schrempf Signed-off-by: Tristram Ha Reviewed-by: Łukasz Majewski Tested-by: Frieder Schrempf Reviewed-by: Frieder Schrempf Link: https://patch.msgid.link/20250819010457.563286-1-Tristram.Ha@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 4cb14288ff0f6d..9568cc391fe3ec 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2457,6 +2457,12 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) dev->dev_ops->cfg_port_member(dev, i, val | cpu_port); } + /* HSR ports are setup once so need to use the assigned membership + * when the port is enabled. + */ + if (!port_member && p->stp_state == BR_STATE_FORWARDING && + (dev->hsr_ports & BIT(port))) + port_member = dev->hsr_ports; dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port); } From 15de71d06a400f7fdc15bf377a2552b0ec437cf5 Mon Sep 17 00:00:00 2001 From: William Liu Date: Tue, 19 Aug 2025 03:36:28 +0000 Subject: [PATCH 0450/1292] net/sched: Make cake_enqueue return NET_XMIT_CN when past buffer_limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following setup can trigger a WARNING in htb_activate due to the condition: !cl->leaf.q->q.qlen tc qdisc del dev lo root tc qdisc add dev lo root handle 1: htb default 1 tc class add dev lo parent 1: classid 1:1 \ htb rate 64bit tc qdisc add dev lo parent 1:1 handle f: \ cake memlimit 1b ping -I lo -f -c1 -s64 -W0.001 127.0.0.1 This is because the low memlimit leads to a low buffer_limit, which causes packet dropping. However, cake_enqueue still returns NET_XMIT_SUCCESS, causing htb_enqueue to call htb_activate with an empty child qdisc. We should return NET_XMIT_CN when packets are dropped from the same tin and flow. I do not believe return value of NET_XMIT_CN is necessary for packet drops in the case of ack filtering, as that is meant to optimize performance, not to signal congestion. Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") Signed-off-by: William Liu Reviewed-by: Savino Dicanosa Acked-by: Toke HĆøiland-JĆørgensen Reviewed-by: Jamal Hadi Salim Link: https://patch.msgid.link/20250819033601.579821-1-will@willsroot.io Signed-off-by: Jakub Kicinski --- net/sched/sch_cake.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index dbcfb948c86707..32bacfc314c260 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1750,7 +1750,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, ktime_t now = ktime_get(); struct cake_tin_data *b; struct cake_flow *flow; - u32 idx; + u32 idx, tin; /* choose flow to insert into */ idx = cake_classify(sch, &b, skb, q->flow_mode, &ret); @@ -1760,6 +1760,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, __qdisc_drop(skb, to_free); return ret; } + tin = (u32)(b - q->tins); idx--; flow = &b->flows[idx]; @@ -1927,13 +1928,22 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, q->buffer_max_used = q->buffer_used; if (q->buffer_used > q->buffer_limit) { + bool same_flow = false; u32 dropped = 0; + u32 drop_id; while (q->buffer_used > q->buffer_limit) { dropped++; - cake_drop(sch, to_free); + drop_id = cake_drop(sch, to_free); + + if ((drop_id >> 16) == tin && + (drop_id & 0xFFFF) == idx) + same_flow = true; } b->drop_overlimit += dropped; + + if (same_flow) + return NET_XMIT_CN; } return NET_XMIT_SUCCESS; } From 2c2192e5f9c7c2892fe2363244d1387f62710d83 Mon Sep 17 00:00:00 2001 From: William Liu Date: Tue, 19 Aug 2025 03:36:59 +0000 Subject: [PATCH 0451/1292] net/sched: Remove unnecessary WARNING condition for empty child qdisc in htb_activate The WARN_ON trigger based on !cl->leaf.q->q.qlen is unnecessary in htb_activate. htb_dequeue_tree already accounts for that scenario. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: William Liu Reviewed-by: Savino Dicanosa Link: https://patch.msgid.link/20250819033632.579854-1-will@willsroot.io Signed-off-by: Jakub Kicinski --- net/sched/sch_htb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index c968ea76377463..b5e40c51655a73 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -592,7 +592,7 @@ htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, s64 *diff) */ static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) { - WARN_ON(cl->level || !cl->leaf.q || !cl->leaf.q->q.qlen); + WARN_ON(cl->level || !cl->leaf.q); if (!cl->prio_activity) { cl->prio_activity = 1 << cl->prio; From 7af76e9d18a9fd6f8611b3313c86c190f9b6a5a7 Mon Sep 17 00:00:00 2001 From: Jakub Acs Date: Tue, 19 Aug 2025 08:28:42 +0000 Subject: [PATCH 0452/1292] net, hsr: reject HSR frame if skb can't hold tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Receiving HSR frame with insufficient space to hold HSR tag in the skb can result in a crash (kernel BUG): [ 45.390915] skbuff: skb_under_panic: text:ffffffff86f32cac len:26 put:14 head:ffff888042418000 data:ffff888042417ff4 tail:0xe end:0x180 dev:bridge_slave_1 [ 45.392559] ------------[ cut here ]------------ [ 45.392912] kernel BUG at net/core/skbuff.c:211! [ 45.393276] Oops: invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN NOPTI [ 45.393809] CPU: 1 UID: 0 PID: 2496 Comm: reproducer Not tainted 6.15.0 #12 PREEMPT(undef) [ 45.394433] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 [ 45.395273] RIP: 0010:skb_panic+0x15b/0x1d0 [ 45.402911] Call Trace: [ 45.403105] [ 45.404470] skb_push+0xcd/0xf0 [ 45.404726] br_dev_queue_push_xmit+0x7c/0x6c0 [ 45.406513] br_forward_finish+0x128/0x260 [ 45.408483] __br_forward+0x42d/0x590 [ 45.409464] maybe_deliver+0x2eb/0x420 [ 45.409763] br_flood+0x174/0x4a0 [ 45.410030] br_handle_frame_finish+0xc7c/0x1bc0 [ 45.411618] br_handle_frame+0xac3/0x1230 [ 45.413674] __netif_receive_skb_core.constprop.0+0x808/0x3df0 [ 45.422966] __netif_receive_skb_one_core+0xb4/0x1f0 [ 45.424478] __netif_receive_skb+0x22/0x170 [ 45.424806] process_backlog+0x242/0x6d0 [ 45.425116] __napi_poll+0xbb/0x630 [ 45.425394] net_rx_action+0x4d1/0xcc0 [ 45.427613] handle_softirqs+0x1a4/0x580 [ 45.427926] do_softirq+0x74/0x90 [ 45.428196] This issue was found by syzkaller. The panic happens in br_dev_queue_push_xmit() once it receives a corrupted skb with ETH header already pushed in linear data. When it attempts the skb_push() call, there's not enough headroom and skb_push() panics. The corrupted skb is put on the queue by HSR layer, which makes a sequence of unintended transformations when it receives a specific corrupted HSR frame (with incomplete TAG). Fix it by dropping and consuming frames that are not long enough to contain both ethernet and hsr headers. Alternative fix would be to check for enough headroom before skb_push() in br_dev_queue_push_xmit(). In the reproducer, this is injected via AF_PACKET, but I don't easily see why it couldn't be sent over the wire from adjacent network. Further Details: In the reproducer, the following network interface chain is set up: ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ veth0_to_hsr ā”œā”€ā”€ā”€ā”¤ hsr_slave0 ┼───┐ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ │ │ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā” ā”œā”€ā”¤ hsr0 ā”œā”€ā”€ā”€ā” │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ │ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ ā”‚ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ veth1_to_hsr ┼───┤ hsr_slave1 ā”œā”€ā”€ā”€ā”˜ └┤ │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā”Œā”¼ bridge │ ││ │ ā”‚ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ │ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ │ ... ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ To trigger the events leading up to crash, reproducer sends a corrupted HSR frame with incomplete TAG, via AF_PACKET socket on 'veth0_to_hsr'. The first HSR-layer function to process this frame is hsr_handle_frame(). It and then checks if the protocol is ETH_P_PRP or ETH_P_HSR. If it is, it calls skb_set_network_header(skb, ETH_HLEN + HSR_HLEN), without checking that the skb is long enough. For the crashing frame it is not, and hence the skb->network_header and skb->mac_len fields are set incorrectly, pointing after the end of the linear buffer. I will call this a BUG#1 and it is what is addressed by this patch. In the crashing scenario before the fix, the skb continues to go down the hsr path as follows. hsr_handle_frame() then calls this sequence hsr_forward_skb() fill_frame_info() hsr->proto_ops->fill_frame_info() hsr_fill_frame_info() hsr_fill_frame_info() contains a check that intends to check whether the skb actually contains the HSR header. But the check relies on the skb->mac_len field which was erroneously setup due to BUG#1, so the check passes and the execution continues back in the hsr_forward_skb(): hsr_forward_skb() hsr_forward_do() hsr->proto_ops->get_untagged_frame() hsr_get_untagged_frame() create_stripped_skb_hsr() In create_stripped_skb_hsr(), a copy of the skb is created and is further corrupted by operation that attempts to strip the HSR tag in a call to __pskb_copy(). The skb enters create_stripped_skb_hsr() with ethernet header pushed in linear buffer. The skb_pull(skb_in, HSR_HLEN) thus pulls 6 bytes of ethernet header into the headroom, creating skb_in with a headroom of size 8. The subsequent __pskb_copy() then creates an skb with headroom of just 2 and skb->len of just 12, this is how it looks after the copy: gdb) p skb->len $10 = 12 (gdb) p skb->data $11 = (unsigned char *) 0xffff888041e45382 "\252\252\252\252\252!\210\373", (gdb) p skb->head $12 = (unsigned char *) 0xffff888041e45380 "" It seems create_stripped_skb_hsr() assumes that ETH header is pulled in the headroom when it's entered, because it just pulls HSR header on top. But that is not the case in our code-path and we end up with the corrupted skb instead. I will call this BUG#2 *I got confused here because it seems that under no conditions can create_stripped_skb_hsr() work well, the assumption it makes is not true during the processing of hsr frames - since the skb_push() in hsr_handle_frame to skb_pull in hsr_deliver_master(). I wonder whether I missed something here.* Next, the execution arrives in hsr_deliver_master(). It calls skb_pull(ETH_HLEN), which just returns NULL - the SKB does not have enough space for the pull (as it only has 12 bytes in total at this point). *The skb_pull() here further suggests that ethernet header is meant to be pushed through the whole hsr processing and create_stripped_skb_hsr() should pull it before doing the HSR header pull.* hsr_deliver_master() then puts the corrupted skb on the queue, it is then picked up from there by bridge frame handling layer and finally lands in br_dev_queue_push_xmit where it panics. Cc: stable@kernel.org Fixes: 48b491a5cc74 ("net: hsr: fix mac_len checks") Reported-by: syzbot+a81f2759d022496b40ab@syzkaller.appspotmail.com Signed-off-by: Jakub Acs Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20250819082842.94378-1-acsjakub@amazon.de Signed-off-by: Jakub Kicinski --- net/hsr/hsr_slave.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index b87b6a6fe07000..102eccf5ead734 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -63,8 +63,14 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) skb_push(skb, ETH_HLEN); skb_reset_mac_header(skb); if ((!hsr->prot_version && protocol == htons(ETH_P_PRP)) || - protocol == htons(ETH_P_HSR)) + protocol == htons(ETH_P_HSR)) { + if (!pskb_may_pull(skb, ETH_HLEN + HSR_HLEN)) { + kfree_skb(skb); + goto finish_consume; + } + skb_set_network_header(skb, ETH_HLEN + HSR_HLEN); + } skb_reset_mac_len(skb); /* Only the frames received over the interlink port will assign a From a458b2902115b26a25d67393b12ddd57d1216aaa Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Aug 2025 13:27:24 -0700 Subject: [PATCH 0453/1292] ipv6: sr: Fix MAC comparison to be constant-time To prevent timing attacks, MACs need to be compared in constant time. Use the appropriate helper function for this. Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Reviewed-by: Andrea Mayer Link: https://patch.msgid.link/20250818202724.15713-1-ebiggers@kernel.org Signed-off-by: Jakub Kicinski --- net/ipv6/seg6_hmac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c index d77b52523b6a8a..fd58426f222beb 100644 --- a/net/ipv6/seg6_hmac.c +++ b/net/ipv6/seg6_hmac.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -280,7 +281,7 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb) if (seg6_hmac_compute(hinfo, srh, &ipv6_hdr(skb)->saddr, hmac_output)) return false; - if (memcmp(hmac_output, tlv->hmac, SEG6_HMAC_FIELD_LEN) != 0) + if (crypto_memneq(hmac_output, tlv->hmac, SEG6_HMAC_FIELD_LEN)) return false; return true; From c42be534547d6e45c155c347dd792b6ad9c24def Mon Sep 17 00:00:00 2001 From: Ryan Wanner Date: Tue, 19 Aug 2025 09:32:30 -0700 Subject: [PATCH 0454/1292] Revert "net: cadence: macb: sama7g5_emac: Remove USARIO CLKEN flag" This reverts commit db400061b5e7cc55f9b4dd15443e9838964119ea. This commit can cause a Devicetree ABI break for older DTS files that rely this flag for RMII configuration. Adding this back in ensures that the older DTBs will not break. Fixes: db400061b5e7 ("net: cadence: macb: sama7g5_emac: Remove USARIO CLKEN flag") Signed-off-by: Ryan Wanner Link: https://patch.msgid.link/20250819163236.100680-1-Ryan.Wanner@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/cadence/macb_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index ce95fad8cedd73..9693f028943569 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -5113,7 +5113,8 @@ static const struct macb_config sama7g5_gem_config = { static const struct macb_config sama7g5_emac_config = { .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | - MACB_CAPS_MIIONRGMII | MACB_CAPS_GEM_HAS_PTP, + MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_MIIONRGMII | + MACB_CAPS_GEM_HAS_PTP, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, From 5003a65790ed66be882d1987cc2ca86af0de3db1 Mon Sep 17 00:00:00 2001 From: Dewei Meng Date: Thu, 21 Aug 2025 09:43:17 +0800 Subject: [PATCH 0455/1292] ALSA: timer: fix ida_free call while not allocated In the snd_utimer_create() function, if the kasprintf() function return NULL, snd_utimer_put_id() will be called, finally use ida_free() to free the unallocated id 0. the syzkaller reported the following information: ------------[ cut here ]------------ ida_free called for id=0 which is not allocated. WARNING: CPU: 1 PID: 1286 at lib/idr.c:592 ida_free+0x1fd/0x2f0 lib/idr.c:592 Modules linked in: CPU: 1 UID: 0 PID: 1286 Comm: syz-executor164 Not tainted 6.15.8 #3 PREEMPT(lazy) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-4.fc42 04/01/2014 RIP: 0010:ida_free+0x1fd/0x2f0 lib/idr.c:592 Code: f8 fc 41 83 fc 3e 76 69 e8 70 b2 f8 (...) RSP: 0018:ffffc900007f79c8 EFLAGS: 00010282 RAX: 0000000000000000 RBX: 1ffff920000fef3b RCX: ffffffff872176a5 RDX: ffff88800369d200 RSI: 0000000000000000 RDI: ffff88800369d200 RBP: 0000000000000000 R08: ffffffff87ba60a5 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000002 R14: 0000000000000000 R15: 0000000000000000 FS: 00007f6f1abc1740(0000) GS:ffff8880d76a0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f6f1ad7a784 CR3: 000000007a6e2000 CR4: 00000000000006f0 Call Trace: snd_utimer_put_id sound/core/timer.c:2043 [inline] [snd_timer] snd_utimer_create+0x59b/0x6a0 sound/core/timer.c:2184 [snd_timer] snd_utimer_ioctl_create sound/core/timer.c:2202 [inline] [snd_timer] __snd_timer_user_ioctl.isra.0+0x724/0x1340 sound/core/timer.c:2287 [snd_timer] snd_timer_user_ioctl+0x75/0xc0 sound/core/timer.c:2298 [snd_timer] vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:907 [inline] __se_sys_ioctl fs/ioctl.c:893 [inline] __x64_sys_ioctl+0x198/0x200 fs/ioctl.c:893 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x7b/0x160 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e [...] The utimer->id should be set properly before the kasprintf() function, ensures the snd_utimer_put_id() function will free the allocated id. Fixes: 37745918e0e75 ("ALSA: timer: Introduce virtual userspace-driven timers") Signed-off-by: Dewei Meng Link: https://patch.msgid.link/20250821014317.40786-1-mengdewei@cqsoftware.com.cn Signed-off-by: Takashi Iwai --- sound/core/timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/timer.c b/sound/core/timer.c index 3ce12264eed8a9..d9fff5c87613ef 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -2139,14 +2139,14 @@ static int snd_utimer_create(struct snd_timer_uinfo *utimer_info, goto err_take_id; } + utimer->id = utimer_id; + utimer->name = kasprintf(GFP_KERNEL, "snd-utimer%d", utimer_id); if (!utimer->name) { err = -ENOMEM; goto err_get_name; } - utimer->id = utimer_id; - tid.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL; tid.card = -1; From b64d035f77b1f02ab449393342264b44950a75ae Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 15 Aug 2025 06:19:58 +0000 Subject: [PATCH 0456/1292] bonding: update LACP activity flag after setting lacp_active The port's actor_oper_port_state activity flag should be updated immediately after changing the lacp_active option to reflect the current mode correctly. Fixes: 3a755cd8b7c6 ("bonding: add new option lacp_active") Signed-off-by: Hangbin Liu Link: https://patch.msgid.link/20250815062000.22220-2-liuhangbin@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/bonding/bond_3ad.c | 25 +++++++++++++++++++++++++ drivers/net/bonding/bond_options.c | 1 + include/net/bond_3ad.h | 1 + 3 files changed, 27 insertions(+) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 2fca8e84ab100b..414fecfd2a0ee1 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2883,6 +2883,31 @@ void bond_3ad_update_lacp_rate(struct bonding *bond) spin_unlock_bh(&bond->mode_lock); } +/** + * bond_3ad_update_lacp_active - change the lacp active + * @bond: bonding struct + * + * Update actor_oper_port_state when lacp_active is modified. + */ +void bond_3ad_update_lacp_active(struct bonding *bond) +{ + struct port *port = NULL; + struct list_head *iter; + struct slave *slave; + int lacp_active; + + lacp_active = bond->params.lacp_active; + spin_lock_bh(&bond->mode_lock); + bond_for_each_slave(bond, slave, iter) { + port = &(SLAVE_AD_INFO(slave)->port); + if (lacp_active) + port->actor_oper_port_state |= LACP_STATE_LACP_ACTIVITY; + else + port->actor_oper_port_state &= ~LACP_STATE_LACP_ACTIVITY; + } + spin_unlock_bh(&bond->mode_lock); +} + size_t bond_3ad_stats_size(void) { return nla_total_size_64bit(sizeof(u64)) + /* BOND_3AD_STAT_LACPDU_RX */ diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1d639a3be6bac8..3b6f815c55ffaa 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -1660,6 +1660,7 @@ static int bond_option_lacp_active_set(struct bonding *bond, netdev_dbg(bond->dev, "Setting LACP active to %s (%llu)\n", newval->string, newval->value); bond->params.lacp_active = newval->value; + bond_3ad_update_lacp_active(bond); return 0; } diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h index 2053cd8e788a73..dba369a2cf27ef 100644 --- a/include/net/bond_3ad.h +++ b/include/net/bond_3ad.h @@ -307,6 +307,7 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave); int bond_3ad_set_carrier(struct bonding *bond); void bond_3ad_update_lacp_rate(struct bonding *bond); +void bond_3ad_update_lacp_active(struct bonding *bond); void bond_3ad_update_ad_actor_settings(struct bonding *bond); int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats); size_t bond_3ad_stats_size(void); From 0599640a21e98f0d6a3e9ff85c0a687c90a8103b Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 15 Aug 2025 06:19:59 +0000 Subject: [PATCH 0457/1292] bonding: send LACPDUs periodically in passive mode after receiving partner's LACPDU When `lacp_active` is set to `off`, the bond operates in passive mode, meaning it only "speaks when spoken to." However, the current kernel implementation only sends an LACPDU in response when the partner's state changes. As a result, once LACP negotiation succeeds, the actor stops sending LACPDUs until the partner times out and sends an "expired" LACPDU. This causes continuous LACP state flapping. According to IEEE 802.1AX-2014, 6.4.13 Periodic Transmission machine. The values of Partner_Oper_Port_State.LACP_Activity and Actor_Oper_Port_State.LACP_Activity determine whether periodic transmissions take place. If either or both parameters are set to Active LACP, then periodic transmissions occur; if both are set to Passive LACP, then periodic transmissions do not occur. To comply with this, we remove the `!bond->params.lacp_active` check in `ad_periodic_machine()`. Instead, we initialize the actor's port's `LACP_STATE_LACP_ACTIVITY` state based on `lacp_active` setting. Additionally, we avoid setting the partner's state to `LACP_STATE_LACP_ACTIVITY` in the EXPIRED state, since we should not assume the partner is active by default. This ensures that in passive mode, the bond starts sending periodic LACPDUs after receiving one from the partner, and avoids flapping due to inactivity. Fixes: 3a755cd8b7c6 ("bonding: add new option lacp_active") Signed-off-by: Hangbin Liu Link: https://patch.msgid.link/20250815062000.22220-3-liuhangbin@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/bonding/bond_3ad.c | 42 +++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 414fecfd2a0ee1..4edc8e6b6b649f 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -95,13 +95,13 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker); static void ad_mux_machine(struct port *port, bool *update_slave_arr); static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port); static void ad_tx_machine(struct port *port); -static void ad_periodic_machine(struct port *port, struct bond_params *bond_params); +static void ad_periodic_machine(struct port *port); static void ad_port_selection_logic(struct port *port, bool *update_slave_arr); static void ad_agg_selection_logic(struct aggregator *aggregator, bool *update_slave_arr); static void ad_clear_agg(struct aggregator *aggregator); static void ad_initialize_agg(struct aggregator *aggregator); -static void ad_initialize_port(struct port *port, int lacp_fast); +static void ad_initialize_port(struct port *port, const struct bond_params *bond_params); static void ad_enable_collecting(struct port *port); static void ad_disable_distributing(struct port *port, bool *update_slave_arr); @@ -1307,10 +1307,16 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) * case of EXPIRED even if LINK_DOWN didn't arrive for * the port. */ - port->partner_oper.port_state &= ~LACP_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; + /* Based on IEEE 8021AX-2014, Figure 6-18 - Receive + * machine state diagram, the statue should be + * Partner_Oper_Port_State.Synchronization = FALSE; + * Partner_Oper_Port_State.LACP_Timeout = Short Timeout; + * start current_while_timer(Short Timeout); + * Actor_Oper_Port_State.Expired = TRUE; + */ + port->partner_oper.port_state &= ~LACP_STATE_SYNCHRONIZATION; port->partner_oper.port_state |= LACP_STATE_LACP_TIMEOUT; - port->partner_oper.port_state |= LACP_STATE_LACP_ACTIVITY; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= LACP_STATE_EXPIRED; port->sm_vars |= AD_PORT_CHURNED; @@ -1417,11 +1423,10 @@ static void ad_tx_machine(struct port *port) /** * ad_periodic_machine - handle a port's periodic state machine * @port: the port we're looking at - * @bond_params: bond parameters we will use * * Turn ntt flag on priodically to perform periodic transmission of lacpdu's. */ -static void ad_periodic_machine(struct port *port, struct bond_params *bond_params) +static void ad_periodic_machine(struct port *port) { periodic_states_t last_state; @@ -1430,8 +1435,7 @@ static void ad_periodic_machine(struct port *port, struct bond_params *bond_para /* check if port was reinitialized */ if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) || - (!(port->actor_oper_port_state & LACP_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & LACP_STATE_LACP_ACTIVITY)) || - !bond_params->lacp_active) { + (!(port->actor_oper_port_state & LACP_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & LACP_STATE_LACP_ACTIVITY))) { port->sm_periodic_state = AD_NO_PERIODIC; } /* check if state machine should change state */ @@ -1955,16 +1959,16 @@ static void ad_initialize_agg(struct aggregator *aggregator) /** * ad_initialize_port - initialize a given port's parameters * @port: the port we're looking at - * @lacp_fast: boolean. whether fast periodic should be used + * @bond_params: bond parameters we will use */ -static void ad_initialize_port(struct port *port, int lacp_fast) +static void ad_initialize_port(struct port *port, const struct bond_params *bond_params) { static const struct port_params tmpl = { .system_priority = 0xffff, .key = 1, .port_number = 1, .port_priority = 0xff, - .port_state = 1, + .port_state = 0, }; static const struct lacpdu lacpdu = { .subtype = 0x01, @@ -1982,12 +1986,14 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->actor_port_priority = 0xff; port->actor_port_aggregator_identifier = 0; port->ntt = false; - port->actor_admin_port_state = LACP_STATE_AGGREGATION | - LACP_STATE_LACP_ACTIVITY; - port->actor_oper_port_state = LACP_STATE_AGGREGATION | - LACP_STATE_LACP_ACTIVITY; + port->actor_admin_port_state = LACP_STATE_AGGREGATION; + port->actor_oper_port_state = LACP_STATE_AGGREGATION; + if (bond_params->lacp_active) { + port->actor_admin_port_state |= LACP_STATE_LACP_ACTIVITY; + port->actor_oper_port_state |= LACP_STATE_LACP_ACTIVITY; + } - if (lacp_fast) + if (bond_params->lacp_fast) port->actor_oper_port_state |= LACP_STATE_LACP_TIMEOUT; memcpy(&port->partner_admin, &tmpl, sizeof(tmpl)); @@ -2201,7 +2207,7 @@ void bond_3ad_bind_slave(struct slave *slave) /* port initialization */ port = &(SLAVE_AD_INFO(slave)->port); - ad_initialize_port(port, bond->params.lacp_fast); + ad_initialize_port(port, &bond->params); port->slave = slave; port->actor_port_number = SLAVE_AD_INFO(slave)->id; @@ -2513,7 +2519,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work) } ad_rx_machine(NULL, port); - ad_periodic_machine(port, &bond->params); + ad_periodic_machine(port); ad_port_selection_logic(port, &update_slave_arr); ad_mux_machine(port, &update_slave_arr); ad_tx_machine(port); From 87951b566446da04eed1fe8100f99a512ef02756 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 15 Aug 2025 06:20:00 +0000 Subject: [PATCH 0458/1292] selftests: bonding: add test for passive LACP mode Add a selftest to verify bonding behavior when `lacp_active` is set to `off`. The test checks the following: - The passive LACP bond should not send LACPDUs before receiving a partner's LACPDU. - The transmitted LACPDUs must not include the active flag. - After transitioning to EXPIRED and DEFAULTED states, the passive side should still not initiate LACPDUs. Signed-off-by: Hangbin Liu Link: https://patch.msgid.link/20250815062000.22220-4-liuhangbin@gmail.com Signed-off-by: Paolo Abeni --- .../selftests/drivers/net/bonding/Makefile | 3 +- .../drivers/net/bonding/bond_passive_lacp.sh | 105 ++++++++++++++++++ .../selftests/drivers/net/bonding/config | 1 + 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100755 tools/testing/selftests/drivers/net/bonding/bond_passive_lacp.sh diff --git a/tools/testing/selftests/drivers/net/bonding/Makefile b/tools/testing/selftests/drivers/net/bonding/Makefile index 2b10854e4b1e3b..44b98f17f8ff57 100644 --- a/tools/testing/selftests/drivers/net/bonding/Makefile +++ b/tools/testing/selftests/drivers/net/bonding/Makefile @@ -10,7 +10,8 @@ TEST_PROGS := \ mode-2-recovery-updelay.sh \ bond_options.sh \ bond-eth-type-change.sh \ - bond_macvlan_ipvlan.sh + bond_macvlan_ipvlan.sh \ + bond_passive_lacp.sh TEST_FILES := \ lag_lib.sh \ diff --git a/tools/testing/selftests/drivers/net/bonding/bond_passive_lacp.sh b/tools/testing/selftests/drivers/net/bonding/bond_passive_lacp.sh new file mode 100755 index 00000000000000..9c3b089813dfc6 --- /dev/null +++ b/tools/testing/selftests/drivers/net/bonding/bond_passive_lacp.sh @@ -0,0 +1,105 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Test if a bond interface works with lacp_active=off. + +# shellcheck disable=SC2034 +REQUIRE_MZ=no +NUM_NETIFS=0 +lib_dir=$(dirname "$0") +# shellcheck disable=SC1091 +source "$lib_dir"/../../../net/forwarding/lib.sh + +# shellcheck disable=SC2317 +check_port_state() +{ + local netns=$1 + local port=$2 + local state=$3 + + ip -n "${netns}" -d -j link show "$port" | \ + jq -e ".[].linkinfo.info_slave_data.ad_actor_oper_port_state_str | index(\"${state}\") != null" > /dev/null +} + +check_pkt_count() +{ + RET=0 + local ns="$1" + local iface="$2" + + # wait 65s, one per 30s + slowwait_for_counter 65 2 tc_rule_handle_stats_get \ + "dev ${iface} egress" 101 ".packets" "-n ${ns}" &> /dev/null +} + +setup() { + setup_ns c_ns s_ns + + # shellcheck disable=SC2154 + ip -n "${c_ns}" link add eth0 type veth peer name eth0 netns "${s_ns}" + ip -n "${c_ns}" link add eth1 type veth peer name eth1 netns "${s_ns}" + + # Add tc filter to count the pkts + tc -n "${c_ns}" qdisc add dev eth0 clsact + tc -n "${c_ns}" filter add dev eth0 egress handle 101 protocol 0x8809 matchall action pass + tc -n "${s_ns}" qdisc add dev eth1 clsact + tc -n "${s_ns}" filter add dev eth1 egress handle 101 protocol 0x8809 matchall action pass + + ip -n "${s_ns}" link add bond0 type bond mode 802.3ad lacp_active on lacp_rate fast + ip -n "${s_ns}" link set eth0 master bond0 + ip -n "${s_ns}" link set eth1 master bond0 + + ip -n "${c_ns}" link add bond0 type bond mode 802.3ad lacp_active off lacp_rate fast + ip -n "${c_ns}" link set eth0 master bond0 + ip -n "${c_ns}" link set eth1 master bond0 + +} + +trap cleanup_all_ns EXIT +setup + +# The bond will send 2 lacpdu pkts during init time, let's wait at least 2s +# after interface up +ip -n "${c_ns}" link set bond0 up +sleep 2 + +# 1. The passive side shouldn't send LACPDU. +check_pkt_count "${c_ns}" "eth0" && RET=1 +log_test "802.3ad lacp_active off" "init port" + +ip -n "${s_ns}" link set bond0 up +# 2. The passive side should not have the 'active' flag. +RET=0 +slowwait 2 check_port_state "${c_ns}" "eth0" "active" && RET=1 +log_test "802.3ad lacp_active off" "port state active" + +# 3. The active side should have the 'active' flag. +RET=0 +slowwait 2 check_port_state "${s_ns}" "eth0" "active" || RET=1 +log_test "802.3ad lacp_active on" "port state active" + +# 4. Make sure the connection is not expired. +RET=0 +slowwait 5 check_port_state "${s_ns}" "eth0" "distributing" +slowwait 10 check_port_state "${s_ns}" "eth0" "expired" && RET=1 +log_test "bond 802.3ad lacp_active off" "port connection" + +# After testing, disconnect one port on each side to check the state. +ip -n "${s_ns}" link set eth0 nomaster +ip -n "${s_ns}" link set eth0 up +ip -n "${c_ns}" link set eth1 nomaster +ip -n "${c_ns}" link set eth1 up +# Due to Periodic Machine and Rx Machine state change, the bond will still +# send lacpdu pkts in a few seconds. sleep at lease 5s to make sure +# negotiation finished +sleep 5 + +# 5. The active side should keep sending LACPDU. +check_pkt_count "${s_ns}" "eth1" || RET=1 +log_test "bond 802.3ad lacp_active on" "port pkt after disconnect" + +# 6. The passive side shouldn't send LACPDU anymore. +check_pkt_count "${c_ns}" "eth0" && RET=1 +log_test "bond 802.3ad lacp_active off" "port pkt after disconnect" + +exit "$EXIT_STATUS" diff --git a/tools/testing/selftests/drivers/net/bonding/config b/tools/testing/selftests/drivers/net/bonding/config index dad4e5fda4db3b..4d16a69ffc6507 100644 --- a/tools/testing/selftests/drivers/net/bonding/config +++ b/tools/testing/selftests/drivers/net/bonding/config @@ -6,6 +6,7 @@ CONFIG_MACVLAN=y CONFIG_IPVLAN=y CONFIG_NET_ACT_GACT=y CONFIG_NET_CLS_FLOWER=y +CONFIG_NET_CLS_MATCHALL=m CONFIG_NET_SCH_INGRESS=y CONFIG_NLMON=y CONFIG_VETH=y From d2d7a96b29ea6ab093973a1a37d26126db70c79f Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Wed, 20 Aug 2025 14:30:47 -0500 Subject: [PATCH 0459/1292] mmc: sdhci_am654: Disable HS400 for AM62P SR1.0 and SR1.1 This adds SDHCI_AM654_QUIRK_DISABLE_HS400 quirk which shall be used to disable HS400 support. AM62P SR1.0 and SR1.1 do not support HS400 due to errata i2458 [0] so disable HS400 for these SoC revisions. [0] https://www.ti.com/lit/er/sprz574a/sprz574a.pdf Fixes: 37f28165518f ("arm64: dts: ti: k3-am62p: Add ITAP/OTAP values for MMC") Cc: stable@vger.kernel.org Signed-off-by: Judith Mendez Reviewed-by: Andrew Davis Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20250820193047.4064142-1-jm@ti.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index e4fc345be7e5d3..17e62c61b6e688 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -156,6 +156,7 @@ struct sdhci_am654_data { #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) #define SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA BIT(1) +#define SDHCI_AM654_QUIRK_DISABLE_HS400 BIT(2) }; struct window { @@ -765,6 +766,7 @@ static int sdhci_am654_init(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + struct device *dev = mmc_dev(host->mmc); u32 ctl_cfg_2 = 0; u32 mask; u32 val; @@ -820,6 +822,12 @@ static int sdhci_am654_init(struct sdhci_host *host) if (ret) goto err_cleanup_host; + if (sdhci_am654->quirks & SDHCI_AM654_QUIRK_DISABLE_HS400 && + host->mmc->caps2 & (MMC_CAP2_HS400 | MMC_CAP2_HS400_ES)) { + dev_info(dev, "HS400 mode not supported on this silicon revision, disabling it\n"); + host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); + } + ret = __sdhci_add_host(host); if (ret) goto err_cleanup_host; @@ -883,6 +891,12 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev, return 0; } +static const struct soc_device_attribute sdhci_am654_descope_hs400[] = { + { .family = "AM62PX", .revision = "SR1.0" }, + { .family = "AM62PX", .revision = "SR1.1" }, + { /* sentinel */ } +}; + static const struct of_device_id sdhci_am654_of_match[] = { { .compatible = "ti,am654-sdhci-5.1", @@ -970,6 +984,10 @@ static int sdhci_am654_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "parsing dt failed\n"); + soc = soc_device_match(sdhci_am654_descope_hs400); + if (soc) + sdhci_am654->quirks |= SDHCI_AM654_QUIRK_DISABLE_HS400; + host->mmc_host_ops.start_signal_voltage_switch = sdhci_am654_start_signal_voltage_switch; host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; From 9f6b606b6b37e61427412708411e8e04b1a858e8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 18 Aug 2025 11:58:25 +0200 Subject: [PATCH 0460/1292] net: airoha: ppe: Do not invalid PPE entries in case of SW hash collision SW hash computed by airoha_ppe_foe_get_entry_hash routine (used for foe_flow hlist) can theoretically produce collisions between two different HW PPE entries. In airoha_ppe_foe_insert_entry() if the collision occurs we will mark the second PPE entry in the list as stale (setting the hw hash to 0xffff). Stale entries are no more updated in airoha_ppe_foe_flow_entry_update routine and so they are removed by Netfilter. Fix the problem not marking the second entry as stale in airoha_ppe_foe_insert_entry routine if we have already inserted the brand new entry in the PPE table and let Netfilter remove real stale entries according to their timestamp. Please note this is just a theoretical issue spotted reviewing the code and not faced running the system. Fixes: cd53f622611f9 ("net: airoha: Add L2 hw acceleration support") Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250818-airoha-en7581-hash-collision-fix-v1-1-d190c4b53d1c@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/airoha/airoha_ppe.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 47411d2cbd2803..88694b08afa1ce 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -736,10 +736,8 @@ static void airoha_ppe_foe_insert_entry(struct airoha_ppe *ppe, continue; } - if (commit_done || !airoha_ppe_foe_compare_entry(e, hwe)) { - e->hash = 0xffff; + if (!airoha_ppe_foe_compare_entry(e, hwe)) continue; - } airoha_ppe_foe_commit_entry(ppe, &e->data, hash); commit_done = true; From 2d82f3bd8910eb65e30bb2a3c9b945bfb3b6d661 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 15 Aug 2025 21:17:37 +0800 Subject: [PATCH 0461/1292] blk-mq: fix lockdep warning in __blk_mq_update_nr_hw_queues Commit 5989bfe6ac6b ("block: restore two stage elevator switch while running nr_hw_queue update") reintroduced a lockdep warning by calling blk_mq_freeze_queue_nomemsave() before switching the I/O scheduler. The function blk_mq_elv_switch_none() calls elevator_change_done(). Running this while the queue is frozen causes a lockdep warning. Fix this by reordering the operations: first, switch the I/O scheduler to 'none', and then freeze the queue. This ensures that elevator_change_done() is not called on an already frozen queue. And this way is safe because elevator_set_none() does freeze queue before switching to none. Also we still have to rely on blk_mq_elv_switch_back() for switching back, and it has to cover unfrozen queue case. Cc: Nilay Shroff Cc: Yu Kuai Fixes: 5989bfe6ac6b ("block: restore two stage elevator switch while running nr_hw_queue update") Signed-off-by: Ming Lei Reviewed-by: Yu Kuai Reviewed-by: Nilay Shroff Link: https://lore.kernel.org/r/20250815131737.331692-1-ming.lei@redhat.com Signed-off-by: Jens Axboe --- block/blk-mq.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index b67d6c02ecebd9..ba3a4b77f5786e 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -5033,6 +5033,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, unsigned int memflags; int i; struct xarray elv_tbl, et_tbl; + bool queues_frozen = false; lockdep_assert_held(&set->tag_list_lock); @@ -5056,9 +5057,6 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, blk_mq_sysfs_unregister_hctxs(q); } - list_for_each_entry(q, &set->tag_list, tag_set_list) - blk_mq_freeze_queue_nomemsave(q); - /* * Switch IO scheduler to 'none', cleaning up the data associated * with the previous scheduler. We will switch back once we are done @@ -5068,6 +5066,9 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, if (blk_mq_elv_switch_none(q, &elv_tbl)) goto switch_back; + list_for_each_entry(q, &set->tag_list, tag_set_list) + blk_mq_freeze_queue_nomemsave(q); + queues_frozen = true; if (blk_mq_realloc_tag_set_tags(set, nr_hw_queues) < 0) goto switch_back; @@ -5091,8 +5092,12 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, } switch_back: /* The blk_mq_elv_switch_back unfreezes queue for us. */ - list_for_each_entry(q, &set->tag_list, tag_set_list) + list_for_each_entry(q, &set->tag_list, tag_set_list) { + /* switch_back expects queue to be frozen */ + if (!queues_frozen) + blk_mq_freeze_queue_nomemsave(q); blk_mq_elv_switch_back(q, &elv_tbl, &et_tbl); + } list_for_each_entry(q, &set->tag_list, tag_set_list) { blk_mq_sysfs_register_hctxs(q); From 7c7cda81159b1abe7d50bcef2ccc6f662e225c8b Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Wed, 20 Aug 2025 20:03:10 +0200 Subject: [PATCH 0462/1292] spi: st: fix PM macros to use CONFIG_PM instead of CONFIG_PM_SLEEP pm_sleep_ptr() depends on CONFIG_PM_SLEEP while pm_ptr() depends on CONFIG_PM. Since ST SSC4 implements runtime PM it makes sense using pm_ptr() here. For the same reason replace PM macros that use CONFIG_PM. Doing so prevents from using __maybe_unused attribute of runtime PM functions. Link: https://lore.kernel.org/lkml/CAMuHMdX9nkROkAJJ5odv4qOWe0bFTmaFs=Rfxsfuc9+DT-bsEQ@mail.gmail.com Fixes: 6f8584a4826f ("spi: st: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr()") Signed-off-by: Raphael Gallais-Pou Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250820180310.9605-1-rgallaispou@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-st-ssc4.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index 49ab4c515156fb..c07c61dc4938a7 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -378,7 +378,7 @@ static void spi_st_remove(struct platform_device *pdev) pinctrl_pm_select_sleep_state(&pdev->dev); } -static int __maybe_unused spi_st_runtime_suspend(struct device *dev) +static int spi_st_runtime_suspend(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); struct spi_st *spi_st = spi_controller_get_devdata(host); @@ -391,7 +391,7 @@ static int __maybe_unused spi_st_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused spi_st_runtime_resume(struct device *dev) +static int spi_st_runtime_resume(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); struct spi_st *spi_st = spi_controller_get_devdata(host); @@ -428,8 +428,8 @@ static int __maybe_unused spi_st_resume(struct device *dev) } static const struct dev_pm_ops spi_st_pm = { - SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume) - SET_RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume) + RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL) }; static const struct of_device_id stm_spi_match[] = { @@ -441,7 +441,7 @@ MODULE_DEVICE_TABLE(of, stm_spi_match); static struct platform_driver spi_st_driver = { .driver = { .name = "spi-st", - .pm = pm_sleep_ptr(&spi_st_pm), + .pm = pm_ptr(&spi_st_pm), .of_match_table = of_match_ptr(stm_spi_match), }, .probe = spi_st_probe, From d78e48ebe04e9566f8ecbf51471e80da3adbceeb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Aug 2025 10:31:01 +0200 Subject: [PATCH 0463/1292] ASoC: dt-bindings: Minor whitespace cleanup in example The DTS code coding style expects exactly one space around '=' character. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250821083100.46340-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,easrc.yaml | 2 +- Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml index 8f1108e7e14e27..d5727f8bfb0b56 100644 --- a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml @@ -104,6 +104,6 @@ examples: "ctx2_rx", "ctx2_tx", "ctx3_rx", "ctx3_tx"; firmware-name = "imx/easrc/easrc-imx8mn.bin"; - fsl,asrc-rate = <8000>; + fsl,asrc-rate = <8000>; fsl,asrc-format = <2>; }; diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml index 85799f83e65f10..c9152bac742185 100644 --- a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml @@ -176,7 +176,7 @@ examples: <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", "txa", "txb", "txc"; - fsl,asrc-rate = <48000>; + fsl,asrc-rate = <48000>; fsl,asrc-width = <16>; port { From 275332877e2fa9d6efa7402b1e897f6c6ee695bb Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Thu, 14 Aug 2025 13:54:57 +0530 Subject: [PATCH 0464/1292] block: skip q->rq_qos check in rq_qos_done_bio() If a bio has BIO_QOS_THROTTLED or BIO_QOS_MERGED set, it implicitly guarantees that q->rq_qos is present. Avoid re-checking q->rq_qos in this case and call __rq_qos_done_bio() directly as a minor optimization. Suggested-by : Yu Kuai Signed-off-by: Nilay Shroff Reviewed-by: Ming Lei Reviewed-by: Yu Kuai Link: https://lore.kernel.org/r/20250814082612.500845-2-nilay@linux.ibm.com Signed-off-by: Jens Axboe --- block/blk-rq-qos.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index 39749f4066fb10..28125fc49effc7 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -142,8 +142,14 @@ static inline void rq_qos_done_bio(struct bio *bio) bio->bi_bdev && (bio_flagged(bio, BIO_QOS_THROTTLED) || bio_flagged(bio, BIO_QOS_MERGED))) { struct request_queue *q = bdev_get_queue(bio->bi_bdev); - if (q->rq_qos) - __rq_qos_done_bio(q->rq_qos, bio); + + /* + * If a bio has BIO_QOS_xxx set, it implicitly implies that + * q->rq_qos is present. So, we skip re-checking q->rq_qos + * here as an extra optimization and directly call + * __rq_qos_done_bio(). + */ + __rq_qos_done_bio(q->rq_qos, bio); } } From ade1beea1c27657712aa8f594226d461639382ff Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Thu, 14 Aug 2025 13:54:58 +0530 Subject: [PATCH 0465/1292] block: decrement block_rq_qos static key in rq_qos_del() rq_qos_add() increments the block_rq_qos static key when a QoS policy is attached. When a QoS policy is removed via rq_qos_del(), we must symmetrically decrement the static key. If this removal drops the last QoS policy from the queue (q->rq_qos becomes NULL), the static branch can be disabled and the jump label patched to a NOP, avoiding overhead on the hot path. This change ensures rq_qos_add()/rq_qos_del() keep the block_rq_qos static key balanced and prevents leaving the branch permanently enabled after the last policy is removed. Fixes: 033b667a823e ("block: blk-rq-qos: guard rq-qos helpers by static key") Signed-off-by: Nilay Shroff Reviewed-by: Ming Lei Reviewed-by: Yu Kuai Link: https://lore.kernel.org/r/20250814082612.500845-3-nilay@linux.ibm.com Signed-off-by: Jens Axboe --- block/blk-rq-qos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index 848591fb3c57b6..b1e24bb85ad2af 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c @@ -374,6 +374,7 @@ void rq_qos_del(struct rq_qos *rqos) for (cur = &q->rq_qos; *cur; cur = &(*cur)->next) { if (*cur == rqos) { *cur = rqos->next; + static_branch_dec(&block_rq_qos); break; } } From 370ac285f23aecae40600851fb4a1a9e75e50973 Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Thu, 14 Aug 2025 13:54:59 +0530 Subject: [PATCH 0466/1292] block: avoid cpu_hotplug_lock depedency on freeze_lock A recent lockdep[1] splat observed while running blktest block/005 reveals a potential deadlock caused by the cpu_hotplug_lock dependency on ->freeze_lock. This dependency was introduced by commit 033b667a823e ("block: blk-rq-qos: guard rq-qos helpers by static key"). That change added a static key to avoid fetching q->rq_qos when neither blk-wbt nor blk-iolatency is configured. The static key dynamically patches kernel text to a NOP when disabled, eliminating overhead of fetching q->rq_qos in the I/O hot path. However, enabling a static key at runtime requires acquiring both cpu_hotplug_lock and jump_label_mutex. When this happens after the queue has already been frozen (i.e., while holding ->freeze_lock), it creates a locking dependency from cpu_hotplug_lock to ->freeze_lock, which leads to a potential deadlock reported by lockdep [1]. To resolve this, replace the static key mechanism with q->queue_flags: QUEUE_FLAG_QOS_ENABLED. This flag is evaluated in the fast path before accessing q->rq_qos. If the flag is set, we proceed to fetch q->rq_qos; otherwise, the access is skipped. Since q->queue_flags is commonly accessed in IO hotpath and resides in the first cacheline of struct request_queue, checking it imposes minimal overhead while eliminating the deadlock risk. This change avoids the lockdep splat without introducing performance regressions. [1] https://lore.kernel.org/linux-block/4fdm37so3o4xricdgfosgmohn63aa7wj3ua4e5vpihoamwg3ui@fq42f5q5t5ic/ Reported-by: Shinichiro Kawasaki Closes: https://lore.kernel.org/linux-block/4fdm37so3o4xricdgfosgmohn63aa7wj3ua4e5vpihoamwg3ui@fq42f5q5t5ic/ Fixes: 033b667a823e ("block: blk-rq-qos: guard rq-qos helpers by static key") Tested-by: Shin'ichiro Kawasaki Signed-off-by: Nilay Shroff Reviewed-by: Ming Lei Reviewed-by: Yu Kuai Link: https://lore.kernel.org/r/20250814082612.500845-4-nilay@linux.ibm.com Signed-off-by: Jens Axboe --- block/blk-mq-debugfs.c | 1 + block/blk-rq-qos.c | 9 ++++--- block/blk-rq-qos.h | 54 ++++++++++++++++++++++++------------------ include/linux/blkdev.h | 1 + 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c index 7ed3e71f2fc0c3..32c65efdda46c9 100644 --- a/block/blk-mq-debugfs.c +++ b/block/blk-mq-debugfs.c @@ -95,6 +95,7 @@ static const char *const blk_queue_flag_name[] = { QUEUE_FLAG_NAME(SQ_SCHED), QUEUE_FLAG_NAME(DISABLE_WBT_DEF), QUEUE_FLAG_NAME(NO_ELV_SWITCH), + QUEUE_FLAG_NAME(QOS_ENABLED), }; #undef QUEUE_FLAG_NAME diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index b1e24bb85ad2af..654478dfbc2044 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c @@ -2,8 +2,6 @@ #include "blk-rq-qos.h" -__read_mostly DEFINE_STATIC_KEY_FALSE(block_rq_qos); - /* * Increment 'v', if 'v' is below 'below'. Returns true if we succeeded, * false if 'v' + 1 would be bigger than 'below'. @@ -319,8 +317,8 @@ void rq_qos_exit(struct request_queue *q) struct rq_qos *rqos = q->rq_qos; q->rq_qos = rqos->next; rqos->ops->exit(rqos); - static_branch_dec(&block_rq_qos); } + blk_queue_flag_clear(QUEUE_FLAG_QOS_ENABLED, q); mutex_unlock(&q->rq_qos_mutex); } @@ -346,7 +344,7 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id, goto ebusy; rqos->next = q->rq_qos; q->rq_qos = rqos; - static_branch_inc(&block_rq_qos); + blk_queue_flag_set(QUEUE_FLAG_QOS_ENABLED, q); blk_mq_unfreeze_queue(q, memflags); @@ -374,10 +372,11 @@ void rq_qos_del(struct rq_qos *rqos) for (cur = &q->rq_qos; *cur; cur = &(*cur)->next) { if (*cur == rqos) { *cur = rqos->next; - static_branch_dec(&block_rq_qos); break; } } + if (!q->rq_qos) + blk_queue_flag_clear(QUEUE_FLAG_QOS_ENABLED, q); blk_mq_unfreeze_queue(q, memflags); mutex_lock(&q->debugfs_mutex); diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index 28125fc49effc7..1fe22000a3790e 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -12,7 +12,6 @@ #include "blk-mq-debugfs.h" struct blk_mq_debugfs_attr; -extern struct static_key_false block_rq_qos; enum rq_qos_id { RQ_QOS_WBT, @@ -113,49 +112,55 @@ void __rq_qos_queue_depth_changed(struct rq_qos *rqos); static inline void rq_qos_cleanup(struct request_queue *q, struct bio *bio) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos) + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos) __rq_qos_cleanup(q->rq_qos, bio); } static inline void rq_qos_done(struct request_queue *q, struct request *rq) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos && - !blk_rq_is_passthrough(rq)) + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos && !blk_rq_is_passthrough(rq)) __rq_qos_done(q->rq_qos, rq); } static inline void rq_qos_issue(struct request_queue *q, struct request *rq) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos) + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos) __rq_qos_issue(q->rq_qos, rq); } static inline void rq_qos_requeue(struct request_queue *q, struct request *rq) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos) + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos) __rq_qos_requeue(q->rq_qos, rq); } static inline void rq_qos_done_bio(struct bio *bio) { - if (static_branch_unlikely(&block_rq_qos) && - bio->bi_bdev && (bio_flagged(bio, BIO_QOS_THROTTLED) || - bio_flagged(bio, BIO_QOS_MERGED))) { - struct request_queue *q = bdev_get_queue(bio->bi_bdev); - - /* - * If a bio has BIO_QOS_xxx set, it implicitly implies that - * q->rq_qos is present. So, we skip re-checking q->rq_qos - * here as an extra optimization and directly call - * __rq_qos_done_bio(). - */ - __rq_qos_done_bio(q->rq_qos, bio); - } + struct request_queue *q; + + if (!bio->bi_bdev || (!bio_flagged(bio, BIO_QOS_THROTTLED) && + !bio_flagged(bio, BIO_QOS_MERGED))) + return; + + q = bdev_get_queue(bio->bi_bdev); + + /* + * If a bio has BIO_QOS_xxx set, it implicitly implies that + * q->rq_qos is present. So, we skip re-checking q->rq_qos + * here as an extra optimization and directly call + * __rq_qos_done_bio(). + */ + __rq_qos_done_bio(q->rq_qos, bio); } static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos) { + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos) { bio_set_flag(bio, BIO_QOS_THROTTLED); __rq_qos_throttle(q->rq_qos, bio); } @@ -164,14 +169,16 @@ static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio) static inline void rq_qos_track(struct request_queue *q, struct request *rq, struct bio *bio) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos) + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos) __rq_qos_track(q->rq_qos, rq, bio); } static inline void rq_qos_merge(struct request_queue *q, struct request *rq, struct bio *bio) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos) { + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos) { bio_set_flag(bio, BIO_QOS_MERGED); __rq_qos_merge(q->rq_qos, rq, bio); } @@ -179,7 +186,8 @@ static inline void rq_qos_merge(struct request_queue *q, struct request *rq, static inline void rq_qos_queue_depth_changed(struct request_queue *q) { - if (static_branch_unlikely(&block_rq_qos) && q->rq_qos) + if (unlikely(test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags)) && + q->rq_qos) __rq_qos_queue_depth_changed(q->rq_qos); } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 95886b404b16b7..fe1797bbec420c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -656,6 +656,7 @@ enum { QUEUE_FLAG_SQ_SCHED, /* single queue style io dispatch */ QUEUE_FLAG_DISABLE_WBT_DEF, /* for sched to disable/enable wbt */ QUEUE_FLAG_NO_ELV_SWITCH, /* can't switch elevator any more */ + QUEUE_FLAG_QOS_ENABLED, /* qos is enabled */ QUEUE_FLAG_MAX }; From 220abf77e7c2835cc63ea8cd7158cf83952640af Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Thu, 21 Aug 2025 09:56:38 +0530 Subject: [PATCH 0467/1292] cpufreq/amd-pstate: Fix setting of CPPC.min_perf in active mode for performance governor In the "active" mode of the amd-pstate driver with performance governor, the CPPC.min_perf is expected to be the nominal_perf. However after commit a9b9b4c2a4cd ("cpufreq/amd-pstate: Drop min and max cached frequencies"), this is not the case when the governor is switched from performance to powersave and back to performance, and the CPPC.min_perf will be equal to the scaling_min_freq that was set for the powersave governor. This is because prior to commit a9b9b4c2a4cd ("cpufreq/amd-pstate: Drop min and max cached frequencies"), amd_pstate_epp_update_limit() would unconditionally call amd_pstate_update_min_max_limit() and the latter function would enforce the CPPC.min_perf constraint when the governor is performance. However, after the aforementioned commit, amd_pstate_update_min_max_limit() is called by amd_pstate_epp_update_limit() only when either the scaling_{min/max}_freq is different from the cached value of cpudata->{min/max}_limit_freq, which wouldn't have changed on a governor transition from powersave to performance, thus missing out on enforcing the CPPC.min_perf constraint for the performance governor. Fix this by invoking amd_pstate_epp_udpate_limit() not only when the {min/max} limits have changed from the cached values, but also when the policy itself has changed. Fixes: a9b9b4c2a4cd ("cpufreq/amd-pstate: Drop min and max cached frequencies") Signed-off-by: Gautham R. Shenoy Reviewed-by: Mario Limonciello Link: https://lore.kernel.org/r/20250821042638.356-1-gautham.shenoy@amd.com Signed-off-by: Mario Limonciello (AMD) --- drivers/cpufreq/amd-pstate.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index bbc27ef9edf7ba..5cd91489fcbe58 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -1554,13 +1554,15 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy) pr_debug("CPU %d exiting\n", policy->cpu); } -static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy) +static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy, bool policy_change) { struct amd_cpudata *cpudata = policy->driver_data; union perf_cached perf; u8 epp; - if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq) + if (policy_change || + policy->min != cpudata->min_limit_freq || + policy->max != cpudata->max_limit_freq) amd_pstate_update_min_max_limit(policy); if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) @@ -1584,7 +1586,7 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy) cpudata->policy = policy->policy; - ret = amd_pstate_epp_update_limit(policy); + ret = amd_pstate_epp_update_limit(policy, true); if (ret) return ret; @@ -1658,7 +1660,7 @@ static int amd_pstate_epp_resume(struct cpufreq_policy *policy) int ret; /* enable amd pstate from suspend state*/ - ret = amd_pstate_epp_update_limit(policy); + ret = amd_pstate_epp_update_limit(policy, false); if (ret) return ret; From 62708b9452f8eb77513115b17c4f8d1a22ebf843 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 19 Aug 2025 19:19:51 -0700 Subject: [PATCH 0468/1292] tls: fix handling of zero-length records on the rx_list Each recvmsg() call must process either - only contiguous DATA records (any number of them) - one non-DATA record If the next record has different type than what has already been processed we break out of the main processing loop. If the record has already been decrypted (which may be the case for TLS 1.3 where we don't know type until decryption) we queue the pending record to the rx_list. Next recvmsg() will pick it up from there. Queuing the skb to rx_list after zero-copy decrypt is not possible, since in that case we decrypted directly to the user space buffer, and we don't have an skb to queue (darg.skb points to the ciphertext skb for access to metadata like length). Only data records are allowed zero-copy, and we break the processing loop after each non-data record. So we should never zero-copy and then find out that the record type has changed. The corner case we missed is when the initial record comes from rx_list, and it's zero length. Reported-by: Muhammad Alifa Ramdhan Reported-by: Billy Jheng Bing-Jhong Fixes: 84c61fe1a75b ("tls: rx: do not use the standard strparser") Reviewed-by: Sabrina Dubroca Link: https://patch.msgid.link/20250820021952.143068-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- net/tls/tls_sw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 51c98a007ddac4..bac65d0d4e3e1e 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1808,6 +1808,9 @@ int decrypt_skb(struct sock *sk, struct scatterlist *sgout) return tls_decrypt_sg(sk, NULL, sgout, &darg); } +/* All records returned from a recvmsg() call must have the same type. + * 0 is not a valid content type. Use it as "no type reported, yet". + */ static int tls_record_content_type(struct msghdr *msg, struct tls_msg *tlm, u8 *control) { @@ -2051,8 +2054,10 @@ int tls_sw_recvmsg(struct sock *sk, if (err < 0) goto end; + /* process_rx_list() will set @control if it processed any records */ copied = err; - if (len <= copied || (copied && control != TLS_RECORD_TYPE_DATA) || rx_more) + if (len <= copied || rx_more || + (control && control != TLS_RECORD_TYPE_DATA)) goto end; target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); From a61a3e961baff65b0a49f862fe21ce304f279b24 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 19 Aug 2025 19:19:52 -0700 Subject: [PATCH 0469/1292] selftests: tls: add tests for zero-length records Test various combinations of zero-length records. Unfortunately, kernel cannot be coerced into producing those, so hardcode the ciphertext messages in the test. Reviewed-by: Sabrina Dubroca Link: https://patch.msgid.link/20250820021952.143068-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/tls.c | 300 +++++++++++++++++++++++++++++- 1 file changed, 295 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index 2b8387a83bc78e..0f5640d8dc7fbf 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -181,13 +181,12 @@ static int tls_send_cmsg(int fd, unsigned char record_type, return sendmsg(fd, &msg, flags); } -static int tls_recv_cmsg(struct __test_metadata *_metadata, - int fd, unsigned char record_type, - void *data, size_t len, int flags) +static int __tls_recv_cmsg(struct __test_metadata *_metadata, + int fd, unsigned char *ctype, + void *data, size_t len, int flags) { char cbuf[CMSG_SPACE(sizeof(char))]; struct cmsghdr *cmsg; - unsigned char ctype; struct msghdr msg; struct iovec vec; int n; @@ -206,7 +205,20 @@ static int tls_recv_cmsg(struct __test_metadata *_metadata, EXPECT_NE(cmsg, NULL); EXPECT_EQ(cmsg->cmsg_level, SOL_TLS); EXPECT_EQ(cmsg->cmsg_type, TLS_GET_RECORD_TYPE); - ctype = *((unsigned char *)CMSG_DATA(cmsg)); + if (ctype) + *ctype = *((unsigned char *)CMSG_DATA(cmsg)); + + return n; +} + +static int tls_recv_cmsg(struct __test_metadata *_metadata, + int fd, unsigned char record_type, + void *data, size_t len, int flags) +{ + unsigned char ctype; + int n; + + n = __tls_recv_cmsg(_metadata, fd, &ctype, data, len, flags); EXPECT_EQ(ctype, record_type); return n; @@ -2164,6 +2176,284 @@ TEST_F(tls, rekey_poll_delay) } } +struct raw_rec { + unsigned int plain_len; + unsigned char plain_data[100]; + unsigned int cipher_len; + unsigned char cipher_data[128]; +}; + +/* TLS 1.2, AES_CCM, data, seqno:0, plaintext: 'Hello world' */ +static const struct raw_rec id0_data_l11 = { + .plain_len = 11, + .plain_data = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, + 0x72, 0x6c, 0x64, + }, + .cipher_len = 40, + .cipher_data = { + 0x17, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0xa2, 0x33, + 0xde, 0x8d, 0x94, 0xf0, 0x29, 0x6c, 0xb1, 0xaf, + 0x6a, 0x75, 0xb2, 0x93, 0xad, 0x45, 0xd5, 0xfd, + 0x03, 0x51, 0x57, 0x8f, 0xf9, 0xcc, 0x3b, 0x42, + }, +}; + +/* TLS 1.2, AES_CCM, ctrl, seqno:0, plaintext: '' */ +static const struct raw_rec id0_ctrl_l0 = { + .plain_len = 0, + .plain_data = { + }, + .cipher_len = 29, + .cipher_data = { + 0x16, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x38, 0x7b, + 0xa6, 0x1c, 0xdd, 0xa7, 0x19, 0x33, 0xab, 0xae, + 0x88, 0xe1, 0xd2, 0x08, 0x4f, + }, +}; + +/* TLS 1.2, AES_CCM, data, seqno:0, plaintext: '' */ +static const struct raw_rec id0_data_l0 = { + .plain_len = 0, + .plain_data = { + }, + .cipher_len = 29, + .cipher_data = { + 0x17, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x37, 0x90, + 0x70, 0x45, 0x89, 0xfb, 0x5c, 0xc7, 0x89, 0x03, + 0x68, 0x80, 0xd3, 0xd8, 0xcc, + }, +}; + +/* TLS 1.2, AES_CCM, data, seqno:1, plaintext: 'Hello world' */ +static const struct raw_rec id1_data_l11 = { + .plain_len = 11, + .plain_data = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, + 0x72, 0x6c, 0x64, + }, + .cipher_len = 40, + .cipher_data = { + 0x17, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x1a, 0x9c, + 0xd0, 0xa8, 0x9a, 0xd6, 0x69, 0xd6, 0x1a, 0xe3, + 0xb5, 0x1f, 0x0d, 0x2c, 0xe2, 0x97, 0x46, 0xff, + 0x2b, 0xcc, 0x5a, 0xc4, 0xa3, 0xb9, 0xef, 0xba, + }, +}; + +/* TLS 1.2, AES_CCM, ctrl, seqno:1, plaintext: '' */ +static const struct raw_rec id1_ctrl_l0 = { + .plain_len = 0, + .plain_data = { + }, + .cipher_len = 29, + .cipher_data = { + 0x16, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0xf0, 0xfe, + 0xee, 0xd9, 0xe2, 0x5d, 0xc7, 0x11, 0x4c, 0xe6, + 0xb4, 0x7e, 0xef, 0x40, 0x2b, + }, +}; + +/* TLS 1.2, AES_CCM, data, seqno:1, plaintext: '' */ +static const struct raw_rec id1_data_l0 = { + .plain_len = 0, + .plain_data = { + }, + .cipher_len = 29, + .cipher_data = { + 0x17, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xce, 0xfc, 0x86, + 0xc8, 0xf0, 0x55, 0xf9, 0x47, 0x3f, 0x74, 0xdc, + 0xc9, 0xbf, 0xfe, 0x5b, 0xb1, + }, +}; + +/* TLS 1.2, AES_CCM, ctrl, seqno:2, plaintext: 'Hello world' */ +static const struct raw_rec id2_ctrl_l11 = { + .plain_len = 11, + .plain_data = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, + 0x72, 0x6c, 0x64, + }, + .cipher_len = 40, + .cipher_data = { + 0x16, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xe5, 0x3d, 0x19, + 0x3d, 0xca, 0xb8, 0x16, 0xb6, 0xff, 0x79, 0x87, + 0x2a, 0x04, 0x11, 0x3d, 0xf8, 0x64, 0x5f, 0x36, + 0x8b, 0xa8, 0xee, 0x4c, 0x6d, 0x62, 0xa5, 0x00, + }, +}; + +/* TLS 1.2, AES_CCM, data, seqno:2, plaintext: 'Hello world' */ +static const struct raw_rec id2_data_l11 = { + .plain_len = 11, + .plain_data = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, + 0x72, 0x6c, 0x64, + }, + .cipher_len = 40, + .cipher_data = { + 0x17, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xe5, 0x3d, 0x19, + 0x3d, 0xca, 0xb8, 0x16, 0xb6, 0xff, 0x79, 0x87, + 0x8e, 0xa1, 0xd0, 0xcd, 0x33, 0xb5, 0x86, 0x2b, + 0x17, 0xf1, 0x52, 0x2a, 0x55, 0x62, 0x65, 0x11, + }, +}; + +/* TLS 1.2, AES_CCM, ctrl, seqno:2, plaintext: '' */ +static const struct raw_rec id2_ctrl_l0 = { + .plain_len = 0, + .plain_data = { + }, + .cipher_len = 29, + .cipher_data = { + 0x16, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xdc, 0x5c, 0x0e, + 0x41, 0xdd, 0xba, 0xd3, 0xcc, 0xcf, 0x6d, 0xd9, + 0x06, 0xdb, 0x79, 0xe5, 0x5d, + }, +}; + +/* TLS 1.2, AES_CCM, data, seqno:2, plaintext: '' */ +static const struct raw_rec id2_data_l0 = { + .plain_len = 0, + .plain_data = { + }, + .cipher_len = 29, + .cipher_data = { + 0x17, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xc3, 0xca, 0x26, + 0x22, 0xe4, 0x25, 0xfb, 0x5f, 0x6d, 0xbf, 0x83, + 0x30, 0x48, 0x69, 0x1a, 0x47, + }, +}; + +FIXTURE(zero_len) +{ + int fd, cfd; + bool notls; +}; + +FIXTURE_VARIANT(zero_len) +{ + const struct raw_rec *recs[4]; + ssize_t recv_ret[4]; +}; + +FIXTURE_VARIANT_ADD(zero_len, data_data_data) +{ + .recs = { &id0_data_l11, &id1_data_l11, &id2_data_l11, }, + .recv_ret = { 33, -EAGAIN, }, +}; + +FIXTURE_VARIANT_ADD(zero_len, data_0ctrl_data) +{ + .recs = { &id0_data_l11, &id1_ctrl_l0, &id2_data_l11, }, + .recv_ret = { 11, 0, 11, -EAGAIN, }, +}; + +FIXTURE_VARIANT_ADD(zero_len, 0data_0data_0data) +{ + .recs = { &id0_data_l0, &id1_data_l0, &id2_data_l0, }, + .recv_ret = { -EAGAIN, }, +}; + +FIXTURE_VARIANT_ADD(zero_len, 0data_0data_ctrl) +{ + .recs = { &id0_data_l0, &id1_data_l0, &id2_ctrl_l11, }, + .recv_ret = { 0, 11, -EAGAIN, }, +}; + +FIXTURE_VARIANT_ADD(zero_len, 0data_0data_0ctrl) +{ + .recs = { &id0_data_l0, &id1_data_l0, &id2_ctrl_l0, }, + .recv_ret = { 0, 0, -EAGAIN, }, +}; + +FIXTURE_VARIANT_ADD(zero_len, 0ctrl_0ctrl_0ctrl) +{ + .recs = { &id0_ctrl_l0, &id1_ctrl_l0, &id2_ctrl_l0, }, + .recv_ret = { 0, 0, 0, -EAGAIN, }, +}; + +FIXTURE_VARIANT_ADD(zero_len, 0data_0data_data) +{ + .recs = { &id0_data_l0, &id1_data_l0, &id2_data_l11, }, + .recv_ret = { 11, -EAGAIN, }, +}; + +FIXTURE_VARIANT_ADD(zero_len, data_0data_0data) +{ + .recs = { &id0_data_l11, &id1_data_l0, &id2_data_l0, }, + .recv_ret = { 11, -EAGAIN, }, +}; + +FIXTURE_SETUP(zero_len) +{ + struct tls_crypto_info_keys tls12; + int ret; + + tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_CCM_128, + &tls12, 0); + + ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls); + if (self->notls) + return; + + /* Don't install keys on fd, we'll send raw records */ + ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len); + ASSERT_EQ(ret, 0); +} + +FIXTURE_TEARDOWN(zero_len) +{ + close(self->fd); + close(self->cfd); +} + +TEST_F(zero_len, test) +{ + const struct raw_rec *const *rec; + unsigned char buf[128]; + int rec_off; + int i; + + for (i = 0; i < 4 && variant->recs[i]; i++) + EXPECT_EQ(send(self->fd, variant->recs[i]->cipher_data, + variant->recs[i]->cipher_len, 0), + variant->recs[i]->cipher_len); + + rec = &variant->recs[0]; + rec_off = 0; + for (i = 0; i < 4; i++) { + int j, ret; + + ret = variant->recv_ret[i] >= 0 ? variant->recv_ret[i] : -1; + EXPECT_EQ(__tls_recv_cmsg(_metadata, self->cfd, NULL, + buf, sizeof(buf), MSG_DONTWAIT), ret); + if (ret == -1) + EXPECT_EQ(errno, -variant->recv_ret[i]); + if (variant->recv_ret[i] == -EAGAIN) + break; + + for (j = 0; j < ret; j++) { + while (rec_off == (*rec)->plain_len) { + rec++; + rec_off = 0; + } + EXPECT_EQ(buf[j], (*rec)->plain_data[rec_off]); + rec_off++; + } + } +}; + FIXTURE(tls_err) { int fd, cfd; From 8c5d95988c34f0aeba1f34cd5e4ba69494c90c5f Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 20 Aug 2025 12:09:18 +0530 Subject: [PATCH 0470/1292] Octeontx2-af: Skip overlap check for SPI field Octeontx2/CN10K silicon supports generating a 256-bit key per packet. The specific fields to be extracted from a packet for key generation are configurable via a Key Extraction (MKEX) Profile. The AF driver scans the configured extraction profile to ensure that fields from upper layers do not overwrite fields from lower layers in the key. Example Packet Field Layout: LA: DMAC + SMAC LB: VLAN LC: IPv4/IPv6 LD: TCP/UDP Valid MKEX Profile Configuration: LA -> DMAC -> key_offset[0-5] LC -> SIP -> key_offset[20-23] LD -> SPORT -> key_offset[30-31] Invalid MKEX profile configuration: LA -> DMAC -> key_offset[0-5] LC -> SIP -> key_offset[20-23] LD -> SPORT -> key_offset[2-3] // Overlaps with DMAC field In another scenario, if the MKEX profile is configured to extract the SPI field from both AH and ESP headers at the same key offset, the driver rejecting this configuration. In a regular traffic, ipsec packet will be having either AH(LD) or ESP (LE). This patch relaxes the check for the same. Fixes: 12aa0a3b93f3 ("octeontx2-af: Harden rule validation.") Signed-off-by: Hariprasad Kelam Link: https://patch.msgid.link/20250820063919.1463518-1-hkelam@marvell.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index 1b765045aa636b..b56395ac5a7439 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -606,8 +606,8 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf) if (!npc_check_field(rvu, blkaddr, NPC_LB, intf)) *features &= ~BIT_ULL(NPC_OUTER_VID); - /* Set SPI flag only if AH/ESP and IPSEC_SPI are in the key */ - if (npc_check_field(rvu, blkaddr, NPC_IPSEC_SPI, intf) && + /* Allow extracting SPI field from AH and ESP headers at same offset */ + if (npc_is_field_present(rvu, NPC_IPSEC_SPI, intf) && (*features & (BIT_ULL(NPC_IPPROTO_ESP) | BIT_ULL(NPC_IPPROTO_AH)))) *features |= BIT_ULL(NPC_IPSEC_SPI); From 1c67f9c54cdc70627e3f6472b89cd3d895df974c Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Wed, 20 Aug 2025 15:27:07 +0200 Subject: [PATCH 0471/1292] net: pse-pd: pd692x0: Fix power budget leak in manager setup error path Fix a resource leak where manager power budgets were freed on both success and error paths during manager setup. Power budgets should only be freed on error paths after regulator registration or during driver removal. Refactor cleanup logic by extracting OF node cleanup and power budget freeing into separate helper functions for better maintainability. Fixes: 359754013e6a ("net: pse-pd: pd692x0: Add support for PSE PI priority feature") Signed-off-by: Kory Maincent Link: https://patch.msgid.link/20250820132708.837255-1-kory.maincent@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/pse-pd/pd692x0.c | 59 +++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c index 399ce9febda493..395f6c662175c0 100644 --- a/drivers/net/pse-pd/pd692x0.c +++ b/drivers/net/pse-pd/pd692x0.c @@ -1162,12 +1162,44 @@ pd692x0_write_ports_matrix(struct pd692x0_priv *priv, return 0; } +static void pd692x0_of_put_managers(struct pd692x0_priv *priv, + struct pd692x0_manager *manager, + int nmanagers) +{ + int i, j; + + for (i = 0; i < nmanagers; i++) { + for (j = 0; j < manager[i].nports; j++) + of_node_put(manager[i].port_node[j]); + of_node_put(manager[i].node); + } +} + +static void pd692x0_managers_free_pw_budget(struct pd692x0_priv *priv) +{ + int i; + + for (i = 0; i < PD692X0_MAX_MANAGERS; i++) { + struct regulator *supply; + + if (!priv->manager_reg[i] || !priv->manager_pw_budget[i]) + continue; + + supply = priv->manager_reg[i]->supply; + if (!supply) + continue; + + regulator_free_power_budget(supply, + priv->manager_pw_budget[i]); + } +} + static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev) { struct pd692x0_manager *manager __free(kfree) = NULL; struct pd692x0_priv *priv = to_pd692x0_priv(pcdev); struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS]; - int ret, i, j, nmanagers; + int ret, nmanagers; /* Should we flash the port matrix */ if (priv->fw_state != PD692X0_FW_OK && @@ -1185,31 +1217,27 @@ static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev) nmanagers = ret; ret = pd692x0_register_managers_regulator(priv, manager, nmanagers); if (ret) - goto out; + goto err_of_managers; ret = pd692x0_configure_managers(priv, nmanagers); if (ret) - goto out; + goto err_of_managers; ret = pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix); if (ret) - goto out; + goto err_managers_req_pw; ret = pd692x0_write_ports_matrix(priv, port_matrix); if (ret) - goto out; + goto err_managers_req_pw; -out: - for (i = 0; i < nmanagers; i++) { - struct regulator *supply = priv->manager_reg[i]->supply; - - regulator_free_power_budget(supply, - priv->manager_pw_budget[i]); + pd692x0_of_put_managers(priv, manager, nmanagers); + return 0; - for (j = 0; j < manager[i].nports; j++) - of_node_put(manager[i].port_node[j]); - of_node_put(manager[i].node); - } +err_managers_req_pw: + pd692x0_managers_free_pw_budget(priv); +err_of_managers: + pd692x0_of_put_managers(priv, manager, nmanagers); return ret; } @@ -1748,6 +1776,7 @@ static void pd692x0_i2c_remove(struct i2c_client *client) { struct pd692x0_priv *priv = i2c_get_clientdata(client); + pd692x0_managers_free_pw_budget(priv); firmware_upload_unregister(priv->fwl); } From 7ef353879f714602b43f98662069f4fb86536761 Mon Sep 17 00:00:00 2001 From: Kory Maincent Date: Wed, 20 Aug 2025 15:33:21 +0200 Subject: [PATCH 0472/1292] net: pse-pd: pd692x0: Skip power budget configuration when undefined If the power supply's power budget is not defined in the device tree, the current code still requests power and configures the PSE manager with a 0W power limit, which is undesirable behavior. Skip power budget configuration entirely when the budget is zero, avoiding unnecessary power requests and preventing invalid 0W limits from being set on the PSE manager. Fixes: 359754013e6a ("net: pse-pd: pd692x0: Add support for PSE PI priority feature") Signed-off-by: Kory Maincent Acked-by: Oleksij Rempel Link: https://patch.msgid.link/20250820133321.841054-1-kory.maincent@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/pse-pd/pd692x0.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c index 395f6c662175c0..f4e91ba64a666c 100644 --- a/drivers/net/pse-pd/pd692x0.c +++ b/drivers/net/pse-pd/pd692x0.c @@ -1041,6 +1041,10 @@ pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers) int pw_budget; pw_budget = regulator_get_unclaimed_power_budget(supply); + if (!pw_budget) + /* Do nothing if no power budget */ + continue; + /* Max power budget per manager */ if (pw_budget > 6000000) pw_budget = 6000000; From bc17455bc843b2f4b206e0bb8139013eb3d3c08b Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Wed, 20 Aug 2025 16:32:02 +0300 Subject: [PATCH 0473/1292] net/mlx5: Base ECVF devlink port attrs from 0 Adjust the vport number by the base ECVF vport number so the port attributes start at 0. Previously the port attributes would start 1 after the maximum number of host VFs. Fixes: dc13180824b7 ("net/mlx5: Enable devlink port for embedded cpu VF vports") Signed-off-by: Daniel Jurgens Reviewed-by: Parav Pandit Reviewed-by: Saeed Mahameed Signed-off-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250820133209.389065-2-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index b7102e14d23d3b..c33accadae0f01 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -47,10 +47,12 @@ static void mlx5_esw_offloads_pf_vf_devlink_port_attrs_set(struct mlx5_eswitch * devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum, vport_num - 1, external); } else if (mlx5_core_is_ec_vf_vport(esw->dev, vport_num)) { + u16 base_vport = mlx5_core_ec_vf_vport_base(dev); + memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len); dl_port->attrs.switch_id.id_len = ppid.id_len; devlink_port_attrs_pci_vf_set(dl_port, 0, pfnum, - vport_num - 1, false); + vport_num - base_vport, false); } } From 330f0f6713a39581936decac72331e6ab7f13529 Mon Sep 17 00:00:00 2001 From: Carolina Jubran Date: Wed, 20 Aug 2025 16:32:03 +0300 Subject: [PATCH 0474/1292] net/mlx5: Remove default QoS group and attach vports directly to root TSAR Currently, the driver creates a default group (`node0`) and attaches all vports to it unless the user explicitly sets a parent group. As a result, when a user configures tx_share on a group and tx_share on a VF, the expectation is for the group and the VF to share bandwidth relatively. However, since the VF is not connected to the same parent (but to the default node), the proportional share logic is not applied correctly. To fix this, remove the default group (`node0`) and instead connect vports directly to the root TSAR when no parent is specified. This ensures that vports and groups share the same root scheduler and their tx_share values are compared directly under the same hierarchy. Fixes: 0fe132eac38c ("net/mlx5: E-switch, Allow to add vports to rate groups") Signed-off-by: Carolina Jubran Reviewed-by: Cosmin Ratiu Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250820133209.389065-3-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/esw/qos.c | 97 +++++++------------ .../net/ethernet/mellanox/mlx5/core/eswitch.h | 5 - 2 files changed, 33 insertions(+), 69 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index 91d863c8c152a4..cd58d39345965b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -462,6 +462,7 @@ static int esw_qos_vport_create_sched_element(struct mlx5_esw_sched_node *vport_node, struct netlink_ext_ack *extack) { + struct mlx5_esw_sched_node *parent = vport_node->parent; u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; struct mlx5_core_dev *dev = vport_node->esw->dev; void *attr; @@ -477,7 +478,7 @@ esw_qos_vport_create_sched_element(struct mlx5_esw_sched_node *vport_node, attr = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes); MLX5_SET(vport_element, attr, vport_number, vport_node->vport->vport); MLX5_SET(scheduling_context, sched_ctx, parent_element_id, - vport_node->parent->ix); + parent ? parent->ix : vport_node->esw->qos.root_tsar_ix); MLX5_SET(scheduling_context, sched_ctx, max_average_bw, vport_node->max_rate); @@ -786,48 +787,15 @@ static int esw_qos_create(struct mlx5_eswitch *esw, struct netlink_ext_ack *exta return err; } - if (MLX5_CAP_QOS(dev, log_esw_max_sched_depth)) { - esw->qos.node0 = __esw_qos_create_vports_sched_node(esw, NULL, extack); - } else { - /* The eswitch doesn't support scheduling nodes. - * Create a software-only node0 using the root TSAR to attach vport QoS to. - */ - if (!__esw_qos_alloc_node(esw, - esw->qos.root_tsar_ix, - SCHED_NODE_TYPE_VPORTS_TSAR, - NULL)) - esw->qos.node0 = ERR_PTR(-ENOMEM); - else - list_add_tail(&esw->qos.node0->entry, - &esw->qos.domain->nodes); - } - if (IS_ERR(esw->qos.node0)) { - err = PTR_ERR(esw->qos.node0); - esw_warn(dev, "E-Switch create rate node 0 failed (%d)\n", err); - goto err_node0; - } refcount_set(&esw->qos.refcnt, 1); return 0; - -err_node0: - if (mlx5_destroy_scheduling_element_cmd(esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, - esw->qos.root_tsar_ix)) - esw_warn(esw->dev, "E-Switch destroy root TSAR failed.\n"); - - return err; } static void esw_qos_destroy(struct mlx5_eswitch *esw) { int err; - if (esw->qos.node0->ix != esw->qos.root_tsar_ix) - __esw_qos_destroy_node(esw->qos.node0, NULL); - else - __esw_qos_free_node(esw->qos.node0); - esw->qos.node0 = NULL; - err = mlx5_destroy_scheduling_element_cmd(esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, esw->qos.root_tsar_ix); @@ -990,13 +958,16 @@ esw_qos_vport_tc_enable(struct mlx5_vport *vport, enum sched_node_type type, struct netlink_ext_ack *extack) { struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; - int err, new_level, max_level; + struct mlx5_esw_sched_node *parent = vport_node->parent; + int err; if (type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) { + int new_level, max_level; + /* Increase the parent's level by 2 to account for both the * TC arbiter and the vports TC scheduling element. */ - new_level = vport_node->parent->level + 2; + new_level = (parent ? parent->level : 2) + 2; max_level = 1 << MLX5_CAP_QOS(vport_node->esw->dev, log_esw_max_sched_depth); if (new_level > max_level) { @@ -1033,9 +1004,7 @@ esw_qos_vport_tc_enable(struct mlx5_vport *vport, enum sched_node_type type, err_sched_nodes: if (type == SCHED_NODE_TYPE_RATE_LIMITER) { esw_qos_node_destroy_sched_element(vport_node, NULL); - list_add_tail(&vport_node->entry, - &vport_node->parent->children); - vport_node->level = vport_node->parent->level + 1; + esw_qos_node_attach_to_parent(vport_node); } else { esw_qos_tc_arbiter_scheduling_teardown(vport_node, NULL); } @@ -1083,7 +1052,6 @@ static int esw_qos_set_vport_tcs_min_rate(struct mlx5_vport *vport, static void esw_qos_vport_disable(struct mlx5_vport *vport, struct netlink_ext_ack *extack) { struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; - struct mlx5_esw_sched_node *parent = vport_node->parent; enum sched_node_type curr_type = vport_node->type; if (curr_type == SCHED_NODE_TYPE_VPORT) @@ -1093,7 +1061,7 @@ static void esw_qos_vport_disable(struct mlx5_vport *vport, struct netlink_ext_a vport_node->bw_share = 0; list_del_init(&vport_node->entry); - esw_qos_normalize_min_rate(parent->esw, parent, extack); + esw_qos_normalize_min_rate(vport_node->esw, vport_node->parent, extack); trace_mlx5_esw_vport_qos_destroy(vport_node->esw->dev, vport); } @@ -1103,25 +1071,23 @@ static int esw_qos_vport_enable(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent, struct netlink_ext_ack *extack) { + struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; int err; esw_assert_qos_lock_held(vport->dev->priv.eswitch); - esw_qos_node_set_parent(vport->qos.sched_node, parent); - if (type == SCHED_NODE_TYPE_VPORT) { - err = esw_qos_vport_create_sched_element(vport->qos.sched_node, - extack); - } else { + esw_qos_node_set_parent(vport_node, parent); + if (type == SCHED_NODE_TYPE_VPORT) + err = esw_qos_vport_create_sched_element(vport_node, extack); + else err = esw_qos_vport_tc_enable(vport, type, extack); - } if (err) return err; - vport->qos.sched_node->type = type; - esw_qos_normalize_min_rate(parent->esw, parent, extack); - trace_mlx5_esw_vport_qos_create(vport->dev, vport, - vport->qos.sched_node->max_rate, - vport->qos.sched_node->bw_share); + vport_node->type = type; + esw_qos_normalize_min_rate(vport_node->esw, parent, extack); + trace_mlx5_esw_vport_qos_create(vport->dev, vport, vport_node->max_rate, + vport_node->bw_share); return 0; } @@ -1132,6 +1098,7 @@ static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_t { struct mlx5_eswitch *esw = vport->dev->priv.eswitch; struct mlx5_esw_sched_node *sched_node; + struct mlx5_eswitch *parent_esw; int err; esw_assert_qos_lock_held(esw); @@ -1139,10 +1106,12 @@ static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_t if (err) return err; - parent = parent ?: esw->qos.node0; - sched_node = __esw_qos_alloc_node(parent->esw, 0, type, parent); + parent_esw = parent ? parent->esw : esw; + sched_node = __esw_qos_alloc_node(parent_esw, 0, type, parent); if (!sched_node) return -ENOMEM; + if (!parent) + list_add_tail(&sched_node->entry, &esw->qos.domain->nodes); sched_node->max_rate = max_rate; sched_node->min_rate = min_rate; @@ -1168,7 +1137,7 @@ void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport) goto unlock; parent = vport->qos.sched_node->parent; - WARN(parent != esw->qos.node0, "Disabling QoS on port before detaching it from node"); + WARN(parent, "Disabling QoS on port before detaching it from node"); esw_qos_vport_disable(vport, NULL); mlx5_esw_qos_vport_qos_free(vport); @@ -1268,7 +1237,6 @@ static int esw_qos_vport_update(struct mlx5_vport *vport, int err; esw_assert_qos_lock_held(vport->dev->priv.eswitch); - parent = parent ?: curr_parent; if (curr_type == type && curr_parent == parent) return 0; @@ -1306,16 +1274,16 @@ static int esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw esw_assert_qos_lock_held(esw); curr_parent = vport->qos.sched_node->parent; - parent = parent ?: esw->qos.node0; if (curr_parent == parent) return 0; /* Set vport QoS type based on parent node type if different from * default QoS; otherwise, use the vport's current QoS type. */ - if (parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) + if (parent && parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) type = SCHED_NODE_TYPE_RATE_LIMITER; - else if (curr_parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) + else if (curr_parent && + curr_parent->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) type = SCHED_NODE_TYPE_VPORT; else type = vport->qos.sched_node->type; @@ -1654,9 +1622,10 @@ static bool esw_qos_validate_unsupported_tc_bw(struct mlx5_eswitch *esw, static bool esw_qos_vport_validate_unsupported_tc_bw(struct mlx5_vport *vport, u32 *tc_bw) { - struct mlx5_eswitch *esw = vport->qos.sched_node ? - vport->qos.sched_node->parent->esw : - vport->dev->priv.eswitch; + struct mlx5_esw_sched_node *node = vport->qos.sched_node; + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + + esw = (node && node->parent) ? node->parent->esw : esw; return esw_qos_validate_unsupported_tc_bw(esw, tc_bw); } @@ -1763,7 +1732,7 @@ int mlx5_esw_devlink_rate_leaf_tc_bw_set(struct devlink_rate *rate_leaf, if (disable) { if (vport_node->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) err = esw_qos_vport_update(vport, SCHED_NODE_TYPE_VPORT, - NULL, extack); + vport_node->parent, extack); goto unlock; } @@ -1775,7 +1744,7 @@ int mlx5_esw_devlink_rate_leaf_tc_bw_set(struct devlink_rate *rate_leaf, } else { err = esw_qos_vport_update(vport, SCHED_NODE_TYPE_TC_ARBITER_TSAR, - NULL, extack); + vport_node->parent, extack); } if (!err) esw_qos_set_tc_arbiter_bw_shares(vport_node, tc_bw, extack); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index b0b8ef3ec3c474..45506ad568470d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -373,11 +373,6 @@ struct mlx5_eswitch { refcount_t refcnt; u32 root_tsar_ix; struct mlx5_qos_domain *domain; - /* Contains all vports with QoS enabled but no explicit node. - * Cannot be NULL if QoS is enabled, but may be a fake node - * referencing the root TSAR if the esw doesn't support nodes. - */ - struct mlx5_esw_sched_node *node0; } qos; struct mlx5_esw_bridge_offloads *br_offloads; From e8f973576ca5387ffd2917b8ae661d3f9acde526 Mon Sep 17 00:00:00 2001 From: Carolina Jubran Date: Wed, 20 Aug 2025 16:32:04 +0300 Subject: [PATCH 0475/1292] net/mlx5e: Preserve tc-bw during parent changes When changing parent of a node/leaf with tc-bw configured, the code saves and restores tc-bw values. However, it was reading the converted hardware bw_share values (where 0 becomes 1) instead of the original user values, causing incorrect tc-bw calculations after parent change. Store original tc-bw values in the node structure and use them directly for save/restore operations. Fixes: cf7e73770d1b ("net/mlx5: Manage TC arbiter nodes and implement full support for tc-bw") Signed-off-by: Carolina Jubran Reviewed-by: Cosmin Ratiu Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250820133209.389065-4-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/esw/qos.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index cd58d39345965b..4ed5968f16385b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -102,6 +102,8 @@ struct mlx5_esw_sched_node { u8 level; /* Valid only when this node represents a traffic class. */ u8 tc; + /* Valid only for a TC arbiter node or vport TC arbiter. */ + u32 tc_bw[DEVLINK_RATE_TCS_MAX]; }; static void esw_qos_node_attach_to_parent(struct mlx5_esw_sched_node *node) @@ -609,10 +611,7 @@ static void esw_qos_tc_arbiter_get_bw_shares(struct mlx5_esw_sched_node *tc_arbiter_node, u32 *tc_bw) { - struct mlx5_esw_sched_node *vports_tc_node; - - list_for_each_entry(vports_tc_node, &tc_arbiter_node->children, entry) - tc_bw[vports_tc_node->tc] = vports_tc_node->bw_share; + memcpy(tc_bw, tc_arbiter_node->tc_bw, sizeof(tc_arbiter_node->tc_bw)); } static void @@ -629,6 +628,7 @@ esw_qos_set_tc_arbiter_bw_shares(struct mlx5_esw_sched_node *tc_arbiter_node, u8 tc = vports_tc_node->tc; u32 bw_share; + tc_arbiter_node->tc_bw[tc] = tc_bw[tc]; bw_share = tc_bw[tc] * fw_max_bw_share; bw_share = esw_qos_calc_bw_share(bw_share, divider, fw_max_bw_share); @@ -1060,6 +1060,7 @@ static void esw_qos_vport_disable(struct mlx5_vport *vport, struct netlink_ext_a esw_qos_vport_tc_disable(vport, extack); vport_node->bw_share = 0; + memset(vport_node->tc_bw, 0, sizeof(vport_node->tc_bw)); list_del_init(&vport_node->entry); esw_qos_normalize_min_rate(vport_node->esw, vport_node->parent, extack); @@ -1231,8 +1232,9 @@ static int esw_qos_vport_update(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent, struct netlink_ext_ack *extack) { - struct mlx5_esw_sched_node *curr_parent = vport->qos.sched_node->parent; - enum sched_node_type curr_type = vport->qos.sched_node->type; + struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; + struct mlx5_esw_sched_node *curr_parent = vport_node->parent; + enum sched_node_type curr_type = vport_node->type; u32 curr_tc_bw[DEVLINK_RATE_TCS_MAX] = {0}; int err; @@ -1244,10 +1246,8 @@ static int esw_qos_vport_update(struct mlx5_vport *vport, if (err) return err; - if (curr_type == SCHED_NODE_TYPE_TC_ARBITER_TSAR && curr_type == type) { - esw_qos_tc_arbiter_get_bw_shares(vport->qos.sched_node, - curr_tc_bw); - } + if (curr_type == SCHED_NODE_TYPE_TC_ARBITER_TSAR && curr_type == type) + esw_qos_tc_arbiter_get_bw_shares(vport_node, curr_tc_bw); esw_qos_vport_disable(vport, extack); @@ -1258,8 +1258,8 @@ static int esw_qos_vport_update(struct mlx5_vport *vport, } if (curr_type == SCHED_NODE_TYPE_TC_ARBITER_TSAR && curr_type == type) { - esw_qos_set_tc_arbiter_bw_shares(vport->qos.sched_node, - curr_tc_bw, extack); + esw_qos_set_tc_arbiter_bw_shares(vport_node, curr_tc_bw, + extack); } return err; From b697ef4d1d136948d282384e6cc3d1af469ea123 Mon Sep 17 00:00:00 2001 From: Carolina Jubran Date: Wed, 20 Aug 2025 16:32:05 +0300 Subject: [PATCH 0476/1292] net/mlx5: Destroy vport QoS element when no configuration remains If a VF has been configured and the user later clears all QoS settings, the vport element remains in the firmware QoS tree. This leads to inconsistent behavior compared to VFs that were never configured, since the FW assumes that unconfigured VFs are outside the QoS hierarchy. As a result, the bandwidth share across VFs may differ, even though none of them appear to have any configuration. Align the driver behavior with the FW expectation by destroying the vport QoS element when all configurations are removed. Fixes: c9497c98901c ("net/mlx5: Add support for setting VF min rate") Fixes: cf7e73770d1b ("net/mlx5: Manage TC arbiter nodes and implement full support for tc-bw") Signed-off-by: Carolina Jubran Reviewed-by: Cosmin Ratiu Signed-off-by: Mark Bloch Reviewed-by: Przemek Kitszel Link: https://patch.msgid.link/20250820133209.389065-5-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/esw/qos.c | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index 4ed5968f16385b..452a948a3e6d22 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -1127,6 +1127,19 @@ static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_t return err; } +static void mlx5_esw_qos_vport_disable_locked(struct mlx5_vport *vport) +{ + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + + esw_assert_qos_lock_held(esw); + if (!vport->qos.sched_node) + return; + + esw_qos_vport_disable(vport, NULL); + mlx5_esw_qos_vport_qos_free(vport); + esw_qos_put(esw); +} + void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport) { struct mlx5_eswitch *esw = vport->dev->priv.eswitch; @@ -1140,9 +1153,7 @@ void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport) parent = vport->qos.sched_node->parent; WARN(parent, "Disabling QoS on port before detaching it from node"); - esw_qos_vport_disable(vport, NULL); - mlx5_esw_qos_vport_qos_free(vport); - esw_qos_put(esw); + mlx5_esw_qos_vport_disable_locked(vport); unlock: esw_qos_unlock(esw); } @@ -1642,6 +1653,21 @@ static bool esw_qos_tc_bw_disabled(u32 *tc_bw) return true; } +static void esw_vport_qos_prune_empty(struct mlx5_vport *vport) +{ + struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; + + esw_assert_qos_lock_held(vport->dev->priv.eswitch); + if (!vport_node) + return; + + if (vport_node->parent || vport_node->max_rate || + vport_node->min_rate || !esw_qos_tc_bw_disabled(vport_node->tc_bw)) + return; + + mlx5_esw_qos_vport_disable_locked(vport); +} + int mlx5_esw_qos_init(struct mlx5_eswitch *esw) { if (esw->qos.domain) @@ -1675,6 +1701,10 @@ int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void esw_qos_lock(esw); err = mlx5_esw_qos_set_vport_min_rate(vport, tx_share, extack); + if (err) + goto out; + esw_vport_qos_prune_empty(vport); +out: esw_qos_unlock(esw); return err; } @@ -1696,6 +1726,10 @@ int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void * esw_qos_lock(esw); err = mlx5_esw_qos_set_vport_max_rate(vport, tx_max, extack); + if (err) + goto out; + esw_vport_qos_prune_empty(vport); +out: esw_qos_unlock(esw); return err; } @@ -1733,6 +1767,7 @@ int mlx5_esw_devlink_rate_leaf_tc_bw_set(struct devlink_rate *rate_leaf, if (vport_node->type == SCHED_NODE_TYPE_TC_ARBITER_TSAR) err = esw_qos_vport_update(vport, SCHED_NODE_TYPE_VPORT, vport_node->parent, extack); + esw_vport_qos_prune_empty(vport); goto unlock; } @@ -1893,14 +1928,20 @@ int mlx5_esw_devlink_rate_leaf_parent_set(struct devlink_rate *devlink_rate, void *priv, void *parent_priv, struct netlink_ext_ack *extack) { - struct mlx5_esw_sched_node *node; + struct mlx5_esw_sched_node *node = parent ? parent_priv : NULL; struct mlx5_vport *vport = priv; + int err; - if (!parent) - return mlx5_esw_qos_vport_update_parent(vport, NULL, extack); + err = mlx5_esw_qos_vport_update_parent(vport, node, extack); + if (!err) { + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + + esw_qos_lock(esw); + esw_vport_qos_prune_empty(vport); + esw_qos_unlock(esw); + } - node = parent_priv; - return mlx5_esw_qos_vport_update_parent(vport, node, extack); + return err; } static bool esw_qos_is_node_empty(struct mlx5_esw_sched_node *node) From 3c114fb2afe493066df5b9e560ef37216b153c90 Mon Sep 17 00:00:00 2001 From: Carolina Jubran Date: Wed, 20 Aug 2025 16:32:06 +0300 Subject: [PATCH 0477/1292] net/mlx5: Fix QoS reference leak in vport enable error path Add missing esw_qos_put() call when __esw_qos_alloc_node() fails in mlx5_esw_qos_vport_enable(). Fixes: be034baba83e ("net/mlx5: Make vport QoS enablement more flexible for future extensions") Signed-off-by: Carolina Jubran Reviewed-by: Cosmin Ratiu Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250820133209.389065-6-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index 452a948a3e6d22..41aec07bb6c208 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -1109,8 +1109,10 @@ static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_t parent_esw = parent ? parent->esw : esw; sched_node = __esw_qos_alloc_node(parent_esw, 0, type, parent); - if (!sched_node) + if (!sched_node) { + esw_qos_put(esw); return -ENOMEM; + } if (!parent) list_add_tail(&sched_node->entry, &esw->qos.domain->nodes); From 51b17c98e3dbb2093a81b0490050a0eaa919ebee Mon Sep 17 00:00:00 2001 From: Carolina Jubran Date: Wed, 20 Aug 2025 16:32:07 +0300 Subject: [PATCH 0478/1292] net/mlx5: Restore missing scheduling node cleanup on vport enable failure Restore the __esw_qos_free_node() call removed by the offending commit. Fixes: 97733d1e00a0 ("net/mlx5: Add traffic class scheduling support for vport QoS") Signed-off-by: Carolina Jubran Reviewed-by: Tariq Toukan Reviewed-by: Cosmin Ratiu Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250820133209.389065-7-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index 41aec07bb6c208..8b497765018381 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -1122,6 +1122,7 @@ static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_t vport->qos.sched_node = sched_node; err = esw_qos_vport_enable(vport, type, parent, extack); if (err) { + __esw_qos_free_node(sched_node); esw_qos_put(esw); vport->qos.sched_node = NULL; } From 451d2849ea66659040b59ae3cb7e50cc97404733 Mon Sep 17 00:00:00 2001 From: Alexei Lazar Date: Wed, 20 Aug 2025 16:32:08 +0300 Subject: [PATCH 0479/1292] net/mlx5e: Query FW for buffer ownership The SW currently saves local buffer ownership when setting the buffer. This means that the SW assumes it has ownership of the buffer after the command is set. If setting the buffer fails and we remain in FW ownership, the local buffer ownership state incorrectly remains as SW-owned. This leads to incorrect behavior in subsequent PFC commands, causing failures. Instead of saving local buffer ownership in SW, query the FW for buffer ownership when setting the buffer. This ensures that the buffer ownership state is accurately reflected, avoiding the issues caused by incorrect ownership states. Fixes: ecdf2dadee8e ("net/mlx5e: Receive buffer support for DCBX") Signed-off-by: Alexei Lazar Reviewed-by: Shahar Shitrit Reviewed-by: Dragos Tatulea Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250820133209.389065-8-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlx5/core/en/dcbnl.h | 1 - .../ethernet/mellanox/mlx5/core/en_dcbnl.c | 12 ++++++++--- .../ethernet/mellanox/mlx5/core/mlx5_core.h | 2 ++ .../net/ethernet/mellanox/mlx5/core/port.c | 20 +++++++++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/dcbnl.h b/drivers/net/ethernet/mellanox/mlx5/core/en/dcbnl.h index b59aee75de94e2..2c98a5299df337 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/dcbnl.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/dcbnl.h @@ -26,7 +26,6 @@ struct mlx5e_dcbx { u8 cap; /* Buffer configuration */ - bool manual_buffer; u32 cable_len; u32 xoff; u16 port_buff_cell_sz; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index 5fe016e477b37e..d166c0d5189e19 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c @@ -362,6 +362,7 @@ static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev, static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc) { + u8 buffer_ownership = MLX5_BUF_OWNERSHIP_UNKNOWN; struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5_core_dev *mdev = priv->mdev; u32 old_cable_len = priv->dcbx.cable_len; @@ -389,7 +390,14 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, if (MLX5_BUFFER_SUPPORTED(mdev)) { pfc_new.pfc_en = (changed & MLX5E_PORT_BUFFER_PFC) ? pfc->pfc_en : curr_pfc_en; - if (priv->dcbx.manual_buffer) + ret = mlx5_query_port_buffer_ownership(mdev, + &buffer_ownership); + if (ret) + netdev_err(dev, + "%s, Failed to get buffer ownership: %d\n", + __func__, ret); + + if (buffer_ownership == MLX5_BUF_OWNERSHIP_SW_OWNED) ret = mlx5e_port_manual_buffer_config(priv, changed, dev->mtu, &pfc_new, NULL, NULL); @@ -982,7 +990,6 @@ static int mlx5e_dcbnl_setbuffer(struct net_device *dev, if (!changed) return 0; - priv->dcbx.manual_buffer = true; err = mlx5e_port_manual_buffer_config(priv, changed, dev->mtu, NULL, buffer_size, prio2buffer); return err; @@ -1252,7 +1259,6 @@ void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv) priv->dcbx.cap |= DCB_CAP_DCBX_HOST; priv->dcbx.port_buff_cell_sz = mlx5e_query_port_buffers_cell_size(priv); - priv->dcbx.manual_buffer = false; priv->dcbx.cable_len = MLX5E_DEFAULT_CABLE_LEN; mlx5e_ets_init(priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b6d53db27cd573..9d3504f5abfab2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -367,6 +367,8 @@ int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out); int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in); int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state); int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state); +int mlx5_query_port_buffer_ownership(struct mlx5_core_dev *mdev, + u8 *buffer_ownership); int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio); int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 549f1066d2a508..2d7adf7444ba29 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -968,6 +968,26 @@ int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state) return err; } +int mlx5_query_port_buffer_ownership(struct mlx5_core_dev *mdev, + u8 *buffer_ownership) +{ + u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {}; + int err; + + if (!MLX5_CAP_PCAM_FEATURE(mdev, buffer_ownership)) { + *buffer_ownership = MLX5_BUF_OWNERSHIP_UNKNOWN; + return 0; + } + + err = mlx5_query_pfcc_reg(mdev, out, sizeof(out)); + if (err) + return err; + + *buffer_ownership = MLX5_GET(pfcc_reg, out, buf_ownership); + + return 0; +} + int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio) { int sz = MLX5_ST_SZ_BYTES(qpdpm_reg); From 8b0587a885fdb34fd6090a3f8625cb7ac1444826 Mon Sep 17 00:00:00 2001 From: Armen Ratner Date: Wed, 20 Aug 2025 16:32:09 +0300 Subject: [PATCH 0480/1292] net/mlx5e: Preserve shared buffer capacity during headroom updates When port buffer headroom changes, port_update_shared_buffer() recalculates the shared buffer size and splits it in a 3:1 ratio (lossy:lossless) - Currently, the calculation is: lossless = shared / 4; lossy = (shared / 4) * 3; Meaning, the calculation dropped the remainder of shared % 4 due to integer division, unintentionally reducing the total shared buffer by up to three cells on each update. Over time, this could shrink the buffer below usable size. Fix it by changing the calculation to: lossless = shared / 4; lossy = shared - lossless; This retains all buffer cells while still approximating the intended 3:1 split, preventing capacity loss over time. While at it, perform headroom calculations in units of cells rather than in bytes for more accurate calculations avoiding extra divisions. Fixes: a440030d8946 ("net/mlx5e: Update shared buffer along with device buffer changes") Signed-off-by: Armen Ratner Signed-off-by: Maher Sanalla Reviewed-by: Tariq Toukan Signed-off-by: Alexei Lazar Signed-off-by: Mark Bloch Reviewed-by: Przemek Kitszel Link: https://patch.msgid.link/20250820133209.389065-9-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../mellanox/mlx5/core/en/port_buffer.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c index 5ae787656a7ca0..3efa8bf1d14ef4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c @@ -272,8 +272,8 @@ static int port_update_shared_buffer(struct mlx5_core_dev *mdev, /* Total shared buffer size is split in a ratio of 3:1 between * lossy and lossless pools respectively. */ - lossy_epool_size = (shared_buffer_size / 4) * 3; lossless_ipool_size = shared_buffer_size / 4; + lossy_epool_size = shared_buffer_size - lossless_ipool_size; mlx5e_port_set_sbpr(mdev, 0, MLX5_EGRESS_DIR, MLX5_LOSSY_POOL, 0, lossy_epool_size); @@ -288,14 +288,12 @@ static int port_set_buffer(struct mlx5e_priv *priv, u16 port_buff_cell_sz = priv->dcbx.port_buff_cell_sz; struct mlx5_core_dev *mdev = priv->mdev; int sz = MLX5_ST_SZ_BYTES(pbmc_reg); - u32 new_headroom_size = 0; - u32 current_headroom_size; + u32 current_headroom_cells = 0; + u32 new_headroom_cells = 0; void *in; int err; int i; - current_headroom_size = port_buffer->headroom_size; - in = kzalloc(sz, GFP_KERNEL); if (!in) return -ENOMEM; @@ -306,12 +304,14 @@ static int port_set_buffer(struct mlx5e_priv *priv, for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { void *buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]); + current_headroom_cells += MLX5_GET(bufferx_reg, buffer, size); + u64 size = port_buffer->buffer[i].size; u64 xoff = port_buffer->buffer[i].xoff; u64 xon = port_buffer->buffer[i].xon; - new_headroom_size += size; do_div(size, port_buff_cell_sz); + new_headroom_cells += size; do_div(xoff, port_buff_cell_sz); do_div(xon, port_buff_cell_sz); MLX5_SET(bufferx_reg, buffer, size, size); @@ -320,10 +320,8 @@ static int port_set_buffer(struct mlx5e_priv *priv, MLX5_SET(bufferx_reg, buffer, xon_threshold, xon); } - new_headroom_size /= port_buff_cell_sz; - current_headroom_size /= port_buff_cell_sz; - err = port_update_shared_buffer(priv->mdev, current_headroom_size, - new_headroom_size); + err = port_update_shared_buffer(priv->mdev, current_headroom_cells, + new_headroom_cells); if (err) goto out; From 8410fe81093ff231e964891e215b624dabb734b0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Aug 2025 17:08:34 +0200 Subject: [PATCH 0481/1292] ALSA: usb-audio: Use correct sub-type for UAC3 feature unit validation The entry of the validators table for UAC3 feature unit is defined with a wrong sub-type UAC_FEATURE (= 0x06) while it should have been UAC3_FEATURE (= 0x07). This patch corrects the entry value. Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units") Link: https://patch.msgid.link/20250821150835.8894-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/validate.c b/sound/usb/validate.c index 4f4e8e87a14cd0..a0d55b77c9941d 100644 --- a/sound/usb/validate.c +++ b/sound/usb/validate.c @@ -285,7 +285,7 @@ static const struct usb_desc_validator audio_validators[] = { /* UAC_VERSION_3, UAC3_EXTENDED_TERMINAL: not implemented yet */ FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit), FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit), - FUNC(UAC_VERSION_3, UAC_FEATURE_UNIT, validate_uac3_feature_unit), + FUNC(UAC_VERSION_3, UAC3_FEATURE_UNIT, validate_uac3_feature_unit), /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */ FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit), FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit), From 2aec0b6a6b5395bca7d6fde9c7e9dc391d329698 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Aug 2025 17:17:50 +0200 Subject: [PATCH 0482/1292] ALSA: usb-audio: Add validation of UAC2/UAC3 effect units Just add fixed struct size validations for UAC2 and UAC3 effect units. The descriptor has a variable-length array, so it should be validated with a proper function later once when the unit is really parsed and used by the driver (currently only referred partially for the input terminal parsing). Link: https://patch.msgid.link/20250821151751.12100-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/validate.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/usb/validate.c b/sound/usb/validate.c index a0d55b77c9941d..4bb4893f6e74f7 100644 --- a/sound/usb/validate.c +++ b/sound/usb/validate.c @@ -266,7 +266,11 @@ static const struct usb_desc_validator audio_validators[] = { FUNC(UAC_VERSION_2, UAC_MIXER_UNIT, validate_mixer_unit), FUNC(UAC_VERSION_2, UAC_SELECTOR_UNIT, validate_selector_unit), FUNC(UAC_VERSION_2, UAC_FEATURE_UNIT, validate_uac2_feature_unit), - /* UAC_VERSION_2, UAC2_EFFECT_UNIT: not implemented yet */ + /* just a stop-gap, it should be a proper function for the array + * once if the unit is really parsed/used + */ + FIXED(UAC_VERSION_2, UAC2_EFFECT_UNIT, + struct uac2_effect_unit_descriptor), FUNC(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2, validate_processing_unit), FUNC(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2, validate_processing_unit), FIXED(UAC_VERSION_2, UAC2_CLOCK_SOURCE, @@ -286,7 +290,8 @@ static const struct usb_desc_validator audio_validators[] = { FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit), FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit), FUNC(UAC_VERSION_3, UAC3_FEATURE_UNIT, validate_uac3_feature_unit), - /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */ + FIXED(UAC_VERSION_3, UAC3_EFFECT_UNIT, + struct uac2_effect_unit_descriptor), /* sharing the same struct */ FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit), FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit), FIXED(UAC_VERSION_3, UAC3_CLOCK_SOURCE, From fec7bdfe7f8694a0c39e6c3ec026ff61ca1058b9 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 21 Aug 2025 14:35:40 +0200 Subject: [PATCH 0483/1292] s390/hypfs: Avoid unnecessary ioctl registration in debugfs Currently, hypfs registers ioctl callbacks for all debugfs files, despite only one file requiring them. This leads to unintended exposure of unused interfaces to user space and can trigger side effects such as restricted access when kernel lockdown is enabled. Restrict ioctl registration to only those files that implement ioctl functionality to avoid interface clutter and unnecessary access restrictions. Tested-by: Mete Durlu Reviewed-by: Vasily Gorbik Fixes: 5496197f9b08 ("debugfs: Restrict debugfs when the kernel is locked down") Signed-off-by: Peter Oberparleiter Signed-off-by: Alexander Gordeev --- arch/s390/hypfs/hypfs_dbfs.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c index 5d9effb0867cde..e74eb8f9b23a5b 100644 --- a/arch/s390/hypfs/hypfs_dbfs.c +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -66,23 +66,27 @@ static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) long rc; mutex_lock(&df->lock); - if (df->unlocked_ioctl) - rc = df->unlocked_ioctl(file, cmd, arg); - else - rc = -ENOTTY; + rc = df->unlocked_ioctl(file, cmd, arg); mutex_unlock(&df->lock); return rc; } -static const struct file_operations dbfs_ops = { +static const struct file_operations dbfs_ops_ioctl = { .read = dbfs_read, .unlocked_ioctl = dbfs_ioctl, }; +static const struct file_operations dbfs_ops = { + .read = dbfs_read, +}; + void hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) { - df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, - &dbfs_ops); + const struct file_operations *fops = &dbfs_ops; + + if (df->unlocked_ioctl) + fops = &dbfs_ops_ioctl; + df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, fops); mutex_init(&df->lock); } From 3868f910440c47cd5d158776be4ba4e2186beda7 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 21 Aug 2025 15:12:37 +0200 Subject: [PATCH 0484/1292] s390/hypfs: Enable limited access during lockdown When kernel lockdown is active, debugfs_locked_down() blocks access to hypfs files that register ioctl callbacks, even if the ioctl interface is not required for a function. This unnecessarily breaks userspace tools that only rely on read operations. Resolve this by registering a minimal set of file operations during lockdown, avoiding ioctl registration and preserving access for affected tooling. Note that this change restores hypfs functionality when lockdown is active from early boot (e.g. via lockdown=integrity kernel parameter), but does not apply to scenarios where lockdown is enabled dynamically while Linux is running. Tested-by: Mete Durlu Reviewed-by: Vasily Gorbik Fixes: 5496197f9b08 ("debugfs: Restrict debugfs when the kernel is locked down") Signed-off-by: Peter Oberparleiter Signed-off-by: Alexander Gordeev --- arch/s390/hypfs/hypfs_dbfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c index e74eb8f9b23a5b..41a0d2066fa002 100644 --- a/arch/s390/hypfs/hypfs_dbfs.c +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -6,6 +6,7 @@ * Author(s): Michael Holzheu */ +#include #include #include "hypfs.h" @@ -84,7 +85,7 @@ void hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) { const struct file_operations *fops = &dbfs_ops; - if (df->unlocked_ioctl) + if (df->unlocked_ioctl && !security_locked_down(LOCKDOWN_DEBUGFS)) fops = &dbfs_ops_ioctl; df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, fops); mutex_init(&df->lock); From cb83b559bea39f207ee214ee2972657e8576ed18 Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Fri, 25 Jul 2025 11:42:18 -0700 Subject: [PATCH 0485/1292] idpf: add support for Tx refillqs in flow scheduling mode In certain production environments, it is possible for completion tags to collide, meaning N packets with the same completion tag are in flight at the same time. In this environment, any given Tx queue is effectively used to send both slower traffic and higher throughput traffic simultaneously. This is the result of a customer's specific configuration in the device pipeline, the details of which Intel cannot provide. This configuration results in a small number of out-of-order completions, i.e., a small number of packets in flight. The existing guardrails in the driver only protect against a large number of packets in flight. The slower flow completions are delayed which causes the out-of-order completions. The fast flow will continue sending traffic and generating tags. Because tags are generated on the fly, the fast flow eventually uses the same tag for a packet that is still in flight from the slower flow. The driver has no idea which packet it should clean when it processes the completion with that tag, but it will look for the packet on the buffer ring before the hash table. If the slower flow packet completion is processed first, it will end up cleaning the fast flow packet on the ring prematurely. This leaves the descriptor ring in a bad state resulting in a crash or Tx timeout. In summary, generating a tag when a packet is sent can lead to the same tag being associated with multiple packets. This can lead to resource leaks, crashes, and/or Tx timeouts. Before we can replace the tag generation, we need a new mechanism for the send path to know what tag to use next. The driver will allocate and initialize a refillq for each TxQ with all of the possible free tag values. During send, the driver grabs the next free tag from the refillq from next_to_clean. While cleaning the packet, the clean routine posts the tag back to the refillq's next_to_use to indicate that it is now free to use. This mechanism works exactly the same way as the existing Rx refill queues, which post the cleaned buffer IDs back to the buffer queue to be reposted to HW. Since we're using the refillqs for both Rx and Tx now, genericize some of the existing refillq support. Note: the refillqs will not be used yet. This is only demonstrating how they will be used to pass free tags back to the send path. Signed-off-by: Joshua Hay Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 93 +++++++++++++++++++-- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 8 +- 2 files changed, 91 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 66a1b040639d11..9b63944235fb74 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -139,6 +139,9 @@ static void idpf_tx_desc_rel(struct idpf_tx_queue *txq) if (!txq->desc_ring) return; + if (txq->refillq) + kfree(txq->refillq->ring); + dmam_free_coherent(txq->dev, txq->size, txq->desc_ring, txq->dma); txq->desc_ring = NULL; txq->next_to_use = 0; @@ -244,6 +247,7 @@ static int idpf_tx_desc_alloc(const struct idpf_vport *vport, struct idpf_tx_queue *tx_q) { struct device *dev = tx_q->dev; + struct idpf_sw_queue *refillq; int err; err = idpf_tx_buf_alloc_all(tx_q); @@ -267,6 +271,29 @@ static int idpf_tx_desc_alloc(const struct idpf_vport *vport, tx_q->next_to_clean = 0; idpf_queue_set(GEN_CHK, tx_q); + if (!idpf_queue_has(FLOW_SCH_EN, tx_q)) + return 0; + + refillq = tx_q->refillq; + refillq->desc_count = tx_q->desc_count; + refillq->ring = kcalloc(refillq->desc_count, sizeof(u32), + GFP_KERNEL); + if (!refillq->ring) { + err = -ENOMEM; + goto err_alloc; + } + + for (unsigned int i = 0; i < refillq->desc_count; i++) + refillq->ring[i] = + FIELD_PREP(IDPF_RFL_BI_BUFID_M, i) | + FIELD_PREP(IDPF_RFL_BI_GEN_M, + idpf_queue_has(GEN_CHK, refillq)); + + /* Go ahead and flip the GEN bit since this counts as filling + * up the ring, i.e. we already ring wrapped. + */ + idpf_queue_change(GEN_CHK, refillq); + return 0; err_alloc: @@ -603,18 +630,18 @@ static int idpf_rx_hdr_buf_alloc_all(struct idpf_buf_queue *bufq) } /** - * idpf_rx_post_buf_refill - Post buffer id to refill queue + * idpf_post_buf_refill - Post buffer id to refill queue * @refillq: refill queue to post to * @buf_id: buffer id to post */ -static void idpf_rx_post_buf_refill(struct idpf_sw_queue *refillq, u16 buf_id) +static void idpf_post_buf_refill(struct idpf_sw_queue *refillq, u16 buf_id) { u32 nta = refillq->next_to_use; /* store the buffer ID and the SW maintained GEN bit to the refillq */ refillq->ring[nta] = - FIELD_PREP(IDPF_RX_BI_BUFID_M, buf_id) | - FIELD_PREP(IDPF_RX_BI_GEN_M, + FIELD_PREP(IDPF_RFL_BI_BUFID_M, buf_id) | + FIELD_PREP(IDPF_RFL_BI_GEN_M, idpf_queue_has(GEN_CHK, refillq)); if (unlikely(++nta == refillq->desc_count)) { @@ -995,6 +1022,11 @@ static void idpf_txq_group_rel(struct idpf_vport *vport) struct idpf_txq_group *txq_grp = &vport->txq_grps[i]; for (j = 0; j < txq_grp->num_txq; j++) { + if (flow_sch_en) { + kfree(txq_grp->txqs[j]->refillq); + txq_grp->txqs[j]->refillq = NULL; + } + kfree(txq_grp->txqs[j]); txq_grp->txqs[j] = NULL; } @@ -1414,6 +1446,13 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq) } idpf_queue_set(FLOW_SCH_EN, q); + + q->refillq = kzalloc(sizeof(*q->refillq), GFP_KERNEL); + if (!q->refillq) + goto err_alloc; + + idpf_queue_set(GEN_CHK, q->refillq); + idpf_queue_set(RFL_GEN_CHK, q->refillq); } if (!split) @@ -2005,6 +2044,8 @@ static void idpf_tx_handle_rs_completion(struct idpf_tx_queue *txq, compl_tag = le16_to_cpu(desc->q_head_compl_tag.compl_tag); + idpf_post_buf_refill(txq->refillq, compl_tag); + /* If we didn't clean anything on the ring, this packet must be * in the hash table. Go clean it there. */ @@ -2364,6 +2405,37 @@ static unsigned int idpf_tx_splitq_bump_ntu(struct idpf_tx_queue *txq, u16 ntu) return ntu; } +/** + * idpf_tx_get_free_buf_id - get a free buffer ID from the refill queue + * @refillq: refill queue to get buffer ID from + * @buf_id: return buffer ID + * + * Return: true if a buffer ID was found, false if not + */ +static bool idpf_tx_get_free_buf_id(struct idpf_sw_queue *refillq, + u16 *buf_id) +{ + u32 ntc = refillq->next_to_clean; + u32 refill_desc; + + refill_desc = refillq->ring[ntc]; + + if (unlikely(idpf_queue_has(RFL_GEN_CHK, refillq) != + !!(refill_desc & IDPF_RFL_BI_GEN_M))) + return false; + + *buf_id = FIELD_GET(IDPF_RFL_BI_BUFID_M, refill_desc); + + if (unlikely(++ntc == refillq->desc_count)) { + idpf_queue_change(RFL_GEN_CHK, refillq); + ntc = 0; + } + + refillq->next_to_clean = ntc; + + return true; +} + /** * idpf_tx_splitq_map - Build the Tx flex descriptor * @tx_q: queue to send buffer on @@ -2912,6 +2984,13 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, } if (idpf_queue_has(FLOW_SCH_EN, tx_q)) { + if (unlikely(!idpf_tx_get_free_buf_id(tx_q->refillq, + &tx_params.compl_tag))) { + u64_stats_update_begin(&tx_q->stats_sync); + u64_stats_inc(&tx_q->q_stats.q_busy); + u64_stats_update_end(&tx_q->stats_sync); + } + tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE; tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP; /* Set the RE bit to catch any packets that may have not been @@ -3472,7 +3551,7 @@ static int idpf_rx_splitq_clean(struct idpf_rx_queue *rxq, int budget) skip_data: rx_buf->netmem = 0; - idpf_rx_post_buf_refill(refillq, buf_id); + idpf_post_buf_refill(refillq, buf_id); IDPF_RX_BUMP_NTC(rxq, ntc); /* skip if it is non EOP desc */ @@ -3580,10 +3659,10 @@ static void idpf_rx_clean_refillq(struct idpf_buf_queue *bufq, bool failure; if (idpf_queue_has(RFL_GEN_CHK, refillq) != - !!(refill_desc & IDPF_RX_BI_GEN_M)) + !!(refill_desc & IDPF_RFL_BI_GEN_M)) break; - buf_id = FIELD_GET(IDPF_RX_BI_BUFID_M, refill_desc); + buf_id = FIELD_GET(IDPF_RFL_BI_BUFID_M, refill_desc); failure = idpf_rx_update_bufq_desc(bufq, buf_id, buf_desc); if (failure) break; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 281de655a813bb..58232a1bd0a9b0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -108,8 +108,8 @@ do { \ */ #define IDPF_TX_SPLITQ_RE_MIN_GAP 64 -#define IDPF_RX_BI_GEN_M BIT(16) -#define IDPF_RX_BI_BUFID_M GENMASK(15, 0) +#define IDPF_RFL_BI_GEN_M BIT(16) +#define IDPF_RFL_BI_BUFID_M GENMASK(15, 0) #define IDPF_RXD_EOF_SPLITQ VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_EOF_M #define IDPF_RXD_EOF_SINGLEQ VIRTCHNL2_RX_BASE_DESC_STATUS_EOF_M @@ -622,6 +622,7 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64, * @cleaned_pkts: Number of packets cleaned for the above said case * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather * @stash: Tx buffer stash for Flow-based scheduling mode + * @refillq: Pointer to refill queue * @compl_tag_bufid_m: Completion tag buffer id mask * @compl_tag_cur_gen: Used to keep track of current completion tag generation * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset @@ -671,6 +672,7 @@ struct idpf_tx_queue { u16 tx_max_bufs; struct idpf_txq_stash *stash; + struct idpf_sw_queue *refillq; u16 compl_tag_bufid_m; u16 compl_tag_cur_gen; @@ -692,7 +694,7 @@ struct idpf_tx_queue { __cacheline_group_end_aligned(cold); }; libeth_cacheline_set_assert(struct idpf_tx_queue, 64, - 112 + sizeof(struct u64_stats_sync), + 120 + sizeof(struct u64_stats_sync), 24); /** From f2d18e16479cac7a708d77cbfb4220a9114a71fc Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Fri, 25 Jul 2025 11:42:19 -0700 Subject: [PATCH 0486/1292] idpf: improve when to set RE bit logic Track the gap between next_to_use and the last RE index. Set RE again if the gap is large enough to ensure RE bit is set frequently. This is critical before removing the stashing mechanisms because the opportunistic descriptor ring cleaning from the out-of-order completions will go away. Previously the descriptors would be "cleaned" by both the descriptor (RE) completion and the out-of-order completions. Without the latter, we must ensure the RE bit is set more frequently. Otherwise, it's theoretically possible for the descriptor ring next_to_clean to never advance. The previous implementation was dependent on the start of a packet falling on a 64th index in the descriptor ring, which is not guaranteed with large packets. Signed-off-by: Luigi Rizzo Signed-off-by: Brian Vazquez Signed-off-by: Joshua Hay Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 20 +++++++++++++++++++- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 6 ++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 9b63944235fb74..ee59153508af68 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -294,6 +294,8 @@ static int idpf_tx_desc_alloc(const struct idpf_vport *vport, */ idpf_queue_change(GEN_CHK, refillq); + tx_q->last_re = tx_q->desc_count - IDPF_TX_SPLITQ_RE_MIN_GAP; + return 0; err_alloc: @@ -2912,6 +2914,21 @@ static void idpf_tx_set_tstamp_desc(union idpf_flex_tx_ctx_desc *ctx_desc, { } #endif /* CONFIG_PTP_1588_CLOCK */ +/** + * idpf_tx_splitq_need_re - check whether RE bit needs to be set + * @tx_q: pointer to Tx queue + * + * Return: true if RE bit needs to be set, false otherwise + */ +static bool idpf_tx_splitq_need_re(struct idpf_tx_queue *tx_q) +{ + int gap = tx_q->next_to_use - tx_q->last_re; + + gap += (gap < 0) ? tx_q->desc_count : 0; + + return gap >= IDPF_TX_SPLITQ_RE_MIN_GAP; +} + /** * idpf_tx_splitq_frame - Sends buffer on Tx ring using flex descriptors * @skb: send buffer @@ -2998,9 +3015,10 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, * MIN_RING size to ensure it will be set at least once each * time around the ring. */ - if (!(tx_q->next_to_use % IDPF_TX_SPLITQ_RE_MIN_GAP)) { + if (idpf_tx_splitq_need_re(tx_q)) { tx_params.eop_cmd |= IDPF_TXD_FLEX_FLOW_CMD_RE; tx_q->txq_grp->num_completions_pending++; + tx_q->last_re = tx_q->next_to_use; } if (skb->ip_summed == CHECKSUM_PARTIAL) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 58232a1bd0a9b0..c75ca5d3e57cc0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -610,6 +610,8 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64, * @netdev: &net_device corresponding to this queue * @next_to_use: Next descriptor to use * @next_to_clean: Next descriptor to clean + * @last_re: last descriptor index that RE bit was set + * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather * @cleaned_bytes: Splitq only, TXQ only: When a TX completion is received on * the TX completion queue, it can be for any TXQ associated * with that completion queue. This means we can clean up to @@ -620,7 +622,6 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64, * only once at the end of the cleaning routine. * @clean_budget: singleq only, queue cleaning budget * @cleaned_pkts: Number of packets cleaned for the above said case - * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather * @stash: Tx buffer stash for Flow-based scheduling mode * @refillq: Pointer to refill queue * @compl_tag_bufid_m: Completion tag buffer id mask @@ -663,6 +664,8 @@ struct idpf_tx_queue { __cacheline_group_begin_aligned(read_write); u16 next_to_use; u16 next_to_clean; + u16 last_re; + u16 tx_max_bufs; union { u32 cleaned_bytes; @@ -670,7 +673,6 @@ struct idpf_tx_queue { }; u16 cleaned_pkts; - u16 tx_max_bufs; struct idpf_txq_stash *stash; struct idpf_sw_queue *refillq; From b61dfa9bc4430ad82b96d3a7c1c485350f91b467 Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Fri, 25 Jul 2025 11:42:20 -0700 Subject: [PATCH 0487/1292] idpf: simplify and fix splitq Tx packet rollback error path Move (and rename) the existing rollback logic to singleq.c since that will be the only consumer. Create a simplified splitq specific rollback function to loop through and unmap tx_bufs based on the completion tag. This is critical before replacing the Tx buffer ring with the buffer pool since the previous rollback indexing will not work to unmap the chained buffers from the pool. Cache the next_to_use index before any portion of the packet is put on the descriptor ring. In case of an error, the rollback will bump tail to the correct next_to_use value. Because the splitq path now supports different types of context descriptors (and potentially multiple in the future), this will take care of rolling back any and all context descriptors encoded on the ring for the erroneous packet. The previous rollback logic was broken for PTP packets since it would not account for the PTP context descriptor. Fixes: 1a49cf814fe1 ("idpf: add Tx timestamp flows") Signed-off-by: Joshua Hay Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- .../ethernet/intel/idpf/idpf_singleq_txrx.c | 57 +++++++++++- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 91 ++++++++----------- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 5 +- 3 files changed, 95 insertions(+), 58 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c index 555879b1248d84..57c0f5ab8f9ed8 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c @@ -179,6 +179,58 @@ static int idpf_tx_singleq_csum(struct sk_buff *skb, return 1; } +/** + * idpf_tx_singleq_dma_map_error - handle TX DMA map errors + * @txq: queue to send buffer on + * @skb: send buffer + * @first: original first buffer info buffer for packet + * @idx: starting point on ring to unwind + */ +static void idpf_tx_singleq_dma_map_error(struct idpf_tx_queue *txq, + struct sk_buff *skb, + struct idpf_tx_buf *first, u16 idx) +{ + struct libeth_sq_napi_stats ss = { }; + struct libeth_cq_pp cp = { + .dev = txq->dev, + .ss = &ss, + }; + + u64_stats_update_begin(&txq->stats_sync); + u64_stats_inc(&txq->q_stats.dma_map_errs); + u64_stats_update_end(&txq->stats_sync); + + /* clear dma mappings for failed tx_buf map */ + for (;;) { + struct idpf_tx_buf *tx_buf; + + tx_buf = &txq->tx_buf[idx]; + libeth_tx_complete(tx_buf, &cp); + if (tx_buf == first) + break; + if (idx == 0) + idx = txq->desc_count; + idx--; + } + + if (skb_is_gso(skb)) { + union idpf_tx_flex_desc *tx_desc; + + /* If we failed a DMA mapping for a TSO packet, we will have + * used one additional descriptor for a context + * descriptor. Reset that here. + */ + tx_desc = &txq->flex_tx[idx]; + memset(tx_desc, 0, sizeof(*tx_desc)); + if (idx == 0) + idx = txq->desc_count; + idx--; + } + + /* Update tail in case netdev_xmit_more was previously true */ + idpf_tx_buf_hw_update(txq, idx, false); +} + /** * idpf_tx_singleq_map - Build the Tx base descriptor * @tx_q: queue to send buffer on @@ -219,8 +271,9 @@ static void idpf_tx_singleq_map(struct idpf_tx_queue *tx_q, for (frag = &skb_shinfo(skb)->frags[0];; frag++) { unsigned int max_data = IDPF_TX_MAX_DESC_DATA_ALIGNED; - if (dma_mapping_error(tx_q->dev, dma)) - return idpf_tx_dma_map_error(tx_q, skb, first, i); + if (unlikely(dma_mapping_error(tx_q->dev, dma))) + return idpf_tx_singleq_dma_map_error(tx_q, skb, + first, i); /* record length, and DMA address */ dma_unmap_len_set(tx_buf, len, size); diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index ee59153508af68..527d56bcbbef3f 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -2339,57 +2339,6 @@ unsigned int idpf_tx_desc_count_required(struct idpf_tx_queue *txq, return count; } -/** - * idpf_tx_dma_map_error - handle TX DMA map errors - * @txq: queue to send buffer on - * @skb: send buffer - * @first: original first buffer info buffer for packet - * @idx: starting point on ring to unwind - */ -void idpf_tx_dma_map_error(struct idpf_tx_queue *txq, struct sk_buff *skb, - struct idpf_tx_buf *first, u16 idx) -{ - struct libeth_sq_napi_stats ss = { }; - struct libeth_cq_pp cp = { - .dev = txq->dev, - .ss = &ss, - }; - - u64_stats_update_begin(&txq->stats_sync); - u64_stats_inc(&txq->q_stats.dma_map_errs); - u64_stats_update_end(&txq->stats_sync); - - /* clear dma mappings for failed tx_buf map */ - for (;;) { - struct idpf_tx_buf *tx_buf; - - tx_buf = &txq->tx_buf[idx]; - libeth_tx_complete(tx_buf, &cp); - if (tx_buf == first) - break; - if (idx == 0) - idx = txq->desc_count; - idx--; - } - - if (skb_is_gso(skb)) { - union idpf_tx_flex_desc *tx_desc; - - /* If we failed a DMA mapping for a TSO packet, we will have - * used one additional descriptor for a context - * descriptor. Reset that here. - */ - tx_desc = &txq->flex_tx[idx]; - memset(tx_desc, 0, sizeof(*tx_desc)); - if (idx == 0) - idx = txq->desc_count; - idx--; - } - - /* Update tail in case netdev_xmit_more was previously true */ - idpf_tx_buf_hw_update(txq, idx, false); -} - /** * idpf_tx_splitq_bump_ntu - adjust NTU and generation * @txq: the tx ring to wrap @@ -2438,6 +2387,37 @@ static bool idpf_tx_get_free_buf_id(struct idpf_sw_queue *refillq, return true; } +/** + * idpf_tx_splitq_pkt_err_unmap - Unmap buffers and bump tail in case of error + * @txq: Tx queue to unwind + * @params: pointer to splitq params struct + * @first: starting buffer for packet to unmap + */ +static void idpf_tx_splitq_pkt_err_unmap(struct idpf_tx_queue *txq, + struct idpf_tx_splitq_params *params, + struct idpf_tx_buf *first) +{ + struct libeth_sq_napi_stats ss = { }; + struct idpf_tx_buf *tx_buf = first; + struct libeth_cq_pp cp = { + .dev = txq->dev, + .ss = &ss, + }; + u32 idx = 0; + + u64_stats_update_begin(&txq->stats_sync); + u64_stats_inc(&txq->q_stats.dma_map_errs); + u64_stats_update_end(&txq->stats_sync); + + do { + libeth_tx_complete(tx_buf, &cp); + idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf); + } while (idpf_tx_buf_compl_tag(tx_buf) == params->compl_tag); + + /* Update tail in case netdev_xmit_more was previously true. */ + idpf_tx_buf_hw_update(txq, params->prev_ntu, false); +} + /** * idpf_tx_splitq_map - Build the Tx flex descriptor * @tx_q: queue to send buffer on @@ -2482,8 +2462,9 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, for (frag = &skb_shinfo(skb)->frags[0];; frag++) { unsigned int max_data = IDPF_TX_MAX_DESC_DATA_ALIGNED; - if (dma_mapping_error(tx_q->dev, dma)) - return idpf_tx_dma_map_error(tx_q, skb, first, i); + if (unlikely(dma_mapping_error(tx_q->dev, dma))) + return idpf_tx_splitq_pkt_err_unmap(tx_q, params, + first); first->nr_frags++; idpf_tx_buf_compl_tag(tx_buf) = params->compl_tag; @@ -2939,7 +2920,9 @@ static bool idpf_tx_splitq_need_re(struct idpf_tx_queue *tx_q) static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, struct idpf_tx_queue *tx_q) { - struct idpf_tx_splitq_params tx_params = { }; + struct idpf_tx_splitq_params tx_params = { + .prev_ntu = tx_q->next_to_use, + }; union idpf_flex_tx_ctx_desc *ctx_desc; struct idpf_tx_buf *first; unsigned int count; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index c75ca5d3e57cc0..a7632d845a2a2b 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -196,6 +196,7 @@ struct idpf_tx_offload_params { * @compl_tag: Associated tag for completion * @td_tag: Descriptor tunneling tag * @offload: Offload parameters + * @prev_ntu: stored TxQ next_to_use in case of rollback */ struct idpf_tx_splitq_params { enum idpf_tx_desc_dtype_value dtype; @@ -206,6 +207,8 @@ struct idpf_tx_splitq_params { }; struct idpf_tx_offload_params offload; + + u16 prev_ntu; }; enum idpf_tx_ctx_desc_eipt_offload { @@ -1042,8 +1045,6 @@ void idpf_tx_buf_hw_update(struct idpf_tx_queue *tx_q, u32 val, bool xmit_more); unsigned int idpf_size_to_txd_count(unsigned int size); netdev_tx_t idpf_tx_drop_skb(struct idpf_tx_queue *tx_q, struct sk_buff *skb); -void idpf_tx_dma_map_error(struct idpf_tx_queue *txq, struct sk_buff *skb, - struct idpf_tx_buf *first, u16 ring_idx); unsigned int idpf_tx_desc_count_required(struct idpf_tx_queue *txq, struct sk_buff *skb); void idpf_tx_timeout(struct net_device *netdev, unsigned int txqueue); From 5f417d551324d2894168b362f2429d120ab06243 Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Fri, 25 Jul 2025 11:42:21 -0700 Subject: [PATCH 0488/1292] idpf: replace flow scheduling buffer ring with buffer pool Replace the TxQ buffer ring with one large pool/array of buffers (only for flow scheduling). This eliminates the tag generation and makes it impossible for a tag to be associated with more than one packet. The completion tag passed to HW through the descriptor is the index into the array. That same completion tag is posted back to the driver in the completion descriptor, and used to index into the array to quickly retrieve the buffer during cleaning. In this way, the tags are treated as a fix sized resource. If all tags are in use, no more packets can be sent on that particular queue (until some are freed up). The tag pool size is 64K since the completion tag width is 16 bits. For each packet, the driver pulls a free tag from the refillq to get the next free buffer index. When cleaning is complete, the tag is posted back to the refillq. A multi-frag packet spans multiple buffers in the driver, therefore it uses multiple buffer indexes/tags from the pool. Each frag pulls from the refillq to get the next free buffer index. These are tracked in a next_buf field that replaces the completion tag field in the buffer struct. This chains the buffers together so that the packet can be cleaned from the starting completion tag taken from the completion descriptor, then from the next_buf field for each subsequent buffer. In case of a dma_mapping_error occurs or the refillq runs out of free buf_ids, the packet will execute the rollback error path. This unmaps any buffers previously mapped for the packet. Since several free buf_ids could have already been pulled from the refillq, we need to restore its original state as well. Otherwise, the buf_ids/tags will be leaked and not used again until the queue is reallocated. Descriptor completions only advance the descriptor ring index to "clean" the descriptors. The packet completions only clean the buffers associated with the given packet completion tag and do not update the descriptor ring index. When operating in queue based scheduling mode, the array still acts as a ring and will only have TxQ descriptor count entries. The tx_bufs are still associated 1:1 with the descriptor ring entries and we can use the conventional indexing mechanisms. Fixes: c2d548cad150 ("idpf: add TX splitq napi poll support") Signed-off-by: Luigi Rizzo Signed-off-by: Brian Vazquez Signed-off-by: Joshua Hay Reviewed-by: Madhu Chittim Reviewed-by: Aleksandr Loktionov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 204 +++++++++----------- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 10 +- 2 files changed, 103 insertions(+), 111 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 527d56bcbbef3f..5fe329a7c944e6 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -13,6 +13,7 @@ struct idpf_tx_stash { struct libeth_sqe buf; }; +#define idpf_tx_buf_next(buf) (*(u32 *)&(buf)->priv) #define idpf_tx_buf_compl_tag(buf) (*(u32 *)&(buf)->priv) LIBETH_SQE_CHECK_PRIV(u32); @@ -91,7 +92,7 @@ static void idpf_tx_buf_rel_all(struct idpf_tx_queue *txq) return; /* Free all the Tx buffer sk_buffs */ - for (i = 0; i < txq->desc_count; i++) + for (i = 0; i < txq->buf_pool_size; i++) libeth_tx_complete(&txq->tx_buf[i], &cp); kfree(txq->tx_buf); @@ -199,14 +200,17 @@ static void idpf_tx_desc_rel_all(struct idpf_vport *vport) static int idpf_tx_buf_alloc_all(struct idpf_tx_queue *tx_q) { struct idpf_buf_lifo *buf_stack; - int buf_size; int i; /* Allocate book keeping buffers only. Buffers to be supplied to HW * are allocated by kernel network stack and received as part of skb */ - buf_size = sizeof(struct idpf_tx_buf) * tx_q->desc_count; - tx_q->tx_buf = kzalloc(buf_size, GFP_KERNEL); + if (idpf_queue_has(FLOW_SCH_EN, tx_q)) + tx_q->buf_pool_size = U16_MAX; + else + tx_q->buf_pool_size = tx_q->desc_count; + tx_q->tx_buf = kcalloc(tx_q->buf_pool_size, sizeof(*tx_q->tx_buf), + GFP_KERNEL); if (!tx_q->tx_buf) return -ENOMEM; @@ -275,7 +279,7 @@ static int idpf_tx_desc_alloc(const struct idpf_vport *vport, return 0; refillq = tx_q->refillq; - refillq->desc_count = tx_q->desc_count; + refillq->desc_count = tx_q->buf_pool_size; refillq->ring = kcalloc(refillq->desc_count, sizeof(u32), GFP_KERNEL); if (!refillq->ring) { @@ -1869,6 +1873,12 @@ static bool idpf_tx_splitq_clean(struct idpf_tx_queue *tx_q, u16 end, struct idpf_tx_buf *tx_buf; bool clean_complete = true; + if (descs_only) { + /* Bump ring index to mark as cleaned. */ + tx_q->next_to_clean = end; + return true; + } + tx_desc = &tx_q->flex_tx[ntc]; next_pending_desc = &tx_q->flex_tx[end]; tx_buf = &tx_q->tx_buf[ntc]; @@ -1935,87 +1945,43 @@ do { \ } while (0) /** - * idpf_tx_clean_buf_ring - clean flow scheduling TX queue buffers + * idpf_tx_clean_bufs - clean flow scheduling TX queue buffers * @txq: queue to clean - * @compl_tag: completion tag of packet to clean (from completion descriptor) + * @buf_id: packet's starting buffer ID, from completion descriptor * @cleaned: pointer to stats struct to track cleaned packets/bytes * @budget: Used to determine if we are in netpoll * - * Cleans all buffers associated with the input completion tag either from the - * TX buffer ring or from the hash table if the buffers were previously - * stashed. Returns the byte/segment count for the cleaned packet associated - * this completion tag. + * Clean all buffers associated with the packet starting at buf_id. Returns the + * byte/segment count for the cleaned packet. */ -static bool idpf_tx_clean_buf_ring(struct idpf_tx_queue *txq, u16 compl_tag, - struct libeth_sq_napi_stats *cleaned, - int budget) +static bool idpf_tx_clean_bufs(struct idpf_tx_queue *txq, u32 buf_id, + struct libeth_sq_napi_stats *cleaned, + int budget) { - u16 idx = compl_tag & txq->compl_tag_bufid_m; struct idpf_tx_buf *tx_buf = NULL; struct libeth_cq_pp cp = { .dev = txq->dev, .ss = cleaned, .napi = budget, }; - u16 ntc, orig_idx = idx; - - tx_buf = &txq->tx_buf[idx]; - - if (unlikely(tx_buf->type <= LIBETH_SQE_CTX || - idpf_tx_buf_compl_tag(tx_buf) != compl_tag)) - return false; + tx_buf = &txq->tx_buf[buf_id]; if (tx_buf->type == LIBETH_SQE_SKB) { if (skb_shinfo(tx_buf->skb)->tx_flags & SKBTX_IN_PROGRESS) idpf_tx_read_tstamp(txq, tx_buf->skb); libeth_tx_complete(tx_buf, &cp); + idpf_post_buf_refill(txq->refillq, buf_id); } - idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf); + while (idpf_tx_buf_next(tx_buf) != IDPF_TXBUF_NULL) { + buf_id = idpf_tx_buf_next(tx_buf); - while (idpf_tx_buf_compl_tag(tx_buf) == compl_tag) { + tx_buf = &txq->tx_buf[buf_id]; libeth_tx_complete(tx_buf, &cp); - idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf); + idpf_post_buf_refill(txq->refillq, buf_id); } - /* - * It's possible the packet we just cleaned was an out of order - * completion, which means we can stash the buffers starting from - * the original next_to_clean and reuse the descriptors. We need - * to compare the descriptor ring next_to_clean packet's "first" buffer - * to the "first" buffer of the packet we just cleaned to determine if - * this is the case. Howevever, next_to_clean can point to either a - * reserved buffer that corresponds to a context descriptor used for the - * next_to_clean packet (TSO packet) or the "first" buffer (single - * packet). The orig_idx from the packet we just cleaned will always - * point to the "first" buffer. If next_to_clean points to a reserved - * buffer, let's bump ntc once and start the comparison from there. - */ - ntc = txq->next_to_clean; - tx_buf = &txq->tx_buf[ntc]; - - if (tx_buf->type == LIBETH_SQE_CTX) - idpf_tx_clean_buf_ring_bump_ntc(txq, ntc, tx_buf); - - /* - * If ntc still points to a different "first" buffer, clean the - * descriptor ring and stash all of the buffers for later cleaning. If - * we cannot stash all of the buffers, next_to_clean will point to the - * "first" buffer of the packet that could not be stashed and cleaning - * will start there next time. - */ - if (unlikely(tx_buf != &txq->tx_buf[orig_idx] && - !idpf_tx_splitq_clean(txq, orig_idx, budget, cleaned, - true))) - return true; - - /* - * Otherwise, update next_to_clean to reflect the cleaning that was - * done above. - */ - txq->next_to_clean = idx; - return true; } @@ -2046,12 +2012,10 @@ static void idpf_tx_handle_rs_completion(struct idpf_tx_queue *txq, compl_tag = le16_to_cpu(desc->q_head_compl_tag.compl_tag); - idpf_post_buf_refill(txq->refillq, compl_tag); - /* If we didn't clean anything on the ring, this packet must be * in the hash table. Go clean it there. */ - if (!idpf_tx_clean_buf_ring(txq, compl_tag, cleaned, budget)) + if (!idpf_tx_clean_bufs(txq, compl_tag, cleaned, budget)) idpf_tx_clean_stashed_bufs(txq, compl_tag, cleaned, budget); } @@ -2364,7 +2328,7 @@ static unsigned int idpf_tx_splitq_bump_ntu(struct idpf_tx_queue *txq, u16 ntu) * Return: true if a buffer ID was found, false if not */ static bool idpf_tx_get_free_buf_id(struct idpf_sw_queue *refillq, - u16 *buf_id) + u32 *buf_id) { u32 ntc = refillq->next_to_clean; u32 refill_desc; @@ -2397,25 +2361,34 @@ static void idpf_tx_splitq_pkt_err_unmap(struct idpf_tx_queue *txq, struct idpf_tx_splitq_params *params, struct idpf_tx_buf *first) { + struct idpf_sw_queue *refillq = txq->refillq; struct libeth_sq_napi_stats ss = { }; struct idpf_tx_buf *tx_buf = first; struct libeth_cq_pp cp = { .dev = txq->dev, .ss = &ss, }; - u32 idx = 0; u64_stats_update_begin(&txq->stats_sync); u64_stats_inc(&txq->q_stats.dma_map_errs); u64_stats_update_end(&txq->stats_sync); - do { + libeth_tx_complete(tx_buf, &cp); + while (idpf_tx_buf_next(tx_buf) != IDPF_TXBUF_NULL) { + tx_buf = &txq->tx_buf[idpf_tx_buf_next(tx_buf)]; libeth_tx_complete(tx_buf, &cp); - idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf); - } while (idpf_tx_buf_compl_tag(tx_buf) == params->compl_tag); + } /* Update tail in case netdev_xmit_more was previously true. */ idpf_tx_buf_hw_update(txq, params->prev_ntu, false); + + if (!refillq) + return; + + /* Restore refillq state to avoid leaking tags. */ + if (params->prev_refill_gen != idpf_queue_has(RFL_GEN_CHK, refillq)) + idpf_queue_change(RFL_GEN_CHK, refillq); + refillq->next_to_clean = params->prev_refill_ntc; } /** @@ -2439,6 +2412,7 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, struct netdev_queue *nq; struct sk_buff *skb; skb_frag_t *frag; + u32 next_buf_id; u16 td_cmd = 0; dma_addr_t dma; @@ -2456,18 +2430,16 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, tx_buf = first; first->nr_frags = 0; - params->compl_tag = - (tx_q->compl_tag_cur_gen << tx_q->compl_tag_gen_s) | i; - for (frag = &skb_shinfo(skb)->frags[0];; frag++) { unsigned int max_data = IDPF_TX_MAX_DESC_DATA_ALIGNED; - if (unlikely(dma_mapping_error(tx_q->dev, dma))) + if (unlikely(dma_mapping_error(tx_q->dev, dma))) { + idpf_tx_buf_next(tx_buf) = IDPF_TXBUF_NULL; return idpf_tx_splitq_pkt_err_unmap(tx_q, params, first); + } first->nr_frags++; - idpf_tx_buf_compl_tag(tx_buf) = params->compl_tag; tx_buf->type = LIBETH_SQE_FRAG; /* record length, and DMA address */ @@ -2523,29 +2495,14 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, max_data); if (unlikely(++i == tx_q->desc_count)) { - tx_buf = tx_q->tx_buf; tx_desc = &tx_q->flex_tx[0]; i = 0; tx_q->compl_tag_cur_gen = IDPF_TX_ADJ_COMPL_TAG_GEN(tx_q); } else { - tx_buf++; tx_desc++; } - /* Since this packet has a buffer that is going to span - * multiple descriptors, it's going to leave holes in - * to the TX buffer ring. To ensure these holes do not - * cause issues in the cleaning routines, we will clear - * them of any stale data and assign them the same - * completion tag as the current packet. Then when the - * packet is being cleaned, the cleaning routines will - * simply pass over these holes and finish cleaning the - * rest of the packet. - */ - tx_buf->type = LIBETH_SQE_EMPTY; - idpf_tx_buf_compl_tag(tx_buf) = params->compl_tag; - /* Adjust the DMA offset and the remaining size of the * fragment. On the first iteration of this loop, * max_data will be >= 12K and <= 16K-1. On any @@ -2570,15 +2527,26 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, idpf_tx_splitq_build_desc(tx_desc, params, td_cmd, size); if (unlikely(++i == tx_q->desc_count)) { - tx_buf = tx_q->tx_buf; tx_desc = &tx_q->flex_tx[0]; i = 0; tx_q->compl_tag_cur_gen = IDPF_TX_ADJ_COMPL_TAG_GEN(tx_q); } else { - tx_buf++; tx_desc++; } + if (idpf_queue_has(FLOW_SCH_EN, tx_q)) { + if (unlikely(!idpf_tx_get_free_buf_id(tx_q->refillq, + &next_buf_id))) { + idpf_tx_buf_next(tx_buf) = IDPF_TXBUF_NULL; + return idpf_tx_splitq_pkt_err_unmap(tx_q, params, + first); + } + } else { + next_buf_id = i; + } + idpf_tx_buf_next(tx_buf) = next_buf_id; + tx_buf = &tx_q->tx_buf[next_buf_id]; + size = skb_frag_size(frag); data_len -= size; @@ -2593,6 +2561,7 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, /* write last descriptor with RS and EOP bits */ first->rs_idx = i; + idpf_tx_buf_next(tx_buf) = IDPF_TXBUF_NULL; td_cmd |= params->eop_cmd; idpf_tx_splitq_build_desc(tx_desc, params, td_cmd, size); i = idpf_tx_splitq_bump_ntu(tx_q, i); @@ -2801,8 +2770,6 @@ idpf_tx_splitq_get_ctx_desc(struct idpf_tx_queue *txq) union idpf_flex_tx_ctx_desc *desc; int i = txq->next_to_use; - txq->tx_buf[i].type = LIBETH_SQE_CTX; - /* grab the next descriptor */ desc = &txq->flex_ctx[i]; txq->next_to_use = idpf_tx_splitq_bump_ntu(txq, i); @@ -2927,6 +2894,7 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, struct idpf_tx_buf *first; unsigned int count; int tso, idx; + u32 buf_id; count = idpf_tx_desc_count_required(tx_q, skb); if (unlikely(!count)) @@ -2970,26 +2938,28 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, idpf_tx_set_tstamp_desc(ctx_desc, idx); } - /* record the location of the first descriptor for this packet */ - first = &tx_q->tx_buf[tx_q->next_to_use]; - first->skb = skb; + if (idpf_queue_has(FLOW_SCH_EN, tx_q)) { + struct idpf_sw_queue *refillq = tx_q->refillq; - if (tso) { - first->packets = tx_params.offload.tso_segs; - first->bytes = skb->len + - ((first->packets - 1) * tx_params.offload.tso_hdr_len); - } else { - first->packets = 1; - first->bytes = max_t(unsigned int, skb->len, ETH_ZLEN); - } + /* Save refillq state in case of a packet rollback. Otherwise, + * the tags will be leaked since they will be popped from the + * refillq but never reposted during cleaning. + */ + tx_params.prev_refill_gen = + idpf_queue_has(RFL_GEN_CHK, refillq); + tx_params.prev_refill_ntc = refillq->next_to_clean; - if (idpf_queue_has(FLOW_SCH_EN, tx_q)) { if (unlikely(!idpf_tx_get_free_buf_id(tx_q->refillq, - &tx_params.compl_tag))) { - u64_stats_update_begin(&tx_q->stats_sync); - u64_stats_inc(&tx_q->q_stats.q_busy); - u64_stats_update_end(&tx_q->stats_sync); + &buf_id))) { + if (tx_params.prev_refill_gen != + idpf_queue_has(RFL_GEN_CHK, refillq)) + idpf_queue_change(RFL_GEN_CHK, refillq); + refillq->next_to_clean = tx_params.prev_refill_ntc; + + tx_q->next_to_use = tx_params.prev_ntu; + return idpf_tx_drop_skb(tx_q, skb); } + tx_params.compl_tag = buf_id; tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE; tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP; @@ -3008,6 +2978,8 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, tx_params.offload.td_cmd |= IDPF_TXD_FLEX_FLOW_CMD_CS_EN; } else { + buf_id = tx_q->next_to_use; + tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_L2TAG1_L2TAG2; tx_params.eop_cmd = IDPF_TXD_LAST_DESC_CMD; @@ -3015,6 +2987,18 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, tx_params.offload.td_cmd |= IDPF_TX_FLEX_DESC_CMD_CS_EN; } + first = &tx_q->tx_buf[buf_id]; + first->skb = skb; + + if (tso) { + first->packets = tx_params.offload.tso_segs; + first->bytes = skb->len + + ((first->packets - 1) * tx_params.offload.tso_hdr_len); + } else { + first->packets = 1; + first->bytes = max_t(unsigned int, skb->len, ETH_ZLEN); + } + idpf_tx_splitq_map(tx_q, &tx_params, first); return NETDEV_TX_OK; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index a7632d845a2a2b..d86246c320c878 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -137,6 +137,8 @@ do { \ ((++(txq)->compl_tag_cur_gen) >= (txq)->compl_tag_gen_max ? \ 0 : (txq)->compl_tag_cur_gen) +#define IDPF_TXBUF_NULL U32_MAX + #define IDPF_TXD_LAST_DESC_CMD (IDPF_TX_DESC_CMD_EOP | IDPF_TX_DESC_CMD_RS) #define IDPF_TX_FLAGS_TSO BIT(0) @@ -197,6 +199,8 @@ struct idpf_tx_offload_params { * @td_tag: Descriptor tunneling tag * @offload: Offload parameters * @prev_ntu: stored TxQ next_to_use in case of rollback + * @prev_refill_ntc: stored refillq next_to_clean in case of packet rollback + * @prev_refill_gen: stored refillq generation bit in case of packet rollback */ struct idpf_tx_splitq_params { enum idpf_tx_desc_dtype_value dtype; @@ -209,6 +213,8 @@ struct idpf_tx_splitq_params { struct idpf_tx_offload_params offload; u16 prev_ntu; + u16 prev_refill_ntc; + bool prev_refill_gen; }; enum idpf_tx_ctx_desc_eipt_offload { @@ -638,6 +644,7 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64, * @size: Length of descriptor ring in bytes * @dma: Physical address of ring * @q_vector: Backreference to associated vector + * @buf_pool_size: Total number of idpf_tx_buf */ struct idpf_tx_queue { __cacheline_group_begin_aligned(read_mostly); @@ -696,11 +703,12 @@ struct idpf_tx_queue { dma_addr_t dma; struct idpf_q_vector *q_vector; + u32 buf_pool_size; __cacheline_group_end_aligned(cold); }; libeth_cacheline_set_assert(struct idpf_tx_queue, 64, 120 + sizeof(struct u64_stats_sync), - 24); + 32); /** * struct idpf_buf_queue - software structure representing a buffer queue From 0c3f135e840d4a2ba4253e15d530ec61bc30718e Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Fri, 25 Jul 2025 11:42:22 -0700 Subject: [PATCH 0489/1292] idpf: stop Tx if there are insufficient buffer resources The Tx refillq logic will cause packets to be silently dropped if there are not enough buffer resources available to send a packet in flow scheduling mode. Instead, determine how many buffers are needed along with number of descriptors. Make sure there are enough of both resources to send the packet, and stop the queue if not. Fixes: 7292af042bcf ("idpf: fix a race in txq wakeup") Signed-off-by: Joshua Hay Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- .../ethernet/intel/idpf/idpf_singleq_txrx.c | 4 +- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 47 +++++++++++++------ drivers/net/ethernet/intel/idpf/idpf_txrx.h | 15 +++++- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c index 57c0f5ab8f9ed8..b19b462e0bb645 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c @@ -415,11 +415,11 @@ netdev_tx_t idpf_tx_singleq_frame(struct sk_buff *skb, { struct idpf_tx_offload_params offload = { }; struct idpf_tx_buf *first; + u32 count, buf_count = 1; int csum, tso, needed; - unsigned int count; __be16 protocol; - count = idpf_tx_desc_count_required(tx_q, skb); + count = idpf_tx_res_count_required(tx_q, skb, &buf_count); if (unlikely(!count)) return idpf_tx_drop_skb(tx_q, skb); diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 5fe329a7c944e6..fa5432a0566aab 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -2191,15 +2191,22 @@ void idpf_tx_splitq_build_flow_desc(union idpf_tx_flex_desc *desc, desc->flow.qw1.compl_tag = cpu_to_le16(params->compl_tag); } -/* Global conditions to tell whether the txq (and related resources) - * has room to allow the use of "size" descriptors. +/** + * idpf_tx_splitq_has_room - check if enough Tx splitq resources are available + * @tx_q: the queue to be checked + * @descs_needed: number of descriptors required for this packet + * @bufs_needed: number of Tx buffers required for this packet + * + * Return: 0 if no room available, 1 otherwise */ -static int idpf_txq_has_room(struct idpf_tx_queue *tx_q, u32 size) +static int idpf_txq_has_room(struct idpf_tx_queue *tx_q, u32 descs_needed, + u32 bufs_needed) { - if (IDPF_DESC_UNUSED(tx_q) < size || + if (IDPF_DESC_UNUSED(tx_q) < descs_needed || IDPF_TX_COMPLQ_PENDING(tx_q->txq_grp) > IDPF_TX_COMPLQ_OVERFLOW_THRESH(tx_q->txq_grp->complq) || - IDPF_TX_BUF_RSV_LOW(tx_q)) + IDPF_TX_BUF_RSV_LOW(tx_q) || + idpf_tx_splitq_get_free_bufs(tx_q->refillq) < bufs_needed) return 0; return 1; } @@ -2208,14 +2215,21 @@ static int idpf_txq_has_room(struct idpf_tx_queue *tx_q, u32 size) * idpf_tx_maybe_stop_splitq - 1st level check for Tx splitq stop conditions * @tx_q: the queue to be checked * @descs_needed: number of descriptors required for this packet + * @bufs_needed: number of buffers needed for this packet * - * Returns 0 if stop is not needed + * Return: 0 if stop is not needed */ static int idpf_tx_maybe_stop_splitq(struct idpf_tx_queue *tx_q, - unsigned int descs_needed) + u32 descs_needed, + u32 bufs_needed) { + /* Since we have multiple resources to check for splitq, our + * start,stop_thrs becomes a boolean check instead of a count + * threshold. + */ if (netif_subqueue_maybe_stop(tx_q->netdev, tx_q->idx, - idpf_txq_has_room(tx_q, descs_needed), + idpf_txq_has_room(tx_q, descs_needed, + bufs_needed), 1, 1)) return 0; @@ -2257,14 +2271,16 @@ void idpf_tx_buf_hw_update(struct idpf_tx_queue *tx_q, u32 val, } /** - * idpf_tx_desc_count_required - calculate number of Tx descriptors needed + * idpf_tx_res_count_required - get number of Tx resources needed for this pkt * @txq: queue to send buffer on * @skb: send buffer + * @bufs_needed: (output) number of buffers needed for this skb. * - * Returns number of data descriptors needed for this skb. + * Return: number of data descriptors and buffers needed for this skb. */ -unsigned int idpf_tx_desc_count_required(struct idpf_tx_queue *txq, - struct sk_buff *skb) +unsigned int idpf_tx_res_count_required(struct idpf_tx_queue *txq, + struct sk_buff *skb, + u32 *bufs_needed) { const struct skb_shared_info *shinfo; unsigned int count = 0, i; @@ -2275,6 +2291,7 @@ unsigned int idpf_tx_desc_count_required(struct idpf_tx_queue *txq, return count; shinfo = skb_shinfo(skb); + *bufs_needed += shinfo->nr_frags; for (i = 0; i < shinfo->nr_frags; i++) { unsigned int size; @@ -2892,11 +2909,11 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, }; union idpf_flex_tx_ctx_desc *ctx_desc; struct idpf_tx_buf *first; - unsigned int count; + u32 count, buf_count = 1; int tso, idx; u32 buf_id; - count = idpf_tx_desc_count_required(tx_q, skb); + count = idpf_tx_res_count_required(tx_q, skb, &buf_count); if (unlikely(!count)) return idpf_tx_drop_skb(tx_q, skb); @@ -2906,7 +2923,7 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, /* Check for splitq specific TX resources */ count += (IDPF_TX_DESCS_PER_CACHE_LINE + tso); - if (idpf_tx_maybe_stop_splitq(tx_q, count)) { + if (idpf_tx_maybe_stop_splitq(tx_q, count, buf_count)) { idpf_tx_buf_hw_update(tx_q, tx_q->next_to_use, false); return NETDEV_TX_BUSY; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index d86246c320c878..9565e4dc3514c3 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -1026,6 +1026,17 @@ static inline void idpf_vport_intr_set_wb_on_itr(struct idpf_q_vector *q_vector) reg->dyn_ctl); } +/** + * idpf_tx_splitq_get_free_bufs - get number of free buf_ids in refillq + * @refillq: pointer to refillq containing buf_ids + */ +static inline u32 idpf_tx_splitq_get_free_bufs(struct idpf_sw_queue *refillq) +{ + return (refillq->next_to_use > refillq->next_to_clean ? + 0 : refillq->desc_count) + + refillq->next_to_use - refillq->next_to_clean - 1; +} + int idpf_vport_singleq_napi_poll(struct napi_struct *napi, int budget); void idpf_vport_init_num_qs(struct idpf_vport *vport, struct virtchnl2_create_vport *vport_msg); @@ -1053,8 +1064,8 @@ void idpf_tx_buf_hw_update(struct idpf_tx_queue *tx_q, u32 val, bool xmit_more); unsigned int idpf_size_to_txd_count(unsigned int size); netdev_tx_t idpf_tx_drop_skb(struct idpf_tx_queue *tx_q, struct sk_buff *skb); -unsigned int idpf_tx_desc_count_required(struct idpf_tx_queue *txq, - struct sk_buff *skb); +unsigned int idpf_tx_res_count_required(struct idpf_tx_queue *txq, + struct sk_buff *skb, u32 *buf_count); void idpf_tx_timeout(struct net_device *netdev, unsigned int txqueue); netdev_tx_t idpf_tx_singleq_frame(struct sk_buff *skb, struct idpf_tx_queue *tx_q); From 6c4e68480238274f84aa50d54da0d9e262df6284 Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Fri, 25 Jul 2025 11:42:23 -0700 Subject: [PATCH 0490/1292] idpf: remove obsolete stashing code With the new Tx buffer management scheme, there is no need for all of the stashing mechanisms, the hash table, the reserve buffer stack, etc. Remove all of that. Signed-off-by: Joshua Hay Reviewed-by: Madhu Chittim Reviewed-by: Aleksandr Loktionov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 314 ++------------------ drivers/net/ethernet/intel/idpf/idpf_txrx.h | 47 +-- 2 files changed, 22 insertions(+), 339 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index fa5432a0566aab..eaad52a83b04c0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -8,48 +8,12 @@ #include "idpf_ptp.h" #include "idpf_virtchnl.h" -struct idpf_tx_stash { - struct hlist_node hlist; - struct libeth_sqe buf; -}; - #define idpf_tx_buf_next(buf) (*(u32 *)&(buf)->priv) -#define idpf_tx_buf_compl_tag(buf) (*(u32 *)&(buf)->priv) LIBETH_SQE_CHECK_PRIV(u32); static bool idpf_chk_linearize(struct sk_buff *skb, unsigned int max_bufs, unsigned int count); -/** - * idpf_buf_lifo_push - push a buffer pointer onto stack - * @stack: pointer to stack struct - * @buf: pointer to buf to push - * - * Returns 0 on success, negative on failure - **/ -static int idpf_buf_lifo_push(struct idpf_buf_lifo *stack, - struct idpf_tx_stash *buf) -{ - if (unlikely(stack->top == stack->size)) - return -ENOSPC; - - stack->bufs[stack->top++] = buf; - - return 0; -} - -/** - * idpf_buf_lifo_pop - pop a buffer pointer from stack - * @stack: pointer to stack struct - **/ -static struct idpf_tx_stash *idpf_buf_lifo_pop(struct idpf_buf_lifo *stack) -{ - if (unlikely(!stack->top)) - return NULL; - - return stack->bufs[--stack->top]; -} - /** * idpf_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure @@ -78,14 +42,11 @@ void idpf_tx_timeout(struct net_device *netdev, unsigned int txqueue) static void idpf_tx_buf_rel_all(struct idpf_tx_queue *txq) { struct libeth_sq_napi_stats ss = { }; - struct idpf_buf_lifo *buf_stack; - struct idpf_tx_stash *stash; struct libeth_cq_pp cp = { .dev = txq->dev, .ss = &ss, }; - struct hlist_node *tmp; - u32 i, tag; + u32 i; /* Buffers already cleared, nothing to do */ if (!txq->tx_buf) @@ -97,33 +58,6 @@ static void idpf_tx_buf_rel_all(struct idpf_tx_queue *txq) kfree(txq->tx_buf); txq->tx_buf = NULL; - - if (!idpf_queue_has(FLOW_SCH_EN, txq)) - return; - - buf_stack = &txq->stash->buf_stack; - if (!buf_stack->bufs) - return; - - /* - * If a Tx timeout occurred, there are potentially still bufs in the - * hash table, free them here. - */ - hash_for_each_safe(txq->stash->sched_buf_hash, tag, tmp, stash, - hlist) { - if (!stash) - continue; - - libeth_tx_complete(&stash->buf, &cp); - hash_del(&stash->hlist); - idpf_buf_lifo_push(buf_stack, stash); - } - - for (i = 0; i < buf_stack->size; i++) - kfree(buf_stack->bufs[i]); - - kfree(buf_stack->bufs); - buf_stack->bufs = NULL; } /** @@ -199,9 +133,6 @@ static void idpf_tx_desc_rel_all(struct idpf_vport *vport) */ static int idpf_tx_buf_alloc_all(struct idpf_tx_queue *tx_q) { - struct idpf_buf_lifo *buf_stack; - int i; - /* Allocate book keeping buffers only. Buffers to be supplied to HW * are allocated by kernel network stack and received as part of skb */ @@ -214,29 +145,6 @@ static int idpf_tx_buf_alloc_all(struct idpf_tx_queue *tx_q) if (!tx_q->tx_buf) return -ENOMEM; - if (!idpf_queue_has(FLOW_SCH_EN, tx_q)) - return 0; - - buf_stack = &tx_q->stash->buf_stack; - - /* Initialize tx buf stack for out-of-order completions if - * flow scheduling offload is enabled - */ - buf_stack->bufs = kcalloc(tx_q->desc_count, sizeof(*buf_stack->bufs), - GFP_KERNEL); - if (!buf_stack->bufs) - return -ENOMEM; - - buf_stack->size = tx_q->desc_count; - buf_stack->top = tx_q->desc_count; - - for (i = 0; i < tx_q->desc_count; i++) { - buf_stack->bufs[i] = kzalloc(sizeof(*buf_stack->bufs[i]), - GFP_KERNEL); - if (!buf_stack->bufs[i]) - return -ENOMEM; - } - return 0; } @@ -350,8 +258,6 @@ static int idpf_tx_desc_alloc_all(struct idpf_vport *vport) for (i = 0; i < vport->num_txq_grp; i++) { for (j = 0; j < vport->txq_grps[i].num_txq; j++) { struct idpf_tx_queue *txq = vport->txq_grps[i].txqs[j]; - u8 gen_bits = 0; - u16 bufidx_mask; err = idpf_tx_desc_alloc(vport, txq); if (err) { @@ -360,34 +266,6 @@ static int idpf_tx_desc_alloc_all(struct idpf_vport *vport) i); goto err_out; } - - if (!idpf_is_queue_model_split(vport->txq_model)) - continue; - - txq->compl_tag_cur_gen = 0; - - /* Determine the number of bits in the bufid - * mask and add one to get the start of the - * generation bits - */ - bufidx_mask = txq->desc_count - 1; - while (bufidx_mask >> 1) { - txq->compl_tag_gen_s++; - bufidx_mask = bufidx_mask >> 1; - } - txq->compl_tag_gen_s++; - - gen_bits = IDPF_TX_SPLITQ_COMPL_TAG_WIDTH - - txq->compl_tag_gen_s; - txq->compl_tag_gen_max = GETMAXVAL(gen_bits); - - /* Set bufid mask based on location of first - * gen bit; it cannot simply be the descriptor - * ring size-1 since we can have size values - * where not all of those bits are set. - */ - txq->compl_tag_bufid_m = - GETMAXVAL(txq->compl_tag_gen_s); } if (!idpf_is_queue_model_split(vport->txq_model)) @@ -1042,9 +920,6 @@ static void idpf_txq_group_rel(struct idpf_vport *vport) kfree(txq_grp->complq); txq_grp->complq = NULL; - - if (flow_sch_en) - kfree(txq_grp->stashes); } kfree(vport->txq_grps); vport->txq_grps = NULL; @@ -1405,7 +1280,6 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq) for (i = 0; i < vport->num_txq_grp; i++) { struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i]; struct idpf_adapter *adapter = vport->adapter; - struct idpf_txq_stash *stashes; int j; tx_qgrp->vport = vport; @@ -1418,15 +1292,6 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq) goto err_alloc; } - if (split && flow_sch_en) { - stashes = kcalloc(num_txq, sizeof(*stashes), - GFP_KERNEL); - if (!stashes) - goto err_alloc; - - tx_qgrp->stashes = stashes; - } - for (j = 0; j < tx_qgrp->num_txq; j++) { struct idpf_tx_queue *q = tx_qgrp->txqs[j]; @@ -1446,11 +1311,6 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq) if (!flow_sch_en) continue; - if (split) { - q->stash = &stashes[j]; - hash_init(q->stash->sched_buf_hash); - } - idpf_queue_set(FLOW_SCH_EN, q); q->refillq = kzalloc(sizeof(*q->refillq), GFP_KERNEL); @@ -1742,87 +1602,6 @@ static void idpf_tx_read_tstamp(struct idpf_tx_queue *txq, struct sk_buff *skb) spin_unlock_bh(&tx_tstamp_caps->status_lock); } -/** - * idpf_tx_clean_stashed_bufs - clean bufs that were stored for - * out of order completions - * @txq: queue to clean - * @compl_tag: completion tag of packet to clean (from completion descriptor) - * @cleaned: pointer to stats struct to track cleaned packets/bytes - * @budget: Used to determine if we are in netpoll - */ -static void idpf_tx_clean_stashed_bufs(struct idpf_tx_queue *txq, - u16 compl_tag, - struct libeth_sq_napi_stats *cleaned, - int budget) -{ - struct idpf_tx_stash *stash; - struct hlist_node *tmp_buf; - struct libeth_cq_pp cp = { - .dev = txq->dev, - .ss = cleaned, - .napi = budget, - }; - - /* Buffer completion */ - hash_for_each_possible_safe(txq->stash->sched_buf_hash, stash, tmp_buf, - hlist, compl_tag) { - if (unlikely(idpf_tx_buf_compl_tag(&stash->buf) != compl_tag)) - continue; - - hash_del(&stash->hlist); - - if (stash->buf.type == LIBETH_SQE_SKB && - (skb_shinfo(stash->buf.skb)->tx_flags & SKBTX_IN_PROGRESS)) - idpf_tx_read_tstamp(txq, stash->buf.skb); - - libeth_tx_complete(&stash->buf, &cp); - - /* Push shadow buf back onto stack */ - idpf_buf_lifo_push(&txq->stash->buf_stack, stash); - } -} - -/** - * idpf_stash_flow_sch_buffers - store buffer parameters info to be freed at a - * later time (only relevant for flow scheduling mode) - * @txq: Tx queue to clean - * @tx_buf: buffer to store - */ -static int idpf_stash_flow_sch_buffers(struct idpf_tx_queue *txq, - struct idpf_tx_buf *tx_buf) -{ - struct idpf_tx_stash *stash; - - if (unlikely(tx_buf->type <= LIBETH_SQE_CTX)) - return 0; - - stash = idpf_buf_lifo_pop(&txq->stash->buf_stack); - if (unlikely(!stash)) { - net_err_ratelimited("%s: No out-of-order TX buffers left!\n", - netdev_name(txq->netdev)); - - return -ENOMEM; - } - - /* Store buffer params in shadow buffer */ - stash->buf.skb = tx_buf->skb; - stash->buf.bytes = tx_buf->bytes; - stash->buf.packets = tx_buf->packets; - stash->buf.type = tx_buf->type; - stash->buf.nr_frags = tx_buf->nr_frags; - dma_unmap_addr_set(&stash->buf, dma, dma_unmap_addr(tx_buf, dma)); - dma_unmap_len_set(&stash->buf, len, dma_unmap_len(tx_buf, len)); - idpf_tx_buf_compl_tag(&stash->buf) = idpf_tx_buf_compl_tag(tx_buf); - - /* Add buffer to buf_hash table to be freed later */ - hash_add(txq->stash->sched_buf_hash, &stash->hlist, - idpf_tx_buf_compl_tag(&stash->buf)); - - tx_buf->type = LIBETH_SQE_EMPTY; - - return 0; -} - #define idpf_tx_splitq_clean_bump_ntc(txq, ntc, desc, buf) \ do { \ if (unlikely(++(ntc) == (txq)->desc_count)) { \ @@ -1850,14 +1629,8 @@ do { \ * Separate packet completion events will be reported on the completion queue, * and the buffers will be cleaned separately. The stats are not updated from * this function when using flow-based scheduling. - * - * Furthermore, in flow scheduling mode, check to make sure there are enough - * reserve buffers to stash the packet. If there are not, return early, which - * will leave next_to_clean pointing to the packet that failed to be stashed. - * - * Return: false in the scenario above, true otherwise. */ -static bool idpf_tx_splitq_clean(struct idpf_tx_queue *tx_q, u16 end, +static void idpf_tx_splitq_clean(struct idpf_tx_queue *tx_q, u16 end, int napi_budget, struct libeth_sq_napi_stats *cleaned, bool descs_only) @@ -1871,12 +1644,11 @@ static bool idpf_tx_splitq_clean(struct idpf_tx_queue *tx_q, u16 end, .napi = napi_budget, }; struct idpf_tx_buf *tx_buf; - bool clean_complete = true; if (descs_only) { /* Bump ring index to mark as cleaned. */ tx_q->next_to_clean = end; - return true; + return; } tx_desc = &tx_q->flex_tx[ntc]; @@ -1897,53 +1669,24 @@ static bool idpf_tx_splitq_clean(struct idpf_tx_queue *tx_q, u16 end, break; eop_idx = tx_buf->rs_idx; + libeth_tx_complete(tx_buf, &cp); - if (descs_only) { - if (IDPF_TX_BUF_RSV_UNUSED(tx_q) < tx_buf->nr_frags) { - clean_complete = false; - goto tx_splitq_clean_out; - } - - idpf_stash_flow_sch_buffers(tx_q, tx_buf); + /* unmap remaining buffers */ + while (ntc != eop_idx) { + idpf_tx_splitq_clean_bump_ntc(tx_q, ntc, + tx_desc, tx_buf); - while (ntc != eop_idx) { - idpf_tx_splitq_clean_bump_ntc(tx_q, ntc, - tx_desc, tx_buf); - idpf_stash_flow_sch_buffers(tx_q, tx_buf); - } - } else { + /* unmap any remaining paged data */ libeth_tx_complete(tx_buf, &cp); - - /* unmap remaining buffers */ - while (ntc != eop_idx) { - idpf_tx_splitq_clean_bump_ntc(tx_q, ntc, - tx_desc, tx_buf); - - /* unmap any remaining paged data */ - libeth_tx_complete(tx_buf, &cp); - } } fetch_next_txq_desc: idpf_tx_splitq_clean_bump_ntc(tx_q, ntc, tx_desc, tx_buf); } -tx_splitq_clean_out: tx_q->next_to_clean = ntc; - - return clean_complete; } -#define idpf_tx_clean_buf_ring_bump_ntc(txq, ntc, buf) \ -do { \ - (buf)++; \ - (ntc)++; \ - if (unlikely((ntc) == (txq)->desc_count)) { \ - buf = (txq)->tx_buf; \ - ntc = 0; \ - } \ -} while (0) - /** * idpf_tx_clean_bufs - clean flow scheduling TX queue buffers * @txq: queue to clean @@ -1954,7 +1697,7 @@ do { \ * Clean all buffers associated with the packet starting at buf_id. Returns the * byte/segment count for the cleaned packet. */ -static bool idpf_tx_clean_bufs(struct idpf_tx_queue *txq, u32 buf_id, +static void idpf_tx_clean_bufs(struct idpf_tx_queue *txq, u32 buf_id, struct libeth_sq_napi_stats *cleaned, int budget) { @@ -1981,8 +1724,6 @@ static bool idpf_tx_clean_bufs(struct idpf_tx_queue *txq, u32 buf_id, libeth_tx_complete(tx_buf, &cp); idpf_post_buf_refill(txq->refillq, buf_id); } - - return true; } /** @@ -2001,22 +1742,17 @@ static void idpf_tx_handle_rs_completion(struct idpf_tx_queue *txq, struct libeth_sq_napi_stats *cleaned, int budget) { - u16 compl_tag; + /* RS completion contains queue head for queue based scheduling or + * completion tag for flow based scheduling. + */ + u16 rs_compl_val = le16_to_cpu(desc->q_head_compl_tag.q_head); if (!idpf_queue_has(FLOW_SCH_EN, txq)) { - u16 head = le16_to_cpu(desc->q_head_compl_tag.q_head); - - idpf_tx_splitq_clean(txq, head, budget, cleaned, false); + idpf_tx_splitq_clean(txq, rs_compl_val, budget, cleaned, false); return; } - compl_tag = le16_to_cpu(desc->q_head_compl_tag.compl_tag); - - /* If we didn't clean anything on the ring, this packet must be - * in the hash table. Go clean it there. - */ - if (!idpf_tx_clean_bufs(txq, compl_tag, cleaned, budget)) - idpf_tx_clean_stashed_bufs(txq, compl_tag, cleaned, budget); + idpf_tx_clean_bufs(txq, rs_compl_val, cleaned, budget); } /** @@ -2133,8 +1869,7 @@ static bool idpf_tx_clean_complq(struct idpf_compl_queue *complq, int budget, /* Update BQL */ nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx); - dont_wake = !complq_ok || IDPF_TX_BUF_RSV_LOW(tx_q) || - np->state != __IDPF_VPORT_UP || + dont_wake = !complq_ok || np->state != __IDPF_VPORT_UP || !netif_carrier_ok(tx_q->netdev); /* Check if the TXQ needs to and can be restarted */ __netif_txq_completed_wake(nq, tx_q->cleaned_pkts, tx_q->cleaned_bytes, @@ -2205,7 +1940,6 @@ static int idpf_txq_has_room(struct idpf_tx_queue *tx_q, u32 descs_needed, if (IDPF_DESC_UNUSED(tx_q) < descs_needed || IDPF_TX_COMPLQ_PENDING(tx_q->txq_grp) > IDPF_TX_COMPLQ_OVERFLOW_THRESH(tx_q->txq_grp->complq) || - IDPF_TX_BUF_RSV_LOW(tx_q) || idpf_tx_splitq_get_free_bufs(tx_q->refillq) < bufs_needed) return 0; return 1; @@ -2329,10 +2063,8 @@ static unsigned int idpf_tx_splitq_bump_ntu(struct idpf_tx_queue *txq, u16 ntu) { ntu++; - if (ntu == txq->desc_count) { + if (ntu == txq->desc_count) ntu = 0; - txq->compl_tag_cur_gen = IDPF_TX_ADJ_COMPL_TAG_GEN(txq); - } return ntu; } @@ -2514,8 +2246,6 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, if (unlikely(++i == tx_q->desc_count)) { tx_desc = &tx_q->flex_tx[0]; i = 0; - tx_q->compl_tag_cur_gen = - IDPF_TX_ADJ_COMPL_TAG_GEN(tx_q); } else { tx_desc++; } @@ -2546,7 +2276,6 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, if (unlikely(++i == tx_q->desc_count)) { tx_desc = &tx_q->flex_tx[0]; i = 0; - tx_q->compl_tag_cur_gen = IDPF_TX_ADJ_COMPL_TAG_GEN(tx_q); } else { tx_desc++; } @@ -2980,10 +2709,9 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb, tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE; tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP; - /* Set the RE bit to catch any packets that may have not been - * stashed during RS completion cleaning. MIN_GAP is set to - * MIN_RING size to ensure it will be set at least once each - * time around the ring. + /* Set the RE bit to periodically "clean" the descriptor ring. + * MIN_GAP is set to MIN_RING size to ensure it will be set at + * least once each time around the ring. */ if (idpf_tx_splitq_need_re(tx_q)) { tx_params.eop_cmd |= IDPF_TXD_FLEX_FLOW_CMD_RE; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 9565e4dc3514c3..52753dff381c31 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -118,10 +118,6 @@ do { \ ((((txq)->next_to_clean > (txq)->next_to_use) ? 0 : (txq)->desc_count) + \ (txq)->next_to_clean - (txq)->next_to_use - 1) -#define IDPF_TX_BUF_RSV_UNUSED(txq) ((txq)->stash->buf_stack.top) -#define IDPF_TX_BUF_RSV_LOW(txq) (IDPF_TX_BUF_RSV_UNUSED(txq) < \ - (txq)->desc_count >> 2) - #define IDPF_TX_COMPLQ_OVERFLOW_THRESH(txcq) ((txcq)->desc_count >> 1) /* Determine the absolute number of completions pending, i.e. the number of * completions that are expected to arrive on the TX completion queue. @@ -131,12 +127,6 @@ do { \ 0 : U32_MAX) + \ (txq)->num_completions_pending - (txq)->complq->num_completions) -#define IDPF_TX_SPLITQ_COMPL_TAG_WIDTH 16 -/* Adjust the generation for the completion tag and wrap if necessary */ -#define IDPF_TX_ADJ_COMPL_TAG_GEN(txq) \ - ((++(txq)->compl_tag_cur_gen) >= (txq)->compl_tag_gen_max ? \ - 0 : (txq)->compl_tag_cur_gen) - #define IDPF_TXBUF_NULL U32_MAX #define IDPF_TXD_LAST_DESC_CMD (IDPF_TX_DESC_CMD_EOP | IDPF_TX_DESC_CMD_RS) @@ -154,18 +144,6 @@ union idpf_tx_flex_desc { #define idpf_tx_buf libeth_sqe -/** - * struct idpf_buf_lifo - LIFO for managing OOO completions - * @top: Used to know how many buffers are left - * @size: Total size of LIFO - * @bufs: Backing array - */ -struct idpf_buf_lifo { - u16 top; - u16 size; - struct idpf_tx_stash **bufs; -}; - /** * struct idpf_tx_offload_params - Offload parameters for a given packet * @tx_flags: Feature flags enabled for this packet @@ -476,17 +454,6 @@ struct idpf_tx_queue_stats { #define IDPF_ITR_IDX_SPACING(spacing, dflt) (spacing ? spacing : dflt) #define IDPF_DIM_DEFAULT_PROFILE_IX 1 -/** - * struct idpf_txq_stash - Tx buffer stash for Flow-based scheduling mode - * @buf_stack: Stack of empty buffers to store buffer info for out of order - * buffer completions. See struct idpf_buf_lifo - * @sched_buf_hash: Hash table to store buffers - */ -struct idpf_txq_stash { - struct idpf_buf_lifo buf_stack; - DECLARE_HASHTABLE(sched_buf_hash, 12); -} ____cacheline_aligned; - /** * struct idpf_rx_queue - software structure representing a receive queue * @rx: universal receive descriptor array @@ -631,11 +598,7 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64, * only once at the end of the cleaning routine. * @clean_budget: singleq only, queue cleaning budget * @cleaned_pkts: Number of packets cleaned for the above said case - * @stash: Tx buffer stash for Flow-based scheduling mode * @refillq: Pointer to refill queue - * @compl_tag_bufid_m: Completion tag buffer id mask - * @compl_tag_cur_gen: Used to keep track of current completion tag generation - * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset * @cached_tstamp_caps: Tx timestamp capabilities negotiated with the CP * @tstamp_task: Work that handles Tx timestamp read * @stats_sync: See struct u64_stats_sync @@ -666,7 +629,6 @@ struct idpf_tx_queue { u16 desc_count; u16 tx_min_pkt_len; - u16 compl_tag_gen_s; struct net_device *netdev; __cacheline_group_end_aligned(read_mostly); @@ -683,13 +645,8 @@ struct idpf_tx_queue { }; u16 cleaned_pkts; - struct idpf_txq_stash *stash; struct idpf_sw_queue *refillq; - u16 compl_tag_bufid_m; - u16 compl_tag_cur_gen; - u16 compl_tag_gen_max; - struct idpf_ptp_vport_tx_tstamp_caps *cached_tstamp_caps; struct work_struct *tstamp_task; @@ -707,7 +664,7 @@ struct idpf_tx_queue { __cacheline_group_end_aligned(cold); }; libeth_cacheline_set_assert(struct idpf_tx_queue, 64, - 120 + sizeof(struct u64_stats_sync), + 104 + sizeof(struct u64_stats_sync), 32); /** @@ -918,7 +875,6 @@ struct idpf_rxq_group { * @vport: Vport back pointer * @num_txq: Number of TX queues associated * @txqs: Array of TX queue pointers - * @stashes: array of OOO stashes for the queues * @complq: Associated completion queue pointer, split queue only * @num_completions_pending: Total number of completions pending for the * completion queue, acculumated for all TX queues @@ -933,7 +889,6 @@ struct idpf_txq_group { u16 num_txq; struct idpf_tx_queue *txqs[IDPF_LARGE_MAX_Q]; - struct idpf_txq_stash *stashes; struct idpf_compl_queue *complq; From 91a79b792204313153e1bdbbe5acbfc28903b3a5 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 20 Aug 2025 14:37:07 +0200 Subject: [PATCH 0491/1292] netfilter: nf_reject: don't leak dst refcount for loopback packets recent patches to add a WARN() when replacing skb dst entry found an old bug: WARNING: include/linux/skbuff.h:1165 skb_dst_check_unset include/linux/skbuff.h:1164 [inline] WARNING: include/linux/skbuff.h:1165 skb_dst_set include/linux/skbuff.h:1210 [inline] WARNING: include/linux/skbuff.h:1165 nf_reject_fill_skb_dst+0x2a4/0x330 net/ipv4/netfilter/nf_reject_ipv4.c:234 [..] Call Trace: nf_send_unreach+0x17b/0x6e0 net/ipv4/netfilter/nf_reject_ipv4.c:325 nft_reject_inet_eval+0x4bc/0x690 net/netfilter/nft_reject_inet.c:27 expr_call_ops_eval net/netfilter/nf_tables_core.c:237 [inline] .. This is because blamed commit forgot about loopback packets. Such packets already have a dst_entry attached, even at PRE_ROUTING stage. Instead of checking hook just check if the skb already has a route attached to it. Fixes: f53b9b0bdc59 ("netfilter: introduce support for reject at prerouting stage") Signed-off-by: Florian Westphal Link: https://patch.msgid.link/20250820123707.10671-1-fw@strlen.de Signed-off-by: Jakub Kicinski --- net/ipv4/netfilter/nf_reject_ipv4.c | 6 ++---- net/ipv6/netfilter/nf_reject_ipv6.c | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index 87fd945a0d27a5..0d3cb2ba6fc841 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c @@ -247,8 +247,7 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb, if (!oth) return; - if ((hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) && - nf_reject_fill_skb_dst(oldskb) < 0) + if (!skb_dst(oldskb) && nf_reject_fill_skb_dst(oldskb) < 0) return; if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) @@ -321,8 +320,7 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook) if (iph->frag_off & htons(IP_OFFSET)) return; - if ((hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) && - nf_reject_fill_skb_dst(skb_in) < 0) + if (!skb_dst(skb_in) && nf_reject_fill_skb_dst(skb_in) < 0) return; if (skb_csum_unnecessary(skb_in) || diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index 838295fa32e364..cb2d38e80de9a6 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c @@ -293,7 +293,7 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb, fl6.fl6_sport = otcph->dest; fl6.fl6_dport = otcph->source; - if (hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) { + if (!skb_dst(oldskb)) { nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false); if (!dst) return; @@ -397,8 +397,7 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in, if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) skb_in->dev = net->loopback_dev; - if ((hooknum == NF_INET_PRE_ROUTING || hooknum == NF_INET_INGRESS) && - nf_reject6_fill_skb_dst(skb_in) < 0) + if (!skb_dst(skb_in) && nf_reject6_fill_skb_dst(skb_in) < 0) return; icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); From aea70964b5a7ca491a3701f2dde6c9d05d51878d Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 20 Aug 2025 14:28:04 -0500 Subject: [PATCH 0492/1292] of: reserved_mem: Add missing IORESOURCE_MEM flag on resources Commit f4fcfdda2fd8 ('of: reserved_mem: Add functions to parse "memory-region"') failed to set IORESOURCE_MEM flag on the resources. The result is functions such as devm_ioremap_resource_wc() will fail. Add the missing flag. Fixes: f4fcfdda2fd8 ('of: reserved_mem: Add functions to parse "memory-region"') Reported-by: Iuliana Prodan Reported-by: Daniel Baluta Tested-by: Iuliana Prodan Reviewed-by: Iuliana Prodan Reviewed-by: Saravana Kannan Link: https://lore.kernel.org/r/20250820192805.565568-1-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- drivers/of/of_reserved_mem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 77016c0cc296e5..d3b7c4ae429c7d 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -771,6 +771,7 @@ int of_reserved_mem_region_to_resource(const struct device_node *np, return -EINVAL; resource_set_range(res, rmem->base, rmem->size); + res->flags = IORESOURCE_MEM; res->name = rmem->name; return 0; } From 8a30114073639fd97f2c7390abbc34fb8711327a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C3=B3rkowski?= Date: Mon, 11 Aug 2025 12:43:58 +0200 Subject: [PATCH 0493/1292] drm/xe: Move ASID allocation and user PT BO tracking into xe_vm_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, ASID assignment for user VMs and page-table BO accounting for client memory tracking are performed in xe_vm_create_ioctl. To consolidate VM object initialization, move this logic to xe_vm_create. v2: - removed unnecessary duplicate BO tracking code - using the local variable xef to verify whether the VM is being created by userspace Fixes: 658a1c8e0a66 ("drm/xe: Assign ioctl xe file handler to vm in xe_vm_create") Suggested-by: Matthew Auld Signed-off-by: Piotr Piórkowski Reviewed-by: Matthew Auld Link: https://lore.kernel.org/r/20250811104358.2064150-3-piotr.piorkowski@intel.com Signed-off-by: Michał Winiarski (cherry picked from commit 30e0c3f43a414616e0b6ca76cf7f7b2cd387e1d4) Signed-off-by: Rodrigo Vivi [Rodrigo: Added fixes tag] --- drivers/gpu/drm/xe/xe_vm.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 5bff317e335a03..1bb73bb63406fe 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1795,6 +1795,20 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef) if (number_tiles > 1) vm->composite_fence_ctx = dma_fence_context_alloc(1); + if (xef && xe->info.has_asid) { + u32 asid; + + down_write(&xe->usm.lock); + err = xa_alloc_cyclic(&xe->usm.asid_to_vm, &asid, vm, + XA_LIMIT(1, XE_MAX_ASID - 1), + &xe->usm.next_asid, GFP_KERNEL); + up_write(&xe->usm.lock); + if (err < 0) + goto err_unlock_close; + + vm->usm.asid = asid; + } + trace_xe_vm_create(vm); return vm; @@ -2062,9 +2076,8 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, struct xe_device *xe = to_xe_device(dev); struct xe_file *xef = to_xe_file(file); struct drm_xe_vm_create *args = data; - struct xe_tile *tile; struct xe_vm *vm; - u32 id, asid; + u32 id; int err; u32 flags = 0; @@ -2104,23 +2117,6 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, if (IS_ERR(vm)) return PTR_ERR(vm); - if (xe->info.has_asid) { - down_write(&xe->usm.lock); - err = xa_alloc_cyclic(&xe->usm.asid_to_vm, &asid, vm, - XA_LIMIT(1, XE_MAX_ASID - 1), - &xe->usm.next_asid, GFP_KERNEL); - up_write(&xe->usm.lock); - if (err < 0) - goto err_close_and_put; - - vm->usm.asid = asid; - } - - /* Record BO memory for VM pagetable created against client */ - for_each_tile(tile, xe, id) - if (vm->pt_root[id]) - xe_drm_client_add_bo(vm->xef->client, vm->pt_root[id]->bo); - #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_MEM) /* Warning: Security issue - never enable by default */ args->reserved[0] = xe_bo_main_addr(vm->pt_root[0]->bo, XE_PAGE_SIZE); From 111fb43a557726079a67ce3ab51f602ddbf7097e Mon Sep 17 00:00:00 2001 From: Christoph Manszewski Date: Wed, 13 Aug 2025 12:12:30 +0200 Subject: [PATCH 0494/1292] drm/xe: Fix vm_bind_ioctl double free bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the argument check during an array bind fails, the bind_ops are freed twice as seen below. Fix this by setting bind_ops to NULL after freeing. ================================================================== BUG: KASAN: double-free in xe_vm_bind_ioctl+0x1b2/0x21f0 [xe] Free of addr ffff88813bb9b800 by task xe_vm/14198 CPU: 5 UID: 0 PID: 14198 Comm: xe_vm Not tainted 6.16.0-xe-eudebug-cmanszew+ #520 PREEMPT(full) Hardware name: Intel Corporation Alder Lake Client Platform/AlderLake-P DDR5 RVP, BIOS ADLPFWI1.R00.2411.A02.2110081023 10/08/2021 Call Trace: dump_stack_lvl+0x82/0xd0 print_report+0xcb/0x610 ? __virt_addr_valid+0x19a/0x300 ? xe_vm_bind_ioctl+0x1b2/0x21f0 [xe] kasan_report_invalid_free+0xc8/0xf0 ? xe_vm_bind_ioctl+0x1b2/0x21f0 [xe] ? xe_vm_bind_ioctl+0x1b2/0x21f0 [xe] check_slab_allocation+0x102/0x130 kfree+0x10d/0x440 ? should_fail_ex+0x57/0x2f0 ? xe_vm_bind_ioctl+0x1b2/0x21f0 [xe] xe_vm_bind_ioctl+0x1b2/0x21f0 [xe] ? __pfx_xe_vm_bind_ioctl+0x10/0x10 [xe] ? __lock_acquire+0xab9/0x27f0 ? lock_acquire+0x165/0x300 ? drm_dev_enter+0x53/0xe0 [drm] ? find_held_lock+0x2b/0x80 ? drm_dev_exit+0x30/0x50 [drm] ? drm_ioctl_kernel+0x128/0x1c0 [drm] drm_ioctl_kernel+0x128/0x1c0 [drm] ? __pfx_xe_vm_bind_ioctl+0x10/0x10 [xe] ? find_held_lock+0x2b/0x80 ? __pfx_drm_ioctl_kernel+0x10/0x10 [drm] ? should_fail_ex+0x57/0x2f0 ? __pfx_xe_vm_bind_ioctl+0x10/0x10 [xe] drm_ioctl+0x352/0x620 [drm] ? __pfx_drm_ioctl+0x10/0x10 [drm] ? __pfx_rpm_resume+0x10/0x10 ? do_raw_spin_lock+0x11a/0x1b0 ? find_held_lock+0x2b/0x80 ? __pm_runtime_resume+0x61/0xc0 ? rcu_is_watching+0x20/0x50 ? trace_irq_enable.constprop.0+0xac/0xe0 xe_drm_ioctl+0x91/0xc0 [xe] __x64_sys_ioctl+0xb2/0x100 ? rcu_is_watching+0x20/0x50 do_syscall_64+0x68/0x2e0 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7fa9acb24ded Fixes: b43e864af0d4 ("drm/xe/uapi: Add DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR") Cc: Matthew Brost Cc: Himal Prasad Ghimiray Cc: Thomas Hellstrƶm Signed-off-by: Christoph Manszewski Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://lore.kernel.org/r/20250813101231.196632-2-christoph.manszewski@intel.com (cherry picked from commit a01b704527c28a2fd43a17a85f8996b75ec8492a) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 1bb73bb63406fe..ec04bef8ae4088 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -3418,6 +3418,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, free_bind_ops: if (args->num_binds > 1) kvfree(*bind_ops); + *bind_ops = NULL; return err; } @@ -3524,7 +3525,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) struct xe_exec_queue *q = NULL; u32 num_syncs, num_ufence = 0; struct xe_sync_entry *syncs = NULL; - struct drm_xe_vm_bind_op *bind_ops; + struct drm_xe_vm_bind_op *bind_ops = NULL; struct xe_vma_ops vops; struct dma_fence *fence; int err; From ac29e4487aa20a21b7c3facbd1f14f5093835dc9 Mon Sep 17 00:00:00 2001 From: Pritesh Patel Date: Mon, 16 Jun 2025 16:53:12 +0530 Subject: [PATCH 0495/1292] dt-bindings: vendor-prefixes: add eswin Add new vendor string to dt bindings. This new vendor string is used by - ESWIN EIC770X SoC - HiFive Premier P550 board which uses EIC7700 SoC. Link: https://www.eswin.com/en/ Signed-off-by: Pritesh Patel Reviewed-by: Samuel Holland Signed-off-by: Pinkesh Vaghela Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250616112316.3833343-4-pinkesh.vaghela@einfochips.com Signed-off-by: Rob Herring (Arm) --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 741b545e3ab090..982ef10eed766d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -499,6 +499,8 @@ patternProperties: description: Espressif Systems Co. Ltd. "^est,.*": description: ESTeem Wireless Modems + "^eswin,.*": + description: Beijing ESWIN Technology Group Co. Ltd. "^ettus,.*": description: NI Ettus Research "^eukrea,.*": From 508c1314b342b78591f51c4b5dadee31a88335df Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 21 Aug 2025 13:23:21 -0600 Subject: [PATCH 0496/1292] io_uring/futex: ensure io_futex_wait() cleans up properly on failure The io_futex_data is allocated upfront and assigned to the io_kiocb async_data field, but the request isn't marked with REQ_F_ASYNC_DATA at that point. Those two should always go together, as the flag tells io_uring whether the field is valid or not. Additionally, on failure cleanup, the futex handler frees the data but does not clear ->async_data. Clear the data and the flag in the error path as well. Thanks to Trend Micro Zero Day Initiative and particularly ReDress for reporting this. Cc: stable@vger.kernel.org Fixes: 194bb58c6090 ("io_uring: add support for futex wake and wait") Signed-off-by: Jens Axboe --- io_uring/futex.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/io_uring/futex.c b/io_uring/futex.c index 692462d50c8c0c..9113a44984f3cb 100644 --- a/io_uring/futex.c +++ b/io_uring/futex.c @@ -288,6 +288,7 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags) goto done_unlock; } + req->flags |= REQ_F_ASYNC_DATA; req->async_data = ifd; ifd->q = futex_q_init; ifd->q.bitset = iof->futex_mask; @@ -309,6 +310,8 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags) if (ret < 0) req_set_fail(req); io_req_set_res(req, ret, 0); + req->async_data = NULL; + req->flags &= ~REQ_F_ASYNC_DATA; kfree(ifd); return IOU_COMPLETE; } From e4e6aaea46b7be818eba0510ba68d30df8689ea3 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 21 Aug 2025 13:24:57 -0600 Subject: [PATCH 0497/1292] io_uring: clear ->async_data as part of normal init Opcode handlers like POLL_ADD will use ->async_data as the pointer for double poll handling, which is a bit different than the usual case where it's strictly gated by the REQ_F_ASYNC_DATA flag. Be a bit more proactive in handling ->async_data, and clear it to NULL as part of regular init. Init is touching that cacheline anyway, so might as well clear it. Signed-off-by: Jens Axboe --- io_uring/io_uring.c | 1 + 1 file changed, 1 insertion(+) diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 4ef69dd58734ae..93633613a1657c 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -2119,6 +2119,7 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req, req->file = NULL; req->tctx = current->io_uring; req->cancel_seq_set = false; + req->async_data = NULL; if (unlikely(opcode >= IORING_OP_LAST)) { req->opcode = 0; From 03cf825911c95f39d77d2a60b35fe5b4a33115b1 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Wed, 13 Aug 2025 15:54:33 +0800 Subject: [PATCH 0498/1292] powercap: idle_inject: use us_to_ktime() where appropriate Convert values in microseconds to ktime using us_to_ktime() instead of multiplying them by NSEC_PER_USEC and using ns_to_ktime() for the conversion. Signed-off-by: Xichao Zhao Link: https://patch.msgid.link/20250813075433.464786-1-zhao.xichao@vivo.com [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/powercap/idle_inject.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/powercap/idle_inject.c b/drivers/powercap/idle_inject.c index 5ad7cc438068e5..a25eb2018acdec 100644 --- a/drivers/powercap/idle_inject.c +++ b/drivers/powercap/idle_inject.c @@ -133,7 +133,7 @@ static enum hrtimer_restart idle_inject_timer_fn(struct hrtimer *timer) duration_us = READ_ONCE(ii_dev->run_duration_us); duration_us += READ_ONCE(ii_dev->idle_duration_us); - hrtimer_forward_now(timer, ns_to_ktime(duration_us * NSEC_PER_USEC)); + hrtimer_forward_now(timer, us_to_ktime(duration_us)); return HRTIMER_RESTART; } @@ -232,8 +232,7 @@ int idle_inject_start(struct idle_inject_device *ii_dev) idle_inject_wakeup(ii_dev); hrtimer_start(&ii_dev->timer, - ns_to_ktime((idle_duration_us + run_duration_us) * - NSEC_PER_USEC), + us_to_ktime(idle_duration_us + run_duration_us), HRTIMER_MODE_REL); return 0; From 17224c1d2574d29668c4879e1fbf36d6f68cd22b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Aug 2025 12:26:35 +0200 Subject: [PATCH 0499/1292] cpuidle: governors: menu: Rearrange main loop in menu_select() Reduce the indentation level in the main loop of menu_select() by rearranging some checks and assignments in it. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Christian Loehle Link: https://patch.msgid.link/2389215.ElGaqSPkdT@rafael.j.wysocki --- drivers/cpuidle/governors/menu.c | 70 ++++++++++++++++---------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index b2e3d0b0a116dc..4d9aa5ce31f084 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -314,45 +314,47 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, if (s->exit_latency_ns > latency_req) break; - if (s->target_residency_ns > predicted_ns) { - /* - * Use a physical idle state, not busy polling, unless - * a timer is going to trigger soon enough. - */ - if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) && - s->target_residency_ns <= data->next_timer_ns) { - predicted_ns = s->target_residency_ns; - idx = i; - break; - } - if (predicted_ns < TICK_NSEC) - break; - - if (!tick_nohz_tick_stopped()) { - /* - * If the state selected so far is shallow, - * waking up early won't hurt, so retain the - * tick in that case and let the governor run - * again in the next iteration of the loop. - */ - predicted_ns = drv->states[idx].target_residency_ns; - break; - } + if (s->target_residency_ns <= predicted_ns) { + idx = i; + continue; + } + + /* + * Use a physical idle state, not busy polling, unless a timer + * is going to trigger soon enough. + */ + if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) && + s->target_residency_ns <= data->next_timer_ns) { + predicted_ns = s->target_residency_ns; + idx = i; + break; + } + if (predicted_ns < TICK_NSEC) + break; + + if (!tick_nohz_tick_stopped()) { /* - * If the state selected so far is shallow and this - * state's target residency matches the time till the - * closest timer event, select this one to avoid getting - * stuck in the shallow one for too long. + * If the state selected so far is shallow, waking up + * early won't hurt, so retain the tick in that case and + * let the governor run again in the next iteration of + * the idle loop. */ - if (drv->states[idx].target_residency_ns < TICK_NSEC && - s->target_residency_ns <= delta_tick) - idx = i; - - return idx; + predicted_ns = drv->states[idx].target_residency_ns; + break; } - idx = i; + /* + * If the state selected so far is shallow and this state's + * target residency matches the time till the closest timer + * event, select this one to avoid getting stuck in the shallow + * one for too long. + */ + if (drv->states[idx].target_residency_ns < TICK_NSEC && + s->target_residency_ns <= delta_tick) + idx = i; + + return idx; } if (idx == -1) From 2b3979624c3e34dcdd77d910c6490939727d91b2 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 25 Jul 2025 16:51:49 +0100 Subject: [PATCH 0500/1292] btrfs: abort transaction on failure to add link to inode If we fail to update the inode or delete the orphan item, we must abort the transaction to prevent persisting an inconsistent state. For example if we fail to update the inode item, we have the inconsistency of having a persisted inode item with a link count of N but we have N + 1 inode ref items and N + 1 directory entries pointing to our inode in case the transaction gets committed. Reviewed-by: Johannes Thumshirn Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/inode.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 9e4aec7330cb61..af2f9b2c8c851c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6852,16 +6852,20 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *parent = dentry->d_parent; ret = btrfs_update_inode(trans, BTRFS_I(inode)); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto fail; + } if (inode->i_nlink == 1) { /* * If new hard link count is 1, it's a file created * with open(2) O_TMPFILE flag. */ ret = btrfs_orphan_del(trans, BTRFS_I(inode)); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto fail; + } } d_instantiate(dentry, inode); btrfs_log_new_name(trans, old_dentry, NULL, 0, parent); From e87e953bb20629ca1f008f8146c38e313e5ed319 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 25 Jul 2025 16:54:49 +0100 Subject: [PATCH 0501/1292] btrfs: fix inode leak on failure to add link to inode If we fail to update the inode or delete the orphan item we leak the inode since we update its refcount with the ihold() call to account for the d_instantiate() call which never happens in case we fail those steps. Fix this by setting 'drop_inode' to true in case we fail those steps. Reviewed-by: Johannes Thumshirn Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/inode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index af2f9b2c8c851c..4ed5ab5d3ac15b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6854,6 +6854,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, ret = btrfs_update_inode(trans, BTRFS_I(inode)); if (ret) { btrfs_abort_transaction(trans, ret); + drop_inode = 1; goto fail; } if (inode->i_nlink == 1) { @@ -6864,6 +6865,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, ret = btrfs_orphan_del(trans, BTRFS_I(inode)); if (ret) { btrfs_abort_transaction(trans, ret); + drop_inode = 1; goto fail; } } From 5bb00879cb23db7e5e2fc0aa47b5ce3b1c713d8a Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 25 Jul 2025 17:08:13 +0100 Subject: [PATCH 0502/1292] btrfs: simplify error handling logic for btrfs_link() Instead of incrementing the inode's link count and refcount early before adding the link, updating the inode and deleting orphan item, do it after all those steps succeeded right before calling d_instantiate(). This makes the error handling logic simpler by avoiding the need for the 'drop_inode' variable to signal if we need to undo the link count increment and the inode refcount increase under the 'fail' label. This also reduces the level of indentation by one, making the code easier to read. Reviewed-by: Johannes Thumshirn Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/inode.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4ed5ab5d3ac15b..321a46be0377b4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6805,7 +6805,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, struct fscrypt_name fname; u64 index; int ret; - int drop_inode = 0; /* do not allow sys_link's with other subvols of the same device */ if (btrfs_root_id(root) != btrfs_root_id(BTRFS_I(inode)->root)) @@ -6837,50 +6836,44 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, /* There are several dir indexes for this inode, clear the cache. */ BTRFS_I(inode)->dir_index = 0ULL; - inc_nlink(inode); inode_inc_iversion(inode); inode_set_ctime_current(inode); - ihold(inode); set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags); ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), &fname.disk_name, 1, index); + if (ret) + goto fail; + /* Link added now we update the inode item with the new link count. */ + inc_nlink(inode); + ret = btrfs_update_inode(trans, BTRFS_I(inode)); if (ret) { - drop_inode = 1; - } else { - struct dentry *parent = dentry->d_parent; + btrfs_abort_transaction(trans, ret); + goto fail; + } - ret = btrfs_update_inode(trans, BTRFS_I(inode)); + if (inode->i_nlink == 1) { + /* + * If the new hard link count is 1, it's a file created with the + * open(2) O_TMPFILE flag. + */ + ret = btrfs_orphan_del(trans, BTRFS_I(inode)); if (ret) { btrfs_abort_transaction(trans, ret); - drop_inode = 1; goto fail; } - if (inode->i_nlink == 1) { - /* - * If new hard link count is 1, it's a file created - * with open(2) O_TMPFILE flag. - */ - ret = btrfs_orphan_del(trans, BTRFS_I(inode)); - if (ret) { - btrfs_abort_transaction(trans, ret); - drop_inode = 1; - goto fail; - } - } - d_instantiate(dentry, inode); - btrfs_log_new_name(trans, old_dentry, NULL, 0, parent); } + /* Grab reference for the new dentry passed to d_instantiate(). */ + ihold(inode); + d_instantiate(dentry, inode); + btrfs_log_new_name(trans, old_dentry, NULL, 0, dentry->d_parent); + fail: fscrypt_free_filename(&fname); if (trans) btrfs_end_transaction(trans); - if (drop_inode) { - inode_dec_link_count(inode); - iput(inode); - } btrfs_btree_balance_dirty(fs_info); return ret; } From ef07b74e1be56f9eafda6aadebb9ebba0743c9f0 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 6 Aug 2025 12:11:30 +0100 Subject: [PATCH 0503/1292] btrfs: fix race between logging inode and checking if it was logged before There's a race between checking if an inode was logged before and logging an inode that can cause us to mark an inode as not logged just after it was logged by a concurrent task: 1) We have inode X which was not logged before neither in the current transaction not in past transaction since the inode was loaded into memory, so it's ->logged_trans value is 0; 2) We are at transaction N; 3) Task A calls inode_logged() against inode X, sees that ->logged_trans is 0 and there is a log tree and so it proceeds to search in the log tree for an inode item for inode X. It doesn't see any, but before it sets ->logged_trans to N - 1... 3) Task B calls btrfs_log_inode() against inode X, logs the inode and sets ->logged_trans to N; 4) Task A now sets ->logged_trans to N - 1; 5) At this point anyone calling inode_logged() gets 0 (inode not logged) since ->logged_trans is greater than 0 and less than N, but our inode was really logged. As a consequence operations like rename, unlink and link that happen afterwards in the current transaction end up not updating the log when they should. Fix this by ensuring inode_logged() only updates ->logged_trans in case the inode item is not found in the log tree if after tacking the inode's lock (spinlock struct btrfs_inode::lock) the ->logged_trans value is still zero, since the inode lock is what protects setting ->logged_trans at btrfs_log_inode(). Fixes: 0f8ce49821de ("btrfs: avoid inode logging during rename and link when possible") Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 69e11557fd13d8..839dad70129005 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3340,6 +3340,31 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, return 0; } +static bool mark_inode_as_not_logged(const struct btrfs_trans_handle *trans, + struct btrfs_inode *inode) +{ + bool ret = false; + + /* + * Do this only if ->logged_trans is still 0 to prevent races with + * concurrent logging as we may see the inode not logged when + * inode_logged() is called but it gets logged after inode_logged() did + * not find it in the log tree and we end up setting ->logged_trans to a + * value less than trans->transid after the concurrent logging task has + * set it to trans->transid. As a consequence, subsequent rename, unlink + * and link operations may end up not logging new names and removing old + * names from the log. + */ + spin_lock(&inode->lock); + if (inode->logged_trans == 0) + inode->logged_trans = trans->transid - 1; + else if (inode->logged_trans == trans->transid) + ret = true; + spin_unlock(&inode->lock); + + return ret; +} + /* * Check if an inode was logged in the current transaction. This correctly deals * with the case where the inode was logged but has a logged_trans of 0, which @@ -3374,10 +3399,8 @@ static int inode_logged(const struct btrfs_trans_handle *trans, * transaction's ID, to avoid the search below in a future call in case * a log tree gets created after this. */ - if (!test_bit(BTRFS_ROOT_HAS_LOG_TREE, &inode->root->state)) { - inode->logged_trans = trans->transid - 1; - return 0; - } + if (!test_bit(BTRFS_ROOT_HAS_LOG_TREE, &inode->root->state)) + return mark_inode_as_not_logged(trans, inode); /* * We have a log tree and the inode's logged_trans is 0. We can't tell @@ -3431,8 +3454,7 @@ static int inode_logged(const struct btrfs_trans_handle *trans, * Set logged_trans to a value greater than 0 and less then the * current transaction to avoid doing the search in future calls. */ - inode->logged_trans = trans->transid - 1; - return 0; + return mark_inode_as_not_logged(trans, inode); } /* @@ -3440,7 +3462,9 @@ static int inode_logged(const struct btrfs_trans_handle *trans, * the current transacion's ID, to avoid future tree searches as long as * the inode is not evicted again. */ + spin_lock(&inode->lock); inode->logged_trans = trans->transid; + spin_unlock(&inode->lock); /* * If it's a directory, then we must set last_dir_index_offset to the From 59a0dd4ab98970086fd096281b1606c506ff2698 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 6 Aug 2025 12:11:31 +0100 Subject: [PATCH 0504/1292] btrfs: fix race between setting last_dir_index_offset and inode logging At inode_logged() if we find that the inode was not logged before we update its ->last_dir_index_offset to (u64)-1 with the goal that the next directory log operation will see the (u64)-1 and then figure out it must check what was the index of the last logged dir index key and update ->last_dir_index_offset to that key's offset (this is done in update_last_dir_index_offset()). This however has a possibility for a time window where a race can happen and lead to directory logging skipping dir index keys that should be logged. The race happens like this: 1) Task A calls inode_logged(), sees ->logged_trans as 0 and then checks that the inode item was logged before, but before it sets the inode's ->last_dir_index_offset to (u64)-1... 2) Task B is at btrfs_log_inode() which calls inode_logged() early, and that has set ->last_dir_index_offset to (u64)-1; 3) Task B then enters log_directory_changes() which calls update_last_dir_index_offset(). There it sees ->last_dir_index_offset is (u64)-1 and that the inode was logged before (ctx->logged_before is true), and so it searches for the last logged dir index key in the log tree and it finds that it has an offset (index) value of N, so it sets ->last_dir_index_offset to N, so that we can skip index keys that are less than or equal to N (later at process_dir_items_leaf()); 4) Task A now sets ->last_dir_index_offset to (u64)-1, undoing the update that task B just did; 5) Task B will now skip every index key when it enters process_dir_items_leaf(), since ->last_dir_index_offset is (u64)-1. Fix this by making inode_logged() not touch ->last_dir_index_offset and initializing it to 0 when an inode is loaded (at btrfs_alloc_inode()) and then having update_last_dir_index_offset() treat a value of 0 as meaning we must check the log tree and update with the index of the last logged index key. This is fine since the minimum possible value for ->last_dir_index_offset is 1 (BTRFS_DIR_START_INDEX - 1 = 2 - 1 = 1). This also simplifies the management of ->last_dir_index_offset and now all accesses to it are done under the inode's log_mutex. Fixes: 0f8ce49821de ("btrfs: avoid inode logging during rename and link when possible") Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/btrfs_inode.h | 2 +- fs/btrfs/inode.c | 1 + fs/btrfs/tree-log.c | 17 ++--------------- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index b99fb027329290..0387b9f43a5292 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -248,7 +248,7 @@ struct btrfs_inode { u64 new_delalloc_bytes; /* * The offset of the last dir index key that was logged. - * This is used only for directories. + * This is used only for directories. Protected by 'log_mutex'. */ u64 last_dir_index_offset; }; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 321a46be0377b4..dd82dcc7b2b7b2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7829,6 +7829,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) ei->last_sub_trans = 0; ei->logged_trans = 0; ei->delalloc_bytes = 0; + /* new_delalloc_bytes and last_dir_index_offset are in a union. */ ei->new_delalloc_bytes = 0; ei->defrag_bytes = 0; ei->disk_i_size = 0; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 839dad70129005..2a3d9e996e729b 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3466,19 +3466,6 @@ static int inode_logged(const struct btrfs_trans_handle *trans, inode->logged_trans = trans->transid; spin_unlock(&inode->lock); - /* - * If it's a directory, then we must set last_dir_index_offset to the - * maximum possible value, so that the next attempt to log the inode does - * not skip checking if dir index keys found in modified subvolume tree - * leaves have been logged before, otherwise it would result in attempts - * to insert duplicate dir index keys in the log tree. This must be done - * because last_dir_index_offset is an in-memory only field, not persisted - * in the inode item or any other on-disk structure, so its value is lost - * once the inode is evicted. - */ - if (S_ISDIR(inode->vfs_inode.i_mode)) - inode->last_dir_index_offset = (u64)-1; - return 1; } @@ -4069,7 +4056,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, /* * If the inode was logged before and it was evicted, then its - * last_dir_index_offset is (u64)-1, so we don't the value of the last index + * last_dir_index_offset is 0, so we don't know the value of the last index * key offset. If that's the case, search for it and update the inode. This * is to avoid lookups in the log tree every time we try to insert a dir index * key from a leaf changed in the current transaction, and to allow us to always @@ -4085,7 +4072,7 @@ static int update_last_dir_index_offset(struct btrfs_inode *inode, lockdep_assert_held(&inode->log_mutex); - if (inode->last_dir_index_offset != (u64)-1) + if (inode->last_dir_index_offset != 0) return 0; if (!ctx->logged_before) { From 986bf6ed44dff7fbae7b43a0882757ee7f5ba21b Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 6 Aug 2025 12:11:32 +0100 Subject: [PATCH 0505/1292] btrfs: avoid load/store tearing races when checking if an inode was logged At inode_logged() we do a couple lockless checks for ->logged_trans, and these are generally safe except the second one in case we get a load or store tearing due to a concurrent call updating ->logged_trans (either at btrfs_log_inode() or later at inode_logged()). In the first case it's safe to compare to the current transaction ID since once ->logged_trans is set the current transaction, we never set it to a lower value. In the second case, where we check if it's greater than zero, we are prone to load/store tearing races, since we can have a concurrent task updating to the current transaction ID with store tearing for example, instead of updating with a single 64 bits write, to update with two 32 bits writes or four 16 bits writes. In that case the reading side at inode_logged() could see a positive value that does not match the current transaction and then return a false negative. Fix this by doing the second check while holding the inode's spinlock, add some comments about it too. Also add the data_race() annotation to the first check to avoid any reports from KCSAN (or similar tools) and comment about it. Fixes: 0f8ce49821de ("btrfs: avoid inode logging during rename and link when possible") Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 2a3d9e996e729b..7d5d90845ca985 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3382,15 +3382,32 @@ static int inode_logged(const struct btrfs_trans_handle *trans, struct btrfs_key key; int ret; - if (inode->logged_trans == trans->transid) + /* + * Quick lockless call, since once ->logged_trans is set to the current + * transaction, we never set it to a lower value anywhere else. + */ + if (data_race(inode->logged_trans) == trans->transid) return 1; /* - * If logged_trans is not 0, then we know the inode logged was not logged - * in this transaction, so we can return false right away. + * If logged_trans is not 0 and not trans->transid, then we know the + * inode was not logged in this transaction, so we can return false + * right away. We take the lock to avoid a race caused by load/store + * tearing with a concurrent btrfs_log_inode() call or a concurrent task + * in this function further below - an update to trans->transid can be + * teared into two 32 bits updates for example, in which case we could + * see a positive value that is not trans->transid and assume the inode + * was not logged when it was. */ - if (inode->logged_trans > 0) + spin_lock(&inode->lock); + if (inode->logged_trans == trans->transid) { + spin_unlock(&inode->lock); + return 1; + } else if (inode->logged_trans > 0) { + spin_unlock(&inode->lock); return 0; + } + spin_unlock(&inode->lock); /* * If no log tree was created for this root in this transaction, then From 0e89ca13ee5ff41b437bb2a003c0eaf34ea43555 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 20 Aug 2025 16:22:41 +0000 Subject: [PATCH 0506/1292] KVM: arm64: Split kvm_pgtable_stage2_destroy() Split kvm_pgtable_stage2_destroy() into two: - kvm_pgtable_stage2_destroy_range(), that performs the page-table walk and free the entries over a range of addresses. - kvm_pgtable_stage2_destroy_pgd(), that frees the PGD. This refactoring enables subsequent patches to free large page-tables in chunks, calling cond_resched() between each chunk, to yield the CPU as necessary. Existing callers of kvm_pgtable_stage2_destroy(), that probably cannot take advantage of this (such as nVMHE), will continue to function as is. Signed-off-by: Raghavendra Rao Ananta Suggested-by: Oliver Upton Link: https://lore.kernel.org/r/20250820162242.2624752-2-rananta@google.com Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_pgtable.h | 30 ++++++++++++++++++++++++++++ arch/arm64/include/asm/kvm_pkvm.h | 4 +++- arch/arm64/kvm/hyp/pgtable.c | 25 +++++++++++++++++++---- arch/arm64/kvm/mmu.c | 12 +++++++++-- arch/arm64/kvm/pkvm.c | 11 ++++++++-- 5 files changed, 73 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h index 2888b5d0375736..1246216616b518 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -355,6 +355,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke return pteref; } +static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref) +{ + return pteref; +} + static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker) { /* @@ -384,6 +389,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke return rcu_dereference_check(pteref, !(walker->flags & KVM_PGTABLE_WALK_SHARED)); } +static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref) +{ + return rcu_dereference_raw(pteref); +} + static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker) { if (walker->flags & KVM_PGTABLE_WALK_SHARED) @@ -551,6 +561,26 @@ static inline int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2 */ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt); +/** + * kvm_pgtable_stage2_destroy_range() - Destroy the unlinked range of addresses. + * @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*(). + * @addr: Intermediate physical address at which to place the mapping. + * @size: Size of the mapping. + * + * The page-table is assumed to be unreachable by any hardware walkers prior + * to freeing and therefore no TLB invalidation is performed. + */ +void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, + u64 addr, u64 size); + +/** + * kvm_pgtable_stage2_destroy_pgd() - Destroy the PGD of guest stage-2 page-table. + * @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*(). + * + * It is assumed that the rest of the page-table is freed before this operation. + */ +void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt); + /** * kvm_pgtable_stage2_free_unlinked() - Free an unlinked stage-2 paging structure. * @mm_ops: Memory management callbacks. diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index ea58282f59bb4f..35f9d94780048c 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -179,7 +179,9 @@ struct pkvm_mapping { int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu, struct kvm_pgtable_mm_ops *mm_ops); -void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt); +void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, + u64 addr, u64 size); +void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt); int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys, enum kvm_pgtable_prot prot, void *mc, enum kvm_pgtable_walk_flags flags); diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index c351b4abd5dbfb..c36f282a175dfc 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -1551,21 +1551,38 @@ static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx, return 0; } -void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) +void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, + u64 addr, u64 size) { - size_t pgd_sz; struct kvm_pgtable_walker walker = { .cb = stage2_free_walker, .flags = KVM_PGTABLE_WALK_LEAF | KVM_PGTABLE_WALK_TABLE_POST, }; - WARN_ON(kvm_pgtable_walk(pgt, 0, BIT(pgt->ia_bits), &walker)); + WARN_ON(kvm_pgtable_walk(pgt, addr, size, &walker)); +} + +void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt) +{ + size_t pgd_sz; + pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level) * PAGE_SIZE; - pgt->mm_ops->free_pages_exact(kvm_dereference_pteref(&walker, pgt->pgd), pgd_sz); + + /* + * Since the pgtable is unlinked at this point, and not shared with + * other walkers, safely deference pgd with kvm_dereference_pteref_raw() + */ + pgt->mm_ops->free_pages_exact(kvm_dereference_pteref_raw(pgt->pgd), pgd_sz); pgt->pgd = NULL; } +void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) +{ + kvm_pgtable_stage2_destroy_range(pgt, 0, BIT(pgt->ia_bits)); + kvm_pgtable_stage2_destroy_pgd(pgt); +} + void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level) { kvm_pteref_t ptep = (kvm_pteref_t)pgtable; diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 9a45daf817bfd2..6330a02c841866 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -904,6 +904,14 @@ static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type) return 0; } +static void kvm_stage2_destroy(struct kvm_pgtable *pgt) +{ + unsigned int ia_bits = VTCR_EL2_IPA(pgt->mmu->vtcr); + + KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, 0, BIT(ia_bits)); + KVM_PGT_FN(kvm_pgtable_stage2_destroy_pgd)(pgt); +} + /** * kvm_init_stage2_mmu - Initialise a S2 MMU structure * @kvm: The pointer to the KVM structure @@ -980,7 +988,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t return 0; out_destroy_pgtable: - KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt); + kvm_stage2_destroy(pgt); out_free_pgtable: kfree(pgt); return err; @@ -1077,7 +1085,7 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu) write_unlock(&kvm->mmu_lock); if (pgt) { - KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt); + kvm_stage2_destroy(pgt); kfree(pgt); } } diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index fcd70bfe44fb8c..61827cf6fea4aa 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -316,9 +316,16 @@ static int __pkvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 start, u64 e return 0; } -void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) +void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, + u64 addr, u64 size) { - __pkvm_pgtable_stage2_unmap(pgt, 0, ~(0ULL)); + __pkvm_pgtable_stage2_unmap(pgt, addr, addr + size); +} + +void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt) +{ + /* Expected to be called after all pKVM mappings have been released. */ + WARN_ON_ONCE(!RB_EMPTY_ROOT(&pgt->pkvm_mappings.rb_root)); } int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size, From e9abe311f35631a999fe38c86f26f0e48ffe46d5 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 20 Aug 2025 16:22:42 +0000 Subject: [PATCH 0507/1292] KVM: arm64: Reschedule as needed when destroying the stage-2 page-tables When a large VM, specifically one that holds a significant number of PTEs, gets abruptly destroyed, the following warning is seen during the page-table walk: sched: CPU 0 need_resched set for > 100018840 ns (100 ticks) without schedule CPU: 0 UID: 0 PID: 9617 Comm: kvm_page_table_ Tainted: G O 6.16.0-smp-DEV #3 NONE Tainted: [O]=OOT_MODULE Call trace: show_stack+0x20/0x38 (C) dump_stack_lvl+0x3c/0xb8 dump_stack+0x18/0x30 resched_latency_warn+0x7c/0x88 sched_tick+0x1c4/0x268 update_process_times+0xa8/0xd8 tick_nohz_handler+0xc8/0x168 __hrtimer_run_queues+0x11c/0x338 hrtimer_interrupt+0x104/0x308 arch_timer_handler_phys+0x40/0x58 handle_percpu_devid_irq+0x8c/0x1b0 generic_handle_domain_irq+0x48/0x78 gic_handle_irq+0x1b8/0x408 call_on_irq_stack+0x24/0x30 do_interrupt_handler+0x54/0x78 el1_interrupt+0x44/0x88 el1h_64_irq_handler+0x18/0x28 el1h_64_irq+0x84/0x88 stage2_free_walker+0x30/0xa0 (P) __kvm_pgtable_walk+0x11c/0x258 __kvm_pgtable_walk+0x180/0x258 __kvm_pgtable_walk+0x180/0x258 __kvm_pgtable_walk+0x180/0x258 kvm_pgtable_walk+0xc4/0x140 kvm_pgtable_stage2_destroy+0x5c/0xf0 kvm_free_stage2_pgd+0x6c/0xe8 kvm_uninit_stage2_mmu+0x24/0x48 kvm_arch_flush_shadow_all+0x80/0xa0 kvm_mmu_notifier_release+0x38/0x78 __mmu_notifier_release+0x15c/0x250 exit_mmap+0x68/0x400 __mmput+0x38/0x1c8 mmput+0x30/0x68 exit_mm+0xd4/0x198 do_exit+0x1a4/0xb00 do_group_exit+0x8c/0x120 get_signal+0x6d4/0x778 do_signal+0x90/0x718 do_notify_resume+0x70/0x170 el0_svc+0x74/0xd8 el0t_64_sync_handler+0x60/0xc8 el0t_64_sync+0x1b0/0x1b8 The warning is seen majorly on the host kernels that are configured not to force-preempt, such as CONFIG_PREEMPT_NONE=y. To avoid this, instead of walking the entire page-table in one go, split it into smaller ranges, by checking for cond_resched() between each range. Since the path is executed during VM destruction, after the page-table structure is unlinked from the KVM MMU, relying on cond_resched_rwlock_write() isn't necessary. Signed-off-by: Raghavendra Rao Ananta Suggested-by: Oliver Upton Link: https://lore.kernel.org/r/20250820162242.2624752-3-rananta@google.com Signed-off-by: Oliver Upton --- arch/arm64/kvm/mmu.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 6330a02c841866..86f3d80daf37af 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -904,11 +904,35 @@ static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type) return 0; } +/* + * Assume that @pgt is valid and unlinked from the KVM MMU to free the + * page-table without taking the kvm_mmu_lock and without performing any + * TLB invalidations. + * + * Also, the range of addresses can be large enough to cause need_resched + * warnings, for instance on CONFIG_PREEMPT_NONE kernels. Hence, invoke + * cond_resched() periodically to prevent hogging the CPU for a long time + * and schedule something else, if required. + */ +static void stage2_destroy_range(struct kvm_pgtable *pgt, phys_addr_t addr, + phys_addr_t end) +{ + u64 next; + + do { + next = stage2_range_addr_end(addr, end); + KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, addr, + next - addr); + if (next != end) + cond_resched(); + } while (addr = next, addr != end); +} + static void kvm_stage2_destroy(struct kvm_pgtable *pgt) { unsigned int ia_bits = VTCR_EL2_IPA(pgt->mmu->vtcr); - KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, 0, BIT(ia_bits)); + stage2_destroy_range(pgt, 0, BIT(ia_bits)); KVM_PGT_FN(kvm_pgtable_stage2_destroy_pgd)(pgt); } From 8049164653c6e6e7b347da773098d8660a26a6f6 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 21:21:53 +0100 Subject: [PATCH 0508/1292] arm64: Add capability denoting FEAT_RASv1p1 Detecting FEAT_RASv1p1 is rather complicated, as there are two ways for the architecture to advertise the same thing (always a delight...). Add a capability that will advertise this in a synthetic way to the rest of the kernel. Acked-by: Catalin Marinas Signed-off-by: Marc Zyngier Reviewed-by: Cornelia Huck Link: https://lore.kernel.org/r/20250817202158.395078-2-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kernel/cpufeature.c | 24 ++++++++++++++++++++++++ arch/arm64/tools/cpucaps | 1 + 2 files changed, 25 insertions(+) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 4dece9ca68bc6b..22a94e548362d1 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2235,6 +2235,24 @@ static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused) /* Firmware may have left a deferred SError in this register. */ write_sysreg_s(0, SYS_DISR_EL1); } +static bool has_rasv1p1(const struct arm64_cpu_capabilities *__unused, int scope) +{ + const struct arm64_cpu_capabilities rasv1p1_caps[] = { + { + ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, RAS, V1P1) + }, + { + ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, RAS, IMP) + }, + { + ARM64_CPUID_FIELDS(ID_AA64PFR1_EL1, RAS_frac, RASv1p1) + }, + }; + + return (has_cpuid_feature(&rasv1p1_caps[0], scope) || + (has_cpuid_feature(&rasv1p1_caps[1], scope) && + has_cpuid_feature(&rasv1p1_caps[2], scope))); +} #endif /* CONFIG_ARM64_RAS_EXTN */ #ifdef CONFIG_ARM64_PTR_AUTH @@ -2653,6 +2671,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .cpu_enable = cpu_clear_disr, ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, RAS, IMP) }, + { + .desc = "RASv1p1 Extension Support", + .capability = ARM64_HAS_RASV1P1_EXTN, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_rasv1p1, + }, #endif /* CONFIG_ARM64_RAS_EXTN */ #ifdef CONFIG_ARM64_AMU_EXTN { diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index 115161dd9a24d7..eb7f1f5622a8fa 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -52,6 +52,7 @@ HAS_S1PIE HAS_S1POE HAS_SCTLR2 HAS_RAS_EXTN +HAS_RASV1P1_EXTN HAS_RNG HAS_SB HAS_STAGE2_FWB From d7b3e23f945b36aec3938e5ea954bc125f38562e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 21:21:54 +0100 Subject: [PATCH 0509/1292] KVM: arm64: Handle RASv1p1 registers FEAT_RASv1p1 system registeres are not handled at all so far. KVM will give an embarassed warning on the console and inject an UNDEF, despite RASv1p1 being exposed to the guest on suitable HW. Handle these registers similarly to FEAT_RAS, with the added fun that there are *two* way to indicate the presence of FEAT_RASv1p1. Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier Reviewed-by: Cornelia Huck Link: https://lore.kernel.org/r/20250817202158.395078-3-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index ad254847725740..1b4114790024e5 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2695,6 +2695,18 @@ static bool access_ras(struct kvm_vcpu *vcpu, struct kvm *kvm = vcpu->kvm; switch(reg_to_encoding(r)) { + case SYS_ERXPFGCDN_EL1: + case SYS_ERXPFGCTL_EL1: + case SYS_ERXPFGF_EL1: + case SYS_ERXMISC2_EL1: + case SYS_ERXMISC3_EL1: + if (!(kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, V1P1) || + (kvm_has_feat_enum(kvm, ID_AA64PFR0_EL1, RAS, IMP) && + kvm_has_feat(kvm, ID_AA64PFR1_EL1, RAS_frac, RASv1p1)))) { + kvm_inject_undefined(vcpu); + return false; + } + break; default: if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, IMP)) { kvm_inject_undefined(vcpu); @@ -3058,8 +3070,13 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_ERXCTLR_EL1), access_ras }, { SYS_DESC(SYS_ERXSTATUS_EL1), access_ras }, { SYS_DESC(SYS_ERXADDR_EL1), access_ras }, + { SYS_DESC(SYS_ERXPFGF_EL1), access_ras }, + { SYS_DESC(SYS_ERXPFGCTL_EL1), access_ras }, + { SYS_DESC(SYS_ERXPFGCDN_EL1), access_ras }, { SYS_DESC(SYS_ERXMISC0_EL1), access_ras }, { SYS_DESC(SYS_ERXMISC1_EL1), access_ras }, + { SYS_DESC(SYS_ERXMISC2_EL1), access_ras }, + { SYS_DESC(SYS_ERXMISC3_EL1), access_ras }, MTE_REG(TFSR_EL1), MTE_REG(TFSRE0_EL1), From 9049fb1227a2d1ab8515788c8553232966380248 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 21:21:55 +0100 Subject: [PATCH 0510/1292] KVM: arm64: Ignore HCR_EL2.FIEN set by L1 guest's EL2 An EL2 guest can set HCR_EL2.FIEN, which gives access to the RASv1p1 fault injection mechanism. This would allow an EL1 guest to inject error records into the system, which does sound like a terrible idea. Prevent this situation by added FIEN to the list of bits we silently exclude from being inserted into the host configuration. Signed-off-by: Marc Zyngier Reviewed-by: Joey Gouly Link: https://lore.kernel.org/r/20250817202158.395078-4-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/vhe/switch.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index e482181c66322a..0998ad4a25524f 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -43,8 +43,11 @@ DEFINE_PER_CPU(unsigned long, kvm_hyp_vector); * * - API/APK: they are already accounted for by vcpu_load(), and can * only take effect across a load/put cycle (such as ERET) + * + * - FIEN: no way we let a guest have access to the RAS "Common Fault + * Injection" thing, whatever that does */ -#define NV_HCR_GUEST_EXCLUDE (HCR_TGE | HCR_API | HCR_APK) +#define NV_HCR_GUEST_EXCLUDE (HCR_TGE | HCR_API | HCR_APK | HCR_FIEN) static u64 __compute_hcr(struct kvm_vcpu *vcpu) { From 1fab657cb2a07889c343302fbebca035e702683e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 21:21:56 +0100 Subject: [PATCH 0511/1292] KVM: arm64: Make ID_AA64PFR0_EL1.RAS writable Make ID_AA64PFR0_EL1.RAS writable so that we can restore a VM from a system without RAS to a RAS-equipped machine (or disable RAS in the guest). Signed-off-by: Marc Zyngier Reviewed-by: Cornelia Huck Link: https://lore.kernel.org/r/20250817202158.395078-5-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 1b4114790024e5..bf160693963c81 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2939,7 +2939,6 @@ static const struct sys_reg_desc sys_reg_descs[] = { ~(ID_AA64PFR0_EL1_AMU | ID_AA64PFR0_EL1_MPAM | ID_AA64PFR0_EL1_SVE | - ID_AA64PFR0_EL1_RAS | ID_AA64PFR0_EL1_AdvSIMD | ID_AA64PFR0_EL1_FP)), ID_FILTERED(ID_AA64PFR1_EL1, id_aa64pfr1_el1, From 7a765aa88e345782d3e4ed4c82e49f1ea82fd29c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 21:21:57 +0100 Subject: [PATCH 0512/1292] KVM: arm64: Make ID_AA64PFR1_EL1.RAS_frac writable Allow userspace to write to RAS_frac, under the condition that the host supports RASv1p1 with RAS_frac==1. Other configurations will result in RAS_frac being exposed as 0, and therefore implicitly not writable. To avoid the clutter, the ID_AA64PFR1_EL1 sanitisation is moved to its own function. Signed-off-by: Marc Zyngier Reviewed-by: Cornelia Huck Link: https://lore.kernel.org/r/20250817202158.395078-6-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/sys_regs.c | 41 ++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index bf160693963c81..5abe4db6c00841 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1584,6 +1584,7 @@ static u8 pmuver_to_perfmon(u8 pmuver) } static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val); +static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val); static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val); /* Read a sanitised cpufeature ID register by sys_reg_desc */ @@ -1606,19 +1607,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, val = sanitise_id_aa64pfr0_el1(vcpu, val); break; case SYS_ID_AA64PFR1_EL1: - if (!kvm_has_mte(vcpu->kvm)) { - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac); - } - - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_RNDR_trap); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_GCS); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_THE); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTEX); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_PFAR); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MPAM_frac); + val = sanitise_id_aa64pfr1_el1(vcpu, val); break; case SYS_ID_AA64PFR2_EL1: /* We only expose FPMR */ @@ -1834,6 +1823,31 @@ static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val) return val; } +static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val) +{ + u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); + + if (!kvm_has_mte(vcpu->kvm)) { + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac); + } + + if (!(cpus_have_final_cap(ARM64_HAS_RASV1P1_EXTN) && + SYS_FIELD_GET(ID_AA64PFR0_EL1, RAS, pfr0) == ID_AA64PFR0_EL1_RAS_IMP)) + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_RAS_frac); + + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_RNDR_trap); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_GCS); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_THE); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTEX); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_PFAR); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MPAM_frac); + + return val; +} + static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val) { val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8); @@ -2952,7 +2966,6 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_AA64PFR1_EL1_SME | ID_AA64PFR1_EL1_RES0 | ID_AA64PFR1_EL1_MPAM_frac | - ID_AA64PFR1_EL1_RAS_frac | ID_AA64PFR1_EL1_MTE)), ID_WRITABLE(ID_AA64PFR2_EL1, ID_AA64PFR2_EL1_FPMR), ID_UNALLOCATED(4,3), From 0843e0ced338d07c8bcec5675c560a94d05a4d41 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 21:21:58 +0100 Subject: [PATCH 0513/1292] KVM: arm64: Get rid of ARM64_FEATURE_MASK() The ARM64_FEATURE_MASK() macro was a hack introduce whilst the automatic generation of sysreg encoding was introduced, and was too unreliable to be entirely trusted. We are in a better place now, and we could really do without this macro. Get rid of it altogether. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20250817202158.395078-7-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/sysreg.h | 3 -- arch/arm64/kvm/arm.c | 8 ++-- arch/arm64/kvm/sys_regs.c | 40 +++++++++---------- tools/arch/arm64/include/asm/sysreg.h | 3 -- .../selftests/kvm/arm64/aarch32_id_regs.c | 2 +- .../selftests/kvm/arm64/debug-exceptions.c | 12 +++--- .../testing/selftests/kvm/arm64/no-vgic-v3.c | 4 +- .../selftests/kvm/arm64/page_fault_test.c | 6 +-- .../testing/selftests/kvm/arm64/set_id_regs.c | 8 ++-- .../selftests/kvm/arm64/vpmu_counter_access.c | 2 +- .../selftests/kvm/lib/arm64/processor.c | 6 +-- 11 files changed, 44 insertions(+), 50 deletions(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 948007cd368459..845875991eb86a 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -1146,9 +1146,6 @@ #define ARM64_FEATURE_FIELD_BITS 4 -/* Defined for compatibility only, do not add new users. */ -#define ARM64_FEATURE_MASK(x) (x##_MASK) - #ifdef __ASSEMBLY__ .macro mrs_s, rt, sreg diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 7a1a8210ff9185..d60d2a644391cd 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2404,12 +2404,12 @@ static u64 get_hyp_id_aa64pfr0_el1(void) */ u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); - val &= ~(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2) | - ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3)); + val &= ~(ID_AA64PFR0_EL1_CSV2 | + ID_AA64PFR0_EL1_CSV3); - val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2), + val |= FIELD_PREP(ID_AA64PFR0_EL1_CSV2, arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED); - val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3), + val |= FIELD_PREP(ID_AA64PFR0_EL1_CSV3, arm64_get_meltdown_state() == SPECTRE_UNAFFECTED); return val; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 5abe4db6c00841..e387d1dfed1e64 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1615,18 +1615,18 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, break; case SYS_ID_AA64ISAR1_EL1: if (!vcpu_has_ptrauth(vcpu)) - val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) | - ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) | - ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) | - ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI)); + val &= ~(ID_AA64ISAR1_EL1_APA | + ID_AA64ISAR1_EL1_API | + ID_AA64ISAR1_EL1_GPA | + ID_AA64ISAR1_EL1_GPI); break; case SYS_ID_AA64ISAR2_EL1: if (!vcpu_has_ptrauth(vcpu)) - val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) | - ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3)); + val &= ~(ID_AA64ISAR2_EL1_APA3 | + ID_AA64ISAR2_EL1_GPA3); if (!cpus_have_final_cap(ARM64_HAS_WFXT) || has_broken_cntvoff()) - val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT); + val &= ~ID_AA64ISAR2_EL1_WFxT; break; case SYS_ID_AA64ISAR3_EL1: val &= ID_AA64ISAR3_EL1_FPRCVT | ID_AA64ISAR3_EL1_FAMINMAX; @@ -1642,7 +1642,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, ID_AA64MMFR3_EL1_S1PIE; break; case SYS_ID_MMFR4_EL1: - val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX); + val &= ~ID_MMFR4_EL1_CCIDX; break; } @@ -1828,22 +1828,22 @@ static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val) u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); if (!kvm_has_mte(vcpu->kvm)) { - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac); + val &= ~ID_AA64PFR1_EL1_MTE; + val &= ~ID_AA64PFR1_EL1_MTE_frac; } if (!(cpus_have_final_cap(ARM64_HAS_RASV1P1_EXTN) && SYS_FIELD_GET(ID_AA64PFR0_EL1, RAS, pfr0) == ID_AA64PFR0_EL1_RAS_IMP)) - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_RAS_frac); - - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_RNDR_trap); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_GCS); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_THE); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTEX); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_PFAR); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MPAM_frac); + val &= ~ID_AA64PFR1_EL1_RAS_frac; + + val &= ~ID_AA64PFR1_EL1_SME; + val &= ~ID_AA64PFR1_EL1_RNDR_trap; + val &= ~ID_AA64PFR1_EL1_NMI; + val &= ~ID_AA64PFR1_EL1_GCS; + val &= ~ID_AA64PFR1_EL1_THE; + val &= ~ID_AA64PFR1_EL1_MTEX; + val &= ~ID_AA64PFR1_EL1_PFAR; + val &= ~ID_AA64PFR1_EL1_MPAM_frac; return val; } diff --git a/tools/arch/arm64/include/asm/sysreg.h b/tools/arch/arm64/include/asm/sysreg.h index 690b6ebd118f4f..65f2759ea27a35 100644 --- a/tools/arch/arm64/include/asm/sysreg.h +++ b/tools/arch/arm64/include/asm/sysreg.h @@ -1080,9 +1080,6 @@ #define ARM64_FEATURE_FIELD_BITS 4 -/* Defined for compatibility only, do not add new users. */ -#define ARM64_FEATURE_MASK(x) (x##_MASK) - #ifdef __ASSEMBLY__ .macro mrs_s, rt, sreg diff --git a/tools/testing/selftests/kvm/arm64/aarch32_id_regs.c b/tools/testing/selftests/kvm/arm64/aarch32_id_regs.c index cef8f7323ceb88..713005b6f508e8 100644 --- a/tools/testing/selftests/kvm/arm64/aarch32_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/aarch32_id_regs.c @@ -146,7 +146,7 @@ static bool vcpu_aarch64_only(struct kvm_vcpu *vcpu) val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1)); - el0 = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0), val); + el0 = FIELD_GET(ID_AA64PFR0_EL1_EL0, val); return el0 == ID_AA64PFR0_EL1_EL0_IMP; } diff --git a/tools/testing/selftests/kvm/arm64/debug-exceptions.c b/tools/testing/selftests/kvm/arm64/debug-exceptions.c index c7fb55c9135ba4..521991a89ad94a 100644 --- a/tools/testing/selftests/kvm/arm64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/arm64/debug-exceptions.c @@ -116,12 +116,12 @@ static void reset_debug_state(void) /* Reset all bcr/bvr/wcr/wvr registers */ dfr0 = read_sysreg(id_aa64dfr0_el1); - brps = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_BRPs), dfr0); + brps = FIELD_GET(ID_AA64DFR0_EL1_BRPs, dfr0); for (i = 0; i <= brps; i++) { write_dbgbcr(i, 0); write_dbgbvr(i, 0); } - wrps = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_WRPs), dfr0); + wrps = FIELD_GET(ID_AA64DFR0_EL1_WRPs, dfr0); for (i = 0; i <= wrps; i++) { write_dbgwcr(i, 0); write_dbgwvr(i, 0); @@ -418,7 +418,7 @@ static void guest_code_ss(int test_cnt) static int debug_version(uint64_t id_aa64dfr0) { - return FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_DebugVer), id_aa64dfr0); + return FIELD_GET(ID_AA64DFR0_EL1_DebugVer, id_aa64dfr0); } static void test_guest_debug_exceptions(uint8_t bpn, uint8_t wpn, uint8_t ctx_bpn) @@ -539,14 +539,14 @@ void test_guest_debug_exceptions_all(uint64_t aa64dfr0) int b, w, c; /* Number of breakpoints */ - brp_num = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_BRPs), aa64dfr0) + 1; + brp_num = FIELD_GET(ID_AA64DFR0_EL1_BRPs, aa64dfr0) + 1; __TEST_REQUIRE(brp_num >= 2, "At least two breakpoints are required"); /* Number of watchpoints */ - wrp_num = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_WRPs), aa64dfr0) + 1; + wrp_num = FIELD_GET(ID_AA64DFR0_EL1_WRPs, aa64dfr0) + 1; /* Number of context aware breakpoints */ - ctx_brp_num = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_CTX_CMPs), aa64dfr0) + 1; + ctx_brp_num = FIELD_GET(ID_AA64DFR0_EL1_CTX_CMPs, aa64dfr0) + 1; pr_debug("%s brp_num:%d, wrp_num:%d, ctx_brp_num:%d\n", __func__, brp_num, wrp_num, ctx_brp_num); diff --git a/tools/testing/selftests/kvm/arm64/no-vgic-v3.c b/tools/testing/selftests/kvm/arm64/no-vgic-v3.c index ebd70430c89ded..f222538e608418 100644 --- a/tools/testing/selftests/kvm/arm64/no-vgic-v3.c +++ b/tools/testing/selftests/kvm/arm64/no-vgic-v3.c @@ -54,7 +54,7 @@ static void guest_code(void) * Check that we advertise that ID_AA64PFR0_EL1.GIC == 0, having * hidden the feature at runtime without any other userspace action. */ - __GUEST_ASSERT(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC), + __GUEST_ASSERT(FIELD_GET(ID_AA64PFR0_EL1_GIC, read_sysreg(id_aa64pfr0_el1)) == 0, "GICv3 wrongly advertised"); @@ -165,7 +165,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, NULL); pfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1)); - __TEST_REQUIRE(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC), pfr0), + __TEST_REQUIRE(FIELD_GET(ID_AA64PFR0_EL1_GIC, pfr0), "GICv3 not supported."); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/arm64/page_fault_test.c b/tools/testing/selftests/kvm/arm64/page_fault_test.c index dc6559dad9d863..4ccbd389d13369 100644 --- a/tools/testing/selftests/kvm/arm64/page_fault_test.c +++ b/tools/testing/selftests/kvm/arm64/page_fault_test.c @@ -95,14 +95,14 @@ static bool guest_check_lse(void) uint64_t isar0 = read_sysreg(id_aa64isar0_el1); uint64_t atomic; - atomic = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_ATOMIC), isar0); + atomic = FIELD_GET(ID_AA64ISAR0_EL1_ATOMIC, isar0); return atomic >= 2; } static bool guest_check_dc_zva(void) { uint64_t dczid = read_sysreg(dczid_el0); - uint64_t dzp = FIELD_GET(ARM64_FEATURE_MASK(DCZID_EL0_DZP), dczid); + uint64_t dzp = FIELD_GET(DCZID_EL0_DZP, dczid); return dzp == 0; } @@ -195,7 +195,7 @@ static bool guest_set_ha(void) uint64_t hadbs, tcr; /* Skip if HA is not supported. */ - hadbs = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HAFDBS), mmfr1); + hadbs = FIELD_GET(ID_AA64MMFR1_EL1_HAFDBS, mmfr1); if (hadbs == 0) return false; diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index d3bf9204409c35..36d40c267b9949 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -594,8 +594,8 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu) */ val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1)); - mte = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE), val); - mte_frac = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac), val); + mte = FIELD_GET(ID_AA64PFR1_EL1_MTE, val); + mte_frac = FIELD_GET(ID_AA64PFR1_EL1_MTE_frac, val); if (mte != ID_AA64PFR1_EL1_MTE_MTE2 || mte_frac != ID_AA64PFR1_EL1_MTE_frac_NI) { ksft_test_result_skip("MTE_ASYNC or MTE_ASYMM are supported, nothing to test\n"); @@ -612,7 +612,7 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu) } val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1)); - mte_frac = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac), val); + mte_frac = FIELD_GET(ID_AA64PFR1_EL1_MTE_frac, val); if (mte_frac == ID_AA64PFR1_EL1_MTE_frac_NI) ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac=0 accepted and still 0xF\n"); else @@ -774,7 +774,7 @@ int main(void) /* Check for AARCH64 only system */ val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1)); - el0 = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0), val); + el0 = FIELD_GET(ID_AA64PFR0_EL1_EL0, val); aarch64_only = (el0 == ID_AA64PFR0_EL1_EL0_IMP); ksft_print_header(); diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c index f16b3b27e32ed7..a0c4ab83915597 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -441,7 +441,7 @@ static void create_vpmu_vm(void *guest_code) /* Make sure that PMUv3 support is indicated in the ID register */ dfr0 = vcpu_get_reg(vpmu_vm.vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1)); - pmuver = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), dfr0); + pmuver = FIELD_GET(ID_AA64DFR0_EL1_PMUVer, dfr0); TEST_ASSERT(pmuver != ID_AA64DFR0_EL1_PMUVer_IMP_DEF && pmuver >= ID_AA64DFR0_EL1_PMUVer_IMP, "Unexpected PMUVER (0x%x) on the vCPU with PMUv3", pmuver); diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index 9d69904cb6084a..eb115123d74118 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -573,15 +573,15 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); - gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val); + gran = FIELD_GET(ID_AA64MMFR0_EL1_TGRAN4, val); *ipa4k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN4_NI, ID_AA64MMFR0_EL1_TGRAN4_52_BIT); - gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val); + gran = FIELD_GET(ID_AA64MMFR0_EL1_TGRAN64, val); *ipa64k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN64_NI, ID_AA64MMFR0_EL1_TGRAN64_IMP); - gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val); + gran = FIELD_GET(ID_AA64MMFR0_EL1_TGRAN16, val); *ipa16k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN16_NI, ID_AA64MMFR0_EL1_TGRAN16_52_BIT); From 01860bcc53432d8b9b92a72939b35679ac24059f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 18 Aug 2025 17:41:00 +0100 Subject: [PATCH 0514/1292] KVM: arm64: selftests: Sync ID_AA64MMFR3_EL1 in set_id_regs When we added coverage for ID_AA64MMFR3_EL1 we didn't add it to the list of registers we read in the guest, do so. Fixes: 0b593ef12afc ("KVM: arm64: selftests: Catch up set_id_regs with the kernel") Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20250818-kvm-arm64-selftests-mmfr3-idreg-v1-1-2f85114d0163@kernel.org Signed-off-by: Oliver Upton --- tools/testing/selftests/kvm/arm64/set_id_regs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index 36d40c267b9949..189321e969258c 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -243,6 +243,7 @@ static void guest_code(void) GUEST_REG_SYNC(SYS_ID_AA64MMFR0_EL1); GUEST_REG_SYNC(SYS_ID_AA64MMFR1_EL1); GUEST_REG_SYNC(SYS_ID_AA64MMFR2_EL1); + GUEST_REG_SYNC(SYS_ID_AA64MMFR3_EL1); GUEST_REG_SYNC(SYS_ID_AA64ZFR0_EL1); GUEST_REG_SYNC(SYS_CTR_EL0); GUEST_REG_SYNC(SYS_MIDR_EL1); From b08a784a5d1495c42ff9b0c70887d49211cddfe0 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 18 Aug 2025 19:03:54 +0100 Subject: [PATCH 0515/1292] net: Introduce skb_copy_datagram_from_iter_full() In a similar manner to copy_from_iter()/copy_from_iter_full(), introduce skb_copy_datagram_from_iter_full() which reverts the iterator to its initial state when returning an error. A subsequent fix for a vsock regression will make use of this new function. Cc: Christian Brauner Cc: Alexander Viro Signed-off-by: Will Deacon Acked-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Link: https://patch.msgid.link/20250818180355.29275-2-will@kernel.org Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 2 ++ net/core/datagram.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 14b923ddb6dfcc..fa633657e4c068 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4172,6 +4172,8 @@ int skb_copy_and_crc32c_datagram_iter(const struct sk_buff *skb, int offset, struct iov_iter *to, int len, u32 *crcp); int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset, struct iov_iter *from, int len); +int skb_copy_datagram_from_iter_full(struct sk_buff *skb, int offset, + struct iov_iter *from, int len); int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm); void skb_free_datagram(struct sock *sk, struct sk_buff *skb); int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); diff --git a/net/core/datagram.c b/net/core/datagram.c index 94cc4705e91da6..f474b9b120f984 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -618,6 +618,20 @@ int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset, } EXPORT_SYMBOL(skb_copy_datagram_from_iter); +int skb_copy_datagram_from_iter_full(struct sk_buff *skb, int offset, + struct iov_iter *from, int len) +{ + struct iov_iter_state state; + int ret; + + iov_iter_save_state(from, &state); + ret = skb_copy_datagram_from_iter(skb, offset, from, len); + if (ret) + iov_iter_restore(from, &state); + return ret; +} +EXPORT_SYMBOL(skb_copy_datagram_from_iter_full); + int zerocopy_fill_skb_from_iter(struct sk_buff *skb, struct iov_iter *from, size_t length) { From 7fb1291257ea1e27dbc3f34c6a37b4d640aafdd7 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 18 Aug 2025 19:03:55 +0100 Subject: [PATCH 0516/1292] vsock/virtio: Fix message iterator handling on transmit path Commit 6693731487a8 ("vsock/virtio: Allocate nonlinear SKBs for handling large transmit buffers") converted the virtio vsock transmit path to utilise nonlinear SKBs when handling large buffers. As part of this change, virtio_transport_fill_skb() was updated to call skb_copy_datagram_from_iter() instead of memcpy_from_msg() as the latter expects a single destination buffer and cannot handle nonlinear SKBs correctly. Unfortunately, during this conversion, I overlooked the error case when the copying function returns -EFAULT due to a fault on the input buffer in userspace. In this case, memcpy_from_msg() reverts the iterator to its initial state thanks to copy_from_iter_full() whereas skb_copy_datagram_from_iter() leaves the iterator partially advanced. This results in a WARN_ONCE() from the vsock code, which expects the iterator to stay in sync with the number of bytes transmitted so that virtio_transport_send_pkt_info() can return -EFAULT when it is called again: ------------[ cut here ]------------ 'send_pkt()' returns 0, but 65536 expected WARNING: CPU: 0 PID: 5503 at net/vmw_vsock/virtio_transport_common.c:428 virtio_transport_send_pkt_info+0xd11/0xf00 net/vmw_vsock/virtio_transport_common.c:426 Modules linked in: CPU: 0 UID: 0 PID: 5503 Comm: syz.0.17 Not tainted 6.16.0-syzkaller-12063-g37816488247d #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 Call virtio_transport_fill_skb_full() to restore the previous iterator behaviour. Cc: Jason Wang Cc: Stefano Garzarella Fixes: 6693731487a8 ("vsock/virtio: Allocate nonlinear SKBs for handling large transmit buffers") Reported-by: syzbot+b4d960daf7a3c7c2b7b1@syzkaller.appspotmail.com Signed-off-by: Will Deacon Acked-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Link: https://patch.msgid.link/20250818180355.29275-3-will@kernel.org Signed-off-by: Jakub Kicinski --- net/vmw_vsock/virtio_transport_common.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index fe92e5fa95b4d3..dcc8a1d5851e6a 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -105,12 +105,14 @@ static int virtio_transport_fill_skb(struct sk_buff *skb, size_t len, bool zcopy) { + struct msghdr *msg = info->msg; + if (zcopy) - return __zerocopy_sg_from_iter(info->msg, NULL, skb, - &info->msg->msg_iter, len, NULL); + return __zerocopy_sg_from_iter(msg, NULL, skb, + &msg->msg_iter, len, NULL); virtio_vsock_skb_put(skb, len); - return skb_copy_datagram_from_iter(skb, 0, &info->msg->msg_iter, len); + return skb_copy_datagram_from_iter_full(skb, 0, &msg->msg_iter, len); } static void virtio_transport_init_hdr(struct sk_buff *skb, From 01b9128c5db1b470575d07b05b67ffa3cb02ebf1 Mon Sep 17 00:00:00 2001 From: luoguangfei <15388634752@163.com> Date: Tue, 19 Aug 2025 07:25:27 +0800 Subject: [PATCH 0517/1292] net: macb: fix unregister_netdev call order in macb_remove() When removing a macb device, the driver calls phy_exit() before unregister_netdev(). This leads to a WARN from kernfs: ------------[ cut here ]------------ kernfs: can not remove 'attached_dev', no directory WARNING: CPU: 1 PID: 27146 at fs/kernfs/dir.c:1683 Call trace: kernfs_remove_by_name_ns+0xd8/0xf0 sysfs_remove_link+0x24/0x58 phy_detach+0x5c/0x168 phy_disconnect+0x4c/0x70 phylink_disconnect_phy+0x6c/0xc0 [phylink] macb_close+0x6c/0x170 [macb] ... macb_remove+0x60/0x168 [macb] platform_remove+0x5c/0x80 ... The warning happens because the PHY is being exited while the netdev is still registered. The correct order is to unregister the netdev before shutting down the PHY and cleaning up the MDIO bus. Fix this by moving unregister_netdev() ahead of phy_exit() in macb_remove(). Fixes: 8b73fa3ae02b ("net: macb: Added ZynqMP-specific initialization") Signed-off-by: luoguangfei <15388634752@163.com> Link: https://patch.msgid.link/20250818232527.1316-1-15388634752@163.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 9693f028943569..b29c3beae0b254 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -5399,11 +5399,11 @@ static void macb_remove(struct platform_device *pdev) if (dev) { bp = netdev_priv(dev); + unregister_netdev(dev); phy_exit(bp->sgmii_phy); mdiobus_unregister(bp->mii_bus); mdiobus_free(bp->mii_bus); - unregister_netdev(dev); cancel_work_sync(&bp->hresp_err_bh_work); pm_runtime_disable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); From c08e42c9a40ab634a7b762838977854ee3503b3d Mon Sep 17 00:00:00 2001 From: "Nikola Z. Ivanov" Date: Thu, 21 Aug 2025 23:01:32 +0300 Subject: [PATCH 0518/1292] selftests/alsa: remove 0/NULL global variable assignment Remove 0/NULL global variable assignment in mixer-test.c and pcm-test.c Signed-off-by: Nikola Z. Ivanov Reviewed-by: Mark Brown Link: https://patch.msgid.link/20250821200132.1218850-1-zlatistiv@gmail.com Signed-off-by: Takashi Iwai --- tools/testing/selftests/alsa/mixer-test.c | 8 ++++---- tools/testing/selftests/alsa/pcm-test.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c index 2a4b2662035efc..e113dafa5c2464 100644 --- a/tools/testing/selftests/alsa/mixer-test.c +++ b/tools/testing/selftests/alsa/mixer-test.c @@ -53,10 +53,10 @@ struct ctl_data { struct ctl_data *next; }; -int num_cards = 0; -int num_controls = 0; -struct card_data *card_list = NULL; -struct ctl_data *ctl_list = NULL; +int num_cards; +int num_controls; +struct card_data *card_list; +struct ctl_data *ctl_list; static void find_controls(void) { diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index dbd7c222ce938e..ce92548670c893 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -30,7 +30,7 @@ struct card_data { struct card_data *next; }; -struct card_data *card_list = NULL; +struct card_data *card_list; struct pcm_data { snd_pcm_t *handle; @@ -43,10 +43,10 @@ struct pcm_data { struct pcm_data *next; }; -struct pcm_data *pcm_list = NULL; +struct pcm_data *pcm_list; -int num_missing = 0; -struct pcm_data *pcm_missing = NULL; +int num_missing; +struct pcm_data *pcm_missing; snd_config_t *default_pcm_config; From a12946bef0407cf2db0899c83d42c47c00af3fbc Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 14 Aug 2025 19:27:21 -0700 Subject: [PATCH 0519/1292] pinctrl: STMFX: add missing HAS_IOMEM dependency When building on ARCH=um (which does not set HAS_IOMEM), kconfig reports an unmet dependency caused by PINCTRL_STMFX. It selects MFD_STMFX, which depends on HAS_IOMEM. To stop this warning, PINCTRL_STMFX should also depend on HAS_IOMEM. kconfig warning: WARNING: unmet direct dependencies detected for MFD_STMFX Depends on [n]: HAS_IOMEM [=n] && I2C [=y] && OF [=y] Selected by [y]: - PINCTRL_STMFX [=y] && PINCTRL [=y] && I2C [=y] && OF_GPIO [=y] Fixes: 1490d9f841b1 ("pinctrl: Add STMFX GPIO expander Pinctrl/GPIO driver") Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/20250815022721.1650885-1-rdunlap@infradead.org Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ddd11668457ced..be1ca8e85754bc 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -539,6 +539,7 @@ config PINCTRL_STMFX tristate "STMicroelectronics STMFX GPIO expander pinctrl driver" depends on I2C depends on OF_GPIO + depends on HAS_IOMEM select GENERIC_PINCONF select GPIOLIB_IRQCHIP select MFD_STMFX From 685ca577b408ffd9c5a4057a2acc0cd3e6978b36 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Thu, 31 Jul 2025 20:01:27 -0700 Subject: [PATCH 0520/1292] iommu/arm-smmu-v3: Fix smmu_domain->nr_ats_masters decrement The arm_smmu_attach_commit() updates master->ats_enabled before calling arm_smmu_remove_master_domain() that is supposed to clean up everything in the old domain, including the old domain's nr_ats_masters. So, it is supposed to use the old ats_enabled state of the device, not an updated state. This isn't a problem if switching between two domains where: - old ats_enabled = false; new ats_enabled = false - old ats_enabled = true; new ats_enabled = true but can fail cases where: - old ats_enabled = false; new ats_enabled = true (old domain should keep the counter but incorrectly decreased it) - old ats_enabled = true; new ats_enabled = false (old domain needed to decrease the counter but incorrectly missed it) Update master->ats_enabled after arm_smmu_remove_master_domain() to fix this. Fixes: 7497f4211f4f ("iommu/arm-smmu-v3: Make changing domains be hitless for ATS") Cc: stable@vger.kernel.org Signed-off-by: Nicolin Chen Acked-by: Will Deacon Reviewed-by: Jason Gunthorpe Reviewed-by: Pranjal Shrivastava Link: https://lore.kernel.org/r/20250801030127.2006979-1-nicolinc@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 5968043ac80235..2a8b46b948f050 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2997,9 +2997,9 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state) /* ATS is being switched off, invalidate the entire ATC */ arm_smmu_atc_inv_master(master, IOMMU_NO_PASID); } - master->ats_enabled = state->ats_enabled; arm_smmu_remove_master_domain(master, state->old_domain, state->ssid); + master->ats_enabled = state->ats_enabled; } static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) From 72b6f7cd89cea8251979b65528d302f9c0ed37bf Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 14 Aug 2025 17:47:16 +0100 Subject: [PATCH 0521/1292] iommu/virtio: Make instance lookup robust Much like arm-smmu in commit 7d835134d4e1 ("iommu/arm-smmu: Make instance lookup robust"), virtio-iommu appears to have the same issue where iommu_device_register() makes the IOMMU instance visible to other API callers (including itself) straight away, but internally the instance isn't ready to recognise itself for viommu_probe_device() to work correctly until after viommu_probe() has returned. This matters a lot more now that bus_iommu_probe() has the DT/VIOT knowledge to probe client devices the way that was always intended. Tweak the lookup and initialisation in much the same way as for arm-smmu, to ensure that what we register is functional and ready to go. Cc: stable@vger.kernel.org Fixes: bcb81ac6ae3c ("iommu: Get DT/ACPI parsing into the proper probe path") Signed-off-by: Robin Murphy Tested-by: Eric Auger Link: https://lore.kernel.org/r/308911aaa1f5be32a3a709996c7bd6cf71d30f33.1755190036.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/virtio-iommu.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c index 532db1de201bae..b39d6f134ab28f 100644 --- a/drivers/iommu/virtio-iommu.c +++ b/drivers/iommu/virtio-iommu.c @@ -998,8 +998,7 @@ static void viommu_get_resv_regions(struct device *dev, struct list_head *head) iommu_dma_get_resv_regions(dev, head); } -static const struct iommu_ops viommu_ops; -static struct virtio_driver virtio_iommu_drv; +static const struct bus_type *virtio_bus_type; static int viommu_match_node(struct device *dev, const void *data) { @@ -1008,8 +1007,9 @@ static int viommu_match_node(struct device *dev, const void *data) static struct viommu_dev *viommu_get_by_fwnode(struct fwnode_handle *fwnode) { - struct device *dev = driver_find_device(&virtio_iommu_drv.driver, NULL, - fwnode, viommu_match_node); + struct device *dev = bus_find_device(virtio_bus_type, NULL, fwnode, + viommu_match_node); + put_device(dev); return dev ? dev_to_virtio(dev)->priv : NULL; @@ -1160,6 +1160,9 @@ static int viommu_probe(struct virtio_device *vdev) if (!viommu) return -ENOMEM; + /* Borrow this for easy lookups later */ + virtio_bus_type = dev->bus; + spin_lock_init(&viommu->request_lock); ida_init(&viommu->domain_ids); viommu->dev = dev; @@ -1229,10 +1232,10 @@ static int viommu_probe(struct virtio_device *vdev) if (ret) goto err_free_vqs; - iommu_device_register(&viommu->iommu, &viommu_ops, parent_dev); - vdev->priv = viommu; + iommu_device_register(&viommu->iommu, &viommu_ops, parent_dev); + dev_info(dev, "input address: %u bits\n", order_base_2(viommu->geometry.aperture_end)); dev_info(dev, "page mask: %#llx\n", viommu->pgsize_bitmap); From 99d4d1a070870aa08163af8ce0522992b7f35d8c Mon Sep 17 00:00:00 2001 From: XianLiang Huang Date: Wed, 20 Aug 2025 15:22:48 +0800 Subject: [PATCH 0522/1292] iommu/riscv: prevent NULL deref in iova_to_phys The riscv_iommu_pte_fetch() function returns either NULL for unmapped/never-mapped iova, or a valid leaf pte pointer that requires no further validation. riscv_iommu_iova_to_phys() failed to handle NULL returns. Prevent null pointer dereference in riscv_iommu_iova_to_phys(), and remove the pte validation. Fixes: 488ffbf18171 ("iommu/riscv: Paging domain support") Cc: Tomasz Jeznach Signed-off-by: XianLiang Huang Link: https://lore.kernel.org/r/20250820072248.312-1-huangxianliang@lanxincomputing.com Signed-off-by: Joerg Roedel --- drivers/iommu/riscv/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c index 2d0d31ba28860a..0eae2f4bdc5e64 100644 --- a/drivers/iommu/riscv/iommu.c +++ b/drivers/iommu/riscv/iommu.c @@ -1283,7 +1283,7 @@ static phys_addr_t riscv_iommu_iova_to_phys(struct iommu_domain *iommu_domain, unsigned long *ptr; ptr = riscv_iommu_pte_fetch(domain, iova, &pte_size); - if (_io_pte_none(*ptr) || !_io_pte_present(*ptr)) + if (!ptr) return 0; return pfn_to_phys(__page_val_to_pfn(*ptr)) | (iova & (pte_size - 1)); From f8d63d7e60e8912b5ded72319c305765b0a6322f Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Mon, 18 Aug 2025 14:26:30 -0500 Subject: [PATCH 0523/1292] cpufreq: ti: Support more speed grades on AM62Px SoC As the AM62Px SoC family matures more speed grades are being defined. Add support for speed grades U and T which both support all currently established OPPs. Signed-off-by: Judith Mendez Signed-off-by: Viresh Kumar --- drivers/cpufreq/ti-cpufreq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 9a912d30931539..d6bd0d2dcf156c 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -72,7 +72,9 @@ enum { #define AM62P5_EFUSE_O_MPU_OPP 15 #define AM62P5_EFUSE_S_MPU_OPP 19 +#define AM62P5_EFUSE_T_MPU_OPP 20 #define AM62P5_EFUSE_U_MPU_OPP 21 +#define AM62P5_EFUSE_V_MPU_OPP 22 #define AM62P5_SUPPORT_O_MPU_OPP BIT(0) #define AM62P5_SUPPORT_U_MPU_OPP BIT(2) @@ -153,7 +155,9 @@ static unsigned long am62p5_efuse_xlate(struct ti_cpufreq_data *opp_data, unsigned long calculated_efuse = AM62P5_SUPPORT_O_MPU_OPP; switch (efuse) { + case AM62P5_EFUSE_V_MPU_OPP: case AM62P5_EFUSE_U_MPU_OPP: + case AM62P5_EFUSE_T_MPU_OPP: case AM62P5_EFUSE_S_MPU_OPP: calculated_efuse |= AM62P5_SUPPORT_U_MPU_OPP; fallthrough; From 37f846830b510121c5364ba7bd23e3d77a83ff9b Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Mon, 18 Aug 2025 14:26:31 -0500 Subject: [PATCH 0524/1292] cpufreq: ti: Allow all silicon revisions to support OPPs More silicon revisions are being defined for AM62x, AM62Px, and AM62ax SoCs. These silicon may also support currently establishes OPPs, so remove the revision limitation in ti-cpufreq and thus determine if an OPP applies with speed grade efuse parsing. Signed-off-by: Judith Mendez Signed-off-by: Viresh Kumar --- drivers/cpufreq/ti-cpufreq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index d6bd0d2dcf156c..6ee76f5fe9c567 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -311,10 +311,10 @@ static struct ti_cpufreq_soc_data am3517_soc_data = { }; static const struct soc_device_attribute k3_cpufreq_soc[] = { - { .family = "AM62X", .revision = "SR1.0" }, - { .family = "AM62AX", .revision = "SR1.0" }, - { .family = "AM62PX", .revision = "SR1.0" }, - { .family = "AM62DX", .revision = "SR1.0" }, + { .family = "AM62X", }, + { .family = "AM62AX", }, + { .family = "AM62PX", }, + { .family = "AM62DX", }, { /* sentinel */ } }; From f434ec2200667d5362bd19f93a498d9b3f121588 Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Mon, 18 Aug 2025 14:26:32 -0500 Subject: [PATCH 0525/1292] arm64: dts: ti: k3-am62p: Fix supported hardware for 1GHz OPP The 1GHz OPP is supported on speed grade "O" as well according to the device datasheet [0], so fix the opp-supported-hw property to support this speed grade for 1GHz OPP. [0] https://www.ti.com/lit/gpn/am62p Fixes: 76d855f05801 ("arm64: dts: ti: k3-am62p: add opp frequencies") Cc: stable@vger.kernel.org Signed-off-by: Judith Mendez Signed-off-by: Viresh Kumar --- arch/arm64/boot/dts/ti/k3-am62p5.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/ti/k3-am62p5.dtsi b/arch/arm64/boot/dts/ti/k3-am62p5.dtsi index 202378d9d5cfdc..8982a7b9f1a6a1 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p5.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62p5.dtsi @@ -135,7 +135,7 @@ opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; - opp-supported-hw = <0x01 0x0006>; + opp-supported-hw = <0x01 0x0007>; clock-latency-ns = <6000000>; }; From 5245dc5ff9b1f6c02ef948f623432805ea148fca Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Thu, 31 Jul 2025 11:16:52 +0200 Subject: [PATCH 0526/1292] arm64: dts: imx8mp-tqma8mpql: fix LDO5 power off Fix SD card removal caused by automatic LDO5 power off after boot: LDO5: disabling mmc1: card 59b4 removed EXT4-fs (mmcblk1p2): shut down requested (2) Aborting journal on device mmcblk1p2-8. JBD2: I/O error when updating journal superblock for mmcblk1p2-8. To prevent this, add vqmmc regulator for USDHC, using a GPIO-controlled regulator that is supplied by LDO5. Since this is implemented on SoM but used on baseboards with SD-card interface, implement the functionality on SoM part and optionally enable it on baseboards if needed. Fixes: 418d1d840e42 ("arm64: dts: freescale: add initial device tree for TQMa8MPQL with i.MX8MP") Signed-off-by: Markus Niebel Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- .../imx8mp-tqma8mpql-mba8mp-ras314.dts | 13 ++++++----- .../freescale/imx8mp-tqma8mpql-mba8mpxl.dts | 13 ++++++----- .../boot/dts/freescale/imx8mp-tqma8mpql.dtsi | 22 +++++++++++++++++++ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts index d7fd9d36f8240e..f7346b3d35fe53 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts @@ -467,6 +467,10 @@ status = "okay"; }; +®_usdhc2_vqmmc { + status = "okay"; +}; + &sai5 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai5>; @@ -876,8 +880,7 @@ , , , - , - ; + ; }; pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { @@ -886,8 +889,7 @@ , , , - , - ; + ; }; pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { @@ -896,8 +898,7 @@ , , , - , - ; + ; }; pinctrl_usdhc2_gpio: usdhc2-gpiogrp { diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts index 33cd92e63c5d5f..4eedd00d83b9fc 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts @@ -604,6 +604,10 @@ status = "okay"; }; +®_usdhc2_vqmmc { + status = "okay"; +}; + &sai3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai3>; @@ -983,8 +987,7 @@ , , , - , - ; + ; }; pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { @@ -993,8 +996,7 @@ , , , - , - ; + ; }; pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { @@ -1003,8 +1005,7 @@ , , , - , - ; + ; }; pinctrl_usdhc2_gpio: usdhc2-gpiogrp { diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi index fd70b686e7efc0..b48d5da1472739 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi @@ -24,6 +24,20 @@ regulator-max-microvolt = <3300000>; regulator-always-on; }; + + reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc { + compatible = "regulator-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc2_vqmmc>; + regulator-name = "V_SD2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + states = <1800000 0x1>, + <3300000 0x0>; + vin-supply = <&ldo5_reg>; + status = "disabled"; + }; }; &A53_0 { @@ -184,6 +198,10 @@ }; }; +&usdhc2 { + vqmmc-supply = <®_usdhc2_vqmmc>; +}; + &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc3>; @@ -233,6 +251,10 @@ fsl,pins = ; }; + pinctrl_reg_usdhc2_vqmmc: regusdhc2vqmmcgrp { + fsl,pins = ; + }; + pinctrl_usdhc3: usdhc3grp { fsl,pins = , , From 917baa75e376084240ca1696ab29589006563128 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Thu, 31 Jul 2025 11:16:53 +0200 Subject: [PATCH 0527/1292] arm64: dts: imx8mp-tqma8mpql: remove virtual 3.3V regulator BUCK4 rail supplies the 3.3V rail. Use the actual regulator instead of a virtual fixed regulator. Signed-off-by: Markus Niebel Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- .../boot/dts/freescale/imx8mp-tqma8mpql.dtsi | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi index b48d5da1472739..9716f24f7c6ed7 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi @@ -16,15 +16,6 @@ reg = <0x0 0x40000000 0 0x80000000>; }; - /* identical to buck4_reg, but should never change */ - reg_vcc3v3: regulator-vcc3v3 { - compatible = "regulator-fixed"; - regulator-name = "VCC3V3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc { compatible = "regulator-gpio"; pinctrl-names = "default"; @@ -187,14 +178,14 @@ read-only; reg = <0x53>; pagesize = <16>; - vcc-supply = <®_vcc3v3>; + vcc-supply = <&buck4_reg>; }; m24c64: eeprom@57 { compatible = "atmel,24c64"; reg = <0x57>; pagesize = <32>; - vcc-supply = <®_vcc3v3>; + vcc-supply = <&buck4_reg>; }; }; @@ -211,7 +202,7 @@ non-removable; no-sd; no-sdio; - vmmc-supply = <®_vcc3v3>; + vmmc-supply = <&buck4_reg>; vqmmc-supply = <&buck5_reg>; status = "okay"; }; From c53cf8ce3bfe1309cb4fd4d74c5be27c26a86e52 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 10 Aug 2025 18:03:07 +0200 Subject: [PATCH 0528/1292] arm64: dts: imx8mp: Fix missing microSD slot vqmmc on DH electronics i.MX8M Plus DHCOM Add missing microSD slot vqmmc-supply property, otherwise the kernel might shut down LDO5 regulator and that would power off the microSD card slot, possibly while it is in use. Add the property to make sure the kernel is aware of the LDO5 regulator which supplies the microSD slot and keeps the LDO5 enabled. Fixes: 8d6712695bc8 ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2") Signed-off-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi index 7f754e0a5d693f..68c2e0156a5c81 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi @@ -609,6 +609,7 @@ pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; vmmc-supply = <®_usdhc2_vmmc>; + vqmmc-supply = <&ldo5>; bus-width = <4>; status = "okay"; }; From 80733306290f6d2e05f0632e5d3e98cd16105c3c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 10 Aug 2025 18:04:32 +0200 Subject: [PATCH 0529/1292] arm64: dts: imx8mp: Fix missing microSD slot vqmmc on Data Modul i.MX8M Plus eDM SBC Add missing microSD slot vqmmc-supply property, otherwise the kernel might shut down LDO5 regulator and that would power off the microSD card slot, possibly while it is in use. Add the property to make sure the kernel is aware of the LDO5 regulator which supplies the microSD slot and keeps the LDO5 enabled. Fixes: 562d222f23f0 ("arm64: dts: imx8mp: Add support for Data Modul i.MX8M Plus eDM SBC") Signed-off-by: Marek Vasut Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts index d0fc5977258fbf..16078ff60ef08b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts @@ -555,6 +555,7 @@ pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; vmmc-supply = <®_usdhc2_vmmc>; + vqmmc-supply = <&ldo5>; bus-width = <4>; status = "okay"; }; From e35318d8d2d2dccc50454e3fc0bd9caaf2a797cd Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 19 Aug 2025 10:43:37 +0800 Subject: [PATCH 0530/1292] arm64: dts: imx95-19x19-evk: correct the phy setting for flexcan1/2 1, the phy support up to 8Mbit/s databitrate for CAN FD. refer to product data sheet: https://www.nxp.com/docs/en/data-sheet/TJA1463.pdf 2, the standby pin of the phy is ACTIVE_LOW. 3, the phy of flexcan2 connect the standby/en pin to PCAL6408 on i2c4 bus. Fixes: 02b7adb791e1 ("arm64: dts: imx95-19x19-evk: add adc0 flexcan[1,2] i2c[2,3] uart5 spi3 and tpm3") Signed-off-by: Haibo Chen Reviewed-by: Frank Li Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts index 2f949a0d48d2d8..9d034275c84760 100644 --- a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts @@ -80,17 +80,17 @@ flexcan1_phy: can-phy0 { compatible = "nxp,tjr1443"; #phy-cells = <0>; - max-bitrate = <1000000>; + max-bitrate = <8000000>; enable-gpios = <&i2c6_pcal6416 6 GPIO_ACTIVE_HIGH>; - standby-gpios = <&i2c6_pcal6416 5 GPIO_ACTIVE_HIGH>; + standby-gpios = <&i2c6_pcal6416 5 GPIO_ACTIVE_LOW>; }; flexcan2_phy: can-phy1 { compatible = "nxp,tjr1443"; #phy-cells = <0>; - max-bitrate = <1000000>; - enable-gpios = <&i2c6_pcal6416 4 GPIO_ACTIVE_HIGH>; - standby-gpios = <&i2c6_pcal6416 3 GPIO_ACTIVE_HIGH>; + max-bitrate = <8000000>; + enable-gpios = <&i2c4_gpio_expander_21 4 GPIO_ACTIVE_HIGH>; + standby-gpios = <&i2c4_gpio_expander_21 3 GPIO_ACTIVE_LOW>; }; reg_vref_1v8: regulator-1p8v { From 37e5caa5571b5a60b0c835a0bc09ab1e53f57bfe Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 20 Aug 2025 18:27:26 +0200 Subject: [PATCH 0531/1292] arm64: dts: imx95: Fix JPEG encoder node assigned clock The assigned clock for JPEG encoder IP has to be IMX95_CLK_VPUBLK_JPEG_ENC and not IMX95_CLK_VPUBLK_JPEG_DEC (_ENC at the end, not _DEC). This is a simple copy-paste error, fix it. Fixes: 153c039a7357 ("arm64: dts: imx95: add jpeg encode and decode nodes") Signed-off-by: Marek Vasut Reviewed-by: Laurent Pinchart Reviewed-by: Frank Li Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx95.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi index 4ca6a7ea586eaa..8296888bce5947 100644 --- a/arch/arm64/boot/dts/freescale/imx95.dtsi +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi @@ -1843,7 +1843,7 @@ ; clocks = <&scmi_clk IMX95_CLK_VPU>, <&vpu_blk_ctrl IMX95_CLK_VPUBLK_JPEG_ENC>; - assigned-clocks = <&vpu_blk_ctrl IMX95_CLK_VPUBLK_JPEG_DEC>; + assigned-clocks = <&vpu_blk_ctrl IMX95_CLK_VPUBLK_JPEG_ENC>; assigned-clock-parents = <&scmi_clk IMX95_CLK_VPUJPEG>; power-domains = <&scmi_devpd IMX95_PD_VPU>; }; From 08fb45446ebf1e2e435f95163c59d692acb0b514 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 21 Aug 2025 08:40:12 +0200 Subject: [PATCH 0532/1292] drm/amdgpu: Pin buffers while vmap'ing exported dma-buf objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current dma-buf vmap semantics require that the mapped buffer remains in place until the corresponding vunmap has completed. For GEM-SHMEM, this used to be guaranteed by a pin operation while creating an S/G table in import. GEM-SHMEN can now import dma-buf objects without creating the S/G table, so the pin is missing. Leads to page-fault errors, such as the one shown below. [ 102.101726] BUG: unable to handle page fault for address: ffffc90127000000 [...] [ 102.157102] RIP: 0010:udl_compress_hline16+0x219/0x940 [udl] [...] [ 102.243250] Call Trace: [ 102.245695] [ 102.2477V95] ? validate_chain+0x24e/0x5e0 [ 102.251805] ? __lock_acquire+0x568/0xae0 [ 102.255807] udl_render_hline+0x165/0x341 [udl] [ 102.260338] ? __pfx_udl_render_hline+0x10/0x10 [udl] [ 102.265379] ? local_clock_noinstr+0xb/0x100 [ 102.269642] ? __lock_release.isra.0+0x16c/0x2e0 [ 102.274246] ? mark_held_locks+0x40/0x70 [ 102.278177] udl_primary_plane_helper_atomic_update+0x43e/0x680 [udl] [ 102.284606] ? __pfx_udl_primary_plane_helper_atomic_update+0x10/0x10 [udl] [ 102.291551] ? lockdep_hardirqs_on_prepare.part.0+0x92/0x170 [ 102.297208] ? lockdep_hardirqs_on+0x88/0x130 [ 102.301554] ? _raw_spin_unlock_irq+0x24/0x50 [ 102.305901] ? wait_for_completion_timeout+0x2bb/0x3a0 [ 102.311028] ? drm_atomic_helper_calc_timestamping_constants+0x141/0x200 [ 102.317714] ? drm_atomic_helper_commit_planes+0x3b6/0x1030 [ 102.323279] drm_atomic_helper_commit_planes+0x3b6/0x1030 [ 102.328664] drm_atomic_helper_commit_tail+0x41/0xb0 [ 102.333622] commit_tail+0x204/0x330 [...] [ 102.529946] ---[ end trace 0000000000000000 ]--- [ 102.651980] RIP: 0010:udl_compress_hline16+0x219/0x940 [udl] In this stack strace, udl (based on GEM-SHMEM) imported and vmap'ed a dma-buf from amdgpu. Amdgpu relocated the buffer, thereby invalidating the mapping. Provide a custom dma-buf vmap method in amdgpu that pins the object before mapping it's buffer's pages into kernel address space. Do the opposite in vunmap. Note that dma-buf vmap differs from GEM vmap in how it handles relocation. While dma-buf vmap keeps the buffer in place, GEM vmap requires the caller to keep the buffer in place. Hence, this fix is in amdgpu's dma-buf code instead of its GEM code. A discussion of various approaches to solving the problem is available at [1]. v3: - try (GTT | VRAM); drop CPU domain (Christian) v2: - only use mapable domains (Christian) - try pinning to domains in preferred order Signed-off-by: Thomas Zimmermann Fixes: 660cd44659a0 ("drm/shmem-helper: Import dmabuf without mapping its sg_table") Reported-by: Thomas Zimmermann Closes: https://lore.kernel.org/dri-devel/ba1bdfb8-dbf7-4372-bdcb-df7e0511c702@suse.de/ Cc: Shixiong Ou Cc: Thomas Zimmermann Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: David Airlie Cc: Simona Vetter Cc: Sumit Semwal Cc: "Christian Kƶnig" Cc: dri-devel@lists.freedesktop.org Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://lore.kernel.org/dri-devel/9792c6c3-a2b8-4b2b-b5ba-fba19b153e21@suse.de/ # [1] Reviewed-by: Christian Kƶnig Link: https://lore.kernel.org/r/20250821064031.39090-1-tzimmermann@suse.de --- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 34 +++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index 5743ebb2f1b7cf..ce27cb5bb05e54 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -285,6 +285,36 @@ static int amdgpu_dma_buf_begin_cpu_access(struct dma_buf *dma_buf, return ret; } +static int amdgpu_dma_buf_vmap(struct dma_buf *dma_buf, struct iosys_map *map) +{ + struct drm_gem_object *obj = dma_buf->priv; + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + int ret; + + /* + * Pin to keep buffer in place while it's vmap'ed. The actual + * domain is not that important as long as it's mapable. Using + * GTT and VRAM should be compatible with most use cases. + */ + ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT | AMDGPU_GEM_DOMAIN_VRAM); + if (ret) + return ret; + ret = drm_gem_dmabuf_vmap(dma_buf, map); + if (ret) + amdgpu_bo_unpin(bo); + + return ret; +} + +static void amdgpu_dma_buf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map) +{ + struct drm_gem_object *obj = dma_buf->priv; + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + + drm_gem_dmabuf_vunmap(dma_buf, map); + amdgpu_bo_unpin(bo); +} + const struct dma_buf_ops amdgpu_dmabuf_ops = { .attach = amdgpu_dma_buf_attach, .pin = amdgpu_dma_buf_pin, @@ -294,8 +324,8 @@ const struct dma_buf_ops amdgpu_dmabuf_ops = { .release = drm_gem_dmabuf_release, .begin_cpu_access = amdgpu_dma_buf_begin_cpu_access, .mmap = drm_gem_dmabuf_mmap, - .vmap = drm_gem_dmabuf_vmap, - .vunmap = drm_gem_dmabuf_vunmap, + .vmap = amdgpu_dma_buf_vmap, + .vunmap = amdgpu_dma_buf_vunmap, }; /** From 563fcd6475931c5c8c652a4dd548256314cc87ed Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 22 Aug 2025 14:14:18 +0200 Subject: [PATCH 0533/1292] pinctrl: airoha: Fix return value in pinconf callbacks Pinctrl stack requires ENOTSUPP error code if the parameter is not supported by the pinctrl driver. Fix the returned error code in pinconf callbacks if the operation is not supported. Fixes: 1c8ace2d0725 ("pinctrl: airoha: Add support for EN7581 SoC") Signed-off-by: Lorenzo Bianconi Link: https://lore.kernel.org/20250822-airoha-pinconf-err-val-fix-v1-1-87b4f264ced2@kernel.org Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-airoha.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/mediatek/pinctrl-airoha.c b/drivers/pinctrl/mediatek/pinctrl-airoha.c index 5f1ec9e0de213d..1b2f132d76f0af 100644 --- a/drivers/pinctrl/mediatek/pinctrl-airoha.c +++ b/drivers/pinctrl/mediatek/pinctrl-airoha.c @@ -2696,7 +2696,7 @@ static int airoha_pinconf_get(struct pinctrl_dev *pctrl_dev, arg = 1; break; default: - return -EOPNOTSUPP; + return -ENOTSUPP; } *config = pinconf_to_config_packed(param, arg); @@ -2788,7 +2788,7 @@ static int airoha_pinconf_set(struct pinctrl_dev *pctrl_dev, break; } default: - return -EOPNOTSUPP; + return -ENOTSUPP; } } @@ -2805,10 +2805,10 @@ static int airoha_pinconf_group_get(struct pinctrl_dev *pctrl_dev, if (airoha_pinconf_get(pctrl_dev, airoha_pinctrl_groups[group].pins[i], config)) - return -EOPNOTSUPP; + return -ENOTSUPP; if (i && cur_config != *config) - return -EOPNOTSUPP; + return -ENOTSUPP; cur_config = *config; } From 9c6182843b0d02ca04cc1d946954a65a2286c7db Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Fri, 22 Aug 2025 20:58:08 +0800 Subject: [PATCH 0534/1292] ALSA: usb-audio: Add mute TLV for playback volumes on some devices Applying the quirk of that, the lowest Playback mixer volume setting mutes the audio output, on more devices. Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/merge_requests/2514 Cc: Tested-by: Guoli An Signed-off-by: Cryolitia PukNgae Link: https://patch.msgid.link/20250822-mixer-quirk-v1-1-b19252239c1c@uniontech.com Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 7cc27ae5512f07..6b47b3145d2cfd 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -4609,9 +4609,11 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, snd_dragonfly_quirk_db_scale(mixer, cval, kctl); break; /* lowest playback value is muted on some devices */ + case USB_ID(0x0572, 0x1b09): /* Conexant Systems (Rockwell), Inc. */ case USB_ID(0x0d8c, 0x000c): /* C-Media */ case USB_ID(0x0d8c, 0x0014): /* C-Media */ case USB_ID(0x19f7, 0x0003): /* RODE NT-USB */ + case USB_ID(0x2d99, 0x0026): /* HECATE G2 GAMING HEADSET */ if (strstr(kctl->id.name, "Playback")) cval->min_mute = 1; break; From dc88b77113d75a8fd5818355f8e313bec144ea5d Mon Sep 17 00:00:00 2001 From: Brady Norander Date: Wed, 20 Aug 2025 21:47:30 -0400 Subject: [PATCH 0535/1292] ALSA: hda: intel-dsp-config: Select SOF driver on MTL Chromebooks The SOF driver is required for functional audio on MTL Chromebooks Signed-off-by: Brady Norander Link: https://patch.msgid.link/20250821014730.8843-1-bradynorander@gmail.com Signed-off-by: Takashi Iwai --- sound/hda/core/intel-dsp-config.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/hda/core/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c index 3cb1e7fc3b3b00..00f184917623d6 100644 --- a/sound/hda/core/intel-dsp-config.c +++ b/sound/hda/core/intel-dsp-config.c @@ -167,9 +167,9 @@ static const struct config_entry config_table[] = { /* * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake, AlderLake, - * RaptorLake use legacy HDAudio driver except for Google Chromebooks - * and when DMICs are present. Two cases are required since Coreboot - * does not expose NHLT tables. + * RaptorLake, MeteorLake use legacy HDAudio driver except for Google + * Chromebooks and when DMICs are present. Two cases are required since + * Coreboot does not expose NHLT tables. * * When the Chromebook quirk is not present, it's based on information * that no such device exists. When the quirk is present, it could be @@ -516,6 +516,19 @@ static const struct config_entry config_table[] = { /* Meteor Lake */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE) /* Meteorlake-P */ + { + .flags = FLAG_SOF, + .device = PCI_DEVICE_ID_INTEL_HDA_MTL, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_MTL, From 5d7eba62e5eb68347de59b31b347b24f304cf21c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 22 Aug 2025 13:40:18 -0400 Subject: [PATCH 0536/1292] Bluetooth: hci_conn: Make unacked packet handling more robust This attempts to make unacked packet handling more robust by detecting if there are no connections left then restore all buffers of the respective pool. Fixes: 5638d9ea9c01 ("Bluetooth: hci_conn: Fix not restoring ISO buffer count on disconnect") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 58 ++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7a879290dd28d5..e524bb59bff234 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -149,8 +149,6 @@ static void hci_conn_cleanup(struct hci_conn *conn) hci_chan_list_flush(conn); - hci_conn_hash_del(hdev, conn); - if (HCI_CONN_HANDLE_UNSET(conn->handle)) ida_free(&hdev->unset_handle_ida, conn->handle); @@ -1152,28 +1150,54 @@ void hci_conn_del(struct hci_conn *conn) disable_delayed_work_sync(&conn->auto_accept_work); disable_delayed_work_sync(&conn->idle_work); - if (conn->type == ACL_LINK) { - /* Unacked frames */ - hdev->acl_cnt += conn->sent; - } else if (conn->type == LE_LINK) { - cancel_delayed_work(&conn->le_conn_timeout); + /* Remove the connection from the list so unacked logic can detect when + * a certain pool is not being utilized. + */ + hci_conn_hash_del(hdev, conn); - if (hdev->le_pkts) - hdev->le_cnt += conn->sent; + /* Handle unacked frames: + * + * - In case there are no connection, or if restoring the buffers + * considered in transist would overflow, restore all buffers to the + * pool. + * - Otherwise restore just the buffers considered in transit for the + * hci_conn + */ + switch (conn->type) { + case ACL_LINK: + if (!hci_conn_num(hdev, ACL_LINK) || + hdev->acl_cnt + conn->sent > hdev->acl_pkts) + hdev->acl_cnt = hdev->acl_pkts; else hdev->acl_cnt += conn->sent; - } else { - /* Unacked ISO frames */ - if (conn->type == CIS_LINK || - conn->type == BIS_LINK || - conn->type == PA_LINK) { - if (hdev->iso_pkts) - hdev->iso_cnt += conn->sent; - else if (hdev->le_pkts) + break; + case LE_LINK: + cancel_delayed_work(&conn->le_conn_timeout); + + if (hdev->le_pkts) { + if (!hci_conn_num(hdev, LE_LINK) || + hdev->le_cnt + conn->sent > hdev->le_pkts) + hdev->le_cnt = hdev->le_pkts; + else hdev->le_cnt += conn->sent; + } else { + if ((!hci_conn_num(hdev, LE_LINK) && + !hci_conn_num(hdev, ACL_LINK)) || + hdev->acl_cnt + conn->sent > hdev->acl_pkts) + hdev->acl_cnt = hdev->acl_pkts; else hdev->acl_cnt += conn->sent; } + break; + case CIS_LINK: + case BIS_LINK: + case PA_LINK: + if (!hci_iso_count(hdev) || + hdev->iso_cnt + conn->sent > hdev->iso_pkts) + hdev->iso_cnt = hdev->iso_pkts; + else + hdev->iso_cnt += conn->sent; + break; } skb_queue_purge(&conn->data_q); From 2f050a5392b7a0928bf836d9891df4851463512c Mon Sep 17 00:00:00 2001 From: Ludovico de Nittis Date: Tue, 12 Aug 2025 17:55:26 +0200 Subject: [PATCH 0537/1292] Bluetooth: hci_event: Treat UNKNOWN_CONN_ID on disconnect as success When the host sends an HCI_OP_DISCONNECT command, the controller may respond with the status HCI_ERROR_UNKNOWN_CONN_ID (0x02). E.g. this can happen on resume from suspend, if the link was terminated by the remote device before the event mask was correctly set. This is a btmon snippet that shows the issue: ``` > ACL Data RX: Handle 3 flags 0x02 dlen 12 L2CAP: Disconnection Request (0x06) ident 5 len 4 Destination CID: 65 Source CID: 72 < ACL Data TX: Handle 3 flags 0x00 dlen 12 L2CAP: Disconnection Response (0x07) ident 5 len 4 Destination CID: 65 Source CID: 72 > ACL Data RX: Handle 3 flags 0x02 dlen 12 L2CAP: Disconnection Request (0x06) ident 6 len 4 Destination CID: 64 Source CID: 71 < ACL Data TX: Handle 3 flags 0x00 dlen 12 L2CAP: Disconnection Response (0x07) ident 6 len 4 Destination CID: 64 Source CID: 71 < HCI Command: Set Event Mask (0x03|0x0001) plen 8 Mask: 0x3dbff807fffbffff Inquiry Complete Inquiry Result Connection Complete Connection Request Disconnection Complete Authentication Complete [...] < HCI Command: Disconnect (0x01|0x0006) plen 3 Handle: 3 Address: 78:20:A5:4A:DF:28 (Nintendo Co.,Ltd) Reason: Remote User Terminated Connection (0x13) > HCI Event: Command Status (0x0f) plen 4 Disconnect (0x01|0x0006) ncmd 1 Status: Unknown Connection Identifier (0x02) ``` Currently, the hci_cs_disconnect function treats any non-zero status as a command failure. This can be misleading because the connection is indeed being terminated and the controller is confirming that is has no knowledge of that connection handle. Meaning that the initial request of disconnecting a device should be treated as done. With this change we allow the function to proceed, following the success path, which correctly calls `mgmt_device_disconnected` and ensures a consistent state. Link: https://github.com/bluez/bluez/issues/1226 Fixes: 182ee45da083 ("Bluetooth: hci_sync: Rework hci_suspend_notifier") Signed-off-by: Ludovico de Nittis Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fe7cdd67ad2a20..6c67dfa139e26e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2703,7 +2703,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) if (!conn) goto unlock; - if (status) { + if (status && status != HCI_ERROR_UNKNOWN_CONN_ID) { mgmt_disconnect_failed(hdev, &conn->dst, conn->type, conn->dst_type, status); From b7fafbc499b5ee164018eb0eefe9027f5a6aaad2 Mon Sep 17 00:00:00 2001 From: Ludovico de Nittis Date: Tue, 12 Aug 2025 17:55:27 +0200 Subject: [PATCH 0538/1292] Bluetooth: hci_event: Mark connection as closed during suspend disconnect When suspending, the disconnect command for an active Bluetooth connection could be issued, but the corresponding `HCI_EV_DISCONN_COMPLETE` event might not be received before the system completes the suspend process. This can lead to an inconsistent state. On resume, the controller may auto-accept reconnections from the same device (due to suspend event filters), but these new connections are rejected by the kernel which still has connection objects from before suspend. Resulting in errors like: ``` kernel: Bluetooth: hci0: ACL packet for unknown connection handle 1 kernel: Bluetooth: hci0: Ignoring HCI_Connection_Complete for existing connection ``` This is a btmon snippet that shows the issue: ``` < HCI Command: Disconnect (0x01|0x0006) plen 3 Handle: 1 Address: 78:20:A5:4A:DF:28 (Nintendo Co.,Ltd) Reason: Remote User Terminated Connection (0x13) > HCI Event: Command Status (0x0f) plen 4 Disconnect (0x01|0x0006) ncmd 2 Status: Success (0x00) [...] // Host suspends with the event filter set for the device // On resume, the device tries to reconnect with a new handle > HCI Event: Connect Complete (0x03) plen 11 Status: Success (0x00) Handle: 2 Address: 78:20:A5:4A:DF:28 (Nintendo Co.,Ltd) // Kernel ignores this event because there is an existing connection with // handle 1 ``` By explicitly setting the connection state to BT_CLOSED we can ensure a consistent state, even if we don't receive the disconnect complete event in time. Link: https://github.com/bluez/bluez/issues/1226 Fixes: 182ee45da083 ("Bluetooth: hci_sync: Rework hci_suspend_notifier") Signed-off-by: Ludovico de Nittis Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6c67dfa139e26e..ce0ff06f2f731a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2718,6 +2718,12 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) goto done; } + /* During suspend, mark connection as closed immediately + * since we might not receive HCI_EV_DISCONN_COMPLETE + */ + if (hdev->suspended) + conn->state = BT_CLOSED; + mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); if (conn->type == ACL_LINK) { From 15bf2c6391bafb14a3020d06ec0761bce0803463 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 20 Aug 2025 17:04:00 -0400 Subject: [PATCH 0539/1292] Bluetooth: hci_event: Detect if HCI_EV_NUM_COMP_PKTS is unbalanced This attempts to detect if HCI_EV_NUM_COMP_PKTS contain an unbalanced (more than currently considered outstanding) number of packets otherwise it could cause the hcon->sent to underflow and loop around breaking the tracking of the outstanding packets pending acknowledgment. Fixes: f42809185896 ("Bluetooth: Simplify num_comp_pkts_evt function") Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ce0ff06f2f731a..904bcff4f4cac5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4404,7 +4404,17 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, if (!conn) continue; - conn->sent -= count; + /* Check if there is really enough packets outstanding before + * attempting to decrease the sent counter otherwise it could + * underflow.. + */ + if (conn->sent >= count) { + conn->sent -= count; + } else { + bt_dev_warn(hdev, "hcon %p sent %u < count %u", + conn, conn->sent, count); + conn->sent = 0; + } for (i = 0; i < count; ++i) hci_conn_tx_dequeue(conn); From 55b9551fcdf6a2fe7f3422918d5697b56794da72 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 20 Aug 2025 10:16:17 +0800 Subject: [PATCH 0540/1292] Bluetooth: hci_event: Disconnect device when BIG sync is lost When a BIG sync is lost, the device should be set to "disconnected". This ensures symmetry with the ISO path setup, where the device is marked as "connected" once the path is established. Without this change, the device state remains inconsistent and may lead to a memory leak. Fixes: b2a5f2e1c127 ("Bluetooth: hci_event: Add support for handling LE BIG Sync Lost event") Signed-off-by: Yang Li Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 5 +++++ net/bluetooth/mgmt.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 904bcff4f4cac5..7a217485185741 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -7024,6 +7024,7 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data, { struct hci_evt_le_big_sync_lost *ev = data; struct hci_conn *bis, *conn; + bool mgmt_conn; bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle); @@ -7042,6 +7043,10 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data, while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle, BT_CONNECTED, HCI_ROLE_SLAVE))) { + mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &bis->flags); + mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type, + ev->reason, mgmt_conn); + clear_bit(HCI_CONN_BIG_SYNC, &bis->flags); hci_disconn_cfm(bis, ev->reason); hci_conn_del(bis); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3166f5fb876b11..90e37ff2c85db2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -9705,7 +9705,9 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!mgmt_connected) return; - if (link_type != ACL_LINK && link_type != LE_LINK) + if (link_type != ACL_LINK && + link_type != LE_LINK && + link_type != BIS_LINK) return; bacpy(&ev.addr.bdaddr, bdaddr); From 6bbd0d3f0c23fc53c17409dd7476f38ae0ff0cd9 Mon Sep 17 00:00:00 2001 From: Pavel Shpakovskiy Date: Fri, 22 Aug 2025 12:20:55 +0300 Subject: [PATCH 0541/1292] Bluetooth: hci_sync: fix set_local_name race condition Function set_name_sync() uses hdev->dev_name field to send HCI_OP_WRITE_LOCAL_NAME command, but copying from data to hdev->dev_name is called after mgmt cmd was queued, so it is possible that function set_name_sync() will read old name value. This change adds name as a parameter for function hci_update_name_sync() to avoid race condition. Fixes: 6f6ff38a1e14 ("Bluetooth: hci_sync: Convert MGMT_OP_SET_LOCAL_NAME") Signed-off-by: Pavel Shpakovskiy Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_sync.h | 2 +- net/bluetooth/hci_sync.c | 6 +++--- net/bluetooth/mgmt.c | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 5224f57f6af2c4..e352a4e0ef8d76 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -93,7 +93,7 @@ int hci_update_class_sync(struct hci_dev *hdev); int hci_update_eir_sync(struct hci_dev *hdev); int hci_update_class_sync(struct hci_dev *hdev); -int hci_update_name_sync(struct hci_dev *hdev); +int hci_update_name_sync(struct hci_dev *hdev, const u8 *name); int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode); int hci_get_random_address(struct hci_dev *hdev, bool require_privacy, diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 31d72b9683ef52..b6f888d8354e3f 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -3481,13 +3481,13 @@ int hci_update_scan_sync(struct hci_dev *hdev) return hci_write_scan_enable_sync(hdev, scan); } -int hci_update_name_sync(struct hci_dev *hdev) +int hci_update_name_sync(struct hci_dev *hdev, const u8 *name) { struct hci_cp_write_local_name cp; memset(&cp, 0, sizeof(cp)); - memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); + memcpy(cp.name, name, sizeof(cp.name)); return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp, @@ -3540,7 +3540,7 @@ int hci_powered_update_sync(struct hci_dev *hdev) hci_write_fast_connectable_sync(hdev, false); hci_update_scan_sync(hdev); hci_update_class_sync(hdev); - hci_update_name_sync(hdev); + hci_update_name_sync(hdev, hdev->dev_name); hci_update_eir_sync(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 90e37ff2c85db2..50634ef5c8b707 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3892,8 +3892,11 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err) static int set_name_sync(struct hci_dev *hdev, void *data) { + struct mgmt_pending_cmd *cmd = data; + struct mgmt_cp_set_local_name *cp = cmd->param; + if (lmp_bredr_capable(hdev)) { - hci_update_name_sync(hdev); + hci_update_name_sync(hdev, cp->name); hci_update_eir_sync(hdev); } From 11b3de1c03fa9f3b5d17e6d48050bc98b3704420 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Mon, 28 Jul 2025 15:06:11 +0800 Subject: [PATCH 0542/1292] ACPI: processor: idle: Fix memory leak when register cpuidle device failed The cpuidle device's memory is leaked when cpuidle device registration fails in acpi_processor_power_init(). Free it as appropriate. Fixes: 3d339dcbb56d ("cpuidle / ACPI : move cpuidle_device field out of the acpi_processor_power structure") Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250728070612.1260859-2-lihuisong@huawei.com [ rjw: Changed the order of the new statements, added empty line after if () ] [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 2c2dc559e0f8de..d0fc045a8d310c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1405,6 +1405,9 @@ int acpi_processor_power_init(struct acpi_processor *pr) if (retval) { if (acpi_processor_registered == 0) cpuidle_unregister_driver(&acpi_idle_driver); + + per_cpu(acpi_cpuidle_device, pr->id) = NULL; + kfree(dev); return retval; } acpi_processor_registered++; From e9e124501f0d7ea2caea94711efe50fe081a11ea Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Fri, 22 Aug 2025 15:04:23 +0800 Subject: [PATCH 0543/1292] cpufreq: use strlen() for governor name comparison Most kernel code using strncasecmp()/strncmp() passes strlen("xxx") as the length argument. cpufreq_parse_policy() previously used CPUFREQ_NAME_LEN (16), which is longer than the actual strings ("performance" is 11 chars, "powersave" is 9 chars). This patch switches to strlen() for the comparison, making the matching slightly more permissive (e.g., "powersavexxx" will now also match "powersave"). While this is unlikely to cause functional issues, it aligns cpufreq with common kernel style and makes the behavior more intuitive. Signed-off-by: Zihuan Zhang Acked-by: Viresh Kumar Link: https://patch.msgid.link/20250822070424.166795-2-zhangzihuan@kylinos.cn Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b8937737d09676..d337f94f70a388 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -664,10 +664,10 @@ static struct cpufreq_governor *get_governor(const char *str_governor) static unsigned int cpufreq_parse_policy(char *str_governor) { - if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) + if (!strncasecmp(str_governor, "performance", strlen("performance"))) return CPUFREQ_POLICY_PERFORMANCE; - if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) + if (!strncasecmp(str_governor, "powersave", strlen("powersave"))) return CPUFREQ_POLICY_POWERSAVE; return CPUFREQ_POLICY_UNKNOWN; From 1647830388ffea4d7a39c1a5f7692925e9d8351d Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Fri, 22 Aug 2025 15:04:24 +0800 Subject: [PATCH 0544/1292] cpufreq: simplify setpolicy/target check in driver verification cpufreq drivers are supposed to use either ->setpolicy() or ->target()/->target_index(). Simplify the existing check by collapsing it into a single boolean expression: (!!driver->setpolicy == (driver->target_index || driver->target)) This is a readability/maintainability cleanup and keeps the semantics unchanged. No functional change intended. Signed-off-by: Zihuan Zhang Acked-by: Viresh Kumar Link: https://patch.msgid.link/20250822070424.166795-3-zhangzihuan@kylinos.cn Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d337f94f70a388..a615c98d80ca01 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2922,10 +2922,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) return -EPROBE_DEFER; if (!driver_data || !driver_data->verify || !driver_data->init || - !(driver_data->setpolicy || driver_data->target_index || - driver_data->target) || - (driver_data->setpolicy && (driver_data->target_index || - driver_data->target)) || + (!!driver_data->setpolicy == (driver_data->target_index || driver_data->target)) || (!driver_data->get_intermediate != !driver_data->target_intermediate) || (!driver_data->online != !driver_data->offline) || (driver_data->adjust_perf && !driver_data->fast_switch)) From 7b28232921782aa38048249132899c337405eaa8 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Sun, 17 Aug 2025 14:49:06 +0200 Subject: [PATCH 0545/1292] mips: dts: lantiq: danube: add missing burst length property The upstream dts lacks the lantiq,{rx/tx}-burst-length property. Other issues were also fixed: arch/mips/boot/dts/lantiq/danube_easy50712.dtb: etop@e180000 (lantiq,etop-xway): 'interrupt-names' is a required property from schema $id: http://devicetree.org/schemas/net/lantiq,etop-xway.yaml# arch/mips/boot/dts/lantiq/danube_easy50712.dtb: etop@e180000 (lantiq,etop-xway): 'lantiq,tx-burst-length' is a required property from schema $id: http://devicetree.org/schemas/net/lantiq,etop-xway.yaml# arch/mips/boot/dts/lantiq/danube_easy50712.dtb: etop@e180000 (lantiq,etop-xway): 'lantiq,rx-burst-length' is a required property from schema $id: http://devicetree.org/schemas/net/lantiq,etop-xway.yaml# Fixes: 14d4e308e0aa ("net: lantiq: configure the burst length in ethernet drivers") Signed-off-by: Aleksander Jan Bajkowski Acked-by: Jakub Kicinski --- arch/mips/boot/dts/lantiq/danube_easy50712.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/boot/dts/lantiq/danube_easy50712.dts b/arch/mips/boot/dts/lantiq/danube_easy50712.dts index 1ce20b7d05cb8c..d8b3cd69eda3c3 100644 --- a/arch/mips/boot/dts/lantiq/danube_easy50712.dts +++ b/arch/mips/boot/dts/lantiq/danube_easy50712.dts @@ -87,8 +87,11 @@ reg = <0xe180000 0x40000>; interrupt-parent = <&icu0>; interrupts = <73 78>; + interrupt-names = "tx", "rx"; phy-mode = "rmii"; mac-address = [ 00 11 22 33 44 55 ]; + lantiq,rx-burst-length = <4>; + lantiq,tx-burst-length = <4>; }; stp0: stp@e100bb0 { From 8c431ea8f3f795c4b9cfa57a85bc4166b9cce0ac Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Sun, 17 Aug 2025 14:49:07 +0200 Subject: [PATCH 0546/1292] mips: lantiq: xway: sysctrl: rename the etop node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bindig requires a node name matching ā€˜^ethernet@[0-9a-f]+$’. This patch changes the clock name from ā€œetopā€ to ā€œethernetā€. This fixes the following warning: arch/mips/boot/dts/lantiq/danube_easy50712.dtb: etop@e180000 (lantiq,etop-xway): $nodename:0: 'etop@e180000' does not match '^ethernet@[0-9a-f]+$' from schema $id: http://devicetree.org/schemas/net/lantiq,etop-xway.yaml# Fixes: dac0bad93741 ("dt-bindings: net: lantiq,etop-xway: Document Lantiq Xway ETOP bindings") Signed-off-by: Aleksander Jan Bajkowski Acked-by: Jakub Kicinski --- arch/mips/boot/dts/lantiq/danube_easy50712.dts | 2 +- arch/mips/lantiq/xway/sysctrl.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/boot/dts/lantiq/danube_easy50712.dts b/arch/mips/boot/dts/lantiq/danube_easy50712.dts index d8b3cd69eda3c3..c4d7aa5753b043 100644 --- a/arch/mips/boot/dts/lantiq/danube_easy50712.dts +++ b/arch/mips/boot/dts/lantiq/danube_easy50712.dts @@ -82,7 +82,7 @@ }; }; - etop@e180000 { + ethernet@e180000 { compatible = "lantiq,etop-xway"; reg = <0xe180000 0x40000>; interrupt-parent = <&icu0>; diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 5a75283d17f10e..6031a0272d8743 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -497,7 +497,7 @@ void __init ltq_soc_init(void) ifccr = CGU_IFCCR_VR9; pcicr = CGU_PCICR_VR9; } else { - clkdev_add_pmu("1e180000.etop", NULL, 1, 0, PMU_PPE); + clkdev_add_pmu("1e180000.ethernet", NULL, 1, 0, PMU_PPE); } if (!of_machine_is_compatible("lantiq,ase")) @@ -531,9 +531,9 @@ void __init ltq_soc_init(void) CLOCK_133M, CLOCK_133M); clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0); clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P); - clkdev_add_pmu("1e180000.etop", "ppe", 1, 0, PMU_PPE); - clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY); - clkdev_add_pmu("1e180000.etop", "ephy", 1, 0, PMU_EPHY); + clkdev_add_pmu("1e180000.ethernet", "ppe", 1, 0, PMU_PPE); + clkdev_add_cgu("1e180000.ethernet", "ephycgu", CGU_EPHY); + clkdev_add_pmu("1e180000.ethernet", "ephy", 1, 0, PMU_EPHY); clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_ASE_SDIO); clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); } else if (of_machine_is_compatible("lantiq,grx390")) { @@ -592,7 +592,7 @@ void __init ltq_soc_init(void) clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM); clkdev_add_pmu("1f203034.usb2-phy", "phy", 1, 0, PMU_USB1_P); clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1 | PMU_AHBM); - clkdev_add_pmu("1e180000.etop", "switch", 1, 0, PMU_SWITCH); + clkdev_add_pmu("1e180000.ethernet", "switch", 1, 0, PMU_SWITCH); clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO); clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); From 80af3745ca465c6c47e833c1902004a7fa944f37 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Aug 2025 11:08:46 +0300 Subject: [PATCH 0547/1292] of: dynamic: Fix use after free in of_changeset_add_prop_helper() If the of_changeset_add_property() function call fails, then this code frees "new_pp" and then dereference it on the next line. Return the error code directly instead. Fixes: c81f6ce16785 ("of: dynamic: Fix memleak when of_pci_add_properties() failed") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/aKgljjhnpa4lVpdx@stanley.mountain Signed-off-by: Rob Herring (Arm) --- drivers/of/dynamic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index dd30b7d8b5e469..2eaaddcb0ec4e2 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -935,13 +935,15 @@ static int of_changeset_add_prop_helper(struct of_changeset *ocs, return -ENOMEM; ret = of_changeset_add_property(ocs, np, new_pp); - if (ret) + if (ret) { __of_prop_free(new_pp); + return ret; + } new_pp->next = np->deadprops; np->deadprops = new_pp; - return ret; + return 0; } /** From e3d01979e4bff5c87eb4054a22e7568bb679b1fe Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Aug 2025 19:55:22 -0400 Subject: [PATCH 0548/1292] fgraph: Copy args in intermediate storage with entry The output of the function graph tracer has two ways to display its entries. One way for leaf functions with no events recorded within them, and the other is for functions with events recorded inside it. As function graph has an entry and exit event, to simplify the output of leaf functions it combines the two, where as non leaf functions are separate: 2) | invoke_rcu_core() { 2) | raise_softirq() { 2) 0.391 us | __raise_softirq_irqoff(); 2) 1.191 us | } 2) 2.086 us | } The __raise_softirq_irqoff() function above is really two events that were merged into one. Otherwise it would have looked like: 2) | invoke_rcu_core() { 2) | raise_softirq() { 2) | __raise_softirq_irqoff() { 2) 0.391 us | } 2) 1.191 us | } 2) 2.086 us | } In order to do this merge, the reading of the trace output file needs to look at the next event before printing. But since the pointer to the event is on the ring buffer, it needs to save the entry event before it looks at the next event as the next event goes out of focus as soon as a new event is read from the ring buffer. After it reads the next event, it will print the entry event with either the '{' (non leaf) or ';' and timestamps (leaf). The iterator used to read the trace file has storage for this event. The problem happens when the function graph tracer has arguments attached to the entry event as the entry now has a variable length "args" field. This field only gets set when funcargs option is used. But the args are not recorded in this temp data and garbage could be printed. The entry field is copied via: data->ent = *curr; Where "curr" is the entry field. But this method only saves the non variable length fields from the structure. Add a helper structure to the iterator data that adds the max args size to the data storage in the iterator. Then simply copy the entire entry into this storage (with size protection). Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Cc: Mark Rutland Link: https://lore.kernel.org/20250820195522.51d4a268@gandalf.local.home Reported-by: Sasha Levin Tested-by: Sasha Levin Closes: https://lore.kernel.org/all/aJaxRVKverIjF4a6@lappy/ Fixes: ff5c9c576e75 ("ftrace: Add support for function argument to graph tracer") Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace_functions_graph.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 66e1a527cf1acd..a7f4b9a47a71a0 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -27,14 +27,21 @@ struct fgraph_cpu_data { unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; }; +struct fgraph_ent_args { + struct ftrace_graph_ent_entry ent; + /* Force the sizeof of args[] to have FTRACE_REGS_MAX_ARGS entries */ + unsigned long args[FTRACE_REGS_MAX_ARGS]; +}; + struct fgraph_data { struct fgraph_cpu_data __percpu *cpu_data; /* Place to preserve last processed entry. */ union { - struct ftrace_graph_ent_entry ent; + struct fgraph_ent_args ent; + /* TODO allow retaddr to have args */ struct fgraph_retaddr_ent_entry rent; - } ent; + }; struct ftrace_graph_ret_entry ret; int failed; int cpu; @@ -627,10 +634,13 @@ get_return_for_leaf(struct trace_iterator *iter, * Save current and next entries for later reference * if the output fails. */ - if (unlikely(curr->ent.type == TRACE_GRAPH_RETADDR_ENT)) - data->ent.rent = *(struct fgraph_retaddr_ent_entry *)curr; - else - data->ent.ent = *curr; + if (unlikely(curr->ent.type == TRACE_GRAPH_RETADDR_ENT)) { + data->rent = *(struct fgraph_retaddr_ent_entry *)curr; + } else { + int size = min((int)sizeof(data->ent), (int)iter->ent_size); + + memcpy(&data->ent, curr, size); + } /* * If the next event is not a return type, then * we only care about what type it is. Otherwise we can From 4013aef2ced9b756a410f50d12df9ebe6a883e4a Mon Sep 17 00:00:00 2001 From: Tengda Wu Date: Fri, 22 Aug 2025 03:33:43 +0000 Subject: [PATCH 0549/1292] ftrace: Fix potential warning in trace_printk_seq during ftrace_dump When calling ftrace_dump_one() concurrently with reading trace_pipe, a WARN_ON_ONCE() in trace_printk_seq() can be triggered due to a race condition. The issue occurs because: CPU0 (ftrace_dump) CPU1 (reader) echo z > /proc/sysrq-trigger !trace_empty(&iter) trace_iterator_reset(&iter) <- len = size = 0 cat /sys/kernel/tracing/trace_pipe trace_find_next_entry_inc(&iter) __find_next_entry ring_buffer_empty_cpu <- all empty return NULL trace_printk_seq(&iter.seq) WARN_ON_ONCE(s->seq.len >= s->seq.size) In the context between trace_empty() and trace_find_next_entry_inc() during ftrace_dump, the ring buffer data was consumed by other readers. This caused trace_find_next_entry_inc to return NULL, failing to populate `iter.seq`. At this point, due to the prior trace_iterator_reset, both `iter.seq.len` and `iter.seq.size` were set to 0. Since they are equal, the WARN_ON_ONCE condition is triggered. Move the trace_printk_seq() into the if block that checks to make sure the return value of trace_find_next_entry_inc() is non-NULL in ftrace_dump_one(), ensuring the 'iter.seq' is properly populated before subsequent operations. Cc: Masami Hiramatsu Cc: Mark Rutland Cc: Mathieu Desnoyers Cc: Ingo Molnar Link: https://lore.kernel.org/20250822033343.3000289-1-wutengda@huaweicloud.com Fixes: d769041f8653 ("ring_buffer: implement new locking") Signed-off-by: Tengda Wu Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 8d8935ed416d7d..1b7db732c0b1eb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -10638,10 +10638,10 @@ static void ftrace_dump_one(struct trace_array *tr, enum ftrace_dump_mode dump_m ret = print_trace_line(&iter); if (ret != TRACE_TYPE_NO_CONSUME) trace_consume(&iter); + + trace_printk_seq(&iter.seq); } touch_nmi_watchdog(); - - trace_printk_seq(&iter.seq); } if (!cnt) From abadf0ff63be488dc502ecfc9f622929a21b7117 Mon Sep 17 00:00:00 2001 From: Mina Almasry Date: Thu, 21 Aug 2025 03:03:46 +0000 Subject: [PATCH 0550/1292] page_pool: fix incorrect mp_ops error handling Minor fix to the memory provider error handling, we should be jumping to free_ptr_ring in this error case rather than returning directly. Found by code-inspection. Cc: skhawaja@google.com Fixes: b400f4b87430 ("page_pool: Set `dma_sync` to false for devmem memory provider") Signed-off-by: Mina Almasry Reviewed-by: Samiullah Khawaja Link: https://patch.msgid.link/20250821030349.705244-1-almasrymina@google.com Signed-off-by: Jakub Kicinski --- net/core/page_pool.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 343a6cac21e3b5..ba70569bd4b051 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -287,8 +287,10 @@ static int page_pool_init(struct page_pool *pool, } if (pool->mp_ops) { - if (!pool->dma_map || !pool->dma_sync) - return -EOPNOTSUPP; + if (!pool->dma_map || !pool->dma_sync) { + err = -EOPNOTSUPP; + goto free_ptr_ring; + } if (WARN_ON(!is_kernel_rodata((unsigned long)pool->mp_ops))) { err = -EFAULT; From a64494aafc56939564e3e9e57f99df5c27204e04 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Thu, 21 Aug 2025 11:55:28 +0530 Subject: [PATCH 0551/1292] Octeontx2-vf: Fix max packet length errors Once driver submits the packets to the hardware, each packet traverse through multiple transmit levels in the following order: SMQ -> TL4 -> TL3 -> TL2 -> TL1 The SMQ supports configurable minimum and maximum packet sizes. It enters to a hang state, if driver submits packets with out of bound lengths. To avoid the same, implement packet length validation before submitting packets to the hardware. Increment tx_dropped counter on failure. Fixes: 3184fb5ba96e ("octeontx2-vf: Virtual function driver support") Fixes: 22f858796758 ("octeontx2-pf: Add basic net_device_ops") Fixes: 3ca6c4c882a7 ("octeontx2-pf: Add packet transmission support") Signed-off-by: Hariprasad Kelam Link: https://patch.msgid.link/20250821062528.1697992-1-hkelam@marvell.com Signed-off-by: Jakub Kicinski --- .../ethernet/marvell/octeontx2/nic/otx2_common.c | 4 +++- .../ethernet/marvell/octeontx2/nic/otx2_common.h | 1 + .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 3 +++ .../net/ethernet/marvell/octeontx2/nic/otx2_vf.c | 10 ++++++++++ drivers/net/ethernet/marvell/octeontx2/nic/rep.c | 13 ++++++++++++- drivers/net/ethernet/marvell/octeontx2/nic/rep.h | 1 + 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index f674729124e691..aff17c37ddde07 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -124,7 +124,9 @@ void otx2_get_dev_stats(struct otx2_nic *pfvf) dev_stats->rx_ucast_frames; dev_stats->tx_bytes = OTX2_GET_TX_STATS(TX_OCTS); - dev_stats->tx_drops = OTX2_GET_TX_STATS(TX_DROP); + dev_stats->tx_drops = OTX2_GET_TX_STATS(TX_DROP) + + (unsigned long)atomic_long_read(&dev_stats->tx_discards); + dev_stats->tx_bcast_frames = OTX2_GET_TX_STATS(TX_BCAST); dev_stats->tx_mcast_frames = OTX2_GET_TX_STATS(TX_MCAST); dev_stats->tx_ucast_frames = OTX2_GET_TX_STATS(TX_UCAST); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index e3765b73c434dd..1c8a3c078a647d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -153,6 +153,7 @@ struct otx2_dev_stats { u64 tx_bcast_frames; u64 tx_mcast_frames; u64 tx_drops; + atomic_long_t tx_discards; }; /* Driver counted stats */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index b23585c5e5c242..5027fae0aa77a6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -2220,6 +2220,7 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev) { struct otx2_nic *pf = netdev_priv(netdev); int qidx = skb_get_queue_mapping(skb); + struct otx2_dev_stats *dev_stats; struct otx2_snd_queue *sq; struct netdev_queue *txq; int sq_idx; @@ -2232,6 +2233,8 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev) /* Check for minimum and maximum packet length */ if (skb->len <= ETH_HLEN || (!skb_shinfo(skb)->gso_size && skb->len > pf->tx_max_pktlen)) { + dev_stats = &pf->hw.dev_stats; + atomic_long_inc(&dev_stats->tx_discards); dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index 5589fccd370b8a..7ebb6e656884ae 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -417,9 +417,19 @@ static netdev_tx_t otx2vf_xmit(struct sk_buff *skb, struct net_device *netdev) { struct otx2_nic *vf = netdev_priv(netdev); int qidx = skb_get_queue_mapping(skb); + struct otx2_dev_stats *dev_stats; struct otx2_snd_queue *sq; struct netdev_queue *txq; + /* Check for minimum and maximum packet length */ + if (skb->len <= ETH_HLEN || + (!skb_shinfo(skb)->gso_size && skb->len > vf->tx_max_pktlen)) { + dev_stats = &vf->hw.dev_stats; + atomic_long_inc(&dev_stats->tx_discards); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + sq = &vf->qset.sq[qidx]; txq = netdev_get_tx_queue(netdev, qidx); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c index 25af98034e2ec7..b476733a023455 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c @@ -371,7 +371,8 @@ static void rvu_rep_get_stats(struct work_struct *work) stats->rx_mcast_frames = rsp->rx.mcast; stats->tx_bytes = rsp->tx.octs; stats->tx_frames = rsp->tx.ucast + rsp->tx.bcast + rsp->tx.mcast; - stats->tx_drops = rsp->tx.drop; + stats->tx_drops = rsp->tx.drop + + (unsigned long)atomic_long_read(&stats->tx_discards); exit: mutex_unlock(&priv->mbox.lock); } @@ -418,6 +419,16 @@ static netdev_tx_t rvu_rep_xmit(struct sk_buff *skb, struct net_device *dev) struct otx2_nic *pf = rep->mdev; struct otx2_snd_queue *sq; struct netdev_queue *txq; + struct rep_stats *stats; + + /* Check for minimum and maximum packet length */ + if (skb->len <= ETH_HLEN || + (!skb_shinfo(skb)->gso_size && skb->len > pf->tx_max_pktlen)) { + stats = &rep->stats; + atomic_long_inc(&stats->tx_discards); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } sq = &pf->qset.sq[rep->rep_id]; txq = netdev_get_tx_queue(dev, 0); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h index 38446b3e4f13cc..5bc9e2c7d800b4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h @@ -27,6 +27,7 @@ struct rep_stats { u64 tx_bytes; u64 tx_frames; u64 tx_drops; + atomic_long_t tx_discards; }; struct rep_dev { From e2fe0c54fb7401e6ecd3c10348519ab9e23bd639 Mon Sep 17 00:00:00 2001 From: James Jones Date: Mon, 11 Aug 2025 15:00:16 -0700 Subject: [PATCH 0552/1292] drm/nouveau/disp: Always accept linear modifier On some chipsets, which block-linear modifiers are supported is format-specific. However, linear modifiers are always be supported. The prior modifier filtering logic was not accounting for the linear case. Cc: stable@vger.kernel.org Fixes: c586f30bf74c ("drm/nouveau/kms: Add format mod prop to base/ovly/nvdisp") Signed-off-by: James Jones Link: https://lore.kernel.org/r/20250811220017.1337-3-jajones@nvidia.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/dispnv50/wndw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index 11d5b923d6e703..e2c55f4b9c5a14 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -795,6 +795,10 @@ static bool nv50_plane_format_mod_supported(struct drm_plane *plane, struct nouveau_drm *drm = nouveau_drm(plane->dev); uint8_t i; + /* All chipsets can display all formats in linear layout */ + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + if (drm->client.device.info.chipset < 0xc0) { const struct drm_format_info *info = drm_format_info(format); const uint8_t kind = (modifier >> 12) & 0xff; From bfb336cf97df7b37b2b2edec0f69773e06d11955 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 22 Aug 2025 18:36:06 -0400 Subject: [PATCH 0553/1292] ftrace: Also allocate and copy hash for reading of filter files Currently the reader of set_ftrace_filter and set_ftrace_notrace just adds the pointer to the global tracer hash to its iterator. Unlike the writer that allocates a copy of the hash, the reader keeps the pointer to the filter hashes. This is problematic because this pointer is static across function calls that release the locks that can update the global tracer hashes. This can cause UAF and similar bugs. Allocate and copy the hash for reading the filter files like it is done for the writers. This not only fixes UAF bugs, but also makes the code a bit simpler as it doesn't have to differentiate when to free the iterator's hash between writers and readers. Cc: stable@vger.kernel.org Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Cc: Nathan Chancellor Cc: Linus Torvalds Link: https://lore.kernel.org/20250822183606.12962cc3@batman.local.home Fixes: c20489dad156 ("ftrace: Assign iter->hash to filter or notrace hashes on seq read") Closes: https://lore.kernel.org/all/20250813023044.2121943-1-wutengda@huaweicloud.com/ Closes: https://lore.kernel.org/all/20250822192437.GA458494@ax162/ Reported-by: Tengda Wu Tested-by: Tengda Wu Tested-by: Nathan Chancellor Signed-off-by: Steven Rostedt (Google) --- kernel/trace/ftrace.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 00b76d450a8979..a69067367c2968 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -4661,13 +4661,17 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, } else { iter->hash = alloc_and_copy_ftrace_hash(size_bits, hash); } + } else { + if (hash) + iter->hash = alloc_and_copy_ftrace_hash(hash->size_bits, hash); + else + iter->hash = EMPTY_HASH; + } - if (!iter->hash) { - trace_parser_put(&iter->parser); - goto out_unlock; - } - } else - iter->hash = hash; + if (!iter->hash) { + trace_parser_put(&iter->parser); + goto out_unlock; + } ret = 0; @@ -6543,9 +6547,6 @@ int ftrace_regex_release(struct inode *inode, struct file *file) ftrace_hash_move_and_update_ops(iter->ops, orig_hash, iter->hash, filter_hash); mutex_unlock(&ftrace_lock); - } else { - /* For read only, the hash is the ops hash */ - iter->hash = NULL; } mutex_unlock(&iter->ops->func_hash->regex_lock); From ec79003c5f9d2c7f9576fc69b8dbda80305cbe3a Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 21 Aug 2025 02:18:24 +0000 Subject: [PATCH 0554/1292] atm: atmtcp: Prevent arbitrary write in atmtcp_recv_control(). syzbot reported the splat below. [0] When atmtcp_v_open() or atmtcp_v_close() is called via connect() or close(), atmtcp_send_control() is called to send an in-kernel special message. The message has ATMTCP_HDR_MAGIC in atmtcp_control.hdr.length. Also, a pointer of struct atm_vcc is set to atmtcp_control.vcc. The notable thing is struct atmtcp_control is uAPI but has a space for an in-kernel pointer. struct atmtcp_control { struct atmtcp_hdr hdr; /* must be first */ ... atm_kptr_t vcc; /* both directions */ ... } __ATM_API_ALIGN; typedef struct { unsigned char _[8]; } __ATM_API_ALIGN atm_kptr_t; The special message is processed in atmtcp_recv_control() called from atmtcp_c_send(). atmtcp_c_send() is vcc->dev->ops->send() and called from 2 paths: 1. .ndo_start_xmit() (vcc->send() == atm_send_aal0()) 2. vcc_sendmsg() The problem is sendmsg() does not validate the message length and userspace can abuse atmtcp_recv_control() to overwrite any kptr by atmtcp_control. Let's add a new ->pre_send() hook to validate messages from sendmsg(). [0]: Oops: general protection fault, probably for non-canonical address 0xdffffc00200000ab: 0000 [#1] SMP KASAN PTI KASAN: probably user-memory-access in range [0x0000000100000558-0x000000010000055f] CPU: 0 UID: 0 PID: 5865 Comm: syz-executor331 Not tainted 6.17.0-rc1-syzkaller-00215-gbab3ce404553 #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/12/2025 RIP: 0010:atmtcp_recv_control drivers/atm/atmtcp.c:93 [inline] RIP: 0010:atmtcp_c_send+0x1da/0x950 drivers/atm/atmtcp.c:297 Code: 4d 8d 75 1a 4c 89 f0 48 c1 e8 03 42 0f b6 04 20 84 c0 0f 85 15 06 00 00 41 0f b7 1e 4d 8d b7 60 05 00 00 4c 89 f0 48 c1 e8 03 <42> 0f b6 04 20 84 c0 0f 85 13 06 00 00 66 41 89 1e 4d 8d 75 1c 4c RSP: 0018:ffffc90003f5f810 EFLAGS: 00010203 RAX: 00000000200000ab RBX: 0000000000000000 RCX: 0000000000000000 RDX: ffff88802a510000 RSI: 00000000ffffffff RDI: ffff888030a6068c RBP: ffff88802699fb40 R08: ffff888030a606eb R09: 1ffff1100614c0dd R10: dffffc0000000000 R11: ffffffff8718fc40 R12: dffffc0000000000 R13: ffff888030a60680 R14: 000000010000055f R15: 00000000ffffffff FS: 00007f8d7e9236c0(0000) GS:ffff888125c1c000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000045ad50 CR3: 0000000075bde000 CR4: 00000000003526f0 Call Trace: vcc_sendmsg+0xa10/0xc60 net/atm/common.c:645 sock_sendmsg_nosec net/socket.c:714 [inline] __sock_sendmsg+0x219/0x270 net/socket.c:729 ____sys_sendmsg+0x505/0x830 net/socket.c:2614 ___sys_sendmsg+0x21f/0x2a0 net/socket.c:2668 __sys_sendmsg net/socket.c:2700 [inline] __do_sys_sendmsg net/socket.c:2705 [inline] __se_sys_sendmsg net/socket.c:2703 [inline] __x64_sys_sendmsg+0x19b/0x260 net/socket.c:2703 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f8d7e96a4a9 Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 51 18 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f8d7e923198 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007f8d7e9f4308 RCX: 00007f8d7e96a4a9 RDX: 0000000000000000 RSI: 0000200000000240 RDI: 0000000000000005 RBP: 00007f8d7e9f4300 R08: 65732f636f72702f R09: 65732f636f72702f R10: 65732f636f72702f R11: 0000000000000246 R12: 00007f8d7e9c10ac R13: 00007f8d7e9231a0 R14: 0000200000000200 R15: 0000200000000250 Modules linked in: Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+1741b56d54536f4ec349@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/68a6767c.050a0220.3d78fd.0011.GAE@google.com/ Tested-by: syzbot+1741b56d54536f4ec349@syzkaller.appspotmail.com Signed-off-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250821021901.2814721-1-kuniyu@google.com Signed-off-by: Jakub Kicinski --- drivers/atm/atmtcp.c | 17 ++++++++++++++--- include/linux/atmdev.h | 1 + net/atm/common.c | 15 ++++++++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index eeae160c898d38..fa3c76a2b49d1f 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -279,6 +279,19 @@ static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) return NULL; } +static int atmtcp_c_pre_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct atmtcp_hdr *hdr; + + if (skb->len < sizeof(struct atmtcp_hdr)) + return -EINVAL; + + hdr = (struct atmtcp_hdr *)skb->data; + if (hdr->length == ATMTCP_HDR_MAGIC) + return -EINVAL; + + return 0; +} static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) { @@ -288,9 +301,6 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) struct sk_buff *new_skb; int result = 0; - if (skb->len < sizeof(struct atmtcp_hdr)) - goto done; - dev = vcc->dev_data; hdr = (struct atmtcp_hdr *) skb->data; if (hdr->length == ATMTCP_HDR_MAGIC) { @@ -347,6 +357,7 @@ static const struct atmdev_ops atmtcp_v_dev_ops = { static const struct atmdev_ops atmtcp_c_dev_ops = { .close = atmtcp_c_close, + .pre_send = atmtcp_c_pre_send, .send = atmtcp_c_send }; diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 45f2f278b50a8a..70807c679f1abc 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -185,6 +185,7 @@ struct atmdev_ops { /* only send is required */ int (*compat_ioctl)(struct atm_dev *dev,unsigned int cmd, void __user *arg); #endif + int (*pre_send)(struct atm_vcc *vcc, struct sk_buff *skb); int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); int (*send_bh)(struct atm_vcc *vcc, struct sk_buff *skb); int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags); diff --git a/net/atm/common.c b/net/atm/common.c index d7f7976ea13ac6..881c7f259dbd46 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -635,18 +635,27 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) skb->dev = NULL; /* for paths shared with net_device interfaces */ if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) { - atm_return_tx(vcc, skb); - kfree_skb(skb); error = -EFAULT; - goto out; + goto free_skb; } if (eff != size) memset(skb->data + size, 0, eff-size); + + if (vcc->dev->ops->pre_send) { + error = vcc->dev->ops->pre_send(vcc, skb); + if (error) + goto free_skb; + } + error = vcc->dev->ops->send(vcc, skb); error = error ? error : size; out: release_sock(sk); return error; +free_skb: + atm_return_tx(vcc, skb); + kfree_skb(skb); + goto out; } __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait) From c2bac68067bba5edda09112c09f2f670792dcdc8 Mon Sep 17 00:00:00 2001 From: Edgar Bonet Date: Thu, 14 Aug 2025 14:59:42 +0200 Subject: [PATCH 0555/1292] irqchip/atmel-aic[5]: Fix incorrect lock guard conversion Commit b00bee8afaca ("irqchip: Convert generic irqchip locking to guards") replaced calls to irq_gc_lock_irq{save,restore}() with guard(raw_spinlock_irq). However, in irq-atmel-aic5.c and irq-atmel-aic.c, the xlate callback is used in the early boot process, before interrupts are initially enabled. As its destructor enables interrupts, this triggers the warning in start_kernel(): WARNING: CPU: 0 PID: 0 at init/main.c:1024 start_kernel+0x4d0/0x5dc Interrupts were enabled early Fix this by using guard(raw_spinlock_irqsave) instead. [ tglx: Folded the equivivalent fix for atmel-aic ] Fixes: b00bee8afaca ("irqchip: Convert generic irqchip locking to guards") Signed-off-by: Edgar Bonet Signed-off-by: Thomas Gleixner Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/all/280dd506-e1fc-4d2e-bdc4-98dd9dca6138@grenoble.cnrs.fr --- drivers/irqchip/irq-atmel-aic.c | 2 +- drivers/irqchip/irq-atmel-aic5.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index 03aeed39a4d29a..1dcc52760ecaee 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -188,7 +188,7 @@ static int aic_irq_domain_xlate(struct irq_domain *d, gc = dgc->gc[idx]; - guard(raw_spinlock_irq)(&gc->lock); + guard(raw_spinlock_irqsave)(&gc->lock); smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq)); aic_common_set_priority(intspec[2], &smr); irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq)); diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 60b00d2c3d7ad6..1f14b401f71d0d 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -279,7 +279,7 @@ static int aic5_irq_domain_xlate(struct irq_domain *d, if (ret) return ret; - guard(raw_spinlock_irq)(&bgc->lock); + guard(raw_spinlock_irqsave)(&bgc->lock); irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR); smr = irq_reg_readl(bgc, AT91_AIC5_SMR); aic_common_set_priority(intspec[2], &smr); From 8976583832579fe7e450034d6143d74d9f8c8608 Mon Sep 17 00:00:00 2001 From: Maud Spierings Date: Sat, 23 Aug 2025 14:43:50 +0200 Subject: [PATCH 0556/1292] arm64: dts: rockchip: Fix the headphone detection on the orangepi 5 plus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The logic of the headphone detect pin seems to be inverted, with this change headphones actually output sound when plugged in. Verified by checking /sys/kernel/debug/gpio and by listening. Fixes: 236d225e1ee7 ("arm64: dts: rockchip: Add board device tree for rk3588-orangepi-5-plus") Signed-off-by: Maud Spierings Reviewed-by: Ondřej Jirman Link: https://lore.kernel.org/r/20250823-orangepi5-v1-1-ae77dd0e06d7@hotmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts index 121e4d1c3fa5da..8222f1fae8fadc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts @@ -77,7 +77,7 @@ pinctrl-names = "default"; pinctrl-0 = <&hp_detect>; simple-audio-card,aux-devs = <&speaker_amp>, <&headphone_amp>; - simple-audio-card,hp-det-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>; simple-audio-card,widgets = "Microphone", "Onboard Microphone", "Microphone", "Microphone Jack", From 2dea24df234940b27d378f786933dc10f33de6b8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 21 Aug 2025 13:29:39 +0800 Subject: [PATCH 0557/1292] arm64: dts: rockchip: Add supplies for eMMC on rk3588-orangepi-5 The eMMC description is missing both vmmc and vqmmc supplies. Add them to complete the description. Fixes: 236d225e1ee7 ("arm64: dts: rockchip: Add board device tree for rk3588-orangepi-5-plus") Fixes: ea63f4666e48 ("arm64: dts: rockchip: refactor common rk3588-orangepi-5.dtsi") Signed-off-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20250821052939.1869171-1-wens@kernel.org Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi index 91d56c34a1e456..8a8f3b26754d74 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5.dtsi @@ -365,6 +365,8 @@ max-frequency = <200000000>; mmc-hs400-1_8v; mmc-hs400-enhanced-strobe; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vcc_1v8_s3>; status = "okay"; }; From 106bdca970c1f66e2d4ee53675df1575b01c65ce Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 19 Aug 2025 15:16:08 +0200 Subject: [PATCH 0558/1292] ARM: dts: rockchip: Minor whitespace cleanup The DTS code coding style expects exactly one space around '=' character. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250819131607.86338-3-krzysztof.kozlowski@linaro.org Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts | 2 +- arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts index 21f824b0919163..decbf2726ec430 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -272,7 +272,7 @@ phy-mode = "rmii"; phy-handle = <&phy0>; assigned-clocks = <&cru SCLK_MAC_SRC>; - assigned-clock-rates= <50000000>; + assigned-clock-rates = <50000000>; pinctrl-names = "default"; pinctrl-0 = <&rmii_pins>; status = "okay"; diff --git a/arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts b/arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts index c13829d32c3253..8a92700349b4e4 100644 --- a/arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts +++ b/arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts @@ -250,9 +250,9 @@ &i2s0 { /delete-property/ pinctrl-0; rockchip,trcm-sync-rx-only; - pinctrl-0 = <&i2s0m0_sclk_rx>, - <&i2s0m0_lrck_rx>, - <&i2s0m0_sdi0>; + pinctrl-0 = <&i2s0m0_sclk_rx>, + <&i2s0m0_lrck_rx>, + <&i2s0m0_sdi0>; pinctrl-names = "default"; status = "okay"; }; From 521b36e5a243d94e843c0f03285fc49ee88c37b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 19 Aug 2025 15:16:09 +0200 Subject: [PATCH 0559/1292] arm64: dts: rockchip: Minor whitespace cleanup The DTS code coding style expects exactly one space around '=' or '{' characters. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250819131607.86338-4-krzysztof.kozlowski@linaro.org Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi | 8 ++++---- .../dts/rockchip/px30-ringneck-haikou-video-demo.dtso | 6 +++--- arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts | 2 +- .../boot/dts/rockchip/rk3399-puma-haikou-video-demo.dtso | 6 +++--- arch/arm64/boot/dts/rockchip/rk3566-bigtreetech-cb2.dtsi | 4 ++-- arch/arm64/boot/dts/rockchip/rk3588j.dtsi | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi b/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi index b4bd4e34747ca0..192791993f0591 100644 --- a/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi @@ -72,7 +72,7 @@ }; vcc_cam_avdd: regulator-vcc-cam-avdd { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; regulator-name = "vcc_cam_avdd"; gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -83,7 +83,7 @@ }; vcc_cam_dovdd: regulator-vcc-cam-dovdd { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; regulator-name = "vcc_cam_dovdd"; gpio = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -94,7 +94,7 @@ }; vcc_cam_dvdd: regulator-vcc-cam-dvdd { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; regulator-name = "vcc_cam_dvdd"; gpio = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; enable-active-high; @@ -106,7 +106,7 @@ }; vcc_lens_afvdd: regulator-vcc-lens-afvdd { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; regulator-name = "vcc_lens_afvdd"; gpio = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou-video-demo.dtso b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou-video-demo.dtso index ea5ce919984f07..760d5139f95dfa 100644 --- a/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou-video-demo.dtso +++ b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou-video-demo.dtso @@ -26,7 +26,7 @@ }; cam_afvdd_2v8: regulator-cam-afvdd-2v8 { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; gpio = <&pca9670 2 GPIO_ACTIVE_LOW>; regulator-max-microvolt = <2800000>; regulator-min-microvolt = <2800000>; @@ -35,7 +35,7 @@ }; cam_avdd_2v8: regulator-cam-avdd-2v8 { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; gpio = <&pca9670 4 GPIO_ACTIVE_LOW>; regulator-max-microvolt = <2800000>; regulator-min-microvolt = <2800000>; @@ -44,7 +44,7 @@ }; cam_dovdd_1v8: regulator-cam-dovdd-1v8 { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; gpio = <&pca9670 3 GPIO_ACTIVE_LOW>; regulator-max-microvolt = <1800000>; regulator-min-microvolt = <1800000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts b/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts index f9f633aebb64f9..e5e6b800c2d163 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts @@ -260,6 +260,6 @@ status = "okay"; }; -&usb_host_ohci{ +&usb_host_ohci { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou-video-demo.dtso b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou-video-demo.dtso index d28880b8dd4499..5e8f729c2cf220 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou-video-demo.dtso +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou-video-demo.dtso @@ -26,7 +26,7 @@ }; cam_afvdd_2v8: regulator-cam-afvdd-2v8 { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; gpio = <&pca9670 2 GPIO_ACTIVE_LOW>; regulator-max-microvolt = <2800000>; regulator-min-microvolt = <2800000>; @@ -35,7 +35,7 @@ }; cam_avdd_2v8: regulator-cam-avdd-2v8 { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; gpio = <&pca9670 4 GPIO_ACTIVE_LOW>; regulator-max-microvolt = <2800000>; regulator-min-microvolt = <2800000>; @@ -44,7 +44,7 @@ }; cam_dovdd_1v8: regulator-cam-dovdd-1v8 { - compatible = "regulator-fixed"; + compatible = "regulator-fixed"; gpio = <&pca9670 3 GPIO_ACTIVE_LOW>; regulator-max-microvolt = <1800000>; regulator-min-microvolt = <1800000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-bigtreetech-cb2.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-bigtreetech-cb2.dtsi index e7ba477e75f9bf..7f578c50b4ad1e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-bigtreetech-cb2.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-bigtreetech-cb2.dtsi @@ -53,7 +53,7 @@ gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>; linux,default-trigger = "default-on"; pinctrl-names = "default"; - pinctrl-0 =<&blue_led>; + pinctrl-0 = <&blue_led>; }; led-1 { @@ -62,7 +62,7 @@ gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_LOW>; linux,default-trigger = "heartbeat"; pinctrl-names = "default"; - pinctrl-0 =<&heartbeat_led>; + pinctrl-0 = <&heartbeat_led>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588j.dtsi b/arch/arm64/boot/dts/rockchip/rk3588j.dtsi index 3045cb3bd68c63..9884a5df47dfed 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588j.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588j.dtsi @@ -28,7 +28,7 @@ compatible = "operating-points-v2"; opp-shared; - opp-1200000000{ + opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <750000 750000 950000>; clock-latency-ns = <40000>; @@ -49,7 +49,7 @@ compatible = "operating-points-v2"; opp-shared; - opp-1200000000{ + opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <750000 750000 950000>; clock-latency-ns = <40000>; From c8bb0f00a4886b24d933ffaabcdc09bf9a370dca Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Aug 2025 12:40:02 +0300 Subject: [PATCH 0560/1292] irqchip/mvebu-gicp: Fix an IS_ERR() vs NULL check in probe() ioremap() never returns error pointers, it returns NULL on error. Fix the check to match. Fixes: 3c3d7dbab2c7 ("irqchip/mvebu-gicp: Clear pending interrupts on init") Signed-off-by: Dan Carpenter Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/aKRGcgMeaXm2TMIC@stanley.mountain --- drivers/irqchip/irq-mvebu-gicp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-mvebu-gicp.c b/drivers/irqchip/irq-mvebu-gicp.c index 54833717f8a70f..667bde3c651ff2 100644 --- a/drivers/irqchip/irq-mvebu-gicp.c +++ b/drivers/irqchip/irq-mvebu-gicp.c @@ -238,7 +238,7 @@ static int mvebu_gicp_probe(struct platform_device *pdev) } base = ioremap(gicp->res->start, resource_size(gicp->res)); - if (IS_ERR(base)) { + if (!base) { dev_err(&pdev->dev, "ioremap() failed. Unable to clear pending interrupts.\n"); } else { for (i = 0; i < 64; i++) From 1a2cce5b91eeeac24104cbccd8cd3a4dfbdbaa7a Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 11 Aug 2025 15:50:01 +0200 Subject: [PATCH 0561/1292] irqchip/gic-v5: Fix kmemleak L2 IST table entries false positives L2 IST table entries are allocated with the kmalloc interface and their physical addresses are programmed in the GIC (either IST base address register or L1 IST table entries) but their virtual addresses are not stored in any kernel data structure because they are not needed at runtime - the L2 IST table entries are managed through system instructions but never dereferenced directly by the driver. This triggers kmemleak false positive reports: unreferenced object 0xffff00080039a000 (size 4096): comm "swapper/0", pid 0, jiffies 4294892296 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace (crc 0): kmemleak_alloc+0x34/0x40 __kmalloc_noprof+0x320/0x464 gicv5_irs_iste_alloc+0x1a4/0x484 gicv5_irq_lpi_domain_alloc+0xe4/0x194 irq_domain_alloc_irqs_parent+0x78/0xd8 gicv5_irq_ipi_domain_alloc+0x180/0x238 irq_domain_alloc_irqs_locked+0x238/0x7d4 __irq_domain_alloc_irqs+0x88/0x114 gicv5_of_init+0x284/0x37c of_irq_init+0x3b8/0xb18 irqchip_init+0x18/0x40 init_IRQ+0x104/0x164 start_kernel+0x1a4/0x3d4 __primary_switched+0x8c/0x94 Instruct kmemleak to ignore L2 IST table memory allocation virtual addresses to prevent these false positive reports. Reported-by: Jinjie Ruan Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Reviewed-by: Jinjie Ruan Reviewed-by: Zenghui Yu Acked-by: Marc Zyngier Link: https://lore.kernel.org/all/20250811135001.1333684-1-lpieralisi@kernel.org Closes: https://lore.kernel.org/lkml/cc611dda-d1e4-4793-9bb2-0eaa47277584@huawei.com/ --- drivers/irqchip/irq-gic-v5-irs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c index f845415f914346..ffc97737a75700 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -5,6 +5,7 @@ #define pr_fmt(fmt) "GICv5 IRS: " fmt +#include #include #include #include @@ -117,6 +118,7 @@ static int __init gicv5_irs_init_ist_linear(struct gicv5_irs_chip_data *irs_data kfree(ist); return ret; } + kmemleak_ignore(ist); return 0; } @@ -232,6 +234,7 @@ int gicv5_irs_iste_alloc(const u32 lpi) kfree(l2ist); return ret; } + kmemleak_ignore(l2ist); /* * Make sure we invalidate the cache line pulled before the IRS From 09cce878427962a5c2a3a37d6cc52485a0134ac1 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 18 Aug 2025 19:12:23 +0200 Subject: [PATCH 0562/1292] arm64: dts: rockchip: correct network description on Sige5 Both network PHYs have dedicated crystals for the 25 MHz clock and do not source it from the RK3576. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20250818-sige5-network-phy-clock-v1-1-87a9122d41c2@kernel.org Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts index 101e2ee9766d7b..3386084f63183e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts @@ -302,8 +302,7 @@ ð1m0_tx_bus2 ð1m0_rx_bus2 ð1m0_rgmii_clk - ð1m0_rgmii_bus - ðm0_clk1_25m_out>; + ð1m0_rgmii_bus>; status = "okay"; }; @@ -784,7 +783,6 @@ rgmii_phy0: phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0x1>; - clocks = <&cru REFCLKO25M_GMAC0_OUT>; pinctrl-names = "default"; pinctrl-0 = <&gmac0_rst>; reset-assert-us = <20000>; @@ -797,7 +795,6 @@ rgmii_phy1: phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0x1>; - clocks = <&cru REFCLKO25M_GMAC1_OUT>; pinctrl-names = "default"; pinctrl-0 = <&gmac1_rst>; reset-assert-us = <20000>; From c9f986a54d4031a9b9dff1eb616b0796aa28c730 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 18 Aug 2025 11:04:47 +0200 Subject: [PATCH 0563/1292] arm64: dts: rockchip: Fix Bluetooth interrupts flag on Neardi LBA3368 GPIO_ACTIVE_x flags are not correct in the context of interrupt flags. These are simple defines so they could be used in DTS but they will not have the same meaning: GPIO_ACTIVE_HIGH = 0 = IRQ_TYPE_NONE. Correct the interrupt flags, assuming the author of the code wanted same logical behavior behind the name "ACTIVE_xxx", this is: ACTIVE_HIGH => IRQ_TYPE_LEVEL_HIGH Fixes: 7b4a8097e58b ("arm64: dts: rockchip: Add Neardi LBA3368 board") Cc: stable+noautosel@kernel.org # Needs testing, because actual level is just a guess Signed-off-by: Krzysztof Kozlowski Tested-By: Alex Bee Link: https://lore.kernel.org/r/20250818090445.28112-4-krzysztof.kozlowski@linaro.org Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts b/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts index b99bb0a5f9006b..b9801a691b486c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts @@ -609,7 +609,7 @@ bluetooth { compatible = "brcm,bcm4345c5"; - interrupts-extended = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&gpio3 RK_PA7 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "host-wakeup"; clocks = <&rk808 RK808_CLKOUT1>; clock-names = "lpo"; From 4138adfd3594ebe957c6cb640372c93e354aa171 Mon Sep 17 00:00:00 2001 From: Kaison Deng Date: Thu, 14 Aug 2025 12:32:30 +0800 Subject: [PATCH 0564/1292] arm64: dts: rockchip: fix es8388 address on rk3588s-roc-pc Use the correct es8388 address for rk3588s-roc-ps Signed-off-by: Kaison Deng Link: https://lore.kernel.org/r/20250814043230.2774813-1-dkx@t-chip.com.cn Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dts index 7434ac39246f75..7e179862da6e56 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dts @@ -320,9 +320,9 @@ &i2c3 { status = "okay"; - es8388: audio-codec@10 { + es8388: audio-codec@11 { compatible = "everest,es8388", "everest,es8328"; - reg = <0x10>; + reg = <0x11>; clocks = <&cru I2S1_8CH_MCLKOUT>; AVDD-supply = <&vcc_3v3_s0>; DVDD-supply = <&vcc_1v8_s0>; From 35c23871be0072738ccc7ca00354c791711e5640 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 14 Aug 2025 11:41:38 +0200 Subject: [PATCH 0565/1292] irqchip/gic-v5: Remove undue WARN_ON()s in the IRS affinity parsing In gicv5_irs_of_init_affinity() a WARN_ON() is triggered if: 1) a phandle in the "cpus" property does not correspond to a valid OF node 2 a CPU logical id does not exist for a given OF cpu_node #1 is a firmware bug and should be reported as such but does not warrant a WARN_ON() backtrace. #2 is not necessarily an error condition (eg a kernel can be booted with nr_cpus=X limiting the number of cores artificially) and therefore there is no reason to clutter the kernel log with WARN_ON() output when the condition is hit. Rework the IRS affinity parsing code to remove undue WARN_ON()s thus making it less noisy. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250814094138.1611017-1-lpieralisi@kernel.org --- drivers/irqchip/irq-gic-v5-irs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c index ffc97737a75700..13c035727e32b0 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -626,12 +626,14 @@ static int __init gicv5_irs_of_init_affinity(struct device_node *node, int cpu; cpu_node = of_parse_phandle(node, "cpus", i); - if (WARN_ON(!cpu_node)) + if (!cpu_node) { + pr_warn(FW_BUG "Erroneous CPU node phandle\n"); continue; + } cpu = of_cpu_node_to_id(cpu_node); of_node_put(cpu_node); - if (WARN_ON(cpu < 0)) + if (cpu < 0) continue; if (iaffids[i] & ~iaffid_mask) { From 1b237f190eb3d36f52dffe07a40b5eb210280e00 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 24 Aug 2025 12:04:12 -0400 Subject: [PATCH 0566/1292] Linux 6.17-rc3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d1adb78c3596a5..06c28b1d7e67a3 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Baby Opossum Posse # *DOCUMENTATION* From 168873ca1799d3f23442b9e79eae55f907b9b126 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 19 Aug 2025 01:58:51 +0000 Subject: [PATCH 0567/1292] ASoC: soc-core: care NULL dirver name on snd_soc_lookup_component_nolocked() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit soc-generic-dmaengine-pcm.c uses same dev for both CPU and Platform. In such case, CPU component driver might not have driver->name, then snd_soc_lookup_component_nolocked() will be NULL pointer access error. Care NULL driver name. Call trace: strcmp from snd_soc_lookup_component_nolocked+0x64/0xa4 snd_soc_lookup_component_nolocked from snd_soc_unregister_component_by_driver+0x2c/0x44 snd_soc_unregister_component_by_driver from snd_dmaengine_pcm_unregister+0x28/0x64 snd_dmaengine_pcm_unregister from devres_release_all+0x98/0xfc devres_release_all from device_unbind_cleanup+0xc/0x60 device_unbind_cleanup from really_probe+0x220/0x2c8 really_probe from __driver_probe_device+0x88/0x1a0 __driver_probe_device from driver_probe_device+0x30/0x110 driver_probe_device from __driver_attach+0x90/0x178 __driver_attach from bus_for_each_dev+0x7c/0xcc bus_for_each_dev from bus_add_driver+0xcc/0x1ec bus_add_driver from driver_register+0x80/0x11c driver_register from do_one_initcall+0x58/0x23c do_one_initcall from kernel_init_freeable+0x198/0x1f4 kernel_init_freeable from kernel_init+0x1c/0x12c kernel_init from ret_from_fork+0x14/0x28 Fixes: 144d6dfc7482 ("ASoC: soc-core: merge snd_soc_unregister_component() and snd_soc_unregister_component_by_driver()") Reported-by: J. NeuschƤfer Closes: https://lore.kernel.org/r/aJb311bMDc9x-dpW@probook Signed-off-by: Kuninori Morimoto Reported-by: Ondřej Jirman Closes: https://lore.kernel.org/r/arxpwzu6nzgjxvsndct65ww2wz4aezb5gjdzlgr24gfx7xvyih@natjg6dg2pj6 Tested-by: J. NeuschƤfer Message-ID: <87ect8ysv8.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 37bc5867f81d4a..c1cf205e055695 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -375,8 +375,9 @@ struct snd_soc_component for_each_component(component) { if ((dev == component->dev) && (!driver_name || - (driver_name == component->driver->name) || - (strcmp(component->driver->name, driver_name) == 0))) { + (component->driver->name && + ((component->driver->name == driver_name) || + (strcmp(component->driver->name, driver_name) == 0))))) { found_component = component; break; } From b833b412a522e58b790abe79b6ec46e8ba1f312a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 19 Aug 2025 01:59:01 +0000 Subject: [PATCH 0568/1292] ASoC: soc-core: tidyup snd_soc_lookup_component_nolocked() snd_soc_lookup_component_nolocked() is very complex today. Let's tidyup the code. Signed-off-by: Kuninori Morimoto Message-ID: <87cy8sysuy.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c1cf205e055695..cc9125ffe92ac0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -369,21 +369,25 @@ struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name) { struct snd_soc_component *component; - struct snd_soc_component *found_component; - found_component = NULL; for_each_component(component) { - if ((dev == component->dev) && - (!driver_name || - (component->driver->name && - ((component->driver->name == driver_name) || - (strcmp(component->driver->name, driver_name) == 0))))) { - found_component = component; - break; - } + if (dev != component->dev) + continue; + + if (!driver_name) + return component; + + if (!component->driver->name) + continue; + + if (component->driver->name == driver_name) + return component; + + if (strcmp(component->driver->name, driver_name) == 0) + return component; } - return found_component; + return NULL; } EXPORT_SYMBOL_GPL(snd_soc_lookup_component_nolocked); From b1c99d5bd24ce0a1193d8476d83bf8c8bc633266 Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Fri, 22 Aug 2025 18:28:33 +0800 Subject: [PATCH 0569/1292] ASoC: codecs: idt821034: fix wrong log in idt821034_chip_direction_output() Change `dir in` to `dir out` Suggested-by: Jun Zhan Signed-off-by: Cryolitia PukNgae Acked-by: Herve Codina Message-ID: <20250822-idt821034-v1-1-e2bfffbde56f@uniontech.com> Signed-off-by: Mark Brown --- sound/soc/codecs/idt821034.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c index 6738cf21983b0d..a03d4e5e7d1441 100644 --- a/sound/soc/codecs/idt821034.c +++ b/sound/soc/codecs/idt821034.c @@ -1067,7 +1067,7 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off ret = idt821034_set_slic_conf(idt821034, ch, slic_conf); if (ret) { - dev_err(&idt821034->spi->dev, "dir in gpio %d (%u, 0x%x) failed (%d)\n", + dev_err(&idt821034->spi->dev, "dir out gpio %d (%u, 0x%x) failed (%d)\n", offset, ch, mask, ret); } From ef3e9c91ed87f13dba877a20569f4a0accf0612c Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Sat, 23 Aug 2025 01:56:39 +0530 Subject: [PATCH 0570/1292] regulator: pm8008: fix probe failure due to negative voltage selector In the current design, the `pm8008_regulator_get_voltage_sel()` callback can return a negative value if the raw voltage value is read as 0 uV from the PMIC HW register. This can cause the probe to fail when the `machine_constraints_voltage()` check is called during the regulator registration flow. Fix this by using the helper `regulator_map_voltage_linear_range()` to convert the raw value to a voltage selector inside the mentioned get voltage selector function. This ensures that the value returned is always within the defined range. Signed-off-by: Kamal Wadhwa Message-ID: <20250823-pm8008-negitive-selector-v1-1-52b026a4b5e8@quicinc.com> Signed-off-by: Mark Brown --- drivers/regulator/qcom-pm8008-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c index da017c1969d0cc..90c78ee1c37bf9 100644 --- a/drivers/regulator/qcom-pm8008-regulator.c +++ b/drivers/regulator/qcom-pm8008-regulator.c @@ -96,7 +96,7 @@ static int pm8008_regulator_get_voltage_sel(struct regulator_dev *rdev) uV = le16_to_cpu(val) * 1000; - return (uV - preg->desc.min_uV) / preg->desc.uV_step; + return regulator_map_voltage_linear_range(rdev, uV, INT_MAX); } static const struct regulator_ops pm8008_regulator_ops = { From bc017f28b1c6c3d44c3631f8f6d152b7e703e990 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 20 Aug 2025 11:16:41 +0800 Subject: [PATCH 0571/1292] ASoC: imx-hdmi: remove cpu_pdev related code If a defer probe happens for the cpu device, the return value for cpu_pdev "ret = -EINVAL" breaks defer probe. As the cpus->dai_name can be replaced by cpus->of_node, to simplify the code, remove related code for cpu_pdev. Fixes: 6a5f850aa83a ("ASoC: fsl: Add imx-hdmi machine driver") Signed-off-by: Shengjiu Wang Message-ID: <20250820031641.2158261-1-shengjiu.wang@nxp.com> Signed-off-by: Mark Brown --- sound/soc/fsl/imx-hdmi.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index fe47b439a8183d..1115189cc6400a 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -101,7 +101,6 @@ static int imx_hdmi_probe(struct platform_device *pdev) bool hdmi_out = of_property_read_bool(np, "hdmi-out"); bool hdmi_in = of_property_read_bool(np, "hdmi-in"); struct snd_soc_dai_link_component *dlc; - struct platform_device *cpu_pdev; struct device_node *cpu_np; struct imx_hdmi_data *data; int ret; @@ -117,17 +116,9 @@ static int imx_hdmi_probe(struct platform_device *pdev) goto fail; } - cpu_pdev = of_find_device_by_node(cpu_np); - if (!cpu_pdev) { - dev_err(&pdev->dev, "failed to find SAI platform device\n"); - ret = -EINVAL; - goto fail; - } - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { ret = -ENOMEM; - put_device(&cpu_pdev->dev); goto fail; } @@ -140,15 +131,13 @@ static int imx_hdmi_probe(struct platform_device *pdev) data->dai.name = "i.MX HDMI"; data->dai.stream_name = "i.MX HDMI"; - data->dai.cpus->dai_name = dev_name(&cpu_pdev->dev); + data->dai.cpus->of_node = cpu_np; data->dai.platforms->of_node = cpu_np; data->dai.ops = &imx_hdmi_ops; data->dai.playback_only = true; data->dai.capture_only = false; data->dai.init = imx_hdmi_init; - put_device(&cpu_pdev->dev); - if (of_node_name_eq(cpu_np, "sai")) { data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; From f840737d1746398c2993be34bfdc80bdc19ecae2 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 19:26:54 +0800 Subject: [PATCH 0572/1292] ASoC: SOF: imx: Remove the use of dev_err_probe() The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Laurentiu Mihalcea Message-ID: <20250819112654.588527-1-zhao.xichao@vivo.com> Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx-common.c | 4 ++-- sound/soc/sof/imx/imx8.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 1757539a6a2833..40debc541bf9eb 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -354,8 +354,8 @@ static int imx_probe(struct snd_sof_dev *sdev) common = devm_kzalloc(sdev->dev, sizeof(*common), GFP_KERNEL); if (!common) - return dev_err_probe(sdev->dev, -ENOMEM, - "failed to allocate common data\n"); + return -ENOMEM; + sdev->pdata->hw_pdata = common; common->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index b73dd91bd5292a..7e9eab2e303472 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -171,8 +171,7 @@ static int imx8m_probe(struct snd_sof_dev *sdev) chip = devm_kzalloc(sdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) - return dev_err_probe(sdev->dev, -ENOMEM, - "failed to allocate chip data\n"); + return -ENOMEM; chip->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE); if (!chip->dap) From 9bca8be646e043d1fc6cd426fef05558c02de3df Mon Sep 17 00:00:00 2001 From: Fangyu Yu Date: Thu, 7 Aug 2025 15:07:29 +0800 Subject: [PATCH 0573/1292] RISC-V: KVM: Fix pte settings within kvm_riscv_gstage_ioremap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, kvm_riscv_gstage_ioremap() is used to map IMSIC gpa to the spa of IMSIC guest interrupt file. The PAGE_KERNEL_IO property includes global setting whereas it does not include user mode settings, so when accessing the IMSIC address in the virtual machine, a guest page fault will occur, this is not expected. According to the RISC-V Privileged Architecture Spec, for G-stage address translation, all memory accesses are considered to be user-level accesses as though executed in U-mode. Fixes: 659ad6d82c31 ("RISC-V: KVM: Use PAGE_KERNEL_IO in kvm_riscv_gstage_ioremap()") Signed-off-by: Fangyu Yu Reviewed-by: Radim KrčmÔř Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/20250807070729.89701-1-fangyu.yu@linux.alibaba.com Signed-off-by: Anup Patel --- arch/riscv/kvm/mmu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index a1c3b2ec1dde54..525fb5a330c0d2 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -39,6 +39,7 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa, unsigned long size, bool writable, bool in_atomic) { int ret = 0; + pgprot_t prot; unsigned long pfn; phys_addr_t addr, end; struct kvm_mmu_memory_cache pcache = { @@ -55,10 +56,12 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa, end = (gpa + size + PAGE_SIZE - 1) & PAGE_MASK; pfn = __phys_to_pfn(hpa); + prot = pgprot_noncached(PAGE_WRITE); for (addr = gpa; addr < end; addr += PAGE_SIZE) { map.addr = addr; - map.pte = pfn_pte(pfn, PAGE_KERNEL_IO); + map.pte = pfn_pte(pfn, prot); + map.pte = pte_mkdirty(map.pte); map.level = 0; if (!writable) From e61a12a4baf06a4c71e15f522bb5c4345c2ba198 Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Mon, 11 Aug 2025 10:18:29 +0800 Subject: [PATCH 0574/1292] RISC-V: KVM: Correct kvm_riscv_check_vcpu_requests() comment Correct `check_vcpu_requests` to `kvm_riscv_check_vcpu_requests` in comments. Fixes: f55ffaf89636 ("RISC-V: KVM: Enable ring-based dirty memory tracking") Signed-off-by: Quan Zhou Reviewed-by: Nutty Liu Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/49680363098c45516ec4b305283d662d26fa9386.1754326285.git.zhouquan@iscas.ac.cn Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index f001e56403f9fa..3ebcfffaa97815 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -683,7 +683,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) } /** - * check_vcpu_requests - check and handle pending vCPU requests + * kvm_riscv_check_vcpu_requests - check and handle pending vCPU requests * @vcpu: the VCPU pointer * * Return: 1 if we should enter the guest From 799766208f09f95677a9ab111b93872d414fbad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Tue, 5 Aug 2025 12:44:21 +0200 Subject: [PATCH 0575/1292] RISC-V: KVM: fix stack overrun when loading vlenb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The userspace load can put up to 2048 bits into an xlen bit stack buffer. We want only xlen bits, so check the size beforehand. Fixes: 2fa290372dfe ("RISC-V: KVM: add 'vlenb' Vector CSR") Cc: stable@vger.kernel.org Signed-off-by: Radim KrčmÔř Reviewed-by: Nutty Liu Reviewed-by: Daniel Henrique Barboza Link: https://lore.kernel.org/r/20250805104418.196023-4-rkrcmar@ventanamicro.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_vector.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c index a5f88cb717f3df..05f3cc2d8e311a 100644 --- a/arch/riscv/kvm/vcpu_vector.c +++ b/arch/riscv/kvm/vcpu_vector.c @@ -182,6 +182,8 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu, struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; unsigned long reg_val; + if (reg_size != sizeof(reg_val)) + return -EINVAL; if (copy_from_user(®_val, uaddr, reg_size)) return -EFAULT; if (reg_val != cntx->vector.vlenb) From d3a8ca2ebe6e3f2b1fb0e8e74f909d109a1d77c7 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Fri, 22 Aug 2025 16:33:29 +0800 Subject: [PATCH 0576/1292] platform/x86/amd: hfi: Fix pcct_tbl leak in amd_hfi_metadata_parser() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a permanent ACPI table memory leak when amd_hfi_metadata_parser() fails due to invalid PCCT table length or memory allocation errors. Fixes: d4e95ea7a78e ("platform/x86: hfi: Parse CPU core ranking data from shared memory") Cc: stable@vger.kernel.org Signed-off-by: Zhen Ni Reviewed-by: Mario Limonciello (AMD) Link: https://lore.kernel.org/r/20250822083329.710857-1-zhen.ni@easystack.cn Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/amd/hfi/hfi.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/amd/hfi/hfi.c b/drivers/platform/x86/amd/hfi/hfi.c index 4f56149b377428..a465ac6f607eac 100644 --- a/drivers/platform/x86/amd/hfi/hfi.c +++ b/drivers/platform/x86/amd/hfi/hfi.c @@ -385,12 +385,16 @@ static int amd_hfi_metadata_parser(struct platform_device *pdev, amd_hfi_data->pcct_entry = pcct_entry; pcct_ext = (struct acpi_pcct_ext_pcc_slave *)pcct_entry; - if (pcct_ext->length <= 0) - return -EINVAL; + if (pcct_ext->length <= 0) { + ret = -EINVAL; + goto out; + } amd_hfi_data->shmem = devm_kzalloc(amd_hfi_data->dev, pcct_ext->length, GFP_KERNEL); - if (!amd_hfi_data->shmem) - return -ENOMEM; + if (!amd_hfi_data->shmem) { + ret = -ENOMEM; + goto out; + } pcc_chan->shmem_base_addr = pcct_ext->base_address; pcc_chan->shmem_size = pcct_ext->length; @@ -398,6 +402,8 @@ static int amd_hfi_metadata_parser(struct platform_device *pdev, /* parse the shared memory info from the PCCT table */ ret = amd_hfi_fill_metadata(amd_hfi_data); +out: + /* Don't leak any ACPI memory */ acpi_put_table(pcct_tbl); return ret; From cf3940ac737d05c85395f343fe33a3cfcadb47db Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Fri, 8 Aug 2025 17:47:09 +0200 Subject: [PATCH 0577/1292] platform/x86: asus-wmi: Remove extra keys from ignore_key_wlan quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the ignore_key_wlan quirk applies to keycodes 0x5D, 0x5E, and 0x5F. However, the relevant code for the Asus Zenbook Duo is only 0x5F. Since this code is emitted by other Asus devices, such as from the Z13 for its ROG button, remove the extra codes before expanding the quirk. For the Duo devices, which are the only ones that use this quirk, there should be no effect. Fixes: 9286dfd5735b ("platform/x86: asus-wmi: Fix spurious rfkill on UX8406MA") Signed-off-by: Antheas Kapenekakis Link: https://lore.kernel.org/r/20250808154710.8981-1-lkml@antheas.dev Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/asus-nb-wmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index f84c3d03c1de78..e6726be5890e7f 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -655,8 +655,6 @@ static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, if (atkbd_reports_vol_keys) *code = ASUS_WMI_KEY_IGNORE; break; - case 0x5D: /* Wireless console Toggle */ - case 0x5E: /* Wireless console Enable */ case 0x5F: /* Wireless console Disable */ if (quirks->ignore_key_wlan) *code = ASUS_WMI_KEY_IGNORE; From 132bfcd24925d4d4531a19b87acb8474be82a017 Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Fri, 8 Aug 2025 17:47:10 +0200 Subject: [PATCH 0578/1292] platform/x86: asus-wmi: Fix ROG button mapping, tablet mode on ASUS ROG Z13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On commit 9286dfd5735b ("platform/x86: asus-wmi: Fix spurious rfkill on UX8406MA"), Mathieu adds a quirk for the Zenbook Duo to ignore the code 0x5f (WLAN button disable). On that laptop, this code is triggered when the device keyboard is attached. On the ASUS ROG Z13 2025, this code is triggered when pressing the side button of the device, which is used to open Armoury Crate in Windows. As this is becoming a pattern, where newer Asus laptops use this keycode for emitting events, let's convert the wlan ignore quirk to instead allow emitting codes, so that userspace programs can listen to it and so that it does not interfere with the rfkill state. With this patch, the Z13 wil emit KEY_PROG3 and the Duo will remain unchanged and emit no event. While at it, add a quirk for the Z13 to switch into tablet mode when removing the keyboard. Signed-off-by: Antheas Kapenekakis Link: https://lore.kernel.org/r/20250808154710.8981-2-lkml@antheas.dev Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/asus-nb-wmi.c | 23 +++++++++++++++++++---- drivers/platform/x86/asus-wmi.h | 3 ++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index e6726be5890e7f..6928bb6ae0f3c8 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -147,7 +147,12 @@ static struct quirk_entry quirk_asus_ignore_fan = { }; static struct quirk_entry quirk_asus_zenbook_duo_kbd = { - .ignore_key_wlan = true, + .key_wlan_event = ASUS_WMI_KEY_IGNORE, +}; + +static struct quirk_entry quirk_asus_z13 = { + .key_wlan_event = ASUS_WMI_KEY_ARMOURY, + .tablet_switch_mode = asus_wmi_kbd_dock_devid, }; static int dmi_matched(const struct dmi_system_id *dmi) @@ -539,6 +544,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_zenbook_duo_kbd, }, + { + .callback = dmi_matched, + .ident = "ASUS ROG Z13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow Z13"), + }, + .driver_data = &quirk_asus_z13, + }, {}, }; @@ -636,6 +650,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_IGNORE, 0xCF, }, /* AC mode */ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */ + { KE_KEY, ASUS_WMI_KEY_ARMOURY, { KEY_PROG3 } }, { KE_END, 0}, }; @@ -655,9 +670,9 @@ static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, if (atkbd_reports_vol_keys) *code = ASUS_WMI_KEY_IGNORE; break; - case 0x5F: /* Wireless console Disable */ - if (quirks->ignore_key_wlan) - *code = ASUS_WMI_KEY_IGNORE; + case 0x5F: /* Wireless console Disable / Special Key */ + if (quirks->key_wlan_event) + *code = quirks->key_wlan_event; break; } } diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 018dfde4025e79..5cd4392b964eb8 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -18,6 +18,7 @@ #include #define ASUS_WMI_KEY_IGNORE (-1) +#define ASUS_WMI_KEY_ARMOURY 0xffff01 #define ASUS_WMI_BRN_DOWN 0x2e #define ASUS_WMI_BRN_UP 0x2f @@ -40,7 +41,7 @@ struct quirk_entry { bool wmi_force_als_set; bool wmi_ignore_fan; bool filter_i8042_e1_extended_codes; - bool ignore_key_wlan; + int key_wlan_event; enum asus_wmi_tablet_switch_mode tablet_switch_mode; int wapf; /* From ff2a66d21fd2364ed9396d151115eec59612b200 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Thu, 31 Jul 2025 04:15:27 +0100 Subject: [PATCH 0579/1292] EDAC/altera: Delete an inappropriate dma_free_coherent() call dma_free_coherent() must only be called if the corresponding dma_alloc_coherent() call has succeeded. Calling it when the allocation fails leads to undefined behavior. Delete the wrong call. [ bp: Massage commit message. ] Fixes: 71bcada88b0f3 ("edac: altera: Add Altera SDRAM EDAC support") Signed-off-by: Salah Triki Signed-off-by: Borislav Petkov (AMD) Acked-by: Dinh Nguyen Cc: stable@vger.kernel.org Link: https://lore.kernel.org/aIrfzzqh4IzYtDVC@pc --- drivers/edac/altera_edac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index cae52c654a15c6..7685a8550d4b1f 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -128,7 +128,6 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file, ptemp = dma_alloc_coherent(mci->pdev, 16, &dma_handle, GFP_KERNEL); if (!ptemp) { - dma_free_coherent(mci->pdev, 16, ptemp, dma_handle); edac_printk(KERN_ERR, EDAC_MC, "Inject: Buffer Allocation error\n"); return -ENOMEM; From ae91aea2d2265c88dbed65a07bbaf3c133fe970c Mon Sep 17 00:00:00 2001 From: Junhui Pei Date: Mon, 2 Jun 2025 23:38:41 +0800 Subject: [PATCH 0580/1292] ubsan: Fix incorrect hand-side used in handle __ubsan_handle_divrem_overflow() incorrectly uses the RHS to report. It always reports the same log: division of -1 by -1. But it should report division of LHS by -1. Signed-off-by: Junhui Pei Fixes: c6d308534aef ("UBSAN: run-time undefined behavior sanity checker") Link: https://lore.kernel.org/r/20250602153841.62935-1-paradoxskin233@gmail.com Signed-off-by: Kees Cook --- lib/ubsan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ubsan.c b/lib/ubsan.c index a6ca235dd714f5..456e3dd8f4ea89 100644 --- a/lib/ubsan.c +++ b/lib/ubsan.c @@ -333,18 +333,18 @@ EXPORT_SYMBOL(__ubsan_handle_implicit_conversion); void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs) { struct overflow_data *data = _data; - char rhs_val_str[VALUE_LENGTH]; + char lhs_val_str[VALUE_LENGTH]; if (suppress_report(&data->location)) return; ubsan_prologue(&data->location, "division-overflow"); - val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs); + val_to_string(lhs_val_str, sizeof(lhs_val_str), data->type, lhs); if (type_is_signed(data->type) && get_signed_val(data->type, rhs) == -1) pr_err("division of %s by -1 cannot be represented in type %s\n", - rhs_val_str, data->type->type_name); + lhs_val_str, data->type->type_name); else pr_err("division by zero\n"); From f05995cc6d3bb742a10996036043ade8d1c65ab7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Aug 2025 09:18:58 +0200 Subject: [PATCH 0581/1292] ARM: stacktrace: include asm/sections.h in asm/stacktrace.h The recent kstack erase changes appear to have uncovered an existing issue with a missing header inclusion: In file included from drivers/misc/lkdtm/kstack_erase.c:12: In file included from include/linux/kstack_erase.h:16: arch/arm/include/asm/stacktrace.h:48:21: error: call to undeclared function 'in_entry_text'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 48 | frame->ex_frame = in_entry_text(frame->pc); | ^ Include asm/sections.h here so the compiler can see the in_entry_text() declaration. Fixes: 752ec621ef5c ("ARM: 9234/1: stacktrace: Avoid duplicate saving of exception PC value") Cc: Kees Cook Signed-off-by: Arnd Bergmann Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20250807071902.4077714-1-arnd@kernel.org Signed-off-by: Kees Cook --- arch/arm/include/asm/stacktrace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/stacktrace.h b/arch/arm/include/asm/stacktrace.h index f80a85b091d6c4..ba2f771cca23f3 100644 --- a/arch/arm/include/asm/stacktrace.h +++ b/arch/arm/include/asm/stacktrace.h @@ -2,8 +2,9 @@ #ifndef __ASM_STACKTRACE_H #define __ASM_STACKTRACE_H -#include #include +#include +#include struct stackframe { /* From 0d50f4d6ec5a8fedfd7169417b25672cadd0e652 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 25 Aug 2025 06:23:12 -0700 Subject: [PATCH 0582/1292] thermal: intel: int340x: Add support for power slider Add support for system wide energy performance preference using a SoC slider interface defined via processor thermal PCI device MMIO space. Using Linux platform-profile class API, register a new platform profile. Provide three platform power profile choices: "performance", "balanced" and "low-power". Profile sysfs is located at: /sys/class/platform-profile/platform-profile-* where attribute "name" is presented as "SoC Power Slider". At boot by default the slider is set to balanced mode. This profile is changed by user space based on user preference via power profile daemon or directly writing to the "profile" sysfs attribute. Add a CPU model specific processor thermal device feature PROC_THERMAL_FEATURE_SOC_POWER_SLIDER. When enabled for a CPU model, slider interface is registered. During system suspend callback save slider register and restore during resume callback. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20250825132315.75521-2-srinivas.pandruvada@linux.intel.com [ rjw: Removal of redundant outer parens from one expression ] Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/Kconfig | 1 + .../thermal/intel/int340x_thermal/Makefile | 1 + .../processor_thermal_device.c | 20 ++ .../processor_thermal_device.h | 6 + .../processor_thermal_soc_slider.c | 194 ++++++++++++++++++ 5 files changed, 222 insertions(+) create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig index 4c699f0896b576..4ced7bdcd62c62 100644 --- a/drivers/thermal/intel/int340x_thermal/Kconfig +++ b/drivers/thermal/intel/int340x_thermal/Kconfig @@ -12,6 +12,7 @@ config INT340X_THERMAL select ACPI_THERMAL_LIB select INTEL_SOC_DTS_IOSF_CORE select INTEL_TCC + select ACPI_PLATFORM_PROFILE select PROC_THERMAL_MMIO_RAPL if POWERCAP help Newer laptops and tablets that use ACPI may have thermal sensors and diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile index 184318d1792b92..436be34b21a92a 100644 --- a/drivers/thermal/intel/int340x_thermal/Makefile +++ b/drivers/thermal/intel/int340x_thermal/Makefile @@ -14,5 +14,6 @@ obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_req.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_hint.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_power_floor.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_soc_slider.o obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 29fcece48cad84..48e7849d48160e 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -338,10 +338,17 @@ static int tcc_offset_save = -1; int proc_thermal_suspend(struct device *dev) { + struct proc_thermal_device *proc_dev; + tcc_offset_save = intel_tcc_get_offset(-1); if (tcc_offset_save < 0) dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save); + proc_dev = dev_get_drvdata(dev); + + if (proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) + proc_thermal_soc_power_slider_suspend(proc_dev); + return 0; } EXPORT_SYMBOL_GPL(proc_thermal_suspend); @@ -357,6 +364,9 @@ int proc_thermal_resume(struct device *dev) if (tcc_offset_save >= 0) intel_tcc_set_offset(-1, tcc_offset_save); + if (proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) + proc_thermal_soc_power_slider_resume(proc_dev); + return 0; } EXPORT_SYMBOL_GPL(proc_thermal_resume); @@ -432,8 +442,18 @@ int proc_thermal_mmio_add(struct pci_dev *pdev, } } + if (feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) { + ret = proc_thermal_soc_power_slider_add(pdev, proc_priv); + if (ret) { + dev_info(&pdev->dev, "failed to add soc power efficiency slider\n"); + goto err_rem_wlt; + } + } + return 0; +err_rem_wlt: + proc_thermal_wt_hint_remove(pdev); err_rem_rfim: proc_thermal_rfim_remove(pdev); err_rem_ptc: diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index 49398794124a26..30760475102feb 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -69,6 +69,7 @@ struct rapl_mmio_regs { #define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40 #define PROC_THERMAL_FEATURE_MSI_SUPPORT 0x80 #define PROC_THERMAL_FEATURE_PTC 0x100 +#define PROC_THERMAL_FEATURE_SOC_POWER_SLIDER 0x200 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL) int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); @@ -127,4 +128,9 @@ int proc_thermal_mmio_add(struct pci_dev *pdev, void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); void proc_thermal_ptc_remove(struct pci_dev *pdev); + +int proc_thermal_soc_power_slider_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); +void proc_thermal_soc_power_slider_suspend(struct proc_thermal_device *proc_priv); +void proc_thermal_soc_power_slider_resume(struct proc_thermal_device *proc_priv); + #endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c new file mode 100644 index 00000000000000..57782a63b9b50b --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Processor Thermal Device Interface for Reading and Writing + * SoC Power Slider Values from User Space. + * + * Operation: + * The SOC_EFFICIENCY_SLIDER_0_0_0_MCHBAR register is accessed + * using the MMIO (Memory-Mapped I/O) interface with an MMIO offset of 0x5B38. + * Although this register is 64 bits wide, only bits 7:0 are used, + * and the other bits remain unchanged. + * + * Bit definitions + * + * Bits 2:0 (Slider value): + * The SoC optimizer slider value indicates the system wide energy performance + * hint. The slider has no specific units and ranges from 0 (highest + * performance) to 6 (highest energy efficiency). Value of 7 is reserved. + * Bits 3 : Reserved + * Bits 6:4 (Offset) + * Offset allows the SoC to automatically switch slider position in range + * [slider value (bits 2:0) + offset] to improve power efficiency based on + * internal SoC algorithms. + * Bit 7 (Enable): + * If this bit is set, the SoC Optimization sliders will be processed by the + * SoC firmware. + * + * Copyright (c) 2025, Intel Corporation. + */ + +#include +#include +#include +#include "processor_thermal_device.h" + +#define SOC_POWER_SLIDER_OFFSET 0x5B38 + +enum power_slider_preference { + SOC_POWER_SLIDER_PERFORMANCE, + SOC_POWER_SLIDER_BALANCE, + SOC_POWER_SLIDER_POWERSAVE, +}; + +#define SOC_SLIDER_VALUE_MINIMUM 0x00 +#define SOC_SLIDER_VALUE_BALANCE 0x03 +#define SOC_SLIDER_VALUE_MAXIMUM 0x06 + +#define SLIDER_MASK GENMASK_ULL(2, 0) +#define SLIDER_ENABLE_BIT 7 + +static u8 slider_values[] = { + [SOC_POWER_SLIDER_PERFORMANCE] = SOC_SLIDER_VALUE_MINIMUM, + [SOC_POWER_SLIDER_BALANCE] = SOC_SLIDER_VALUE_BALANCE, + [SOC_POWER_SLIDER_POWERSAVE] = SOC_SLIDER_VALUE_MAXIMUM, +}; + +/* Convert from platform power profile option to SoC slider value */ +static int convert_profile_to_power_slider(enum platform_profile_option profile) +{ + switch (profile) { + case PLATFORM_PROFILE_LOW_POWER: + return slider_values[SOC_POWER_SLIDER_POWERSAVE]; + case PLATFORM_PROFILE_BALANCED: + return slider_values[SOC_POWER_SLIDER_BALANCE]; + case PLATFORM_PROFILE_PERFORMANCE: + return slider_values[SOC_POWER_SLIDER_PERFORMANCE]; + default: + break; + } + + return -EOPNOTSUPP; +} + +/* Convert to platform power profile option from SoC slider values */ +static int convert_power_slider_to_profile(u8 slider) +{ + if (slider == slider_values[SOC_POWER_SLIDER_PERFORMANCE]) + return PLATFORM_PROFILE_PERFORMANCE; + if (slider == slider_values[SOC_POWER_SLIDER_BALANCE]) + return PLATFORM_PROFILE_BALANCED; + if (slider == slider_values[SOC_POWER_SLIDER_POWERSAVE]) + return PLATFORM_PROFILE_LOW_POWER; + + return -EOPNOTSUPP; +} + +static inline u64 read_soc_slider(struct proc_thermal_device *proc_priv) +{ + return readq(proc_priv->mmio_base + SOC_POWER_SLIDER_OFFSET); +} + +static inline void write_soc_slider(struct proc_thermal_device *proc_priv, u64 val) +{ + writeq(val, proc_priv->mmio_base + SOC_POWER_SLIDER_OFFSET); +} + +static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int slider) +{ + u64 val; + + val = read_soc_slider(proc_priv); + val &= ~SLIDER_MASK; + val |= FIELD_PREP(SLIDER_MASK, slider) | BIT(SLIDER_ENABLE_BIT); + write_soc_slider(proc_priv, val); +} + +/* profile get/set callbacks are called with a profile lock, so no need for local locks */ + +static int power_slider_platform_profile_set(struct device *dev, + enum platform_profile_option profile) +{ + struct proc_thermal_device *proc_priv; + int slider; + + proc_priv = dev_get_drvdata(dev); + if (!proc_priv) + return -EOPNOTSUPP; + + slider = convert_profile_to_power_slider(profile); + if (slider < 0) + return slider; + + set_soc_power_profile(proc_priv, slider); + + return 0; +} + +static int power_slider_platform_profile_get(struct device *dev, + enum platform_profile_option *profile) +{ + struct proc_thermal_device *proc_priv; + int slider, ret; + u64 val; + + proc_priv = dev_get_drvdata(dev); + if (!proc_priv) + return -EOPNOTSUPP; + + val = read_soc_slider(proc_priv); + slider = FIELD_GET(SLIDER_MASK, val); + + ret = convert_power_slider_to_profile(slider); + if (ret < 0) + return ret; + + *profile = ret; + + return 0; +} + +static int power_slider_platform_profile_probe(void *drvdata, unsigned long *choices) +{ + set_bit(PLATFORM_PROFILE_LOW_POWER, choices); + set_bit(PLATFORM_PROFILE_BALANCED, choices); + set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); + + return 0; +} + +static const struct platform_profile_ops power_slider_platform_profile_ops = { + .probe = power_slider_platform_profile_probe, + .profile_get = power_slider_platform_profile_get, + .profile_set = power_slider_platform_profile_set, +}; + +int proc_thermal_soc_power_slider_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) +{ + struct device *ppdev; + + set_soc_power_profile(proc_priv, slider_values[SOC_POWER_SLIDER_BALANCE]); + + ppdev = devm_platform_profile_register(&pdev->dev, "SoC Power Slider", proc_priv, + &power_slider_platform_profile_ops); + + return PTR_ERR_OR_ZERO(ppdev); +} +EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_add, "INT340X_THERMAL"); + +static u64 soc_slider_save; + +void proc_thermal_soc_power_slider_suspend(struct proc_thermal_device *proc_priv) +{ + soc_slider_save = read_soc_slider(proc_priv); +} +EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_suspend, "INT340X_THERMAL"); + +void proc_thermal_soc_power_slider_resume(struct proc_thermal_device *proc_priv) +{ + write_soc_slider(proc_priv, soc_slider_save); +} +EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_resume, "INT340X_THERMAL"); + +MODULE_IMPORT_NS("INT340X_THERMAL"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Processor Thermal Power Slider Interface"); From 018d046a1a2cdf917bd8e3b6a3fdab6ce7aa698b Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 25 Aug 2025 06:23:13 -0700 Subject: [PATCH 0583/1292] thermal: intel: int340x: Enable power slider interface for Panther Lake Set the PROC_THERMAL_FEATURE_SOC_POWER_SLIDER feature flag in proc_thermal_pci_ids[] for Panther Lake to enable power slider interface. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20250825132315.75521-3-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki --- .../intel/int340x_thermal/processor_thermal_device_pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c index d4d7e8e147d2b9..e2471768d355f0 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -498,7 +498,8 @@ static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, PTL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT | - PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) }, + PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC | + PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) }, { PCI_DEVICE_DATA(INTEL, WCL_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_HINT | From 4a64a748e45cded20443ad54826ac78b3967de15 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 25 Aug 2025 06:23:14 -0700 Subject: [PATCH 0584/1292] thermal: intel: int340x: Add module parameter for balanced Slider By default, the SoC slider value for the "balanced" platform profile is set to 3. This update introduces a new module parameter, allowing users to modify this default value. The module parameter can be specified during load time to set a custom slider value for the "balanced" profile. If the module parameter is not specified at load time and is updated later, the new value will only take effect after the next write of "balanced" to the sysfs "profile" attribute. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20250825132315.75521-4-srinivas.pandruvada@linux.intel.com [ rjw: Minor adjustments of module param description ] Signed-off-by: Rafael J. Wysocki --- .../processor_thermal_soc_slider.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c index 57782a63b9b50b..ffbad6b4326ea9 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c @@ -53,6 +53,43 @@ static u8 slider_values[] = { [SOC_POWER_SLIDER_POWERSAVE] = SOC_SLIDER_VALUE_MAXIMUM, }; +/* Lock to protect module param updates */ +static DEFINE_MUTEX(slider_param_lock); + +static int slider_balanced_param = SOC_SLIDER_VALUE_BALANCE; + +static int slider_def_balance_set(const char *arg, const struct kernel_param *kp) +{ + u8 slider_val; + int ret; + + guard(mutex)(&slider_param_lock); + + ret = kstrtou8(arg, 16, &slider_val); + if (!ret) { + if (slider_val > SOC_SLIDER_VALUE_MAXIMUM) + return -EINVAL; + + slider_balanced_param = slider_val; + } + + return ret; +} + +static int slider_def_balance_get(char *buf, const struct kernel_param *kp) +{ + guard(mutex)(&slider_param_lock); + return sysfs_emit(buf, "%02x\n", slider_values[SOC_POWER_SLIDER_BALANCE]); +} + +static const struct kernel_param_ops slider_def_balance_ops = { + .set = slider_def_balance_set, + .get = slider_def_balance_get, +}; + +module_param_cb(slider_balance, &slider_def_balance_ops, NULL, 0644); +MODULE_PARM_DESC(slider_balance, "Set slider default value for balance"); + /* Convert from platform power profile option to SoC slider value */ static int convert_profile_to_power_slider(enum platform_profile_option profile) { @@ -115,6 +152,10 @@ static int power_slider_platform_profile_set(struct device *dev, if (!proc_priv) return -EOPNOTSUPP; + guard(mutex)(&slider_param_lock); + + slider_values[SOC_POWER_SLIDER_BALANCE] = slider_balanced_param; + slider = convert_profile_to_power_slider(profile); if (slider < 0) return slider; From 8306bcaba06dfa658e3dd852e930b0154cb46c9f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 25 Aug 2025 06:23:15 -0700 Subject: [PATCH 0585/1292] thermal: intel: int340x: Add module parameter to change slider offset SoC slider value is set by the user (or the default when user has not modified it). To enhance power efficiency dynamically, the firmware can optionally auto-adjust the slider value based on the current workload. This adjustment is governed by an additional parameter known as the "slider offset". This offset permits the firmware to increase the slider value up to and including "SoC slider + slider offset". Add a module parameter to specify this "slier offset" value. By default, the SoC slider offset is set to 0. This means that SoC is not allowed to switch slider position. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20250825132315.75521-5-srinivas.pandruvada@linux.intel.com [ rjw: Comment and module param description adjustments ] Signed-off-by: Rafael J. Wysocki --- .../processor_thermal_soc_slider.c | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c index ffbad6b4326ea9..20d70cb0154201 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c @@ -90,6 +90,47 @@ static const struct kernel_param_ops slider_def_balance_ops = { module_param_cb(slider_balance, &slider_def_balance_ops, NULL, 0644); MODULE_PARM_DESC(slider_balance, "Set slider default value for balance"); +static u8 slider_offset; + +static int slider_def_offset_set(const char *arg, const struct kernel_param *kp) +{ + u8 offset; + int ret; + + guard(mutex)(&slider_param_lock); + + ret = kstrtou8(arg, 16, &offset); + if (!ret) { + if (offset > SOC_SLIDER_VALUE_MAXIMUM) + return -EINVAL; + + slider_offset = offset; + } + + return ret; +} + +static int slider_def_offset_get(char *buf, const struct kernel_param *kp) +{ + guard(mutex)(&slider_param_lock); + return sysfs_emit(buf, "%02x\n", slider_offset); +} + +static const struct kernel_param_ops slider_offset_ops = { + .set = slider_def_offset_set, + .get = slider_def_offset_get, +}; + +/* + * To enhance power efficiency dynamically, the firmware can optionally + * auto-adjust the slider value based on the current workload. This + * adjustment is controlled by the "slider_offset" module parameter. + * This offset permits the firmware to increase the slider value + * up to and including "SoC slider + slider offset,". + */ +module_param_cb(slider_offset, &slider_offset_ops, NULL, 0644); +MODULE_PARM_DESC(slider_offset, "Set slider offset"); + /* Convert from platform power profile option to SoC slider value */ static int convert_profile_to_power_slider(enum platform_profile_option profile) { @@ -130,6 +171,8 @@ static inline void write_soc_slider(struct proc_thermal_device *proc_priv, u64 v writeq(val, proc_priv->mmio_base + SOC_POWER_SLIDER_OFFSET); } +#define SLIDER_OFFSET_MASK GENMASK_ULL(6, 4) + static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int slider) { u64 val; @@ -137,6 +180,11 @@ static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int sli val = read_soc_slider(proc_priv); val &= ~SLIDER_MASK; val |= FIELD_PREP(SLIDER_MASK, slider) | BIT(SLIDER_ENABLE_BIT); + + /* Set the slider offset from module params */ + val &= ~SLIDER_OFFSET_MASK; + val |= FIELD_PREP(SLIDER_OFFSET_MASK, slider_offset); + write_soc_slider(proc_priv, val); } From d14469ed7c00314fe8957b2841bda329e4eaf4ab Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Mon, 25 Aug 2025 17:32:05 +0800 Subject: [PATCH 0586/1292] loop: fix zero sized loop for block special file By default, /dev/sda is block special file from devtmpfs, getattr will return file size as zero, causing loop failed for raw block device. We can add bdev_statx() to return device size, however this may introduce changes that are not acknowledged by user. Fix this problem by reverting changes for block special file, file mapping host is set to bdev inode while opening, and use i_size_read() directly to get device size. Fixes: 47b71abd5846 ("loop: use vfs_getattr_nosec for accurate file size") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202508200409.b2459c02-lkp@intel.com Signed-off-by: Yu Kuai Reviewed-by: Ming Lei Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20250825093205.3684121-1-yukuai1@huaweicloud.com [axboe: fix spelling error] Signed-off-by: Jens Axboe --- drivers/block/loop.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 57263c273f0fb4..053a086d547ec6 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -139,20 +139,26 @@ static int part_shift; static loff_t lo_calculate_size(struct loop_device *lo, struct file *file) { - struct kstat stat; loff_t loopsize; int ret; - /* - * Get the accurate file size. This provides better results than - * cached inode data, particularly for network filesystems where - * metadata may be stale. - */ - ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0); - if (ret) - return 0; + if (S_ISBLK(file_inode(file)->i_mode)) { + loopsize = i_size_read(file->f_mapping->host); + } else { + struct kstat stat; + + /* + * Get the accurate file size. This provides better results than + * cached inode data, particularly for network filesystems where + * metadata may be stale. + */ + ret = vfs_getattr_nosec(&file->f_path, &stat, STATX_SIZE, 0); + if (ret) + return 0; + + loopsize = stat.size; + } - loopsize = stat.size; if (lo->lo_offset > 0) loopsize -= lo->lo_offset; /* offset is beyond i_size, weird but possible */ From 3bc3dc166dd23404bb2091292cd4e17f87678ca6 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 3 Aug 2025 21:18:11 +0200 Subject: [PATCH 0587/1292] ACPI: PM: Add power resource init function This way DMI based quirk matching and quirk flag initialization can be done just once - in the newly introduced acpi_power_resources_init() function, which is similar to existing acpi_*_init() functions. Convert the single already existing DMI match-based quirk in this ACPI power resource handler ("leave unused power resources on" quirk) to such one-time initialization in acpi_power_resources_init() function instead of re-running that DMI match each time acpi_turn_off_unused_power_resources() gets called. Signed-off-by: Maciej S. Szmigiero Link: https://patch.msgid.link/b173a6987f0b35597fd82400cb28f289786e03d0.1754243159.git.mail@maciej.szmigiero.name Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 1 + drivers/acpi/power.c | 10 +++++++++- drivers/acpi/scan.c | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index e2781864fdcebd..63354972ab0b8a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -140,6 +140,7 @@ int __acpi_device_uevent_modalias(const struct acpi_device *adev, /* -------------------------------------------------------------------------- Power Resource -------------------------------------------------------------------------- */ +void acpi_power_resources_init(void); void acpi_power_resources_list_free(struct list_head *list); int acpi_extract_power_resources(union acpi_object *package, unsigned int start, struct list_head *list); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index b7243d7563b1bb..cd9380b1f9516b 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -63,6 +63,8 @@ struct acpi_power_resource_entry { struct acpi_power_resource *resource; }; +static bool unused_power_resources_quirk; + static LIST_HEAD(acpi_power_resource_list); static DEFINE_MUTEX(power_resource_list_lock); @@ -1046,7 +1048,7 @@ void acpi_turn_off_unused_power_resources(void) { struct acpi_power_resource *resource; - if (dmi_check_system(dmi_leave_unused_power_resources_on)) + if (unused_power_resources_quirk) return; mutex_lock(&power_resource_list_lock); @@ -1065,3 +1067,9 @@ void acpi_turn_off_unused_power_resources(void) mutex_unlock(&power_resource_list_lock); } + +void __init acpi_power_resources_init(void) +{ + unused_power_resources_quirk = + dmi_check_system(dmi_leave_unused_power_resources_on); +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fb1fe9f3b1a366..bb74e783443589 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2702,6 +2702,7 @@ void __init acpi_scan_init(void) acpi_memory_hotplug_init(); acpi_watchdog_init(); acpi_pnp_init(); + acpi_power_resources_init(); acpi_int340x_thermal_init(); acpi_init_lpit(); From 0467ed880a17c276c52e442c2454c7c16973a902 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 3 Aug 2025 21:18:12 +0200 Subject: [PATCH 0588/1292] ACPI: PM: Add HP EliteBook 855 G7 WWAN modem power resource quirk This laptop (and possibly similar models too) has power resource called "GP12.PXP_" for its Intel XMM7360 WWAN modem. For this power resource to turn ON power for the modem it needs certain internal flag called "ONEN" to be set: Method (_ON, 0, NotSerialized) // _ON_: Power On { If (^^^LPCB.EC0.ECRG) { If ((ONEN == Zero)) { Return (Zero) } (..) } } This flag only gets set from this power resource _OFF method, while the actual modem power gets turned off during suspend by "GP12.PTS" method called from the global _PTS (Prepare To Sleep) method. In fact, this power resource _OFF method implementation just sets the aforementioned flag: Method (_OFF, 0, NotSerialized) // _OFF: Power Off { OFEN = Zero ONEN = One } Upon hibernation finish, the kernel tries to set this power resource back ON since its _STA method returns 0 and the resource is still considered in use as it is declared as required for D0 for both the modem ACPI device (GP12.PWAN) and its parent PCIe port ACPI device object (GP12). But the _ON method won't do anything since that "ONEN" flag is not set. Overall, this means the modem is dead after hibernation finish until the laptop is rebooted since the modem power has been cut by _PTS and its PCI configuration was lost and not able to be restored. The easiest way to workaround this issue is to call this power resource _OFF method before calling the _ON method to make sure the "ONEN" flag gets properly set. This makes the modem alive once again after hibernation finish - with properly restored PCI configuration space. Since this platform does *not* support S3 the fact that acpi_resume_power_resources() is also called during resume from S3 is not a problem there. Do the DMI based quirk matching and quirk flag initialization just once - in acpi_power_resources_init() function. This way the whole resume path overhead of this change on other systems amounts to simple hp_eb_gp12pxp_quirk flag comparison. Signed-off-by: Maciej S. Szmigiero Link: https://patch.msgid.link/c6ff6931c5d27592052f30339de1b9cc298c43f0.1754243159.git.mail@maciej.szmigiero.name [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 80 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index cd9380b1f9516b..361a7721a6a873 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -23,6 +23,7 @@ #define pr_fmt(fmt) "ACPI: PM: " fmt +#include #include #include #include @@ -63,6 +64,7 @@ struct acpi_power_resource_entry { struct acpi_power_resource *resource; }; +static bool hp_eb_gp12pxp_quirk; static bool unused_power_resources_quirk; static LIST_HEAD(acpi_power_resource_list); @@ -994,6 +996,38 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) } #ifdef CONFIG_ACPI_SLEEP +static bool resource_is_gp12pxp(acpi_handle handle) +{ + const char *path; + bool ret; + + path = acpi_handle_path(handle); + ret = path && strcmp(path, "\\_SB_.PCI0.GP12.PXP_") == 0; + kfree(path); + + return ret; +} + +static void acpi_resume_on_eb_gp12pxp(struct acpi_power_resource *resource) +{ + acpi_handle_notice(resource->device.handle, + "HP EB quirk - turning OFF then ON\n"); + + __acpi_power_off(resource); + __acpi_power_on(resource); + + /* + * Use the same delay as DSDT uses in modem _RST method. + * + * Otherwise we get "Unable to change power state from unknown to D0, + * device inaccessible" error for the modem PCI device after thaw. + * + * This power resource is normally being enabled only during thaw (once) + * so this wait is not a performance issue. + */ + msleep(200); +} + void acpi_resume_power_resources(void) { struct acpi_power_resource *resource; @@ -1015,8 +1049,14 @@ void acpi_resume_power_resources(void) if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count) { - acpi_handle_debug(resource->device.handle, "Turning ON\n"); - __acpi_power_on(resource); + if (hp_eb_gp12pxp_quirk && + resource_is_gp12pxp(resource->device.handle)) { + acpi_resume_on_eb_gp12pxp(resource); + } else { + acpi_handle_debug(resource->device.handle, + "Turning ON\n"); + __acpi_power_on(resource); + } } mutex_unlock(&resource->resource_lock); @@ -1026,6 +1066,41 @@ void acpi_resume_power_resources(void) } #endif +static const struct dmi_system_id dmi_hp_elitebook_gp12pxp_quirk[] = { +/* + * This laptop (and possibly similar models too) has power resource called + * "GP12.PXP_" for its WWAN modem. + * + * For this power resource to turn ON power for the modem it needs certain + * internal flag called "ONEN" to be set. + * This flag only gets set from this power resource "_OFF" method, while the + * actual modem power gets turned off during suspend by "GP12.PTS" method + * called from the global "_PTS" (Prepare To Sleep) method. + * On the other hand, this power resource "_OFF" method implementation just + * sets the aforementioned flag without actually doing anything else (it + * doesn't contain any code to actually turn off power). + * + * The above means that when upon hibernation finish we try to set this + * power resource back ON since its "_STA" method returns 0 (while the resource + * is still considered in use) its "_ON" method won't do anything since + * that "ONEN" flag is not set. + * Overall, this means the modem is dead until laptop is rebooted since its + * power has been cut by "_PTS" and its PCI configuration was lost and not able + * to be restored. + * + * The easiest way to workaround the issue is to call this power resource + * "_OFF" method before calling the "_ON" method to make sure the "ONEN" + * flag gets properly set. + */ + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 855 G7 Notebook PC"), + }, + }, + {} +}; + static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = { { /* @@ -1070,6 +1145,7 @@ void acpi_turn_off_unused_power_resources(void) void __init acpi_power_resources_init(void) { + hp_eb_gp12pxp_quirk = dmi_check_system(dmi_hp_elitebook_gp12pxp_quirk); unused_power_resources_quirk = dmi_check_system(dmi_leave_unused_power_resources_on); } From 0e08fa789d39aa01923e3ba144bd808291895c3c Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 23 Aug 2025 21:15:59 -0500 Subject: [PATCH 0589/1292] smb3 client: fix return code mapping of remap_file_range We were returning -EOPNOTSUPP for various remap_file_range cases but for some of these the copy_file_range_syscall() requires -EINVAL to be returned (e.g. where source and target file ranges overlap when source and target are the same file). This fixes xfstest generic/157 which was expecting EINVAL for that (and also e.g. for when the src offset is beyond end of file). Cc: stable@vger.kernel.org Acked-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French --- fs/smb/client/cifsfs.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 3bd85ab2deb192..e1848276bab413 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1358,6 +1358,20 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, truncate_setsize(target_inode, new_size); fscache_resize_cookie(cifs_inode_cookie(target_inode), new_size); + } else if (rc == -EOPNOTSUPP) { + /* + * copy_file_range syscall man page indicates EINVAL + * is returned e.g when "fd_in and fd_out refer to the + * same file and the source and target ranges overlap." + * Test generic/157 was what showed these cases where + * we need to remap EOPNOTSUPP to EINVAL + */ + if (off >= src_inode->i_size) { + rc = -EINVAL; + } else if (src_inode == target_inode) { + if (off + len > destoff) + rc = -EINVAL; + } } if (rc == 0 && new_size > target_cifsi->netfs.zero_point) target_cifsi->netfs.zero_point = new_size; From ac46f5b6c6614668727732e117842c9fa7a42c19 Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Mon, 11 Aug 2025 14:45:05 +0100 Subject: [PATCH 0590/1292] ACPICA: Add SoundWire File Table (SWFT) signature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The File Download (FDL) process of SoundWire Class Audio (SDCA) driver, which provides code/data which may be required by an SDCA device, utilizes SWFT to obtain that code/data. There is a single SWFT for the system, and SWFT can contain multiple files (information about the file as well as its binary contents). The SWFT has a standard ACPI Descriptor Table Header, followed by SoundWire File definitions as described in Discovery and Configuration (DisCo) Specification for SoundWireĀ® Link: https://github.com/acpica/acpica/commit/18c96022 Signed-off-by: Maciej Strozek Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20250811134505.1162661-1-mstrozek@opensource.cirrus.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/tables.c | 2 +- include/acpi/actbl2.h | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index fa9bb8c8ce9534..57fc8bc56166b6 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -408,7 +408,7 @@ static const char table_sigs[][ACPI_NAMESEG_SIZE] __nonstring_array __initconst ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI, - ACPI_SIG_NBFT }; + ACPI_SIG_NBFT, ACPI_SIG_SWFT}; #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 048f5f47f8b88c..f726bce3eb8494 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -57,6 +57,7 @@ #define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */ #define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */ #define ACPI_SIG_SVKL "SVKL" /* Storage Volume Key Location Table */ +#define ACPI_SIG_SWFT "SWFT" /* SoundWire File Table */ #define ACPI_SIG_TDEL "TDEL" /* TD Event Log Table */ /* @@ -3478,6 +3479,26 @@ enum acpi_svkl_format { ACPI_SVKL_FORMAT_RESERVED = 1 /* 1 and greater are reserved */ }; +/******************************************************************************* + * SWFT - SoundWire File Table + * + * Conforms to "Discovery and Configuration (DisCo) Specification for SoundWire" + * Version 2.1, 2 October 2023 + * + ******************************************************************************/ +struct acpi_sw_file { + u16 vendor_id; + u32 file_id; + u16 file_version; + u32 file_length; + u8 data[]; +}; + +struct acpi_table_swft { + struct acpi_table_header header; + struct acpi_sw_file files[]; +}; + /******************************************************************************* * * TDEL - TD-Event Log From b4efccec8d06ceb10a7d34d7b1c449c569d53770 Mon Sep 17 00:00:00 2001 From: Li Qiong Date: Mon, 4 Aug 2025 10:57:59 +0800 Subject: [PATCH 0591/1292] mm/slub: avoid accessing metadata when pointer is invalid in object_err() object_err() reports details of an object for further debugging, such as the freelist pointer, redzone, etc. However, if the pointer is invalid, attempting to access object metadata can lead to a crash since it does not point to a valid object. One known path to the crash is when alloc_consistency_checks() determines the pointer to the allocated object is invalid because of a freelist corruption, and calls object_err() to report it. The debug code should report and handle the corruption gracefully and not crash in the process. In case the pointer is NULL or check_valid_pointer() returns false for the pointer, only print the pointer value and skip accessing metadata. Fixes: 81819f0fc828 ("SLUB core") Cc: Signed-off-by: Li Qiong Reviewed-by: Harry Yoo Reviewed-by: Matthew Wilcox (Oracle) Signed-off-by: Vlastimil Babka --- mm/slub.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index 30003763d224c2..1787e4d51e483d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1140,7 +1140,12 @@ static void object_err(struct kmem_cache *s, struct slab *slab, return; slab_bug(s, reason); - print_trailer(s, slab, object); + if (!object || !check_valid_pointer(s, slab, object)) { + print_slab_info(slab); + pr_err("Invalid pointer 0x%p\n", object); + } else { + print_trailer(s, slab, object); + } add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); WARN_ON(1); From 24963ae1b0b6596dc36e352c18593800056251d8 Mon Sep 17 00:00:00 2001 From: Suchit Karunakaran Date: Sat, 16 Aug 2025 12:21:26 +0530 Subject: [PATCH 0592/1292] x86/cpu/intel: Fix the constant_tsc model check for Pentium 4 Pentium 4's which are INTEL_P4_PRESCOTT (model 0x03) and later have a constant TSC. This was correctly captured until commit fadb6f569b10 ("x86/cpu/intel: Limit the non-architectural constant_tsc model checks"). In that commit, an error was introduced while selecting the last P4 model (0x06) as the upper bound. Model 0x06 was transposed to INTEL_P4_WILLAMETTE, which is just plain wrong. That was presumably a simple typo, probably just copying and pasting the wrong P4 model. Fix the constant TSC logic to cover all later P4 models. End at INTEL_P4_CEDARMILL which accurately corresponds to the last P4 model. Fixes: fadb6f569b10 ("x86/cpu/intel: Limit the non-architectural constant_tsc model checks") Signed-off-by: Suchit Karunakaran Signed-off-by: Dave Hansen Reviewed-by: Sohil Mehta Cc:stable@vger.kernel.org Link: https://lore.kernel.org/all/20250816065126.5000-1-suchitkarunakaran%40gmail.com --- arch/x86/kernel/cpu/intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 076eaa41b8c81b..98ae4c37c93ecc 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -262,7 +262,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) if (c->x86_power & (1 << 8)) { set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC); - } else if ((c->x86_vfm >= INTEL_P4_PRESCOTT && c->x86_vfm <= INTEL_P4_WILLAMETTE) || + } else if ((c->x86_vfm >= INTEL_P4_PRESCOTT && c->x86_vfm <= INTEL_P4_CEDARMILL) || (c->x86_vfm >= INTEL_CORE_YONAH && c->x86_vfm <= INTEL_IVYBRIDGE)) { set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); } From b8db5517fe5265d68abbceb3200fba1aecac4d5f Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Mon, 18 Aug 2025 16:24:51 +0800 Subject: [PATCH 0593/1292] PNP: isapnp: use str_plural() to simplify the code Use the string choice helper function str_plural() to simplify the code. Signed-off-by: Xichao Zhao Link: https://patch.msgid.link/20250818082451.497935-1-zhao.xichao@vivo.com Signed-off-by: Rafael J. Wysocki --- drivers/pnp/isapnp/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index d2ff76e74a0558..219f96f2aaaf45 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "../base.h" @@ -1037,7 +1038,7 @@ static int __init isapnp_init(void) if (cards) printk(KERN_INFO "isapnp: %i Plug & Play card%s detected total\n", cards, - cards > 1 ? "s" : ""); + str_plural(cards)); else printk(KERN_INFO "isapnp: No Plug & Play card found\n"); From 66e82b6e0a28d4970383e1ee5d60f431001128cd Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 12 Aug 2025 19:10:02 -0500 Subject: [PATCH 0594/1292] drm/nouveau: fix error path in nvkm_gsp_fwsec_v2 Function nvkm_gsp_fwsec_v2() sets 'ret' if the kmemdup() call fails, but it never uses or returns 'ret' after that point. We always need to release the firmware regardless, so do that and then check for error. Fixes: 176fdcbddfd2 ("drm/nouveau/gsp/r535: add support for booting GSP-RM") Cc: stable@vger.kernel.org # v6.7+ Signed-off-by: Timur Tabi Link: https://lore.kernel.org/r/20250813001004.2986092-1-ttabi@nvidia.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c index 52412965fac107..5b721bd9d79949 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c @@ -209,11 +209,12 @@ nvkm_gsp_fwsec_v2(struct nvkm_gsp *gsp, const char *name, fw->boot_addr = bld->start_tag << 8; fw->boot_size = bld->code_size; fw->boot = kmemdup(bl->data + hdr->data_offset + bld->code_off, fw->boot_size, GFP_KERNEL); - if (!fw->boot) - ret = -ENOMEM; nvkm_firmware_put(bl); + if (!fw->boot) + return -ENOMEM; + /* Patch in interface data. */ return nvkm_gsp_fwsec_patch(gsp, fw, desc->InterfaceOffset, init_cmd); } From f529b8915543fb9ceb732cec5571f7fe12bc9530 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 12 Aug 2025 19:10:03 -0500 Subject: [PATCH 0595/1292] drm/nouveau: remove unused increment in gm200_flcn_pio_imem_wr The 'tag' parameter is passed by value and is not actually used after being incremented, so remove the increment. It's the function that calls gm200_flcn_pio_imem_wr that is supposed to (and does) increment 'tag'. Fixes: 0e44c2170876 ("drm/nouveau/flcn: new code to load+boot simple HS FWs (VPR scrubber)") Reviewed-by: Philipp Stanner Signed-off-by: Timur Tabi Link: https://lore.kernel.org/r/20250813001004.2986092-2-ttabi@nvidia.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c index b7da3ab44c277d..6a004c6e674255 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c @@ -103,7 +103,7 @@ gm200_flcn_pio_imem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 i static void gm200_flcn_pio_imem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag) { - nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag++); + nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag); while (len >= 4) { nvkm_falcon_wr32(falcon, 0x184 + (port * 0x10), *(u32 *)img); img += 4; From 64c722b5e7f6b909b0e448e580f64628a0d76208 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 12 Aug 2025 19:10:04 -0500 Subject: [PATCH 0596/1292] drm/nouveau: remove unused memory target test The memory target check is a hold-over from a refactor. It's harmless but distracting, so just remove it. Fixes: 2541626cfb79 ("drm/nouveau/acr: use common falcon HS FW code for ACR FWs") Signed-off-by: Timur Tabi Link: https://lore.kernel.org/r/20250813001004.2986092-3-ttabi@nvidia.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c index 6a004c6e674255..7c43397c19e61d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c @@ -249,9 +249,11 @@ int gm200_flcn_fw_load(struct nvkm_falcon_fw *fw) { struct nvkm_falcon *falcon = fw->falcon; - int target, ret; + int ret; if (fw->inst) { + int target; + nvkm_falcon_mask(falcon, 0x048, 0x00000001, 0x00000001); switch (nvkm_memory_target(fw->inst)) { @@ -285,15 +287,6 @@ gm200_flcn_fw_load(struct nvkm_falcon_fw *fw) } if (fw->boot) { - switch (nvkm_memory_target(&fw->fw.mem.memory)) { - case NVKM_MEM_TARGET_VRAM: target = 4; break; - case NVKM_MEM_TARGET_HOST: target = 5; break; - case NVKM_MEM_TARGET_NCOH: target = 6; break; - default: - WARN_ON(1); - return -EINVAL; - } - ret = nvkm_falcon_pio_wr(falcon, fw->boot, 0, 0, IMEM, falcon->code.limit - fw->boot_size, fw->boot_size, fw->boot_addr >> 8, false); From 60dfe2434eed13082f26eb7409665dfafb38fa51 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Tue, 24 Jun 2025 07:26:40 -0700 Subject: [PATCH 0597/1292] ice: fix NULL pointer dereference in ice_unplug_aux_dev() on reset Issuing a reset when the driver is loaded without RDMA support, will results in a crash as it attempts to remove RDMA's non-existent auxbus device: echo 1 > /sys/class/net//device/reset BUG: kernel NULL pointer dereference, address: 0000000000000008 ... RIP: 0010:ice_unplug_aux_dev+0x29/0x70 [ice] ... Call Trace: ice_prepare_for_reset+0x77/0x260 [ice] pci_dev_save_and_disable+0x2c/0x70 pci_reset_function+0x88/0x130 reset_store+0x5a/0xa0 kernfs_fop_write_iter+0x15e/0x210 vfs_write+0x273/0x520 ksys_write+0x6b/0xe0 do_syscall_64+0x79/0x3b0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ice_unplug_aux_dev() checks pf->cdev_info->adev for NULL pointer, but pf->cdev_info will also be NULL, leading to the deref in the trace above. Introduce a flag to be set when the creation of the auxbus device is successful, to avoid multiple NULL pointer checks in ice_unplug_aux_dev(). Fixes: c24a65b6a27c7 ("iidc/ice/irdma: Update IDC to support multiple consumers") Signed-off-by: Emil Tantilov Reviewed-by: Przemek Kitszel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_idc.c | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 2098f00b3cd367..8a8a01a4bb401b 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -510,6 +510,7 @@ enum ice_pf_flags { ICE_FLAG_LINK_LENIENT_MODE_ENA, ICE_FLAG_PLUG_AUX_DEV, ICE_FLAG_UNPLUG_AUX_DEV, + ICE_FLAG_AUX_DEV_CREATED, ICE_FLAG_MTU_CHANGED, ICE_FLAG_GNSS, /* GNSS successfully initialized */ ICE_FLAG_DPLL, /* SyncE/PTP dplls initialized */ diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c index 6ab53e430f9121..420d45c2558b62 100644 --- a/drivers/net/ethernet/intel/ice/ice_idc.c +++ b/drivers/net/ethernet/intel/ice/ice_idc.c @@ -336,6 +336,7 @@ int ice_plug_aux_dev(struct ice_pf *pf) mutex_lock(&pf->adev_mutex); cdev->adev = adev; mutex_unlock(&pf->adev_mutex); + set_bit(ICE_FLAG_AUX_DEV_CREATED, pf->flags); return 0; } @@ -347,15 +348,16 @@ void ice_unplug_aux_dev(struct ice_pf *pf) { struct auxiliary_device *adev; + if (!test_and_clear_bit(ICE_FLAG_AUX_DEV_CREATED, pf->flags)) + return; + mutex_lock(&pf->adev_mutex); adev = pf->cdev_info->adev; pf->cdev_info->adev = NULL; mutex_unlock(&pf->adev_mutex); - if (adev) { - auxiliary_device_delete(adev); - auxiliary_device_uninit(adev); - } + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); } /** From 86aae43f21cf784c1d7f6a9af93e5116b0f232ab Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 17 Jul 2025 09:57:09 -0700 Subject: [PATCH 0598/1292] ice: don't leave device non-functional if Tx scheduler config fails The ice_cfg_tx_topo function attempts to apply Tx scheduler topology configuration based on NVM parameters, selecting either a 5 or 9 layer topology. As part of this flow, the driver acquires the "Global Configuration Lock", which is a hardware resource associated with programming the DDP package to the device. This "lock" is implemented by firmware as a way to guarantee that only one PF can program the DDP for a device. Unlike a traditional lock, once a PF has acquired this lock, no other PF will be able to acquire it again (including that PF) until a CORER of the device. Future requests to acquire the lock report that global configuration has already completed. The following flow is used to program the Tx topology: * Read the DDP package for scheduler configuration data * Acquire the global configuration lock * Program Tx scheduler topology according to DDP package data * Trigger a CORER which clears the global configuration lock This is followed by the flow for programming the DDP package: * Acquire the global configuration lock (again) * Download the DDP package to the device * Release the global configuration lock. However, if configuration of the Tx topology fails, (i.e. ice_get_set_tx_topo returns an error code), the driver exits ice_cfg_tx_topo() immediately, and fails to trigger CORER. While the global configuration lock is held, the firmware rejects most AdminQ commands, as it is waiting for the DDP package download (or Tx scheduler topology programming) to occur. The current driver flows assume that the global configuration lock has been reset by CORER after programming the Tx topology. Thus, the same PF attempts to acquire the global lock again, and fails. This results in the driver reporting "an unknown error occurred when loading the DDP package". It then attempts to enter safe mode, but ultimately fails to finish ice_probe() since nearly all AdminQ command report error codes, and the driver stops loading the device at some point during its initialization. The only currently known way that ice_get_set_tx_topo() can fail is with certain older DDP packages which contain invalid topology configuration, on firmware versions which strictly validate this data. The most recent releases of the DDP have resolved the invalid data. However, it is still poor practice to essentially brick the device, and prevent access to the device even through safe mode or recovery mode. It is also plausible that this command could fail for some other reason in the future. We cannot simply release the global lock after a failed call to ice_get_set_tx_topo(). Releasing the lock indicates to firmware that global configuration (downloading of the DDP) has completed. Future attempts by this or other PFs to load the DDP will fail with a report that the DDP package has already been downloaded. Then, PFs will enter safe mode as they realize that the package on the device does not meet the minimum version requirement to load. The reported error messages are confusing, as they indicate the version of the default "safe mode" package in the NVM, rather than the version of the file loaded from /lib/firmware. Instead, we need to trigger CORER to clear global configuration. This is the lowest level of hardware reset which clears the global configuration lock and related state. It also clears any already downloaded DDP. Crucially, it does *not* clear the Tx scheduler topology configuration. Refactor ice_cfg_tx_topo() to always trigger a CORER after acquiring the global lock, regardless of success or failure of the topology configuration. We need to re-initialize the HW structure when we trigger the CORER. Thus, it makes sense for this to be the responsibility of ice_cfg_tx_topo() rather than its caller, ice_init_tx_topology(). This avoids needless re-initialization in cases where we don't attempt to update the Tx scheduler topology, such as if it has already been programmed. There is one catch: failure to re-initialize the HW struct should stop ice_probe(). If this function fails, we won't have a valid HW structure and cannot ensure the device is functioning properly. To handle this, ensure ice_cfg_tx_topo() returns a limited set of error codes. Set aside one specifically, -ENODEV, to indicate that the ice_init_tx_topology() should fail and stop probe. Other error codes indicate failure to apply the Tx scheduler topology. This is treated as a non-fatal error, with an informational message informing the system administrator that the updated Tx topology did not apply. This allows the device to load and function with the default Tx scheduler topology, rather than failing to load entirely. Note that this use of CORER will not result in loops with future PFs attempting to also load the invalid Tx topology configuration. The first PF will acquire the global configuration lock as part of programming the DDP. Each PF after this will attempt to acquire the global lock as part of programming the Tx topology, and will fail with the indication from firmware that global configuration is already complete. Tx scheduler topology configuration is only performed during driver init (probe or devlink reload) and not during cleanup for a CORER that happens after probe completes. Fixes: 91427e6d9030 ("ice: Support 5 layer topology") Signed-off-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_ddp.c | 44 ++++++++++++++++------- drivers/net/ethernet/intel/ice/ice_main.c | 16 ++++++--- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.c b/drivers/net/ethernet/intel/ice/ice_ddp.c index e2a036ce76ca32..3b2d9c43697927 100644 --- a/drivers/net/ethernet/intel/ice/ice_ddp.c +++ b/drivers/net/ethernet/intel/ice/ice_ddp.c @@ -2377,7 +2377,13 @@ ice_get_set_tx_topo(struct ice_hw *hw, u8 *buf, u16 buf_size, * The function will apply the new Tx topology from the package buffer * if available. * - * Return: zero when update was successful, negative values otherwise. + * Return: + * * 0 - Successfully applied topology configuration. + * * -EBUSY - Failed to acquire global configuration lock. + * * -EEXIST - Topology configuration has already been applied. + * * -EIO - Unable to apply topology configuration. + * * -ENODEV - Failed to re-initialize device after applying configuration. + * * Other negative error codes indicate unexpected failures. */ int ice_cfg_tx_topo(struct ice_hw *hw, const void *buf, u32 len) { @@ -2410,7 +2416,7 @@ int ice_cfg_tx_topo(struct ice_hw *hw, const void *buf, u32 len) if (status) { ice_debug(hw, ICE_DBG_INIT, "Get current topology is failed\n"); - return status; + return -EIO; } /* Is default topology already applied ? */ @@ -2497,31 +2503,45 @@ int ice_cfg_tx_topo(struct ice_hw *hw, const void *buf, u32 len) ICE_GLOBAL_CFG_LOCK_TIMEOUT); if (status) { ice_debug(hw, ICE_DBG_INIT, "Failed to acquire global lock\n"); - return status; + return -EBUSY; } /* Check if reset was triggered already. */ reg = rd32(hw, GLGEN_RSTAT); if (reg & GLGEN_RSTAT_DEVSTATE_M) { - /* Reset is in progress, re-init the HW again */ ice_debug(hw, ICE_DBG_INIT, "Reset is in progress. Layer topology might be applied already\n"); ice_check_reset(hw); - return 0; + /* Reset is in progress, re-init the HW again */ + goto reinit_hw; } /* Set new topology */ status = ice_get_set_tx_topo(hw, new_topo, size, NULL, NULL, true); if (status) { - ice_debug(hw, ICE_DBG_INIT, "Failed setting Tx topology\n"); - return status; + ice_debug(hw, ICE_DBG_INIT, "Failed to set Tx topology, status %pe\n", + ERR_PTR(status)); + /* only report -EIO here as the caller checks the error value + * and reports an informational error message informing that + * the driver failed to program Tx topology. + */ + status = -EIO; } - /* New topology is updated, delay 1 second before issuing the CORER */ + /* Even if Tx topology config failed, we need to CORE reset here to + * clear the global configuration lock. Delay 1 second to allow + * hardware to settle then issue a CORER + */ msleep(1000); ice_reset(hw, ICE_RESET_CORER); - /* CORER will clear the global lock, so no explicit call - * required for release. - */ + ice_check_reset(hw); + +reinit_hw: + /* Since we triggered a CORER, re-initialize hardware */ + ice_deinit_hw(hw); + if (ice_init_hw(hw)) { + ice_debug(hw, ICE_DBG_INIT, "Failed to re-init hardware after setting Tx topology\n"); + return -ENODEV; + } - return 0; + return status; } diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 8e0b06c1e02b2a..cae992d8f03ca5 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4536,17 +4536,23 @@ ice_init_tx_topology(struct ice_hw *hw, const struct firmware *firmware) dev_info(dev, "Tx scheduling layers switching feature disabled\n"); else dev_info(dev, "Tx scheduling layers switching feature enabled\n"); - /* if there was a change in topology ice_cfg_tx_topo triggered - * a CORER and we need to re-init hw + return 0; + } else if (err == -ENODEV) { + /* If we failed to re-initialize the device, we can no longer + * continue loading. */ - ice_deinit_hw(hw); - err = ice_init_hw(hw); - + dev_warn(dev, "Failed to initialize hardware after applying Tx scheduling configuration.\n"); return err; } else if (err == -EIO) { dev_info(dev, "DDP package does not support Tx scheduling layers switching feature - please update to the latest DDP package and try again\n"); + return 0; + } else if (err == -EEXIST) { + return 0; } + /* Do not treat this as a fatal error. */ + dev_info(dev, "Failed to apply Tx scheduling configuration, err %pe\n", + ERR_PTR(err)); return 0; } From 5c5e5b52bf05c7fe88768318c041052c5fac36b8 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 1 Aug 2025 15:27:12 -0700 Subject: [PATCH 0599/1292] ice: use fixed adapter index for E825C embedded devices The ice_adapter structure is used by the ice driver to connect multiple physical functions of a device in software. It was introduced by commit 0e2bddf9e5f9 ("ice: add ice_adapter for shared data across PFs on the same NIC") and is primarily used for PTP support, as well as for handling certain cross-PF synchronization. The original design of ice_adapter used PCI address information to determine which devices should be connected. This was extended to support E825C devices by commit fdb7f54700b1 ("ice: Initial support for E825C hardware in ice_adapter"), which used the device ID for E825C devices instead of the PCI address. Later, commit 0093cb194a75 ("ice: use DSN instead of PCI BDF for ice_adapter index") replaced the use of Bus/Device/Function addressing with use of the device serial number. E825C devices may appear in "Dual NAC" configuration which has multiple physical devices tied to the same clock source and which need to use the same ice_adapter. Unfortunately, each "NAC" has its own NVM which has its own unique Device Serial Number. Thus, use of the DSN for connecting ice_adapter does not work properly. It "worked" in the pre-production systems because the DSN was not initialized on the test NVMs and all the NACs had the same zero'd serial number. Since we cannot rely on the DSN, lets fall back to the logic in the original E825C support which used the device ID. This is safe for E825C only because of the embedded nature of the device. It isn't a discreet adapter that can be plugged into an arbitrary system. All E825C devices on a given system are connected to the same clock source and need to be configured through the same PTP clock. To make this separation clear, reserve bit 63 of the 64-bit index values as a "fixed index" indicator. Always clear this bit when using the device serial number as an index. For E825C, use a fixed value defined as the 0x579C E825C backplane device ID bitwise ORed with the fixed index indicator. This is slightly different than the original logic of just using the device ID directly. Doing so prevents a potential issue with systems where only one of the NACs is connected with an external PHY over SGMII. In that case, one NAC would have the E825C_SGMII device ID, but the other would not. Separate the determination of the full 64-bit index from the 32-bit reduction logic. Provide both ice_adapter_index() and a wrapping ice_adapter_xa_index() which handles reducing the index to a long on 32-bit systems. As before, cache the full index value in the adapter structure to warn about collisions. This fixes issues with E825C not initializing PTP on both NACs, due to failure to connect the appropriate devices to the same ice_adapter. Fixes: 0093cb194a75 ("ice: use DSN instead of PCI BDF for ice_adapter index") Signed-off-by: Jacob Keller Reviewed-by: Grzegorz Nitka Reviewed-by: Aleksandr Loktionov Reviewed-by: Przemek Kitszel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_adapter.c | 49 +++++++++++++++----- drivers/net/ethernet/intel/ice/ice_adapter.h | 4 +- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c index 9e4adc43e474c9..b53561c347082f 100644 --- a/drivers/net/ethernet/intel/ice/ice_adapter.c +++ b/drivers/net/ethernet/intel/ice/ice_adapter.c @@ -13,16 +13,45 @@ static DEFINE_XARRAY(ice_adapters); static DEFINE_MUTEX(ice_adapters_mutex); -static unsigned long ice_adapter_index(u64 dsn) +#define ICE_ADAPTER_FIXED_INDEX BIT_ULL(63) + +#define ICE_ADAPTER_INDEX_E825C \ + (ICE_DEV_ID_E825C_BACKPLANE | ICE_ADAPTER_FIXED_INDEX) + +static u64 ice_adapter_index(struct pci_dev *pdev) { + switch (pdev->device) { + case ICE_DEV_ID_E825C_BACKPLANE: + case ICE_DEV_ID_E825C_QSFP: + case ICE_DEV_ID_E825C_SFP: + case ICE_DEV_ID_E825C_SGMII: + /* E825C devices have multiple NACs which are connected to the + * same clock source, and which must share the same + * ice_adapter structure. We can't use the serial number since + * each NAC has its own NVM generated with its own unique + * Device Serial Number. Instead, rely on the embedded nature + * of the E825C devices, and use a fixed index. This relies on + * the fact that all E825C physical functions in a given + * system are part of the same overall device. + */ + return ICE_ADAPTER_INDEX_E825C; + default: + return pci_get_dsn(pdev) & ~ICE_ADAPTER_FIXED_INDEX; + } +} + +static unsigned long ice_adapter_xa_index(struct pci_dev *pdev) +{ + u64 index = ice_adapter_index(pdev); + #if BITS_PER_LONG == 64 - return dsn; + return index; #else - return (u32)dsn ^ (u32)(dsn >> 32); + return (u32)index ^ (u32)(index >> 32); #endif } -static struct ice_adapter *ice_adapter_new(u64 dsn) +static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev) { struct ice_adapter *adapter; @@ -30,7 +59,7 @@ static struct ice_adapter *ice_adapter_new(u64 dsn) if (!adapter) return NULL; - adapter->device_serial_number = dsn; + adapter->index = ice_adapter_index(pdev); spin_lock_init(&adapter->ptp_gltsyn_time_lock); spin_lock_init(&adapter->txq_ctx_lock); refcount_set(&adapter->refcount, 1); @@ -64,24 +93,23 @@ static void ice_adapter_free(struct ice_adapter *adapter) */ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev) { - u64 dsn = pci_get_dsn(pdev); struct ice_adapter *adapter; unsigned long index; int err; - index = ice_adapter_index(dsn); + index = ice_adapter_xa_index(pdev); scoped_guard(mutex, &ice_adapters_mutex) { err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL); if (err == -EBUSY) { adapter = xa_load(&ice_adapters, index); refcount_inc(&adapter->refcount); - WARN_ON_ONCE(adapter->device_serial_number != dsn); + WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev)); return adapter; } if (err) return ERR_PTR(err); - adapter = ice_adapter_new(dsn); + adapter = ice_adapter_new(pdev); if (!adapter) return ERR_PTR(-ENOMEM); xa_store(&ice_adapters, index, adapter, GFP_KERNEL); @@ -100,11 +128,10 @@ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev) */ void ice_adapter_put(struct pci_dev *pdev) { - u64 dsn = pci_get_dsn(pdev); struct ice_adapter *adapter; unsigned long index; - index = ice_adapter_index(dsn); + index = ice_adapter_xa_index(pdev); scoped_guard(mutex, &ice_adapters_mutex) { adapter = xa_load(&ice_adapters, index); if (WARN_ON(!adapter)) diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h index db66d03c9f96f8..e95266c7f20bd2 100644 --- a/drivers/net/ethernet/intel/ice/ice_adapter.h +++ b/drivers/net/ethernet/intel/ice/ice_adapter.h @@ -33,7 +33,7 @@ struct ice_port_list { * @txq_ctx_lock: Spinlock protecting access to the GLCOMM_QTX_CNTX_CTL register * @ctrl_pf: Control PF of the adapter * @ports: Ports list - * @device_serial_number: DSN cached for collision detection on 32bit systems + * @index: 64-bit index cached for collision detection on 32bit systems */ struct ice_adapter { refcount_t refcount; @@ -44,7 +44,7 @@ struct ice_adapter { struct ice_pf *ctrl_pf; struct ice_port_list ports; - u64 device_serial_number; + u64 index; }; struct ice_adapter *ice_adapter_get(struct pci_dev *pdev); From b1a0c977c6f1130f7dd125ee3db8c2435d7e3d41 Mon Sep 17 00:00:00 2001 From: Michal Kubiak Date: Fri, 8 Aug 2025 17:53:10 +0200 Subject: [PATCH 0600/1292] ice: fix incorrect counter for buffer allocation failures Currently, the driver increments `alloc_page_failed` when buffer allocation fails in `ice_clean_rx_irq()`. However, this counter is intended for page allocation failures, not buffer allocation issues. This patch corrects the counter by incrementing `alloc_buf_failed` instead, ensuring accurate statistics reporting for buffer allocation failures. Fixes: 2fba7dc5157b ("ice: Add support for XDP multi-buffer on Rx side") Reported-by: Jacob Keller Suggested-by: Paul Menzel Signed-off-by: Michal Kubiak Reviewed-by: Paul Menzel Reviewed-by: Jason Xing Reviewed-by: Aleksandr Loktionov Tested-by: Priya Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 29e0088ab6b28b..d2871757ec9401 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1352,7 +1352,7 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) skb = ice_construct_skb(rx_ring, xdp); /* exit if we failed to retrieve a buffer */ if (!skb) { - rx_ring->ring_stats->rx_stats.alloc_page_failed++; + rx_ring->ring_stats->rx_stats.alloc_buf_failed++; xdp_verdict = ICE_XDP_CONSUMED; } ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); From ed913b343dcf9f623e7436fa1a153c89b22d109b Mon Sep 17 00:00:00 2001 From: Jedrzej Jagielski Date: Thu, 31 Jul 2025 14:45:33 +0200 Subject: [PATCH 0601/1292] ixgbe: fix ixgbe_orom_civd_info struct layout The current layout of struct ixgbe_orom_civd_info causes incorrect data storage due to compiler-inserted padding. This results in issues when writing OROM data into the structure. Add the __packed attribute to ensure the structure layout matches the expected binary format without padding. Fixes: 70db0788a262 ("ixgbe: read the OROM version information") Reviewed-by: Aleksandr Loktionov Signed-off-by: Jedrzej Jagielski Reviewed-by: Simon Horman Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index d74116441d1c65..bfeef5b0b99d87 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -3125,7 +3125,7 @@ static int ixgbe_get_orom_ver_info(struct ixgbe_hw *hw, if (err) return err; - combo_ver = le32_to_cpu(civd.combo_ver); + combo_ver = get_unaligned_le32(&civd.combo_ver); orom->major = (u8)FIELD_GET(IXGBE_OROM_VER_MASK, combo_ver); orom->patch = (u8)FIELD_GET(IXGBE_OROM_VER_PATCH_MASK, combo_ver); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h index d2f22d8558f830..ff8d640a50b1c1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h @@ -932,7 +932,7 @@ struct ixgbe_orom_civd_info { __le32 combo_ver; /* Combo Image Version number */ u8 combo_name_len; /* Length of the unicode combo image version string, max of 32 */ __le16 combo_name[32]; /* Unicode string representing the Combo Image version */ -}; +} __packed; /* Function specific capabilities */ struct ixgbe_hw_func_caps { From f144bc21befdcf8e54d2f19b23b4e84f13be01f9 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Wed, 20 Aug 2025 12:09:26 -0500 Subject: [PATCH 0602/1292] ACPI: video: force native for Lenovo 82K8 Lenovo 82K8 has a broken brightness control provided by nvidia_wmi_ec. Add a quirk to prevent using it. Reported-by: Wilson Alvarez Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4512 Tested-by: Wilson Alvarez Signed-off-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/20250820170927.895573-1-superm1@kernel.org Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video_detect.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d507d5e084354b..4cf74f173c785d 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -948,6 +948,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), }, }, + /* https://gitlab.freedesktop.org/drm/amd/-/issues/4512 */ + { + .callback = video_detect_force_native, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "82K8"), + }, + }, { }, }; From 149139ddcb99583fdec8d1eaf7dada41e5896101 Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Fri, 22 Aug 2025 11:49:46 +0530 Subject: [PATCH 0603/1292] ACPI: sysfs: Use ACPI_FREE() for freeing an ACPI object Since str_obj is allocated by ACPICA in acpi_evaluate_object_typed(), it should be free with ACPI_FREE() rather than with kfree(), so use the former instead of the latter for freeing it. Signed-off-by: Kaushlendra Kumar Link: https://patch.msgid.link/20250822061946.472594-1-kaushlendra.kumar@intel.com [ rjw: Subject and changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 3961fc47152c0a..cd199fbe4dc902 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -464,7 +464,7 @@ static ssize_t description_show(struct device *dev, buf[result++] = '\n'; - kfree(str_obj); + ACPI_FREE(str_obj); return result; } From 39c87887606e5197723616c909d1f3054792f0dd Mon Sep 17 00:00:00 2001 From: Chelsy Ratnawat Date: Sat, 23 Aug 2025 15:03:11 -0700 Subject: [PATCH 0604/1292] ACPI: Use str_low_high() helper in two places Replace hard-coded string choices with the str_low_high() helper in two places in the ACPI code. Signed-off-by: Chelsy Ratnawat Link: https://patch.msgid.link/20250823220311.2035533-1-chelsyratnawat2001@gmail.com [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_irq.c | 3 ++- drivers/acpi/resource.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 630fe0a34bc6e7..ad81aa03fe2f85 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -22,6 +22,7 @@ #include #include #include +#include struct acpi_prt_entry { struct acpi_pci_id id; @@ -468,7 +469,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) dev_dbg(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n", pin_name(pin), link_desc, gsi, (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", - (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); + str_low_high(polarity == ACPI_ACTIVE_LOW), dev->irq); kfree(entry); return 0; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index b1ab192d7a0809..55b195ad5c7e5e 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #define valid_IRQ(i) (((i) != 0) && ((i) != 2)) @@ -773,7 +774,7 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, pr_warn("ACPI: IRQ %d override to %s%s, %s%s\n", gsi, t ? "level" : "edge", trig == triggering ? "" : "(!)", - p ? "low" : "high", + str_low_high(p), pol == polarity ? "" : "(!)"); triggering = trig; polarity = pol; From e228e7d382fa85005ee2ebf303e1bf194aca49a8 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 25 Aug 2025 09:22:09 +0000 Subject: [PATCH 0605/1292] drm/gpuvm: fix various typos in .c and .h gpuvm file After working with this code for a while, I came across several typos. This patch fixes them. Signed-off-by: Alice Ryhl Link: https://lore.kernel.org/r/20250825-gpuvm-typo-fix-v1-1-14e9e78e28e6@google.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/drm_gpuvm.c | 78 ++++++++++++++++++------------------- include/drm/drm_gpuvm.h | 10 ++--- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 74d949995a72f3..60b672d3fd8353 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -40,7 +40,7 @@ * mapping's backing &drm_gem_object buffers. * * &drm_gem_object buffers maintain a list of &drm_gpuva objects representing - * all existent GPU VA mappings using this &drm_gem_object as backing buffer. + * all existing GPU VA mappings using this &drm_gem_object as backing buffer. * * GPU VAs can be flagged as sparse, such that drivers may use GPU VAs to also * keep track of sparse PTEs in order to support Vulkan 'Sparse Resources'. @@ -72,7 +72,7 @@ * but it can also be a 'dummy' object, which can be allocated with * drm_gpuvm_resv_object_alloc(). * - * In order to connect a struct drm_gpuva its backing &drm_gem_object each + * In order to connect a struct drm_gpuva to its backing &drm_gem_object each * &drm_gem_object maintains a list of &drm_gpuvm_bo structures, and each * &drm_gpuvm_bo contains a list of &drm_gpuva structures. * @@ -81,7 +81,7 @@ * This is ensured by the API through drm_gpuvm_bo_obtain() and * drm_gpuvm_bo_obtain_prealloc() which first look into the corresponding * &drm_gem_object list of &drm_gpuvm_bos for an existing instance of this - * particular combination. If not existent a new instance is created and linked + * particular combination. If not present, a new instance is created and linked * to the &drm_gem_object. * * &drm_gpuvm_bo structures, since unique for a given &drm_gpuvm, are also used @@ -108,7 +108,7 @@ * sequence of operations to satisfy a given map or unmap request. * * Therefore the DRM GPU VA manager provides an algorithm implementing splitting - * and merging of existent GPU VA mappings with the ones that are requested to + * and merging of existing GPU VA mappings with the ones that are requested to * be mapped or unmapped. This feature is required by the Vulkan API to * implement Vulkan 'Sparse Memory Bindings' - drivers UAPIs often refer to this * as VM BIND. @@ -119,7 +119,7 @@ * execute in order to integrate the new mapping cleanly into the current state * of the GPU VA space. * - * Depending on how the new GPU VA mapping intersects with the existent mappings + * Depending on how the new GPU VA mapping intersects with the existing mappings * of the GPU VA space the &drm_gpuvm_ops callbacks contain an arbitrary amount * of unmap operations, a maximum of two remap operations and a single map * operation. The caller might receive no callback at all if no operation is @@ -139,16 +139,16 @@ * one unmap operation and one or two map operations, such that drivers can * derive the page table update delta accordingly. * - * Note that there can't be more than two existent mappings to split up, one at + * Note that there can't be more than two existing mappings to split up, one at * the beginning and one at the end of the new mapping, hence there is a * maximum of two remap operations. * * Analogous to drm_gpuvm_sm_map() drm_gpuvm_sm_unmap() uses &drm_gpuvm_ops to * call back into the driver in order to unmap a range of GPU VA space. The - * logic behind this function is way simpler though: For all existent mappings + * logic behind this function is way simpler though: For all existing mappings * enclosed by the given range unmap operations are created. For mappings which - * are only partically located within the given range, remap operations are - * created such that those mappings are split up and re-mapped partically. + * are only partially located within the given range, remap operations are + * created such that those mappings are split up and re-mapped partially. * * As an alternative to drm_gpuvm_sm_map() and drm_gpuvm_sm_unmap(), * drm_gpuvm_sm_map_ops_create() and drm_gpuvm_sm_unmap_ops_create() can be used @@ -168,7 +168,7 @@ * provided helper functions drm_gpuva_map(), drm_gpuva_remap() and * drm_gpuva_unmap() instead. * - * The following diagram depicts the basic relationships of existent GPU VA + * The following diagram depicts the basic relationships of existing GPU VA * mappings, a newly requested mapping and the resulting mappings as implemented * by drm_gpuvm_sm_map() - it doesn't cover any arbitrary combinations of these. * @@ -218,7 +218,7 @@ * * * 4) Existent mapping is a left aligned subset of the requested one, hence - * replace the existent one. + * replace the existing one. * * :: * @@ -236,9 +236,9 @@ * and/or non-contiguous BO offset. * * - * 5) Requested mapping's range is a left aligned subset of the existent one, + * 5) Requested mapping's range is a left aligned subset of the existing one, * but backed by a different BO. Hence, map the requested mapping and split - * the existent one adjusting its BO offset. + * the existing one adjusting its BO offset. * * :: * @@ -271,9 +271,9 @@ * new: |-----|-----| (a.bo_offset=n, a'.bo_offset=n+1) * * - * 7) Requested mapping's range is a right aligned subset of the existent one, + * 7) Requested mapping's range is a right aligned subset of the existing one, * but backed by a different BO. Hence, map the requested mapping and split - * the existent one, without adjusting the BO offset. + * the existing one, without adjusting the BO offset. * * :: * @@ -304,7 +304,7 @@ * * 9) Existent mapping is overlapped at the end by the requested mapping backed * by a different BO. Hence, map the requested mapping and split up the - * existent one, without adjusting the BO offset. + * existing one, without adjusting the BO offset. * * :: * @@ -334,9 +334,9 @@ * new: |-----|-----------| (a'.bo_offset=n, a.bo_offset=n+1) * * - * 11) Requested mapping's range is a centered subset of the existent one + * 11) Requested mapping's range is a centered subset of the existing one * having a different backing BO. Hence, map the requested mapping and split - * up the existent one in two mappings, adjusting the BO offset of the right + * up the existing one in two mappings, adjusting the BO offset of the right * one accordingly. * * :: @@ -351,7 +351,7 @@ * new: |-----|-----|-----| (a.bo_offset=n,b.bo_offset=m,a'.bo_offset=n+2) * * - * 12) Requested mapping is a contiguous subset of the existent one. Split it + * 12) Requested mapping is a contiguous subset of the existing one. Split it * up, but indicate that the backing PTEs could be kept. * * :: @@ -367,7 +367,7 @@ * * * 13) Existent mapping is a right aligned subset of the requested one, hence - * replace the existent one. + * replace the existing one. * * :: * @@ -386,7 +386,7 @@ * * * 14) Existent mapping is a centered subset of the requested one, hence - * replace the existent one. + * replace the existing one. * * :: * @@ -406,7 +406,7 @@ * * 15) Existent mappings is overlapped at the beginning by the requested mapping * backed by a different BO. Hence, map the requested mapping and split up - * the existent one, adjusting its BO offset accordingly. + * the existing one, adjusting its BO offset accordingly. * * :: * @@ -469,8 +469,8 @@ * make use of them. * * The below code is strictly limited to illustrate the generic usage pattern. - * To maintain simplicitly, it doesn't make use of any abstractions for common - * code, different (asyncronous) stages with fence signalling critical paths, + * To maintain simplicity, it doesn't make use of any abstractions for common + * code, different (asynchronous) stages with fence signalling critical paths, * any other helpers or error handling in terms of freeing memory and dropping * previously taken locks. * @@ -479,7 +479,7 @@ * // Allocates a new &drm_gpuva. * struct drm_gpuva * driver_gpuva_alloc(void); * - * // Typically drivers would embedd the &drm_gpuvm and &drm_gpuva + * // Typically drivers would embed the &drm_gpuvm and &drm_gpuva * // structure in individual driver structures and lock the dma-resv with * // drm_exec or similar helpers. * int driver_mapping_create(struct drm_gpuvm *gpuvm, @@ -582,7 +582,7 @@ * .sm_step_unmap = driver_gpuva_unmap, * }; * - * // Typically drivers would embedd the &drm_gpuvm and &drm_gpuva + * // Typically drivers would embed the &drm_gpuvm and &drm_gpuva * // structure in individual driver structures and lock the dma-resv with * // drm_exec or similar helpers. * int driver_mapping_create(struct drm_gpuvm *gpuvm, @@ -680,7 +680,7 @@ * * This helper is here to provide lockless list iteration. Lockless as in, the * iterator releases the lock immediately after picking the first element from - * the list, so list insertion deletion can happen concurrently. + * the list, so list insertion and deletion can happen concurrently. * * Elements popped from the original list are kept in a local list, so removal * and is_empty checks can still happen while we're iterating the list. @@ -1160,7 +1160,7 @@ drm_gpuvm_prepare_objects_locked(struct drm_gpuvm *gpuvm, } /** - * drm_gpuvm_prepare_objects() - prepare all assoiciated BOs + * drm_gpuvm_prepare_objects() - prepare all associated BOs * @gpuvm: the &drm_gpuvm * @exec: the &drm_exec locking context * @num_fences: the amount of &dma_fences to reserve @@ -1230,13 +1230,13 @@ drm_gpuvm_prepare_range(struct drm_gpuvm *gpuvm, struct drm_exec *exec, EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_range); /** - * drm_gpuvm_exec_lock() - lock all dma-resv of all assoiciated BOs + * drm_gpuvm_exec_lock() - lock all dma-resv of all associated BOs * @vm_exec: the &drm_gpuvm_exec wrapper * * Acquires all dma-resv locks of all &drm_gem_objects the given * &drm_gpuvm contains mappings of. * - * Addionally, when calling this function with struct drm_gpuvm_exec::extra + * Additionally, when calling this function with struct drm_gpuvm_exec::extra * being set the driver receives the given @fn callback to lock additional * dma-resv in the context of the &drm_gpuvm_exec instance. Typically, drivers * would call drm_exec_prepare_obj() from within this callback. @@ -1293,7 +1293,7 @@ fn_lock_array(struct drm_gpuvm_exec *vm_exec) } /** - * drm_gpuvm_exec_lock_array() - lock all dma-resv of all assoiciated BOs + * drm_gpuvm_exec_lock_array() - lock all dma-resv of all associated BOs * @vm_exec: the &drm_gpuvm_exec wrapper * @objs: additional &drm_gem_objects to lock * @num_objs: the number of additional &drm_gem_objects to lock @@ -1588,7 +1588,7 @@ drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, EXPORT_SYMBOL_GPL(drm_gpuvm_bo_find); /** - * drm_gpuvm_bo_obtain() - obtains and instance of the &drm_gpuvm_bo for the + * drm_gpuvm_bo_obtain() - obtains an instance of the &drm_gpuvm_bo for the * given &drm_gpuvm and &drm_gem_object * @gpuvm: The &drm_gpuvm the @obj is mapped in. * @obj: The &drm_gem_object being mapped in the @gpuvm. @@ -1624,7 +1624,7 @@ drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain); /** - * drm_gpuvm_bo_obtain_prealloc() - obtains and instance of the &drm_gpuvm_bo + * drm_gpuvm_bo_obtain_prealloc() - obtains an instance of the &drm_gpuvm_bo * for the given &drm_gpuvm and &drm_gem_object * @__vm_bo: A pre-allocated struct drm_gpuvm_bo. * @@ -1688,7 +1688,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_extobj_add); * @vm_bo: the &drm_gpuvm_bo to add or remove * @evict: indicates whether the object is evicted * - * Adds a &drm_gpuvm_bo to or removes it from the &drm_gpuvms evicted list. + * Adds a &drm_gpuvm_bo to or removes it from the &drm_gpuvm's evicted list. */ void drm_gpuvm_bo_evict(struct drm_gpuvm_bo *vm_bo, bool evict) @@ -1790,7 +1790,7 @@ __drm_gpuva_remove(struct drm_gpuva *va) * drm_gpuva_remove() - remove a &drm_gpuva * @va: the &drm_gpuva to remove * - * This removes the given &va from the underlaying tree. + * This removes the given &va from the underlying tree. * * It is safe to use this function using the safe versions of iterating the GPU * VA space, such as drm_gpuvm_for_each_va_safe() and @@ -2358,7 +2358,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_sm_map); * * This function iterates the given range of the GPU VA space. It utilizes the * &drm_gpuvm_ops to call back into the driver providing the operations to - * unmap and, if required, split existent mappings. + * unmap and, if required, split existing mappings. * * Drivers may use these callbacks to update the GPU VA space right away within * the callback. In case the driver decides to copy and store the operations for @@ -2475,7 +2475,7 @@ static const struct drm_gpuvm_ops lock_ops = { * required without the earlier DRIVER_OP_MAP. This is safe because we've * already locked the GEM object in the earlier DRIVER_OP_MAP step. * - * Returns: 0 on success or a negative error codec + * Returns: 0 on success or a negative error code */ int drm_gpuvm_sm_map_exec_lock(struct drm_gpuvm *gpuvm, @@ -2619,12 +2619,12 @@ static const struct drm_gpuvm_ops gpuvm_list_ops = { * @req_offset: the offset within the &drm_gem_object * * This function creates a list of operations to perform splitting and merging - * of existent mapping(s) with the newly requested one. + * of existing mapping(s) with the newly requested one. * * The list can be iterated with &drm_gpuva_for_each_op and must be processed * in the given order. It can contain map, unmap and remap operations, but it * also can be empty if no operation is required, e.g. if the requested mapping - * already exists is the exact same way. + * already exists in the exact same way. * * There can be an arbitrary amount of unmap operations, a maximum of two remap * operations and a single map operation. The latter one represents the original diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index 274532facfd627..2e7088264355da 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -103,7 +103,7 @@ struct drm_gpuva { } va; /** - * @gem: structure containing the &drm_gem_object and it's offset + * @gem: structure containing the &drm_gem_object and its offset */ struct { /** @@ -843,7 +843,7 @@ struct drm_gpuva_op_map { } va; /** - * @gem: structure containing the &drm_gem_object and it's offset + * @gem: structure containing the &drm_gem_object and its offset */ struct { /** @@ -1189,11 +1189,11 @@ struct drm_gpuvm_ops { /** * @sm_step_unmap: called from &drm_gpuvm_sm_map and - * &drm_gpuvm_sm_unmap to unmap an existent mapping + * &drm_gpuvm_sm_unmap to unmap an existing mapping * - * This callback is called when existent mapping needs to be unmapped. + * This callback is called when existing mapping needs to be unmapped. * This is the case when either a newly requested mapping encloses an - * existent mapping or an unmap of an existent mapping is requested. + * existing mapping or an unmap of an existing mapping is requested. * * The &priv pointer matches the one the driver passed to * &drm_gpuvm_sm_map or &drm_gpuvm_sm_unmap, respectively. From a12b74d2bd4724ee1883bc97ec93eac8fafc8d3c Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 25 Aug 2025 14:11:38 +0200 Subject: [PATCH 0606/1292] ASoC: tlv320aic32x4: use dev_err_probe() for regulators Avoid error messages like the following when the regulators have not been probed yet: tlv320aic32x4 0-0018: Missing supply 'iov' tlv320aic32x4 0-0018: Failed to setup regulators Signed-off-by: Matthias Schiffer Signed-off-by: Alexander Stein Message-ID: <20250825121139.2150099-1-alexander.stein@ew.tq-group.com> Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 7399080f8580c9..715a07ab97b9f9 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1277,8 +1277,8 @@ static int aic32x4_setup_regulators(struct device *dev, /* Check if the regulator requirements are fulfilled */ if (IS_ERR(aic32x4->supply_iov)) { - dev_err(dev, "Missing supply 'iov'\n"); - return PTR_ERR(aic32x4->supply_iov); + return dev_err_probe(dev, PTR_ERR(aic32x4->supply_iov), + "Missing supply 'iov'\n"); } if (IS_ERR(aic32x4->supply_ldo)) { @@ -1286,12 +1286,12 @@ static int aic32x4_setup_regulators(struct device *dev, return -EPROBE_DEFER; if (IS_ERR(aic32x4->supply_dv)) { - dev_err(dev, "Missing supply 'dv' or 'ldoin'\n"); - return PTR_ERR(aic32x4->supply_dv); + return dev_err_probe(dev, PTR_ERR(aic32x4->supply_dv), + "Missing supply 'dv' or 'ldoin'\n"); } if (IS_ERR(aic32x4->supply_av)) { - dev_err(dev, "Missing supply 'av' or 'ldoin'\n"); - return PTR_ERR(aic32x4->supply_av); + return dev_err_probe(dev, PTR_ERR(aic32x4->supply_av), + "Missing supply 'av' or 'ldoin'\n"); } } else { if (PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER) @@ -1383,10 +1383,8 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, } ret = aic32x4_setup_regulators(dev, aic32x4); - if (ret) { - dev_err(dev, "Failed to setup regulators\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to setup regulators\n"); if (aic32x4->rstn_gpio) { ndelay(10); From 7ab3b7579a6d2660a3425b9ea93b9a140b07f49c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 9 Aug 2025 11:36:54 +0300 Subject: [PATCH 0607/1292] dt-bindings: display/msm: qcom,mdp5: drop lut clock None of MDP5 platforms have a LUT clock on the display-controller, it was added by the mistake. Drop it, fixing DT warnings on MSM8976 / MSM8956 platforms. Technically it's an ABI break, but no other platforms are affected. Fixes: 385c8ac763b3 ("dt-bindings: display/msm: convert MDP5 schema to YAML format") Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Patchwork: https://patchwork.freedesktop.org/patch/667822/ Signed-off-by: Rob Clark --- Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml b/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml index e153f8d26e7aae..2735c78b0b67af 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml @@ -60,7 +60,6 @@ properties: - const: bus - const: core - const: vsync - - const: lut - const: tbu - const: tbu_rt # MSM8996 has additional iommu clock From abebfed208515726760d79cf4f9f1a76b9a10a84 Mon Sep 17 00:00:00 2001 From: Chenyuan Yang Date: Tue, 22 Jul 2025 16:17:40 -0500 Subject: [PATCH 0608/1292] drm/msm/dpu: Add a null ptr check for dpu_encoder_needs_modeset The drm_atomic_get_new_connector_state() can return NULL if the connector is not part of the atomic state. Add a check to prevent a NULL pointer dereference. This follows the same pattern used in dpu_encoder_update_topology() within the same file, which checks for NULL before using conn_state. Signed-off-by: Chenyuan Yang Fixes: 1ce69c265a53 ("drm/msm/dpu: move resource allocation to CRTC") Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/665188/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 05e5f3463e30c9..258edaa18fc02f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -730,6 +730,8 @@ bool dpu_encoder_needs_modeset(struct drm_encoder *drm_enc, struct drm_atomic_st return false; conn_state = drm_atomic_get_new_connector_state(state, connector); + if (!conn_state) + return false; /** * These checks are duplicated from dpu_encoder_update_topology() since From 5cfd298cc0359697f26b2b6e25385c665e431a7e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 14 Aug 2025 10:22:20 +0300 Subject: [PATCH 0609/1292] soc: qcom: ubwc: use no-uwbc config for MSM8917 MSM8917 has MDSS 1.15 and Adreno 308, neither of which support UBWC. Change UBWC configuration to point out that UBWC is not supported on this platform. Fixes: 1924272b9ce1 ("soc: qcom: Add UBWC config provider") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/668500/ Signed-off-by: Rob Clark --- drivers/soc/qcom/ubwc_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 1490a7f63767bb..5113c2902bf2ba 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -225,7 +225,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,apq8096", .data = &msm8998_data }, { .compatible = "qcom,msm8226", .data = &no_ubwc_data }, { .compatible = "qcom,msm8916", .data = &no_ubwc_data }, - { .compatible = "qcom,msm8917", .data = &msm8937_data }, + { .compatible = "qcom,msm8917", .data = &no_ubwc_data }, { .compatible = "qcom,msm8937", .data = &msm8937_data }, { .compatible = "qcom,msm8939", .data = &no_ubwc_data }, { .compatible = "qcom,msm8953", .data = &msm8937_data }, From 61f3c19af5ce6606a8f50ba9a0661881925d28c2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 14 Aug 2025 10:22:21 +0300 Subject: [PATCH 0610/1292] soc: qcom: ubwc: add more missing platforms Add UBWC configuration for SDA660 (modem-less variant of SDM660), SDM450 (similar to MSM8953), SDM632 (similar to MSM8953) and SM7325 (similar to SC7280). Fixes: 1924272b9ce1 ("soc: qcom: Add UBWC config provider") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/668501/ Signed-off-by: Rob Clark --- drivers/soc/qcom/ubwc_config.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 5113c2902bf2ba..8b23b4d4e3989a 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -244,7 +244,10 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,sc7280", .data = &sc7280_data, }, { .compatible = "qcom,sc8180x", .data = &sc8180x_data, }, { .compatible = "qcom,sc8280xp", .data = &sc8280xp_data, }, + { .compatible = "qcom,sda660", .data = &msm8937_data }, + { .compatible = "qcom,sdm450", .data = &msm8937_data }, { .compatible = "qcom,sdm630", .data = &msm8937_data }, + { .compatible = "qcom,sdm632", .data = &msm8937_data }, { .compatible = "qcom,sdm636", .data = &msm8937_data }, { .compatible = "qcom,sdm660", .data = &msm8937_data }, { .compatible = "qcom,sdm670", .data = &sdm670_data, }, @@ -258,6 +261,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,sm7125", .data = &sc7180_data }, { .compatible = "qcom,sm7150", .data = &sm7150_data, }, { .compatible = "qcom,sm7225", .data = &sm6350_data, }, + { .compatible = "qcom,sm7325", .data = &sc7280_data, }, { .compatible = "qcom,sm8150", .data = &sm8150_data, }, { .compatible = "qcom,sm8250", .data = &sm8250_data, }, { .compatible = "qcom,sm8350", .data = &sm8350_data, }, From ec770bb2e19196b28868698a81321d3a3c74da9d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 14 Aug 2025 10:22:22 +0300 Subject: [PATCH 0611/1292] soc: qcom: add configuration for MSM8929 MSM8929 is similar to MSM8939, it doesn't support UBWC. Provide no-UBWC config for the platform. Fixes: 197713d0cf01 ("soc: qcom: ubwc: provide no-UBWC configuration") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/668502/ Signed-off-by: Rob Clark --- drivers/soc/qcom/ubwc_config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 8b23b4d4e3989a..689e333ae44308 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -227,6 +227,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,msm8916", .data = &no_ubwc_data }, { .compatible = "qcom,msm8917", .data = &no_ubwc_data }, { .compatible = "qcom,msm8937", .data = &msm8937_data }, + { .compatible = "qcom,msm8929", .data = &no_ubwc_data }, { .compatible = "qcom,msm8939", .data = &no_ubwc_data }, { .compatible = "qcom,msm8953", .data = &msm8937_data }, { .compatible = "qcom,msm8956", .data = &msm8937_data }, From 3cf6147f2b51a569761e1ef010efbd891e3a3a15 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 14 Aug 2025 10:22:23 +0300 Subject: [PATCH 0612/1292] soc: qcom: use no-UBWC config for MSM8956/76 Both MSM8956 and MSM8976 have MDSS 1.11 which doesn't support UBWC (although they also have Adreno 510, which might support UBWC). Disable UBWC support for those platforms. Fixes: 1924272b9ce1 ("soc: qcom: Add UBWC config provider") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/668503/ Signed-off-by: Rob Clark --- drivers/soc/qcom/ubwc_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 689e333ae44308..15d373bff231d7 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -230,9 +230,9 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,msm8929", .data = &no_ubwc_data }, { .compatible = "qcom,msm8939", .data = &no_ubwc_data }, { .compatible = "qcom,msm8953", .data = &msm8937_data }, - { .compatible = "qcom,msm8956", .data = &msm8937_data }, + { .compatible = "qcom,msm8956", .data = &no_ubwc_data }, { .compatible = "qcom,msm8974", .data = &no_ubwc_data }, - { .compatible = "qcom,msm8976", .data = &msm8937_data }, + { .compatible = "qcom,msm8976", .data = &no_ubwc_data }, { .compatible = "qcom,msm8996", .data = &msm8998_data }, { .compatible = "qcom,msm8998", .data = &msm8998_data }, { .compatible = "qcom,qcm2290", .data = &qcm2290_data, }, From ba0b7081f7a521d7c28b527a4f18666a148471e7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 22 Aug 2025 17:00:23 -0700 Subject: [PATCH 0613/1292] perf symbol-minimal: Fix ehdr reading in filename__read_build_id The e_ident is part of the ehdr and so reading it a second time would mean the read ehdr was displaced by 16-bytes. Switch from stdio to open/read/lseek syscalls for similarity with the symbol-elf version of the function and so that later changes can alter then open flags. Fixes: fef8f648bb47 ("perf symbol: Fix use-after-free in filename__read_build_id") Signed-off-by: Ian Rogers Link: https://lore.kernel.org/r/20250823000024.724394-2-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/util/symbol-minimal.c | 55 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 7201494c5c20d9..8d41bd7842dfa3 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -88,11 +87,8 @@ int filename__read_debuglink(const char *filename __maybe_unused, */ int filename__read_build_id(const char *filename, struct build_id *bid) { - FILE *fp; - int ret = -1; + int fd, ret = -1; bool need_swap = false, elf32; - u8 e_ident[EI_NIDENT]; - int i; union { struct { Elf32_Ehdr ehdr32; @@ -103,28 +99,27 @@ int filename__read_build_id(const char *filename, struct build_id *bid) Elf64_Phdr *phdr64; }; } hdrs; - void *phdr; - size_t phdr_size; - void *buf = NULL; - size_t buf_size = 0; + void *phdr, *buf = NULL; + ssize_t phdr_size, ehdr_size, buf_size = 0; - fp = fopen(filename, "r"); - if (fp == NULL) + fd = open(filename, O_RDONLY); + if (fd < 0) return -1; - if (fread(e_ident, sizeof(e_ident), 1, fp) != 1) + if (read(fd, hdrs.ehdr32.e_ident, EI_NIDENT) != EI_NIDENT) goto out; - if (memcmp(e_ident, ELFMAG, SELFMAG) || - e_ident[EI_VERSION] != EV_CURRENT) + if (memcmp(hdrs.ehdr32.e_ident, ELFMAG, SELFMAG) || + hdrs.ehdr32.e_ident[EI_VERSION] != EV_CURRENT) goto out; - need_swap = check_need_swap(e_ident[EI_DATA]); - elf32 = e_ident[EI_CLASS] == ELFCLASS32; + need_swap = check_need_swap(hdrs.ehdr32.e_ident[EI_DATA]); + elf32 = hdrs.ehdr32.e_ident[EI_CLASS] == ELFCLASS32; + ehdr_size = (elf32 ? sizeof(hdrs.ehdr32) : sizeof(hdrs.ehdr64)) - EI_NIDENT; - if (fread(elf32 ? (void *)&hdrs.ehdr32 : (void *)&hdrs.ehdr64, - elf32 ? sizeof(hdrs.ehdr32) : sizeof(hdrs.ehdr64), - 1, fp) != 1) + if (read(fd, + (elf32 ? (void *)&hdrs.ehdr32 : (void *)&hdrs.ehdr64) + EI_NIDENT, + ehdr_size) != ehdr_size) goto out; if (need_swap) { @@ -138,14 +133,18 @@ int filename__read_build_id(const char *filename, struct build_id *bid) hdrs.ehdr64.e_phnum = bswap_16(hdrs.ehdr64.e_phnum); } } - phdr_size = elf32 ? hdrs.ehdr32.e_phentsize * hdrs.ehdr32.e_phnum - : hdrs.ehdr64.e_phentsize * hdrs.ehdr64.e_phnum; + if ((elf32 && hdrs.ehdr32.e_phentsize != sizeof(Elf32_Phdr)) || + (!elf32 && hdrs.ehdr64.e_phentsize != sizeof(Elf64_Phdr))) + goto out; + + phdr_size = elf32 ? sizeof(Elf32_Phdr) * hdrs.ehdr32.e_phnum + : sizeof(Elf64_Phdr) * hdrs.ehdr64.e_phnum; phdr = malloc(phdr_size); if (phdr == NULL) goto out; - fseek(fp, elf32 ? hdrs.ehdr32.e_phoff : hdrs.ehdr64.e_phoff, SEEK_SET); - if (fread(phdr, phdr_size, 1, fp) != 1) + lseek(fd, elf32 ? hdrs.ehdr32.e_phoff : hdrs.ehdr64.e_phoff, SEEK_SET); + if (read(fd, phdr, phdr_size) != phdr_size) goto out_free; if (elf32) @@ -153,8 +152,8 @@ int filename__read_build_id(const char *filename, struct build_id *bid) else hdrs.phdr64 = phdr; - for (i = 0; i < elf32 ? hdrs.ehdr32.e_phnum : hdrs.ehdr64.e_phnum; i++) { - size_t p_filesz; + for (int i = 0; i < (elf32 ? hdrs.ehdr32.e_phnum : hdrs.ehdr64.e_phnum); i++) { + ssize_t p_filesz; if (need_swap) { if (elf32) { @@ -180,8 +179,8 @@ int filename__read_build_id(const char *filename, struct build_id *bid) goto out_free; buf = tmp; } - fseek(fp, elf32 ? hdrs.phdr32[i].p_offset : hdrs.phdr64[i].p_offset, SEEK_SET); - if (fread(buf, p_filesz, 1, fp) != 1) + lseek(fd, elf32 ? hdrs.phdr32[i].p_offset : hdrs.phdr64[i].p_offset, SEEK_SET); + if (read(fd, buf, p_filesz) != p_filesz) goto out_free; ret = read_build_id(buf, p_filesz, bid, need_swap); @@ -194,7 +193,7 @@ int filename__read_build_id(const char *filename, struct build_id *bid) free(buf); free(phdr); out: - fclose(fp); + close(fd); return ret; } From 2c369d91d0933aaff96b6b807b22363e6a38a625 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 22 Aug 2025 17:00:24 -0700 Subject: [PATCH 0614/1292] perf symbol: Add blocking argument to filename__read_build_id When synthesizing build-ids, for build ID mmap2 events, they will be added for data mmaps if -d/--data is specified. The files opened for their build IDs may block on the open causing perf to hang during synthesis. There is some robustness in existing calls to filename__read_build_id by checking the file path is to a regular file, which unfortunately fails for symlinks. Rather than adding more is_regular_file calls, switch filename__read_build_id to take a "block" argument and specify O_NONBLOCK when this is false. The existing is_regular_file checking callers and the event synthesis callers are made to pass false and thereby avoiding the hang. Fixes: 53b00ff358dc ("perf record: Make --buildid-mmap the default") Signed-off-by: Ian Rogers Link: https://lore.kernel.org/r/20250823000024.724394-3-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/bench/inject-buildid.c | 2 +- tools/perf/builtin-buildid-cache.c | 8 ++++---- tools/perf/builtin-inject.c | 4 ++-- tools/perf/tests/sdt.c | 2 +- tools/perf/util/build-id.c | 4 ++-- tools/perf/util/debuginfo.c | 8 ++++++-- tools/perf/util/dsos.c | 4 ++-- tools/perf/util/symbol-elf.c | 9 +++++---- tools/perf/util/symbol-minimal.c | 6 +++--- tools/perf/util/symbol.c | 8 ++++---- tools/perf/util/symbol.h | 2 +- tools/perf/util/synthetic-events.c | 2 +- 12 files changed, 32 insertions(+), 27 deletions(-) diff --git a/tools/perf/bench/inject-buildid.c b/tools/perf/bench/inject-buildid.c index aad572a78d7fcf..12387ea88b9a9c 100644 --- a/tools/perf/bench/inject-buildid.c +++ b/tools/perf/bench/inject-buildid.c @@ -85,7 +85,7 @@ static int add_dso(const char *fpath, const struct stat *sb __maybe_unused, if (typeflag == FTW_D || typeflag == FTW_SL) return 0; - if (filename__read_build_id(fpath, &bid) < 0) + if (filename__read_build_id(fpath, &bid, /*block=*/true) < 0) return 0; dso->name = realpath(fpath, NULL); diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index c98104481c8a19..2e0f2004696ae9 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -180,7 +180,7 @@ static int build_id_cache__add_file(const char *filename, struct nsinfo *nsi) struct nscookie nsc; nsinfo__mountns_enter(nsi, &nsc); - err = filename__read_build_id(filename, &bid); + err = filename__read_build_id(filename, &bid, /*block=*/true); nsinfo__mountns_exit(&nsc); if (err < 0) { pr_debug("Couldn't read a build-id in %s\n", filename); @@ -204,7 +204,7 @@ static int build_id_cache__remove_file(const char *filename, struct nsinfo *nsi) int err; nsinfo__mountns_enter(nsi, &nsc); - err = filename__read_build_id(filename, &bid); + err = filename__read_build_id(filename, &bid, /*block=*/true); nsinfo__mountns_exit(&nsc); if (err < 0) { pr_debug("Couldn't read a build-id in %s\n", filename); @@ -280,7 +280,7 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused) if (!dso__build_id_filename(dso, filename, sizeof(filename), false)) return true; - if (filename__read_build_id(filename, &bid) == -1) { + if (filename__read_build_id(filename, &bid, /*block=*/true) == -1) { if (errno == ENOENT) return false; @@ -309,7 +309,7 @@ static int build_id_cache__update_file(const char *filename, struct nsinfo *nsi) int err; nsinfo__mountns_enter(nsi, &nsc); - err = filename__read_build_id(filename, &bid); + err = filename__read_build_id(filename, &bid, /*block=*/true); nsinfo__mountns_exit(&nsc); if (err < 0) { pr_debug("Couldn't read a build-id in %s\n", filename); diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 40ba6a94f7196f..a114b3fa1bea1d 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -680,12 +680,12 @@ static int dso__read_build_id(struct dso *dso) mutex_lock(dso__lock(dso)); nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); - if (filename__read_build_id(dso__long_name(dso), &bid) > 0) + if (filename__read_build_id(dso__long_name(dso), &bid, /*block=*/true) > 0) dso__set_build_id(dso, &bid); else if (dso__nsinfo(dso)) { char *new_name = dso__filename_with_chroot(dso, dso__long_name(dso)); - if (new_name && filename__read_build_id(new_name, &bid) > 0) + if (new_name && filename__read_build_id(new_name, &bid, /*block=*/true) > 0) dso__set_build_id(dso, &bid); free(new_name); } diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c index 93baee2eae42ab..6132f1af3e22d3 100644 --- a/tools/perf/tests/sdt.c +++ b/tools/perf/tests/sdt.c @@ -31,7 +31,7 @@ static int build_id_cache__add_file(const char *filename) struct build_id bid = { .size = 0, }; int err; - err = filename__read_build_id(filename, &bid); + err = filename__read_build_id(filename, &bid, /*block=*/true); if (err < 0) { pr_debug("Failed to read build id of %s\n", filename); return err; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a7018a3b0437a6..bf7f3268b9a2f3 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -115,7 +115,7 @@ int filename__snprintf_build_id(const char *pathname, char *sbuild_id, size_t sb struct build_id bid = { .size = 0, }; int ret; - ret = filename__read_build_id(pathname, &bid); + ret = filename__read_build_id(pathname, &bid, /*block=*/true); if (ret < 0) return ret; @@ -841,7 +841,7 @@ static int filename__read_build_id_ns(const char *filename, int ret; nsinfo__mountns_enter(nsi, &nsc); - ret = filename__read_build_id(filename, bid); + ret = filename__read_build_id(filename, bid, /*block=*/true); nsinfo__mountns_exit(&nsc); return ret; diff --git a/tools/perf/util/debuginfo.c b/tools/perf/util/debuginfo.c index a44c70f931568c..bb9ebd84ec2d2a 100644 --- a/tools/perf/util/debuginfo.c +++ b/tools/perf/util/debuginfo.c @@ -110,8 +110,12 @@ struct debuginfo *debuginfo__new(const char *path) if (!dso) goto out; - /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */ - if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0) + /* + * Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO. Don't block + * incase the path isn't for a regular file. + */ + assert(!dso__has_build_id(dso)); + if (filename__read_build_id(path, &bid, /*block=*/false) > 0) dso__set_build_id(dso, &bid); for (type = distro_dwarf_types; diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index 0a7645c7fae7d3..64c1d65b014961 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -81,13 +81,13 @@ static int dsos__read_build_ids_cb(struct dso *dso, void *data) return 0; } nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); - if (filename__read_build_id(dso__long_name(dso), &bid) > 0) { + if (filename__read_build_id(dso__long_name(dso), &bid, /*block=*/true) > 0) { dso__set_build_id(dso, &bid); args->have_build_id = true; } else if (errno == ENOENT && dso__nsinfo(dso)) { char *new_name = dso__filename_with_chroot(dso, dso__long_name(dso)); - if (new_name && filename__read_build_id(new_name, &bid) > 0) { + if (new_name && filename__read_build_id(new_name, &bid, /*block=*/true) > 0) { dso__set_build_id(dso, &bid); args->have_build_id = true; } diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 6d2c280a1730c5..033c79231a54cd 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -902,7 +902,7 @@ static int read_build_id(const char *filename, struct build_id *bid) #else // HAVE_LIBBFD_BUILDID_SUPPORT -static int read_build_id(const char *filename, struct build_id *bid) +static int read_build_id(const char *filename, struct build_id *bid, bool block) { size_t size = sizeof(bid->data); int fd, err = -1; @@ -911,7 +911,7 @@ static int read_build_id(const char *filename, struct build_id *bid) if (size < BUILD_ID_SIZE) goto out; - fd = open(filename, O_RDONLY); + fd = open(filename, block ? O_RDONLY : (O_RDONLY | O_NONBLOCK)); if (fd < 0) goto out; @@ -934,7 +934,7 @@ static int read_build_id(const char *filename, struct build_id *bid) #endif // HAVE_LIBBFD_BUILDID_SUPPORT -int filename__read_build_id(const char *filename, struct build_id *bid) +int filename__read_build_id(const char *filename, struct build_id *bid, bool block) { struct kmod_path m = { .name = NULL, }; char path[PATH_MAX]; @@ -958,9 +958,10 @@ int filename__read_build_id(const char *filename, struct build_id *bid) } close(fd); filename = path; + block = true; } - err = read_build_id(filename, bid); + err = read_build_id(filename, bid, block); if (m.comp) unlink(filename); diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 8d41bd7842dfa3..41e4ebe5eac56e 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -85,7 +85,7 @@ int filename__read_debuglink(const char *filename __maybe_unused, /* * Just try PT_NOTE header otherwise fails */ -int filename__read_build_id(const char *filename, struct build_id *bid) +int filename__read_build_id(const char *filename, struct build_id *bid, bool block) { int fd, ret = -1; bool need_swap = false, elf32; @@ -102,7 +102,7 @@ int filename__read_build_id(const char *filename, struct build_id *bid) void *phdr, *buf = NULL; ssize_t phdr_size, ehdr_size, buf_size = 0; - fd = open(filename, O_RDONLY); + fd = open(filename, block ? O_RDONLY : (O_RDONLY | O_NONBLOCK)); if (fd < 0) return -1; @@ -323,7 +323,7 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, if (ret >= 0) RC_CHK_ACCESS(dso)->is_64_bit = ret; - if (filename__read_build_id(ss->name, &bid) > 0) + if (filename__read_build_id(ss->name, &bid, /*block=*/true) > 0) dso__set_build_id(dso, &bid); return 0; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e816e4220d330d..3fed54de540162 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1869,14 +1869,14 @@ int dso__load(struct dso *dso, struct map *map) /* * Read the build id if possible. This is required for - * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work + * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work. Don't block in case path + * isn't for a regular file. */ - if (!dso__has_build_id(dso) && - is_regular_file(dso__long_name(dso))) { + if (!dso__has_build_id(dso)) { struct build_id bid = { .size = 0, }; __symbol__join_symfs(name, PATH_MAX, dso__long_name(dso)); - if (filename__read_build_id(name, &bid) > 0) + if (filename__read_build_id(name, &bid, /*block=*/false) > 0) dso__set_build_id(dso, &bid); } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 3fb5d146d9b15b..3471062187992a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -140,7 +140,7 @@ struct symbol *dso__next_symbol(struct symbol *sym); enum dso_type dso__type_fd(int fd); -int filename__read_build_id(const char *filename, struct build_id *id); +int filename__read_build_id(const char *filename, struct build_id *id, bool block); int sysfs__read_build_id(const char *filename, struct build_id *bid); int modules__parse(const char *filename, void *arg, int (*process_module)(void *arg, const char *name, diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index cb2c1ace304aec..fcd1fd13c30e6e 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -401,7 +401,7 @@ static void perf_record_mmap2__read_build_id(struct perf_record_mmap2 *event, nsi = nsinfo__new(event->pid); nsinfo__mountns_enter(nsi, &nc); - rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1; + rc = filename__read_build_id(event->filename, &bid, /*block=*/false) > 0 ? 0 : -1; nsinfo__mountns_exit(&nc); nsinfo__put(nsi); From 70c1595c181c48a022756116a6c46d5e8bad2c6f Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 21 Aug 2025 16:23:14 +0900 Subject: [PATCH 0615/1292] ata: ahci: Allow ignoring the external/hotplug capability of ports Commit 4edf1505b76d ("ata: ahci: Disallow LPM policy control for external ports") introduced disabling link power management (LPM) for ports that are advertized as external/hotplug capable. This is necessary to force the maximum power policy (ATA_LPM_MAX_POWER) onto the port link to ensure that the hotplug capability of the port is functional. However, doing so blindly for all ports can prevent systems from going into a low power state, even if the external/hotplug ports on the system are unused. E.g., a laptop may see the internal SATA slot of a docking station as an external hotplug capable port, and in such case, the user may prefer to not use the port and to favor instead enabling LPM to allow the laptop to transition to low power states. Since there is no easy method to automatically detect such choice, introduce the new mask_port_ext module parameter to allow a user to ignore the external/hotplug capability of a port. The format for this parameter value is identical to the format used for the mask_port_map parameter: a mask can be defined for all AHCI adapters of a system or for a particular adapters identified with their PCI IDs (bus:dev.func format). The function ahci_get_port_map_mask() is renamed to ahci_get_port_mask() and modified to return a mask, either for the port map mask of an adapter (to ignore ports) or for the external/hotplug capability of an adapter. Differentiation between map_port_mask and map_port_ext_mask is done by passing the parameter string to ahci_get_port_mask() as a second argument. To be consistent with this change, the function ahci_apply_port_map_mask() is renamed ahci_port_mask() and changed to return a mask value. The mask for the external/hotplug capability for an adapter, if defined by the map_port_ext_mask parameter, is stored in the new field mask_port_ext of struct ahci_host_priv. ahci_mark_external_port() is modified to not set the ATA_PFLAG_EXTERNAL flag for a port if hpriv->mask_port_ext includes the number of the port. In such case, an information message is printed to notify that the external/hotplug capability is being ignored. Reported-by: Dieter Mummenschanz Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220465 Fixes: 4edf1505b76d ("ata: ahci: Disallow LPM policy control for external ports") Signed-off-by: Damien Le Moal Tested-by: Dieter Mummenschanz --- drivers/ata/ahci.c | 57 ++++++++++++++++++++++++++++++++-------------- drivers/ata/ahci.h | 1 + 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e1c24bbacf648c..7a7f88b3fa2b18 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -689,40 +689,50 @@ MODULE_PARM_DESC(mask_port_map, "where is the PCI ID of an AHCI controller in the " "form \"domain:bus:dev.func\""); -static void ahci_apply_port_map_mask(struct device *dev, - struct ahci_host_priv *hpriv, char *mask_s) +static char *ahci_mask_port_ext; +module_param_named(mask_port_ext, ahci_mask_port_ext, charp, 0444); +MODULE_PARM_DESC(mask_port_ext, + "32-bits mask to ignore the external/hotplug capability of ports. " + "Valid values are: " + "\"\" to apply the same mask to all AHCI controller " + "devices, and \"=,=,...\" to " + "specify different masks for the controllers specified, " + "where is the PCI ID of an AHCI controller in the " + "form \"domain:bus:dev.func\""); + +static u32 ahci_port_mask(struct device *dev, char *mask_s) { unsigned int mask; if (kstrtouint(mask_s, 0, &mask)) { dev_err(dev, "Invalid port map mask\n"); - return; + return 0; } - hpriv->mask_port_map = mask; + return mask; } -static void ahci_get_port_map_mask(struct device *dev, - struct ahci_host_priv *hpriv) +static u32 ahci_get_port_mask(struct device *dev, char *mask_p) { char *param, *end, *str, *mask_s; char *name; + u32 mask = 0; - if (!strlen(ahci_mask_port_map)) - return; + if (!mask_p || !strlen(mask_p)) + return 0; - str = kstrdup(ahci_mask_port_map, GFP_KERNEL); + str = kstrdup(mask_p, GFP_KERNEL); if (!str) - return; + return 0; /* Handle single mask case */ if (!strchr(str, '=')) { - ahci_apply_port_map_mask(dev, hpriv, str); + mask = ahci_port_mask(dev, str); goto free; } /* - * Mask list case: parse the parameter to apply the mask only if + * Mask list case: parse the parameter to get the mask only if * the device name matches. */ param = str; @@ -752,11 +762,13 @@ static void ahci_get_port_map_mask(struct device *dev, param++; } - ahci_apply_port_map_mask(dev, hpriv, mask_s); + mask = ahci_port_mask(dev, mask_s); } free: kfree(str); + + return mask; } static void ahci_pci_save_initial_config(struct pci_dev *pdev, @@ -782,8 +794,10 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev, } /* Handle port map masks passed as module parameter. */ - if (ahci_mask_port_map) - ahci_get_port_map_mask(&pdev->dev, hpriv); + hpriv->mask_port_map = + ahci_get_port_mask(&pdev->dev, ahci_mask_port_map); + hpriv->mask_port_ext = + ahci_get_port_mask(&pdev->dev, ahci_mask_port_ext); ahci_save_initial_config(&pdev->dev, hpriv); } @@ -1757,11 +1771,20 @@ static void ahci_mark_external_port(struct ata_port *ap) void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; - /* mark external ports (hotplug-capable, eSATA) */ + /* + * Mark external ports (hotplug-capable, eSATA), unless we were asked to + * ignore this feature. + */ tmp = readl(port_mmio + PORT_CMD); if (((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)) || - (tmp & PORT_CMD_HPCP)) + (tmp & PORT_CMD_HPCP)) { + if (hpriv->mask_port_ext & (1U << ap->port_no)) { + ata_port_info(ap, + "Ignoring external/hotplug capability\n"); + return; + } ap->pflags |= ATA_PFLAG_EXTERNAL; + } } static void ahci_update_initial_lpm_policy(struct ata_port *ap) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 2c10c8f440d122..293b7fb216b517 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -330,6 +330,7 @@ struct ahci_host_priv { /* Input fields */ unsigned int flags; /* AHCI_HFLAG_* */ u32 mask_port_map; /* Mask of valid ports */ + u32 mask_port_ext; /* Mask of ports ext capability */ void __iomem * mmio; /* bus-independent mem map */ u32 cap; /* cap to use */ From d280233fc86692f495d5e08092e5422bc2f583a8 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Fri, 22 Aug 2025 16:28:05 +0530 Subject: [PATCH 0616/1292] Octeontx2-af: Fix NIX X2P calibration failures Before configuring the NIX block, the AF driver initiates the "NIX block X2P bus calibration" and verifies that NIX interfaces such as CGX and LBK are active and functioning correctly. On few silicon variants(CNF10KA and CNF10KB), X2P calibration failures have been observed on some CGX blocks that are not mapped to the NIX block. Since both NIX-mapped and non-NIX-mapped CGX blocks share the same VENDOR,DEVICE,SUBSYS_DEVID, it's not possible to skip probe based on these parameters. This patch introuduces "is_cgx_mapped_to_nix" API to detect and skip probe of non NIX mapped CGX blocks. Fixes: aba53d5dbcea ("octeontx2-af: NIX block admin queue init") Signed-off-by: Hariprasad Kelam Link: https://patch.msgid.link/20250822105805.2236528-1-hkelam@marvell.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 7 +++++++ drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 4ff19a04b23ee6..0c46ba8a5adc8f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -1978,6 +1978,13 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_release_regions; } + if (!is_cn20k(pdev) && + !is_cgx_mapped_to_nix(pdev->subsystem_device, cgx->cgx_id)) { + dev_notice(dev, "CGX %d not mapped to NIX, skipping probe\n", + cgx->cgx_id); + goto err_release_regions; + } + cgx->lmac_count = cgx->mac_ops->get_nr_lmacs(cgx); if (!cgx->lmac_count) { dev_notice(dev, "CGX %d LMAC count is zero, skipping probe\n", cgx->cgx_id); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 7ee1fdeb5295f3..18c7bb39dbc73b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -783,6 +783,20 @@ static inline bool is_cn10kb(struct rvu *rvu) return false; } +static inline bool is_cgx_mapped_to_nix(unsigned short id, u8 cgx_id) +{ + /* On CNF10KA and CNF10KB silicons only two CGX blocks are connected + * to NIX. + */ + if (id == PCI_SUBSYS_DEVID_CNF10K_A || id == PCI_SUBSYS_DEVID_CNF10K_B) + return cgx_id <= 1; + + return !(cgx_id && !(id == PCI_SUBSYS_DEVID_96XX || + id == PCI_SUBSYS_DEVID_98XX || + id == PCI_SUBSYS_DEVID_CN10K_A || + id == PCI_SUBSYS_DEVID_CN10K_B)); +} + static inline bool is_rvu_npc_hash_extract_en(struct rvu *rvu) { u64 npc_const3; From 97766512a9951b9fd6fc97f1b93211642bb0b220 Mon Sep 17 00:00:00 2001 From: Vladimir Riabchun Date: Fri, 22 Aug 2025 20:11:36 +0200 Subject: [PATCH 0617/1292] mISDN: hfcpci: Fix warning when deleting uninitialized timer With CONFIG_DEBUG_OBJECTS_TIMERS unloading hfcpci module leads to the following splat: [ 250.215892] ODEBUG: assert_init not available (active state 0) object: ffffffffc01a3dc0 object type: timer_list hint: 0x0 [ 250.217520] WARNING: CPU: 0 PID: 233 at lib/debugobjects.c:612 debug_print_object+0x1b6/0x2c0 [ 250.218775] Modules linked in: hfcpci(-) mISDN_core [ 250.219537] CPU: 0 UID: 0 PID: 233 Comm: rmmod Not tainted 6.17.0-rc2-g6f713187ac98 #2 PREEMPT(voluntary) [ 250.220940] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 250.222377] RIP: 0010:debug_print_object+0x1b6/0x2c0 [ 250.223131] Code: fc ff df 48 89 fa 48 c1 ea 03 80 3c 02 00 75 4f 41 56 48 8b 14 dd a0 4e 01 9f 48 89 ee 48 c7 c7 20 46 01 9f e8 cb 84d [ 250.225805] RSP: 0018:ffff888015ea7c08 EFLAGS: 00010286 [ 250.226608] RAX: 0000000000000000 RBX: 0000000000000005 RCX: ffffffff9be93a95 [ 250.227708] RDX: 1ffff1100d945138 RSI: 0000000000000008 RDI: ffff88806ca289c0 [ 250.228993] RBP: ffffffff9f014a00 R08: 0000000000000001 R09: ffffed1002bd4f39 [ 250.230043] R10: ffff888015ea79cf R11: 0000000000000001 R12: 0000000000000001 [ 250.231185] R13: ffffffff9eea0520 R14: 0000000000000000 R15: ffff888015ea7cc8 [ 250.232454] FS: 00007f3208f01540(0000) GS:ffff8880caf5a000(0000) knlGS:0000000000000000 [ 250.233851] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 250.234856] CR2: 00007f32090a7421 CR3: 0000000004d63000 CR4: 00000000000006f0 [ 250.236117] Call Trace: [ 250.236599] [ 250.236967] ? trace_irq_enable.constprop.0+0xd4/0x130 [ 250.237920] debug_object_assert_init+0x1f6/0x310 [ 250.238762] ? __pfx_debug_object_assert_init+0x10/0x10 [ 250.239658] ? __lock_acquire+0xdea/0x1c70 [ 250.240369] __try_to_del_timer_sync+0x69/0x140 [ 250.241172] ? __pfx___try_to_del_timer_sync+0x10/0x10 [ 250.242058] ? __timer_delete_sync+0xc6/0x120 [ 250.242842] ? lock_acquire+0x30/0x80 [ 250.243474] ? __timer_delete_sync+0xc6/0x120 [ 250.244262] __timer_delete_sync+0x98/0x120 [ 250.245015] HFC_cleanup+0x10/0x20 [hfcpci] [ 250.245704] __do_sys_delete_module+0x348/0x510 [ 250.246461] ? __pfx___do_sys_delete_module+0x10/0x10 [ 250.247338] do_syscall_64+0xc1/0x360 [ 250.247924] entry_SYSCALL_64_after_hwframe+0x77/0x7f Fix this by initializing hfc_tl timer with DEFINE_TIMER macro. Also, use mod_timer instead of manual timeout update. Fixes: 87c5fa1bb426 ("mISDN: Add different different timer settings for hfc-pci") Fixes: 175302f6b79e ("mISDN: hfcpci: Fix use-after-free bug in hfcpci_softirq") Signed-off-by: Vladimir Riabchun Link: https://patch.msgid.link/aKiy2D_LiWpQ5kXq@vova-pc Signed-off-by: Jakub Kicinski --- drivers/isdn/hardware/mISDN/hfcpci.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 2b05722d4dbe8b..ea8a0ab47afd8a 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -39,12 +39,13 @@ #include "hfc_pci.h" +static void hfcpci_softirq(struct timer_list *unused); static const char *hfcpci_revision = "2.0"; static int HFC_cnt; static uint debug; static uint poll, tics; -static struct timer_list hfc_tl; +static DEFINE_TIMER(hfc_tl, hfcpci_softirq); static unsigned long hfc_jiffies; MODULE_AUTHOR("Karsten Keil"); @@ -2305,8 +2306,7 @@ hfcpci_softirq(struct timer_list *unused) hfc_jiffies = jiffies + 1; else hfc_jiffies += tics; - hfc_tl.expires = hfc_jiffies; - add_timer(&hfc_tl); + mod_timer(&hfc_tl, hfc_jiffies); } static int __init @@ -2332,10 +2332,8 @@ HFC_init(void) if (poll != HFCPCI_BTRANS_THRESHOLD) { printk(KERN_INFO "%s: Using alternative poll value of %d\n", __func__, poll); - timer_setup(&hfc_tl, hfcpci_softirq, 0); - hfc_tl.expires = jiffies + tics; - hfc_jiffies = hfc_tl.expires; - add_timer(&hfc_tl); + hfc_jiffies = jiffies + tics; + mod_timer(&hfc_tl, hfc_jiffies); } else tics = 0; /* indicate the use of controller's timer */ From 007a5ffadc4fd51739527f1503b7cf048f31c413 Mon Sep 17 00:00:00 2001 From: Yeounsu Moon Date: Sun, 24 Aug 2025 03:29:24 +0900 Subject: [PATCH 0618/1292] net: dlink: fix multicast stats being counted incorrectly `McstFramesRcvdOk` counts the number of received multicast packets, and it reports the value correctly. However, reading `McstFramesRcvdOk` clears the register to zero. As a result, the driver was reporting only the packets since the last read, instead of the accumulated total. Fix this by updating the multicast statistics accumulatively instaed of instantaneously. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Tested-on: D-Link DGE-550T Rev-A3 Signed-off-by: Yeounsu Moon Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250823182927.6063-3-yyyynoom@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/dlink/dl2k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c index cc60ee454bf9be..6bbf6e5584e54f 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -1099,7 +1099,7 @@ get_stats (struct net_device *dev) dev->stats.rx_bytes += dr32(OctetRcvOk); dev->stats.tx_bytes += dr32(OctetXmtOk); - dev->stats.multicast = dr32(McstFramesRcvdOk); + dev->stats.multicast += dr32(McstFramesRcvdOk); dev->stats.collisions += dr32(SingleColFrames) + dr32(MultiColFrames); From 22763c35c635466545c0cea825da01c72becbcea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Thu, 21 Aug 2025 12:16:05 +0300 Subject: [PATCH 0619/1292] rust: opp: use to_result for error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifies error handling by replacing the manual check of the return value with the `to_result` helper. Signed-off-by: Onur Ɩzkan Reviewed-by: Elle Rhumsaa Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index 08126035d2c66f..9d79c2816af5cc 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -12,7 +12,7 @@ use crate::{ clk::Hertz, cpumask::{Cpumask, CpumaskVar}, device::Device, - error::{code::*, from_err_ptr, from_result, to_result, Error, Result, VTABLE_DEFAULT_ERROR}, + error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR}, ffi::c_ulong, prelude::*, str::CString, @@ -500,11 +500,8 @@ impl Config { // requirements. The OPP core guarantees not to access fields of [`Config`] after this call // and so we don't need to save a copy of them for future use. let ret = unsafe { bindings::dev_pm_opp_set_config(dev.as_raw(), &mut config) }; - if ret < 0 { - Err(Error::from_errno(ret)) - } else { - Ok(ConfigToken(ret)) - } + + to_result(ret).map(|()| ConfigToken(ret)) } /// Config's clk callback. @@ -713,11 +710,8 @@ impl Table { // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety // requirements. let ret = unsafe { bindings::dev_pm_opp_get_opp_count(self.dev.as_raw()) }; - if ret < 0 { - Err(Error::from_errno(ret)) - } else { - Ok(ret as u32) - } + + to_result(ret).map(|()| ret as u32) } /// Returns max clock latency (in nanoseconds) of the [`OPP`]s in the [`Table`]. From 05db35963eef7a55f1782190185cb8ddb9d923b7 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Wed, 20 Aug 2025 13:58:47 +0530 Subject: [PATCH 0620/1292] OPP: Add support to find OPP for a set of keys Some clients, such as PCIe, may operate at the same clock frequency across different data rates by varying link width. In such cases, frequency alone is not sufficient to uniquely identify an OPP. To support these scenarios, introduce a new API dev_pm_opp_find_key_exact() that allows OPP lookup with different set of keys like freq, level & bandwidth. Signed-off-by: Krishna Chaitanya Chundru [ Viresh: Minor cleanups ] Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 99 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 30 +++++++++++++ 2 files changed, 129 insertions(+) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index edbd60501cf00d..bba4f7daff8cb8 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -476,6 +476,16 @@ static unsigned long _read_bw(struct dev_pm_opp *opp, int index) return opp->bandwidth[index].peak; } +static unsigned long _read_opp_key(struct dev_pm_opp *opp, int index, + struct dev_pm_opp_key *key) +{ + key->bw = opp->bandwidth ? opp->bandwidth[index].peak : 0; + key->freq = opp->rates[index]; + key->level = opp->level; + + return true; +} + /* Generic comparison helpers */ static bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp, unsigned long opp_key, unsigned long key) @@ -509,6 +519,22 @@ static bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp, return false; } +static bool _compare_opp_key_exact(struct dev_pm_opp **opp, + struct dev_pm_opp *temp_opp, struct dev_pm_opp_key *opp_key, + struct dev_pm_opp_key *key) +{ + bool level_match = (key->level == OPP_LEVEL_UNSET || opp_key->level == key->level); + bool freq_match = (key->freq == 0 || opp_key->freq == key->freq); + bool bw_match = (key->bw == 0 || opp_key->bw == key->bw); + + if (freq_match && level_match && bw_match) { + *opp = temp_opp; + return true; + } + + return false; +} + /* Generic key finding helpers */ static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table, unsigned long *key, int index, bool available, @@ -541,6 +567,37 @@ static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table, return opp; } +static struct dev_pm_opp *_opp_table_find_opp_key(struct opp_table *opp_table, + struct dev_pm_opp_key *key, bool available, + unsigned long (*read)(struct dev_pm_opp *opp, int index, + struct dev_pm_opp_key *key), + bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp, + struct dev_pm_opp_key *opp_key, struct dev_pm_opp_key *key), + bool (*assert)(struct opp_table *opp_table, unsigned int index)) +{ + struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); + struct dev_pm_opp_key temp_key; + + /* Assert that the requirement is met */ + if (!assert(opp_table, 0)) + return ERR_PTR(-EINVAL); + + guard(mutex)(&opp_table->lock); + + list_for_each_entry(temp_opp, &opp_table->opp_list, node) { + if (temp_opp->available == available) { + read(temp_opp, 0, &temp_key); + if (compare(&opp, temp_opp, &temp_key, key)) { + /* Increment the reference count of OPP */ + dev_pm_opp_get(opp); + break; + } + } + } + + return opp; +} + static struct dev_pm_opp * _find_key(struct device *dev, unsigned long *key, int index, bool available, unsigned long (*read)(struct dev_pm_opp *opp, int index), @@ -632,6 +689,48 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact); +/** + * dev_pm_opp_find_key_exact() - Search for an OPP with exact key set + * @dev: Device for which the OPP is being searched + * @key: OPP key set to match + * @available: true/false - match for available OPP + * + * Search for an exact match of the key set in the OPP table. + * + * Return: A matching opp on success, else ERR_PTR in case of error. + * Possible error values: + * EINVAL: for bad pointers + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices + * + * Note: 'available' is a modifier for the search. If 'available' == true, + * then the match is for exact matching key and is available in the stored + * OPP table. If false, the match is for exact key which is not available. + * + * This provides a mechanism to enable an OPP which is not available currently + * or the opposite as well. + * + * The callers are required to call dev_pm_opp_put() for the returned OPP after + * use. + */ +struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, + struct dev_pm_opp_key *key, + bool available) +{ + struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev); + + if (IS_ERR(opp_table)) { + dev_err(dev, "%s: OPP table not found (%ld)\n", __func__, + PTR_ERR(opp_table)); + return ERR_CAST(opp_table); + } + + return _opp_table_find_opp_key(opp_table, key, available, + _read_opp_key, _compare_opp_key_exact, + assert_single_clk); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_find_key_exact); + /** * dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the * clock corresponding to the index diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index cf477beae4bbed..789406d95e69f8 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -98,6 +98,25 @@ struct dev_pm_opp_data { unsigned long u_volt; }; +/** + * struct dev_pm_opp_key - Key used to identify OPP entries + * @freq: Frequency in Hz. Use 0 if frequency is not to be matched. + * @level: Performance level associated with the OPP entry. + * Use OPP_LEVEL_UNSET if level is not to be matched. + * @bw: Bandwidth associated with the OPP entry. + * Use 0 if bandwidth is not to be matched. + * + * This structure is used to uniquely identify an OPP entry based on + * frequency, performance level, and bandwidth. Each field can be + * selectively ignored during matching by setting it to its respective + * NOP value. + */ +struct dev_pm_opp_key { + unsigned long freq; + unsigned int level; + u32 bw; +}; + #if defined(CONFIG_PM_OPP) struct opp_table *dev_pm_opp_get_opp_table(struct device *dev); @@ -131,6 +150,10 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, unsigned long freq, bool available); +struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, + struct dev_pm_opp_key *key, + bool available); + struct dev_pm_opp * dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq, u32 index, bool available); @@ -289,6 +312,13 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, return ERR_PTR(-EOPNOTSUPP); } +static inline struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, + struct dev_pm_opp_key *key, + bool available) +{ + return ERR_PTR(-EOPNOTSUPP); +} + static inline struct dev_pm_opp * dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq, u32 index, bool available) From a39d13e291c2681e475d9fd41655764dab09be7b Mon Sep 17 00:00:00 2001 From: Liming Wu Date: Thu, 31 Jul 2025 17:27:57 +0800 Subject: [PATCH 0621/1292] virtio_pci: Fix misleading comment for queue vector This patch fixes misleading comments in both legacy and modern virtio-pci device implementations. The comments previously referred to the "config vector" for parameters and return values of the `vp_legacy_queue_vector()` and `vp_modern_queue_vector()` functions, which is incorrect. Signed-off-by: Liming Wu Message-Id: <20250731092757.1000-1-liming.wu@jaguarmicro.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_legacy_dev.c | 4 ++-- drivers/virtio/virtio_pci_modern_dev.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/virtio/virtio_pci_legacy_dev.c b/drivers/virtio/virtio_pci_legacy_dev.c index 677d1f68bc9bf2..bbbf89c22880a5 100644 --- a/drivers/virtio/virtio_pci_legacy_dev.c +++ b/drivers/virtio/virtio_pci_legacy_dev.c @@ -140,9 +140,9 @@ EXPORT_SYMBOL_GPL(vp_legacy_set_status); * vp_legacy_queue_vector - set the MSIX vector for a specific virtqueue * @ldev: the legacy virtio-pci device * @index: queue index - * @vector: the config vector + * @vector: the queue vector * - * Returns the config vector read from the device + * Returns the queue vector read from the device */ u16 vp_legacy_queue_vector(struct virtio_pci_legacy_device *ldev, u16 index, u16 vector) diff --git a/drivers/virtio/virtio_pci_modern_dev.c b/drivers/virtio/virtio_pci_modern_dev.c index d665f8f73ea863..9e503b7a58d813 100644 --- a/drivers/virtio/virtio_pci_modern_dev.c +++ b/drivers/virtio/virtio_pci_modern_dev.c @@ -546,9 +546,9 @@ EXPORT_SYMBOL_GPL(vp_modern_set_queue_reset); * vp_modern_queue_vector - set the MSIX vector for a specific virtqueue * @mdev: the modern virtio-pci device * @index: queue index - * @vector: the config vector + * @vector: the queue vector * - * Returns the config vector read from the device + * Returns the queue vector read from the device */ u16 vp_modern_queue_vector(struct virtio_pci_modern_device *mdev, u16 index, u16 vector) From dd54bcf86c91a4455b1f95cbc8e9ac91205f3193 Mon Sep 17 00:00:00 2001 From: Nikolay Kuratov Date: Tue, 5 Aug 2025 16:09:17 +0300 Subject: [PATCH 0622/1292] vhost/net: Protect ubufs with rcu read lock in vhost_net_ubuf_put() When operating on struct vhost_net_ubuf_ref, the following execution sequence is theoretically possible: CPU0 is finalizing DMA operation CPU1 is doing VHOST_NET_SET_BACKEND // ubufs->refcount == 2 vhost_net_ubuf_put() vhost_net_ubuf_put_wait_and_free(oldubufs) vhost_net_ubuf_put_and_wait() vhost_net_ubuf_put() int r = atomic_sub_return(1, &ubufs->refcount); // r = 1 int r = atomic_sub_return(1, &ubufs->refcount); // r = 0 wait_event(ubufs->wait, !atomic_read(&ubufs->refcount)); // no wait occurs here because condition is already true kfree(ubufs); if (unlikely(!r)) wake_up(&ubufs->wait); // use-after-free This leads to use-after-free on ubufs access. This happens because CPU1 skips waiting for wake_up() when refcount is already zero. To prevent that use a read-side RCU critical section in vhost_net_ubuf_put(), as suggested by Hillf Danton. For this lock to take effect, free ubufs with kfree_rcu(). Cc: stable@vger.kernel.org Fixes: 0ad8b480d6ee9 ("vhost: fix ref cnt checking deadlock") Reported-by: Andrey Ryabinin Suggested-by: Hillf Danton Signed-off-by: Nikolay Kuratov Message-Id: <20250805130917.727332-1-kniv@yandex-team.ru> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 6edac0c1ba9bbf..c6508fe0d5c8e5 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -99,6 +99,7 @@ struct vhost_net_ubuf_ref { atomic_t refcount; wait_queue_head_t wait; struct vhost_virtqueue *vq; + struct rcu_head rcu; }; #define VHOST_NET_BATCH 64 @@ -250,9 +251,13 @@ vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) { - int r = atomic_sub_return(1, &ubufs->refcount); + int r; + + rcu_read_lock(); + r = atomic_sub_return(1, &ubufs->refcount); if (unlikely(!r)) wake_up(&ubufs->wait); + rcu_read_unlock(); return r; } @@ -265,7 +270,7 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) { vhost_net_ubuf_put_and_wait(ubufs); - kfree(ubufs); + kfree_rcu(ubufs, rcu); } static void vhost_net_clear_ubuf_info(struct vhost_net *n) From ced17ee32a9988b8a260628e7c31a100d7dc082e Mon Sep 17 00:00:00 2001 From: Igor Torrente Date: Thu, 7 Aug 2025 09:41:45 -0300 Subject: [PATCH 0623/1292] Revert "virtio: reject shm region if length is zero" The commit 206cc44588f7 ("virtio: reject shm region if length is zero") breaks the Virtio-gpu `host_visible` feature. As you can see in the snippet below, host_visible_region is zero because of the `kzalloc`. It's using the `vm_get_shm_region` (drivers/virtio/virtio_mmio.c:536) to read the `addr` and `len` from qemu/crosvm. ``` drivers/gpu/drm/virtio/virtgpu_kms.c 132 vgdev = drmm_kzalloc(dev, sizeof(struct virtio_gpu_device), GFP_KERNEL); [...] 177 if (virtio_get_shm_region(vgdev->vdev, &vgdev->host_visible_region, 178 VIRTIO_GPU_SHM_ID_HOST_VISIBLE)) { ``` Now it always fails. To fix, revert the offending commit. Fixes: 206cc44588f7 ("virtio: reject shm region if length is zero") Signed-off-by: Igor Torrente Message-Id: <20250807124145.81816-1-igor.torrente@collabora.com> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 918cf25cd3c69d..8bf156dde554a5 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -328,8 +328,6 @@ static inline bool virtio_get_shm_region(struct virtio_device *vdev, struct virtio_shm_region *region, u8 id) { - if (!region->len) - return false; if (!vdev->config->get_shm_region) return false; return vdev->config->get_shm_region(vdev, region, id); From 24fc631539cc78225f5c61f99c7666fcff48024d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Aug 2025 23:39:57 -0700 Subject: [PATCH 0624/1292] vhost: Fix ioctl # for VHOST_[GS]ET_FORK_FROM_OWNER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VHOST_[GS]ET_FEATURES_ARRAY ioctl already took 0x83 and it would result in a build error when the vhost uapi header is used for perf tool build like below. In file included from trace/beauty/ioctl.c:93: tools/perf/trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c: In function ā€˜ioctl__scnprintf_vhost_virtio_cmd’: tools/perf/trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c:36:18: error: initialized field overwritten [-Werror=override-init] 36 | [0x83] = "SET_FORK_FROM_OWNER", | ^~~~~~~~~~~~~~~~~~~~~ tools/perf/trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c:36:18: note: (near initialization for ā€˜vhost_virtio_ioctl_cmds[131]’) Fixes: 7d9896e9f6d02d8a ("vhost: Reintroduce kthread API and add mode selection") Signed-off-by: Namhyung Kim Message-Id: <20250819063958.833770-1-namhyung@kernel.org> Signed-off-by: Michael S. Tsirkin Tested-by: Lei Yang --- include/uapi/linux/vhost.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index 283348b64af9ac..c57674a6aa0dbb 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -260,7 +260,7 @@ * When fork_owner is set to VHOST_FORK_OWNER_KTHREAD: * - Vhost will create vhost workers as kernel threads. */ -#define VHOST_SET_FORK_FROM_OWNER _IOW(VHOST_VIRTIO, 0x83, __u8) +#define VHOST_SET_FORK_FROM_OWNER _IOW(VHOST_VIRTIO, 0x84, __u8) /** * VHOST_GET_FORK_OWNER - Get the current fork_owner flag for the vhost device. @@ -268,6 +268,6 @@ * * @return: An 8-bit value indicating the current thread mode. */ -#define VHOST_GET_FORK_FROM_OWNER _IOR(VHOST_VIRTIO, 0x84, __u8) +#define VHOST_GET_FORK_FROM_OWNER _IOR(VHOST_VIRTIO, 0x85, __u8) #endif From 528d92bfc0937a6a1ec837dbbcb3612a8545cd37 Mon Sep 17 00:00:00 2001 From: Ying Gao Date: Tue, 12 Aug 2025 17:51:18 +0800 Subject: [PATCH 0625/1292] virtio_input: Improve freeze handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When executing suspend to ram, if lacking the operations to reset device and free unused buffers before deleting a vq, resource leaks and inconsistent device status will appear. According to chapter "3.3.1 Driver Requirements: Device Cleanup:" of virtio-specification: Driver MUST ensure a virtqueue isn’t live (by device reset) before removing exposed buffers. Therefore, modify the virtinput_freeze function to reset the device and delete the unused buffers before deleting the virtqueue, just like virtinput_remove does. Co-developed-by: Ying Xu Signed-off-by: Ying Xu Co-developed-by: Junnan Wu Signed-off-by: Junnan Wu Signed-off-by: Ying Gao Message-Id: <20250812095118.3622717-1-ying01.gao@samsung.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_input.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c index a5d63269f20b94..d0728285b6ce96 100644 --- a/drivers/virtio/virtio_input.c +++ b/drivers/virtio/virtio_input.c @@ -360,11 +360,15 @@ static int virtinput_freeze(struct virtio_device *vdev) { struct virtio_input *vi = vdev->priv; unsigned long flags; + void *buf; spin_lock_irqsave(&vi->lock, flags); vi->ready = false; spin_unlock_irqrestore(&vi->lock, flags); + virtio_reset_device(vdev); + while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL) + kfree(buf); vdev->config->del_vqs(vdev); return 0; } From 45d8ef6322b8a828d3b1e2cfb8893e2ff882cb23 Mon Sep 17 00:00:00 2001 From: Junnan Wu Date: Tue, 12 Aug 2025 17:08:17 +0800 Subject: [PATCH 0626/1292] virtio_net: adjust the execution order of function `virtnet_close` during freeze "Use after free" issue appears in suspend once race occurs when napi poll scheduls after `netif_device_detach` and before napi disables. For details, during suspend flow of virtio-net, the tx queue state is set to "__QUEUE_STATE_DRV_XOFF" by CPU-A. And at some coincidental times, if a TCP connection is still working, CPU-B does `virtnet_poll` before napi disable. In this flow, the state "__QUEUE_STATE_DRV_XOFF" of tx queue will be cleared. This is not the normal process it expects. After that, CPU-A continues to close driver then virtqueue is removed. Sequence likes below: -------------------------------------------------------------------------- CPU-A CPU-B ----- ----- suspend is called A TCP based on virtio-net still work virtnet_freeze |- virtnet_freeze_down | |- netif_device_detach | | |- netif_tx_stop_all_queues | | |- netif_tx_stop_queue | | |- set_bit | | (__QUEUE_STATE_DRV_XOFF,...) | | softirq rasied | | |- net_rx_action | | |- napi_poll | | |- virtnet_poll | | |- virtnet_poll_cleantx | | |- netif_tx_wake_queue | | |- test_and_clear_bit | | (__QUEUE_STATE_DRV_XOFF,...) | |- virtnet_close | |- virtnet_disable_queue_pair | |- virtnet_napi_tx_disable |- remove_vq_common -------------------------------------------------------------------------- When TCP delayack timer is up, a cpu gets softirq and irq handler `tcp_delack_timer_handler` will be called, which will finally call `start_xmit` in virtio net driver. Then the access to tx virtq will cause panic. The root cause of this issue is that napi tx is not disable before `netif_tx_stop_queue`, once `virnet_poll` schedules in such coincidental time, the tx queue state will be cleared. To solve this issue, adjusts the order of function `virtnet_close` in `virtnet_freeze_down`. Co-developed-by: Ying Xu Signed-off-by: Ying Xu Signed-off-by: Junnan Wu Message-Id: <20250812090817.3463403-1-junnan01.wu@samsung.com> Signed-off-by: Michael S. Tsirkin --- drivers/net/virtio_net.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index d14e6d6022735a..975bdc5dab84b5 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -5758,14 +5758,15 @@ static void virtnet_freeze_down(struct virtio_device *vdev) disable_rx_mode_work(vi); flush_work(&vi->rx_mode_work); - netif_tx_lock_bh(vi->dev); - netif_device_detach(vi->dev); - netif_tx_unlock_bh(vi->dev); if (netif_running(vi->dev)) { rtnl_lock(); virtnet_close(vi->dev); rtnl_unlock(); } + + netif_tx_lock_bh(vi->dev); + netif_device_detach(vi->dev); + netif_tx_unlock_bh(vi->dev); } static int init_vqs(struct virtnet_info *vi); From b3dcc9d1d806fb1e175f85978713eef868531da4 Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (Microsoft)" Date: Tue, 26 Aug 2025 10:19:46 +0300 Subject: [PATCH 0627/1292] memblock: fix kernel-doc for MEMBLOCK_RSRV_NOINIT The kernel-doc description of MEMBLOCK_RSRV_NOINIT and memblock_reserved_mark_noinit() do not accurately describe their functionality. Expand their kernel doc to make it clear that the user of MEMBLOCK_RSRV_NOINIT is responsible to properly initialize the struct pages for such regions and add more details about effects of using this flag. Reviewed-by: David Hildenbrand Link: https://lore.kernel.org/r/f8140a17-c4ec-489b-b314-d45abe48bf36@redhat.com Link: https://lore.kernel.org/r/20250826071947.1949725-1-rppt@kernel.org Signed-off-by: Mike Rapoport (Microsoft) --- include/linux/memblock.h | 5 +++-- mm/memblock.c | 15 +++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index b96746376e1788..fcda8481de9a91 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -40,8 +40,9 @@ extern unsigned long long max_possible_pfn; * via a driver, and never indicated in the firmware-provided memory map as * system RAM. This corresponds to IORESOURCE_SYSRAM_DRIVER_MANAGED in the * kernel resource tree. - * @MEMBLOCK_RSRV_NOINIT: memory region for which struct pages are - * not initialized (only for reserved regions). + * @MEMBLOCK_RSRV_NOINIT: reserved memory region for which struct pages are not + * fully initialized. Users of this flag are responsible to properly initialize + * struct pages of this region * @MEMBLOCK_RSRV_KERN: memory region that is reserved for kernel use, * either explictitly with memblock_reserve_kern() or via memblock * allocation APIs. All memblock allocations set this flag. diff --git a/mm/memblock.c b/mm/memblock.c index 8a0ed3074af4b4..117d963e677c93 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1091,13 +1091,20 @@ int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size) /** * memblock_reserved_mark_noinit - Mark a reserved memory region with flag - * MEMBLOCK_RSRV_NOINIT which results in the struct pages not being initialized - * for this region. + * MEMBLOCK_RSRV_NOINIT + * * @base: the base phys addr of the region * @size: the size of the region * - * struct pages will not be initialized for reserved memory regions marked with - * %MEMBLOCK_RSRV_NOINIT. + * The struct pages for the reserved regions marked %MEMBLOCK_RSRV_NOINIT will + * not be fully initialized to allow the caller optimize their initialization. + * + * When %CONFIG_DEFERRED_STRUCT_PAGE_INIT is enabled, setting this flag + * completely bypasses the initialization of struct pages for such region. + * + * When %CONFIG_DEFERRED_STRUCT_PAGE_INIT is disabled, struct pages in this + * region will be initialized with default values but won't be marked as + * reserved. * * Return: 0 on success, -errno on failure. */ From 1148bb0c5827e4b6fcc50358783608b0f2080302 Mon Sep 17 00:00:00 2001 From: Daniel Dadap Date: Mon, 25 Aug 2025 21:48:38 -0500 Subject: [PATCH 0628/1292] ALSA: hda/hdmi: Restore missing HDMI codec entries Commit ad781b550f9a ("ALSA: hda/hdmi: Rewrite to new probe method") rewrote the HDMI codec ID tables to a new format. In doing so, recently added codec IDs from commit e0a911ac868 ("ALSA: hda: Add missing NVIDIA HDA codec IDs") were dropped from the tables. These tables had recently been split from the unified table that existed in patch_hdmi.c, and did contain the entries in question after the split but before the codec ID entries were rewritten to the new format. Restore the missing codec ID entries to nvhdmi.c and tegrahdmi.c. There do not appear to be any additional missing entries in any of the other codec ID tables when compared to the patch_hdmi.c at the final revision before the split. Fixes: ad781b550f9a ("ALSA: hda/hdmi: Rewrite to new probe method") Signed-off-by: Daniel Dadap Link: https://patch.msgid.link/aK0ghvagXy740rxd@ddadap-lakeline.nvidia.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/hdmi/nvhdmi.c | 17 +++++++++++++++++ sound/hda/codecs/hdmi/tegrahdmi.c | 2 ++ 2 files changed, 19 insertions(+) diff --git a/sound/hda/codecs/hdmi/nvhdmi.c b/sound/hda/codecs/hdmi/nvhdmi.c index b513253b110103..94671ad24b5ebe 100644 --- a/sound/hda/codecs/hdmi/nvhdmi.c +++ b/sound/hda/codecs/hdmi/nvhdmi.c @@ -198,15 +198,32 @@ static const struct hda_device_id snd_hda_id_nvhdmi[] = { HDA_CODEC_ID_MODEL(0x10de0098, "GPU 98 HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de0099, "GPU 99 HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de009a, "GPU 9a HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de009b, "GPU 9b HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de009c, "GPU 9c HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de009d, "GPU 9d HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de009e, "GPU 9e HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de009f, "GPU 9f HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de00a0, "GPU a0 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a1, "GPU a1 HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de00a3, "GPU a3 HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de00a4, "GPU a4 HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de00a5, "GPU a5 HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de00a6, "GPU a6 HDMI/DP", MODEL_GENERIC), HDA_CODEC_ID_MODEL(0x10de00a7, "GPU a7 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a8, "GPU a8 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00a9, "GPU a9 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00aa, "GPU aa HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00ab, "GPU ab HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00ad, "GPU ad HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00ae, "GPU ae HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00af, "GPU af HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00b0, "GPU b0 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00b1, "GPU b1 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00c0, "GPU c0 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00c1, "GPU c1 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00c3, "GPU c3 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00c4, "GPU c4 HDMI/DP", MODEL_GENERIC), + HDA_CODEC_ID_MODEL(0x10de00c5, "GPU c5 HDMI/DP", MODEL_GENERIC), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi); diff --git a/sound/hda/codecs/hdmi/tegrahdmi.c b/sound/hda/codecs/hdmi/tegrahdmi.c index f1f745187f68a1..5f6fe31aa20284 100644 --- a/sound/hda/codecs/hdmi/tegrahdmi.c +++ b/sound/hda/codecs/hdmi/tegrahdmi.c @@ -299,7 +299,9 @@ static const struct hda_device_id snd_hda_id_tegrahdmi[] = { HDA_CODEC_ID_MODEL(0x10de002f, "Tegra194 HDMI/DP2", MODEL_TEGRA), HDA_CODEC_ID_MODEL(0x10de0030, "Tegra194 HDMI/DP3", MODEL_TEGRA), HDA_CODEC_ID_MODEL(0x10de0031, "Tegra234 HDMI/DP", MODEL_TEGRA234), + HDA_CODEC_ID_MODEL(0x10de0033, "SoC 33 HDMI/DP", MODEL_TEGRA234), HDA_CODEC_ID_MODEL(0x10de0034, "Tegra264 HDMI/DP", MODEL_TEGRA234), + HDA_CODEC_ID_MODEL(0x10de0035, "SoC 35 HDMI/DP", MODEL_TEGRA234), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_tegrahdmi); From 16fdb3cc6af8460f23a706512c6f5e7dfdd4f338 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 15 Jul 2025 10:45:39 +0200 Subject: [PATCH 0629/1292] Revert "drm/tegra: Use dma_buf from GEM object instance" This reverts commit 482c7e296edc0f594e8869a789a40be53c49bd6a. The dma_buf field in struct drm_gem_object is not stable over the object instance's lifetime. The field becomes NULL when user space releases the final GEM handle on the buffer object. This resulted in a NULL-pointer deref. Workarounds in commit 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers") and commit f6bfc9afc751 ("drm/framebuffer: Acquire internal references on GEM handles") only solved the problem partially. They especially don't work for buffer objects without a DRM framebuffer associated. Hence, this revert to going back to using .import_attach->dmabuf. Signed-off-by: Thomas Zimmermann Reviewed-by: Simona Vetter Link: https://lore.kernel.org/r/20250715084549.41473-1-tzimmermann@suse.de --- drivers/gpu/drm/tegra/gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 41a285ec889fbb..8ede07fb7a21d6 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -526,7 +526,7 @@ void tegra_bo_free_object(struct drm_gem_object *gem) if (drm_gem_is_imported(gem)) { dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt, DMA_TO_DEVICE); - dma_buf_detach(gem->dma_buf, gem->import_attach); + dma_buf_detach(gem->import_attach->dmabuf, gem->import_attach); } } From 4717432dfd99bbd015b6782adca216c6f9340038 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 9 Aug 2025 21:04:19 +0800 Subject: [PATCH 0630/1292] sched/deadline: Fix dl_server_stopped() Commit cccb45d7c429 ("sched/deadline: Less agressive dl_server handling") introduces dl_server_stopped(). But it is obvious that dl_server_stopped() should return true if dl_se->dl_server_active is 0. Fixes: cccb45d7c429 ("sched/deadline: Less agressive dl_server handling") Signed-off-by: Huacai Chen Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20250809130419.1980742-1-chenhuacai@loongson.cn --- kernel/sched/deadline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index e2d51f4306b31f..bb813afe5b089b 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -1611,7 +1611,7 @@ void dl_server_stop(struct sched_dl_entity *dl_se) static bool dl_server_stopped(struct sched_dl_entity *dl_se) { if (!dl_se->dl_server_active) - return false; + return true; if (dl_se->dl_server_idle) { dl_server_stop(dl_se); From bb4700adc3abec34c0a38b64f66258e4e233fc16 Mon Sep 17 00:00:00 2001 From: Juri Lelli Date: Mon, 21 Jul 2025 15:01:42 +0200 Subject: [PATCH 0631/1292] sched/deadline: Always stop dl-server before changing parameters Commit cccb45d7c4295 ("sched/deadline: Less agressive dl_server handling") reduced dl-server overhead by delaying disabling servers only after there are no fair task around for a whole period, which means that deadline entities are not dequeued right away on a server stop event. However, the delay opens up a window in which a request for changing server parameters can break per-runqueue running_bw tracking, as reported by Yuri. Close the problematic window by unconditionally calling dl_server_stop() before applying the new parameters (ensuring deadline entities go through an actual dequeue). Fixes: cccb45d7c4295 ("sched/deadline: Less agressive dl_server handling") Reported-by: Yuri Andriaccio Signed-off-by: Juri Lelli Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Valentin Schneider Link: https://lore.kernel.org/r/20250721-upstream-fix-dlserver-lessaggressive-b4-v1-1-4ebc10c87e40@redhat.com --- kernel/sched/debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 3f06ab84d53f0c..02e16b70a7901e 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -376,10 +376,8 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubu return -EINVAL; } - if (rq->cfs.h_nr_queued) { - update_rq_clock(rq); - dl_server_stop(&rq->fair_server); - } + update_rq_clock(rq); + dl_server_stop(&rq->fair_server); retval = dl_server_apply_params(&rq->fair_server, runtime, period, 0); if (retval) From 421fc59cf58c64f898cafbbbbda0bc705837e7df Mon Sep 17 00:00:00 2001 From: kuyo chang Date: Sun, 15 Jun 2025 21:10:56 +0800 Subject: [PATCH 0632/1292] sched/deadline: Fix RT task potential starvation when expiry time passed [Symptom] The fair server mechanism, which is intended to prevent fair starvation when higher-priority tasks monopolize the CPU. Specifically, RT tasks on the runqueue may not be scheduled as expected. [Analysis] The log "sched: DL replenish lagged too much" triggered. By memory dump of dl_server: curr = 0xFFFFFF80D6A0AC00 ( dl_server = 0xFFFFFF83CD5B1470( dl_runtime = 0x02FAF080, dl_deadline = 0x3B9ACA00, dl_period = 0x3B9ACA00, dl_bw = 0xCCCC, dl_density = 0xCCCC, runtime = 0x02FAF080, deadline = 0x0000082031EB0E80, flags = 0x0, dl_throttled = 0x0, dl_yielded = 0x0, dl_non_contending = 0x0, dl_overrun = 0x0, dl_server = 0x1, dl_server_active = 0x1, dl_defer = 0x1, dl_defer_armed = 0x0, dl_defer_running = 0x1, dl_timer = ( node = ( expires = 0x000008199756E700), _softexpires = 0x000008199756E700, function = 0xFFFFFFDB9AF44D30 = dl_task_timer, base = 0xFFFFFF83CD5A12C0, state = 0x0, is_rel = 0x0, is_soft = 0x0, clock_update_flags = 0x4, clock = 0x000008204A496900, - The timer expiration time (rq->curr->dl_server->dl_timer->expires) is already in the past, indicating the timer has expired. - The timer state (rq->curr->dl_server->dl_timer->state) is 0. [Suspected Root Cause] The relevant code flow in the throttle path of update_curr_dl_se() as follows: dequeue_dl_entity(dl_se, 0); // the DL entity is dequeued if (unlikely(is_dl_boosted(dl_se) || !start_dl_timer(dl_se))) { if (dl_server(dl_se)) // timer registration fails enqueue_dl_entity(dl_se, ENQUEUE_REPLENISH);//enqueue immediately ... } The failure of `start_dl_timer` is caused by attempting to register a timer with an expiration time that is already in the past. When this situation persists, the code repeatedly re-enqueues the DL entity without properly replenishing or restarting the timer, resulting in RT task may not be scheduled as expected. [Proposed Solution]: Instead of immediately re-enqueuing the DL entity on timer registration failure, this change ensures the DL entity is properly replenished and the timer is restarted, preventing RT potential starvation. Fixes: 63ba8422f876 ("sched/deadline: Introduce deadline servers") Signed-off-by: kuyo chang Signed-off-by: Peter Zijlstra (Intel) Closes: https://lore.kernel.org/CAMuHMdXn4z1pioTtBGMfQM0jsLviqS2jwysaWXpoLxWYoGa82w@mail.gmail.com Tested-by: Geert Uytterhoeven Tested-by: Jiri Slaby Tested-by: Diederik de Haas Link: https://lkml.kernel.org/r/20250615131129.954975-1-kuyo.chang@mediatek.com --- kernel/sched/deadline.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index bb813afe5b089b..88c3bd64a8a056 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -1496,10 +1496,12 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64 } if (unlikely(is_dl_boosted(dl_se) || !start_dl_timer(dl_se))) { - if (dl_server(dl_se)) - enqueue_dl_entity(dl_se, ENQUEUE_REPLENISH); - else + if (dl_server(dl_se)) { + replenish_dl_new_period(dl_se, rq); + start_dl_timer(dl_se); + } else { enqueue_task_dl(rq, dl_task_of(dl_se), ENQUEUE_REPLENISH); + } } if (!is_leftmost(dl_se, &rq->dl)) From 52d15521eb75f9b521744db675bee61025d2fa52 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Fri, 27 Jun 2025 11:54:20 +0800 Subject: [PATCH 0633/1292] sched/deadline: Don't count nr_running for dl_server proxy tasks On CPU offline the kernel stalled with below call trace: INFO: task kworker/0:1:11 blocked for more than 120 seconds. cpuhp hold the cpu hotplug lock endless and stalled vmstat_shepherd. This is because we count nr_running twice on cpuhp enqueuing and failed the wait condition of cpuhp: enqueue_task_fair() // pick cpuhp from idle, rq->nr_running = 0 dl_server_start() [...] add_nr_running() // rq->nr_running = 1 add_nr_running() // rq->nr_running = 2 [switch to cpuhp, waiting on balance_hotplug_wait()] rcuwait_wait_event(rq->nr_running == 1 && ...) // failed, rq->nr_running=2 schedule() // wait again It doesn't make sense to count the dl_server towards runnable tasks, since it runs other tasks. Fixes: 63ba8422f876 ("sched/deadline: Introduce deadline servers") Signed-off-by: Yicong Yang Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20250627035420.37712-1-yangyicong@huawei.com --- kernel/sched/deadline.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 88c3bd64a8a056..f25301267e4714 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -1851,7 +1851,9 @@ void inc_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) u64 deadline = dl_se->deadline; dl_rq->dl_nr_running++; - add_nr_running(rq_of_dl_rq(dl_rq), 1); + + if (!dl_server(dl_se)) + add_nr_running(rq_of_dl_rq(dl_rq), 1); inc_dl_deadline(dl_rq, deadline); } @@ -1861,7 +1863,9 @@ void dec_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) { WARN_ON(!dl_rq->dl_nr_running); dl_rq->dl_nr_running--; - sub_nr_running(rq_of_dl_rq(dl_rq), 1); + + if (!dl_server(dl_se)) + sub_nr_running(rq_of_dl_rq(dl_rq), 1); dec_dl_deadline(dl_rq, dl_se->deadline); } From cdbd2acef252a17693558e3f7b51a29beb99edef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Mon, 25 Aug 2025 09:25:57 +0200 Subject: [PATCH 0634/1292] ALSA: usb-audio: us144mkii: Fixes for handshake, MIDI out and cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a handshake value of 0x32, which is required when the device was previously used by another OS with the official drivers. Correct the last byte of the MIDI output protocol to 0xe0. Also, remove the unused DRIVER_VERSION macro. Signed-off-by: Å erif Rami Link: https://patch.msgid.link/20250825072557.7670-1-ramiserifpersia@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us144mkii.c | 2 +- sound/usb/usx2y/us144mkii.h | 1 - sound/usb/usx2y/us144mkii_midi.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index 3127a320637011..f6572a576c150e 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -454,7 +454,7 @@ static int tascam_probe(struct usb_interface *intf, } if (handshake_buf[0] != 0x12 && handshake_buf[0] != 0x16 && - handshake_buf[0] != 0x30) { + handshake_buf[0] != 0x30 && handshake_buf[0] != 0x32) { dev_err(&dev->dev, "Unexpected handshake value: 0x%x\n", handshake_buf[0]); return -ENODEV; diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h index ecc4c2fed9e622..95c4341f038ad4 100644 --- a/sound/usb/usx2y/us144mkii.h +++ b/sound/usb/usx2y/us144mkii.h @@ -15,7 +15,6 @@ #include #define DRIVER_NAME "us144mkii" -#define DRIVER_VERSION "1.7.6" /* --- USB Device Identification --- */ #define USB_VID_TASCAM 0x0644 diff --git a/sound/usb/usx2y/us144mkii_midi.c b/sound/usb/usx2y/us144mkii_midi.c index 08b04aa392781c..ed2afec2a89aec 100644 --- a/sound/usb/usx2y/us144mkii_midi.c +++ b/sound/usb/usx2y/us144mkii_midi.c @@ -257,7 +257,7 @@ static void tascam_midi_out_work_handler(struct work_struct *work) if (bytes_to_send < 9) memset(buf + bytes_to_send, 0xfd, 9 - bytes_to_send); - buf[8] = 0x00; + buf[8] = 0xe0; set_bit(urb_index, &tascam->midi_out_urbs_in_flight); urb->transfer_buffer_length = 9; From ae668cd567a6a7622bc813ee0bb61c42bed61ba7 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 22 Aug 2025 12:55:56 -0500 Subject: [PATCH 0635/1292] xfs: do not propagate ENODATA disk errors into xattr code ENODATA (aka ENOATTR) has a very specific meaning in the xfs xattr code; namely, that the requested attribute name could not be found. However, a medium error from disk may also return ENODATA. At best, this medium error may escape to userspace as "attribute not found" when in fact it's an IO (disk) error. At worst, we may oops in xfs_attr_leaf_get() when we do: error = xfs_attr_leaf_hasname(args, &bp); if (error == -ENOATTR) { xfs_trans_brelse(args->trans, bp); return error; } because an ENODATA/ENOATTR error from disk leaves us with a null bp, and the xfs_trans_brelse will then null-deref it. As discussed on the list, we really need to modify the lower level IO functions to trap all disk errors and ensure that we don't let unique errors like this leak up into higher xfs functions - many like this should be remapped to EIO. However, this patch directly addresses a reported bug in the xattr code, and should be safe to backport to stable kernels. A larger-scope patch to handle more unique errors at lower levels can follow later. (Note, prior to 07120f1abdff we did not oops, but we did return the wrong error code to userspace.) Signed-off-by: Eric Sandeen Fixes: 07120f1abdff ("xfs: Add xfs_has_attr and subroutines") Cc: stable@vger.kernel.org # v5.9+ Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino --- fs/xfs/libxfs/xfs_attr_remote.c | 7 +++++++ fs/xfs/libxfs/xfs_da_btree.c | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c index 4c44ce1c8a644b..bff3dc226f8128 100644 --- a/fs/xfs/libxfs/xfs_attr_remote.c +++ b/fs/xfs/libxfs/xfs_attr_remote.c @@ -435,6 +435,13 @@ xfs_attr_rmtval_get( 0, &bp, &xfs_attr3_rmt_buf_ops); if (xfs_metadata_is_sick(error)) xfs_dirattr_mark_sick(args->dp, XFS_ATTR_FORK); + /* + * ENODATA from disk implies a disk medium failure; + * ENODATA for xattrs means attribute not found, so + * disambiguate that here. + */ + if (error == -ENODATA) + error = -EIO; if (error) return error; diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index 17d9e6154f1978..723a0643b8386c 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -2833,6 +2833,12 @@ xfs_da_read_buf( &bp, ops); if (xfs_metadata_is_sick(error)) xfs_dirattr_mark_sick(dp, whichfork); + /* + * ENODATA from disk implies a disk medium failure; ENODATA for + * xattrs means attribute not found, so disambiguate that here. + */ + if (error == -ENODATA && whichfork == XFS_ATTR_FORK) + error = -EIO; if (error) goto out_free; From 810e154d90f44127239957b06ee51a55553a5815 Mon Sep 17 00:00:00 2001 From: Junjie Cao Date: Mon, 25 Aug 2025 17:08:50 +0800 Subject: [PATCH 0636/1292] gpio: timberdale: fix off-by-one in IRQ type boundary check timbgpio_irq_type() currently accepts offset == ngpio, violating gpiolib's [0..ngpio-1] contract. This can lead to undefined behavior when computing '1 << offset', and it is also inconsistent with users that iterate with for_each_set_bit(..., ngpio). Tighten the upper bound to reject offset == ngpio. No functional change for in-range offsets. Signed-off-by: Junjie Cao Link: https://lore.kernel.org/r/20250825090850.127163-1-junjie.cao@intel.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-timberdale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 679e27f00ff607..f488939dd00a8a 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -137,7 +137,7 @@ static int timbgpio_irq_type(struct irq_data *d, unsigned trigger) u32 ver; int ret = 0; - if (offset < 0 || offset > tgpio->gpio.ngpio) + if (offset < 0 || offset >= tgpio->gpio.ngpio) return -EINVAL; ver = ioread32(tgpio->membase + TGPIO_VER); From 6fe31c8b53003134e5573cfb89aea85f96a43afd Mon Sep 17 00:00:00 2001 From: Adrian Ng Ho Yin Date: Mon, 25 Aug 2025 15:16:37 +0800 Subject: [PATCH 0637/1292] MAINTAINERS: Change Altera-PIO driver maintainer Update Altera-PIO Driver maintainer from to as Mun Yew is no longer with Altera. Signed-off-by: Adrian Ng Ho Yin Acked-by: Mun Yew Tham Link: https://lore.kernel.org/r/20250825071637.40441-1-adrianhoyin.ng@altera.com Signed-off-by: Bartosz Golaszewski --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fed6cd812d796a..5b3f80f42f3c63 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -931,7 +931,7 @@ F: Documentation/devicetree/bindings/dma/altr,msgdma.yaml F: drivers/dma/altera-msgdma.c ALTERA PIO DRIVER -M: Mun Yew Tham +M: Adrian Ng L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-altera.c From 832e5777143e799a97e8f9b96f002a90f06ba548 Mon Sep 17 00:00:00 2001 From: Martin Hilgendorf Date: Sat, 2 Aug 2025 13:45:55 +0000 Subject: [PATCH 0638/1292] HID: elecom: add support for ELECOM M-DT2DRBK The DT2DRBK trackball has 8 buttons, but the report descriptor only specifies 5. This patch adds the device ID and performs a similar fixup as for other ELECOM devices to enable the remaining 3 buttons. Signed-off-by: Martin Hilgendorf Signed-off-by: Jiri Kosina --- drivers/hid/hid-elecom.c | 2 ++ drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 0ad7d25d98647f..69771fd3500605 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -101,6 +101,7 @@ static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, */ mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); break; + case USB_DEVICE_ID_ELECOM_M_DT2DRBK: case USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C: /* * Report descriptor format: @@ -123,6 +124,7 @@ static const struct hid_device_id elecom_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT2DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_010C) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_019B) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 37dc423803737c..5d18b6ac81e74d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -451,6 +451,7 @@ #define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd #define USB_DEVICE_ID_ELECOM_M_DT1URBK 0x00fe #define USB_DEVICE_ID_ELECOM_M_DT1DRBK 0x00ff +#define USB_DEVICE_ID_ELECOM_M_DT2DRBK 0x018d #define USB_DEVICE_ID_ELECOM_M_HT1URBK_010C 0x010c #define USB_DEVICE_ID_ELECOM_M_HT1URBK_019B 0x019b #define USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D 0x010d diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index ff11f1ad344daf..5c15af9afa98af 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -411,6 +411,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT2DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_010C) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_019B) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, From 1f3214aae9f49faf495f3836216afbc6c5400b2e Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Sun, 3 Aug 2025 18:02:53 +0200 Subject: [PATCH 0639/1292] HID: quirks: add support for Legion Go dual dinput modes The Legion Go features detachable controllers which support a dual dinput mode. In this mode, the controllers appear under a single HID device with two applications. Currently, both controllers appear under the same event device, causing their controls to be mixed up. This patch separates the two so that they can be used independently. In addition, the latest firmware update for the Legion Go swaps the IDs to the ones used by the Legion Go 2, so add those IDs as well. [jkosina@suse.com: improved shortlog] Signed-off-by: Antheas Kapenekakis Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 2 ++ drivers/hid/hid-quirks.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5d18b6ac81e74d..149798754570d3 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -835,6 +835,8 @@ #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093 +#define USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT 0x6184 +#define USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT 0x61ed #define USB_VENDOR_ID_LETSKETCH 0x6161 #define USB_DEVICE_ID_WP9620N 0x4d15 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 5c15af9afa98af..f619ed10535d74 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -124,6 +124,8 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_T609A), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, From 2d52c9e43a48387a323ab6a4fed755d55040e625 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 29 Jul 2025 17:29:21 +0200 Subject: [PATCH 0640/1292] wifi: rt2800: select CONFIG_RT2X00_LIB as needed The rt2800 specific code requires the more general library code: ERROR: modpost: "rt2x00queue_get_entry" [drivers/net/wireless/ralink/rt2x00/rt2x00mmio.ko] undefined! ERROR: modpost: "rt2x00lib_dmastart" [drivers/net/wireless/ralink/rt2x00/rt2x00mmio.ko] undefined! ERROR: modpost: "rt2x00lib_dmadone" [drivers/net/wireless/ralink/rt2x00/rt2x00mmio.ko] undefined! ERROR: modpost: "rt2x00lib_rxdone" [drivers/net/wireless/ralink/rt2x00/rt2x00mmio.ko] undefined! ERROR: modpost: "rt2x00lib_txdone_nomatch" [drivers/net/wireless/ralink/rt2x00/rt2800lib.ko] undefined! ERROR: modpost: "rt2x00lib_txdone" [drivers/net/wireless/ralink/rt2x00/rt2800lib.ko] undefined! ERROR: modpost: "rt2x00queue_get_entry" [drivers/net/wireless/ralink/rt2x00/rt2800lib.ko] undefined! ERROR: modpost: "rt2x00lib_get_bssidx" [drivers/net/wireless/ralink/rt2x00/rt2800lib.ko] undefined! ERROR: modpost: "rt2x00mac_conf_tx" [drivers/net/wireless/ralink/rt2x00/rt2800lib.ko] undefined! ERROR: modpost: "rt2x00lib_txdone_noinfo" [drivers/net/wireless/ralink/rt2x00/rt2800lib.ko] undefined! Select the symbol to avoid this build failure. Fixes: 7f6109086c9e ("wifi: rt2800: move 2x00soc to 2800soc") Signed-off-by: Arnd Bergmann Acked-by: Stanislaw Gruszka Reviewed-by: Sergio Paracuellos Link: https://patch.msgid.link/20250729152924.2462423-1-arnd@kernel.org Signed-off-by: Johannes Berg --- drivers/net/wireless/ralink/rt2x00/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig index 4d98b7723c5675..d66fc839c3ce31 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -225,6 +225,7 @@ config RT2800_LIB_MMIO config RT2X00_LIB_MMIO tristate + select RT2X00_LIB config RT2X00_LIB_PCI tristate From f64768bec0d57988782d26d1ea7ae21f959309dd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 31 Jul 2025 09:58:33 +0200 Subject: [PATCH 0641/1292] wifi: rt2x00: fix CRC_CCITT dependency Compile-testing this driver on Arm platforms shows a link failure when the CRC functions are not part of the kernel: x86_64-linux-ld: drivers/net/wireless/ralink/rt2x00/rt2800lib.o: in function `rt2800_check_firmware': rt2800lib.c:(.text+0x20e5): undefined reference to `crc_ccitt' Move the select statement to the correct Kconfig symbol to match the call site. Fixes: 311b05e235cf ("wifi: rt2x00: add COMPILE_TEST") Signed-off-by: Arnd Bergmann Acked-by: Stanislaw Gruszka Reviewed-by: Sergio Paracuellos Link: https://patch.msgid.link/20250731075837.1969136-1-arnd@kernel.org Signed-off-by: Johannes Berg --- drivers/net/wireless/ralink/rt2x00/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig index d66fc839c3ce31..17f063fc0b576b 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -66,7 +66,6 @@ config RT2800PCI select RT2X00_LIB_PCI select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO - select CRC_CCITT select EEPROM_93CX6 help This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. @@ -142,7 +141,6 @@ config RT2800USB select RT2X00_LIB_USB select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO - select CRC_CCITT help This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. Supported chips: RT2770, RT2870 & RT3070, RT3071 & RT3072 @@ -217,6 +215,7 @@ config RT2800SOC config RT2800_LIB tristate + select CRC_CCITT config RT2800_LIB_MMIO tristate From 26e84445f02ce6b2fe5f3e0e28ff7add77f35e08 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 13 Aug 2025 16:52:36 +0300 Subject: [PATCH 0642/1292] wifi: cfg80211: fix use-after-free in cmp_bss() Following bss_free() quirk introduced in commit 776b3580178f ("cfg80211: track hidden SSID networks properly"), adjust cfg80211_update_known_bss() to free the last beacon frame elements only if they're not shared via the corresponding 'hidden_beacon_bss' pointer. Reported-by: syzbot+30754ca335e6fb7e3092@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=30754ca335e6fb7e3092 Fixes: 3ab8227d3e7d ("cfg80211: refactor cfg80211_bss_update") Signed-off-by: Dmitry Antipov Link: https://patch.msgid.link/20250813135236.799384-1-dmantipov@yandex.ru Signed-off-by: Johannes Berg --- net/wireless/scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index a8339ed52404c6..6c7b7c3828a415 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1916,7 +1916,8 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, */ f = rcu_access_pointer(new->pub.beacon_ies); - kfree_rcu((struct cfg80211_bss_ies *)f, rcu_head); + if (!new->pub.hidden_beacon_bss) + kfree_rcu((struct cfg80211_bss_ies *)f, rcu_head); return false; } From 9cb83d4be0b9b697eae93d321e0da999f9cdfcfc Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Fri, 22 Aug 2025 13:08:39 +0800 Subject: [PATCH 0643/1292] wifi: brcmfmac: fix use-after-free when rescheduling brcmf_btcoex_info work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The brcmf_btcoex_detach() only shuts down the btcoex timer, if the flag timer_on is false. However, the brcmf_btcoex_timerfunc(), which runs as timer handler, sets timer_on to false. This creates critical race conditions: 1.If brcmf_btcoex_detach() is called while brcmf_btcoex_timerfunc() is executing, it may observe timer_on as false and skip the call to timer_shutdown_sync(). 2.The brcmf_btcoex_timerfunc() may then reschedule the brcmf_btcoex_info worker after the cancel_work_sync() has been executed, resulting in use-after-free bugs. The use-after-free bugs occur in two distinct scenarios, depending on the timing of when the brcmf_btcoex_info struct is freed relative to the execution of its worker thread. Scenario 1: Freed before the worker is scheduled The brcmf_btcoex_info is deallocated before the worker is scheduled. A race condition can occur when schedule_work(&bt_local->work) is called after the target memory has been freed. The sequence of events is detailed below: CPU0 | CPU1 brcmf_btcoex_detach | brcmf_btcoex_timerfunc | bt_local->timer_on = false; if (cfg->btcoex->timer_on) | ... | cancel_work_sync(); | ... | kfree(cfg->btcoex); // FREE | | schedule_work(&bt_local->work); // USE Scenario 2: Freed after the worker is scheduled The brcmf_btcoex_info is freed after the worker has been scheduled but before or during its execution. In this case, statements within the brcmf_btcoex_handler() — such as the container_of macro and subsequent dereferences of the brcmf_btcoex_info object will cause a use-after-free access. The following timeline illustrates this scenario: CPU0 | CPU1 brcmf_btcoex_detach | brcmf_btcoex_timerfunc | bt_local->timer_on = false; if (cfg->btcoex->timer_on) | ... | cancel_work_sync(); | ... | schedule_work(); // Reschedule | kfree(cfg->btcoex); // FREE | brcmf_btcoex_handler() // Worker /* | btci = container_of(....); // USE The kfree() above could | ... also occur at any point | btci-> // USE during the worker's execution| */ | To resolve the race conditions, drop the conditional check and call timer_shutdown_sync() directly. It can deactivate the timer reliably, regardless of its current state. Once stopped, the timer_on state is then set to false. Fixes: 61730d4dfffc ("brcmfmac: support critical protocol API for DHCP") Acked-by: Arend van Spriel Signed-off-by: Duoming Zhou Link: https://patch.msgid.link/20250822050839.4413-1-duoming@zju.edu.cn Signed-off-by: Johannes Berg --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c index 69ef8cf203d24f..67c0c5a92f9985 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c @@ -393,10 +393,8 @@ void brcmf_btcoex_detach(struct brcmf_cfg80211_info *cfg) if (!cfg->btcoex) return; - if (cfg->btcoex->timer_on) { - cfg->btcoex->timer_on = false; - timer_shutdown_sync(&cfg->btcoex->timer); - } + timer_shutdown_sync(&cfg->btcoex->timer); + cfg->btcoex->timer_on = false; cancel_work_sync(&cfg->btcoex->work); From a33b375ab5b3a9897a0ab76be8258d9f6b748628 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Mon, 25 Aug 2025 10:29:11 +0800 Subject: [PATCH 0644/1292] wifi: mac80211: fix incorrect type for ret The variable ret is declared as a u32 type, but it is assigned a value of -EOPNOTSUPP. Since unsigned types cannot correctly represent negative values, the type of ret should be changed to int. Signed-off-by: Liao Yuanhong Link: https://patch.msgid.link/20250825022911.139377-1-liaoyuanhong@vivo.com Signed-off-by: Johannes Berg --- net/mac80211/driver-ops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 181bcb34b795fc..55105d238d6bc5 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1416,7 +1416,7 @@ drv_get_ftm_responder_stats(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct cfg80211_ftm_responder_stats *ftm_stats) { - u32 ret = -EOPNOTSUPP; + int ret = -EOPNOTSUPP; might_sleep(); lockdep_assert_wiphy(local->hw.wiphy); From 7e2f3213e85eba00acb4cfe6d71647892d63c3a1 Mon Sep 17 00:00:00 2001 From: Lachlan Hodges Date: Tue, 26 Aug 2025 18:54:37 +1000 Subject: [PATCH 0645/1292] wifi: mac80211: increase scan_ies_len for S1G Currently the S1G capability element is not taken into account for the scan_ies_len, which leads to a buffer length validation failure in ieee80211_prep_hw_scan() and subsequent WARN in __ieee80211_start_scan(). This prevents hw scanning from functioning. To fix ensure we accommodate for the S1G capability length. Signed-off-by: Lachlan Hodges Link: https://patch.msgid.link/20250826085437.3493-1-lachlan.hodges@morsemicro.com Signed-off-by: Johannes Berg --- net/mac80211/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9c8f18b258a68c..3ae6104e5cb201 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1111,7 +1111,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) int result, i; enum nl80211_band band; int channels, max_bitrates; - bool supp_ht, supp_vht, supp_he, supp_eht; + bool supp_ht, supp_vht, supp_he, supp_eht, supp_s1g; struct cfg80211_chan_def dflt_chandef = {}; if (ieee80211_hw_check(hw, QUEUE_CONTROL) && @@ -1227,6 +1227,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) supp_vht = false; supp_he = false; supp_eht = false; + supp_s1g = false; for (band = 0; band < NUM_NL80211_BANDS; band++) { const struct ieee80211_sband_iftype_data *iftd; struct ieee80211_supported_band *sband; @@ -1274,6 +1275,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; supp_vht = supp_vht || sband->vht_cap.vht_supported; + supp_s1g = supp_s1g || sband->s1g_cap.s1g; for_each_sband_iftype_data(sband, i, iftd) { u8 he_40_mhz_cap; @@ -1406,6 +1408,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->scan_ies_len += 2 + sizeof(struct ieee80211_vht_cap); + if (supp_s1g) + local->scan_ies_len += 2 + sizeof(struct ieee80211_s1g_cap); + /* * HE cap element is variable in size - set len to allow max size */ if (supp_he) { From c5e81e672699e0c5557b2b755cc8f7a69aa92bff Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 25 Aug 2025 18:07:10 +0200 Subject: [PATCH 0646/1292] efi: stmm: Fix incorrect buffer allocation method The communication buffer allocated by setup_mm_hdr() is later on passed to tee_shm_register_kernel_buf(). The latter expects those buffers to be contiguous pages, but setup_mm_hdr() just uses kmalloc(). That can cause various corruptions or BUGs, specifically since commit 9aec2fb0fd5e ("slab: allocate frozen pages"), though it was broken before as well. Fix this by using alloc_pages_exact() instead of kmalloc(). Fixes: c44b6be62e8d ("efi: Add tee-based EFI variable driver") Signed-off-by: Jan Kiszka Acked-by: Ilias Apalodimas Acked-by: Sumit Garg Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/stmm/tee_stmm_efi.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c index f741ca279052bb..e15d11ed165eef 100644 --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c @@ -143,6 +143,10 @@ static efi_status_t mm_communicate(u8 *comm_buf, size_t payload_size) return var_hdr->ret_status; } +#define COMM_BUF_SIZE(__payload_size) (MM_COMMUNICATE_HEADER_SIZE + \ + MM_VARIABLE_COMMUNICATE_SIZE + \ + (__payload_size)) + /** * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the * header data. @@ -173,9 +177,8 @@ static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func, return NULL; } - comm_buf = kzalloc(MM_COMMUNICATE_HEADER_SIZE + - MM_VARIABLE_COMMUNICATE_SIZE + payload_size, - GFP_KERNEL); + comm_buf = alloc_pages_exact(COMM_BUF_SIZE(payload_size), + GFP_KERNEL | __GFP_ZERO); if (!comm_buf) { *ret = EFI_OUT_OF_RESOURCES; return NULL; @@ -239,7 +242,7 @@ static efi_status_t get_max_payload(size_t *size) */ *size -= 2; out: - kfree(comm_buf); + free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size)); return ret; } @@ -282,7 +285,7 @@ static efi_status_t get_property_int(u16 *name, size_t name_size, memcpy(var_property, &smm_property->property, sizeof(*var_property)); out: - kfree(comm_buf); + free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size)); return ret; } @@ -347,7 +350,7 @@ static efi_status_t tee_get_variable(u16 *name, efi_guid_t *vendor, memcpy(data, (u8 *)var_acc->name + var_acc->name_size, var_acc->data_size); out: - kfree(comm_buf); + free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size)); return ret; } @@ -404,7 +407,7 @@ static efi_status_t tee_get_next_variable(unsigned long *name_size, memcpy(name, var_getnext->name, var_getnext->name_size); out: - kfree(comm_buf); + free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size)); return ret; } @@ -467,7 +470,7 @@ static efi_status_t tee_set_variable(efi_char16_t *name, efi_guid_t *vendor, ret = mm_communicate(comm_buf, payload_size); dev_dbg(pvt_data.dev, "Set Variable %s %d %lx\n", __FILE__, __LINE__, ret); out: - kfree(comm_buf); + free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size)); return ret; } @@ -507,7 +510,7 @@ static efi_status_t tee_query_variable_info(u32 attributes, *max_variable_size = mm_query_info->max_variable_size; out: - kfree(comm_buf); + free_pages_exact(comm_buf, COMM_BUF_SIZE(payload_size)); return ret; } From 80c6c1048625712200ab9cdc665d792b85594e2c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 25 Aug 2025 18:07:11 +0200 Subject: [PATCH 0647/1292] efi: stmm: Do not return EFI_OUT_OF_RESOURCES on internal errors When we are low on memory or when the internal API is violated, we cannot return EFI_OUT_OF_RESOURCES. According to the UEFI standard, that error code is either related to persistent storage used for the variable or even not foreseen as possible error (GetVariable e.g.). Use the not fully accurate but compliant error code EFI_DEVICE_ERROR in those cases. Signed-off-by: Jan Kiszka Reviewed-by: Ilias Apalodimas Acked-by: Sumit Garg Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/stmm/tee_stmm_efi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c index e15d11ed165eef..8501056ade8a3e 100644 --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c @@ -218,7 +218,7 @@ static efi_status_t get_max_payload(size_t *size) SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, &ret); if (!var_payload) - return EFI_OUT_OF_RESOURCES; + return EFI_DEVICE_ERROR; ret = mm_communicate(comm_buf, payload_size); if (ret != EFI_SUCCESS) @@ -264,7 +264,7 @@ static efi_status_t get_property_int(u16 *name, size_t name_size, &comm_buf, payload_size, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, &ret); if (!smm_property) - return EFI_OUT_OF_RESOURCES; + return EFI_DEVICE_ERROR; memcpy(&smm_property->guid, vendor, sizeof(smm_property->guid)); smm_property->name_size = name_size; @@ -320,7 +320,7 @@ static efi_status_t tee_get_variable(u16 *name, efi_guid_t *vendor, var_acc = setup_mm_hdr(&comm_buf, payload_size, SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret); if (!var_acc) - return EFI_OUT_OF_RESOURCES; + return EFI_DEVICE_ERROR; /* Fill in contents */ memcpy(&var_acc->guid, vendor, sizeof(var_acc->guid)); @@ -386,7 +386,7 @@ static efi_status_t tee_get_next_variable(unsigned long *name_size, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, &ret); if (!var_getnext) - return EFI_OUT_OF_RESOURCES; + return EFI_DEVICE_ERROR; /* Fill in contents */ memcpy(&var_getnext->guid, guid, sizeof(var_getnext->guid)); @@ -442,7 +442,7 @@ static efi_status_t tee_set_variable(efi_char16_t *name, efi_guid_t *vendor, var_acc = setup_mm_hdr(&comm_buf, payload_size, SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); if (!var_acc) - return EFI_OUT_OF_RESOURCES; + return EFI_DEVICE_ERROR; /* * The API has the ability to override RO flags. If no RO check was @@ -498,7 +498,7 @@ static efi_status_t tee_query_variable_info(u32 attributes, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, &ret); if (!mm_query_info) - return EFI_OUT_OF_RESOURCES; + return EFI_DEVICE_ERROR; mm_query_info->attr = attributes; ret = mm_communicate(comm_buf, payload_size); From 01a3044af5d910e1f8b0bee53b2e0eccee8f9a5c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 25 Aug 2025 18:07:12 +0200 Subject: [PATCH 0648/1292] efi: stmm: Drop unused EFI error from setup_mm_hdr arguments No caller ever evaluates what we return in 'ret'. They only use the return code of the function. Signed-off-by: Jan Kiszka Reviewed-by: Ilias Apalodimas Acked-by: Sumit Garg Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/stmm/tee_stmm_efi.c | 25 ++++++++---------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c index 8501056ade8a3e..c2bc8467b09933 100644 --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c @@ -154,11 +154,9 @@ static efi_status_t mm_communicate(u8 *comm_buf, size_t payload_size) * @dptr: pointer address to store allocated buffer * @payload_size: payload size * @func: standAloneMM function number - * @ret: EFI return code * Return: pointer to corresponding StandAloneMM function buffer or NULL */ -static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func, - efi_status_t *ret) +static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func) { const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID; struct efi_mm_communicate_header *mm_hdr; @@ -173,16 +171,13 @@ static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func, if (max_buffer_size && max_buffer_size < (MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE + payload_size)) { - *ret = EFI_INVALID_PARAMETER; return NULL; } comm_buf = alloc_pages_exact(COMM_BUF_SIZE(payload_size), GFP_KERNEL | __GFP_ZERO); - if (!comm_buf) { - *ret = EFI_OUT_OF_RESOURCES; + if (!comm_buf) return NULL; - } mm_hdr = (struct efi_mm_communicate_header *)comm_buf; memcpy(&mm_hdr->header_guid, &mm_var_guid, sizeof(mm_hdr->header_guid)); @@ -192,7 +187,6 @@ static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func, var_hdr->function = func; if (dptr) *dptr = comm_buf; - *ret = EFI_SUCCESS; return var_hdr->data; } @@ -215,8 +209,7 @@ static efi_status_t get_max_payload(size_t *size) payload_size = sizeof(*var_payload); var_payload = setup_mm_hdr(&comm_buf, payload_size, - SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, - &ret); + SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE); if (!var_payload) return EFI_DEVICE_ERROR; @@ -262,7 +255,7 @@ static efi_status_t get_property_int(u16 *name, size_t name_size, smm_property = setup_mm_hdr( &comm_buf, payload_size, - SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, &ret); + SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET); if (!smm_property) return EFI_DEVICE_ERROR; @@ -318,7 +311,7 @@ static efi_status_t tee_get_variable(u16 *name, efi_guid_t *vendor, payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize; var_acc = setup_mm_hdr(&comm_buf, payload_size, - SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret); + SMM_VARIABLE_FUNCTION_GET_VARIABLE); if (!var_acc) return EFI_DEVICE_ERROR; @@ -383,8 +376,7 @@ static efi_status_t tee_get_next_variable(unsigned long *name_size, payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size; var_getnext = setup_mm_hdr(&comm_buf, payload_size, - SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, - &ret); + SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME); if (!var_getnext) return EFI_DEVICE_ERROR; @@ -440,7 +432,7 @@ static efi_status_t tee_set_variable(efi_char16_t *name, efi_guid_t *vendor, * the properties, if the allocation fails */ var_acc = setup_mm_hdr(&comm_buf, payload_size, - SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); + SMM_VARIABLE_FUNCTION_SET_VARIABLE); if (!var_acc) return EFI_DEVICE_ERROR; @@ -495,8 +487,7 @@ static efi_status_t tee_query_variable_info(u32 attributes, payload_size = sizeof(*mm_query_info); mm_query_info = setup_mm_hdr(&comm_buf, payload_size, - SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, - &ret); + SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO); if (!mm_query_info) return EFI_DEVICE_ERROR; From 134ed1093907a79e5d98087513f13fd7652c4df9 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 25 Aug 2025 18:07:13 +0200 Subject: [PATCH 0649/1292] efi: stmm: Drop unneeded null pointer check The API documenation of setup_mm_hdr does not mention that dptr can be NULL, this is a local function, and no caller passes NULL. So drop the unneeded check. Signed-off-by: Jan Kiszka Reviewed-by: Ilias Apalodimas Acked-by: Sumit Garg Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/stmm/tee_stmm_efi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c index c2bc8467b09933..65c0fe1ba275a3 100644 --- a/drivers/firmware/efi/stmm/tee_stmm_efi.c +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c @@ -185,8 +185,7 @@ static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func) var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; var_hdr->function = func; - if (dptr) - *dptr = comm_buf; + *dptr = comm_buf; return var_hdr->data; } From e246518aa24f1460902725e97d0abf574aec6ade Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 26 Aug 2025 13:43:47 +0200 Subject: [PATCH 0650/1292] PM: sleep: annotate RCU list iterations These iterations require the read lock, otherwise RCU lockdep will splat: ============================= WARNING: suspicious RCU usage 6.17.0-rc3-00014-g31419c045d64 #6 Tainted: G O ----------------------------- drivers/base/power/main.c:1333 RCU-list traversed in non-reader section!! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 5 locks held by rtcwake/547: #0: 00000000643ab418 (sb_writers#6){.+.+}-{0:0}, at: file_start_write+0x2b/0x3a #1: 0000000067a0ca88 (&of->mutex#2){+.+.}-{4:4}, at: kernfs_fop_write_iter+0x181/0x24b #2: 00000000631eac40 (kn->active#3){.+.+}-{0:0}, at: kernfs_fop_write_iter+0x191/0x24b #3: 00000000609a1308 (system_transition_mutex){+.+.}-{4:4}, at: pm_suspend+0xaf/0x30b #4: 0000000060c0fdb0 (device_links_srcu){.+.+}-{0:0}, at: device_links_read_lock+0x75/0x98 stack backtrace: CPU: 0 UID: 0 PID: 547 Comm: rtcwake Tainted: G O 6.17.0-rc3-00014-g31419c045d64 #6 VOLUNTARY Tainted: [O]=OOT_MODULE Stack: 223721b3a80 6089eac6 00000001 00000001 ffffff00 6089eac6 00000535 6086e528 721b3ac0 6003c294 00000000 60031fc0 Call Trace: [<600407ed>] show_stack+0x10e/0x127 [<6003c294>] dump_stack_lvl+0x77/0xc6 [<6003c2fd>] dump_stack+0x1a/0x20 [<600bc2f8>] lockdep_rcu_suspicious+0x116/0x13e [<603d8ea1>] dpm_async_suspend_superior+0x117/0x17e [<603d980f>] device_suspend+0x528/0x541 [<603da24b>] dpm_suspend+0x1a2/0x267 [<603da837>] dpm_suspend_start+0x5d/0x72 [<600ca0c9>] suspend_devices_and_enter+0xab/0x736 [...] Add the fourth argument to the iteration to annotate this and avoid the splat. Fixes: 06799631d522 ("PM: sleep: Make async suspend handle suppliers like parents") Fixes: ed18738fff02 ("PM: sleep: Make async resume handle consumers like children") Signed-off-by: Johannes Berg Link: https://patch.msgid.link/20250826134348.aba79f6e6299.I9ecf55da46ccf33778f2c018a82e1819d815b348@changeid Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index dbf5456cd891bd..2ea6e05e6ec90e 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -675,7 +675,7 @@ static void dpm_async_resume_subordinate(struct device *dev, async_func_t func) idx = device_links_read_lock(); /* Start processing the device's "async" consumers. */ - list_for_each_entry_rcu(link, &dev->links.consumers, s_node) + list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_async_with_cleanup(link->consumer, func); @@ -1330,7 +1330,7 @@ static void dpm_async_suspend_superior(struct device *dev, async_func_t func) idx = device_links_read_lock(); /* Start processing the device's "async" suppliers. */ - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) + list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_async_with_cleanup(link->supplier, func); From 04e1f683cd28dc9407b238543871a6e09a570dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20Kempczy=C5=84ski?= Date: Wed, 20 Aug 2025 10:39:04 +0200 Subject: [PATCH 0651/1292] drm/xe/xe_sync: avoid race during ufence signaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marking ufence as signalled after copy_to_user() is too late. Worker thread which signals ufence by memory write might be raced with another userspace vm-bind call. In map/unmap scenario unmap may still see ufence is not signalled causing -EBUSY. Change the order of marking / write to user-fence fixes this issue. Fixes: 977e5b82e090 ("drm/xe: Expose user fence from xe_sync_entry") Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/5536 Signed-off-by: Zbigniew Kempczyński Cc: Matthew Brost Cc: Matthew Auld Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://lore.kernel.org/r/20250820083903.2109891-2-zbigniew.kempczynski@intel.com (cherry picked from commit 8ae04fe9ffc93d6bc3bc63ac08375427d69cee06) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c index f87276df18f280..82872a51f0983a 100644 --- a/drivers/gpu/drm/xe/xe_sync.c +++ b/drivers/gpu/drm/xe/xe_sync.c @@ -77,6 +77,7 @@ static void user_fence_worker(struct work_struct *w) { struct xe_user_fence *ufence = container_of(w, struct xe_user_fence, worker); + WRITE_ONCE(ufence->signalled, 1); if (mmget_not_zero(ufence->mm)) { kthread_use_mm(ufence->mm); if (copy_to_user(ufence->addr, &ufence->value, sizeof(ufence->value))) @@ -91,7 +92,6 @@ static void user_fence_worker(struct work_struct *w) * Wake up waiters only after updating the ufence state, allowing the UMD * to safely reuse the same ufence without encountering -EBUSY errors. */ - WRITE_ONCE(ufence->signalled, 1); wake_up_all(&ufence->xe->ufence_wq); user_fence_put(ufence); } From 7551865cd12af2dc47e5a174eebcfb0b94b5449b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Thu, 21 Aug 2025 16:30:43 +0200 Subject: [PATCH 0652/1292] drm/xe/vm: Don't pin the vm_resv during validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pinning has the odd side-effect that unlocking *any* resv during validation triggers an "unlocking pinned lock" warning. Cc: Matthew Brost Fixes: 5cc3325584c4 ("drm/xe: Rework eviction rejection of bound external bos") Signed-off-by: Thomas Hellstrƶm Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20250821143045.106005-2-thomas.hellstrom@linux.intel.com (cherry picked from commit 0a51bf3e54dd8b77e6f1febbbb66def0660862d2) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_bo.c | 5 ++--- drivers/gpu/drm/xe/xe_vm.h | 15 ++------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 18f27da47a3634..d3ef79ebceee0b 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -2438,7 +2438,6 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict) .no_wait_gpu = false, .gfp_retry_mayfail = true, }; - struct pin_cookie cookie; int ret; if (vm) { @@ -2449,10 +2448,10 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict) ctx.resv = xe_vm_resv(vm); } - cookie = xe_vm_set_validating(vm, allow_res_evict); + xe_vm_set_validating(vm, allow_res_evict); trace_xe_bo_validate(bo); ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx); - xe_vm_clear_validating(vm, allow_res_evict, cookie); + xe_vm_clear_validating(vm, allow_res_evict); return ret; } diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h index 2f213737c7e518..2ecb417c19a280 100644 --- a/drivers/gpu/drm/xe/xe_vm.h +++ b/drivers/gpu/drm/xe/xe_vm.h @@ -315,22 +315,14 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap); * Register this task as currently making bos resident for the vm. Intended * to avoid eviction by the same task of shared bos bound to the vm. * Call with the vm's resv lock held. - * - * Return: A pin cookie that should be used for xe_vm_clear_validating(). */ -static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm, - bool allow_res_evict) +static inline void xe_vm_set_validating(struct xe_vm *vm, bool allow_res_evict) { - struct pin_cookie cookie = {}; - if (vm && !allow_res_evict) { xe_vm_assert_held(vm); - cookie = lockdep_pin_lock(&xe_vm_resv(vm)->lock.base); /* Pairs with READ_ONCE in xe_vm_is_validating() */ WRITE_ONCE(vm->validating, current); } - - return cookie; } /** @@ -338,17 +330,14 @@ static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm, * @vm: Pointer to the vm or NULL * @allow_res_evict: Eviction from @vm was allowed. Must be set to the same * value as for xe_vm_set_validation(). - * @cookie: Cookie obtained from xe_vm_set_validating(). * * Register this task as currently making bos resident for the vm. Intended * to avoid eviction by the same task of shared bos bound to the vm. * Call with the vm's resv lock held. */ -static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict, - struct pin_cookie cookie) +static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict) { if (vm && !allow_res_evict) { - lockdep_unpin_lock(&xe_vm_resv(vm)->lock.base, cookie); /* Pairs with READ_ONCE in xe_vm_is_validating() */ WRITE_ONCE(vm->validating, NULL); } From 2b55ddf36229e0278c956215784ab1feeff510aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Thu, 21 Aug 2025 16:30:45 +0200 Subject: [PATCH 0653/1292] drm/xe/vm: Clear the scratch_pt pointer on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid triggering a dereference of an error pointer on cleanup in xe_vm_free_scratch() by clearing any scratch_pt error pointer. Signed-off-by: Thomas Hellstrƶm Fixes: 06951c2ee72d ("drm/xe: Use NULL PTEs as scratch PTEs") Cc: Brian Welty Cc: Rodrigo Vivi Cc: Lucas De Marchi Cc: # v6.8+ Reviewed-by: Matthew Brost Link: https://lore.kernel.org/r/20250821143045.106005-4-thomas.hellstrom@linux.intel.com (cherry picked from commit 358ee50ab565f3c8ea32480e9d03127a81ba32f8) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_vm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index ec04bef8ae4088..d60c4b1153043c 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1610,8 +1610,12 @@ static int xe_vm_create_scratch(struct xe_device *xe, struct xe_tile *tile, for (i = MAX_HUGEPTE_LEVEL; i < vm->pt_root[id]->level; i++) { vm->scratch_pt[id][i] = xe_pt_create(vm, tile, i); - if (IS_ERR(vm->scratch_pt[id][i])) - return PTR_ERR(vm->scratch_pt[id][i]); + if (IS_ERR(vm->scratch_pt[id][i])) { + int err = PTR_ERR(vm->scratch_pt[id][i]); + + vm->scratch_pt[id][i] = NULL; + return err; + } xe_pt_populate_empty(tile, vm, vm->scratch_pt[id][i]); } From 16ca06aa2c2218cb21907c0c45a746958c944def Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Mon, 25 Aug 2025 08:28:41 -0700 Subject: [PATCH 0654/1292] drm/xe: Don't trigger rebind on initial dma-buf validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the first validate of an imported dma-buf (initial bind), the device has no GPU mappings, so a rebind is unnecessary. Rebinding here is harmful in multi-GPU setups and for VMs using preempt-fence mode, as it would evict in-flight GPU work. v2: - Drop dma_buf_validated, check for XE_PL_SYSTEM (Thomas) Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Signed-off-by: Matthew Brost Reviewed-by: Thomas Hellstrƶm Link: https://lore.kernel.org/r/20250825152841.3837378-1-matthew.brost@intel.com (cherry picked from commit ffdf968762e4fb3cdae54e811ec3525e67440a60) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_bo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index d3ef79ebceee0b..1be2415966df2d 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -812,7 +812,8 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, } if (ttm_bo->type == ttm_bo_type_sg) { - ret = xe_bo_move_notify(bo, ctx); + if (new_mem->mem_type == XE_PL_SYSTEM) + ret = xe_bo_move_notify(bo, ctx); if (!ret) ret = xe_bo_move_dmabuf(ttm_bo, new_mem); return ret; From 75671d90fde8c78e940e15a1366a50ece56c6b69 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 25 Aug 2025 15:57:42 +0000 Subject: [PATCH 0655/1292] drm/xe: switch to local xbasename() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit b0a2ee5567ab ("drm/xe: prepare xe_gen_wa_oob to be multi-use") introduced a call to basename(). The GNU version of this function is not portable and fails to build with alternative libc implementations like musl or bionic. This causes the following build error: drivers/gpu/drm/xe/xe_gen_wa_oob.c:130:12: error: assignment to ā€˜const char *’ from ā€˜int’ makes pointer from integer without a cast [-Wint-conversion] 130 | fn = basename(fn); | ^ While a POSIX version of basename() could be used, it would require a separate header plus the behavior differs from GNU version in that it might modify its argument. Not great. Instead, implement a local xbasename() helper based on strrchr() that provides the same functionality and avoids portability issues. Fixes: b0a2ee5567ab ("drm/xe: prepare xe_gen_wa_oob to be multi-use") Suggested-by: Lucas De Marchi Reviewed-by: Tiffany Yang Signed-off-by: Carlos Llamas Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20250825155743.1132433-1-cmllamas@google.com Signed-off-by: Lucas De Marchi (cherry picked from commit 41be792f5baaf90d744a9a9e82994ce560ca9582) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_gen_wa_oob.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_gen_wa_oob.c b/drivers/gpu/drm/xe/xe_gen_wa_oob.c index 6581cb0f0e5909..247e41c1c48daf 100644 --- a/drivers/gpu/drm/xe/xe_gen_wa_oob.c +++ b/drivers/gpu/drm/xe/xe_gen_wa_oob.c @@ -123,11 +123,19 @@ static int parse(FILE *input, FILE *csource, FILE *cheader, char *prefix) return 0; } +/* Avoid GNU vs POSIX basename() discrepancy, just use our own */ +static const char *xbasename(const char *s) +{ + const char *p = strrchr(s, '/'); + + return p ? p + 1 : s; +} + static int fn_to_prefix(const char *fn, char *prefix, size_t size) { size_t len; - fn = basename(fn); + fn = xbasename(fn); len = strlen(fn); if (len > size - 1) From 198f36f902ec7e99b645382505f74b87a4523ed9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 25 Aug 2025 11:27:19 -0700 Subject: [PATCH 0656/1292] blk-zoned: Fix a lockdep complaint about recursive locking If preparing a write bio fails then blk_zone_wplug_bio_work() calls bio_endio() with zwplug->lock held. If a device mapper driver is stacked on top of the zoned block device then this results in nested locking of zwplug->lock. The resulting lockdep complaint is a false positive because this is nested locking and not recursive locking. Suppress this false positive by calling blk_zone_wplug_bio_io_error() without holding zwplug->lock. This is safe because no code in blk_zone_wplug_bio_io_error() depends on zwplug->lock being held. This patch suppresses the following lockdep complaint: WARNING: possible recursive locking detected -------------------------------------------- kworker/3:0H/46 is trying to acquire lock: ffffff882968b830 (&zwplug->lock){-...}-{2:2}, at: blk_zone_write_plug_bio_endio+0x64/0x1f0 but task is already holding lock: ffffff88315bc230 (&zwplug->lock){-...}-{2:2}, at: blk_zone_wplug_bio_work+0x8c/0x48c other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&zwplug->lock); lock(&zwplug->lock); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by kworker/3:0H/46: #0: ffffff8809486758 ((wq_completion)sdd_zwplugs){+.+.}-{0:0}, at: process_one_work+0x1bc/0x65c #1: ffffffc085de3d70 ((work_completion)(&zwplug->bio_work)){+.+.}-{0:0}, at: process_one_work+0x1e4/0x65c #2: ffffff88315bc230 (&zwplug->lock){-...}-{2:2}, at: blk_zone_wplug_bio_work+0x8c/0x48c stack backtrace: CPU: 3 UID: 0 PID: 46 Comm: kworker/3:0H Tainted: G W OE 6.12.38-android16-5-maybe-dirty-4k #1 8b362b6f76e3645a58cd27d86982bce10d150025 Tainted: [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Hardware name: Spacecraft board based on MALIBU (DT) Workqueue: sdd_zwplugs blk_zone_wplug_bio_work Call trace: dump_backtrace+0xfc/0x17c show_stack+0x18/0x28 dump_stack_lvl+0x40/0xa0 dump_stack+0x18/0x24 print_deadlock_bug+0x38c/0x398 __lock_acquire+0x13e8/0x2e1c lock_acquire+0x134/0x2b4 _raw_spin_lock_irqsave+0x5c/0x80 blk_zone_write_plug_bio_endio+0x64/0x1f0 bio_endio+0x9c/0x240 __dm_io_complete+0x214/0x260 clone_endio+0xe8/0x214 bio_endio+0x218/0x240 blk_zone_wplug_bio_work+0x204/0x48c process_one_work+0x26c/0x65c worker_thread+0x33c/0x498 kthread+0x110/0x134 ret_from_fork+0x10/0x20 Cc: stable@vger.kernel.org Cc: Damien Le Moal Cc: Christoph Hellwig Fixes: dd291d77cc90 ("block: Introduce zone write plugging") Signed-off-by: Bart Van Assche Reviewed-by: Damien Le Moal Link: https://lore.kernel.org/r/20250825182720.1697203-1-bvanassche@acm.org Signed-off-by: Jens Axboe --- block/blk-zoned.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index ef43aaca49f4d9..5e2a5788dc3b29 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -1286,14 +1286,14 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) struct block_device *bdev; unsigned long flags; struct bio *bio; + bool prepared; /* * Submit the next plugged BIO. If we do not have any, clear * the plugged flag. */ - spin_lock_irqsave(&zwplug->lock, flags); - again: + spin_lock_irqsave(&zwplug->lock, flags); bio = bio_list_pop(&zwplug->bio_list); if (!bio) { zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; @@ -1304,13 +1304,14 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) trace_blk_zone_wplug_bio(zwplug->disk->queue, zwplug->zone_no, bio->bi_iter.bi_sector, bio_sectors(bio)); - if (!blk_zone_wplug_prepare_bio(zwplug, bio)) { + prepared = blk_zone_wplug_prepare_bio(zwplug, bio); + spin_unlock_irqrestore(&zwplug->lock, flags); + + if (!prepared) { blk_zone_wplug_bio_io_error(zwplug, bio); goto again; } - spin_unlock_irqrestore(&zwplug->lock, flags); - bdev = bio->bi_bdev; /* From 051b02b17a8b383ee033db211f90f24b91ac7006 Mon Sep 17 00:00:00 2001 From: Aaron Erhardt Date: Tue, 26 Aug 2025 16:10:54 +0200 Subject: [PATCH 0657/1292] ALSA: hda/realtek: Fix headset mic for TongFang X6[AF]R5xxY Add a PCI quirk to enable microphone detection on the headphone jack of TongFang X6AR5xxY and X6FR5xxY devices. Signed-off-by: Aaron Erhardt Cc: Link: https://patch.msgid.link/20250826141054.1201482-1-aer@tuxedocomputers.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 0323606b3d6d9b..85bb8c4d3b1704 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -7147,6 +7147,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1d05, 0x121b, "TongFang GMxAGxx", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x1d05, 0x1387, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1d05, 0x1409, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1d05, 0x300f, "TongFang X6AR5xxY", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1d05, 0x3019, "TongFang X6FR5xxY", ALC2XX_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS), SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE), From e3ef9445cd9d90e43de0bd3cd55d437773dfd139 Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Tue, 26 Aug 2025 22:00:32 +0530 Subject: [PATCH 0658/1292] block: validate QoS before calling __rq_qos_done_bio() If a bio has BIO_QOS_xxx set, it doesn't guarantee that q->rq_qos is also present at-least for stacked block devices. For instance, in case of NVMe when multipath is enabled, the bottom device may have QoS enabled but top device doesn't. So always validate QoS is enabled and q->rq_qos is present before calling __rq_qos_done_bio(). Fixes: 370ac285f23a ("block: avoid cpu_hotplug_lock depedency on freeze_lock") Reported-by: Venkat Rao Bagalkote Closes: https://lore.kernel.org/all/3a07b752-06a4-4eee-b302-f4669feb859d@linux.ibm.com/ Signed-off-by: Nilay Shroff Link: https://lore.kernel.org/r/20250826163128.1952394-1-nilay@linux.ibm.com Signed-off-by: Jens Axboe --- block/blk-rq-qos.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index 1fe22000a3790e..b538f2c0febc2b 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -149,12 +149,15 @@ static inline void rq_qos_done_bio(struct bio *bio) q = bdev_get_queue(bio->bi_bdev); /* - * If a bio has BIO_QOS_xxx set, it implicitly implies that - * q->rq_qos is present. So, we skip re-checking q->rq_qos - * here as an extra optimization and directly call - * __rq_qos_done_bio(). + * A BIO may carry BIO_QOS_* flags even if the associated request_queue + * does not have rq_qos enabled. This can happen with stacked block + * devices — for example, NVMe multipath, where it's possible that the + * bottom device has QoS enabled but the top device does not. Therefore, + * always verify that q->rq_qos is present and QoS is enabled before + * calling __rq_qos_done_bio(). */ - __rq_qos_done_bio(q->rq_qos, bio); + if (test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags) && q->rq_qos) + __rq_qos_done_bio(q->rq_qos, bio); } static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio) From e81a7f65288c7e2cfb7e7890f648e099fd885ab3 Mon Sep 17 00:00:00 2001 From: Fabio Porcedda Date: Fri, 22 Aug 2025 11:13:24 +0200 Subject: [PATCH 0659/1292] net: usb: qmi_wwan: add Telit Cinterion LE910C4-WWX new compositions Add the following Telit Cinterion LE910C4-WWX new compositions: 0x1034: tty (AT) + tty (AT) + rmnet T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 8 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=1034 Rev=00.00 S: Manufacturer=Telit S: Product=LE910C4-WWX S: SerialNumber=93f617e7 C: #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=fe Prot=ff Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x1037: tty (diag) + tty (Telit custom) + tty (AT) + tty (AT) + rmnet T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 15 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=1037 Rev=00.00 S: Manufacturer=Telit S: Product=LE910C4-WWX S: SerialNumber=93f617e7 C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=fe Prot=ff Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x1038: tty (Telit custom) + tty (AT) + tty (AT) + rmnet T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 9 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=1038 Rev=00.00 S: Manufacturer=Telit S: Product=LE910C4-WWX S: SerialNumber=93f617e7 C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=fe Prot=ff Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 64 Ivl=2ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms Cc: stable@vger.kernel.org Signed-off-by: Fabio Porcedda Link: https://patch.msgid.link/20250822091324.39558-1-Fabio.Porcedda@telit.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/qmi_wwan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index e56901bb6ebc43..11352d85475ae2 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1355,6 +1355,9 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1031, 3)}, /* Telit LE910C1-EUX */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1034, 2)}, /* Telit LE910C4-WWX */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1037, 4)}, /* Telit LE910C4-WWX */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1038, 3)}, /* Telit LE910C4-WWX */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x103a, 0)}, /* Telit LE910C4-WWX */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)}, /* Telit FN980 */ From 882e57cbc7204662f6c5672d5b04336c1d790b03 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Mon, 25 Aug 2025 08:55:43 +0200 Subject: [PATCH 0660/1292] phy: mscc: Fix when PTP clock is register and unregister It looks like that every time when the interface was set down and up the driver was creating a new ptp clock. On top of this the function ptp_clock_unregister was never called. Therefore fix this by calling ptp_clock_register and initialize the mii_ts struct inside the probe function and call ptp_clock_unregister when driver is removed. Fixes: 7d272e63e0979d ("net: phy: mscc: timestamping and PHC support") Signed-off-by: Horatiu Vultur Reviewed-by: Vadim Fedorenko Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20250825065543.2916334-1-horatiu.vultur@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc/mscc.h | 4 ++++ drivers/net/phy/mscc/mscc_main.c | 4 +--- drivers/net/phy/mscc/mscc_ptp.c | 34 ++++++++++++++++++++------------ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h index 58c6d47fbe046d..2bfe314ef881c3 100644 --- a/drivers/net/phy/mscc/mscc.h +++ b/drivers/net/phy/mscc/mscc.h @@ -481,6 +481,7 @@ static inline void vsc8584_config_macsec_intr(struct phy_device *phydev) void vsc85xx_link_change_notify(struct phy_device *phydev); void vsc8584_config_ts_intr(struct phy_device *phydev); int vsc8584_ptp_init(struct phy_device *phydev); +void vsc8584_ptp_deinit(struct phy_device *phydev); int vsc8584_ptp_probe_once(struct phy_device *phydev); int vsc8584_ptp_probe(struct phy_device *phydev); irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev); @@ -495,6 +496,9 @@ static inline int vsc8584_ptp_init(struct phy_device *phydev) { return 0; } +static inline void vsc8584_ptp_deinit(struct phy_device *phydev) +{ +} static inline int vsc8584_ptp_probe_once(struct phy_device *phydev) { return 0; diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index f1c9ce351ab42c..24c75903f53543 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2337,9 +2337,7 @@ static int vsc85xx_probe(struct phy_device *phydev) static void vsc85xx_remove(struct phy_device *phydev) { - struct vsc8531_private *priv = phydev->priv; - - skb_queue_purge(&priv->rx_skbs_list); + vsc8584_ptp_deinit(phydev); } /* Microsemi VSC85xx PHYs */ diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c index de6c7312e8f290..72847320cb652d 100644 --- a/drivers/net/phy/mscc/mscc_ptp.c +++ b/drivers/net/phy/mscc/mscc_ptp.c @@ -1298,7 +1298,6 @@ static void vsc8584_set_input_clk_configured(struct phy_device *phydev) static int __vsc8584_init_ptp(struct phy_device *phydev) { - struct vsc8531_private *vsc8531 = phydev->priv; static const u32 ltc_seq_e[] = { 0, 400000, 0, 0, 0 }; static const u8 ltc_seq_a[] = { 8, 6, 5, 4, 2 }; u32 val; @@ -1515,17 +1514,7 @@ static int __vsc8584_init_ptp(struct phy_device *phydev) vsc85xx_ts_eth_cmp1_sig(phydev); - vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp; - vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp; - vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp; - vsc8531->mii_ts.ts_info = vsc85xx_ts_info; - phydev->mii_ts = &vsc8531->mii_ts; - - memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps)); - - vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps, - &phydev->mdio.dev); - return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock); + return 0; } void vsc8584_config_ts_intr(struct phy_device *phydev) @@ -1552,6 +1541,16 @@ int vsc8584_ptp_init(struct phy_device *phydev) return 0; } +void vsc8584_ptp_deinit(struct phy_device *phydev) +{ + struct vsc8531_private *vsc8531 = phydev->priv; + + if (vsc8531->ptp->ptp_clock) { + ptp_clock_unregister(vsc8531->ptp->ptp_clock); + skb_queue_purge(&vsc8531->rx_skbs_list); + } +} + irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev) { struct vsc8531_private *priv = phydev->priv; @@ -1612,7 +1611,16 @@ int vsc8584_ptp_probe(struct phy_device *phydev) vsc8531->ptp->phydev = phydev; - return 0; + vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp; + vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp; + vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp; + vsc8531->mii_ts.ts_info = vsc85xx_ts_info; + phydev->mii_ts = &vsc8531->mii_ts; + + memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps)); + vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps, + &phydev->mdio.dev); + return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock); } int vsc8584_ptp_probe_once(struct phy_device *phydev) From 26c1f55f7ec8d1a4bde8c50e4ee04e3c8c6b27e8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 25 Aug 2025 08:57:53 -0700 Subject: [PATCH 0661/1292] MAINTAINERS: retire Boris from TLS maintainers There's a steady stream of TLS changes and bugs. We need active maintainers in this area, and Boris hasn't been participating much in upstream work. Move him to CREDITS. While at it also add Dave Watson there who was the author of the initial SW implementation, AFAIU. Link: https://patch.msgid.link/20250825155753.2178045-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- CREDITS | 7 +++++++ MAINTAINERS | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CREDITS b/CREDITS index a357f9cbb05daa..a687c3c35c4c23 100644 --- a/CREDITS +++ b/CREDITS @@ -3222,6 +3222,10 @@ D: AIC5800 IEEE 1394, RAW I/O on 1394 D: Starter of Linux1394 effort S: ask per mail for current address +N: Boris Pismenny +E: borisp@mellanox.com +D: Kernel TLS implementation and offload support. + N: Nicolas Pitre E: nico@fluxnic.net D: StrongARM SA1100 support integrator & hacker @@ -4168,6 +4172,9 @@ S: 1513 Brewster Dr. S: Carrollton, TX 75010 S: USA +N: Dave Watson +D: Kernel TLS implementation. + N: Tim Waugh E: tim@cyberelk.net D: Co-architect of the parallel-port sharing system diff --git a/MAINTAINERS b/MAINTAINERS index 2720544cd91fda..1897d8b45df440 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17818,7 +17818,6 @@ F: net/ipv6/syncookies.c F: net/ipv6/tcp*.c NETWORKING [TLS] -M: Boris Pismenny M: John Fastabend M: Jakub Kicinski L: netdev@vger.kernel.org From 16c8a3a67ec799fc731919e3e51be9af6cdf541d Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 25 Aug 2025 13:21:34 -0400 Subject: [PATCH 0662/1292] net: macb: Fix offset error in gem_update_stats hw_stats now has only one variable for tx_octets/rx_octets, so we should only increment p once, not twice. This would cause the statistics to be reported under the wrong categories in `ethtool -S --all-groups` (which uses hw_stats) but not `ethtool -S` (which uses ethtool_stats). Signed-off-by: Sean Anderson Fixes: f6af690a295a ("net: cadence: macb: Report standard stats") Link: https://patch.msgid.link/20250825172134.681861-1-sean.anderson@linux.dev Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index b29c3beae0b254..10688545114708 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -3090,7 +3090,7 @@ static void gem_update_stats(struct macb *bp) /* Add GEM_OCTTXH, GEM_OCTRXH */ val = bp->macb_reg_readl(bp, offset + 4); bp->ethtool_stats[i] += ((u64)val) << 32; - *(p++) += ((u64)val) << 32; + *p += ((u64)val) << 32; } } From d9b0ca1334d8a9a03bef45e95825564c56ca3367 Mon Sep 17 00:00:00 2001 From: Boon Khai Ng Date: Mon, 25 Aug 2025 15:13:21 +0800 Subject: [PATCH 0663/1292] MAINTAINERS: Update maintainer information for Altera Triple Speed Ethernet Driver The previous maintainer, Joyce Ooi, is no longer with the company, and her email is no longer reachable. As a result, the maintainer information for the Altera Triple Speed Ethernet Driver has been updated. Changes: - Replaced Joyce Ooi's email with Boon Khai Ng's email address. - Kept the component's status as "Maintained". Signed-off-by: Boon Khai Ng Link: https://patch.msgid.link/20250825071321.30131-1-boon.khai.ng@altera.com Signed-off-by: Jakub Kicinski --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1897d8b45df440..c5b47955d2a63b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -937,7 +937,7 @@ S: Maintained F: drivers/gpio/gpio-altera.c ALTERA TRIPLE SPEED ETHERNET DRIVER -M: Joyce Ooi +M: Boon Khai Ng L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/altera/ From 2747328ba2714f1a7454208dbbc1dc0631990b4a Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 25 Aug 2025 10:59:25 -0700 Subject: [PATCH 0664/1292] bnxt_en: Fix memory corruption when FW resources change during ifdown bnxt_set_dflt_rings() assumes that it is always called before any TC has been created. So it doesn't take bp->num_tc into account and assumes that it is always 0 or 1. In the FW resource or capability change scenario, the FW will return flags in bnxt_hwrm_if_change() that will cause the driver to reinitialize and call bnxt_cancel_reservations(). This will lead to bnxt_init_dflt_ring_mode() calling bnxt_set_dflt_rings() and bp->num_tc may be greater than 1. This will cause bp->tx_ring[] to be sized too small and cause memory corruption in bnxt_alloc_cp_rings(). Fix it by properly scaling the TX rings by bp->num_tc in the code paths mentioned above. Add 2 helper functions to determine bp->tx_nr_rings and bp->tx_nr_rings_per_tc. Fixes: ec5d31e3c15d ("bnxt_en: Handle firmware reset status during IF_UP.") Reviewed-by: Kalesh AP Reviewed-by: Andy Gospodarek Signed-off-by: Sreekanth Reddy Signed-off-by: Michael Chan Link: https://patch.msgid.link/20250825175927.459987-2-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 207a8bb36ae5f4..1f5c06f1296b28 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -12851,6 +12851,17 @@ static int bnxt_set_xps_mapping(struct bnxt *bp) return rc; } +static int bnxt_tx_nr_rings(struct bnxt *bp) +{ + return bp->num_tc ? bp->tx_nr_rings_per_tc * bp->num_tc : + bp->tx_nr_rings_per_tc; +} + +static int bnxt_tx_nr_rings_per_tc(struct bnxt *bp) +{ + return bp->num_tc ? bp->tx_nr_rings / bp->num_tc : bp->tx_nr_rings; +} + static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) { int rc = 0; @@ -16325,7 +16336,7 @@ static void bnxt_trim_dflt_sh_rings(struct bnxt *bp) bp->cp_nr_rings = min_t(int, bp->tx_nr_rings_per_tc, bp->rx_nr_rings); bp->rx_nr_rings = bp->cp_nr_rings; bp->tx_nr_rings_per_tc = bp->cp_nr_rings; - bp->tx_nr_rings = bp->tx_nr_rings_per_tc; + bp->tx_nr_rings = bnxt_tx_nr_rings(bp); } static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) @@ -16357,7 +16368,7 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) bnxt_trim_dflt_sh_rings(bp); else bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings; - bp->tx_nr_rings = bp->tx_nr_rings_per_tc; + bp->tx_nr_rings = bnxt_tx_nr_rings(bp); avail_msix = bnxt_get_max_func_irqs(bp) - bp->cp_nr_rings; if (avail_msix >= BNXT_MIN_ROCE_CP_RINGS) { @@ -16370,7 +16381,7 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) rc = __bnxt_reserve_rings(bp); if (rc && rc != -ENODEV) netdev_warn(bp->dev, "Unable to reserve tx rings\n"); - bp->tx_nr_rings_per_tc = bp->tx_nr_rings; + bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); if (sh) bnxt_trim_dflt_sh_rings(bp); @@ -16379,7 +16390,7 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) rc = __bnxt_reserve_rings(bp); if (rc && rc != -ENODEV) netdev_warn(bp->dev, "2nd rings reservation failed.\n"); - bp->tx_nr_rings_per_tc = bp->tx_nr_rings; + bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); } if (BNXT_CHIP_TYPE_NITRO_A0(bp)) { bp->rx_nr_rings++; @@ -16413,7 +16424,7 @@ static int bnxt_init_dflt_ring_mode(struct bnxt *bp) if (rc) goto init_dflt_ring_err; - bp->tx_nr_rings_per_tc = bp->tx_nr_rings; + bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); bnxt_set_dflt_rfs(bp); From 1ee581c24dfdcbc6de25aac95a48c1f08e9a542c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 25 Aug 2025 10:59:26 -0700 Subject: [PATCH 0665/1292] bnxt_en: Adjust TX rings if reservation is less than requested Before we accept an ethtool request to increase a resource (such as rings), we call the FW to check that the requested resource is likely available first before we commit. But it is still possible that the actual reservation or allocation can fail. The existing code is missing the logic to adjust the TX rings in case the reserved TX rings are less than requested. Add a warning message (a similar message for RX rings already exists) and add the logic to adjust the TX rings. Without this fix, the number of TX rings reported to the stack can exceed the actual TX rings and ethtool -l will report more than the actual TX rings. Fixes: 674f50a5b026 ("bnxt_en: Implement new method to reserve rings.") Reviewed-by: Kalesh AP Reviewed-by: Somnath Kotur Signed-off-by: Michael Chan Link: https://patch.msgid.link/20250825175927.459987-3-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1f5c06f1296b28..86fc9d340dabfd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8024,6 +8024,11 @@ static int __bnxt_reserve_rings(struct bnxt *bp) hwr.rx = rx_rings << 1; tx_cp = bnxt_num_tx_to_cp(bp, hwr.tx); hwr.cp = sh ? max_t(int, tx_cp, rx_rings) : tx_cp + rx_rings; + if (hwr.tx != bp->tx_nr_rings) { + netdev_warn(bp->dev, + "Able to reserve only %d out of %d requested TX rings\n", + hwr.tx, bp->tx_nr_rings); + } bp->tx_nr_rings = hwr.tx; /* If we cannot reserve all the RX rings, reset the RSS map only @@ -12879,6 +12884,13 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) if (rc) return rc; + /* Make adjustments if reserved TX rings are less than requested */ + bp->tx_nr_rings -= bp->tx_nr_rings_xdp; + bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); + if (bp->tx_nr_rings_xdp) { + bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc; + bp->tx_nr_rings += bp->tx_nr_rings_xdp; + } rc = bnxt_alloc_mem(bp, irq_re_init); if (rc) { netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc); From b4fc8faacfea2538184a1dbd616ae9447a361f3d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 25 Aug 2025 10:59:27 -0700 Subject: [PATCH 0666/1292] bnxt_en: Fix stats context reservation logic The HW resource reservation logic allows the L2 driver to use the RoCE resources if the RoCE driver is not registered. When calculating the stats contexts available for L2, we should not blindly subtract the stats contexts reserved for RoCE unless the RoCE driver is registered. This bug may cause the L2 rings to be less than the number requested when we are close to running out of stats contexts. Fixes: 2e4592dc9bee ("bnxt_en: Change MSIX/NQs allocation policy") Reviewed-by: Kalesh AP Reviewed-by: Somnath Kotur Signed-off-by: Michael Chan Link: https://patch.msgid.link/20250825175927.459987-4-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 86fc9d340dabfd..31e3d825b4bc07 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8016,7 +8016,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp) } rx_rings = min_t(int, rx_rings, hwr.grp); hwr.cp = min_t(int, hwr.cp, bp->cp_nr_rings); - if (hwr.stat > bnxt_get_ulp_stat_ctxs(bp)) + if (bnxt_ulp_registered(bp->edev) && + hwr.stat > bnxt_get_ulp_stat_ctxs(bp)) hwr.stat -= bnxt_get_ulp_stat_ctxs(bp); hwr.cp = min_t(int, hwr.cp, hwr.stat); rc = bnxt_trim_rings(bp, &rx_rings, &hwr.tx, hwr.cp, sh); From 2c0a959bebdc1ada13cf9a8242f177c5400299e6 Mon Sep 17 00:00:00 2001 From: Lama Kayal Date: Mon, 25 Aug 2025 17:34:24 +0300 Subject: [PATCH 0667/1292] net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path In the error path of hws_pool_buddy_init(), the buddy allocator cleanup doesn't free the allocator structure itself, causing a memory leak. Add the missing kfree() to properly release all allocated memory. Fixes: c61afff94373 ("net/mlx5: HWS, added memory management handling") Signed-off-by: Lama Kayal Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-2-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c index 7e37d6e9eb8361..7b5071c3df368b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c @@ -124,6 +124,7 @@ static int hws_pool_buddy_init(struct mlx5hws_pool *pool) mlx5hws_err(pool->ctx, "Failed to create resource type: %d size %zu\n", pool->type, pool->alloc_log_sz); mlx5hws_buddy_cleanup(buddy); + kfree(buddy); return -ENOMEM; } From a630f83592cdad1253523a1b760cfe78fef6cd9c Mon Sep 17 00:00:00 2001 From: Lama Kayal Date: Mon, 25 Aug 2025 17:34:25 +0300 Subject: [PATCH 0668/1292] net/mlx5: HWS, Fix memory leak in hws_action_get_shared_stc_nic error flow When an invalid stc_type is provided, the function allocates memory for shared_stc but jumps to unlock_and_out without freeing it, causing a memory leak. Fix by jumping to free_shared_stc label instead to ensure proper cleanup. Fixes: 504e536d9010 ("net/mlx5: HWS, added actions handling") Signed-off-by: Lama Kayal Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-3-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c index 396804369b00c1..6b36a4a7d895fc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c @@ -117,7 +117,7 @@ static int hws_action_get_shared_stc_nic(struct mlx5hws_context *ctx, mlx5hws_err(ctx, "No such stc_type: %d\n", stc_type); pr_warn("HWS: Invalid stc_type: %d\n", stc_type); ret = -EINVAL; - goto unlock_and_out; + goto free_shared_stc; } ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, From 24b6e53140475b56cadcccd4e82a93aa5bacf1eb Mon Sep 17 00:00:00 2001 From: Lama Kayal Date: Mon, 25 Aug 2025 17:34:26 +0300 Subject: [PATCH 0669/1292] net/mlx5: HWS, Fix uninitialized variables in mlx5hws_pat_calc_nop error flow In mlx5hws_pat_calc_nop(), src_field and dst_field are passed to hws_action_modify_get_target_fields() which should set their values. However, if an invalid action type is encountered, these variables remain uninitialized and are later used to update prev_src_field and prev_dst_field. Initialize both variables to INVALID_FIELD to ensure they have defined values in all code paths. Fixes: 01e035fd0380 ("net/mlx5: HWS, handle modify header actions dependency") Signed-off-by: Lama Kayal Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-4-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c index 51e4c551e0efd6..622fd579f1407e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c @@ -527,7 +527,6 @@ int mlx5hws_pat_calc_nop(__be64 *pattern, size_t num_actions, u32 *nop_locations, __be64 *new_pat) { u16 prev_src_field = INVALID_FIELD, prev_dst_field = INVALID_FIELD; - u16 src_field, dst_field; u8 action_type; bool dependent; size_t i, j; @@ -539,6 +538,9 @@ int mlx5hws_pat_calc_nop(__be64 *pattern, size_t num_actions, return 0; for (i = 0, j = 0; i < num_actions; i++, j++) { + u16 src_field = INVALID_FIELD; + u16 dst_field = INVALID_FIELD; + if (j >= max_actions) return -EINVAL; From 00a50e4e8974cbf5d6a1dc91cfa5cce4aa7af05a Mon Sep 17 00:00:00 2001 From: Lama Kayal Date: Mon, 25 Aug 2025 17:34:27 +0300 Subject: [PATCH 0670/1292] net/mlx5: HWS, Fix pattern destruction in mlx5hws_pat_get_pattern error path In mlx5hws_pat_get_pattern(), when mlx5hws_pat_add_pattern_to_cache() fails, the function attempts to clean up the pattern created by mlx5hws_cmd_header_modify_pattern_create(). However, it incorrectly uses *pattern_id which hasn't been set yet, instead of the local ptrn_id variable that contains the actual pattern ID. This results in attempting to destroy a pattern using uninitialized data from the output parameter, rather than the valid pattern ID returned by the firmware. Use ptrn_id instead of *pattern_id in the cleanup path to properly destroy the created pattern. Fixes: aefc15a0fa1c ("net/mlx5: HWS, added modify header pattern and args handling") Signed-off-by: Lama Kayal Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-5-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c index 622fd579f1407e..d56271a9e4f014 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c @@ -279,7 +279,7 @@ int mlx5hws_pat_get_pattern(struct mlx5hws_context *ctx, return ret; clean_pattern: - mlx5hws_cmd_header_modify_pattern_destroy(ctx->mdev, *pattern_id); + mlx5hws_cmd_header_modify_pattern_destroy(ctx->mdev, ptrn_id); out_unlock: mutex_unlock(&ctx->pattern_cache->lock); return ret; From 34cc6a54914f478c93e176450fae6313404f9f74 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 25 Aug 2025 17:34:28 +0300 Subject: [PATCH 0671/1292] net/mlx5: Reload auxiliary drivers on fw_activate The devlink reload fw_activate command performs firmware activation followed by driver reload, while devlink reload driver_reinit triggers only driver reload. However, the driver reload logic differs between the two modes, as on driver_reinit mode mlx5 also reloads auxiliary drivers, while in fw_activate mode the auxiliary drivers are suspended where applicable. Additionally, following the cited commit, if the device has multiple PFs, the behavior during fw_activate may vary between PFs: one PF may suspend auxiliary drivers, while another reloads them. Align devlink dev reload fw_activate behavior with devlink dev reload driver_reinit, to reload all auxiliary drivers. Fixes: 72ed5d5624af ("net/mlx5: Suspend auxiliary devices only in case of PCI device suspend") Signed-off-by: Moshe Shemesh Reviewed-by: Tariq Toukan Reviewed-by: Akiva Goldberger Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-6-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 3ffa3fbacd162e..26091e7536d33c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -160,7 +160,7 @@ static int mlx5_devlink_reload_fw_activate(struct devlink *devlink, struct netli if (err) return err; - mlx5_unload_one_devl_locked(dev, true); + mlx5_unload_one_devl_locked(dev, false); err = mlx5_health_wait_pci_up(dev); if (err) NL_SET_ERR_MSG_MOD(extack, "FW activate aborted, PCI reads fail after reset"); From 902a8bc23a24882200f57cadc270e15a2cfaf2bb Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 25 Aug 2025 17:34:29 +0300 Subject: [PATCH 0672/1292] net/mlx5: Fix lockdep assertion on sync reset unload event Fix lockdep assertion triggered during sync reset unload event. When the sync reset flow is initiated using the devlink reload fw_activate option, the PF already holds the devlink lock while handling unload event. In this case, delegate sync reset unload event handling back to the devlink callback process to avoid double-locking and resolve the lockdep warning. Kernel log: WARNING: CPU: 9 PID: 1578 at devl_assert_locked+0x31/0x40 [...] Call Trace: mlx5_unload_one_devl_locked+0x2c/0xc0 [mlx5_core] mlx5_sync_reset_unload_event+0xaf/0x2f0 [mlx5_core] process_one_work+0x222/0x640 worker_thread+0x199/0x350 kthread+0x10b/0x230 ? __pfx_worker_thread+0x10/0x10 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x8e/0x100 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Fixes: 7a9770f1bfea ("net/mlx5: Handle sync reset unload event") Signed-off-by: Moshe Shemesh Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-7-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/devlink.c | 2 +- .../ethernet/mellanox/mlx5/core/fw_reset.c | 120 ++++++++++-------- .../ethernet/mellanox/mlx5/core/fw_reset.h | 1 + 3 files changed, 69 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 26091e7536d33c..2c0e0c16ca90a9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -160,7 +160,7 @@ static int mlx5_devlink_reload_fw_activate(struct devlink *devlink, struct netli if (err) return err; - mlx5_unload_one_devl_locked(dev, false); + mlx5_sync_reset_unload_flow(dev, true); err = mlx5_health_wait_pci_up(dev); if (err) NL_SET_ERR_MSG_MOD(extack, "FW activate aborted, PCI reads fail after reset"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 69933addd921e6..38b9b184ae01b6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -12,7 +12,8 @@ enum { MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, MLX5_FW_RESET_FLAGS_PENDING_COMP, MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, - MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED + MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, + MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, }; struct mlx5_fw_reset { @@ -219,7 +220,7 @@ int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev) return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL0, 0, 0, false); } -static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unloaded) +static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev) { struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; struct devlink *devlink = priv_to_devlink(dev); @@ -228,8 +229,7 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unload if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) { complete(&fw_reset->done); } else { - if (!unloaded) - mlx5_unload_one(dev, false); + mlx5_sync_reset_unload_flow(dev, false); if (mlx5_health_wait_pci_up(dev)) mlx5_core_err(dev, "reset reload flow aborted, PCI reads still not working\n"); else @@ -272,7 +272,7 @@ static void mlx5_sync_reset_reload_work(struct work_struct *work) mlx5_sync_reset_clear_reset_requested(dev, false); mlx5_enter_error_state(dev, true); - mlx5_fw_reset_complete_reload(dev, false); + mlx5_fw_reset_complete_reload(dev); } #define MLX5_RESET_POLL_INTERVAL (HZ / 10) @@ -586,6 +586,65 @@ static int mlx5_sync_pci_reset(struct mlx5_core_dev *dev, u8 reset_method) return err; } +void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked) +{ + struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; + unsigned long timeout; + int poll_freq = 20; + bool reset_action; + u8 rst_state; + int err; + + if (locked) + mlx5_unload_one_devl_locked(dev, false); + else + mlx5_unload_one(dev, false); + + if (!test_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags)) + return; + + mlx5_set_fw_rst_ack(dev); + mlx5_core_warn(dev, "Sync Reset Unload done, device reset expected\n"); + + reset_action = false; + timeout = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, RESET_UNLOAD)); + do { + rst_state = mlx5_get_fw_rst_state(dev); + if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ || + rst_state == MLX5_FW_RST_STATE_IDLE) { + reset_action = true; + break; + } + if (rst_state == MLX5_FW_RST_STATE_DROP_MODE) { + mlx5_core_info(dev, "Sync Reset Drop mode ack\n"); + mlx5_set_fw_rst_ack(dev); + poll_freq = 1000; + } + msleep(poll_freq); + } while (!time_after(jiffies, timeout)); + + if (!reset_action) { + mlx5_core_err(dev, "Got timeout waiting for sync reset action, state = %u\n", + rst_state); + fw_reset->ret = -ETIMEDOUT; + goto done; + } + + mlx5_core_warn(dev, "Sync Reset, got reset action. rst_state = %u\n", + rst_state); + if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ) { + err = mlx5_sync_pci_reset(dev, fw_reset->reset_method); + if (err) { + mlx5_core_warn(dev, "mlx5_sync_pci_reset failed, err %d\n", + err); + fw_reset->ret = err; + } + } + +done: + clear_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags); +} + static void mlx5_sync_reset_now_event(struct work_struct *work) { struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset, @@ -613,17 +672,13 @@ static void mlx5_sync_reset_now_event(struct work_struct *work) mlx5_enter_error_state(dev, true); done: fw_reset->ret = err; - mlx5_fw_reset_complete_reload(dev, false); + mlx5_fw_reset_complete_reload(dev); } static void mlx5_sync_reset_unload_event(struct work_struct *work) { struct mlx5_fw_reset *fw_reset; struct mlx5_core_dev *dev; - unsigned long timeout; - int poll_freq = 20; - bool reset_action; - u8 rst_state; int err; fw_reset = container_of(work, struct mlx5_fw_reset, reset_unload_work); @@ -632,6 +687,7 @@ static void mlx5_sync_reset_unload_event(struct work_struct *work) if (mlx5_sync_reset_clear_reset_requested(dev, false)) return; + set_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags); mlx5_core_warn(dev, "Sync Reset Unload. Function is forced down.\n"); err = mlx5_cmd_fast_teardown_hca(dev); @@ -640,49 +696,7 @@ static void mlx5_sync_reset_unload_event(struct work_struct *work) else mlx5_enter_error_state(dev, true); - if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) - mlx5_unload_one_devl_locked(dev, false); - else - mlx5_unload_one(dev, false); - - mlx5_set_fw_rst_ack(dev); - mlx5_core_warn(dev, "Sync Reset Unload done, device reset expected\n"); - - reset_action = false; - timeout = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, RESET_UNLOAD)); - do { - rst_state = mlx5_get_fw_rst_state(dev); - if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ || - rst_state == MLX5_FW_RST_STATE_IDLE) { - reset_action = true; - break; - } - if (rst_state == MLX5_FW_RST_STATE_DROP_MODE) { - mlx5_core_info(dev, "Sync Reset Drop mode ack\n"); - mlx5_set_fw_rst_ack(dev); - poll_freq = 1000; - } - msleep(poll_freq); - } while (!time_after(jiffies, timeout)); - - if (!reset_action) { - mlx5_core_err(dev, "Got timeout waiting for sync reset action, state = %u\n", - rst_state); - fw_reset->ret = -ETIMEDOUT; - goto done; - } - - mlx5_core_warn(dev, "Sync Reset, got reset action. rst_state = %u\n", rst_state); - if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ) { - err = mlx5_sync_pci_reset(dev, fw_reset->reset_method); - if (err) { - mlx5_core_warn(dev, "mlx5_sync_pci_reset failed, err %d\n", err); - fw_reset->ret = err; - } - } - -done: - mlx5_fw_reset_complete_reload(dev, true); + mlx5_fw_reset_complete_reload(dev); } static void mlx5_sync_reset_abort_event(struct work_struct *work) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h index ea527d06a85f07..d5b28525c960dc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h @@ -12,6 +12,7 @@ int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel, int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev); int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev); +void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked); int mlx5_fw_reset_verify_fw_complete(struct mlx5_core_dev *dev, struct netlink_ext_ack *extack); void mlx5_fw_reset_events_start(struct mlx5_core_dev *dev); From 26e42ec7712d392d561964514b1f253b1a96f42d Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 25 Aug 2025 17:34:30 +0300 Subject: [PATCH 0673/1292] net/mlx5: Nack sync reset when SFs are present If PF (Physical Function) has SFs (Sub-Functions), since the SFs are not taking part in the synchronization flow, sync reset can lead to fatal error on the SFs, as the function will be closed unexpectedly from the SF point of view. Add a check to prevent sync reset when there are SFs on a PF device which is not ECPF, as ECPF is teardowned gracefully before reset. Fixes: 92501fa6e421 ("net/mlx5: Ack on sync_reset_request only if PF can do reset_now") Signed-off-by: Moshe Shemesh Reviewed-by: Parav Pandit Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-8-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c | 6 ++++++ drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c | 10 ++++++++++ drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 38b9b184ae01b6..22995131824a03 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -6,6 +6,7 @@ #include "fw_reset.h" #include "diag/fw_tracer.h" #include "lib/tout.h" +#include "sf/sf.h" enum { MLX5_FW_RESET_FLAGS_RESET_REQUESTED, @@ -428,6 +429,11 @@ static bool mlx5_is_reset_now_capable(struct mlx5_core_dev *dev, return false; } + if (!mlx5_core_is_ecpf(dev) && !mlx5_sf_table_empty(dev)) { + mlx5_core_warn(dev, "SFs should be removed before reset\n"); + return false; + } + #if IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE) if (reset_method != MLX5_MFRL_REG_PCI_RESET_METHOD_HOT_RESET) { err = mlx5_check_hotplug_interrupt(dev, bridge); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c index 0864ba625c07d7..3304f25cc8055c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c @@ -518,3 +518,13 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev) WARN_ON(!xa_empty(&table->function_ids)); kfree(table); } + +bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev) +{ + struct mlx5_sf_table *table = dev->priv.sf_table; + + if (!table) + return true; + + return xa_empty(&table->function_ids); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h index 860f9ddb7107b8..89559a37997ad6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h @@ -17,6 +17,7 @@ void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev); int mlx5_sf_table_init(struct mlx5_core_dev *dev); void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev); +bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev); int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_new_attrs *add_attr, @@ -61,6 +62,11 @@ static inline void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev) { } +static inline bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev) +{ + return true; +} + #endif #endif From cf9a8627b9a369ba01d37be6f71b297beb688faa Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 25 Aug 2025 17:34:31 +0300 Subject: [PATCH 0674/1292] net/mlx5: Prevent flow steering mode changes in switchdev mode Changing flow steering modes is not allowed when eswitch is in switchdev mode. This fix ensures that any steering mode change, including to firmware steering, is correctly blocked while eswitch mode is switchdev. Fixes: e890acd5ff18 ("net/mlx5: Add devlink flow_steering_mode parameter") Signed-off-by: Moshe Shemesh Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-9-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index d87392360dbd27..cb165085a4c10c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -3734,6 +3734,13 @@ static int mlx5_fs_mode_validate(struct devlink *devlink, u32 id, char *value = val.vstr; u8 eswitch_mode; + eswitch_mode = mlx5_eswitch_mode(dev); + if (eswitch_mode == MLX5_ESWITCH_OFFLOADS) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Changing fs mode is not supported when eswitch offloads enabled."); + return -EOPNOTSUPP; + } + if (!strcmp(value, "dmfs")) return 0; @@ -3759,14 +3766,6 @@ static int mlx5_fs_mode_validate(struct devlink *devlink, u32 id, return -EINVAL; } - eswitch_mode = mlx5_eswitch_mode(dev); - if (eswitch_mode == MLX5_ESWITCH_OFFLOADS) { - NL_SET_ERR_MSG_FMT_MOD(extack, - "Moving to %s is not supported when eswitch offloads enabled.", - value); - return -EOPNOTSUPP; - } - return 0; } From ceddedc969f0532b7c62ca971ee50d519d2bc0cb Mon Sep 17 00:00:00 2001 From: Alexei Lazar Date: Mon, 25 Aug 2025 17:34:32 +0300 Subject: [PATCH 0675/1292] net/mlx5e: Update and set Xon/Xoff upon MTU set Xon/Xoff sizes are derived from calculation that include the MTU size. Set Xon/Xoff when MTU is set. If Xon/Xoff fails, set the previous MTU. Fixes: 0696d60853d5 ("net/mlx5e: Receive buffer configuration") Signed-off-by: Alexei Lazar Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-10-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- .../mellanox/mlx5/core/en/port_buffer.h | 12 ++++++++++++ .../net/ethernet/mellanox/mlx5/core/en_main.c | 17 ++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h index f4a19ffbb641c0..66d276a1be836a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h @@ -66,11 +66,23 @@ struct mlx5e_port_buffer { struct mlx5e_bufferx_reg buffer[MLX5E_MAX_NETWORK_BUFFER]; }; +#ifdef CONFIG_MLX5_CORE_EN_DCB int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, u32 change, unsigned int mtu, struct ieee_pfc *pfc, u32 *buffer_size, u8 *prio2buffer); +#else +static inline int +mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, + u32 change, unsigned int mtu, + void *pfc, + u32 *buffer_size, + u8 *prio2buffer) +{ + return 0; +} +#endif int mlx5e_port_query_buffer(struct mlx5e_priv *priv, struct mlx5e_port_buffer *port_buffer); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 21bb88c5d3dcee..15eded36b872a2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -49,6 +49,7 @@ #include "en.h" #include "en/dim.h" #include "en/txrx.h" +#include "en/port_buffer.h" #include "en_tc.h" #include "en_rep.h" #include "en_accel/ipsec.h" @@ -3040,9 +3041,11 @@ int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv) struct mlx5e_params *params = &priv->channels.params; struct net_device *netdev = priv->netdev; struct mlx5_core_dev *mdev = priv->mdev; - u16 mtu; + u16 mtu, prev_mtu; int err; + mlx5e_query_mtu(mdev, params, &prev_mtu); + err = mlx5e_set_mtu(mdev, params, params->sw_mtu); if (err) return err; @@ -3052,6 +3055,18 @@ int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv) netdev_warn(netdev, "%s: VPort MTU %d is different than netdev mtu %d\n", __func__, mtu, params->sw_mtu); + if (mtu != prev_mtu && MLX5_BUFFER_SUPPORTED(mdev)) { + err = mlx5e_port_manual_buffer_config(priv, 0, mtu, + NULL, NULL, NULL); + if (err) { + netdev_warn(netdev, "%s: Failed to set Xon/Xoff values with MTU %d (err %d), setting back to previous MTU %d\n", + __func__, mtu, err, prev_mtu); + + mlx5e_set_mtu(mdev, params, prev_mtu); + return err; + } + } + params->sw_mtu = mtu; return 0; } From d24341740fe48add8a227a753e68b6eedf4b385a Mon Sep 17 00:00:00 2001 From: Alexei Lazar Date: Mon, 25 Aug 2025 17:34:33 +0300 Subject: [PATCH 0676/1292] net/mlx5e: Update and set Xon/Xoff upon port speed set Xon/Xoff sizes are derived from calculations that include the port speed. These settings need to be updated and applied whenever the port speed is changed. The port speed is typically set after the physical link goes down and is negotiated as part of the link-up process between the two connected interfaces. Xon/Xoff parameters being updated at the point where the new negotiated speed is established. Fixes: 0696d60853d5 ("net/mlx5e: Receive buffer configuration") Signed-off-by: Alexei Lazar Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-11-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 15eded36b872a2..e680673ffb725c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -139,6 +139,8 @@ void mlx5e_update_carrier(struct mlx5e_priv *priv) if (up) { netdev_info(priv->netdev, "Link up\n"); netif_carrier_on(priv->netdev); + mlx5e_port_manual_buffer_config(priv, 0, priv->netdev->mtu, + NULL, NULL, NULL); } else { netdev_info(priv->netdev, "Link down\n"); netif_carrier_off(priv->netdev); From aca0c31af61e0d5cf1675a0cbd29460b95ae693c Mon Sep 17 00:00:00 2001 From: Alexei Lazar Date: Mon, 25 Aug 2025 17:34:34 +0300 Subject: [PATCH 0677/1292] net/mlx5e: Set local Xoff after FW update The local Xoff value is being set before the firmware (FW) update. In case of a failure where the FW is not updated with the new value, there is no fallback to the previous value. Update the local Xoff value after the FW has been successfully set. Fixes: 0696d60853d5 ("net/mlx5e: Receive buffer configuration") Signed-off-by: Alexei Lazar Reviewed-by: Tariq Toukan Reviewed-by: Dragos Tatulea Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20250825143435.598584-12-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c index 3efa8bf1d14ef4..4720523813b976 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c @@ -575,7 +575,6 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, if (err) return err; } - priv->dcbx.xoff = xoff; /* Apply the settings */ if (update_buffer) { @@ -584,6 +583,8 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, return err; } + priv->dcbx.xoff = xoff; + if (update_prio2buffer) err = mlx5e_port_set_priority2buffer(priv->mdev, prio2buffer); From 4f23382841e67174211271a454811dd17c0ef3c5 Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Mon, 25 Aug 2025 12:36:52 +0800 Subject: [PATCH 0678/1292] net: stmmac: xgmac: Do not enable RX FIFO Overflow interrupts Enabling RX FIFO Overflow interrupts is counterproductive and causes an interrupt storm when RX FIFO overflows. Disabling this interrupt has no side effect and eliminates interrupt storms when the RX FIFO overflows. Commit 8a7cb245cf28 ("net: stmmac: Do not enable RX FIFO overflow interrupts") disables RX FIFO overflow interrupts for DWMAC4 IP and removes the corresponding handling of this interrupt. This patch is doing the same thing for XGMAC IP. Fixes: 2142754f8b9c ("net: stmmac: Add MAC related callbacks for XGMAC2") Signed-off-by: Rohan G Thomas Reviewed-by: Matthew Gerlach Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250825-xgmac-minor-fixes-v3-1-c225fe4444c0@altera.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 5dcc95bc0ad28b..7201a38842651a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -203,10 +203,6 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, } writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel)); - - /* Enable MTL RX overflow */ - value = readl(ioaddr + XGMAC_MTL_QINTEN(channel)); - writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel)); } static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, From 42ef11b2bff5b6a2910c28d2ea47cc00e0fbcaec Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Mon, 25 Aug 2025 12:36:53 +0800 Subject: [PATCH 0679/1292] net: stmmac: xgmac: Correct supported speed modes Correct supported speed modes as per the XGMAC databook. Commit 9cb54af214a7 ("net: stmmac: Fix IP-cores specific MAC capabilities") removes support for 10M, 100M and 1000HD. 1000HD is not supported by XGMAC IP, but it does support 10M and 100M FD mode for XGMAC version >= 2_20, and it also supports 10M and 100M HD mode if the HDSEL bit is set in the MAC_HW_FEATURE0 reg. This commit enables support for 10M and 100M speed modes for XGMAC IP based on XGMAC version and MAC capabilities. Fixes: 9cb54af214a7 ("net: stmmac: Fix IP-cores specific MAC capabilities") Signed-off-by: Rohan G Thomas Reviewed-by: Matthew Gerlach Link: https://patch.msgid.link/20250825-xgmac-minor-fixes-v3-2-c225fe4444c0@altera.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 13 +++++++++++-- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 6cadf8de4fdfdb..00e929bf280bae 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -49,6 +49,14 @@ static void dwxgmac2_core_init(struct mac_device_info *hw, writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN); } +static void dwxgmac2_update_caps(struct stmmac_priv *priv) +{ + if (!priv->dma_cap.mbps_10_100) + priv->hw->link.caps &= ~(MAC_10 | MAC_100); + else if (!priv->dma_cap.half_duplex) + priv->hw->link.caps &= ~(MAC_10HD | MAC_100HD); +} + static void dwxgmac2_set_mac(void __iomem *ioaddr, bool enable) { u32 tx = readl(ioaddr + XGMAC_TX_CONFIG); @@ -1424,6 +1432,7 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en, const struct stmmac_ops dwxgmac210_ops = { .core_init = dwxgmac2_core_init, + .update_caps = dwxgmac2_update_caps, .set_mac = dwxgmac2_set_mac, .rx_ipc = dwxgmac2_rx_ipc, .rx_queue_enable = dwxgmac2_rx_queue_enable, @@ -1532,8 +1541,8 @@ int dwxgmac2_setup(struct stmmac_priv *priv) mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_1000FD | MAC_2500FD | MAC_5000FD | - MAC_10000FD; + MAC_10 | MAC_100 | MAC_1000FD | + MAC_2500FD | MAC_5000FD | MAC_10000FD; mac->link.duplex = 0; mac->link.speed10 = XGMAC_CONFIG_SS_10_MII; mac->link.speed100 = XGMAC_CONFIG_SS_100_MII; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 7201a38842651a..4d6bb995d8d84c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -382,8 +382,11 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, static int dwxgmac2_get_hw_feature(void __iomem *ioaddr, struct dma_features *dma_cap) { + struct stmmac_priv *priv; u32 hw_cap; + priv = container_of(dma_cap, struct stmmac_priv, dma_cap); + /* MAC HW feature 0 */ hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0); dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31; @@ -406,6 +409,8 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr, dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4; dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3; dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1; + if (dma_cap->mbps_1000 && priv->synopsys_id >= DWXGMAC_CORE_2_20) + dma_cap->mbps_10_100 = 1; /* MAC HW feature 1 */ hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1); From b1eded580ab28119de0b0f21efe37ee2b4419144 Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Mon, 25 Aug 2025 12:36:54 +0800 Subject: [PATCH 0680/1292] net: stmmac: Set CIC bit only for TX queues with COE Currently, in the AF_XDP transmit paths, the CIC bit of TX Desc3 is set for all packets. Setting this bit for packets transmitting through queues that don't support checksum offloading causes the TX DMA to get stuck after transmitting some packets. This patch ensures the CIC bit of TX Desc3 is set only if the TX queue supports checksum offloading. Fixes: 132c32ee5bc0 ("net: stmmac: Add TX via XDP zero-copy socket") Signed-off-by: Rohan G Thomas Reviewed-by: Matthew Gerlach Link: https://patch.msgid.link/20250825-xgmac-minor-fixes-v3-3-c225fe4444c0@altera.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f1abf4242cd2fb..7b16d1207b80c9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2584,6 +2584,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; + bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported; struct xsk_buff_pool *pool = tx_q->xsk_pool; unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc = NULL; @@ -2671,7 +2672,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) } stmmac_prepare_tx_desc(priv, tx_desc, 1, xdp_desc.len, - true, priv->mode, true, true, + csum, priv->mode, true, true, xdp_desc.len); stmmac_enable_dma_transmission(priv, priv->ioaddr, queue); @@ -4983,6 +4984,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, { struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported; unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc; dma_addr_t dma_addr; @@ -5034,7 +5036,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, stmmac_set_desc_addr(priv, tx_desc, dma_addr); stmmac_prepare_tx_desc(priv, tx_desc, 1, xdpf->len, - true, priv->mode, true, true, + csum, priv->mode, true, true, xdpf->len); tx_q->tx_count_frames++; From 9448ccd853368582efa9db05db344f8bb9dffe0f Mon Sep 17 00:00:00 2001 From: Dipayaan Roy Date: Mon, 25 Aug 2025 04:56:27 -0700 Subject: [PATCH 0681/1292] net: hv_netvsc: fix loss of early receive events from host during channel open. The hv_netvsc driver currently enables NAPI after opening the primary and subchannels. This ordering creates a race: if the Hyper-V host places data in the host -> guest ring buffer and signals the channel before napi_enable() has been called, the channel callback will run but napi_schedule_prep() will return false. As a result, the NAPI poller never gets scheduled, the data in the ring buffer is not consumed, and the receive queue may remain permanently stuck until another interrupt happens to arrive. Fix this by enabling NAPI and registering it with the RX/TX queues before vmbus channel is opened. This guarantees that any early host signal after open will correctly trigger NAPI scheduling and the ring buffer will be drained. Fixes: 76bb5db5c749d ("netvsc: fix use after free on module removal") Signed-off-by: Dipayaan Roy Link: https://patch.msgid.link/20250825115627.GA32189@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net Signed-off-by: Jakub Kicinski --- drivers/net/hyperv/netvsc.c | 17 ++++++++--------- drivers/net/hyperv/rndis_filter.c | 23 ++++++++++++++++------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 720104661d7f24..60a4629fe6ba7a 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1812,6 +1812,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, /* Enable NAPI handler before init callbacks */ netif_napi_add(ndev, &net_device->chan_table[0].napi, netvsc_poll); + napi_enable(&net_device->chan_table[0].napi); + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, + &net_device->chan_table[0].napi); + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, + &net_device->chan_table[0].napi); /* Open the channel */ device->channel->next_request_id_callback = vmbus_next_request_id; @@ -1831,12 +1836,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, /* Channel is opened */ netdev_dbg(ndev, "hv_netvsc channel opened successfully\n"); - napi_enable(&net_device->chan_table[0].napi); - netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, - &net_device->chan_table[0].napi); - netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, - &net_device->chan_table[0].napi); - /* Connect with the NetVsp */ ret = netvsc_connect_vsp(device, net_device, device_info); if (ret != 0) { @@ -1854,14 +1853,14 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, close: RCU_INIT_POINTER(net_device_ctx->nvdev, NULL); - netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, NULL); - netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, NULL); - napi_disable(&net_device->chan_table[0].napi); /* Now, we can close the channel safely */ vmbus_close(device->channel); cleanup: + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, NULL); + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, NULL); + napi_disable(&net_device->chan_table[0].napi); netif_napi_del(&net_device->chan_table[0].napi); cleanup2: diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 9e73959e61ee0b..c35f9685b6bf04 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1252,17 +1252,26 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) new_sc->rqstor_size = netvsc_rqstor_size(netvsc_ring_bytes); new_sc->max_pkt_size = NETVSC_MAX_PKT_SIZE; + /* Enable napi before opening the vmbus channel to avoid races + * as the host placing data on the host->guest ring may be left + * out if napi was not enabled. + */ + napi_enable(&nvchan->napi); + netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_RX, + &nvchan->napi); + netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_TX, + &nvchan->napi); + ret = vmbus_open(new_sc, netvsc_ring_bytes, netvsc_ring_bytes, NULL, 0, netvsc_channel_cb, nvchan); - if (ret == 0) { - napi_enable(&nvchan->napi); - netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_RX, - &nvchan->napi); - netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_TX, - &nvchan->napi); - } else { + if (ret != 0) { netdev_notice(ndev, "sub channel open failed: %d\n", ret); + netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_TX, + NULL); + netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_RX, + NULL); + napi_disable(&nvchan->napi); } if (atomic_inc_return(&nvscdev->open_chn) == nvscdev->num_chn) From 2c3ca8cc55a3afc7a4fa99ed8f5f5d05dd2e65b3 Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Wed, 27 Aug 2025 11:29:02 +0800 Subject: [PATCH 0682/1292] ALSA: usb-audio: move mixer_quirks' min_mute into common quirk We have found more and more devices that have the same problem, that the mixer's minimum value is muted. Accroding to pipewire's MR[1] and Arch Linux wiki[2], this should be a very common problem in USB audio devices. Move the quirk into common quirk,as a preparation of more devices' quirk's patch coming on the road[3]. 1. https://gitlab.freedesktop.org/pipewire/pipewire/-/merge_requests/2514 2. https://wiki.archlinux.org/index.php?title=PipeWire&oldid=804138#No_sound_from_USB_DAC_until_30%_volume 3. On the road, in the physical sense. We have been buying ton of these devices for testing the problem. Tested-by: Guoli An Signed-off-by: Cryolitia PukNgae Link: https://patch.msgid.link/20250827-sound-quirk-min-mute-v1-1-4717aa8a4f6a@uniontech.com Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 10 +++------- sound/usb/quirks.c | 12 ++++++++++-- sound/usb/usbaudio.h | 4 ++++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 6b47b3145d2cfd..3df537fdb9f1c7 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -4608,16 +4608,12 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, if (unitid == 7 && cval->control == UAC_FU_VOLUME) snd_dragonfly_quirk_db_scale(mixer, cval, kctl); break; + } + /* lowest playback value is muted on some devices */ - case USB_ID(0x0572, 0x1b09): /* Conexant Systems (Rockwell), Inc. */ - case USB_ID(0x0d8c, 0x000c): /* C-Media */ - case USB_ID(0x0d8c, 0x0014): /* C-Media */ - case USB_ID(0x19f7, 0x0003): /* RODE NT-USB */ - case USB_ID(0x2d99, 0x0026): /* HECATE G2 GAMING HEADSET */ + if (mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_MIN_MUTE) if (strstr(kctl->id.name, "Playback")) cval->min_mute = 1; - break; - } /* ALSA-ify some Plantronics headset control names */ if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f && diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index e75b0b1df6eb21..8bc1e247cdf1af 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2199,6 +2199,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_SET_IFACE_FIRST), DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x0572, 0x1b09, /* Conexant Systems (Rockwell), Inc. */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x05a3, 0x9420, /* ELP HD USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x05a7, 0x1020, /* Bose Companion 5 */ @@ -2245,8 +2247,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0c45, 0x636b, /* Microdia JP001 USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), - DEVICE_FLG(0x0d8c, 0x0014, /* USB Audio Device */ - QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0d8c, 0x000c, /* C-Media */ + QUIRK_FLAG_MIXER_MIN_MUTE), + DEVICE_FLG(0x0d8c, 0x0014, /* C-Media */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ QUIRK_FLAG_FIXED_RATE), DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */ @@ -2293,6 +2297,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), DEVICE_FLG(0x1901, 0x0191, /* GE B850V3 CP2114 audio interface */ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x19f7, 0x0003, /* RODE NT-USB */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1bcf, 0x2281, /* HD Webcam */ @@ -2353,6 +2359,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x2d95, 0x8021, /* VIVO USB-C-XE710 HEADSET */ QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x2d99, 0x0026, /* HECATE G2 GAMING HEADSET */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x2fc6, 0xf0b7, /* iBasso DC07 Pro */ QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 158ec053dc44dd..1ef4d39978df36 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -196,6 +196,9 @@ extern bool snd_usb_skip_validation; * for the given endpoint. * QUIRK_FLAG_MIC_RES_16 and QUIRK_FLAG_MIC_RES_384 * Set the fixed resolution for Mic Capture Volume (mostly for webcams) + * QUIRK_FLAG_MIXER_MIN_MUTE + * Set minimum volume control value as mute for devices where the lowest + * playback value represents muted state instead of minimum audible volume */ #define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0) @@ -222,5 +225,6 @@ extern bool snd_usb_skip_validation; #define QUIRK_FLAG_FIXED_RATE (1U << 21) #define QUIRK_FLAG_MIC_RES_16 (1U << 22) #define QUIRK_FLAG_MIC_RES_384 (1U << 23) +#define QUIRK_FLAG_MIXER_MIN_MUTE (1U << 24) #endif /* __USBAUDIO_H */ From d2de0f8b5a8266eec4611d6b3f580e49d9bfd46c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:06:13 +0200 Subject: [PATCH 0683/1292] ALSA: pcm: oss: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Link: https://patch.msgid.link/20250827080618.7682-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 4ecb17bd5436e7..a82dd155e1d3a6 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2002,9 +2002,8 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig static int snd_pcm_oss_nonblock(struct file * file) { - spin_lock(&file->f_lock); + guard(spinlock)(&file->f_lock); file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); return 0; } From fcf8239ad6a5de54fa7ce18e464c6b5951b982cb Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Wed, 20 Aug 2025 11:58:57 +0200 Subject: [PATCH 0684/1292] x86/microcode/AMD: Handle the case of no BIOS microcode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Machines can be shipped without any microcode in the BIOS. Which means, the microcode patch revision is 0. Handle that gracefully. Fixes: 94838d230a6c ("x86/microcode/AMD: Use the family,model,stepping encoded in the patch ID") Reported-by: VĆ­tek VĆ”vra Signed-off-by: Borislav Petkov (AMD) Cc: --- arch/x86/kernel/cpu/microcode/amd.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 097e39327942e7..514f63340880fd 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -171,8 +171,28 @@ static int cmp_id(const void *key, const void *elem) return 1; } +static u32 cpuid_to_ucode_rev(unsigned int val) +{ + union zen_patch_rev p = {}; + union cpuid_1_eax c; + + c.full = val; + + p.stepping = c.stepping; + p.model = c.model; + p.ext_model = c.ext_model; + p.ext_fam = c.ext_fam; + + return p.ucode_rev; +} + static bool need_sha_check(u32 cur_rev) { + if (!cur_rev) { + cur_rev = cpuid_to_ucode_rev(bsp_cpuid_1_eax); + pr_info_once("No current revision, generating the lowest one: 0x%x\n", cur_rev); + } + switch (cur_rev >> 8) { case 0x80012: return cur_rev <= 0x800126f; break; case 0x80082: return cur_rev <= 0x800820f; break; @@ -749,8 +769,6 @@ static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u16 equi n.equiv_cpu = equiv_cpu; n.patch_id = uci->cpu_sig.rev; - WARN_ON_ONCE(!n.patch_id); - list_for_each_entry(p, µcode_cache, plist) if (patch_cpus_equivalent(p, &n, false)) return p; From 87b07a1fbc6b5c23d3b3584ab4288bc9106d3274 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 15 Jul 2025 15:33:25 -0700 Subject: [PATCH 0685/1292] wifi: mt76: mt7996: Initialize hdr before passing to skb_put_data() A new warning in clang [1] points out a couple of places where a hdr variable is not initialized then passed along to skb_put_data(). drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:1894:21: warning: variable 'hdr' is uninitialized when passed as a const pointer argument here [-Wuninitialized-const-pointer] 1894 | skb_put_data(skb, &hdr, sizeof(hdr)); | ^~~ drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:3386:21: warning: variable 'hdr' is uninitialized when passed as a const pointer argument here [-Wuninitialized-const-pointer] 3386 | skb_put_data(skb, &hdr, sizeof(hdr)); | ^~~ Zero initialize these headers as done in other places in the driver when there is nothing stored in the header. Cc: stable@vger.kernel.org Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Link: https://github.com/llvm/llvm-project/commit/00dacf8c22f065cb52efb14cd091d441f19b319e [1] Closes: https://github.com/ClangBuiltLinux/linux/issues/2104 Signed-off-by: Nathan Chancellor Link: https://patch.msgid.link/20250715-mt7996-fix-uninit-const-pointer-v1-1-b5d8d11d7b78@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 3593fd40c51b6c..fe1b34386de232 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1879,8 +1879,8 @@ mt7996_mcu_get_mmps_mode(enum ieee80211_smps_mode smps) int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version) { + struct uni_header hdr = {}; struct ra_fixed_rate *req; - struct uni_header hdr; struct sk_buff *skb; struct tlv *tlv; int len; @@ -3372,7 +3372,7 @@ int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans) { struct { u8 __rsv[4]; - } __packed hdr; + } __packed hdr = {}; struct hdr_trans_blacklist *req_blacklist; struct hdr_trans_en *req_en; struct sk_buff *skb; From 87f38519d27a514c9909f84b8f1334125df9778e Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Wed, 16 Jul 2025 18:54:01 +0200 Subject: [PATCH 0686/1292] wifi: mt76: mt7921: don't disconnect when CSA to DFS chan When station mode, don't disconnect when we get channel switch from AP to DFS channel. Most APs send CSA request after pass background CAC. In other case we should disconnect after detect beacon miss. Without patch when we get CSA to DFS channel get: "kernel: wlo1: preparing for channel switch failed, disconnecting" Fixes: 8aa2f59260eb ("wifi: mt76: mt7921: introduce CSA support") Signed-off-by: Janusz Dziedzic Link: https://patch.msgid.link/20250716165443.28354-1-janusz.dziedzic@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 40954e64c7fccc..5881040ac19527 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1459,11 +1459,8 @@ static int mt7921_pre_channel_switch(struct ieee80211_hw *hw, if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) return -EOPNOTSUPP; - /* Avoid beacon loss due to the CAC(Channel Availability Check) time - * of the AP. - */ if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef, - IEEE80211_CHAN_RADAR)) + IEEE80211_CHAN_DISABLED)) return -EOPNOTSUPP; return 0; From 9f15701370ec15fbf1f6a1cbbf584b0018d036b5 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Sun, 27 Jul 2025 07:04:13 -0700 Subject: [PATCH 0687/1292] wifi: mt76: mt7925: fix locking in mt7925_change_vif_links() &dev->mt76.mutex lock is taken using mt792x_mutex_acquire(dev) but not released in one of the error paths, add the unlock to fix it. Fixes: 5cd0bd815c8a ("wifi: mt76: mt7925: fix NULL deref check in mt7925_change_vif_links") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202503031055.3ZRqxhAl-lkp@intel.com/ Signed-off-by: Harshit Mogalapalli Link: https://patch.msgid.link/20250727140416.1153406-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index a8d25b7d47d045..10390930751836 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -2069,8 +2069,10 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, GFP_KERNEL); mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL); - if (!mconf || !mlink) + if (!mconf || !mlink) { + mt792x_mutex_release(dev); return -ENOMEM; + } } mconfs[link_id] = mconf; From 55424e7b9eeb141d9c8d8a8740ee131c28490425 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Mon, 28 Jul 2025 13:26:12 +0800 Subject: [PATCH 0688/1292] wifi: mt76: mt7925: fix the wrong bss cleanup for SAP When in SAP mode, if a STA disconnect, the SAP's BSS should not be cleared. Fixes: 0ebb60da8416 ("wifi: mt76: mt7925: adjust rm BSS flow to prevent next connection failure") Cc: stable@vger.kernel.org Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250728052612.39751-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 10390930751836..b0e053b1522739 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1191,6 +1191,9 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, struct mt792x_bss_conf *mconf; struct mt792x_link_sta *mlink; + if (vif->type == NL80211_IFTYPE_AP) + break; + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); if (!link_sta) continue; From c22769de25095c6777e8acb68a1349a3257fc955 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Mon, 18 Aug 2025 10:02:03 +0800 Subject: [PATCH 0689/1292] wifi: mt76: mt7925u: use connac3 tx aggr check in tx complete MT7925 is a connac3 device; using the connac2 helper mis-parses TXWI and breaks AMPDU/BA accounting. Use the connac3-specific helper mt7925_tx_check_aggr() instead, Cc: stable@vger.kernel.org Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Reported-by: Nick Morrow Tested-by: Nick Morrow Tested-on: Netgear A9000 USB WiFi adapter Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250818020203.992338-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 75823c9fd3a10b..b581ab9427f22b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -1449,7 +1449,7 @@ void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, sta = wcid_to_sta(wcid); if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt76_connac2_tx_check_aggr(sta, txwi); + mt7925_tx_check_aggr(sta, e->skb, wcid); skb_pull(e->skb, headroom); mt76_tx_complete_skb(mdev, e->wcid, e->skb); From dd6e89cad9951acef3723f3f21b2e892a23b371b Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Mon, 18 Aug 2025 11:02:01 +0800 Subject: [PATCH 0690/1292] wifi: mt76: mt7925: skip EHT MLD TLV on non-MLD and pass conn_state for sta_cmd Return early in mt7925_mcu_sta_eht_mld_tlv() for non-MLD vifs to avoid bogus MLD TLVs, and pass the proper connection state to sta_basic TLV. Cc: stable@vger.kernel.org Fixes: cb1353ef3473 ("wifi: mt76: mt7925: integrate *mlo_sta_cmd and *sta_cmd") Reported-by: Tal Inbar Tested-by: Tal Inbar Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250818030201.997940-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 300c863f0e3e20..cd457be26523e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1834,13 +1834,13 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb, struct tlv *tlv; u16 eml_cap; + if (!ieee80211_vif_is_mld(vif)) + return; + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld)); eht_mld = (struct sta_rec_eht_mld *)tlv; eht_mld->mld_type = 0xff; - if (!ieee80211_vif_is_mld(vif)) - return; - ext_capa = cfg80211_get_iftype_ext_capa(wiphy, ieee80211_vif_type_p2p(vif)); if (!ext_capa) @@ -1912,6 +1912,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, struct mt76_dev *dev = phy->dev; struct mt792x_bss_conf *mconf; struct sk_buff *skb; + int conn_state; mconf = mt792x_vif_to_link(mvif, info->wcid->link_id); @@ -1920,10 +1921,13 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); + conn_state = info->enable ? CONN_STATE_PORT_SECURE : + CONN_STATE_DISCONNECT; + if (info->enable && info->link_sta) { mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, info->link_sta, - info->enable, info->newly); + conn_state, info->newly); mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta); mt7925_mcu_sta_ht_tlv(skb, info->link_sta); mt7925_mcu_sta_vht_tlv(skb, info->link_sta); From 4c2334587b0a13b8f4eda1336ae657297fcd743b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Aug 2025 14:11:06 +0200 Subject: [PATCH 0691/1292] wifi: mt76: prevent non-offchannel mgmt tx during scan/roc Only put probe request packets in the offchannel queue if IEEE80211_TX_CTRL_DONT_USE_RATE_MASK is set and IEEE80211_TX_CTL_TX_OFFCHAN is unset. Fixes: 0b3be9d1d34e ("wifi: mt76: add separate tx scheduling queue for off-channel tx") Reported-by: Chad Monroe Link: https://patch.msgid.link/20250813121106.81559-2-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index e6cf16706667e7..03b042fdf997fc 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -332,6 +332,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; struct sk_buff_head *head; if (mt76_testmode_enabled(phy)) { @@ -349,7 +350,8 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); if ((info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || - (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) + ((info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK) && + ieee80211_is_probe_req(hdr->frame_control))) head = &wcid->tx_offchannel; else head = &wcid->tx_pending; From f30906c55a400a9b7fc677e3f4c614b9069bd4a8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Aug 2025 14:11:05 +0200 Subject: [PATCH 0692/1292] wifi: mt76: mt7996: disable beacons when going offchannel Avoid leaking beacons on unrelated channels during scanning/roc Fixes: c56d6edebc1f ("wifi: mt76: mt7996: use emulated hardware scan support") Reported-by: Chad Monroe Link: https://patch.msgid.link/20250813121106.81559-1-nbd@nbd.name Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mac.c | 46 +++++++++++-------- .../net/wireless/mediatek/mt76/mt7996/main.c | 5 ++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 11 +++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 1 + 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 22653449079245..a9f7e5626dcdda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1694,43 +1694,53 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state) static void mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) { - struct ieee80211_hw *hw = priv; + struct ieee80211_bss_conf *link_conf; + struct mt7996_phy *phy = priv; + struct mt7996_dev *dev = phy->dev; + unsigned int link_id; + switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: - mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf); break; default: - break; + return; + } + + for_each_vif_active_link(vif, link_conf, link_id) { + struct mt7996_vif_link *link; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link || link->phy != phy) + continue; + + mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf); } } +void mt7996_mac_update_beacons(struct mt7996_phy *phy) +{ + ieee80211_iterate_active_interfaces(phy->mt76->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7996_update_vif_beacon, phy); +} + static void mt7996_update_beacons(struct mt7996_dev *dev) { struct mt76_phy *phy2, *phy3; - ieee80211_iterate_active_interfaces(dev->mt76.hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_update_vif_beacon, dev->mt76.hw); + mt7996_mac_update_beacons(&dev->phy); phy2 = dev->mt76.phys[MT_BAND1]; - if (!phy2) - return; - - ieee80211_iterate_active_interfaces(phy2->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_update_vif_beacon, phy2->hw); + if (phy2) + mt7996_mac_update_beacons(phy2->priv); phy3 = dev->mt76.phys[MT_BAND2]; - if (!phy3) - return; - - ieee80211_iterate_active_interfaces(phy3->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_update_vif_beacon, phy3->hw); + if (phy3) + mt7996_mac_update_beacons(phy3->priv); } void mt7996_tx_token_put(struct mt7996_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 92b57bcce74924..84f731b387d20a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -516,6 +516,9 @@ int mt7996_set_channel(struct mt76_phy *mphy) struct mt7996_phy *phy = mphy->priv; int ret; + if (mphy->offchannel) + mt7996_mac_update_beacons(phy); + ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); if (ret) goto out; @@ -533,6 +536,8 @@ int mt7996_set_channel(struct mt76_phy *mphy) mt7996_mac_reset_counters(phy); phy->noise = 0; + if (!mphy->offchannel) + mt7996_mac_update_beacons(phy); out: ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index fe1b34386de232..0be03eb3cf4613 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2755,13 +2755,15 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf); + struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); + struct mt76_vif_link *mlink = link ? &link->mt76 : NULL; struct ieee80211_mutable_offsets offs; struct ieee80211_tx_info *info; struct sk_buff *skb, *rskb; struct tlv *tlv; struct bss_bcn_content_tlv *bcn; int len, extra_len = 0; + bool enabled = link_conf->enable_beacon; if (link_conf->nontransmitted) return 0; @@ -2769,13 +2771,16 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!mlink) return -EINVAL; + if (link->phy && link->phy->mt76->offchannel) + enabled = false; + rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_MAX_BSS_OFFLOAD_SIZE); if (IS_ERR(rskb)) return PTR_ERR(rskb); skb = ieee80211_beacon_get_template(hw, vif, &offs, link_conf->link_id); - if (link_conf->enable_beacon && !skb) { + if (enabled && !skb) { dev_kfree_skb(rskb); return -EINVAL; } @@ -2794,7 +2799,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, len = ALIGN(sizeof(*bcn) + MT_TXD_SIZE + extra_len, 4); tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len); bcn = (struct bss_bcn_content_tlv *)tlv; - bcn->enable = link_conf->enable_beacon; + bcn->enable = enabled; if (!bcn->enable) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 33ac16b64ef113..8509d508e1e19c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -732,6 +732,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed); +void mt7996_mac_update_beacons(struct mt7996_phy *phy); void mt7996_mac_set_coverage_class(struct mt7996_phy *phy); void mt7996_mac_work(struct work_struct *work); void mt7996_mac_reset_work(struct work_struct *work); From 4be3b46ec5190dc79cd38e3750480b2c66a791ad Mon Sep 17 00:00:00 2001 From: Chad Monroe Date: Fri, 8 Aug 2025 13:29:48 +0000 Subject: [PATCH 0693/1292] wifi: mt76: mt7996: use the correct vif link for scanning/roc restore fix which was dropped during MLO rework Fixes: f0b0b239b8f3 ("wifi: mt76: mt7996: rework mt7996_mac_write_txwi() for MLO support") Signed-off-by: Chad Monroe Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/180fffd409aa57f535a3d2c1951e41ae398ce09e.1754659732.git.chad@monroe.io Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index a9f7e5626dcdda..d6531b74be1f15 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -903,8 +903,12 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, IEEE80211_TX_CTRL_MLO_LINK); mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL; - if (mvif) - mlink = rcu_dereference(mvif->mt76.link[link_id]); + if (mvif) { + if (wcid->offchannel) + mlink = rcu_dereference(mvif->mt76.offchannel_link); + if (!mlink) + mlink = rcu_dereference(mvif->mt76.link[link_id]); + } if (mlink) { omac_idx = mlink->omac_idx; From 0300545b8a113e96ee260a7c142be846d391a620 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Aug 2025 10:53:47 +0200 Subject: [PATCH 0694/1292] wifi: mt76: mt7996: fix crash on some tx status reports When a wcid can't be found, link_sta can be stale from a previous batch. The code currently assumes that if link_sta is set, wcid is also non-zero. Fix wcid NULL pointer dereference by resetting link_sta when a wcid entry can't be found. Fixes: 62da647a2b20 ("wifi: mt76: mt7996: Add MLO support to mt7996_tx_check_aggr()") Link: https://patch.msgid.link/20250827085352.51636-1-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index d6531b74be1f15..837deb41ae1311 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1247,8 +1247,10 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); wcid = mt76_wcid_ptr(dev, idx); sta = wcid_to_sta(wcid); - if (!sta) + if (!sta) { + link_sta = NULL; goto next; + } link_sta = rcu_dereference(sta->link[wcid->link_id]); if (!link_sta) From a3c99ef88a084e1c2b99dd56bbfa7f89c9be3e92 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Aug 2025 10:53:48 +0200 Subject: [PATCH 0695/1292] wifi: mt76: do not add non-sta wcid entries to the poll list Polling and airtime reporting is valid for station entries only Link: https://patch.msgid.link/20250827085352.51636-2-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 3afe4c4cd7bbec..6b2641a9ae9a4b 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1690,7 +1690,7 @@ EXPORT_SYMBOL_GPL(mt76_wcid_cleanup); void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid) { - if (test_bit(MT76_MCU_RESET, &dev->phy.state)) + if (test_bit(MT76_MCU_RESET, &dev->phy.state) || !wcid->sta) return; spin_lock_bh(&dev->sta_poll_lock); From 4a522b01e368eec58d182ecc47d24f49a39e440d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Aug 2025 10:53:49 +0200 Subject: [PATCH 0696/1292] wifi: mt76: mt7996: add missing check for rx wcid entries Non-station wcid entries must not be passed to the rx functions. In case of the global wcid entry, it could even lead to corruption in the wcid array due to pointer being casted to struct mt7996_sta_link using container_of. Fixes: 7464b12b7d92 ("wifi: mt76: mt7996: rework mt7996_rx_get_wcid to support MLO") Link: https://patch.msgid.link/20250827085352.51636-3-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 837deb41ae1311..b3fcca9bbb9589 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -62,7 +62,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, int i; wcid = mt76_wcid_ptr(dev, idx); - if (!wcid) + if (!wcid || !wcid->sta) return NULL; if (!mt7996_band_valid(dev, band_idx)) From 065c79df595af21d6d1b27d642860faa1d938774 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Aug 2025 10:53:50 +0200 Subject: [PATCH 0697/1292] wifi: mt76: mt7915: fix list corruption after hardware restart Since stations are recreated from scratch, all lists that wcids are added to must be cleared before calling ieee80211_restart_hw. Set wcid->sta = 0 for each wcid entry in order to ensure that they are not added again before they are ready. Fixes: 8a55712d124f ("wifi: mt76: mt7915: enable full system reset support") Link: https://patch.msgid.link/20250827085352.51636-4-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 37 +++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt7915/mac.c | 12 +++--- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 6b2641a9ae9a4b..0e0d7b3bfe42d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -818,6 +818,43 @@ void mt76_free_device(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_free_device); +static void mt76_reset_phy(struct mt76_phy *phy) +{ + if (!phy) + return; + + INIT_LIST_HEAD(&phy->tx_list); +} + +void mt76_reset_device(struct mt76_dev *dev) +{ + int i; + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { + struct mt76_wcid *wcid; + + wcid = rcu_dereference(dev->wcid[i]); + if (!wcid) + continue; + + wcid->sta = 0; + mt76_wcid_cleanup(dev, wcid); + rcu_assign_pointer(dev->wcid[i], NULL); + } + rcu_read_unlock(); + + INIT_LIST_HEAD(&dev->wcid_list); + INIT_LIST_HEAD(&dev->sta_poll_list); + dev->vif_mask = 0; + memset(dev->wcid_mask, 0, sizeof(dev->wcid_mask)); + + mt76_reset_phy(&dev->phy); + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) + mt76_reset_phy(dev->phys[i]); +} +EXPORT_SYMBOL_GPL(mt76_reset_device); + struct mt76_phy *mt76_vif_phy(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8dd5c29fb75b5c..127637454c827e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1243,6 +1243,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates); void mt76_unregister_device(struct mt76_dev *dev); void mt76_free_device(struct mt76_dev *dev); +void mt76_reset_device(struct mt76_dev *dev); void mt76_unregister_phy(struct mt76_phy *phy); struct mt76_phy *mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 6639976afcee6a..1c0d310146d63b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1460,17 +1460,15 @@ mt7915_mac_full_reset(struct mt7915_dev *dev) if (i == 10) dev_err(dev->mt76.dev, "chip full reset failed\n"); - spin_lock_bh(&dev->mt76.sta_poll_lock); - while (!list_empty(&dev->mt76.sta_poll_list)) - list_del_init(dev->mt76.sta_poll_list.next); - spin_unlock_bh(&dev->mt76.sta_poll_lock); - - memset(dev->mt76.wcid_mask, 0, sizeof(dev->mt76.wcid_mask)); - dev->mt76.vif_mask = 0; dev->phy.omac_mask = 0; if (phy2) phy2->omac_mask = 0; + mt76_reset_device(&dev->mt76); + + INIT_LIST_HEAD(&dev->sta_rc_list); + INIT_LIST_HEAD(&dev->twt_list); + i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); dev->mt76.global_wcid.idx = i; dev->recovery.hw_full_reset = false; From bdeac7815629c1a32b8784922368742e183747ea Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Aug 2025 10:53:51 +0200 Subject: [PATCH 0698/1292] wifi: mt76: free pending offchannel tx frames on wcid cleanup Avoid leaking them or keeping the wcid on the tx list Fixes: 0b3be9d1d34e ("wifi: mt76: add separate tx scheduling queue for off-channel tx") Link: https://patch.msgid.link/20250827085352.51636-5-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 0e0d7b3bfe42d8..59adf33126170c 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1716,6 +1716,10 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) skb_queue_splice_tail_init(&wcid->tx_pending, &list); spin_unlock(&wcid->tx_pending.lock); + spin_lock(&wcid->tx_offchannel.lock); + skb_queue_splice_tail_init(&wcid->tx_offchannel, &list); + spin_unlock(&wcid->tx_offchannel.lock); + spin_unlock_bh(&phy->tx_lock); while ((skb = __skb_dequeue(&list)) != NULL) { From 49fba87205bec14a0f6bd997635bf3968408161e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Aug 2025 10:53:52 +0200 Subject: [PATCH 0699/1292] wifi: mt76: fix linked list corruption Never leave scheduled wcid entries on the temporary on-stack list Fixes: 0b3be9d1d34e ("wifi: mt76: add separate tx scheduling queue for off-channel tx") Link: https://patch.msgid.link/20250827085352.51636-6-nbd@nbd.name Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 03b042fdf997fc..8ab5840fee57f9 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -646,6 +646,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, static void mt76_txq_schedule_pending(struct mt76_phy *phy) { LIST_HEAD(tx_list); + int ret = 0; if (list_empty(&phy->tx_list)) return; @@ -657,13 +658,13 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy) list_splice_init(&phy->tx_list, &tx_list); while (!list_empty(&tx_list)) { struct mt76_wcid *wcid; - int ret; wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list); list_del_init(&wcid->tx_list); spin_unlock(&phy->tx_lock); - ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel); + if (ret >= 0) + ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel); if (ret >= 0 && !phy->offchannel) ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending); spin_lock(&phy->tx_lock); @@ -672,9 +673,6 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy) !skb_queue_empty(&wcid->tx_offchannel) && list_empty(&wcid->tx_list)) list_add_tail(&wcid->tx_list, &phy->tx_list); - - if (ret < 0) - break; } spin_unlock(&phy->tx_lock); From c2415c407a2cde01290d52ce2a1f81b0616379a3 Mon Sep 17 00:00:00 2001 From: K Prateek Nayak Date: Mon, 25 Aug 2025 07:57:29 +0000 Subject: [PATCH 0700/1292] x86/cpu/topology: Use initial APIC ID from XTOPOLOGY leaf on AMD/HYGON Prior to the topology parsing rewrite and the switchover to the new parsing logic for AMD processors in c749ce393b8f ("x86/cpu: Use common topology code for AMD"), the initial_apicid on these platforms was: - First initialized to the LocalApicId from CPUID leaf 0x1 EBX[31:24]. - Then overwritten by the ExtendedLocalApicId in CPUID leaf 0xb EDX[31:0] on processors that supported topoext. With the new parsing flow introduced in f7fb3b2dd92c ("x86/cpu: Provide an AMD/HYGON specific topology parser"), parse_8000_001e() now unconditionally overwrites the initial_apicid already parsed during cpu_parse_topology_ext(). Although this has not been a problem on baremetal platforms, on virtualized AMD guests that feature more than 255 cores, QEMU zeros out the CPUID leaf 0x8000001e on CPUs with CoreID > 255 to prevent collision of these IDs in EBX[7:0] which can only represent a maximum of 255 cores [1]. This results in the following FW_BUG being logged when booting a guest with more than 255 cores: [Firmware Bug]: CPU 512: APIC ID mismatch. CPUID: 0x0000 APIC: 0x0200 AMD64 Architecture Programmer's Manual Volume 2: System Programming Pub. 24593 Rev. 3.42 [2] Section 16.12 "x2APIC_ID" mentions the Extended Enumeration leaf 0xb (Fn0000_000B_EDX[31:0])(which was later superseded by the extended leaf 0x80000026) provides the full x2APIC ID under all circumstances unlike the one reported by CPUID leaf 0x8000001e EAX which depends on the mode in which APIC is configured. Rely on the APIC ID parsed during cpu_parse_topology_ext() from CPUID leaf 0x80000026 or 0xb and only use the APIC ID from leaf 0x8000001e if cpu_parse_topology_ext() failed (has_topoext is false). On platforms that support the 0xb leaf (Zen2 or later, AMD guests on QEMU) or the extended leaf 0x80000026 (Zen4 or later), the initial_apicid is now set to the value parsed from EDX[31:0]. On older AMD/Hygon platforms that do not support the 0xb leaf but support the TOPOEXT extension (families 0x15, 0x16, 0x17[Zen1], and Hygon), retain current behavior where the initial_apicid is set using the 0x8000001e leaf. Issue debugged by Naveen N Rao (AMD) and Sairaj Kodilkar . [ bp: Massage commit message. ] Fixes: c749ce393b8f ("x86/cpu: Use common topology code for AMD") Suggested-by: Thomas Gleixner Signed-off-by: K Prateek Nayak Signed-off-by: Borislav Petkov (AMD) Tested-by: Naveen N Rao (AMD) Cc: stable@vger.kernel.org Link: https://github.com/qemu/qemu/commit/35ac5dfbcaa4b [1] Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 [2] Link: https://lore.kernel.org/20250825075732.10694-2-kprateek.nayak@amd.com --- arch/x86/kernel/cpu/topology_amd.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c index 843b1655ab45df..827dd0dbb6e9d2 100644 --- a/arch/x86/kernel/cpu/topology_amd.c +++ b/arch/x86/kernel/cpu/topology_amd.c @@ -81,20 +81,25 @@ static bool parse_8000_001e(struct topo_scan *tscan, bool has_topoext) cpuid_leaf(0x8000001e, &leaf); - tscan->c->topo.initial_apicid = leaf.ext_apic_id; - /* - * If leaf 0xb is available, then the domain shifts are set - * already and nothing to do here. Only valid for family >= 0x17. + * If leaf 0xb/0x26 is available, then the APIC ID and the domain + * shifts are set already. */ - if (!has_topoext && tscan->c->x86 >= 0x17) { + if (!has_topoext) { + tscan->c->topo.initial_apicid = leaf.ext_apic_id; + /* - * Leaf 0x80000008 set the CORE domain shift already. - * Update the SMT domain, but do not propagate it. + * Leaf 0x8000008 sets the CORE domain shift but not the + * SMT domain shift. On CPUs with family >= 0x17, there + * might be hyperthreads. */ - unsigned int nthreads = leaf.core_nthreads + 1; + if (tscan->c->x86 >= 0x17) { + /* Update the SMT domain, but do not propagate it. */ + unsigned int nthreads = leaf.core_nthreads + 1; - topology_update_dom(tscan, TOPO_SMT_DOMAIN, get_count_order(nthreads), nthreads); + topology_update_dom(tscan, TOPO_SMT_DOMAIN, + get_count_order(nthreads), nthreads); + } } store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id); From 479a54ab92087318514c82428a87af2d7af1a576 Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Fri, 22 Aug 2025 11:52:19 +0800 Subject: [PATCH 0701/1292] netfilter: br_netfilter: do not check confirmed bit in br_nf_local_in() after confirm When send a broadcast packet to a tap device, which was added to a bridge, br_nf_local_in() is called to confirm the conntrack. If another conntrack with the same hash value is added to the hash table, which can be triggered by a normal packet to a non-bridge device, the below warning may happen. ------------[ cut here ]------------ WARNING: CPU: 1 PID: 96 at net/bridge/br_netfilter_hooks.c:632 br_nf_local_in+0x168/0x200 CPU: 1 UID: 0 PID: 96 Comm: tap_send Not tainted 6.17.0-rc2-dirty #44 PREEMPT(voluntary) RIP: 0010:br_nf_local_in+0x168/0x200 Call Trace: nf_hook_slow+0x3e/0xf0 br_pass_frame_up+0x103/0x180 br_handle_frame_finish+0x2de/0x5b0 br_nf_hook_thresh+0xc0/0x120 br_nf_pre_routing_finish+0x168/0x3a0 br_nf_pre_routing+0x237/0x5e0 br_handle_frame+0x1ec/0x3c0 __netif_receive_skb_core+0x225/0x1210 __netif_receive_skb_one_core+0x37/0xa0 netif_receive_skb+0x36/0x160 tun_get_user+0xa54/0x10c0 tun_chr_write_iter+0x65/0xb0 vfs_write+0x305/0x410 ksys_write+0x60/0xd0 do_syscall_64+0xa4/0x260 entry_SYSCALL_64_after_hwframe+0x77/0x7f ---[ end trace 0000000000000000 ]--- To solve the hash conflict, nf_ct_resolve_clash() try to merge the conntracks, and update skb->_nfct. However, br_nf_local_in() still use the old ct from local variable 'nfct' after confirm(), which leads to this warning. If confirm() does not insert the conntrack entry and return NF_DROP, the warning may also occur. There is no need to reserve the WARN_ON_ONCE, just remove it. Link: https://lore.kernel.org/netdev/20250820043329.2902014-1-wangliang74@huawei.com/ Fixes: 62e7151ae3eb ("netfilter: bridge: confirm multicast packets before passing them up the stack") Suggested-by: Florian Westphal Signed-off-by: Wang Liang Signed-off-by: Florian Westphal --- net/bridge/br_netfilter_hooks.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 94cbe967d1c163..083e2fe96441d4 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -626,9 +626,6 @@ static unsigned int br_nf_local_in(void *priv, break; } - ct = container_of(nfct, struct nf_conn, ct_general); - WARN_ON_ONCE(!nf_ct_is_confirmed(ct)); - return ret; } #endif From 54416fd76770bd04fc3c501810e8d673550bab26 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 18 Aug 2025 13:22:20 +0200 Subject: [PATCH 0702/1292] netfilter: conntrack: helper: Replace -EEXIST by -EBUSY The helper registration return value is passed-through by module_init callbacks which modprobe confuses with the harmless -EEXIST returned when trying to load an already loaded module. Make sure modprobe fails so users notice their helper has not been registered and won't work. Suggested-by: Christophe Leroy Fixes: 12f7a505331e ("netfilter: add user-space connection tracking helper infrastructure") Signed-off-by: Phil Sutter Signed-off-by: Florian Westphal --- net/netfilter/nf_conntrack_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 4ed5878cb25b16..ceb48c3ca0a439 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -368,7 +368,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) (cur->tuple.src.l3num == NFPROTO_UNSPEC || cur->tuple.src.l3num == me->tuple.src.l3num) && cur->tuple.dst.protonum == me->tuple.dst.protonum) { - ret = -EEXIST; + ret = -EBUSY; goto out; } } @@ -379,7 +379,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) { if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple, &mask)) { - ret = -EEXIST; + ret = -EBUSY; goto out; } } From f600bddbcf79acd13d4a0d93aed4ee2fe29f927d Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Wed, 27 Aug 2025 12:34:03 +0800 Subject: [PATCH 0703/1292] ALSA: hda/tas2781: Fix EFI name for calibration beginning with 1 instead of 0 A bug reported by one of my customers that EFI name beginning with 0 instead of 1. Fixes: 4fe238513407 ("ALSA: hda/tas2781: Move and unified the calibrated-data getting function for SPI and I2C into the tas2781_hda lib") Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20250827043404.644-1-shenghao-ding@ti.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index e34b17f0c9b9e2..7143926c2c30f3 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -327,8 +327,8 @@ static int tas2563_save_calibration(struct tas2781_hda *h) data[offset] = i; offset++; for (j = 0; j < TASDEV_CALIB_N; ++j) { - ret = snprintf(var8, sizeof(var8), vars[j], i); - + /* EFI name for calibration started with 1, not 0 */ + ret = snprintf(var8, sizeof(var8), vars[j], i + 1); if (ret < 0 || ret >= sizeof(var8) - 1) { dev_err(p->dev, "%s: Read %s failed\n", __func__, var8); From c64eff368ac676e8540344d27a3de47e0ad90d21 Mon Sep 17 00:00:00 2001 From: Qingyue Zhang Date: Wed, 27 Aug 2025 19:43:39 +0800 Subject: [PATCH 0704/1292] io_uring/kbuf: fix signedness in this_len calculation When importing and using buffers, buf->len is considered unsigned. However, buf->len is converted to signed int when committing. This can lead to unexpected behavior if the buffer is large enough to be interpreted as a negative value. Make min_t calculation unsigned. Fixes: ae98dbf43d75 ("io_uring/kbuf: add support for incremental buffer consumption") Co-developed-by: Suoxing Zhang Signed-off-by: Suoxing Zhang Signed-off-by: Qingyue Zhang Link: https://lore.kernel.org/r/tencent_4DBB3674C0419BEC2C0C525949DA410CA307@qq.com Signed-off-by: Jens Axboe --- io_uring/kbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index f2d2cc319faac5..81a13338dfab3e 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -39,7 +39,7 @@ static bool io_kbuf_inc_commit(struct io_buffer_list *bl, int len) u32 this_len; buf = io_ring_head_to_buf(bl->buf_ring, bl->head, bl->mask); - this_len = min_t(int, len, buf->len); + this_len = min_t(u32, len, buf->len); buf->len -= this_len; if (buf->len) { buf->addr += this_len; From dcb34659028f856c423a29ef9b4e2571d203444d Mon Sep 17 00:00:00 2001 From: Takamitsu Iwai Date: Sat, 23 Aug 2025 17:58:55 +0900 Subject: [PATCH 0705/1292] net: rose: split remove and free operations in rose_remove_neigh() The current rose_remove_neigh() performs two distinct operations: 1. Removes rose_neigh from rose_neigh_list 2. Frees the rose_neigh structure Split these operations into separate functions to improve maintainability and prepare for upcoming refcount_t conversion. The timer cleanup remains in rose_remove_neigh() because free operations can be called from timer itself. This patch introduce rose_neigh_put() to handle the freeing of rose_neigh structures and modify rose_remove_neigh() to handle removal only. Signed-off-by: Takamitsu Iwai Reviewed-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250823085857.47674-2-takamitz@amazon.co.jp Signed-off-by: Jakub Kicinski --- include/net/rose.h | 8 ++++++++ net/rose/rose_route.c | 15 ++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/net/rose.h b/include/net/rose.h index 23267b4efcfa32..174b4f605d849b 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -151,6 +151,14 @@ struct rose_sock { #define rose_sk(sk) ((struct rose_sock *)(sk)) +static inline void rose_neigh_put(struct rose_neigh *rose_neigh) +{ + if (rose_neigh->ax25) + ax25_cb_put(rose_neigh->ax25); + kfree(rose_neigh->digipeat); + kfree(rose_neigh); +} + /* af_rose.c */ extern ax25_address rose_callsign; extern int sysctl_rose_restart_request_timeout; diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index b72bf8a08d489f..0c44c416f48539 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -234,20 +234,12 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) if ((s = rose_neigh_list) == rose_neigh) { rose_neigh_list = rose_neigh->next; - if (rose_neigh->ax25) - ax25_cb_put(rose_neigh->ax25); - kfree(rose_neigh->digipeat); - kfree(rose_neigh); return; } while (s != NULL && s->next != NULL) { if (s->next == rose_neigh) { s->next = rose_neigh->next; - if (rose_neigh->ax25) - ax25_cb_put(rose_neigh->ax25); - kfree(rose_neigh->digipeat); - kfree(rose_neigh); return; } @@ -331,8 +323,10 @@ static int rose_del_node(struct rose_route_struct *rose_route, if (rose_node->neighbour[i] == rose_neigh) { rose_neigh->count--; - if (rose_neigh->count == 0 && rose_neigh->use == 0) + if (rose_neigh->count == 0 && rose_neigh->use == 0) { rose_remove_neigh(rose_neigh); + rose_neigh_put(rose_neigh); + } rose_node->count--; @@ -513,6 +507,7 @@ void rose_rt_device_down(struct net_device *dev) } rose_remove_neigh(s); + rose_neigh_put(s); } spin_unlock_bh(&rose_neigh_list_lock); spin_unlock_bh(&rose_node_list_lock); @@ -569,6 +564,7 @@ static int rose_clear_routes(void) if (s->use == 0 && !s->loopback) { s->count = 0; rose_remove_neigh(s); + rose_neigh_put(s); } } @@ -1301,6 +1297,7 @@ void __exit rose_rt_free(void) rose_neigh = rose_neigh->next; rose_remove_neigh(s); + rose_neigh_put(s); } while (rose_node != NULL) { From d860d1faa6b2ce3becfdb8b0c2b048ad31800061 Mon Sep 17 00:00:00 2001 From: Takamitsu Iwai Date: Sat, 23 Aug 2025 17:58:56 +0900 Subject: [PATCH 0706/1292] net: rose: convert 'use' field to refcount_t The 'use' field in struct rose_neigh is used as a reference counter but lacks atomicity. This can lead to race conditions where a rose_neigh structure is freed while still being referenced by other code paths. For example, when rose_neigh->use becomes zero during an ioctl operation via rose_rt_ioctl(), the structure may be removed while its timer is still active, potentially causing use-after-free issues. This patch changes the type of 'use' from unsigned short to refcount_t and updates all code paths to use rose_neigh_hold() and rose_neigh_put() which operate reference counts atomically. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Takamitsu Iwai Reviewed-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250823085857.47674-3-takamitz@amazon.co.jp Signed-off-by: Jakub Kicinski --- include/net/rose.h | 18 +++++++++++++----- net/rose/af_rose.c | 13 +++++++------ net/rose/rose_in.c | 12 ++++++------ net/rose/rose_route.c | 33 ++++++++++++++++++--------------- net/rose/rose_timer.c | 2 +- 5 files changed, 45 insertions(+), 33 deletions(-) diff --git a/include/net/rose.h b/include/net/rose.h index 174b4f605d849b..2b5491bbf39ab5 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -8,6 +8,7 @@ #ifndef _ROSE_H #define _ROSE_H +#include #include #include #include @@ -96,7 +97,7 @@ struct rose_neigh { ax25_cb *ax25; struct net_device *dev; unsigned short count; - unsigned short use; + refcount_t use; unsigned int number; char restarted; char dce_mode; @@ -151,12 +152,19 @@ struct rose_sock { #define rose_sk(sk) ((struct rose_sock *)(sk)) +static inline void rose_neigh_hold(struct rose_neigh *rose_neigh) +{ + refcount_inc(&rose_neigh->use); +} + static inline void rose_neigh_put(struct rose_neigh *rose_neigh) { - if (rose_neigh->ax25) - ax25_cb_put(rose_neigh->ax25); - kfree(rose_neigh->digipeat); - kfree(rose_neigh); + if (refcount_dec_and_test(&rose_neigh->use)) { + if (rose_neigh->ax25) + ax25_cb_put(rose_neigh->ax25); + kfree(rose_neigh->digipeat); + kfree(rose_neigh); + } } /* af_rose.c */ diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 4e72b636a46a5f..543f9e8ebb6937 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -170,7 +170,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh) if (rose->neighbour == neigh) { rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); rose->neighbour = NULL; } } @@ -212,7 +212,7 @@ static void rose_kill_by_device(struct net_device *dev) if (rose->device == dev) { rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); if (rose->neighbour) - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); netdev_put(rose->device, &rose->dev_tracker); rose->device = NULL; } @@ -655,7 +655,7 @@ static int rose_release(struct socket *sock) break; case ROSE_STATE_2: - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); release_sock(sk); rose_disconnect(sk, 0, -1, -1); lock_sock(sk); @@ -823,6 +823,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le rose->lci = rose_new_lci(rose->neighbour); if (!rose->lci) { err = -ENETUNREACH; + rose_neigh_put(rose->neighbour); goto out_release; } @@ -834,12 +835,14 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le dev = rose_dev_first(); if (!dev) { err = -ENETUNREACH; + rose_neigh_put(rose->neighbour); goto out_release; } user = ax25_findbyuid(current_euid()); if (!user) { err = -EINVAL; + rose_neigh_put(rose->neighbour); dev_put(dev); goto out_release; } @@ -874,8 +877,6 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le rose->state = ROSE_STATE_1; - rose->neighbour->use++; - rose_write_internal(sk, ROSE_CALL_REQUEST); rose_start_heartbeat(sk); rose_start_t1timer(sk); @@ -1077,7 +1078,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros GFP_ATOMIC); make_rose->facilities = facilities; - make_rose->neighbour->use++; + rose_neigh_hold(make_rose->neighbour); if (rose_sk(sk)->defer) { make_rose->state = ROSE_STATE_5; diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c index 3e99181e759f98..0276b393f0e530 100644 --- a/net/rose/rose_in.c +++ b/net/rose/rose_in.c @@ -56,7 +56,7 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety case ROSE_CLEAR_REQUEST: rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); break; default: @@ -79,12 +79,12 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety case ROSE_CLEAR_REQUEST: rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); break; case ROSE_CLEAR_CONFIRMATION: rose_disconnect(sk, 0, -1, -1); - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); break; default: @@ -121,7 +121,7 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety case ROSE_CLEAR_REQUEST: rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); break; case ROSE_RR: @@ -234,7 +234,7 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety case ROSE_CLEAR_REQUEST: rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); break; default: @@ -254,7 +254,7 @@ static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int framety if (frametype == ROSE_CLEAR_REQUEST) { rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); rose_disconnect(sk, 0, skb->data[3], skb->data[4]); - rose_sk(sk)->neighbour->use--; + rose_neigh_put(rose_sk(sk)->neighbour); } return 0; diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 0c44c416f48539..8efb9033c057c3 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -93,11 +93,11 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, rose_neigh->ax25 = NULL; rose_neigh->dev = dev; rose_neigh->count = 0; - rose_neigh->use = 0; rose_neigh->dce_mode = 0; rose_neigh->loopback = 0; rose_neigh->number = rose_neigh_no++; rose_neigh->restarted = 0; + refcount_set(&rose_neigh->use, 1); skb_queue_head_init(&rose_neigh->queue); @@ -255,10 +255,10 @@ static void rose_remove_route(struct rose_route *rose_route) struct rose_route *s; if (rose_route->neigh1 != NULL) - rose_route->neigh1->use--; + rose_neigh_put(rose_route->neigh1); if (rose_route->neigh2 != NULL) - rose_route->neigh2->use--; + rose_neigh_put(rose_route->neigh2); if ((s = rose_route_list) == rose_route) { rose_route_list = rose_route->next; @@ -323,7 +323,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, if (rose_node->neighbour[i] == rose_neigh) { rose_neigh->count--; - if (rose_neigh->count == 0 && rose_neigh->use == 0) { + if (rose_neigh->count == 0) { rose_remove_neigh(rose_neigh); rose_neigh_put(rose_neigh); } @@ -375,11 +375,11 @@ void rose_add_loopback_neigh(void) sn->ax25 = NULL; sn->dev = NULL; sn->count = 0; - sn->use = 0; sn->dce_mode = 1; sn->loopback = 1; sn->number = rose_neigh_no++; sn->restarted = 1; + refcount_set(&sn->use, 1); skb_queue_head_init(&sn->queue); @@ -561,8 +561,7 @@ static int rose_clear_routes(void) s = rose_neigh; rose_neigh = rose_neigh->next; - if (s->use == 0 && !s->loopback) { - s->count = 0; + if (!s->loopback) { rose_remove_neigh(s); rose_neigh_put(s); } @@ -680,6 +679,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, for (i = 0; i < node->count; i++) { if (node->neighbour[i]->restarted) { res = node->neighbour[i]; + rose_neigh_hold(node->neighbour[i]); goto out; } } @@ -691,6 +691,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, for (i = 0; i < node->count; i++) { if (!rose_ftimer_running(node->neighbour[i])) { res = node->neighbour[i]; + rose_neigh_hold(node->neighbour[i]); goto out; } failed = 1; @@ -780,13 +781,13 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh) } if (rose_route->neigh1 == rose_neigh) { - rose_route->neigh1->use--; + rose_neigh_put(rose_route->neigh1); rose_route->neigh1 = NULL; rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0); } if (rose_route->neigh2 == rose_neigh) { - rose_route->neigh2->use--; + rose_neigh_put(rose_route->neigh2); rose_route->neigh2 = NULL; rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0); } @@ -915,7 +916,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) rose_clear_queues(sk); rose->cause = ROSE_NETWORK_CONGESTION; rose->diagnostic = 0; - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); rose->neighbour = NULL; rose->lci = 0; rose->state = ROSE_STATE_0; @@ -1040,12 +1041,12 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) if ((new_lci = rose_new_lci(new_neigh)) == 0) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71); - goto out; + goto put_neigh; } if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120); - goto out; + goto put_neigh; } rose_route->lci1 = lci; @@ -1058,8 +1059,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) rose_route->lci2 = new_lci; rose_route->neigh2 = new_neigh; - rose_route->neigh1->use++; - rose_route->neigh2->use++; + rose_neigh_hold(rose_route->neigh1); + rose_neigh_hold(rose_route->neigh2); rose_route->next = rose_route_list; rose_route_list = rose_route; @@ -1071,6 +1072,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) rose_transmit_link(skb, rose_route->neigh2); res = 1; +put_neigh: + rose_neigh_put(new_neigh); out: spin_unlock_bh(&rose_route_list_lock); spin_unlock_bh(&rose_neigh_list_lock); @@ -1186,7 +1189,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v) (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign), rose_neigh->dev ? rose_neigh->dev->name : "???", rose_neigh->count, - rose_neigh->use, + refcount_read(&rose_neigh->use) - 1, (rose_neigh->dce_mode) ? "DCE" : "DTE", (rose_neigh->restarted) ? "yes" : "no", ax25_display_timer(&rose_neigh->t0timer) / HZ, diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c index 020369c49587f1..bb60a1654d6125 100644 --- a/net/rose/rose_timer.c +++ b/net/rose/rose_timer.c @@ -180,7 +180,7 @@ static void rose_timer_expiry(struct timer_list *t) break; case ROSE_STATE_2: /* T3 */ - rose->neighbour->use--; + rose_neigh_put(rose->neighbour); rose_disconnect(sk, ETIMEDOUT, -1, -1); break; From da9c9c877597170b929a6121a68dcd3dd9a80f45 Mon Sep 17 00:00:00 2001 From: Takamitsu Iwai Date: Sat, 23 Aug 2025 17:58:57 +0900 Subject: [PATCH 0707/1292] net: rose: include node references in rose_neigh refcount Current implementation maintains two separate reference counting mechanisms: the 'count' field in struct rose_neigh tracks references from rose_node structures, while the 'use' field (now refcount_t) tracks references from rose_sock. This patch merges these two reference counting systems using 'use' field for proper reference management. Specifically, this patch adds incrementing and decrementing of rose_neigh->use when rose_neigh->count is incremented or decremented. This patch also modifies rose_rt_free(), rose_rt_device_down() and rose_clear_route() to properly release references to rose_neigh objects before freeing a rose_node through rose_remove_node(). These changes ensure rose_neigh structures are properly freed only when all references, including those from rose_node structures, are released. As a result, this resolves a slab-use-after-free issue reported by Syzbot. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+942297eecf7d2d61d1f1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=942297eecf7d2d61d1f1 Signed-off-by: Takamitsu Iwai Reviewed-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250823085857.47674-4-takamitz@amazon.co.jp Signed-off-by: Jakub Kicinski --- net/rose/rose_route.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 8efb9033c057c3..1adee1fbc2ed1d 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -178,6 +178,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, } } rose_neigh->count++; + rose_neigh_hold(rose_neigh); goto out; } @@ -187,6 +188,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, rose_node->neighbour[rose_node->count] = rose_neigh; rose_node->count++; rose_neigh->count++; + rose_neigh_hold(rose_neigh); } out: @@ -322,6 +324,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, for (i = 0; i < rose_node->count; i++) { if (rose_node->neighbour[i] == rose_neigh) { rose_neigh->count--; + rose_neigh_put(rose_neigh); if (rose_neigh->count == 0) { rose_remove_neigh(rose_neigh); @@ -430,6 +433,7 @@ int rose_add_loopback_node(const rose_address *address) rose_node_list = rose_node; rose_loopback_neigh->count++; + rose_neigh_hold(rose_loopback_neigh); out: spin_unlock_bh(&rose_node_list_lock); @@ -461,6 +465,7 @@ void rose_del_loopback_node(const rose_address *address) rose_remove_node(rose_node); rose_loopback_neigh->count--; + rose_neigh_put(rose_loopback_neigh); out: spin_unlock_bh(&rose_node_list_lock); @@ -500,6 +505,7 @@ void rose_rt_device_down(struct net_device *dev) memmove(&t->neighbour[i], &t->neighbour[i + 1], sizeof(t->neighbour[0]) * (t->count - i)); + rose_neigh_put(s); } if (t->count <= 0) @@ -543,6 +549,7 @@ static int rose_clear_routes(void) { struct rose_neigh *s, *rose_neigh; struct rose_node *t, *rose_node; + int i; spin_lock_bh(&rose_node_list_lock); spin_lock_bh(&rose_neigh_list_lock); @@ -553,8 +560,12 @@ static int rose_clear_routes(void) while (rose_node != NULL) { t = rose_node; rose_node = rose_node->next; - if (!t->loopback) + + if (!t->loopback) { + for (i = 0; i < rose_node->count; i++) + rose_neigh_put(t->neighbour[i]); rose_remove_node(t); + } } while (rose_neigh != NULL) { @@ -1189,7 +1200,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v) (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign), rose_neigh->dev ? rose_neigh->dev->name : "???", rose_neigh->count, - refcount_read(&rose_neigh->use) - 1, + refcount_read(&rose_neigh->use) - rose_neigh->count - 1, (rose_neigh->dce_mode) ? "DCE" : "DTE", (rose_neigh->restarted) ? "yes" : "no", ax25_display_timer(&rose_neigh->t0timer) / HZ, @@ -1294,6 +1305,7 @@ void __exit rose_rt_free(void) struct rose_neigh *s, *rose_neigh = rose_neigh_list; struct rose_node *t, *rose_node = rose_node_list; struct rose_route *u, *rose_route = rose_route_list; + int i; while (rose_neigh != NULL) { s = rose_neigh; @@ -1307,6 +1319,8 @@ void __exit rose_rt_free(void) t = rose_node; rose_node = rose_node->next; + for (i = 0; i < t->count; i++) + rose_neigh_put(t->neighbour[i]); rose_remove_node(t); } From 8b3641dfb6f902407495c63b9b64482b32319b66 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 19 Aug 2025 14:21:59 -0500 Subject: [PATCH 0708/1292] x86/bugs: Add attack vector controls for SSB Attack vector controls for SSB were missed in the initial attack vector series. The default mitigation for SSB requires user-space opt-in so it is only relevant for user->user attacks. Check with attack vector controls when the command is auto - i.e., no explicit user selection has been done. Fixes: 2d31d2874663 ("x86/bugs: Define attack vectors relevant for each bug") Signed-off-by: David Kaplan Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250819192200.2003074-5-david.kaplan@amd.com --- .../admin-guide/hw-vuln/attack_vector_controls.rst | 5 +---- arch/x86/kernel/cpu/bugs.c | 9 +++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/hw-vuln/attack_vector_controls.rst b/Documentation/admin-guide/hw-vuln/attack_vector_controls.rst index 6dd0800146f65b..5964901d66e317 100644 --- a/Documentation/admin-guide/hw-vuln/attack_vector_controls.rst +++ b/Documentation/admin-guide/hw-vuln/attack_vector_controls.rst @@ -215,7 +215,7 @@ Spectre_v2 X X Spectre_v2_user X X * (Note 1) SRBDS X X X X SRSO X X X X -SSB (Note 4) +SSB X TAA X X X X * (Note 2) TSA X X X X =============== ============== ============ ============= ============== ============ ======== @@ -229,9 +229,6 @@ Notes: 3 -- Disables SMT if cross-thread mitigations are fully enabled, the CPU is vulnerable, and STIBP is not supported - 4 -- Speculative store bypass is always enabled by default (no kernel - mitigation applied) unless overridden with spec_store_bypass_disable option - When an attack-vector is disabled, all mitigations for the vulnerabilities listed in the above table are disabled, unless mitigation is required for a different enabled attack-vector or a mitigation is explicitly selected via a diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 49ef1b832c1a55..af838b8d845cfb 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -416,6 +416,10 @@ static bool __init should_mitigate_vuln(unsigned int bug) cpu_attack_vector_mitigated(CPU_MITIGATE_USER_USER) || cpu_attack_vector_mitigated(CPU_MITIGATE_GUEST_GUEST) || (smt_mitigations != SMT_MITIGATIONS_OFF); + + case X86_BUG_SPEC_STORE_BYPASS: + return cpu_attack_vector_mitigated(CPU_MITIGATE_USER_USER); + default: WARN(1, "Unknown bug %x\n", bug); return false; @@ -2710,6 +2714,11 @@ static void __init ssb_select_mitigation(void) ssb_mode = SPEC_STORE_BYPASS_DISABLE; break; case SPEC_STORE_BYPASS_CMD_AUTO: + if (should_mitigate_vuln(X86_BUG_SPEC_STORE_BYPASS)) + ssb_mode = SPEC_STORE_BYPASS_PRCTL; + else + ssb_mode = SPEC_STORE_BYPASS_NONE; + break; case SPEC_STORE_BYPASS_CMD_PRCTL: ssb_mode = SPEC_STORE_BYPASS_PRCTL; break; From 27f5e0c1321ee280189cea16044de2e157dc4bb9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 24 Jun 2025 11:37:16 -0400 Subject: [PATCH 0709/1292] drm/amdgpu/gfx11: set MQD as appriopriate for queue types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the MQD as appropriate for the kernel vs user queues. Acked-by: Christian Kƶnig Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit 063d6683208722b1875f888a45084e3d112701ac) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index c01c241a1b0632..456ba758fa94aa 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -4129,6 +4129,8 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m, #endif if (prop->tmz_queue) tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, TMZ_MATCH, 1); + if (!prop->kernel_queue) + tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, RB_NON_PRIV, 1); mqd->cp_gfx_hqd_cntl = tmp; /* set up cp_doorbell_control */ @@ -4281,8 +4283,10 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m, tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, prop->allow_tunneling); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); + if (prop->kernel_queue) { + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); + } if (prop->tmz_queue) tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TMZ, 1); mqd->cp_hqd_pq_control = tmp; From 29f155c5e82fe35ff85b1f13612cb8c2dbe1dca3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 24 Jun 2025 11:38:14 -0400 Subject: [PATCH 0710/1292] drm/amdgpu/gfx12: set MQD as appriopriate for queue types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the MQD as appropriate for the kernel vs user queues. Acked-by: Christian Kƶnig Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit 7b9110f2897957efd9715b52fc01986509729db3) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index 3e138527d534db..fd44d5503e2825 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -3026,6 +3026,8 @@ static int gfx_v12_0_gfx_mqd_init(struct amdgpu_device *adev, void *m, #endif if (prop->tmz_queue) tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, TMZ_MATCH, 1); + if (!prop->kernel_queue) + tmp = REG_SET_FIELD(tmp, CP_GFX_HQD_CNTL, RB_NON_PRIV, 1); mqd->cp_gfx_hqd_cntl = tmp; /* set up cp_doorbell_control */ @@ -3175,8 +3177,10 @@ static int gfx_v12_0_compute_mqd_init(struct amdgpu_device *adev, void *m, (order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1)); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, 0); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); + if (prop->kernel_queue) { + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); + } if (prop->tmz_queue) tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TMZ, 1); mqd->cp_hqd_pq_control = tmp; From ac4ed2da4c1305a1a002415058aa7deaf49ffe3e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 25 Aug 2025 13:40:22 -0400 Subject: [PATCH 0711/1292] Revert "drm/amdgpu: fix incorrect vm flags to map bo" This reverts commit b08425fa77ad2f305fe57a33dceb456be03b653f. Revert this to align with 6.17 because the fixes tag was wrong on this commit. Signed-off-by: Alex Deucher (cherry picked from commit be33e8a239aac204d7e9e673c4220ef244eb1ba3) --- drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c index dfb6cfd8376069..02138aa557935e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c @@ -88,8 +88,8 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, } r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, size, - AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | - AMDGPU_VM_PAGE_EXECUTABLE); + AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | + AMDGPU_PTE_EXECUTABLE); if (r) { DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r); From 5dff50802b285da8284a7bf17ae2fdc6f1357023 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 25 Aug 2025 12:54:01 +0800 Subject: [PATCH 0712/1292] drm/amd/amdgpu: disable hwmon power1_cap* for gfx 11.0.3 on vf mode the PPSMC_MSG_GetPptLimit msg is not valid for gfx 11.0.3 on vf mode, so skiped to create power1_cap* hwmon sysfs node. Signed-off-by: Yang Wang Reviewed-by: Asad Kamal Acked-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit e82a8d441038d8cb10b63047a9e705c42479d156) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 4b64851fdb42e4..5fbfe7333b54df 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -3458,14 +3458,16 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, effective_mode &= ~S_IWUSR; /* not implemented yet for APUs other than GC 10.3.1 (vangogh) and 9.4.3 */ - if (((adev->family == AMDGPU_FAMILY_SI) || - ((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(10, 3, 1)) && - (gc_ver != IP_VERSION(9, 4, 3) && gc_ver != IP_VERSION(9, 4, 4)))) && - (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || - attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr || - attr == &sensor_dev_attr_power1_cap.dev_attr.attr || - attr == &sensor_dev_attr_power1_cap_default.dev_attr.attr)) - return 0; + if (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || + attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr || + attr == &sensor_dev_attr_power1_cap.dev_attr.attr || + attr == &sensor_dev_attr_power1_cap_default.dev_attr.attr) { + if (adev->family == AMDGPU_FAMILY_SI || + ((adev->flags & AMD_IS_APU) && gc_ver != IP_VERSION(10, 3, 1) && + (gc_ver != IP_VERSION(9, 4, 3) && gc_ver != IP_VERSION(9, 4, 4))) || + (amdgpu_sriov_vf(adev) && gc_ver == IP_VERSION(11, 0, 3))) + return 0; + } /* not implemented yet for APUs having < GC 9.3.0 (Renoir) */ if (((adev->family == AMDGPU_FAMILY_SI) || From ee38ea0ae4ed13fe33e033dc98d11e76bc7167cd Mon Sep 17 00:00:00 2001 From: "Jesse.Zhang" Date: Tue, 26 Aug 2025 17:30:58 +0800 Subject: [PATCH 0713/1292] drm/amdgpu: update firmware version checks for user queue support The minimum firmware versions required for user queue functionality have been increased to address an issue where the queue privilege state was lost during queue connect operations. The problem occurred because the privilege state was being restored to its initial value at the beginning of the function, overwriting the state that was properly set during the queue connect case. This commit updates the minimum version requirements: - ME firmware from 2390 to 2420 - PFP firmware from 2530 to 2580 - MEC firmware from 2600 to 2650 - MES firmware remains at 120 These updated firmware versions contain the necessary fixes to properly maintain queue privilege state throughout connect operations. Fixes: 61ca97e9590c ("drm/amdgpu: Add fw minimum version check for usermode queue") Acked-by: Alex Deucher Signed-off-by: Jesse Zhang Signed-off-by: Alex Deucher (cherry picked from commit 5f976c9939f0d5916d2b8ef3156a6d1799781df1) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 456ba758fa94aa..c85de8c8f6f50b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -1612,9 +1612,9 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block) case IP_VERSION(11, 0, 2): case IP_VERSION(11, 0, 3): if (!adev->gfx.disable_uq && - adev->gfx.me_fw_version >= 2390 && - adev->gfx.pfp_fw_version >= 2530 && - adev->gfx.mec_fw_version >= 2600 && + adev->gfx.me_fw_version >= 2420 && + adev->gfx.pfp_fw_version >= 2580 && + adev->gfx.mec_fw_version >= 2650 && adev->mes.fw_version[0] >= 120) { adev->userq_funcs[AMDGPU_HW_IP_GFX] = &userq_mes_funcs; adev->userq_funcs[AMDGPU_HW_IP_COMPUTE] = &userq_mes_funcs; From c767d74a9cdd1042046d02319d16b85d9aa8a8aa Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 22 Aug 2025 12:12:37 -0400 Subject: [PATCH 0714/1292] drm/amdgpu/userq: fix error handling of invalid doorbell If the doorbell is invalid, be sure to set the r to an error state so the function returns an error. Reviewed-by: David (Ming Qiang) Wu Signed-off-by: Alex Deucher (cherry picked from commit 7e2a5b0a9a165a7c51274aa01b18be29491b4345) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index c3ace8030530fe..8190c24a649a24 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -471,6 +471,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) if (index == (uint64_t)-EINVAL) { drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n"); kfree(queue); + r = -EINVAL; goto unlock; } From ab529e6ca1f67bcf31f3ea80c72bffde2e9e053e Mon Sep 17 00:00:00 2001 From: Shuhao Fu Date: Thu, 28 Aug 2025 02:24:19 +0800 Subject: [PATCH 0715/1292] fs/smb: Fix inconsistent refcnt update A possible inconsistent update of refcount was identified in `smb2_compound_op`. Such inconsistent update could lead to possible resource leaks. Why it is a possible bug: 1. In the comment section of the function, it clearly states that the reference to `cfile` should be dropped after calling this function. 2. Every control flow path would check and drop the reference to `cfile`, except the patched one. 3. Existing callers would not handle refcount update of `cfile` if -ENOMEM is returned. To fix the bug, an extra goto label "out" is added, to make sure that the cleanup logic would always be respected. As the problem is caused by the allocation failure of `vars`, the cleanup logic between label "finished" and "out" can be safely ignored. According to the definition of function `is_replayable_error`, the error code of "-ENOMEM" is not recoverable. Therefore, the replay logic also gets ignored. Signed-off-by: Shuhao Fu Acked-by: Paulo Alcantara (Red Hat) Cc: stable@vger.kernel.org Signed-off-by: Steve French --- fs/smb/client/smb2inode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 2a0316c514e473..31c13fb5b85b62 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -207,8 +207,10 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, server = cifs_pick_channel(ses); vars = kzalloc(sizeof(*vars), GFP_ATOMIC); - if (vars == NULL) - return -ENOMEM; + if (vars == NULL) { + rc = -ENOMEM; + goto out; + } rqst = &vars->rqst[0]; rsp_iov = &vars->rsp_iov[0]; @@ -864,6 +866,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, smb2_should_replay(tcon, &retries, &cur_sleep)) goto replay_again; +out: if (cfile) cifsFileInfo_put(cfile); From bcd6f8954dc4a3aa32edda5602e43a0174dc8f0f Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Tue, 26 Aug 2025 14:50:46 -0700 Subject: [PATCH 0716/1292] MAINTAINERS: rmnet: Update email addresses Switch to oss.qualcomm.com ids. Signed-off-by: Sean Tranchetti Signed-off-by: Subash Abhinov Kasiviswanathan Link: https://patch.msgid.link/20250826215046.865530-1-subash.a.kasiviswanathan@oss.qualcomm.com Signed-off-by: Jakub Kicinski --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c5b47955d2a63b..3337577ce54542 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20847,8 +20847,8 @@ S: Maintained F: drivers/firmware/qcom/qcom_qseecom_uefisecapp.c QUALCOMM RMNET DRIVER -M: Subash Abhinov Kasiviswanathan -M: Sean Tranchetti +M: Subash Abhinov Kasiviswanathan +M: Sean Tranchetti L: netdev@vger.kernel.org S: Maintained F: Documentation/networking/device_drivers/cellular/qualcomm/rmnet.rst From 2e8750469242cad8f01f320131fd5a6f540dbb99 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 26 Aug 2025 14:13:14 +0000 Subject: [PATCH 0717/1292] sctp: initialize more fields in sctp_v6_from_sk() syzbot found that sin6_scope_id was not properly initialized, leading to undefined behavior. Clear sin6_scope_id and sin6_flowinfo. BUG: KMSAN: uninit-value in __sctp_v6_cmp_addr+0x887/0x8c0 net/sctp/ipv6.c:649 __sctp_v6_cmp_addr+0x887/0x8c0 net/sctp/ipv6.c:649 sctp_inet6_cmp_addr+0x4f2/0x510 net/sctp/ipv6.c:983 sctp_bind_addr_conflict+0x22a/0x3b0 net/sctp/bind_addr.c:390 sctp_get_port_local+0x21eb/0x2440 net/sctp/socket.c:8452 sctp_get_port net/sctp/socket.c:8523 [inline] sctp_listen_start net/sctp/socket.c:8567 [inline] sctp_inet_listen+0x710/0xfd0 net/sctp/socket.c:8636 __sys_listen_socket net/socket.c:1912 [inline] __sys_listen net/socket.c:1927 [inline] __do_sys_listen net/socket.c:1932 [inline] __se_sys_listen net/socket.c:1930 [inline] __x64_sys_listen+0x343/0x4c0 net/socket.c:1930 x64_sys_call+0x271d/0x3e20 arch/x86/include/generated/asm/syscalls_64.h:51 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xd9/0x210 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Local variable addr.i.i created at: sctp_get_port net/sctp/socket.c:8515 [inline] sctp_listen_start net/sctp/socket.c:8567 [inline] sctp_inet_listen+0x650/0xfd0 net/sctp/socket.c:8636 __sys_listen_socket net/socket.c:1912 [inline] __sys_listen net/socket.c:1927 [inline] __do_sys_listen net/socket.c:1932 [inline] __se_sys_listen net/socket.c:1930 [inline] __x64_sys_listen+0x343/0x4c0 net/socket.c:1930 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+e69f06a0f30116c68056@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/68adc0a2.050a0220.37038e.00c4.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Marcelo Ricardo Leitner Acked-by: Xin Long Link: https://patch.msgid.link/20250826141314.1802610-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/sctp/ipv6.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 3336dcfb451509..568ff8797c393b 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -547,7 +547,9 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) { addr->v6.sin6_family = AF_INET6; addr->v6.sin6_port = 0; + addr->v6.sin6_flowinfo = 0; addr->v6.sin6_addr = sk->sk_v6_rcv_saddr; + addr->v6.sin6_scope_id = 0; } /* Initialize sk->sk_rcv_saddr from sctp_addr. */ From 9b8c88f875c04d4cb9111bd5dd9291c7e9691bf5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 26 Aug 2025 13:44:35 +0000 Subject: [PATCH 0718/1292] l2tp: do not use sock_hold() in pppol2tp_session_get_sock() pppol2tp_session_get_sock() is using RCU, it must be ready for sk_refcnt being zero. Commit ee40fb2e1eb5 ("l2tp: protect sock pointer of struct pppol2tp_session with RCU") was correct because it had a call_rcu(..., pppol2tp_put_sk) which was later removed in blamed commit. pppol2tp_recv() can use pppol2tp_session_get_sock() as well. Fixes: c5cbaef992d6 ("l2tp: refactor ppp socket/session relationship") Signed-off-by: Eric Dumazet Cc: James Chapman Reviewed-by: Guillaume Nault Link: https://patch.msgid.link/20250826134435.1683435-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/l2tp/l2tp_ppp.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index fc5c2fd8f34c7e..5e12e7ce17d8a7 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -129,22 +129,12 @@ static const struct ppp_channel_ops pppol2tp_chan_ops = { static const struct proto_ops pppol2tp_ops; -/* Retrieves the pppol2tp socket associated to a session. - * A reference is held on the returned socket, so this function must be paired - * with sock_put(). - */ +/* Retrieves the pppol2tp socket associated to a session. */ static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session) { struct pppol2tp_session *ps = l2tp_session_priv(session); - struct sock *sk; - - rcu_read_lock(); - sk = rcu_dereference(ps->sk); - if (sk) - sock_hold(sk); - rcu_read_unlock(); - return sk; + return rcu_dereference(ps->sk); } /* Helpers to obtain tunnel/session contexts from sockets. @@ -206,14 +196,13 @@ static int pppol2tp_recvmsg(struct socket *sock, struct msghdr *msg, static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len) { - struct pppol2tp_session *ps = l2tp_session_priv(session); - struct sock *sk = NULL; + struct sock *sk; /* If the socket is bound, send it in to PPP's input queue. Otherwise * queue it on the session socket. */ rcu_read_lock(); - sk = rcu_dereference(ps->sk); + sk = pppol2tp_session_get_sock(session); if (!sk) goto no_sock; @@ -510,13 +499,14 @@ static void pppol2tp_show(struct seq_file *m, void *arg) struct l2tp_session *session = arg; struct sock *sk; + rcu_read_lock(); sk = pppol2tp_session_get_sock(session); if (sk) { struct pppox_sock *po = pppox_sk(sk); seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan)); - sock_put(sk); } + rcu_read_unlock(); } static void pppol2tp_session_init(struct l2tp_session *session) @@ -1530,6 +1520,7 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v) port = ntohs(inet->inet_sport); } + rcu_read_lock(); sk = pppol2tp_session_get_sock(session); if (sk) { state = sk->sk_state; @@ -1565,8 +1556,8 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v) struct pppox_sock *po = pppox_sk(sk); seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan)); - sock_put(sk); } + rcu_read_unlock(); } static int pppol2tp_seq_show(struct seq_file *m, void *v) From 1cc8a5b534e5f9b5e129e54ee2e63c9f5da4f39a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Aug 2025 17:21:49 +0000 Subject: [PATCH 0719/1292] net: rose: fix a typo in rose_clear_routes() syzbot crashed in rose_clear_routes(), after a recent patch typo. KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017] CPU: 0 UID: 0 PID: 10591 Comm: syz.3.1856 Not tainted syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/12/2025 RIP: 0010:rose_clear_routes net/rose/rose_route.c:565 [inline] RIP: 0010:rose_rt_ioctl+0x162/0x1250 net/rose/rose_route.c:760 rose_ioctl+0x3ce/0x8b0 net/rose/af_rose.c:1381 sock_do_ioctl+0xd9/0x300 net/socket.c:1238 sock_ioctl+0x576/0x790 net/socket.c:1359 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:598 [inline] __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:584 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: da9c9c877597 ("net: rose: include node references in rose_neigh refcount") Reported-by: syzbot+2eb8d1719f7cfcfa6840@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/68af3e29.a70a0220.3cafd4.002e.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Takamitsu Iwai Reviewed-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20250827172149.5359-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/rose/rose_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 1adee1fbc2ed1d..a1e9b05ef6f5f6 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -562,7 +562,7 @@ static int rose_clear_routes(void) rose_node = rose_node->next; if (!t->loopback) { - for (i = 0; i < rose_node->count; i++) + for (i = 0; i < t->count; i++) rose_neigh_put(t->neighbour[i]); rose_remove_node(t); } From 2ddaa562b465921a5d1da3fc939993b92b953e20 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 25 Aug 2025 15:56:06 -0700 Subject: [PATCH 0720/1292] fbnic: Fixup rtnl_lock and devl_lock handling related to mailbox code The exception handling path for the __fbnic_pm_resume function had a bug in that it was taking the devlink lock and then exiting to exception handling instead of waiting until after it released the lock to do so. In order to handle that I am swapping the placement of the unlock and the exception handling jump to label so that we don't trigger a deadlock by holding the lock longer than we need to. In addition this change applies the same ordering to the rtnl_lock/unlock calls in the same function as it should make the code easier to follow if it adheres to a consistent pattern. Fixes: 82534f446daa ("eth: fbnic: Add devlink dev flash support") Signed-off-by: Alexander Duyck Reviewed-by: Przemek Kitszel Link: https://patch.msgid.link/175616256667.1963577.5543500806256052549.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c index b70e4cadb37bdf..a7784deea88f0a 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c @@ -443,11 +443,10 @@ static int __fbnic_pm_resume(struct device *dev) /* Re-enable mailbox */ err = fbnic_fw_request_mbx(fbd); + devl_unlock(priv_to_devlink(fbd)); if (err) goto err_free_irqs; - devl_unlock(priv_to_devlink(fbd)); - /* Only send log history if log buffer is empty to prevent duplicate * log entries. */ @@ -464,20 +463,20 @@ static int __fbnic_pm_resume(struct device *dev) rtnl_lock(); - if (netif_running(netdev)) { + if (netif_running(netdev)) err = __fbnic_open(fbn); - if (err) - goto err_free_mbx; - } rtnl_unlock(); + if (err) + goto err_free_mbx; return 0; err_free_mbx: fbnic_fw_log_disable(fbd); - rtnl_unlock(); + devl_lock(priv_to_devlink(fbd)); fbnic_fw_free_mbx(fbd); + devl_unlock(priv_to_devlink(fbd)); err_free_irqs: fbnic_free_irqs(fbd); err_invalidate_uc_addr: From 6ede14a2c6365e7e5d855643c7c8390b5268c467 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 25 Aug 2025 15:56:13 -0700 Subject: [PATCH 0721/1292] fbnic: Move phylink resume out of service_task and into open/close The fbnic driver was presenting with the following locking assert coming out of a PM resume: [ 42.208116][ T164] RTNL: assertion failed at drivers/net/phy/phylink.c (2611) [ 42.208492][ T164] WARNING: CPU: 1 PID: 164 at drivers/net/phy/phylink.c:2611 phylink_resume+0x190/0x1e0 [ 42.208872][ T164] Modules linked in: [ 42.209140][ T164] CPU: 1 UID: 0 PID: 164 Comm: bash Not tainted 6.17.0-rc2-virtme #134 PREEMPT(full) [ 42.209496][ T164] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-5.fc42 04/01/2014 [ 42.209861][ T164] RIP: 0010:phylink_resume+0x190/0x1e0 [ 42.210057][ T164] Code: 83 e5 01 0f 85 b0 fe ff ff c6 05 1c cd 3e 02 01 90 ba 33 0a 00 00 48 c7 c6 20 3a 1d a5 48 c7 c7 e0 3e 1d a5 e8 21 b8 90 fe 90 <0f> 0b 90 90 e9 86 fe ff ff e8 42 ea 1f ff e9 e2 fe ff ff 48 89 ef [ 42.210708][ T164] RSP: 0018:ffffc90000affbd8 EFLAGS: 00010296 [ 42.210983][ T164] RAX: 0000000000000000 RBX: ffff8880078d8400 RCX: 0000000000000000 [ 42.211235][ T164] RDX: 0000000000000000 RSI: 1ffffffff4f10938 RDI: 0000000000000001 [ 42.211466][ T164] RBP: 0000000000000000 R08: ffffffffa2ae79ea R09: fffffbfff4b3eb84 [ 42.211707][ T164] R10: 0000000000000003 R11: 0000000000000000 R12: ffff888007ad8000 [ 42.211997][ T164] R13: 0000000000000002 R14: ffff888006a18800 R15: ffffffffa34c59e0 [ 42.212234][ T164] FS: 00007f0dc8e39740(0000) GS:ffff88808f51f000(0000) knlGS:0000000000000000 [ 42.212505][ T164] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 42.212704][ T164] CR2: 00007f0dc8e9fe10 CR3: 000000000b56d003 CR4: 0000000000772ef0 [ 42.213227][ T164] PKRU: 55555554 [ 42.213366][ T164] Call Trace: [ 42.213483][ T164] [ 42.213565][ T164] __fbnic_pm_attach.isra.0+0x8e/0xa0 [ 42.213725][ T164] pci_reset_function+0x116/0x1d0 [ 42.213895][ T164] reset_store+0xa0/0x100 [ 42.214025][ T164] ? pci_dev_reset_attr_is_visible+0x50/0x50 [ 42.214221][ T164] ? sysfs_file_kobj+0xc1/0x1e0 [ 42.214374][ T164] ? sysfs_kf_write+0x65/0x160 [ 42.214526][ T164] kernfs_fop_write_iter+0x2f8/0x4c0 [ 42.214677][ T164] ? kernfs_vma_page_mkwrite+0x1f0/0x1f0 [ 42.214836][ T164] new_sync_write+0x308/0x6f0 [ 42.214987][ T164] ? __lock_acquire+0x34c/0x740 [ 42.215135][ T164] ? new_sync_read+0x6f0/0x6f0 [ 42.215288][ T164] ? lock_acquire.part.0+0xbc/0x260 [ 42.215440][ T164] ? ksys_write+0xff/0x200 [ 42.215590][ T164] ? perf_trace_sched_switch+0x6d0/0x6d0 [ 42.215742][ T164] vfs_write+0x65e/0xbb0 [ 42.215876][ T164] ksys_write+0xff/0x200 [ 42.215994][ T164] ? __ia32_sys_read+0xc0/0xc0 [ 42.216141][ T164] ? do_user_addr_fault+0x269/0x9f0 [ 42.216292][ T164] ? rcu_is_watching+0x15/0xd0 [ 42.216442][ T164] do_syscall_64+0xbb/0x360 [ 42.216591][ T164] entry_SYSCALL_64_after_hwframe+0x4b/0x53 [ 42.216784][ T164] RIP: 0033:0x7f0dc8ea9986 A bit of digging showed that we were invoking the phylink_resume as a part of the fbnic_up path when we were enabling the service task while not holding the RTNL lock. We should be enabling this sooner as a part of the ndo_open path and then just letting the service task come online later. This will help to enforce the correct locking and brings the phylink interface online at the same time as the network interface, instead of at a later time. I tested this on QEMU to verify this was working by putting the system to sleep using "echo mem > /sys/power/state" to put the system to sleep in the guest and then using the command "system_wakeup" in the QEMU monitor. Fixes: 69684376eed5 ("eth: fbnic: Add link detection") Signed-off-by: Alexander Duyck Reviewed-by: Przemek Kitszel Link: https://patch.msgid.link/175616257316.1963577.12238158800417771119.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 4 ++++ drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index e67e99487a271c..40581550da1a94 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -52,6 +52,8 @@ int __fbnic_open(struct fbnic_net *fbn) fbnic_bmc_rpc_init(fbd); fbnic_rss_reinit(fbd, fbn); + phylink_resume(fbn->phylink); + return 0; time_stop: fbnic_time_stop(fbn); @@ -84,6 +86,8 @@ static int fbnic_stop(struct net_device *netdev) { struct fbnic_net *fbn = netdev_priv(netdev); + phylink_suspend(fbn->phylink, fbnic_bmc_present(fbn->fbd)); + fbnic_down(fbn); fbnic_pcs_free_irq(fbn->fbd); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c index a7784deea88f0a..28e23e3ffca88c 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c @@ -118,14 +118,12 @@ static void fbnic_service_task_start(struct fbnic_net *fbn) struct fbnic_dev *fbd = fbn->fbd; schedule_delayed_work(&fbd->service_task, HZ); - phylink_resume(fbn->phylink); } static void fbnic_service_task_stop(struct fbnic_net *fbn) { struct fbnic_dev *fbd = fbn->fbd; - phylink_suspend(fbn->phylink, fbnic_bmc_present(fbd)); cancel_delayed_work(&fbd->service_task); } From 82b8166171bdebbc74717e4a0cfb4b89cd0510aa Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 26 Aug 2025 15:54:18 +0800 Subject: [PATCH 0722/1292] ata: ahci_xgene: Use int type for 'rc' to store error codes Use int instead of u32 for the 'rc' variable in xgene_ahci_softreset() to store negative error codes returned by ahci_do_softreset(). In xgene_ahci_pmp_softreset(), remove the redundant 'rc' variable and directly return the result of the ahci_do_softreset() call instead. Signed-off-by: Qianfeng Rong Signed-off-by: Damien Le Moal --- drivers/ata/ahci_xgene.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 5d5a51a77f5d41..6b8844646fcd0a 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -450,7 +450,6 @@ static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class, { int pmp = sata_srst_pmp(link); struct ata_port *ap = link->ap; - u32 rc; void __iomem *port_mmio = ahci_port_base(ap); u32 port_fbs; @@ -463,9 +462,7 @@ static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class, port_fbs |= pmp << PORT_FBS_DEV_OFFSET; writel(port_fbs, port_mmio + PORT_FBS); - rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); - - return rc; + return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); } /** @@ -500,7 +497,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class, u32 port_fbs; u32 port_fbs_save; u32 retry = 1; - u32 rc; + int rc; port_fbs_save = readl(port_mmio + PORT_FBS); From d939047d31ff25a49a39667417c2a996caa826f5 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 27 Aug 2025 16:44:01 -0400 Subject: [PATCH 0723/1292] dt-bindings: Remove outdated cpufreq-dt.txt The information present in this file is outdated and doesn't serve any purpose with the current design of the driver. Remove the outdated file. Signed-off-by: Frank Li [ Viresh: Rewrite commit log ] Signed-off-by: Viresh Kumar --- .../bindings/cpufreq/cpufreq-dt.txt | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt deleted file mode 100644 index 1d7e49167666e1..00000000000000 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt +++ /dev/null @@ -1,61 +0,0 @@ -Generic cpufreq driver - -It is a generic DT based cpufreq driver for frequency management. It supports -both uniprocessor (UP) and symmetric multiprocessor (SMP) systems which share -clock and voltage across all CPUs. - -Both required and optional properties listed below must be defined -under node /cpus/cpu@0. - -Required properties: -- None - -Optional properties: -- operating-points: Refer to Documentation/devicetree/bindings/opp/opp-v1.yaml for - details. OPPs *must* be supplied either via DT, i.e. this property, or - populated at runtime. -- clock-latency: Specify the possible maximum transition latency for clock, - in unit of nanoseconds. -- voltage-tolerance: Specify the CPU voltage tolerance in percentage. -- #cooling-cells: - Please refer to - Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml. - -Examples: - -cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "arm,cortex-a9"; - reg = <0>; - next-level-cache = <&L2>; - operating-points = < - /* kHz uV */ - 792000 1100000 - 396000 950000 - 198000 850000 - >; - clock-latency = <61036>; /* two CLK32 periods */ - #cooling-cells = <2>; - }; - - cpu@1 { - compatible = "arm,cortex-a9"; - reg = <1>; - next-level-cache = <&L2>; - }; - - cpu@2 { - compatible = "arm,cortex-a9"; - reg = <2>; - next-level-cache = <&L2>; - }; - - cpu@3 { - compatible = "arm,cortex-a9"; - reg = <3>; - next-level-cache = <&L2>; - }; -}; From ee4d098cbc9160f573b5c1b5a51d6158efdb2896 Mon Sep 17 00:00:00 2001 From: Yin Tirui Date: Tue, 19 Aug 2025 15:55:10 +0800 Subject: [PATCH 0724/1292] of_numa: fix uninitialized memory nodes causing kernel panic When there are memory-only nodes (nodes without CPUs), these nodes are not properly initialized, causing kernel panic during boot. of_numa_init of_numa_parse_cpu_nodes node_set(nid, numa_nodes_parsed); of_numa_parse_memory_nodes In of_numa_parse_cpu_nodes, numa_nodes_parsed gets updated only for nodes containing CPUs. Memory-only nodes should have been updated in of_numa_parse_memory_nodes, but they weren't. Subsequently, when free_area_init() attempts to access NODE_DATA() for these uninitialized memory nodes, the kernel panics due to NULL pointer dereference. This can be reproduced on ARM64 QEMU with 1 CPU and 2 memory nodes: qemu-system-aarch64 \ -cpu host -nographic \ -m 4G -smp 1 \ -machine virt,accel=kvm,gic-version=3,iommu=smmuv3 \ -object memory-backend-ram,size=2G,id=mem0 \ -object memory-backend-ram,size=2G,id=mem1 \ -numa node,nodeid=0,memdev=mem0 \ -numa node,nodeid=1,memdev=mem1 \ -kernel $IMAGE \ -hda $DISK \ -append "console=ttyAMA0 root=/dev/vda rw earlycon" [ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x481fd010] [ 0.000000] Linux version 6.17.0-rc1-00001-gabb4b3daf18c-dirty (yintirui@local) (gcc (GCC) 12.3.1, GNU ld (GNU Binutils) 2.41) #52 SMP PREEMPT Mon Aug 18 09:49:40 CST 2025 [ 0.000000] KASLR enabled [ 0.000000] random: crng init done [ 0.000000] Machine model: linux,dummy-virt [ 0.000000] efi: UEFI not found. [ 0.000000] earlycon: pl11 at MMIO 0x0000000009000000 (options '') [ 0.000000] printk: legacy bootconsole [pl11] enabled [ 0.000000] OF: reserved mem: Reserved memory: No reserved-memory node in the DT [ 0.000000] NODE_DATA(0) allocated [mem 0xbfffd9c0-0xbfffffff] [ 0.000000] node 1 must be removed before remove section 23 [ 0.000000] Zone ranges: [ 0.000000] DMA [mem 0x0000000040000000-0x00000000ffffffff] [ 0.000000] DMA32 empty [ 0.000000] Normal [mem 0x0000000100000000-0x000000013fffffff] [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x0000000040000000-0x00000000bfffffff] [ 0.000000] node 1: [mem 0x00000000c0000000-0x000000013fffffff] [ 0.000000] Initmem setup node 0 [mem 0x0000000040000000-0x00000000bfffffff] [ 0.000000] Unable to handle kernel NULL pointer dereference at virtual address 00000000000000a0 [ 0.000000] Mem abort info: [ 0.000000] ESR = 0x0000000096000004 [ 0.000000] EC = 0x25: DABT (current EL), IL = 32 bits [ 0.000000] SET = 0, FnV = 0 [ 0.000000] EA = 0, S1PTW = 0 [ 0.000000] FSC = 0x04: level 0 translation fault [ 0.000000] Data abort info: [ 0.000000] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 0.000000] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 0.000000] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 0.000000] [00000000000000a0] user address but active_mm is swapper [ 0.000000] Internal error: Oops: 0000000096000004 [#1] SMP [ 0.000000] Modules linked in: [ 0.000000] CPU: 0 UID: 0 PID: 0 Comm: swapper Not tainted 6.17.0-rc1-00001-g760c6dabf762-dirty #54 PREEMPT [ 0.000000] Hardware name: linux,dummy-virt (DT) [ 0.000000] pstate: 800000c5 (Nzcv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 0.000000] pc : free_area_init+0x50c/0xf9c [ 0.000000] lr : free_area_init+0x5c0/0xf9c [ 0.000000] sp : ffffa02ca0f33c00 [ 0.000000] x29: ffffa02ca0f33cb0 x28: 0000000000000000 x27: 0000000000000000 [ 0.000000] x26: 4ec4ec4ec4ec4ec5 x25: 00000000000c0000 x24: 00000000000c0000 [ 0.000000] x23: 0000000000040000 x22: 0000000000000000 x21: ffffa02ca0f3b368 [ 0.000000] x20: ffffa02ca14c7b98 x19: 0000000000000000 x18: 0000000000000002 [ 0.000000] x17: 000000000000cacc x16: 0000000000000001 x15: 0000000000000001 [ 0.000000] x14: 0000000080000000 x13: 0000000000000018 x12: 0000000000000002 [ 0.000000] x11: ffffa02ca0fd4f00 x10: ffffa02ca14bab20 x9 : ffffa02ca14bab38 [ 0.000000] x8 : 00000000000c0000 x7 : 0000000000000001 x6 : 0000000000000002 [ 0.000000] x5 : 0000000140000000 x4 : ffffa02ca0f33c90 x3 : ffffa02ca0f33ca0 [ 0.000000] x2 : ffffa02ca0f33c98 x1 : 0000000080000000 x0 : 0000000000000001 [ 0.000000] Call trace: [ 0.000000] free_area_init+0x50c/0xf9c (P) [ 0.000000] bootmem_init+0x110/0x1dc [ 0.000000] setup_arch+0x278/0x60c [ 0.000000] start_kernel+0x70/0x748 [ 0.000000] __primary_switched+0x88/0x90 [ 0.000000] Code: d503201f b98093e0 52800016 f8607a93 (f9405260) [ 0.000000] ---[ end trace 0000000000000000 ]--- [ 0.000000] Kernel panic - not syncing: Attempted to kill the idle task! [ 0.000000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task! ]--- Link: https://lkml.kernel.org/r/20250819075510.2079961-1-yintirui@huawei.com Fixes: 767507654c22 ("arch_numa: switch over to numa_memblks") Signed-off-by: Yin Tirui Acked-by: David Hildenbrand Acked-by: Mike Rapoport (Microsoft) Reviewed-by: Kefeng Wang Cc: Chen Jun Cc: Dan Williams Cc: Joanthan Cameron Cc: Rob Herring Cc: Saravana Kannan Cc: Signed-off-by: Andrew Morton --- drivers/of/of_numa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index 230d5f628c1b47..cd2dc8e825c92b 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c @@ -59,8 +59,11 @@ static int __init of_numa_parse_memory_nodes(void) r = -EINVAL; } - for (i = 0; !r && !of_address_to_resource(np, i, &rsrc); i++) + for (i = 0; !r && !of_address_to_resource(np, i, &rsrc); i++) { r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1); + if (!r) + node_set(nid, numa_nodes_parsed); + } if (!i || r) { of_node_put(np); From 5cc5e030bce2ec97ae5cdb2c1b94a98b1047b3fa Mon Sep 17 00:00:00 2001 From: Baptiste Lepers Date: Tue, 12 Aug 2025 15:26:56 +0200 Subject: [PATCH 0725/1292] rust: mm: mark VmaNew as transparent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unsafe code in VmaNew's methods assumes that the type has the same layout as the inner `bindings::vm_area_struct`. This is not guaranteed by the default struct representation in Rust, but requires specifying the `transparent` representation. Link: https://lkml.kernel.org/r/20250812132712.61007-1-baptiste.lepers@gmail.com Fixes: dcb81aeab406 ("mm: rust: add VmaNew for f_ops->mmap()") Signed-off-by: Baptiste Lepers Reviewed-by: Alice Ryhl Cc: Alex Gaynor Cc: Andreas Hindborg Cc: Bjƶrn Roy Baron Cc: Boqun Feng Cc: Danilo Krummrich Cc: Gary Guo Cc: Jann Horn Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Miguel Ojeda Cc: Trevor Gross Cc: Signed-off-by: Andrew Morton --- rust/kernel/mm/virt.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/kernel/mm/virt.rs b/rust/kernel/mm/virt.rs index 6086ca981b06bb..a1bfa4e19293a5 100644 --- a/rust/kernel/mm/virt.rs +++ b/rust/kernel/mm/virt.rs @@ -209,6 +209,7 @@ impl VmaMixedMap { /// /// For the duration of 'a, the referenced vma must be undergoing initialization in an /// `f_ops->mmap()` hook. +#[repr(transparent)] pub struct VmaNew { vma: VmaRef, } From f46e8ef8bb7b452584f2e75337b619ac51a7cadf Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 19 Aug 2025 21:41:02 +0800 Subject: [PATCH 0726/1292] ocfs2: prevent release journal inode after journal shutdown Before calling ocfs2_delete_osb(), ocfs2_journal_shutdown() has already been executed in ocfs2_dismount_volume(), so osb->journal must be NULL. Therefore, the following calltrace will inevitably fail when it reaches jbd2_journal_release_jbd_inode(). ocfs2_dismount_volume()-> ocfs2_delete_osb()-> ocfs2_free_slot_info()-> __ocfs2_free_slot_info()-> evict()-> ocfs2_evict_inode()-> ocfs2_clear_inode()-> jbd2_journal_release_jbd_inode(osb->journal->j_journal, Adding osb->journal checks will prevent null-ptr-deref during the above execution path. Link: https://lkml.kernel.org/r/tencent_357489BEAEE4AED74CBD67D246DBD2C4C606@qq.com Fixes: da5e7c87827e ("ocfs2: cleanup journal init and shutdown") Signed-off-by: Edward Adam Davis Reported-by: syzbot+47d8cb2f2cc1517e515a@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=47d8cb2f2cc1517e515a Tested-by: syzbot+47d8cb2f2cc1517e515a@syzkaller.appspotmail.com Reviewed-by: Mark Tinguely Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Cc: Jun Piao Cc: Signed-off-by: Andrew Morton --- fs/ocfs2/inode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 14bf440ea4dff0..6c4f78f473fb41 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -1281,6 +1281,9 @@ static void ocfs2_clear_inode(struct inode *inode) * the journal is flushed before journal shutdown. Thus it is safe to * have inodes get cleaned up after journal shutdown. */ + if (!osb->journal) + return; + jbd2_journal_release_jbd_inode(osb->journal->j_journal, &oi->ip_jinode); } From 9614d8bee66387501f48718fa306e17f2aa3f2f3 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 31 Jul 2025 10:44:31 -0400 Subject: [PATCH 0727/1292] mm/userfaultfd: fix kmap_local LIFO ordering for CONFIG_HIGHPTE With CONFIG_HIGHPTE on 32-bit ARM, move_pages_pte() maps PTE pages using kmap_local_page(), which requires unmapping in Last-In-First-Out order. The current code maps dst_pte first, then src_pte, but unmaps them in the same order (dst_pte, src_pte), violating the LIFO requirement. This causes the warning in kunmap_local_indexed(): WARNING: CPU: 0 PID: 604 at mm/highmem.c:622 kunmap_local_indexed+0x178/0x17c addr \!= __fix_to_virt(FIX_KMAP_BEGIN + idx) Fix this by reversing the unmap order to respect LIFO ordering. This issue follows the same pattern as similar fixes: - commit eca6828403b8 ("crypto: skcipher - fix mismatch between mapping and unmapping order") - commit 8cf57c6df818 ("nilfs2: eliminate staggered calls to kunmap in nilfs_rename") Both of which addressed the same fundamental requirement that kmap_local operations must follow LIFO ordering. Link: https://lkml.kernel.org/r/20250731144431.773923-1-sashal@kernel.org Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI") Signed-off-by: Sasha Levin Acked-by: David Hildenbrand Reviewed-by: Suren Baghdasaryan Cc: Andrea Arcangeli Cc: Signed-off-by: Andrew Morton --- mm/userfaultfd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 45e6290e2e8b33..aefdf3a812a185 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -1453,10 +1453,15 @@ static int move_pages_pte(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, folio_unlock(src_folio); folio_put(src_folio); } - if (dst_pte) - pte_unmap(dst_pte); + /* + * Unmap in reverse order (LIFO) to maintain proper kmap_local + * index ordering when CONFIG_HIGHPTE is enabled. We mapped dst_pte + * first, then src_pte, so we must unmap src_pte first, then dst_pte. + */ if (src_pte) pte_unmap(src_pte); + if (dst_pte) + pte_unmap(dst_pte); mmu_notifier_invalidate_range_end(&range); if (si) put_swap_device(si); From 5bbc2b785e63699cfcaa7adbf739f6e9b771028a Mon Sep 17 00:00:00 2001 From: Zi Yan Date: Tue, 5 Aug 2025 13:51:40 -0400 Subject: [PATCH 0728/1292] selftests/mm: fix FORCE_READ to read input value correctly FORCE_READ() converts input value x to its pointer type then reads from address x. This is wrong. If x is a non-pointer, it would be caught it easily. But all FORCE_READ() callers are trying to read from a pointer and FORCE_READ() basically reads a pointer to a pointer instead of the original typed pointer. Almost no access violation was found, except the one from split_huge_page_test. Fix it by implementing a simplified READ_ONCE() instead. Link: https://lkml.kernel.org/r/20250805175140.241656-1-ziy@nvidia.com Fixes: 3f6bfd4789a0 ("selftests/mm: reuse FORCE_READ to replace "asm volatile("" : "+r" (XXX));"") Signed-off-by: Zi Yan Reviewed-by: Lorenzo Stoakes Acked-by: David Hildenbrand Reviewed-by: wang lian Reviewed-by: Wei Yang Cc: Christian Brauner Cc: Jann Horn Cc: Kairui Song Cc: Liam Howlett Cc: Mark Brown Cc: SeongJae Park Cc: Shuah Khan Cc: Vlastimil Babka Cc: Zi Yan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/cow.c | 4 ++-- tools/testing/selftests/mm/guard-regions.c | 2 +- tools/testing/selftests/mm/hugetlb-madvise.c | 4 +++- tools/testing/selftests/mm/migration.c | 2 +- tools/testing/selftests/mm/pagemap_ioctl.c | 2 +- tools/testing/selftests/mm/split_huge_page_test.c | 7 +++++-- tools/testing/selftests/mm/vm_util.h | 2 +- 7 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c index d30625c18259b9..c744c603d688e4 100644 --- a/tools/testing/selftests/mm/cow.c +++ b/tools/testing/selftests/mm/cow.c @@ -1554,8 +1554,8 @@ static void run_with_zeropage(non_anon_test_fn fn, const char *desc) } /* Read from the page to populate the shared zeropage. */ - FORCE_READ(mem); - FORCE_READ(smem); + FORCE_READ(*mem); + FORCE_READ(*smem); fn(mem, smem, pagesize); munmap: diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c index b0d42eb04e3ae8..8dd81c0a4a5a2c 100644 --- a/tools/testing/selftests/mm/guard-regions.c +++ b/tools/testing/selftests/mm/guard-regions.c @@ -145,7 +145,7 @@ static bool try_access_buf(char *ptr, bool write) if (write) *ptr = 'x'; else - FORCE_READ(ptr); + FORCE_READ(*ptr); } signal_jump_set = false; diff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/selftests/mm/hugetlb-madvise.c index 1afe14b9dc0c34..c5940c0595be88 100644 --- a/tools/testing/selftests/mm/hugetlb-madvise.c +++ b/tools/testing/selftests/mm/hugetlb-madvise.c @@ -50,8 +50,10 @@ void read_fault_pages(void *addr, unsigned long nr_pages) unsigned long i; for (i = 0; i < nr_pages; i++) { + unsigned long *addr2 = + ((unsigned long *)(addr + (i * huge_page_size))); /* Prevent the compiler from optimizing out the entire loop: */ - FORCE_READ(((unsigned long *)(addr + (i * huge_page_size)))); + FORCE_READ(*addr2); } } diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c index c5a73617796aeb..ea945eebec2f62 100644 --- a/tools/testing/selftests/mm/migration.c +++ b/tools/testing/selftests/mm/migration.c @@ -110,7 +110,7 @@ void *access_mem(void *ptr) * the memory access actually happens and prevents the compiler * from optimizing away this entire loop. */ - FORCE_READ((uint64_t *)ptr); + FORCE_READ(*(uint64_t *)ptr); } return NULL; diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c index 0d4209eef0c3d4..e6face7c0166ea 100644 --- a/tools/testing/selftests/mm/pagemap_ioctl.c +++ b/tools/testing/selftests/mm/pagemap_ioctl.c @@ -1525,7 +1525,7 @@ void zeropfn_tests(void) ret = madvise(mem, hpage_size, MADV_HUGEPAGE); if (!ret) { - FORCE_READ(mem); + FORCE_READ(*mem); ret = pagemap_ioctl(mem, hpage_size, &vec, 1, 0, 0, PAGE_IS_PFNZERO, 0, 0, PAGE_IS_PFNZERO); diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 05de1fc0005b78..44a3f8a5880670 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -439,8 +439,11 @@ int create_pagecache_thp_and_fd(const char *testfile, size_t fd_size, int *fd, } madvise(*addr, fd_size, MADV_HUGEPAGE); - for (size_t i = 0; i < fd_size; i++) - FORCE_READ((*addr + i)); + for (size_t i = 0; i < fd_size; i++) { + char *addr2 = *addr + i; + + FORCE_READ(*addr2); + } if (!check_huge_file(*addr, fd_size / pmd_pagesize, pmd_pagesize)) { ksft_print_msg("No large pagecache folio generated, please provide a filesystem supporting large folio\n"); diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index c20298ae98ea5c..b55d1809debc06 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -23,7 +23,7 @@ * anything with it in order to trigger a read page fault. We therefore must use * volatile to stop the compiler from optimising this away. */ -#define FORCE_READ(x) (*(volatile typeof(x) *)x) +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x)) extern unsigned int __page_size; extern unsigned int __page_shift; From 7a19afee6fb39df63ddea7ce78976d8c521178c6 Mon Sep 17 00:00:00 2001 From: Yeoreum Yun Date: Fri, 1 Aug 2025 13:02:36 +0100 Subject: [PATCH 0729/1292] kunit: kasan_test: disable fortify string checker on kasan_strings() test Similar to commit 09c6304e38e4 ("kasan: test: fix compatibility with FORTIFY_SOURCE") the kernel is panicing in kasan_string(). This is due to the `src` and `ptr` not being hidden from the optimizer which would disable the runtime fortify string checker. Call trace: __fortify_panic+0x10/0x20 (P) kasan_strings+0x980/0x9b0 kunit_try_run_case+0x68/0x190 kunit_generic_run_threadfn_adapter+0x34/0x68 kthread+0x1c4/0x228 ret_from_fork+0x10/0x20 Code: d503233f a9bf7bfd 910003fd 9424b243 (d4210000) ---[ end trace 0000000000000000 ]--- note: kunit_try_catch[128] exited with irqs disabled note: kunit_try_catch[128] exited with preempt_count 1 # kasan_strings: try faulted: last ** replaying previous printk message ** # kasan_strings: try faulted: last line seen mm/kasan/kasan_test_c.c:1600 # kasan_strings: internal error occurred preventing test case from running: -4 Link: https://lkml.kernel.org/r/20250801120236.2962642-1-yeoreum.yun@arm.com Fixes: 73228c7ecc5e ("KASAN: port KASAN Tests to KUnit") Signed-off-by: Yeoreum Yun Cc: Alexander Potapenko Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Dmitriy Vyukov Cc: Vincenzo Frascino Cc: Signed-off-by: Andrew Morton --- mm/kasan/kasan_test_c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c index e0968acc03aa63..f4b17984b627a6 100644 --- a/mm/kasan/kasan_test_c.c +++ b/mm/kasan/kasan_test_c.c @@ -1578,9 +1578,11 @@ static void kasan_strings(struct kunit *test) ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); + OPTIMIZER_HIDE_VAR(ptr); src = kmalloc(KASAN_GRANULE_SIZE, GFP_KERNEL | __GFP_ZERO); strscpy(src, "f0cacc1a0000000", KASAN_GRANULE_SIZE); + OPTIMIZER_HIDE_VAR(src); /* * Make sure that strscpy() does not trigger KASAN if it overreads into From 08c7c253e032863199da4f089bd0ccab5d1a4876 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 18 Aug 2025 18:39:12 +0200 Subject: [PATCH 0730/1292] mm/kasan: fix vmalloc shadow memory (de-)population races While working on the lazy MMU mode enablement for s390 I hit pretty curious issues in the kasan code. The first is related to a custom kasan-based sanitizer aimed at catching invalid accesses to PTEs and is inspired by [1] conversation. The kasan complains on valid PTE accesses, while the shadow memory is reported as unpoisoned: [ 102.783993] ================================================================== [ 102.784008] BUG: KASAN: out-of-bounds in set_pte_range+0x36c/0x390 [ 102.784016] Read of size 8 at addr 0000780084cf9608 by task vmalloc_test/0/5542 [ 102.784019] [ 102.784040] CPU: 1 UID: 0 PID: 5542 Comm: vmalloc_test/0 Kdump: loaded Tainted: G OE 6.16.0-gcc-ipte-kasan-11657-gb2d930c4950e #340 PREEMPT [ 102.784047] Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE [ 102.784049] Hardware name: IBM 8561 T01 703 (LPAR) [ 102.784052] Call Trace: [ 102.784054] [<00007fffe0147ac0>] dump_stack_lvl+0xe8/0x140 [ 102.784059] [<00007fffe0112484>] print_address_description.constprop.0+0x34/0x2d0 [ 102.784066] [<00007fffe011282c>] print_report+0x10c/0x1f8 [ 102.784071] [<00007fffe090785a>] kasan_report+0xfa/0x220 [ 102.784078] [<00007fffe01d3dec>] set_pte_range+0x36c/0x390 [ 102.784083] [<00007fffe01d41c2>] leave_ipte_batch+0x3b2/0xb10 [ 102.784088] [<00007fffe07d3650>] apply_to_pte_range+0x2f0/0x4e0 [ 102.784094] [<00007fffe07e62e4>] apply_to_pmd_range+0x194/0x3e0 [ 102.784099] [<00007fffe07e820e>] __apply_to_page_range+0x2fe/0x7a0 [ 102.784104] [<00007fffe07e86d8>] apply_to_page_range+0x28/0x40 [ 102.784109] [<00007fffe090a3ec>] __kasan_populate_vmalloc+0xec/0x310 [ 102.784114] [<00007fffe090aa36>] kasan_populate_vmalloc+0x96/0x130 [ 102.784118] [<00007fffe0833a04>] alloc_vmap_area+0x3d4/0xf30 [ 102.784123] [<00007fffe083a8ba>] __get_vm_area_node+0x1aa/0x4c0 [ 102.784127] [<00007fffe083c4f6>] __vmalloc_node_range_noprof+0x126/0x4e0 [ 102.784131] [<00007fffe083c980>] __vmalloc_node_noprof+0xd0/0x110 [ 102.784135] [<00007fffe083ca32>] vmalloc_noprof+0x32/0x40 [ 102.784139] [<00007fff608aa336>] fix_size_alloc_test+0x66/0x150 [test_vmalloc] [ 102.784147] [<00007fff608aa710>] test_func+0x2f0/0x430 [test_vmalloc] [ 102.784153] [<00007fffe02841f8>] kthread+0x3f8/0x7a0 [ 102.784159] [<00007fffe014d8b4>] __ret_from_fork+0xd4/0x7d0 [ 102.784164] [<00007fffe299c00a>] ret_from_fork+0xa/0x30 [ 102.784173] no locks held by vmalloc_test/0/5542. [ 102.784176] [ 102.784178] The buggy address belongs to the physical page: [ 102.784186] page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x84cf9 [ 102.784198] flags: 0x3ffff00000000000(node=0|zone=1|lastcpupid=0x1ffff) [ 102.784212] page_type: f2(table) [ 102.784225] raw: 3ffff00000000000 0000000000000000 0000000000000122 0000000000000000 [ 102.784234] raw: 0000000000000000 0000000000000000 f200000000000001 0000000000000000 [ 102.784248] page dumped because: kasan: bad access detected [ 102.784250] [ 102.784252] Memory state around the buggy address: [ 102.784260] 0000780084cf9500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 102.784274] 0000780084cf9580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 102.784277] >0000780084cf9600: fd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 102.784290] ^ [ 102.784293] 0000780084cf9680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 102.784303] 0000780084cf9700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 102.784306] ================================================================== The second issue hits when the custom sanitizer above is not implemented, but the kasan itself is still active: [ 1554.438028] Unable to handle kernel pointer dereference in virtual kernel address space [ 1554.438065] Failing address: 001c0ff0066f0000 TEID: 001c0ff0066f0403 [ 1554.438076] Fault in home space mode while using kernel ASCE. [ 1554.438103] AS:00000000059d400b R2:0000000ffec5c00b R3:00000000c6c9c007 S:0000000314470001 P:00000000d0ab413d [ 1554.438158] Oops: 0011 ilc:2 [#1]SMP [ 1554.438175] Modules linked in: test_vmalloc(E+) nft_fib_inet(E) nft_fib_ipv4(E) nft_fib_ipv6(E) nft_fib(E) nft_reject_inet(E) nf_reject_ipv4(E) nf_reject_ipv6(E) nft_reject(E) nft_ct(E) nft_chain_nat(E) nf_nat(E) nf_conntrack(E) nf_defrag_ipv6(E) nf_defrag_ipv4(E) nf_tables(E) sunrpc(E) pkey_pckmo(E) uvdevice(E) s390_trng(E) rng_core(E) eadm_sch(E) vfio_ccw(E) mdev(E) vfio_iommu_type1(E) vfio(E) sch_fq_codel(E) drm(E) loop(E) i2c_core(E) drm_panel_orientation_quirks(E) nfnetlink(E) ctcm(E) fsm(E) zfcp(E) scsi_transport_fc(E) diag288_wdt(E) watchdog(E) ghash_s390(E) prng(E) aes_s390(E) des_s390(E) libdes(E) sha3_512_s390(E) sha3_256_s390(E) sha512_s390(E) sha1_s390(E) sha_common(E) pkey(E) autofs4(E) [ 1554.438319] Unloaded tainted modules: pkey_uv(E):1 hmac_s390(E):2 [ 1554.438354] CPU: 1 UID: 0 PID: 1715 Comm: vmalloc_test/0 Kdump: loaded Tainted: G E 6.16.0-gcc-ipte-kasan-11657-gb2d930c4950e #350 PREEMPT [ 1554.438368] Tainted: [E]=UNSIGNED_MODULE [ 1554.438374] Hardware name: IBM 8561 T01 703 (LPAR) [ 1554.438381] Krnl PSW : 0704e00180000000 00007fffe1d3d6ae (memset+0x5e/0x98) [ 1554.438396] R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:2 PM:0 RI:0 EA:3 [ 1554.438409] Krnl GPRS: 0000000000000001 001c0ff0066f0000 001c0ff0066f0000 00000000000000f8 [ 1554.438418] 00000000000009fe 0000000000000009 0000000000000000 0000000000000002 [ 1554.438426] 0000000000005000 000078031ae655c8 00000feffdcf9f59 0000780258672a20 [ 1554.438433] 0000780243153500 00007f8033780000 00007fffe083a510 00007f7fee7cfa00 [ 1554.438452] Krnl Code: 00007fffe1d3d6a0: eb540008000c srlg %r5,%r4,8 00007fffe1d3d6a6: b9020055 ltgr %r5,%r5 #00007fffe1d3d6aa: a784000b brc 8,00007fffe1d3d6c0 >00007fffe1d3d6ae: 42301000 stc %r3,0(%r1) 00007fffe1d3d6b2: d2fe10011000 mvc 1(255,%r1),0(%r1) 00007fffe1d3d6b8: 41101100 la %r1,256(%r1) 00007fffe1d3d6bc: a757fff9 brctg %r5,00007fffe1d3d6ae 00007fffe1d3d6c0: 42301000 stc %r3,0(%r1) [ 1554.438539] Call Trace: [ 1554.438545] [<00007fffe1d3d6ae>] memset+0x5e/0x98 [ 1554.438552] ([<00007fffe083a510>] remove_vm_area+0x220/0x400) [ 1554.438562] [<00007fffe083a9d6>] vfree.part.0+0x26/0x810 [ 1554.438569] [<00007fff6073bd50>] fix_align_alloc_test+0x50/0x90 [test_vmalloc] [ 1554.438583] [<00007fff6073c73a>] test_func+0x46a/0x6c0 [test_vmalloc] [ 1554.438593] [<00007fffe0283ac8>] kthread+0x3f8/0x7a0 [ 1554.438603] [<00007fffe014d8b4>] __ret_from_fork+0xd4/0x7d0 [ 1554.438613] [<00007fffe299ac0a>] ret_from_fork+0xa/0x30 [ 1554.438622] INFO: lockdep is turned off. [ 1554.438627] Last Breaking-Event-Address: [ 1554.438632] [<00007fffe1d3d65c>] memset+0xc/0x98 [ 1554.438644] Kernel panic - not syncing: Fatal exception: panic_on_oops This series fixes the above issues and is a pre-requisite for the s390 lazy MMU mode implementation. test_vmalloc was used to stress-test the fixes. This patch (of 2): When vmalloc shadow memory is established the modification of the corresponding page tables is not protected by any locks. Instead, the locking is done per-PTE. This scheme however has defects. kasan_populate_vmalloc_pte() - while ptep_get() read is atomic the sequence pte_none(ptep_get()) is not. Doing that outside of the lock might lead to a concurrent PTE update and what could be seen as a shadow memory corruption as result. kasan_depopulate_vmalloc_pte() - by the time a page whose address was extracted from ptep_get() read and cached in a local variable outside of the lock is attempted to get free, could actually be freed already. To avoid these put ptep_get() itself and the code that manipulates the result of the read under lock. In addition, move freeing of the page out of the atomic context. Link: https://lkml.kernel.org/r/cover.1755528662.git.agordeev@linux.ibm.com Link: https://lkml.kernel.org/r/adb258634194593db294c0d1fb35646e894d6ead.1755528662.git.agordeev@linux.ibm.com Link: https://lore.kernel.org/linux-mm/5b0609c9-95ee-4e48-bb6d-98f57c5d2c31@arm.com/ [1] Fixes: 3c5c3cfb9ef4 ("kasan: support backing vmalloc space with real shadow memory") Signed-off-by: Alexander Gordeev Cc: Andrey Ryabinin Cc: Daniel Axtens Cc: Marc Rutland Cc: Ryan Roberts Signed-off-by: Andrew Morton --- mm/kasan/shadow.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index d2c70cd2afb1de..4d846d146d02c7 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -305,9 +305,6 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr, pte_t pte; int index; - if (likely(!pte_none(ptep_get(ptep)))) - return 0; - index = PFN_DOWN(addr - data->start); page = data->pages[index]; __memset(page_to_virt(page), KASAN_VMALLOC_INVALID, PAGE_SIZE); @@ -461,18 +458,19 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size) static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr, void *unused) { - unsigned long page; - - page = (unsigned long)__va(pte_pfn(ptep_get(ptep)) << PAGE_SHIFT); + pte_t pte; + int none; spin_lock(&init_mm.page_table_lock); - - if (likely(!pte_none(ptep_get(ptep)))) { + pte = ptep_get(ptep); + none = pte_none(pte); + if (likely(!none)) pte_clear(&init_mm, addr, ptep); - free_page(page); - } spin_unlock(&init_mm.page_table_lock); + if (likely(!none)) + __free_page(pfn_to_page(pte_pfn(pte))); + return 0; } From c519c3c0a1133c408e83a383aa4dd30010aa5d71 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 18 Aug 2025 18:39:13 +0200 Subject: [PATCH 0731/1292] mm/kasan: avoid lazy MMU mode hazards Functions __kasan_populate_vmalloc() and __kasan_depopulate_vmalloc() use apply_to_pte_range(), which enters lazy MMU mode. In that mode updating PTEs may not be observed until the mode is left. That may lead to a situation in which otherwise correct reads and writes to a PTE using ptep_get(), set_pte(), pte_clear() and other access primitives bring wrong results when the vmalloc shadow memory is being (de-)populated. To avoid these hazards leave the lazy MMU mode before and re-enter it after each PTE manipulation. Link: https://lkml.kernel.org/r/0d2efb7ddddbff6b288fbffeeb10166e90771718.1755528662.git.agordeev@linux.ibm.com Fixes: 3c5c3cfb9ef4 ("kasan: support backing vmalloc space with real shadow memory") Signed-off-by: Alexander Gordeev Cc: Andrey Ryabinin Cc: Daniel Axtens Cc: Marc Rutland Cc: Ryan Roberts Signed-off-by: Andrew Morton --- mm/kasan/shadow.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index 4d846d146d02c7..e2ceebf737ef7b 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -305,6 +305,8 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr, pte_t pte; int index; + arch_leave_lazy_mmu_mode(); + index = PFN_DOWN(addr - data->start); page = data->pages[index]; __memset(page_to_virt(page), KASAN_VMALLOC_INVALID, PAGE_SIZE); @@ -317,6 +319,8 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr, } spin_unlock(&init_mm.page_table_lock); + arch_enter_lazy_mmu_mode(); + return 0; } @@ -461,6 +465,8 @@ static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr, pte_t pte; int none; + arch_leave_lazy_mmu_mode(); + spin_lock(&init_mm.page_table_lock); pte = ptep_get(ptep); none = pte_none(pte); @@ -471,6 +477,8 @@ static int kasan_depopulate_vmalloc_pte(pte_t *ptep, unsigned long addr, if (likely(!none)) __free_page(pfn_to_page(pte_pfn(pte))); + arch_enter_lazy_mmu_mode(); + return 0; } From 51337a9a3a404fde0f5337662ffc7699793dfeb5 Mon Sep 17 00:00:00 2001 From: Ada Couprie Diaz Date: Thu, 21 Aug 2025 13:07:35 +0100 Subject: [PATCH 0732/1292] kasan: fix GCC mem-intrinsic prefix with sw tags GCC doesn't support "hwasan-kernel-mem-intrinsic-prefix", only "asan-kernel-mem-intrinsic-prefix"[0], while LLVM supports both. This is already taken into account when checking "CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX", but not in the KASAN Makefile adding those parameters when "CONFIG_KASAN_SW_TAGS" is enabled. Replace the version check with "CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX", which already validates that mem-intrinsic prefix parameter can be used, and choose the correct name depending on compiler. GCC 13 and above trigger "CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX" which prevents `mem{cpy,move,set}()` being redefined in "mm/kasan/shadow.c" since commit 36be5cba99f6 ("kasan: treat meminstrinsic as builtins in uninstrumented files"), as we expect the compiler to prefix those calls with `__(hw)asan_` instead. But as the option passed to GCC has been incorrect, the compiler has not been emitting those prefixes, effectively never calling the instrumented versions of `mem{cpy,move,set}()` with "CONFIG_KASAN_SW_TAGS" enabled. If "CONFIG_FORTIFY_SOURCES" is enabled, this issue would be mitigated as it redefines `mem{cpy,move,set}()` and properly aliases the `__underlying_mem*()` that will be called to the instrumented versions. Link: https://lkml.kernel.org/r/20250821120735.156244-1-ada.coupriediaz@arm.com Link: https://gcc.gnu.org/onlinedocs/gcc-13.4.0/gcc/Optimize-Options.html [0] Signed-off-by: Ada Couprie Diaz Fixes: 36be5cba99f6 ("kasan: treat meminstrinsic as builtins in uninstrumented files") Reviewed-by: Yeoreum Yun Cc: Alexander Potapenko Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Dmitriy Vyukov Cc: Marco Elver Cc: Marc Rutland Cc: Michael Ellerman Cc: Nathan Chancellor Cc: Vincenzo Frascino Cc: Signed-off-by: Andrew Morton --- scripts/Makefile.kasan | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 693dbbebebba10..0ba2aac3b8dc00 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -86,10 +86,14 @@ kasan_params += hwasan-instrument-stack=$(stack_enable) \ hwasan-use-short-granules=0 \ hwasan-inline-all-checks=0 -# Instrument memcpy/memset/memmove calls by using instrumented __hwasan_mem*(). -ifeq ($(call clang-min-version, 150000)$(call gcc-min-version, 130000),y) - kasan_params += hwasan-kernel-mem-intrinsic-prefix=1 -endif +# Instrument memcpy/memset/memmove calls by using instrumented __(hw)asan_mem*(). +ifdef CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX + ifdef CONFIG_CC_IS_GCC + kasan_params += asan-kernel-mem-intrinsic-prefix=1 + else + kasan_params += hwasan-kernel-mem-intrinsic-prefix=1 + endif +endif # CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX endif # CONFIG_KASAN_SW_TAGS From 6310c149e5dede74bb47110e0d7a38c78772c152 Mon Sep 17 00:00:00 2001 From: Brian Mak Date: Tue, 5 Aug 2025 14:15:26 -0700 Subject: [PATCH 0733/1292] kexec: add KEXEC_FILE_NO_CMA as a legal flag Commit 07d24902977e ("kexec: enable CMA based contiguous allocation") introduces logic to use CMA-based allocation in kexec by default. As part of the changes, it introduces a kexec_file_load flag to disable the use of CMA allocations from userspace. However, this flag is broken since it is missing from the list of legal flags for kexec_file_load. kexec_file_load returns EINVAL when attempting to use the flag. Fix this by adding the KEXEC_FILE_NO_CMA flag to the list of legal flags for kexec_file_load. Without this fix, kexec_file_load syscall will failed and return '-EINVAL' when KEXEC_FILE_NO_CMA is specified. Link: https://lkml.kernel.org/r/20250805211527.122367-2-makb@juniper.net Fixes: 07d24902977e ("kexec: enable CMA based contiguous allocation") Signed-off-by: Brian Mak Acked-by: Baoquan He Cc: Alexander Graf Cc: Borislav Betkov Cc: Dave Young Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Rob Herring Cc: Saravana Kannan Cc: Thomas Gleinxer Signed-off-by: Andrew Morton --- include/linux/kexec.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 1b10a5d84b68c6..39fe3e6cd282f8 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -460,7 +460,8 @@ bool kexec_load_permitted(int kexec_image_type); /* List of defined/legal kexec file flags */ #define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \ - KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_DEBUG) + KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_DEBUG | \ + KEXEC_FILE_NO_CMA) /* flag to track if kexec reboot is in progress */ extern bool kexec_in_progress; From 9f68eabab9d9aaa764a8d234c4170119e6518102 Mon Sep 17 00:00:00 2001 From: Quanmin Yan Date: Thu, 21 Aug 2025 20:55:55 +0800 Subject: [PATCH 0734/1292] mm/damon/core: prevent unnecessary overflow in damos_set_effective_quota() On 32-bit systems, the throughput calculation in damos_set_effective_quota() is prone to unnecessary multiplication overflow. Using mult_frac() to fix it. Andrew Paniakin also recently found and privately reported this issue, on 64 bit systems. This can also happen on 64-bit systems, once the charged size exceeds ~17 TiB. On systems running for long time in production, this issue can actually happen. More specifically, when a DAMOS scheme having the time quota run for longtime, throughput calculation can overflow and set esz too small. As a result, speed of the scheme get unexpectedly slow. Link: https://lkml.kernel.org/r/20250821125555.3020951-1-yanquanmin1@huawei.com Fixes: 1cd243030059 ("mm/damon/schemes: implement time quota") Signed-off-by: Quanmin Yan Reported-by: Andrew Paniakin Reviewed-by: SeongJae Park Cc: Kefeng Wang Cc: ze zuo Cc: [5.16+] Signed-off-by: Andrew Morton --- mm/damon/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/damon/core.c b/mm/damon/core.c index 70eff5cbe6ee11..106ee8b0f2d5f1 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -2073,8 +2073,8 @@ static void damos_set_effective_quota(struct damos_quota *quota) if (quota->ms) { if (quota->total_charged_ns) - throughput = quota->total_charged_sz * 1000000 / - quota->total_charged_ns; + throughput = mult_frac(quota->total_charged_sz, 1000000, + quota->total_charged_ns); else throughput = PAGE_SIZE * 1024; esz = min(throughput * quota->ms, esz); From c3576889d87b603cb66b417e08844a53c1077a37 Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Thu, 7 Aug 2025 20:35:45 +0200 Subject: [PATCH 0735/1292] mm: fix accounting of memmap pages For !CONFIG_SPARSEMEM_VMEMMAP, memmap page accounting is currently done upfront in sparse_buffer_init(). However, sparse_buffer_alloc() may return NULL in failure scenario. Also, memmap pages may be allocated either from the memblock allocator during early boot or from the buddy allocator. When removed via arch_remove_memory(), accounting of memmap pages must reflect the original allocation source. To ensure correctness: * Account memmap pages after successful allocation in sparse_init_nid() and section_activate(). * Account memmap pages in section_deactivate() based on allocation source. Link: https://lkml.kernel.org/r/20250807183545.1424509-1-sumanthk@linux.ibm.com Fixes: 15995a352474 ("mm: report per-page metadata information") Signed-off-by: Sumanth Korikkar Suggested-by: David Hildenbrand Reviewed-by: Wei Yang Cc: Alexander Gordeev Cc: Gerald Schaefer Cc: Heiko Carstens Cc: Vasily Gorbik Cc: Signed-off-by: Andrew Morton --- mm/sparse-vmemmap.c | 5 ----- mm/sparse.c | 15 +++++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index fd2ab5118e13df..41aa0493eb037e 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c @@ -578,11 +578,6 @@ struct page * __meminit __populate_section_memmap(unsigned long pfn, if (r < 0) return NULL; - if (system_state == SYSTEM_BOOTING) - memmap_boot_pages_add(DIV_ROUND_UP(end - start, PAGE_SIZE)); - else - memmap_pages_add(DIV_ROUND_UP(end - start, PAGE_SIZE)); - return pfn_to_page(pfn); } diff --git a/mm/sparse.c b/mm/sparse.c index 3c012cf83cc2b4..e6075b62240707 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -454,9 +454,6 @@ static void __init sparse_buffer_init(unsigned long size, int nid) */ sparsemap_buf = memmap_alloc(size, section_map_size(), addr, nid, true); sparsemap_buf_end = sparsemap_buf + size; -#ifndef CONFIG_SPARSEMEM_VMEMMAP - memmap_boot_pages_add(DIV_ROUND_UP(size, PAGE_SIZE)); -#endif } static void __init sparse_buffer_fini(void) @@ -567,6 +564,8 @@ static void __init sparse_init_nid(int nid, unsigned long pnum_begin, sparse_buffer_fini(); goto failed; } + memmap_boot_pages_add(DIV_ROUND_UP(PAGES_PER_SECTION * sizeof(struct page), + PAGE_SIZE)); sparse_init_early_section(nid, map, pnum, 0); } } @@ -680,7 +679,6 @@ static void depopulate_section_memmap(unsigned long pfn, unsigned long nr_pages, unsigned long start = (unsigned long) pfn_to_page(pfn); unsigned long end = start + nr_pages * sizeof(struct page); - memmap_pages_add(-1L * (DIV_ROUND_UP(end - start, PAGE_SIZE))); vmemmap_free(start, end, altmap); } static void free_map_bootmem(struct page *memmap) @@ -856,10 +854,14 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages, * The memmap of early sections is always fully populated. See * section_activate() and pfn_valid() . */ - if (!section_is_early) + if (!section_is_early) { + memmap_pages_add(-1L * (DIV_ROUND_UP(nr_pages * sizeof(struct page), PAGE_SIZE))); depopulate_section_memmap(pfn, nr_pages, altmap); - else if (memmap) + } else if (memmap) { + memmap_boot_pages_add(-1L * (DIV_ROUND_UP(nr_pages * sizeof(struct page), + PAGE_SIZE))); free_map_bootmem(memmap); + } if (empty) ms->section_mem_map = (unsigned long)NULL; @@ -904,6 +906,7 @@ static struct page * __meminit section_activate(int nid, unsigned long pfn, section_deactivate(pfn, nr_pages, altmap); return ERR_PTR(-ENOMEM); } + memmap_pages_add(DIV_ROUND_UP(nr_pages * sizeof(struct page), PAGE_SIZE)); return memmap; } From 2ce3d282bd5050fca8577defeff08ada0d55d062 Mon Sep 17 00:00:00 2001 From: wangzijie Date: Mon, 18 Aug 2025 20:31:02 +0800 Subject: [PATCH 0736/1292] proc: fix missing pde_set_flags() for net proc files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid potential UAF issues during module removal races, we use pde_set_flags() to save proc_ops flags in PDE itself before proc_register(), and then use pde_has_proc_*() helpers instead of directly dereferencing pde->proc_ops->*. However, the pde_set_flags() call was missing when creating net related proc files. This omission caused incorrect behavior which FMODE_LSEEK was being cleared inappropriately in proc_reg_open() for net proc files. Lars reported it in this link[1]. Fix this by ensuring pde_set_flags() is called when register proc entry, and add NULL check for proc_ops in pde_set_flags(). [wangzijie1@honor.com: stash pde->proc_ops in a local const variable, per Christian] Link: https://lkml.kernel.org/r/20250821105806.1453833-1-wangzijie1@honor.com Link: https://lkml.kernel.org/r/20250818123102.959595-1-wangzijie1@honor.com Link: https://lore.kernel.org/all/20250815195616.64497967@chagall.paradoxon.rec/ [1] Fixes: ff7ec8dc1b64 ("proc: use the same treatment to check proc_lseek as ones for proc_read_iter et.al") Signed-off-by: wangzijie Reported-by: Lars Wendler Tested-by: Stefano Brivio Tested-by: Petr Vaněk Tested by: Lars Wendler Cc: Alexei Starovoitov Cc: Alexey Dobriyan Cc: Al Viro Cc: "Edgecombe, Rick P" Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Kirill A. Shutemov Cc: wangzijie Cc: Signed-off-by: Andrew Morton --- fs/proc/generic.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 76e800e38c8f64..bd0c099cfdd2a5 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -367,6 +367,25 @@ static const struct inode_operations proc_dir_inode_operations = { .setattr = proc_notify_change, }; +static void pde_set_flags(struct proc_dir_entry *pde) +{ + const struct proc_ops *proc_ops = pde->proc_ops; + + if (!proc_ops) + return; + + if (proc_ops->proc_flags & PROC_ENTRY_PERMANENT) + pde->flags |= PROC_ENTRY_PERMANENT; + if (proc_ops->proc_read_iter) + pde->flags |= PROC_ENTRY_proc_read_iter; +#ifdef CONFIG_COMPAT + if (proc_ops->proc_compat_ioctl) + pde->flags |= PROC_ENTRY_proc_compat_ioctl; +#endif + if (proc_ops->proc_lseek) + pde->flags |= PROC_ENTRY_proc_lseek; +} + /* returns the registered entry, or frees dp and returns NULL on failure */ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, struct proc_dir_entry *dp) @@ -374,6 +393,8 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, if (proc_alloc_inum(&dp->low_ino)) goto out_free_entry; + pde_set_flags(dp); + write_lock(&proc_subdir_lock); dp->parent = dir; if (pde_subdir_insert(dir, dp) == false) { @@ -561,20 +582,6 @@ struct proc_dir_entry *proc_create_reg(const char *name, umode_t mode, return p; } -static void pde_set_flags(struct proc_dir_entry *pde) -{ - if (pde->proc_ops->proc_flags & PROC_ENTRY_PERMANENT) - pde->flags |= PROC_ENTRY_PERMANENT; - if (pde->proc_ops->proc_read_iter) - pde->flags |= PROC_ENTRY_proc_read_iter; -#ifdef CONFIG_COMPAT - if (pde->proc_ops->proc_compat_ioctl) - pde->flags |= PROC_ENTRY_proc_compat_ioctl; -#endif - if (pde->proc_ops->proc_lseek) - pde->flags |= PROC_ENTRY_proc_lseek; -} - struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops, void *data) @@ -585,7 +592,6 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, if (!p) return NULL; p->proc_ops = proc_ops; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_data); @@ -636,7 +642,6 @@ struct proc_dir_entry *proc_create_seq_private(const char *name, umode_t mode, p->proc_ops = &proc_seq_ops; p->seq_ops = ops; p->state_size = state_size; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_seq_private); @@ -667,7 +672,6 @@ struct proc_dir_entry *proc_create_single_data(const char *name, umode_t mode, return NULL; p->proc_ops = &proc_single_ops; p->single_show = show; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_single_data); From 7cc183f2e67d19b03ee5c13a6664b8c6cc37ff9d Mon Sep 17 00:00:00 2001 From: Harry Yoo Date: Mon, 18 Aug 2025 11:02:04 +0900 Subject: [PATCH 0737/1292] mm: move page table sync declarations to linux/pgtable.h During our internal testing, we started observing intermittent boot failures when the machine uses 4-level paging and has a large amount of persistent memory: BUG: unable to handle page fault for address: ffffe70000000034 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: 0002 [#1] SMP NOPTI RIP: 0010:__init_single_page+0x9/0x6d Call Trace: __init_zone_device_page+0x17/0x5d memmap_init_zone_device+0x154/0x1bb pagemap_range+0x2e0/0x40f memremap_pages+0x10b/0x2f0 devm_memremap_pages+0x1e/0x60 dev_dax_probe+0xce/0x2ec [device_dax] dax_bus_probe+0x6d/0xc9 [... snip ...] It turns out that the kernel panics while initializing vmemmap (struct page array) when the vmemmap region spans two PGD entries, because the new PGD entry is only installed in init_mm.pgd, but not in the page tables of other tasks. And looking at __populate_section_memmap(): if (vmemmap_can_optimize(altmap, pgmap)) // does not sync top level page tables r = vmemmap_populate_compound_pages(pfn, start, end, nid, pgmap); else // sync top level page tables in x86 r = vmemmap_populate(start, end, nid, altmap); In the normal path, vmemmap_populate() in arch/x86/mm/init_64.c synchronizes the top level page table (See commit 9b861528a801 ("x86-64, mem: Update all PGDs for direct mapping and vmemmap mapping changes")) so that all tasks in the system can see the new vmemmap area. However, when vmemmap_can_optimize() returns true, the optimized path skips synchronization of top-level page tables. This is because vmemmap_populate_compound_pages() is implemented in core MM code, which does not handle synchronization of the top-level page tables. Instead, the core MM has historically relied on each architecture to perform this synchronization manually. We're not the first party to encounter a crash caused by not-sync'd top level page tables: earlier this year, Gwan-gyeong Mun attempted to address the issue [1] [2] after hitting a kernel panic when x86 code accessed the vmemmap area before the corresponding top-level entries were synced. At that time, the issue was believed to be triggered only when struct page was enlarged for debugging purposes, and the patch did not get further updates. It turns out that current approach of relying on each arch to handle the page table sync manually is fragile because 1) it's easy to forget to sync the top level page table, and 2) it's also easy to overlook that the kernel should not access the vmemmap and direct mapping areas before the sync. # The solution: Make page table sync more code robust and harder to miss To address this, Dave Hansen suggested [3] [4] introducing {pgd,p4d}_populate_kernel() for updating kernel portion of the page tables and allow each architecture to explicitly perform synchronization when installing top-level entries. With this approach, we no longer need to worry about missing the sync step, reducing the risk of future regressions. The new interface reuses existing ARCH_PAGE_TABLE_SYNC_MASK, PGTBL_P*D_MODIFIED and arch_sync_kernel_mappings() facility used by vmalloc and ioremap to synchronize page tables. pgd_populate_kernel() looks like this: static inline void pgd_populate_kernel(unsigned long addr, pgd_t *pgd, p4d_t *p4d) { pgd_populate(&init_mm, pgd, p4d); if (ARCH_PAGE_TABLE_SYNC_MASK & PGTBL_PGD_MODIFIED) arch_sync_kernel_mappings(addr, addr); } It is worth noting that vmalloc() and apply_to_range() carefully synchronizes page tables by calling p*d_alloc_track() and arch_sync_kernel_mappings(), and thus they are not affected by this patch series. This series was hugely inspired by Dave Hansen's suggestion and hence added Suggested-by: Dave Hansen. Cc stable because lack of this series opens the door to intermittent boot failures. This patch (of 3): Move ARCH_PAGE_TABLE_SYNC_MASK and arch_sync_kernel_mappings() to linux/pgtable.h so that they can be used outside of vmalloc and ioremap. Link: https://lkml.kernel.org/r/20250818020206.4517-1-harry.yoo@oracle.com Link: https://lkml.kernel.org/r/20250818020206.4517-2-harry.yoo@oracle.com Link: https://lore.kernel.org/linux-mm/20250220064105.808339-1-gwan-gyeong.mun@intel.com [1] Link: https://lore.kernel.org/linux-mm/20250311114420.240341-1-gwan-gyeong.mun@intel.com [2] Link: https://lore.kernel.org/linux-mm/d1da214c-53d3-45ac-a8b6-51821c5416e4@intel.com [3] Link: https://lore.kernel.org/linux-mm/4d800744-7b88-41aa-9979-b245e8bf794b@intel.com [4] Fixes: 8d400913c231 ("x86/vmemmap: handle unpopulated sub-pmd ranges") Signed-off-by: Harry Yoo Acked-by: Kiryl Shutsemau Reviewed-by: Mike Rapoport (Microsoft) Reviewed-by: "Uladzislau Rezki (Sony)" Reviewed-by: Lorenzo Stoakes Acked-by: David Hildenbrand Cc: Alexander Potapenko Cc: Alistair Popple Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: "Aneesh Kumar K.V" Cc: Anshuman Khandual Cc: Ard Biesheuvel Cc: Arnd Bergmann Cc: bibo mao Cc: Borislav Betkov Cc: Christoph Lameter (Ampere) Cc: Dennis Zhou Cc: Dev Jain Cc: Dmitriy Vyukov Cc: Gwan-gyeong Mun Cc: Ingo Molnar Cc: Jane Chu Cc: Joao Martins Cc: Joerg Roedel Cc: John Hubbard Cc: Kevin Brodsky Cc: Liam Howlett Cc: Michal Hocko Cc: Oscar Salvador Cc: Peter Xu Cc: Peter Zijlstra Cc: Qi Zheng Cc: Ryan Roberts Cc: Suren Baghdasaryan Cc: Tejun Heo Cc: Thomas Gleinxer Cc: Thomas Huth Cc: Vincenzo Frascino Cc: Vlastimil Babka Cc: Dave Hansen Cc: Signed-off-by: Andrew Morton --- include/linux/pgtable.h | 16 ++++++++++++++++ include/linux/vmalloc.h | 16 ---------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index 4c035637eeb77f..ba699df6ef69c2 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -1467,6 +1467,22 @@ static inline void modify_prot_commit_ptes(struct vm_area_struct *vma, unsigned } #endif +/* + * Architectures can set this mask to a combination of PGTBL_P?D_MODIFIED values + * and let generic vmalloc and ioremap code know when arch_sync_kernel_mappings() + * needs to be called. + */ +#ifndef ARCH_PAGE_TABLE_SYNC_MASK +#define ARCH_PAGE_TABLE_SYNC_MASK 0 +#endif + +/* + * There is no default implementation for arch_sync_kernel_mappings(). It is + * relied upon the compiler to optimize calls out if ARCH_PAGE_TABLE_SYNC_MASK + * is 0. + */ +void arch_sync_kernel_mappings(unsigned long start, unsigned long end); + #endif /* CONFIG_MMU */ /* diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index fdc9aeb74a446b..2759dac6be44ea 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -219,22 +219,6 @@ extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, int vmap_pages_range(unsigned long addr, unsigned long end, pgprot_t prot, struct page **pages, unsigned int page_shift); -/* - * Architectures can set this mask to a combination of PGTBL_P?D_MODIFIED values - * and let generic vmalloc and ioremap code know when arch_sync_kernel_mappings() - * needs to be called. - */ -#ifndef ARCH_PAGE_TABLE_SYNC_MASK -#define ARCH_PAGE_TABLE_SYNC_MASK 0 -#endif - -/* - * There is no default implementation for arch_sync_kernel_mappings(). It is - * relied upon the compiler to optimize calls out if ARCH_PAGE_TABLE_SYNC_MASK - * is 0. - */ -void arch_sync_kernel_mappings(unsigned long start, unsigned long end); - /* * Lowlevel-APIs (not for driver use!) */ From f2d2f9598ebb0158a3fe17cda0106d7752e654a2 Mon Sep 17 00:00:00 2001 From: Harry Yoo Date: Mon, 18 Aug 2025 11:02:05 +0900 Subject: [PATCH 0738/1292] mm: introduce and use {pgd,p4d}_populate_kernel() Introduce and use {pgd,p4d}_populate_kernel() in core MM code when populating PGD and P4D entries for the kernel address space. These helpers ensure proper synchronization of page tables when updating the kernel portion of top-level page tables. Until now, the kernel has relied on each architecture to handle synchronization of top-level page tables in an ad-hoc manner. For example, see commit 9b861528a801 ("x86-64, mem: Update all PGDs for direct mapping and vmemmap mapping changes"). However, this approach has proven fragile for following reasons: 1) It is easy to forget to perform the necessary page table synchronization when introducing new changes. For instance, commit 4917f55b4ef9 ("mm/sparse-vmemmap: improve memory savings for compound devmaps") overlooked the need to synchronize page tables for the vmemmap area. 2) It is also easy to overlook that the vmemmap and direct mapping areas must not be accessed before explicit page table synchronization. For example, commit 8d400913c231 ("x86/vmemmap: handle unpopulated sub-pmd ranges")) caused crashes by accessing the vmemmap area before calling sync_global_pgds(). To address this, as suggested by Dave Hansen, introduce _kernel() variants of the page table population helpers, which invoke architecture-specific hooks to properly synchronize page tables. These are introduced in a new header file, include/linux/pgalloc.h, so they can be called from common code. They reuse existing infrastructure for vmalloc and ioremap. Synchronization requirements are determined by ARCH_PAGE_TABLE_SYNC_MASK, and the actual synchronization is performed by arch_sync_kernel_mappings(). This change currently targets only x86_64, so only PGD and P4D level helpers are introduced. Currently, these helpers are no-ops since no architecture sets PGTBL_{PGD,P4D}_MODIFIED in ARCH_PAGE_TABLE_SYNC_MASK. In theory, PUD and PMD level helpers can be added later if needed by other architectures. For now, 32-bit architectures (x86-32 and arm) only handle PGTBL_PMD_MODIFIED, so p*d_populate_kernel() will never affect them unless we introduce a PMD level helper. [harry.yoo@oracle.com: fix KASAN build error due to p*d_populate_kernel()] Link: https://lkml.kernel.org/r/20250822020727.202749-1-harry.yoo@oracle.com Link: https://lkml.kernel.org/r/20250818020206.4517-3-harry.yoo@oracle.com Fixes: 8d400913c231 ("x86/vmemmap: handle unpopulated sub-pmd ranges") Signed-off-by: Harry Yoo Suggested-by: Dave Hansen Acked-by: Kiryl Shutsemau Reviewed-by: Mike Rapoport (Microsoft) Reviewed-by: Lorenzo Stoakes Acked-by: David Hildenbrand Cc: Alexander Potapenko Cc: Alistair Popple Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: "Aneesh Kumar K.V" Cc: Anshuman Khandual Cc: Ard Biesheuvel Cc: Arnd Bergmann Cc: bibo mao Cc: Borislav Betkov Cc: Christoph Lameter (Ampere) Cc: Dennis Zhou Cc: Dev Jain Cc: Dmitriy Vyukov Cc: Gwan-gyeong Mun Cc: Ingo Molnar Cc: Jane Chu Cc: Joao Martins Cc: Joerg Roedel Cc: John Hubbard Cc: Kevin Brodsky Cc: Liam Howlett Cc: Michal Hocko Cc: Oscar Salvador Cc: Peter Xu Cc: Peter Zijlstra Cc: Qi Zheng Cc: Ryan Roberts Cc: Suren Baghdasaryan Cc: Tejun Heo Cc: Thomas Gleinxer Cc: Thomas Huth Cc: "Uladzislau Rezki (Sony)" Cc: Vincenzo Frascino Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton --- include/linux/pgalloc.h | 29 +++++++++++++++++++++++++++++ include/linux/pgtable.h | 13 +++++++------ mm/kasan/init.c | 12 ++++++------ mm/percpu.c | 6 +++--- mm/sparse-vmemmap.c | 6 +++--- 5 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 include/linux/pgalloc.h diff --git a/include/linux/pgalloc.h b/include/linux/pgalloc.h new file mode 100644 index 00000000000000..9174fa59bbc54d --- /dev/null +++ b/include/linux/pgalloc.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_PGALLOC_H +#define _LINUX_PGALLOC_H + +#include +#include + +/* + * {pgd,p4d}_populate_kernel() are defined as macros to allow + * compile-time optimization based on the configured page table levels. + * Without this, linking may fail because callers (e.g., KASAN) may rely + * on calls to these functions being optimized away when passing symbols + * that exist only for certain page table levels. + */ +#define pgd_populate_kernel(addr, pgd, p4d) \ + do { \ + pgd_populate(&init_mm, pgd, p4d); \ + if (ARCH_PAGE_TABLE_SYNC_MASK & PGTBL_PGD_MODIFIED) \ + arch_sync_kernel_mappings(addr, addr); \ + } while (0) + +#define p4d_populate_kernel(addr, p4d, pud) \ + do { \ + p4d_populate(&init_mm, p4d, pud); \ + if (ARCH_PAGE_TABLE_SYNC_MASK & PGTBL_P4D_MODIFIED) \ + arch_sync_kernel_mappings(addr, addr); \ + } while (0) + +#endif /* _LINUX_PGALLOC_H */ diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index ba699df6ef69c2..2b80fd456c8b55 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -1469,8 +1469,8 @@ static inline void modify_prot_commit_ptes(struct vm_area_struct *vma, unsigned /* * Architectures can set this mask to a combination of PGTBL_P?D_MODIFIED values - * and let generic vmalloc and ioremap code know when arch_sync_kernel_mappings() - * needs to be called. + * and let generic vmalloc, ioremap and page table update code know when + * arch_sync_kernel_mappings() needs to be called. */ #ifndef ARCH_PAGE_TABLE_SYNC_MASK #define ARCH_PAGE_TABLE_SYNC_MASK 0 @@ -1954,10 +1954,11 @@ static inline bool arch_has_pfn_modify_check(void) /* * Page Table Modification bits for pgtbl_mod_mask. * - * These are used by the p?d_alloc_track*() set of functions an in the generic - * vmalloc/ioremap code to track at which page-table levels entries have been - * modified. Based on that the code can better decide when vmalloc and ioremap - * mapping changes need to be synchronized to other page-tables in the system. + * These are used by the p?d_alloc_track*() and p*d_populate_kernel() + * functions in the generic vmalloc, ioremap and page table update code + * to track at which page-table levels entries have been modified. + * Based on that the code can better decide when page table changes need + * to be synchronized to other page-tables in the system. */ #define __PGTBL_PGD_MODIFIED 0 #define __PGTBL_P4D_MODIFIED 1 diff --git a/mm/kasan/init.c b/mm/kasan/init.c index ced6b29fcf763f..8fce3370c84ea6 100644 --- a/mm/kasan/init.c +++ b/mm/kasan/init.c @@ -13,9 +13,9 @@ #include #include #include +#include #include -#include #include "kasan.h" @@ -191,7 +191,7 @@ static int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, pud_t *pud; pmd_t *pmd; - p4d_populate(&init_mm, p4d, + p4d_populate_kernel(addr, p4d, lm_alias(kasan_early_shadow_pud)); pud = pud_offset(p4d, addr); pud_populate(&init_mm, pud, @@ -212,7 +212,7 @@ static int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, } else { p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); pud_init(p); - p4d_populate(&init_mm, p4d, p); + p4d_populate_kernel(addr, p4d, p); } } zero_pud_populate(p4d, addr, next); @@ -251,10 +251,10 @@ int __ref kasan_populate_early_shadow(const void *shadow_start, * puds,pmds, so pgd_populate(), pud_populate() * is noops. */ - pgd_populate(&init_mm, pgd, + pgd_populate_kernel(addr, pgd, lm_alias(kasan_early_shadow_p4d)); p4d = p4d_offset(pgd, addr); - p4d_populate(&init_mm, p4d, + p4d_populate_kernel(addr, p4d, lm_alias(kasan_early_shadow_pud)); pud = pud_offset(p4d, addr); pud_populate(&init_mm, pud, @@ -273,7 +273,7 @@ int __ref kasan_populate_early_shadow(const void *shadow_start, if (!p) return -ENOMEM; } else { - pgd_populate(&init_mm, pgd, + pgd_populate_kernel(addr, pgd, early_alloc(PAGE_SIZE, NUMA_NO_NODE)); } } diff --git a/mm/percpu.c b/mm/percpu.c index d9cbaee92b6053..a56f35dcc417e6 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -3108,7 +3108,7 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, #endif /* BUILD_EMBED_FIRST_CHUNK */ #ifdef BUILD_PAGE_FIRST_CHUNK -#include +#include #ifndef P4D_TABLE_SIZE #define P4D_TABLE_SIZE PAGE_SIZE @@ -3134,13 +3134,13 @@ void __init __weak pcpu_populate_pte(unsigned long addr) if (pgd_none(*pgd)) { p4d = memblock_alloc_or_panic(P4D_TABLE_SIZE, P4D_TABLE_SIZE); - pgd_populate(&init_mm, pgd, p4d); + pgd_populate_kernel(addr, pgd, p4d); } p4d = p4d_offset(pgd, addr); if (p4d_none(*p4d)) { pud = memblock_alloc_or_panic(PUD_TABLE_SIZE, PUD_TABLE_SIZE); - p4d_populate(&init_mm, p4d, pud); + p4d_populate_kernel(addr, p4d, pud); } pud = pud_offset(p4d, addr); diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index 41aa0493eb037e..dbd8daccade28c 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c @@ -27,9 +27,9 @@ #include #include #include +#include #include -#include #include #include "hugetlb_vmemmap.h" @@ -229,7 +229,7 @@ p4d_t * __meminit vmemmap_p4d_populate(pgd_t *pgd, unsigned long addr, int node) if (!p) return NULL; pud_init(p); - p4d_populate(&init_mm, p4d, p); + p4d_populate_kernel(addr, p4d, p); } return p4d; } @@ -241,7 +241,7 @@ pgd_t * __meminit vmemmap_pgd_populate(unsigned long addr, int node) void *p = vmemmap_alloc_block_zero(PAGE_SIZE, node); if (!p) return NULL; - pgd_populate(&init_mm, pgd, p); + pgd_populate_kernel(addr, pgd, p); } return pgd; } From 6659d027998083fbb6d42a165b0c90dc2e8ba989 Mon Sep 17 00:00:00 2001 From: Harry Yoo Date: Mon, 18 Aug 2025 11:02:06 +0900 Subject: [PATCH 0739/1292] x86/mm/64: define ARCH_PAGE_TABLE_SYNC_MASK and arch_sync_kernel_mappings() Define ARCH_PAGE_TABLE_SYNC_MASK and arch_sync_kernel_mappings() to ensure page tables are properly synchronized when calling p*d_populate_kernel(). For 5-level paging, synchronization is performed via pgd_populate_kernel(). In 4-level paging, pgd_populate() is a no-op, so synchronization is instead performed at the P4D level via p4d_populate_kernel(). This fixes intermittent boot failures on systems using 4-level paging and a large amount of persistent memory: BUG: unable to handle page fault for address: ffffe70000000034 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: 0002 [#1] SMP NOPTI RIP: 0010:__init_single_page+0x9/0x6d Call Trace: __init_zone_device_page+0x17/0x5d memmap_init_zone_device+0x154/0x1bb pagemap_range+0x2e0/0x40f memremap_pages+0x10b/0x2f0 devm_memremap_pages+0x1e/0x60 dev_dax_probe+0xce/0x2ec [device_dax] dax_bus_probe+0x6d/0xc9 [... snip ...] It also fixes a crash in vmemmap_set_pmd() caused by accessing vmemmap before sync_global_pgds() [1]: BUG: unable to handle page fault for address: ffffeb3ff1200000 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: Oops: 0002 [#1] PREEMPT SMP NOPTI Tainted: [W]=WARN RIP: 0010:vmemmap_set_pmd+0xff/0x230 vmemmap_populate_hugepages+0x176/0x180 vmemmap_populate+0x34/0x80 __populate_section_memmap+0x41/0x90 sparse_add_section+0x121/0x3e0 __add_pages+0xba/0x150 add_pages+0x1d/0x70 memremap_pages+0x3dc/0x810 devm_memremap_pages+0x1c/0x60 xe_devm_add+0x8b/0x100 [xe] xe_tile_init_noalloc+0x6a/0x70 [xe] xe_device_probe+0x48c/0x740 [xe] [... snip ...] Link: https://lkml.kernel.org/r/20250818020206.4517-4-harry.yoo@oracle.com Fixes: 8d400913c231 ("x86/vmemmap: handle unpopulated sub-pmd ranges") Signed-off-by: Harry Yoo Closes: https://lore.kernel.org/linux-mm/20250311114420.240341-1-gwan-gyeong.mun@intel.com [1] Suggested-by: Dave Hansen Acked-by: Kiryl Shutsemau Reviewed-by: Mike Rapoport (Microsoft) Reviewed-by: Lorenzo Stoakes Acked-by: David Hildenbrand Cc: Alexander Potapenko Cc: Alistair Popple Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: "Aneesh Kumar K.V" Cc: Anshuman Khandual Cc: Ard Biesheuvel Cc: Arnd Bergmann Cc: bibo mao Cc: Borislav Betkov Cc: Christoph Lameter (Ampere) Cc: Dennis Zhou Cc: Dev Jain Cc: Dmitriy Vyukov Cc: Ingo Molnar Cc: Jane Chu Cc: Joao Martins Cc: Joerg Roedel Cc: John Hubbard Cc: Kevin Brodsky Cc: Liam Howlett Cc: Michal Hocko Cc: Oscar Salvador Cc: Peter Xu Cc: Peter Zijlstra Cc: Qi Zheng Cc: Ryan Roberts Cc: Suren Baghdasaryan Cc: Tejun Heo Cc: Thomas Gleinxer Cc: Thomas Huth Cc: "Uladzislau Rezki (Sony)" Cc: Vincenzo Frascino Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton --- arch/x86/include/asm/pgtable_64_types.h | 3 +++ arch/x86/mm/init_64.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index 4604f924d8b86a..7eb61ef6a185f6 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -36,6 +36,9 @@ static inline bool pgtable_l5_enabled(void) #define pgtable_l5_enabled() cpu_feature_enabled(X86_FEATURE_LA57) #endif /* USE_EARLY_PGTABLE_L5 */ +#define ARCH_PAGE_TABLE_SYNC_MASK \ + (pgtable_l5_enabled() ? PGTBL_PGD_MODIFIED : PGTBL_P4D_MODIFIED) + extern unsigned int pgdir_shift; extern unsigned int ptrs_per_p4d; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 76e33bd7c55680..b9426fce5f3e3f 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -223,6 +223,24 @@ static void sync_global_pgds(unsigned long start, unsigned long end) sync_global_pgds_l4(start, end); } +/* + * Make kernel mappings visible in all page tables in the system. + * This is necessary except when the init task populates kernel mappings + * during the boot process. In that case, all processes originating from + * the init task copies the kernel mappings, so there is no issue. + * Otherwise, missing synchronization could lead to kernel crashes due + * to missing page table entries for certain kernel mappings. + * + * Synchronization is performed at the top level, which is the PGD in + * 5-level paging systems. But in 4-level paging systems, however, + * pgd_populate() is a no-op, so synchronization is done at the P4D level. + * sync_global_pgds() handles this difference between paging levels. + */ +void arch_sync_kernel_mappings(unsigned long start, unsigned long end) +{ + sync_global_pgds(start, end); +} + /* * NOTE: This function is marked __ref because it calls __init function * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0. From a6358f8cf64850f3f27857b8ed8c1b08cfc4685c Mon Sep 17 00:00:00 2001 From: Li Nan Date: Wed, 27 Aug 2025 15:39:54 +0800 Subject: [PATCH 0740/1292] efivarfs: Fix slab-out-of-bounds in efivarfs_d_compare Observed on kernel 6.6 (present on master as well): BUG: KASAN: slab-out-of-bounds in memcmp+0x98/0xd0 Call trace: kasan_check_range+0xe8/0x190 __asan_loadN+0x1c/0x28 memcmp+0x98/0xd0 efivarfs_d_compare+0x68/0xd8 __d_lookup_rcu_op_compare+0x178/0x218 __d_lookup_rcu+0x1f8/0x228 d_alloc_parallel+0x150/0x648 lookup_open.isra.0+0x5f0/0x8d0 open_last_lookups+0x264/0x828 path_openat+0x130/0x3f8 do_filp_open+0x114/0x248 do_sys_openat2+0x340/0x3c0 __arm64_sys_openat+0x120/0x1a0 If dentry->d_name.len < EFI_VARIABLE_GUID_LEN , 'guid' can become negative, leadings to oob. The issue can be triggered by parallel lookups using invalid filename: T1 T2 lookup_open ->lookup simple_lookup d_add // invalid dentry is added to hash list lookup_open d_alloc_parallel __d_lookup_rcu __d_lookup_rcu_op_compare hlist_bl_for_each_entry_rcu // invalid dentry can be retrieved ->d_compare efivarfs_d_compare // oob Fix it by checking 'guid' before cmp. Fixes: da27a24383b2 ("efivarfs: guid part of filenames are case-insensitive") Signed-off-by: Li Nan Signed-off-by: Wu Guanghao Signed-off-by: Ard Biesheuvel --- fs/efivarfs/super.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index c4a13991135689..4bb4002e3cdf04 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -152,6 +152,10 @@ static int efivarfs_d_compare(const struct dentry *dentry, { int guid = len - EFI_VARIABLE_GUID_LEN; + /* Parallel lookups may produce a temporary invalid filename */ + if (guid <= 0) + return 1; + if (name->len != len) return 1; From dac978e51cce0c1f00a14c4a82f81d387f79b2d4 Mon Sep 17 00:00:00 2001 From: Neil Mandir Date: Tue, 26 Aug 2025 10:30:22 -0400 Subject: [PATCH 0741/1292] net: macb: Disable clocks once When the driver is removed the clocks are disabled twice: once in macb_remove and a second time by runtime pm. Disable wakeup in remove so all the clocks are disabled and skip the second call to macb_clks_disable. Always suspend the device as we always set it active in probe. Fixes: d54f89af6cc4 ("net: macb: Add pm runtime support") Signed-off-by: Neil Mandir Co-developed-by: Sean Anderson Signed-off-by: Sean Anderson Link: https://patch.msgid.link/20250826143022.935521-1-sean.anderson@linux.dev Signed-off-by: Paolo Abeni --- drivers/net/ethernet/cadence/macb_main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 10688545114708..16d28a8b3b56cc 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -5404,14 +5404,11 @@ static void macb_remove(struct platform_device *pdev) mdiobus_unregister(bp->mii_bus); mdiobus_free(bp->mii_bus); + device_set_wakeup_enable(&bp->pdev->dev, 0); cancel_work_sync(&bp->hresp_err_bh_work); pm_runtime_disable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - if (!pm_runtime_suspended(&pdev->dev)) { - macb_clks_disable(bp->pclk, bp->hclk, bp->tx_clk, - bp->rx_clk, bp->tsu_clk); - pm_runtime_set_suspended(&pdev->dev); - } + pm_runtime_set_suspended(&pdev->dev); phylink_destroy(bp->phylink); free_netdev(dev); } From 4ef353d546cda466fc39b7daca558d7bcec21c09 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 28 Aug 2025 16:13:10 +0800 Subject: [PATCH 0742/1292] ALSA: lx_core: use int type to store negative error codes Change the 'ret' variable from u16 to int to store negative error codes or zero returned by lx_message_send_atomic(). Storing the negative error codes in unsigned type, doesn't cause an issue at runtime but it's ugly as pants. Additionally, assigning negative error codes to unsigned type may trigger a GCC warning when the -Wsign-conversion flag is enabled. No effect on runtime. Fixes: 02bec4904508 ("ALSA: lx6464es - driver for the digigram lx6464es interface") Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250828081312.393148-1-rongqianfeng@vivo.com Signed-off-by: Takashi Iwai --- sound/pci/lx6464es/lx_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 9d95ecb299aed8..a99acd1125e74f 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -316,7 +316,7 @@ static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) /* low-level dsp access */ int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) { - u16 ret; + int ret; mutex_lock(&chip->msg_lock); @@ -330,10 +330,10 @@ int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) { - u16 ret = 0; u32 freq_raw = 0; u32 freq = 0; u32 frequency = 0; + int ret; mutex_lock(&chip->msg_lock); From 5189446ba995556eaa3755a6e875bc06675b88bd Mon Sep 17 00:00:00 2001 From: Oscar Maes Date: Wed, 27 Aug 2025 08:23:21 +0200 Subject: [PATCH 0743/1292] net: ipv4: fix regression in local-broadcast routes Commit 9e30ecf23b1b ("net: ipv4: fix incorrect MTU in broadcast routes") introduced a regression where local-broadcast packets would have their gateway set in __mkroute_output, which was caused by fi = NULL being removed. Fix this by resetting the fib_info for local-broadcast packets. This preserves the intended changes for directed-broadcast packets. Cc: stable@vger.kernel.org Fixes: 9e30ecf23b1b ("net: ipv4: fix incorrect MTU in broadcast routes") Reported-by: Brett A C Sheffield Closes: https://lore.kernel.org/regressions/20250822165231.4353-4-bacs@librecast.net Signed-off-by: Oscar Maes Reviewed-by: David Ahern Link: https://patch.msgid.link/20250827062322.4807-1-oscmaes92@gmail.com Signed-off-by: Paolo Abeni --- net/ipv4/route.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f639a2ae881ac5..baa43e5966b19b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2575,12 +2575,16 @@ static struct rtable *__mkroute_output(const struct fib_result *res, !netif_is_l3_master(dev_out)) return ERR_PTR(-EINVAL); - if (ipv4_is_lbcast(fl4->daddr)) + if (ipv4_is_lbcast(fl4->daddr)) { type = RTN_BROADCAST; - else if (ipv4_is_multicast(fl4->daddr)) + + /* reset fi to prevent gateway resolution */ + fi = NULL; + } else if (ipv4_is_multicast(fl4->daddr)) { type = RTN_MULTICAST; - else if (ipv4_is_zeronet(fl4->daddr)) + } else if (ipv4_is_zeronet(fl4->daddr)) { return ERR_PTR(-EINVAL); + } if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; From 8022629548949eb4d2e2207b893bfb6d486700cb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 26 Aug 2025 06:30:01 +0000 Subject: [PATCH 0744/1292] ASoC: rsnd: tidyup direction name on rsnd_dai_connect() commit 2c6b6a3e8b93 ("ASoC: rsnd: use snd_pcm_direction_name()") uses snd_pcm_direction_name() instead of original method to get string "Playback" or "Capture". But io->substream might be NULL in this timing. Let's re-use original method. Fixes: 2c6b6a3e8b93 ("ASoC: rsnd: use snd_pcm_direction_name()") Reported-by: Thuan Nguyen Tested-by: Thuan Nguyen Signed-off-by: Kuninori Morimoto Message-ID: <87zfbmwq6v.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c index 37d954495ea5a9..9f086906a2e5c6 100644 --- a/sound/soc/renesas/rcar/core.c +++ b/sound/soc/renesas/rcar/core.c @@ -597,7 +597,7 @@ int rsnd_dai_connect(struct rsnd_mod *mod, dev_dbg(dev, "%s is connected to io (%s)\n", rsnd_mod_name(mod), - snd_pcm_direction_name(io->substream->stream)); + rsnd_io_is_play(io) ? "Playback" : "Capture"); return 0; } From 042e57d59b3e7f44014da23e62911ae9b591953a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 28 Aug 2025 02:21:46 +0000 Subject: [PATCH 0745/1292] ASoC: renesas: msiof: msiof_update_and_wait() checks whether reg was updated msiof_update_and_wait() updates reg and waits until the value was updated. But, if the set value was same as current reg value, no update will be happen. Check the value, and ignore waiting if no update. Signed-off-by: Kuninori Morimoto Message-ID: <87h5xsuqx2.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/msiof.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c index 36d31ab8ac6a5f..b7633ed3e3f0c2 100644 --- a/sound/soc/renesas/rcar/msiof.c +++ b/sound/soc/renesas/rcar/msiof.c @@ -82,13 +82,18 @@ struct msiof_priv { #define msiof_write(priv, reg, val) iowrite32(val, (priv)->base + reg) #define msiof_status_clear(priv) msiof_write(priv, SISTR, SISTR_ERR) -static void msiof_update(struct msiof_priv *priv, u32 reg, u32 mask, u32 val) +static int msiof_update(struct msiof_priv *priv, u32 reg, u32 mask, u32 val) { u32 old = msiof_read(priv, reg); u32 new = (old & ~mask) | (val & mask); + int updated = false; - if (old != new) + if (old != new) { msiof_write(priv, reg, new); + updated = true; + } + + return updated; } static void msiof_update_and_wait(struct msiof_priv *priv, u32 reg, u32 mask, u32 val, u32 expect) @@ -96,7 +101,9 @@ static void msiof_update_and_wait(struct msiof_priv *priv, u32 reg, u32 mask, u3 u32 data; int ret; - msiof_update(priv, reg, mask, val); + ret = msiof_update(priv, reg, mask, val); + if (!ret) /* no update */ + return; ret = readl_poll_timeout_atomic(priv->base + reg, data, (data & mask) == expect, 1, 128); From d3593ac41aaf31db9d6d28cacd584330c769a4a6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 28 Aug 2025 02:21:51 +0000 Subject: [PATCH 0746/1292] ASoC: renesas: msiof: tidyup error message The meesage was strange. tidyup it. Signed-off-by: Kuninori Morimoto Message-ID: <87frdcuqww.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/msiof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c index b7633ed3e3f0c2..56bf64e55ba3d3 100644 --- a/sound/soc/renesas/rcar/msiof.c +++ b/sound/soc/renesas/rcar/msiof.c @@ -218,7 +218,7 @@ static int msiof_hw_stop(struct snd_soc_component *component, if (priv->err_syc[substream->stream] || priv->err_ovf[substream->stream] || priv->err_udf[substream->stream]) - dev_warn(dev, "FSERR(%s) = %d, FOVF = %d, FUDF = %d\n", + dev_warn(dev, "%s: FSERR = %d, FOVF = %d, FUDF = %d\n", snd_pcm_direction_name(substream->stream), priv->err_syc[substream->stream], priv->err_ovf[substream->stream], From d092b70d7b54321ff481226fe6bc2a6aaa91519f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 28 Aug 2025 02:21:57 +0000 Subject: [PATCH 0747/1292] ASoC: renesas: msiof: cleanup status clear method Current MSIOF driver clear status 1) after starting HW, and 2) clear all status. But it should be 1') before starting HW, 2') clear necessary status only. Cleanup it. Signed-off-by: Kuninori Morimoto Message-ID: <87ecswuqwr.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/msiof.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c index 56bf64e55ba3d3..90ca3357392ebb 100644 --- a/sound/soc/renesas/rcar/msiof.c +++ b/sound/soc/renesas/rcar/msiof.c @@ -37,7 +37,6 @@ /* SISTR */ #define SISTR_ERR_TX (SISTR_TFSERR | SISTR_TFOVF | SISTR_TFUDF) #define SISTR_ERR_RX (SISTR_RFSERR | SISTR_RFOVF | SISTR_RFUDF) -#define SISTR_ERR (SISTR_ERR_TX | SISTR_ERR_RX) /* * The data on memory in 24bit case is located at side @@ -80,7 +79,6 @@ struct msiof_priv { #define msiof_is_play(substream) ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK) #define msiof_read(priv, reg) ioread32((priv)->base + reg) #define msiof_write(priv, reg, val) iowrite32(val, (priv)->base + reg) -#define msiof_status_clear(priv) msiof_write(priv, SISTR, SISTR_ERR) static int msiof_update(struct msiof_priv *priv, u32 reg, u32 mask, u32 val) { @@ -174,6 +172,13 @@ static int msiof_hw_start(struct snd_soc_component *component, val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX; msiof_update(priv, SIIER, val, val); + /* clear status */ + if (is_play) + val = SISTR_ERR_TX; + else + val = SISTR_ERR_RX; + msiof_update(priv, SISTR, val, val); + /* SICTR */ if (is_play) val = SICTR_TXE | SICTR_TEDG; @@ -181,8 +186,6 @@ static int msiof_hw_start(struct snd_soc_component *component, val = SICTR_RXE | SICTR_REDG; msiof_update_and_wait(priv, SICTR, val, val, val); - msiof_status_clear(priv); - /* Start DMAC */ snd_dmaengine_pcm_trigger(substream, cmd); @@ -439,7 +442,7 @@ static irqreturn_t msiof_interrupt(int irq, void *data) spin_lock(&priv->lock); sistr = msiof_read(priv, SISTR); - msiof_status_clear(priv); + msiof_write(priv, SISTR, SISTR_ERR_TX | SISTR_ERR_RX); spin_unlock(&priv->lock); From edb5c1f885207d1d74e8a1528e6937e02829ee6e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 28 Aug 2025 02:22:02 +0000 Subject: [PATCH 0748/1292] ASoC: renesas: msiof: start DMAC first MSIOF needs to start DMAC before starting HW. It will get unknown error at 1st using without this patch. Playback: FSERR = 0, FOVF = 0, FUDF = 1 Capture: FSERR = 1, FOVF = 0, FUDF = 0 Signed-off-by: Kuninori Morimoto Message-ID: <87cy8guqwl.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/msiof.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c index 90ca3357392ebb..77e1dadec14d27 100644 --- a/sound/soc/renesas/rcar/msiof.c +++ b/sound/soc/renesas/rcar/msiof.c @@ -136,6 +136,9 @@ static int msiof_hw_start(struct snd_soc_component *component, priv->err_ovf[substream->stream] = priv->err_udf[substream->stream] = 0; + /* Start DMAC */ + snd_dmaengine_pcm_trigger(substream, cmd); + /* SITMDRx */ if (is_play) { val = SITMDR1_PCON | @@ -186,9 +189,6 @@ static int msiof_hw_start(struct snd_soc_component *component, val = SICTR_RXE | SICTR_REDG; msiof_update_and_wait(priv, SICTR, val, val, val); - /* Start DMAC */ - snd_dmaengine_pcm_trigger(substream, cmd); - return 0; } From b088b6189a4066b97cef459afd312fd168a76dea Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 25 Aug 2025 23:11:09 +0800 Subject: [PATCH 0749/1292] ASoC: mediatek: common: Switch to for_each_available_child_of_node_scoped() Using for_each_available_child_of_node_scoped() allows us to get rid of of_node_put() calls from early returns or breaks in the loop. It also fixes issues with missing of_node_put() calls. Switch to for_each_available_child_of_node_scoped() in parse_dai_link_info(). Also drop the braces around if blocks now that the inner block is just one statement. Signed-off-by: Chen-Yu Tsai Reviewed-by: Fei Shao Message-ID: <20250825151111.3696404-1-wenst@chromium.org> Signed-off-by: Mark Brown --- .../mediatek/common/mtk-soundcard-driver.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c index 95a083939f3e22..a2a30a87a359f4 100644 --- a/sound/soc/mediatek/common/mtk-soundcard-driver.c +++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c @@ -89,40 +89,31 @@ static int set_dailink_daifmt(struct snd_soc_card *card, int parse_dai_link_info(struct snd_soc_card *card) { struct device *dev = card->dev; - struct device_node *sub_node; struct snd_soc_dai_link *dai_link; const char *dai_link_name; int ret, i; /* Loop over all the dai link sub nodes */ - for_each_available_child_of_node(dev->of_node, sub_node) { + for_each_available_child_of_node_scoped(dev->of_node, sub_node) { if (of_property_read_string(sub_node, "link-name", - &dai_link_name)) { - of_node_put(sub_node); + &dai_link_name)) return -EINVAL; - } for_each_card_prelinks(card, i, dai_link) { if (!strcmp(dai_link_name, dai_link->name)) break; } - if (i >= card->num_links) { - of_node_put(sub_node); + if (i >= card->num_links) return -EINVAL; - } ret = set_card_codec_info(card, sub_node, dai_link); - if (ret < 0) { - of_node_put(sub_node); + if (ret < 0) return ret; - } ret = set_dailink_daifmt(card, sub_node, dai_link); - if (ret < 0) { - of_node_put(sub_node); + if (ret < 0) return ret; - } } return 0; From 3351e814cb49dff7ef4808f5ebfb299162994118 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 27 Aug 2025 16:22:25 +0200 Subject: [PATCH 0750/1292] ASoC: Intel: avs: New board registration routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support multiple instances of the same card utilize PLATFORM_DEVID_AUTO when registering new platform devices. This adaptation is also an opportunity to streamline the devices registration - avs_register_board(). All the new functions are equivalents of the existing ones apart from adjusting platform_device_register_data() call with PLATFORM_DEVID_AUTO and code size reduction given the presence of unified register function. Follow up changes will complete the transition and cleanup the duplicate members. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Message-ID: <20250827142229.869139-2-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/board_selection.c | 145 ++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index e1d6fa344aa12f..0195e5201a056f 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -399,6 +399,90 @@ static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev) return NULL; } +/* Platform devices spawned by AVS driver are removed with this hook. */ +static void avs_unregister_board(void *pdev) +{ + platform_device_unregister(pdev); +} + +static struct platform_device *avs_register_board(struct avs_dev *adev, const char *name, + const void *data, size_t size) +{ + struct platform_device *pdev; + int ret; + + pdev = platform_device_register_data(NULL, name, PLATFORM_DEVID_AUTO, data, size); + if (IS_ERR(pdev)) + return pdev; + + ret = devm_add_action_or_reset(adev->dev, avs_unregister_board, pdev); + if (ret) + return ERR_PTR(ret); + + return pdev; +} + +static struct platform_device *avs_register_board_pdata(struct avs_dev *adev, const char *name, + struct snd_soc_acpi_mach *mach, + struct hda_codec *codec, + unsigned long *tdms, char *codec_name) +{ + struct avs_mach_pdata *pdata; + + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->codec = codec; + pdata->tdms = tdms; + pdata->codec_name = codec_name; + pdata->obsolete_card_names = obsolete_card_names; + mach->pdata = pdata; + + return avs_register_board(adev, name, mach, sizeof(*mach)); +} + +static int __maybe_unused avs_register_probe_board2(struct avs_dev *adev) +{ + struct platform_device *pdev; + + pdev = avs_register_board(adev, "avs_probe_mb", NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_probe_component(adev, dev_name(&pdev->dev)); +} + +__maybe_unused +static int avs_register_dmic_board2(struct avs_dev *adev) +{ + static struct snd_soc_acpi_mach mach = { + .tplg_filename = "dmic-tplg.bin", + }; + struct platform_device *pdev; + char *codec_name; + + if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) { + dev_dbg(adev->dev, "no DMIC endpoints present\n"); + return 0; + } + + /* DMIC present in Intel PCH is enumerated statically. */ + pdev = avs_register_board(adev, "dmic-codec", NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + codec_name = devm_kstrdup(adev->dev, dev_name(&pdev->dev), GFP_KERNEL); + if (!codec_name) + return -ENOMEM; + + pdev = avs_register_board_pdata(adev, "avs_dmic", &mach, NULL, NULL, codec_name); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_dmic_component(adev, dev_name(&pdev->dev)); +} + /* platform devices owned by AVS audio are removed with this hook */ static void board_pdev_unregister(void *data) { @@ -569,6 +653,31 @@ static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int t return 0; } +__maybe_unused +static int avs_register_i2s_test_board2(struct avs_dev *adev, int ssp_port, int tdm_slot) +{ + struct snd_soc_acpi_mach mach = {{0}}; + struct platform_device *pdev; + unsigned long *tdms; + + tdms = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(*tdms), GFP_KERNEL); + mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, + AVS_STRING_FMT("i2s", "-test-tplg.bin", + ssp_port, tdm_slot)); + if (!tdms || !mach.tplg_filename) + return -ENOMEM; + + tdms[ssp_port] = BIT(tdm_slot); + mach.drv_name = "avs_i2s_test"; + mach.mach_params.i2s_link_mask = AVS_SSP(ssp_port); + + pdev = avs_register_board_pdata(adev, mach.drv_name, &mach, NULL, tdms, NULL); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_i2s_component(adev, dev_name(&pdev->dev), AVS_SSP(ssp_port), tdms); +} + static int avs_register_i2s_test_boards(struct avs_dev *adev) { int max_ssps = adev->hw_cfg.i2s_caps.ctrl_count; @@ -601,6 +710,23 @@ static int avs_register_i2s_test_boards(struct avs_dev *adev) return 0; } +__maybe_unused +static int avs_register_i2s_board2(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) +{ + u32 i2s_mask = mach->mach_params.i2s_link_mask; + struct platform_device *pdev; + unsigned long *tdms = NULL; + + if (mach->pdata) + tdms = ((struct avs_mach_pdata *)mach->pdata)->tdms; + + pdev = avs_register_board_pdata(adev, mach->drv_name, mach, NULL, tdms, NULL); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_i2s_component(adev, dev_name(&pdev->dev), i2s_mask, tdms); +} + static int avs_register_i2s_boards(struct avs_dev *adev) { const struct avs_acpi_boards *boards; @@ -684,6 +810,25 @@ static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec) return 0; } +__maybe_unused +static int avs_register_hda_board2(struct avs_dev *adev, struct hda_codec *codec) +{ + struct hdac_device *hdev = &codec->core; + struct snd_soc_acpi_mach mach = {{0}}; + struct platform_device *pdev; + + mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin", + hdev->vendor_id); + if (!mach.tplg_filename) + return -ENOMEM; + + pdev = avs_register_board_pdata(adev, "avs_hdaudio", &mach, codec, NULL, NULL); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_hda_component(adev, dev_name(&pdev->dev)); +} + static int avs_register_hda_boards(struct avs_dev *adev) { struct hdac_bus *bus = &adev->base.core; From 6acfaee44cbe9364a91dcc373fb4e6e395c5b20b Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 27 Aug 2025 16:22:26 +0200 Subject: [PATCH 0751/1292] ASoC: Intel: avs: Cleanup duplicate members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to the new board registration functions and remove the then-unused code. The SSP-number-check is still important and cannot be just dropped. Move it from avs_register_i2s_board(), which is being removed with this patch, to avs_register_i2s_boards() to maintain sanity when registering a board. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Message-ID: <20250827142229.869139-3-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/avs.h | 1 - sound/soc/intel/avs/board_selection.c | 234 ++------------------------ 2 files changed, 10 insertions(+), 225 deletions(-) diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index 95f9ac2683c0be..0f8ddd0e9e5f18 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -22,7 +22,6 @@ struct avs_dev; struct avs_tplg; struct avs_tplg_library; -struct avs_soc_component; struct avs_ipc_msg; #ifdef CONFIG_ACPI diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 0195e5201a056f..edf20d7816ead5 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -442,7 +442,7 @@ static struct platform_device *avs_register_board_pdata(struct avs_dev *adev, co return avs_register_board(adev, name, mach, sizeof(*mach)); } -static int __maybe_unused avs_register_probe_board2(struct avs_dev *adev) +static int __maybe_unused avs_register_probe_board(struct avs_dev *adev) { struct platform_device *pdev; @@ -453,8 +453,7 @@ static int __maybe_unused avs_register_probe_board2(struct avs_dev *adev) return avs_register_probe_component(adev, dev_name(&pdev->dev)); } -__maybe_unused -static int avs_register_dmic_board2(struct avs_dev *adev) +static int avs_register_dmic_board(struct avs_dev *adev) { static struct snd_soc_acpi_mach mach = { .tplg_filename = "dmic-tplg.bin", @@ -483,178 +482,7 @@ static int avs_register_dmic_board2(struct avs_dev *adev) return avs_register_dmic_component(adev, dev_name(&pdev->dev)); } -/* platform devices owned by AVS audio are removed with this hook */ -static void board_pdev_unregister(void *data) -{ - platform_device_unregister(data); -} - -static int __maybe_unused avs_register_probe_board(struct avs_dev *adev) -{ - struct platform_device *board; - struct snd_soc_acpi_mach mach = {{0}}; - int ret; - - ret = avs_register_probe_component(adev, "probe-platform"); - if (ret < 0) - return ret; - - mach.mach_params.platform = "probe-platform"; - - board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE, - (const void *)&mach, sizeof(mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "probe board register failed\n"); - return PTR_ERR(board); - } - - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; - } - return 0; -} - -static int avs_register_dmic_board(struct avs_dev *adev) -{ - struct platform_device *codec, *board; - struct snd_soc_acpi_mach mach = {{0}}; - struct avs_mach_pdata *pdata; - int ret; - - if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) { - dev_dbg(adev->dev, "no DMIC endpoints present\n"); - return 0; - } - - codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); - if (IS_ERR(codec)) { - dev_err(adev->dev, "dmic codec register failed\n"); - return PTR_ERR(codec); - } - - ret = devm_add_action(adev->dev, board_pdev_unregister, codec); - if (ret < 0) { - platform_device_unregister(codec); - return ret; - } - - ret = avs_register_dmic_component(adev, "dmic-platform"); - if (ret < 0) - return ret; - - pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - pdata->obsolete_card_names = obsolete_card_names; - mach.pdata = pdata; - mach.tplg_filename = "dmic-tplg.bin"; - mach.mach_params.platform = "dmic-platform"; - - board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE, - (const void *)&mach, sizeof(mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "dmic board register failed\n"); - return PTR_ERR(board); - } - - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; - } - - return 0; -} - -static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) -{ - struct platform_device *board; - struct avs_mach_pdata *pdata; - int num_ssps; - char *name; - int ret; - int uid; - - num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; - if (fls(mach->mach_params.i2s_link_mask) > num_ssps) { - dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n", - num_ssps, mach->drv_name, - (unsigned long)__fls(mach->mach_params.i2s_link_mask)); - return -ENODEV; - } - - pdata = mach->pdata; - if (!pdata) - pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - pdata->obsolete_card_names = obsolete_card_names; - mach->pdata = pdata; - - uid = mach->mach_params.i2s_link_mask; - if (avs_mach_singular_ssp(mach)) - uid = (uid << AVS_CHANNELS_MAX) + avs_mach_ssp_tdm(mach, avs_mach_ssp_port(mach)); - - name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name, uid); - if (!name) - return -ENOMEM; - - ret = avs_register_i2s_component(adev, name, mach->mach_params.i2s_link_mask, pdata->tdms); - if (ret < 0) - return ret; - - mach->mach_params.platform = name; - - board = platform_device_register_data(NULL, mach->drv_name, uid, - (const void *)mach, sizeof(*mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "ssp board register failed\n"); - return PTR_ERR(board); - } - - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; - } - - return 0; -} - static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot) -{ - struct snd_soc_acpi_mach *mach; - int tdm_mask = BIT(tdm_slot); - unsigned long *tdm_cfg; - char *tplg_name; - int ret; - - mach = devm_kzalloc(adev->dev, sizeof(*mach), GFP_KERNEL); - tdm_cfg = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(unsigned long), GFP_KERNEL); - tplg_name = devm_kasprintf(adev->dev, GFP_KERNEL, AVS_STRING_FMT("i2s", "-test-tplg.bin", - ssp_port, tdm_slot)); - if (!mach || !tdm_cfg || !tplg_name) - return -ENOMEM; - - mach->drv_name = "avs_i2s_test"; - mach->mach_params.i2s_link_mask = AVS_SSP(ssp_port); - tdm_cfg[ssp_port] = tdm_mask; - mach->pdata = tdm_cfg; - mach->tplg_filename = tplg_name; - - ret = avs_register_i2s_board(adev, mach); - if (ret < 0) { - dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret); - return ret; - } - - return 0; -} - -__maybe_unused -static int avs_register_i2s_test_board2(struct avs_dev *adev, int ssp_port, int tdm_slot) { struct snd_soc_acpi_mach mach = {{0}}; struct platform_device *pdev; @@ -710,8 +538,7 @@ static int avs_register_i2s_test_boards(struct avs_dev *adev) return 0; } -__maybe_unused -static int avs_register_i2s_board2(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) +static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) { u32 i2s_mask = mach->mach_params.i2s_link_mask; struct platform_device *pdev; @@ -729,6 +556,7 @@ static int avs_register_i2s_board2(struct avs_dev *adev, struct snd_soc_acpi_mac static int avs_register_i2s_boards(struct avs_dev *adev) { + int num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; const struct avs_acpi_boards *boards; struct snd_soc_acpi_mach *mach; int ret; @@ -751,6 +579,12 @@ static int avs_register_i2s_boards(struct avs_dev *adev) if (!acpi_dev_present(mach->id, mach->uid, -1)) continue; + if (fls(mach->mach_params.i2s_link_mask) > num_ssps) { + dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n", + num_ssps, mach->drv_name, + (unsigned long)__fls(mach->mach_params.i2s_link_mask)); + continue; + } if (mach->machine_quirk) if (!mach->machine_quirk(mach)) continue; @@ -764,54 +598,6 @@ static int avs_register_i2s_boards(struct avs_dev *adev) } static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec) -{ - struct snd_soc_acpi_mach mach = {{0}}; - struct platform_device *board; - struct avs_mach_pdata *pdata; - struct hdac_device *hdev = &codec->core; - char *pname; - int ret, id; - - pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev)); - if (!pname) - return -ENOMEM; - - pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - pdata->obsolete_card_names = obsolete_card_names; - pdata->codec = codec; - - ret = avs_register_hda_component(adev, pname); - if (ret < 0) - return ret; - - mach.pdata = pdata; - mach.mach_params.platform = pname; - mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin", - hdev->vendor_id); - if (!mach.tplg_filename) - return -ENOMEM; - - id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr; - board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach, - sizeof(mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "hda board register failed\n"); - return PTR_ERR(board); - } - - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; - } - - return 0; -} - -__maybe_unused -static int avs_register_hda_board2(struct avs_dev *adev, struct hda_codec *codec) { struct hdac_device *hdev = &codec->core; struct snd_soc_acpi_mach mach = {{0}}; From a44281b8b58a88ca3020c89fd697fc1cd18a31b4 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 27 Aug 2025 16:22:27 +0200 Subject: [PATCH 0752/1292] ASoC: Intel: avs: Simplify dmi_match_quirk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional changes, just code lines reduction. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Message-ID: <20250827142229.869139-4-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/board_selection.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index edf20d7816ead5..4b0a8482af2ea1 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -58,19 +58,13 @@ static const struct dmi_system_id kblr_dmi_table[] = { static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg) { struct snd_soc_acpi_mach *mach = arg; - const struct dmi_system_id *dmi_id; struct dmi_system_id *dmi_table; - if (mach->quirk_data == NULL) - return mach; - dmi_table = (struct dmi_system_id *)mach->quirk_data; - dmi_id = dmi_first_match(dmi_table); - if (!dmi_id) - return NULL; - - return mach; + if (!dmi_table || dmi_first_match(dmi_table)) + return mach; + return NULL; } #define AVS_SSP(x) (BIT(x)) From db41fe9baa8b8bd1a1aa96962dd4294f2a9135c7 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 27 Aug 2025 16:22:28 +0200 Subject: [PATCH 0753/1292] ASoC: Intel: avs: Simplify avs_get_i2s_boards() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional changes, just code simplification and readability improvements as there is no need to operate on 'struct avs_acpi_boards' if 'struct snd_soc_acpi_mach' is what interests us. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Message-ID: <20250827142229.869139-5-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/board_selection.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 4b0a8482af2ea1..8539ad3d97c45c 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -364,10 +364,10 @@ struct avs_acpi_boards { /* supported I2S boards per platform */ static const struct avs_acpi_boards i2s_boards[] = { - AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines), - AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines), - AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines), - AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines), + AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines), + AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines), + AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines), + AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines), AVS_MACH_ENTRY(HDA_CNL_LP, avs_cnl_i2s_machines), AVS_MACH_ENTRY(HDA_CNL_H, avs_cnl_i2s_machines), AVS_MACH_ENTRY(HDA_CML_LP, avs_cnl_i2s_machines), @@ -382,14 +382,14 @@ static const struct avs_acpi_boards i2s_boards[] = { { }, }; -static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev) +static struct snd_soc_acpi_mach *avs_get_i2s_machines(struct avs_dev *adev) { int id, i; id = adev->base.pci->device; for (i = 0; i < ARRAY_SIZE(i2s_boards); i++) if (i2s_boards[i].id == id) - return &i2s_boards[i]; + return i2s_boards[i].machs; return NULL; } @@ -551,7 +551,7 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach static int avs_register_i2s_boards(struct avs_dev *adev) { int num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; - const struct avs_acpi_boards *boards; + struct snd_soc_acpi_mach *machs; struct snd_soc_acpi_mach *mach; int ret; @@ -563,13 +563,13 @@ static int avs_register_i2s_boards(struct avs_dev *adev) if (i2s_test) return avs_register_i2s_test_boards(adev); - boards = avs_get_i2s_boards(adev); - if (!boards) { + machs = avs_get_i2s_machines(adev); + if (!machs) { dev_dbg(adev->dev, "no I2S endpoints supported\n"); return 0; } - for (mach = boards->machs; mach->id[0]; mach++) { + for (mach = machs; mach->id[0]; mach++) { if (!acpi_dev_present(mach->id, mach->uid, -1)) continue; From a37280daa4d583c7212681c49b285de9464a5200 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 27 Aug 2025 16:22:29 +0200 Subject: [PATCH 0754/1292] ASoC: Intel: avs: Allow i2s test and non-test boards to coexist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i2s_test card serves debug purpose and is not probed by default. Currently i2s_test and non-i2s_test sound cards exclude each other. To increase the test coverage, allow both board types to be probed simultaneously and share the available SSP port pool. As 'i2s_test' module parameter is empty by default and requires manual input from user to activate, there is no impact for standard production scenarios. Reviewed-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Message-ID: <20250827142229.869139-6-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/board_selection.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 8539ad3d97c45c..52e6266a7cb86f 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -507,6 +507,9 @@ static int avs_register_i2s_test_boards(struct avs_dev *adev) unsigned long tdm_slots; u32 *array, num_elems; + if (!i2s_test) + return 0; + ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array); if (ret) { dev_err(adev->dev, "failed to parse i2s_test parameter\n"); @@ -560,9 +563,6 @@ static int avs_register_i2s_boards(struct avs_dev *adev) return 0; } - if (i2s_test) - return avs_register_i2s_test_boards(adev); - machs = avs_get_i2s_machines(adev); if (!machs) { dev_dbg(adev->dev, "no I2S endpoints supported\n"); @@ -649,6 +649,10 @@ int avs_register_all_boards(struct avs_dev *adev) dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n", ret); + ret = avs_register_i2s_test_boards(adev); + if (ret) + dev_dbg(adev->dev, "enumerate I2S TEST endpoints failed: %d\n", ret); + ret = avs_register_i2s_boards(adev); if (ret < 0) dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n", From 224476613c8499f00ce4de975dd65749c5ca498c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 28 Aug 2025 09:55:26 +0300 Subject: [PATCH 0755/1292] wifi: iwlwifi: if scratch is ~0U, consider it a failure We want to see bits being set in the scratch register upon resume, but if all the bits are set, it means that we were kicked out of the PCI bus and that clearly doesn't mean we can assume the firmware is still alive after the suspend / resume cycle. Fixes: cb347bd29d0d ("wifi: iwlwifi: mvm: fix hibernation") Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250828095500.0f203e559242.I59eff718cb5fda575db41081a1a389f7af488717@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index b7add05f7a85d6..46d8c192229268 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1222,11 +1222,15 @@ static int _iwl_pci_resume(struct device *device, bool restore) * Note: MAC (bits 0:7) will be cleared upon suspend even with wowlan, * but not bits [15:8]. So if we have bits set in lower word, assume * the device is alive. + * Alternatively, if the scratch value is 0xFFFFFFFF, then we no longer + * have access to the device and consider it powered off. * For older devices, just try silently to grab the NIC. */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - if (!(iwl_read32(trans, CSR_FUNC_SCRATCH) & - CSR_FUNC_SCRATCH_POWER_OFF_MASK)) + u32 scratch = iwl_read32(trans, CSR_FUNC_SCRATCH); + + if (!(scratch & CSR_FUNC_SCRATCH_POWER_OFF_MASK) || + scratch == ~0U) device_was_powered_off = true; } else { /* From 7bf2dfccc2dd70821104d15cbab7b6fca21872be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Aug 2025 09:55:27 +0300 Subject: [PATCH 0756/1292] wifi: iwlwifi: acpi: check DSM func validity The DSM func 0 (DSM_FUNC_QUERY) returns a bitmap of which other functions contain valid data, query and check it before returning other functions data. Fixes: 9db93491f29e ("iwlwifi: acpi: support device specific method (DSM)") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220085 Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250828095500.881e17ff8f6a.Ic6d92997d9d5fad127919d6e1b830cd3fe944468@changeid --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 25 ++++++++++++++++++- .../net/wireless/intel/iwlwifi/fw/runtime.h | 8 ++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index bee7d92293b8d6..7ec22738b5d650 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -169,7 +169,7 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); - if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size))) + if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size) || !func)) return -EINVAL; expected_size = acpi_dsm_size[func]; @@ -178,6 +178,29 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) return -EOPNOTSUPP; + if (!fwrt->acpi_dsm_funcs_valid) { + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, + DSM_FUNC_QUERY, + &iwl_guid, &tmp, + acpi_dsm_size[DSM_FUNC_QUERY]); + if (ret) { + /* always indicate BIT(0) to avoid re-reading */ + fwrt->acpi_dsm_funcs_valid = BIT(0); + return ret; + } + + IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", + (u32)tmp); + /* always indicate BIT(0) to avoid re-reading */ + fwrt->acpi_dsm_funcs_valid = tmp | BIT(0); + } + + if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n", + func); + return -ENODATA; + } + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, &iwl_guid, &tmp, expected_size); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 0444a736c2b206..bd3bc2846cfa49 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -113,6 +113,10 @@ struct iwl_txf_iter_data { * @phy_filters: specific phy filters as read from WPFC BIOS table * @ppag_bios_rev: PPAG BIOS revision * @ppag_bios_source: see &enum bios_source + * @acpi_dsm_funcs_valid: bitmap indicating which DSM values are valid, + * zero (default initialization) means it hasn't been read yet, + * and BIT(0) is set when it has since function 0 also has this + * bitmap and is always supported */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -189,6 +193,10 @@ struct iwl_fw_runtime { bool uats_valid; u8 uefi_tables_lock_status; struct iwl_phy_specific_cfg phy_filters; + +#ifdef CONFIG_ACPI + u32 acpi_dsm_funcs_valid; +#endif }; void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, From 1d33694462fa7da451846c39d653585b61375992 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Aug 2025 09:55:28 +0300 Subject: [PATCH 0757/1292] wifi: iwlwifi: uefi: check DSM item validity The first array index is a bitmap indicating which of the other values are valid. Check that bitmap before returning a value. Fixes: fc7214c3c986 ("wifi: iwlwifi: read DSM functions from UEFI") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220085 Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250828095500.59ec52ff865e.I9e11f497a029eb38f481b2c90c43c0935285216d@changeid --- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 48126ec6b94bfd..99a17b9323e9b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -747,6 +747,12 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, goto out; } + if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", + func, data->functions[DSM_FUNC_QUERY]); + goto out; + } + *value = data->functions[func]; IWL_DEBUG_RADIO(fwrt, From 75575e2d252afb29fdbcbeec4d67e042007add52 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 26 Aug 2025 20:26:01 +0300 Subject: [PATCH 0758/1292] wifi: mac80211: do not permit 40 MHz EHT operation on 5/6 GHz The EHT PHY requirements state that 80 MHz must be supported on the 5 and 6 GHz bands unless the STA is 20 MHz only. So if the channel width is limited to 40 MHz on a band other than 2.4 GHz, then disable EHT and downgrade to HE. The primary case where this can happen is if the hardware disables puncturing using IEEE80211_HW_DISALLOW_PUNCTURING. Signed-off-by: Benjamin Berg Cc: stable@vger.kernel.org Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250826202553.a6582f3abf57.Ic670429dc7127f68c818b4290d950ebfb5a0b9e1@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 8 ++++++++ net/mac80211/tests/chan-mode.c | 30 +++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1008eb8e9b13be..dd650a127a3174 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1189,6 +1189,14 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata, "required MCSes not supported, disabling EHT\n"); } + if (conn->mode >= IEEE80211_CONN_MODE_EHT && + channel->band != NL80211_BAND_2GHZ && + conn->bw_limit == IEEE80211_CONN_BW_LIMIT_40) { + conn->mode = IEEE80211_CONN_MODE_HE; + link_id_info(sdata, link_id, + "required bandwidth not supported, disabling EHT\n"); + } + /* the mode can only decrease, so this must terminate */ if (ap_mode != conn->mode) { kfree(elems); diff --git a/net/mac80211/tests/chan-mode.c b/net/mac80211/tests/chan-mode.c index 96c7b3ab27444d..adc069065e73dd 100644 --- a/net/mac80211/tests/chan-mode.c +++ b/net/mac80211/tests/chan-mode.c @@ -2,7 +2,7 @@ /* * KUnit tests for channel mode functions * - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation */ #include #include @@ -28,6 +28,10 @@ static const struct determine_chan_mode_case { u8 vht_basic_mcs_1_4, vht_basic_mcs_5_8; u8 he_basic_mcs_1_4, he_basic_mcs_5_8; u8 eht_mcs7_min_nss; + u16 eht_disabled_subchannels; + u8 eht_bw; + enum ieee80211_conn_bw_limit conn_bw_limit; + enum ieee80211_conn_bw_limit expected_bw_limit; int error; } determine_chan_mode_cases[] = { { @@ -128,6 +132,14 @@ static const struct determine_chan_mode_case { .conn_mode = IEEE80211_CONN_MODE_EHT, .eht_mcs7_min_nss = 0x15, .error = EINVAL, + }, { + .desc = "80 MHz EHT is downgraded to 40 MHz HE due to puncturing", + .conn_mode = IEEE80211_CONN_MODE_EHT, + .expected_mode = IEEE80211_CONN_MODE_HE, + .conn_bw_limit = IEEE80211_CONN_BW_LIMIT_80, + .expected_bw_limit = IEEE80211_CONN_BW_LIMIT_40, + .eht_disabled_subchannels = 0x08, + .eht_bw = IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ, } }; KUNIT_ARRAY_PARAM_DESC(determine_chan_mode, determine_chan_mode_cases, desc) @@ -138,7 +150,7 @@ static void test_determine_chan_mode(struct kunit *test) struct t_sdata *t_sdata = T_SDATA(test); struct ieee80211_conn_settings conn = { .mode = params->conn_mode, - .bw_limit = IEEE80211_CONN_BW_LIMIT_20, + .bw_limit = params->conn_bw_limit, }; struct cfg80211_bss cbss = { .channel = &t_sdata->band_5ghz.channels[0], @@ -191,14 +203,21 @@ static void test_determine_chan_mode(struct kunit *test) 0x7f, 0x01, 0x00, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, /* EHT Operation */ - WLAN_EID_EXTENSION, 0x09, WLAN_EID_EXT_EHT_OPERATION, - 0x01, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11, - 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, + WLAN_EID_EXTENSION, 0x0b, WLAN_EID_EXT_EHT_OPERATION, + 0x03, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11, + 0x00, 0x00, 0x00, params->eht_bw, + params->eht_bw == IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ ? 42 : 36, + 0x00, + u16_get_bits(params->eht_disabled_subchannels, 0xff), + u16_get_bits(params->eht_disabled_subchannels, 0xff00), }; struct ieee80211_chan_req chanreq = {}; struct cfg80211_chan_def ap_chandef = {}; struct ieee802_11_elems *elems; + /* To force EHT downgrade to HE on punctured 80 MHz downgraded to 40 MHz */ + set_bit(IEEE80211_HW_DISALLOW_PUNCTURING, t_sdata->local.hw.flags); + if (params->strict) set_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags); else @@ -237,6 +256,7 @@ static void test_determine_chan_mode(struct kunit *test) } else { KUNIT_ASSERT_NOT_ERR_OR_NULL(test, elems); KUNIT_ASSERT_EQ(test, conn.mode, params->expected_mode); + KUNIT_ASSERT_EQ(test, conn.bw_limit, params->expected_bw_limit); } } From 0e20450829ca3c1dbc2db536391537c57a40fe0b Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 15 Aug 2025 10:30:50 +0800 Subject: [PATCH 0759/1292] wifi: mwifiex: Initialize the chan_stats array to zero The adapter->chan_stats[] array is initialized in mwifiex_init_channel_scan_gap() with vmalloc(), which doesn't zero out memory. The array is filled in mwifiex_update_chan_statistics() and then the user can query the data in mwifiex_cfg80211_dump_survey(). There are two potential issues here. What if the user calls mwifiex_cfg80211_dump_survey() before the data has been filled in. Also the mwifiex_update_chan_statistics() function doesn't necessarily initialize the whole array. Since the array was not initialized at the start that could result in an information leak. Also this array is pretty small. It's a maximum of 900 bytes so it's more appropriate to use kcalloc() instead vmalloc(). Cc: stable@vger.kernel.org Fixes: bf35443314ac ("mwifiex: channel statistics support for mwifiex") Suggested-by: Dan Carpenter Signed-off-by: Qianfeng Rong Reviewed-by: Dan Carpenter Link: https://patch.msgid.link/20250815023055.477719-1-rongqianfeng@vivo.com Signed-off-by: Johannes Berg --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 5 +++-- drivers/net/wireless/marvell/mwifiex/main.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 3498743d5ec057..4c8c7a5fdf23e2 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -4673,8 +4673,9 @@ int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter) * additional active scan request for hidden SSIDs on passive channels. */ adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a); - adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats), - adapter->num_in_chan_stats)); + adapter->chan_stats = kcalloc(adapter->num_in_chan_stats, + sizeof(*adapter->chan_stats), + GFP_KERNEL); if (!adapter->chan_stats) return -ENOMEM; diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 7b50a88a18e573..1ec069bc8ea1e3 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -642,7 +642,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); err_init_chan_scan: wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); @@ -1485,7 +1485,7 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) wiphy_free(adapter->wiphy); adapter->wiphy = NULL; - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); mwifiex_free_cmd_buffers(adapter); } From 98b6fa62c84f2e129161e976a5b9b3cb4ccd117b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 27 Aug 2025 15:27:30 -0600 Subject: [PATCH 0760/1292] io_uring/kbuf: always use READ_ONCE() to read ring provided buffer lengths Since the buffers are mapped from userspace, it is prudent to use READ_ONCE() to read the value into a local variable, and use that for any other actions taken. Having a stable read of the buffer length avoids worrying about it changing after checking, or being read multiple times. Similarly, the buffer may well change in between it being picked and being committed. Ensure the looping for incremental ring buffer commit stops if it hits a zero sized buffer, as no further progress can be made at that point. Fixes: ae98dbf43d75 ("io_uring/kbuf: add support for incremental buffer consumption") Link: https://lore.kernel.org/io-uring/tencent_000C02641F6250C856D0C26228DE29A3D30A@qq.com/ Reported-by: Qingyue Zhang Reported-by: Suoxing Zhang Signed-off-by: Jens Axboe --- io_uring/kbuf.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index 81a13338dfab3e..19a8bde5e1e1c3 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -36,15 +36,19 @@ static bool io_kbuf_inc_commit(struct io_buffer_list *bl, int len) { while (len) { struct io_uring_buf *buf; - u32 this_len; + u32 buf_len, this_len; buf = io_ring_head_to_buf(bl->buf_ring, bl->head, bl->mask); - this_len = min_t(u32, len, buf->len); - buf->len -= this_len; - if (buf->len) { + buf_len = READ_ONCE(buf->len); + this_len = min_t(u32, len, buf_len); + buf_len -= this_len; + /* Stop looping for invalid buffer length of 0 */ + if (buf_len || !this_len) { buf->addr += this_len; + buf->len = buf_len; return false; } + buf->len = 0; bl->head++; len -= this_len; } @@ -159,6 +163,7 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len, __u16 tail, head = bl->head; struct io_uring_buf *buf; void __user *ret; + u32 buf_len; tail = smp_load_acquire(&br->tail); if (unlikely(tail == head)) @@ -168,8 +173,9 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len, req->flags |= REQ_F_BL_EMPTY; buf = io_ring_head_to_buf(br, head, bl->mask); - if (*len == 0 || *len > buf->len) - *len = buf->len; + buf_len = READ_ONCE(buf->len); + if (*len == 0 || *len > buf_len) + *len = buf_len; req->flags |= REQ_F_BUFFER_RING | REQ_F_BUFFERS_COMMIT; req->buf_list = bl; req->buf_index = buf->bid; @@ -265,7 +271,7 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg, req->buf_index = buf->bid; do { - u32 len = buf->len; + u32 len = READ_ONCE(buf->len); /* truncate end piece, if needed, for non partial buffers */ if (len > arg->max_len) { From 22e6bdb129ec64e640f5cccef9686f7c1a7d559b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Aug 2025 09:55:29 +0300 Subject: [PATCH 0761/1292] wifi: iwlwifi: cfg: restore some 1000 series configs In the fixed commit, I inadvertently removed two configurations while combining the 0x0083/0x0084 device IDs. Replace the fixed matches for the BG versions by a masked match and add the BGN version back with a similar masked match. Link: https://bugzilla.kernel.org/show_bug.cgi?id=220477 Fixes: 1fb053d9876f ("wifi: iwlwifi: cfg: remove unnecessary configs") Signed-off-by: Johannes Berg Link: https://patch.msgid.link/20250828095500.fabb99c2df9e.If0ad87bf9ab360da5f613e879fd416c17c544733@changeid Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 46d8c192229268..f5e72c90dd5782 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -729,10 +729,10 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { DEVICE(0x0083), SUBDEV_MASKED(0x5, 0xF)), IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, DEVICE(0x0083), SUBDEV_MASKED(0x6, 0xF)), + IWL_DEV_INFO(iwl1000_bgn_cfg, iwl1000_bgn_name, + DEVICE(0x0084), SUBDEV_MASKED(0x5, 0xF)), IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, - DEVICE(0x0084), SUBDEV(0x1216)), - IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, - DEVICE(0x0084), SUBDEV(0x1316)), + DEVICE(0x0084), SUBDEV_MASKED(0x6, 0xF)), /* 100 Series WiFi */ IWL_DEV_INFO(iwl100_bgn_cfg, iwl100_bgn_name, From 586e3cb33ba6890054b95aa0ade0a165890efabd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Aug 2025 09:55:30 +0300 Subject: [PATCH 0762/1292] wifi: iwlwifi: fix byte count table for old devices For devices handled by iwldvm, bc_table_dword was never set, but I missed that during the removal thereof. Change the logic to not treat the byte count table as dwords for devices older than 9000 series to fix that. Fixes: 6570ea227826 ("wifi: iwlwifi: remove bc_table_dword transport config") Signed-off-by: Johannes Berg Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250828095500.eccd7d3939f1.Ibaffa06d0b3aa5f35a9451d94af34de208b8a2bc@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c index 84a05cc1c27a68..d912e709a92cbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c @@ -2092,7 +2092,8 @@ static void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, break; } - if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && + trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) len = DIV_ROUND_UP(len, 4); if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) From 019f71a6760a6f89d388c3cd45622d1aae7d3641 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Aug 2025 09:55:31 +0300 Subject: [PATCH 0763/1292] wifi: iwlwifi: cfg: add back more lost PCI IDs Add back a few more PCI IDs to the config match table that evidently I lost during the cleanups. Fixes: 1fb053d9876f ("wifi: iwlwifi: cfg: remove unnecessary configs") Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250828095500.46fee422651e.I8f6c3e9eea9523bb1658f5690b715eb443740e07@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index f5e72c90dd5782..f9e2095d649050 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -673,6 +673,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_sff_name, DEVICE(0x0082), SUBDEV_MASKED(0xC000, 0xF000)), + IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_sff_name, + DEVICE(0x0085), SUBDEV_MASKED(0xC000, 0xF000)), IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_d_name, DEVICE(0x0082), SUBDEV(0x4820)), IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_mow1_name, @@ -964,6 +966,12 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { DEVICE(0x24F3), SUBDEV(0x0004)), IWL_DEV_INFO(iwl8260_cfg, iwl8260_2n_name, DEVICE(0x24F3), SUBDEV(0x0044)), + IWL_DEV_INFO(iwl8260_cfg, iwl8260_2ac_name, + DEVICE(0x24F4)), + IWL_DEV_INFO(iwl8260_cfg, iwl4165_2ac_name, + DEVICE(0x24F5)), + IWL_DEV_INFO(iwl8260_cfg, iwl4165_2ac_name, + DEVICE(0x24F6)), IWL_DEV_INFO(iwl8265_cfg, iwl8265_2ac_name, DEVICE(0x24FD)), IWL_DEV_INFO(iwl8265_cfg, iwl8275_2ac_name, From 497aa80ec7ee145b3606e7434d57091974d78598 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Wed, 27 Aug 2025 15:34:58 +0100 Subject: [PATCH 0764/1292] arm64: dts: rockchip: Add vcc-supply to SPI flash on Pinephone Pro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As documented in the PinephonePro-Schematic-V1.0-20211127.pdf, page 11, the SPI Flash's VCC pin is connected to VCC_1V8 power source. This fixes the following warning: spi-nor spi1.0: supply vcc not found, using dummy regulator Signed-off-by: Peter Robinson Reviewed-by: Ondřej Jirman Link: https://lore.kernel.org/r/20250827143501.1646163-1-pbrobinson@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts index 585ef0fd88ef05..6f97e57f36f559 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts @@ -754,6 +754,7 @@ compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <10000000>; + vcc-supply = <&vcc_1v8>; }; }; From c5c5eb24ed6177fc0ef4bb75fc18d07a99c1d3f0 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 27 Aug 2025 20:15:59 +0800 Subject: [PATCH 0765/1292] ublk: avoid ublk_io_release() called after ublk char dev is closed When running test_stress_04.sh, the following warning is triggered: WARNING: CPU: 1 PID: 135 at drivers/block/ublk_drv.c:1933 ublk_ch_release+0x423/0x4b0 [ublk_drv] This happens when the daemon is abruptly killed: - some references may still be held, because registering IO buffer doesn't grab ublk char device reference OR - io->task_registered_buffers won't be cleared because io buffer is released from non-daemon context For zero-copy and auto buffer register modes, I/O reference crosses syscalls, so IO reference may not be dropped naturally when ublk server is killed abruptly. However, when releasing io_uring context, it is guaranteed that the reference is dropped finally, see io_sqe_buffers_unregister() from io_ring_ctx_free(). Fix this by adding ublk_drain_io_references() that: - Waits for active I/O references dropped in async way by scheduling work function, for avoiding ublk dev and io_uring file's release dependency - Reinitializes io->ref and io->task_registered_buffers to clean state This ensures the reference count state is clean when ublk_queue_reinit() is called, preventing the warning and potential use-after-free. Fixes: 1f6540e2aabb ("ublk: zc register/unregister bvec") Fixes: 1ceeedb59749 ("ublk: optimize UBLK_IO_UNREGISTER_IO_BUF on daemon task") Fixes: 8a8fe42d765b ("ublk: optimize UBLK_IO_REGISTER_IO_BUF on daemon task") Signed-off-by: Ming Lei Link: https://lore.kernel.org/r/20250827121602.2619736-2-ming.lei@redhat.com Signed-off-by: Jens Axboe --- drivers/block/ublk_drv.c | 72 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 99abd67b708bc2..67d4a867aec487 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -239,6 +239,7 @@ struct ublk_device { struct mutex cancel_mutex; bool canceling; pid_t ublksrv_tgid; + struct delayed_work exit_work; }; /* header of ublk_params */ @@ -1595,12 +1596,62 @@ static void ublk_set_canceling(struct ublk_device *ub, bool canceling) ublk_get_queue(ub, i)->canceling = canceling; } -static int ublk_ch_release(struct inode *inode, struct file *filp) +static bool ublk_check_and_reset_active_ref(struct ublk_device *ub) { - struct ublk_device *ub = filp->private_data; + int i, j; + + if (!(ub->dev_info.flags & (UBLK_F_SUPPORT_ZERO_COPY | + UBLK_F_AUTO_BUF_REG))) + return false; + + for (i = 0; i < ub->dev_info.nr_hw_queues; i++) { + struct ublk_queue *ubq = ublk_get_queue(ub, i); + + for (j = 0; j < ubq->q_depth; j++) { + struct ublk_io *io = &ubq->ios[j]; + unsigned int refs = refcount_read(&io->ref) + + io->task_registered_buffers; + + /* + * UBLK_REFCOUNT_INIT or zero means no active + * reference + */ + if (refs != UBLK_REFCOUNT_INIT && refs != 0) + return true; + + /* reset to zero if the io hasn't active references */ + refcount_set(&io->ref, 0); + io->task_registered_buffers = 0; + } + } + return false; +} + +static void ublk_ch_release_work_fn(struct work_struct *work) +{ + struct ublk_device *ub = + container_of(work, struct ublk_device, exit_work.work); struct gendisk *disk; int i; + /* + * For zero-copy and auto buffer register modes, I/O references + * might not be dropped naturally when the daemon is killed, but + * io_uring guarantees that registered bvec kernel buffers are + * unregistered finally when freeing io_uring context, then the + * active references are dropped. + * + * Wait until active references are dropped for avoiding use-after-free + * + * registered buffer may be unregistered in io_ring's release hander, + * so have to wait by scheduling work function for avoiding the two + * file release dependency. + */ + if (ublk_check_and_reset_active_ref(ub)) { + schedule_delayed_work(&ub->exit_work, 1); + return; + } + /* * disk isn't attached yet, either device isn't live, or it has * been removed already, so we needn't to do anything @@ -1673,6 +1724,23 @@ static int ublk_ch_release(struct inode *inode, struct file *filp) ublk_reset_ch_dev(ub); out: clear_bit(UB_STATE_OPEN, &ub->state); + + /* put the reference grabbed in ublk_ch_release() */ + ublk_put_device(ub); +} + +static int ublk_ch_release(struct inode *inode, struct file *filp) +{ + struct ublk_device *ub = filp->private_data; + + /* + * Grab ublk device reference, so it won't be gone until we are + * really released from work function. + */ + ublk_get_device(ub); + + INIT_DELAYED_WORK(&ub->exit_work, ublk_ch_release_work_fn); + schedule_delayed_work(&ub->exit_work, 0); return 0; } From 9b2785ea8592f239836405de023c75c4f3f5ce00 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 27 Aug 2025 20:16:00 +0800 Subject: [PATCH 0766/1292] ublk selftests: add --no_ublk_fixed_fd for not using registered ublk char device Add a new command line option --no_ublk_fixed_fd that excludes the ublk control device (/dev/ublkcN) from io_uring's registered files array. When this option is used, only backing files are registered starting from index 1, while the ublk control device is accessed using its raw file descriptor. Add ublk_get_registered_fd() helper function that returns the appropriate file descriptor for use with io_uring operations. Key optimizations implemented: - Cache UBLKS_Q_NO_UBLK_FIXED_FD flag in ublk_queue.flags to avoid reading dev->no_ublk_fixed_fd in fast path - Cache ublk char device fd in ublk_queue.ublk_fd for fast access - Update ublk_get_registered_fd() to use ublk_queue * parameter - Update io_uring_prep_buf_register/unregister() to use ublk_queue * - Replace ublk_device * access with ublk_queue * access in fast paths Also pass --no_ublk_fixed_fd to test_stress_04.sh for covering plain ublk char device mode. Signed-off-by: Ming Lei Link: https://lore.kernel.org/r/20250827121602.2619736-3-ming.lei@redhat.com Signed-off-by: Jens Axboe --- tools/testing/selftests/ublk/file_backed.c | 10 ++--- tools/testing/selftests/ublk/kublk.c | 38 +++++++++++++--- tools/testing/selftests/ublk/kublk.h | 45 +++++++++++++------ tools/testing/selftests/ublk/null.c | 4 +- tools/testing/selftests/ublk/stripe.c | 4 +- .../testing/selftests/ublk/test_stress_04.sh | 6 +-- 6 files changed, 74 insertions(+), 33 deletions(-) diff --git a/tools/testing/selftests/ublk/file_backed.c b/tools/testing/selftests/ublk/file_backed.c index 2d93ac860bd590..cd9fe69ecce201 100644 --- a/tools/testing/selftests/ublk/file_backed.c +++ b/tools/testing/selftests/ublk/file_backed.c @@ -20,7 +20,7 @@ static int loop_queue_flush_io(struct ublk_thread *t, struct ublk_queue *q, struct io_uring_sqe *sqe[1]; ublk_io_alloc_sqes(t, sqe, 1); - io_uring_prep_fsync(sqe[0], 1 /*fds[1]*/, IORING_FSYNC_DATASYNC); + io_uring_prep_fsync(sqe[0], ublk_get_registered_fd(q, 1) /*fds[1]*/, IORING_FSYNC_DATASYNC); io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE); /* bit63 marks us as tgt io */ sqe[0]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1); @@ -42,7 +42,7 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, if (!sqe[0]) return -ENOMEM; - io_uring_prep_rw(op, sqe[0], 1 /*fds[1]*/, + io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 1) /*fds[1]*/, addr, iod->nr_sectors << 9, iod->start_sector << 9); @@ -56,19 +56,19 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, ublk_io_alloc_sqes(t, sqe, 3); - io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index); sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; sqe[0]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); - io_uring_prep_rw(op, sqe[1], 1 /*fds[1]*/, 0, + io_uring_prep_rw(op, sqe[1], ublk_get_registered_fd(q, 1) /*fds[1]*/, 0, iod->nr_sectors << 9, iod->start_sector << 9); sqe[1]->buf_index = tag; sqe[1]->flags |= IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK; sqe[1]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1); - io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index); sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1); return 2; diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index 6512dfbdbce3a8..b71faba86c3bf2 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -432,7 +432,7 @@ static void ublk_thread_deinit(struct ublk_thread *t) } } -static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags) +static int ublk_queue_init(struct ublk_queue *q, unsigned long long extra_flags) { struct ublk_dev *dev = q->dev; int depth = dev->dev_info.queue_depth; @@ -446,6 +446,9 @@ static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags) q->flags = dev->dev_info.flags; q->flags |= extra_flags; + /* Cache fd in queue for fast path access */ + q->ublk_fd = dev->fds[0]; + cmd_buf_size = ublk_queue_cmd_buf_sz(q); off = UBLKSRV_CMD_BUF_OFFSET + q->q_id * ublk_queue_max_cmd_buf_sz(); q->io_cmd_buf = mmap(0, cmd_buf_size, PROT_READ, @@ -481,9 +484,10 @@ static int ublk_queue_init(struct ublk_queue *q, unsigned extra_flags) return -ENOMEM; } -static int ublk_thread_init(struct ublk_thread *t) +static int ublk_thread_init(struct ublk_thread *t, unsigned long long extra_flags) { struct ublk_dev *dev = t->dev; + unsigned long long flags = dev->dev_info.flags | extra_flags; int ring_depth = dev->tgt.sq_depth, cq_depth = dev->tgt.cq_depth; int ret; @@ -512,7 +516,17 @@ static int ublk_thread_init(struct ublk_thread *t) io_uring_register_ring_fd(&t->ring); - ret = io_uring_register_files(&t->ring, dev->fds, dev->nr_fds); + if (flags & UBLKS_Q_NO_UBLK_FIXED_FD) { + /* Register only backing files starting from index 1, exclude ublk control device */ + if (dev->nr_fds > 1) { + ret = io_uring_register_files(&t->ring, &dev->fds[1], dev->nr_fds - 1); + } else { + /* No backing files to register, skip file registration */ + ret = 0; + } + } else { + ret = io_uring_register_files(&t->ring, dev->fds, dev->nr_fds); + } if (ret) { ublk_err("ublk dev %d thread %d register files failed %d\n", t->dev->dev_info.dev_id, t->idx, ret); @@ -626,9 +640,12 @@ int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io) /* These fields should be written once, never change */ ublk_set_sqe_cmd_op(sqe[0], cmd_op); - sqe[0]->fd = 0; /* dev->fds[0] */ + sqe[0]->fd = ublk_get_registered_fd(q, 0); /* dev->fds[0] */ sqe[0]->opcode = IORING_OP_URING_CMD; - sqe[0]->flags = IOSQE_FIXED_FILE; + if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD) + sqe[0]->flags = 0; /* Use raw FD, not fixed file */ + else + sqe[0]->flags = IOSQE_FIXED_FILE; sqe[0]->rw_flags = 0; cmd->tag = io->tag; cmd->q_id = q->q_id; @@ -832,6 +849,7 @@ struct ublk_thread_info { unsigned idx; sem_t *ready; cpu_set_t *affinity; + unsigned long long extra_flags; }; static void *ublk_io_handler_fn(void *data) @@ -844,7 +862,7 @@ static void *ublk_io_handler_fn(void *data) t->dev = info->dev; t->idx = info->idx; - ret = ublk_thread_init(t); + ret = ublk_thread_init(t, info->extra_flags); if (ret) { ublk_err("ublk dev %d thread %u init failed\n", dev_id, t->idx); @@ -934,6 +952,8 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev) if (ctx->auto_zc_fallback) extra_flags = UBLKS_Q_AUTO_BUF_REG_FALLBACK; + if (ctx->no_ublk_fixed_fd) + extra_flags |= UBLKS_Q_NO_UBLK_FIXED_FD; for (i = 0; i < dinfo->nr_hw_queues; i++) { dev->q[i].dev = dev; @@ -951,6 +971,7 @@ static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev) tinfo[i].dev = dev; tinfo[i].idx = i; tinfo[i].ready = &ready; + tinfo[i].extra_flags = extra_flags; /* * If threads are not tied 1:1 to queues, setting thread @@ -1471,7 +1492,7 @@ static void __cmd_create_help(char *exe, bool recovery) printf("%s %s -t [null|loop|stripe|fault_inject] [-q nr_queues] [-d depth] [-n dev_id]\n", exe, recovery ? "recover" : "add"); printf("\t[--foreground] [--quiet] [-z] [--auto_zc] [--auto_zc_fallback] [--debug_mask mask] [-r 0|1 ] [-g]\n"); - printf("\t[-e 0|1 ] [-i 0|1]\n"); + printf("\t[-e 0|1 ] [-i 0|1] [--no_ublk_fixed_fd]\n"); printf("\t[--nthreads threads] [--per_io_tasks]\n"); printf("\t[target options] [backfile1] [backfile2] ...\n"); printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n"); @@ -1534,6 +1555,7 @@ int main(int argc, char *argv[]) { "size", 1, NULL, 's'}, { "nthreads", 1, NULL, 0 }, { "per_io_tasks", 0, NULL, 0 }, + { "no_ublk_fixed_fd", 0, NULL, 0 }, { 0, 0, 0, 0 } }; const struct ublk_tgt_ops *ops = NULL; @@ -1613,6 +1635,8 @@ int main(int argc, char *argv[]) ctx.nthreads = strtol(optarg, NULL, 10); if (!strcmp(longopts[option_idx].name, "per_io_tasks")) ctx.per_io_tasks = 1; + if (!strcmp(longopts[option_idx].name, "no_ublk_fixed_fd")) + ctx.no_ublk_fixed_fd = 1; break; case '?': /* diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h index 219233f8a05363..5e55484fb0aa26 100644 --- a/tools/testing/selftests/ublk/kublk.h +++ b/tools/testing/selftests/ublk/kublk.h @@ -77,6 +77,7 @@ struct dev_ctx { unsigned int recovery:1; unsigned int auto_zc_fallback:1; unsigned int per_io_tasks:1; + unsigned int no_ublk_fixed_fd:1; int _evtfd; int _shmid; @@ -166,7 +167,9 @@ struct ublk_queue { /* borrow one bit of ublk uapi flags, which may never be used */ #define UBLKS_Q_AUTO_BUF_REG_FALLBACK (1ULL << 63) +#define UBLKS_Q_NO_UBLK_FIXED_FD (1ULL << 62) __u64 flags; + int ublk_fd; /* cached ublk char device fd */ struct ublk_io ios[UBLK_QUEUE_DEPTH]; }; @@ -273,34 +276,48 @@ static inline int ublk_io_alloc_sqes(struct ublk_thread *t, return nr_sqes; } -static inline void io_uring_prep_buf_register(struct io_uring_sqe *sqe, - int dev_fd, int tag, int q_id, __u64 index) +static inline int ublk_get_registered_fd(struct ublk_queue *q, int fd_index) +{ + if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD) { + if (fd_index == 0) + /* Return the raw ublk FD for index 0 */ + return q->ublk_fd; + /* Adjust index for backing files (index 1 becomes 0, etc.) */ + return fd_index - 1; + } + return fd_index; +} + +static inline void __io_uring_prep_buf_reg_unreg(struct io_uring_sqe *sqe, + struct ublk_queue *q, int tag, int q_id, __u64 index) { struct ublksrv_io_cmd *cmd = (struct ublksrv_io_cmd *)sqe->cmd; + int dev_fd = ublk_get_registered_fd(q, 0); io_uring_prep_read(sqe, dev_fd, 0, 0, 0); sqe->opcode = IORING_OP_URING_CMD; - sqe->flags |= IOSQE_FIXED_FILE; - sqe->cmd_op = UBLK_U_IO_REGISTER_IO_BUF; + if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD) + sqe->flags &= ~IOSQE_FIXED_FILE; + else + sqe->flags |= IOSQE_FIXED_FILE; cmd->tag = tag; cmd->addr = index; cmd->q_id = q_id; } -static inline void io_uring_prep_buf_unregister(struct io_uring_sqe *sqe, - int dev_fd, int tag, int q_id, __u64 index) +static inline void io_uring_prep_buf_register(struct io_uring_sqe *sqe, + struct ublk_queue *q, int tag, int q_id, __u64 index) { - struct ublksrv_io_cmd *cmd = (struct ublksrv_io_cmd *)sqe->cmd; + __io_uring_prep_buf_reg_unreg(sqe, q, tag, q_id, index); + sqe->cmd_op = UBLK_U_IO_REGISTER_IO_BUF; +} - io_uring_prep_read(sqe, dev_fd, 0, 0, 0); - sqe->opcode = IORING_OP_URING_CMD; - sqe->flags |= IOSQE_FIXED_FILE; +static inline void io_uring_prep_buf_unregister(struct io_uring_sqe *sqe, + struct ublk_queue *q, int tag, int q_id, __u64 index) +{ + __io_uring_prep_buf_reg_unreg(sqe, q, tag, q_id, index); sqe->cmd_op = UBLK_U_IO_UNREGISTER_IO_BUF; - - cmd->tag = tag; - cmd->addr = index; - cmd->q_id = q_id; } static inline void *ublk_get_sqe_cmd(const struct io_uring_sqe *sqe) diff --git a/tools/testing/selftests/ublk/null.c b/tools/testing/selftests/ublk/null.c index f0e0003a486018..280043f6b6896a 100644 --- a/tools/testing/selftests/ublk/null.c +++ b/tools/testing/selftests/ublk/null.c @@ -63,7 +63,7 @@ static int null_queue_zc_io(struct ublk_thread *t, struct ublk_queue *q, ublk_io_alloc_sqes(t, sqe, 3); - io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index); sqe[0]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; @@ -71,7 +71,7 @@ static int null_queue_zc_io(struct ublk_thread *t, struct ublk_queue *q, __setup_nop_io(tag, iod, sqe[1], q->q_id); sqe[1]->flags |= IOSQE_IO_HARDLINK; - io_uring_prep_buf_unregister(sqe[2], 0, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index); sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1); // buf register is marked as IOSQE_CQE_SKIP_SUCCESS diff --git a/tools/testing/selftests/ublk/stripe.c b/tools/testing/selftests/ublk/stripe.c index 1fb9b7cc281b0b..791fa8dc165109 100644 --- a/tools/testing/selftests/ublk/stripe.c +++ b/tools/testing/selftests/ublk/stripe.c @@ -142,7 +142,7 @@ static int stripe_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, ublk_io_alloc_sqes(t, sqe, s->nr + extra); if (zc) { - io_uring_prep_buf_register(sqe[0], 0, tag, q->q_id, io->buf_index); + io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, io->buf_index); sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; sqe[0]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); @@ -168,7 +168,7 @@ static int stripe_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, if (zc) { struct io_uring_sqe *unreg = sqe[s->nr + 1]; - io_uring_prep_buf_unregister(unreg, 0, tag, q->q_id, io->buf_index); + io_uring_prep_buf_unregister(unreg, q, tag, q->q_id, io->buf_index); unreg->user_data = build_user_data( tag, ublk_cmd_op_nr(unreg->cmd_op), 0, q->q_id, 1); } diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 40d1437ca298f7..3f901db4d09dc9 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -28,14 +28,14 @@ _create_backfile 0 256M _create_backfile 1 128M _create_backfile 2 128M -ublk_io_and_kill_daemon 8G -t null -q 4 -z & -ublk_io_and_kill_daemon 256M -t loop -q 4 -z "${UBLK_BACKFILES[0]}" & +ublk_io_and_kill_daemon 8G -t null -q 4 -z --no_ublk_fixed_fd & +ublk_io_and_kill_daemon 256M -t loop -q 4 -z --no_ublk_fixed_fd "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 -z "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & - ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & + ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi From d985b60f47893e8fd43989662111bebe78311cd1 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 28 Aug 2025 15:53:57 +0800 Subject: [PATCH 0767/1292] ASoC: amd: use int type to store negative error codes Change the 'ret' variable from u32 to int to store negative error codes directly or returned by other functions. Storing the negative error codes in unsigned type, doesn't cause an issue at runtime but it's ugly as pants. Additionally, assigning negative error codes to unsigned type may trigger a GCC warning when the -Wsign-conversion flag is enabled. No effect on runtime. Signed-off-by: Qianfeng Rong Reviewed-by: Mario Limonciello Message-ID: <20250828075406.386208-2-rongqianfeng@vivo.com> Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-rembrandt.c | 2 +- sound/soc/amd/raven/acp3x-i2s.c | 3 ++- sound/soc/amd/vangogh/acp5x-i2s.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index aeffd24710e7d6..7e9c07488dcca4 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -147,7 +147,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; - u32 ret; + int ret; chip = dev_get_platdata(&pdev->dev); if (!chip || !chip->base) { diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index e7f2a05e802cf2..352485dd98b143 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -149,8 +149,9 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct i2s_stream_instance *rtd; - u32 ret, val, period_bytes, reg_val, ier_val, water_val; + u32 val, period_bytes, reg_val, ier_val, water_val; u32 buf_size, buf_reg; + int ret; rtd = substream->runtime->private_data; period_bytes = frames_to_bytes(substream->runtime, diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c index 7dbe33f4b8678d..bf719f62861746 100644 --- a/sound/soc/amd/vangogh/acp5x-i2s.c +++ b/sound/soc/amd/vangogh/acp5x-i2s.c @@ -234,8 +234,9 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream, { struct i2s_stream_instance *rtd; struct i2s_dev_data *adata; - u32 ret, val, period_bytes, reg_val, ier_val, water_val; + u32 val, period_bytes, reg_val, ier_val, water_val; u32 buf_size, buf_reg; + int ret; adata = snd_soc_dai_get_drvdata(dai); rtd = substream->runtime->private_data; From 784771cdd77091e7e93b78b5de55006295cc7b8e Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 28 Aug 2025 15:53:58 +0800 Subject: [PATCH 0768/1292] ASoC: adau1977: use int type to store negative error codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the 'ret' variable from unsigned int to int to store negative error codes or zero returned by regmap_update_bits(). Storing the negative error codes in unsigned type, doesn't cause an issue at runtime but it's ugly as pants. Additionally, assigning negative error codes to unsigned type may trigger a GCC warning when the -Wsign-conversion flag is enabled. No effect on runtime. Signed-off-by: Qianfeng Rong Reviewed-by: Nuno SĆ” Message-ID: <20250828075406.386208-3-rongqianfeng@vivo.com> Signed-off-by: Mark Brown --- sound/soc/codecs/adau1977.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index ae59efb38f265f..c193a9f22f5901 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -795,7 +795,7 @@ static int adau1977_set_sysclk(struct snd_soc_component *component, struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component); unsigned int mask = 0; unsigned int clk_src; - unsigned int ret; + int ret; if (dir != SND_SOC_CLOCK_IN) return -EINVAL; From 11f5c5f9e43e9020bae452232983fe98e7abfce0 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 28 Aug 2025 15:53:59 +0800 Subject: [PATCH 0769/1292] ASoC: qcom: use int type to store negative error codes Change the 'ret' variable from unsigned int to int to store negative error codes or zero returned by regmap_field_write(). Storing the negative error codes in unsigned type, doesn't cause an issue at runtime but it's ugly as pants. Additionally, assigning negative error codes to unsigned type may trigger a GCC warning when the -Wsign-conversion flag is enabled. No effect on runtime. Signed-off-by: Qianfeng Rong Reviewed-by: Dmitry Baryshkov Message-ID: <20250828075406.386208-4-rongqianfeng@vivo.com> Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cdc-dma.c | 3 ++- sound/soc/qcom/lpass-hdmi.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/lpass-cdc-dma.c b/sound/soc/qcom/lpass-cdc-dma.c index 8106c586f68a4e..2dc8c75c4bf08c 100644 --- a/sound/soc/qcom/lpass-cdc-dma.c +++ b/sound/soc/qcom/lpass-cdc-dma.c @@ -217,8 +217,9 @@ static int lpass_cdc_dma_daiops_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); struct lpaif_dmactl *dmactl = NULL; - unsigned int ret, regval; + unsigned int regval; unsigned int channels = params_channels(params); + int ret; int id; switch (channels) { diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c index ce753ebc08945a..6d9795306cfa91 100644 --- a/sound/soc/qcom/lpass-hdmi.c +++ b/sound/soc/qcom/lpass-hdmi.c @@ -23,7 +23,6 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t format = params_format(params); unsigned int rate = params_rate(params); unsigned int channels = params_channels(params); - unsigned int ret; int bitwidth; unsigned int word_length; unsigned int ch_sts_buf0; @@ -33,6 +32,7 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream, unsigned int ch = 0; struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl; struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl; + int ret; bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { From 5b4dcaf851df8c414bfc2ac3bf9c65fc942f3be4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Aug 2025 15:27:16 +0200 Subject: [PATCH 0770/1292] ASoC: amd: acp: Remove (explicitly) unused header The fwnode.h is not supposed to be used by the drivers as it has the definitions for the core parts for different device property provider implementations. Drop it. Note, that fwnode API for drivers is provided in property.h which is included here. Signed-off-by: Andy Shevchenko Message-ID: <20250826132734.278226-1-andriy.shevchenko@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/amd/acp/amd-sdw-acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/amd-sdw-acpi.c b/sound/soc/amd/acp/amd-sdw-acpi.c index 238b584887eead..0160b0df26a098 100644 --- a/sound/soc/amd/acp/amd-sdw-acpi.c +++ b/sound/soc/amd/acp/amd-sdw-acpi.c @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include #include From f4672dc6e9c07643c8c755856ba8e9eb9ca95d0c Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 28 Aug 2025 23:07:01 +0800 Subject: [PATCH 0771/1292] regmap: use int type to store negative error codes Change the 'ret' variable from unsigned int to int to store negative error codes or zero returned by regmap_field_read() and regmap_read(), and change '-1' to 'negative errno' in the comments. Storing the negative error codes in unsigned type, doesn't cause an issue at runtime but it's ugly as pants. Additionally, assigning negative error codes to unsigned type may trigger a GCC warning when the -Wsign-conversion flag is enabled. No effect on runtime. Signed-off-by: Qianfeng Rong Message-ID: <20250828150702.193288-1-rongqianfeng@vivo.com> Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 6883e1a43fe5d7..ce9be3989a218d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2258,12 +2258,14 @@ EXPORT_SYMBOL_GPL(regmap_field_update_bits_base); * @field: Register field to operate on * @bits: Bits to test * - * Returns -1 if the underlying regmap_field_read() fails, 0 if at least one of the - * tested bits is not set and 1 if all tested bits are set. + * Returns negative errno if the underlying regmap_field_read() fails, + * 0 if at least one of the tested bits is not set and 1 if all tested + * bits are set. */ int regmap_field_test_bits(struct regmap_field *field, unsigned int bits) { - unsigned int val, ret; + unsigned int val; + int ret; ret = regmap_field_read(field, &val); if (ret) @@ -3309,7 +3311,8 @@ EXPORT_SYMBOL_GPL(regmap_update_bits_base); */ int regmap_test_bits(struct regmap *map, unsigned int reg, unsigned int bits) { - unsigned int val, ret; + unsigned int val; + int ret; ret = regmap_read(map, reg, &val); if (ret) From 3c75dc44ad11c347596aa81af3c8d4a7547dd517 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 27 Aug 2025 17:29:54 +0200 Subject: [PATCH 0772/1292] platform/x86: asus-wmi: map more keys on ExpertBook B9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * there is a dedicated "noise cancel" key in top row, between mic mute and PrintScreen; it sends 0xCA when pressed by itself (mapped to F13), 0xCB with Fn (mapped to F14) * Fn+f sends 0x9D; it is not documented in the manual, but some web search results mention "asus intelligent performance"; mapped to FN_F Signed-off-by: Anton Khirnov Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250827152954.4844-1-anton@khirnov.net Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/asus-nb-wmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 6928bb6ae0f3c8..3a488cf9ca06c9 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -632,6 +632,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */ { KE_KEY, 0x95, { KEY_MEDIA } }, { KE_KEY, 0x99, { KEY_PHONE } }, /* Conflicts with fan mode switch */ + { KE_KEY, 0X9D, { KEY_FN_F } }, { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ @@ -646,6 +647,8 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_IGNORE, 0xC0, }, /* External display connect/disconnect notification */ { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, + { KE_KEY, 0xCA, { KEY_F13 } }, /* Noise cancelling on Expertbook B9 */ + { KE_KEY, 0xCB, { KEY_F14 } }, /* Fn+noise-cancel */ { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ { KE_IGNORE, 0xCF, }, /* AC mode */ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ From c96f86217bb28e019403bb8f59eacd8ad5a7ad1a Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Wed, 27 Aug 2025 15:13:51 +0200 Subject: [PATCH 0773/1292] platform/x86/amd/pmc: Add TUXEDO IB Pro Gen10 AMD to spurious 8042 quirks list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents instant wakeup ~1s after suspend. It seems to be kernel/system dependent if the IRQ actually manages to wake the system every time or if it gets ignored (and everything works as expected). Signed-off-by: Christoffer Sandberg Signed-off-by: Werner Sembach Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250827131424.16436-1-wse@tuxedocomputers.com Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/amd/pmc/pmc-quirks.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/platform/x86/amd/pmc/pmc-quirks.c b/drivers/platform/x86/amd/pmc/pmc-quirks.c index 7ffc659b279441..18fb44139de251 100644 --- a/drivers/platform/x86/amd/pmc/pmc-quirks.c +++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c @@ -248,6 +248,20 @@ static const struct dmi_system_id fwbug_list[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Lafite Pro V 14M"), } }, + { + .ident = "TUXEDO InfinityBook Pro 14/15 AMD Gen10", + .driver_data = &quirk_spurious_8042, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "XxHP4NAx"), + } + }, + { + .ident = "TUXEDO InfinityBook Pro 14/15 AMD Gen10", + .driver_data = &quirk_spurious_8042, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"), + } + }, {} }; From 5549202b9c02c2ecbc8634768a3da8d9e82d548d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 07:24:33 +0200 Subject: [PATCH 0774/1292] platform/x86: asus-wmi: Fix racy registrations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit asus_wmi_register_driver() may be called from multiple drivers concurrently, which can lead to the racy list operations, eventually corrupting the memory and hitting Oops on some ASUS machines. Also, the error handling is missing, and it forgot to unregister ACPI lps0 dev ops in the error case. This patch covers those issues by introducing a simple mutex at acpi_wmi_register_driver() & *_unregister_driver, and adding the proper call of asus_s2idle_check_unregister() in the error path. Fixes: feea7bd6b02d ("platform/x86: asus-wmi: Refactor Ally suspend/resume") Link: https://bugzilla.suse.com/show_bug.cgi?id=1246924 Link: https://lore.kernel.org/07815053-0e31-4e8e-8049-b652c929323b@kernel.org Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20250827052441.23382-1-tiwai@suse.de Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/asus-wmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index f7191fdded14d2..e72a2b5d158e9c 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -5088,16 +5088,22 @@ static int asus_wmi_probe(struct platform_device *pdev) asus_s2idle_check_register(); - return asus_wmi_add(pdev); + ret = asus_wmi_add(pdev); + if (ret) + asus_s2idle_check_unregister(); + + return ret; } static bool used; +static DEFINE_MUTEX(register_mutex); int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver) { struct platform_driver *platform_driver; struct platform_device *platform_device; + guard(mutex)(®ister_mutex); if (used) return -EBUSY; @@ -5120,6 +5126,7 @@ EXPORT_SYMBOL_GPL(asus_wmi_register_driver); void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) { + guard(mutex)(®ister_mutex); asus_s2idle_check_unregister(); platform_device_unregister(driver->platform_device); From 3010da6ecf2225e41a79b06bc5f4c9750a4d35cb Mon Sep 17 00:00:00 2001 From: Li Yifan Date: Mon, 25 Aug 2025 23:45:50 -0400 Subject: [PATCH 0775/1292] platform/x86/intel/pmc: Add Bartlett Lake support to intel_pmc_core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Bartlett Lake P-core only product support to intel_pmc_core driver. Bartlett Lake hybrid product reuses Raptor Lake model name so it is already enabled. Acked-by: Xi Pardee Signed-off-by: Li Yifan Link: https://lore.kernel.org/r/20250826034550.2284738-1-yifan2.li@intel.com Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/intel/pmc/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 540cd2fb0673bf..d040290e80ff5e 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1625,6 +1625,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { X86_MATCH_VFM(INTEL_RAPTORLAKE_P, &tgl_l_pmc_dev), X86_MATCH_VFM(INTEL_RAPTORLAKE, &adl_pmc_dev), X86_MATCH_VFM(INTEL_RAPTORLAKE_S, &adl_pmc_dev), + X86_MATCH_VFM(INTEL_BARTLETTLAKE, &adl_pmc_dev), X86_MATCH_VFM(INTEL_METEORLAKE_L, &mtl_pmc_dev), X86_MATCH_VFM(INTEL_ARROWLAKE, &arl_pmc_dev), X86_MATCH_VFM(INTEL_ARROWLAKE_H, &arl_h_pmc_dev), From 23408874e90ee299ab731bc0e0a9b3339dfc3c6e Mon Sep 17 00:00:00 2001 From: Edip Hazuri Date: Thu, 14 Aug 2025 23:45:32 +0300 Subject: [PATCH 0776/1292] platform/x86: hp-wmi: Add support for Fn+P hotkey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Fn+P hotkey found on newer HP Victus (and probably newer Omen) laptops. This hotkey is intended for use with Omen Gaming Hub to change the performance profile (see [1]). Pressing Fn+P under linux produced the following warning in dmesg: > hp_wmi: Unknown event_id - 27 - 0x7 Implemented a handling for this event so that the hotkey cycles between the platform profiles when triggered. Tested on Victus 16-s1011nt (9Z791EA, MB 8C9C). Changes in v2: - Make the key just switches between platform profiles instead of assigning a key event code. - v1: https://lore.kernel.org/all/20250802213541.18791-2-edip@medip.dev/ [1]: https://jpcdn.it/img/adadf6c927ffeb75afd8038f95db400a.png Signed-off-by: Edip Hazuri Link: https://lore.kernel.org/r/20250814204529.18467-4-edip@medip.dev Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/hp/hp-wmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 60c8ac8d902c4f..8b3533d6ba091a 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -122,6 +122,7 @@ enum hp_wmi_event_ids { HPWMI_BATTERY_CHARGE_PERIOD = 0x10, HPWMI_SANITIZATION_MODE = 0x17, HPWMI_CAMERA_TOGGLE = 0x1A, + HPWMI_FN_P_HOTKEY = 0x1B, HPWMI_OMEN_KEY = 0x1D, HPWMI_SMART_EXPERIENCE_APP = 0x21, }; @@ -981,6 +982,9 @@ static void hp_wmi_notify(union acpi_object *obj, void *context) key_code, 1, true)) pr_info("Unknown key code - 0x%x\n", key_code); break; + case HPWMI_FN_P_HOTKEY: + platform_profile_cycle(); + break; case HPWMI_OMEN_KEY: if (event_data) /* Only should be true for HP Omen */ key_code = event_data; From b0908e03fdd488a5ffd5b80d86dcfc77207464e7 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Tue, 26 Aug 2025 22:40:07 +0200 Subject: [PATCH 0777/1292] platform/x86: acer-wmi: Stop using ACPI bitmap for platform profile choices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out that the platform firmware on some models does not return valid data when reading the bitmap of supported platform profiles. This prevents the driver from loading on said models, even when the platform profile interface itself works. Fix this by stop using said bitmap until we have figured out how the OEM software itself detects available platform profiles. Tested-by: Lynne Megido Reported-by: Lynne Megido Closes: https://lore.kernel.org/platform-driver-x86/3f56e68f-85df-4c0a-982c-43f9d635be38@bune.city/ Fixes: 191e21f1a4c3 ("platform/x86: acer-wmi: use an ACPI bitmap to set the platform profile choices") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20250826204007.5088-1-W_Armin@gmx.de Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/acer-wmi.c | 71 ++++++--------------------------- 1 file changed, 12 insertions(+), 59 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 69336bd778eead..13eb22b35aa8f8 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -129,6 +129,7 @@ enum acer_wmi_predator_v4_oc { enum acer_wmi_gaming_misc_setting { ACER_WMID_MISC_SETTING_OC_1 = 0x0005, ACER_WMID_MISC_SETTING_OC_2 = 0x0007, + /* Unreliable on some models */ ACER_WMID_MISC_SETTING_SUPPORTED_PROFILES = 0x000A, ACER_WMID_MISC_SETTING_PLATFORM_PROFILE = 0x000B, }; @@ -794,9 +795,6 @@ static bool platform_profile_support; */ static int last_non_turbo_profile = INT_MIN; -/* The most performant supported profile */ -static int acer_predator_v4_max_perf; - enum acer_predator_v4_thermal_profile { ACER_PREDATOR_V4_THERMAL_PROFILE_QUIET = 0x00, ACER_PREDATOR_V4_THERMAL_PROFILE_BALANCED = 0x01, @@ -2014,7 +2012,7 @@ acer_predator_v4_platform_profile_set(struct device *dev, if (err) return err; - if (tp != acer_predator_v4_max_perf) + if (tp != ACER_PREDATOR_V4_THERMAL_PROFILE_TURBO) last_non_turbo_profile = tp; return 0; @@ -2023,55 +2021,14 @@ acer_predator_v4_platform_profile_set(struct device *dev, static int acer_predator_v4_platform_profile_probe(void *drvdata, unsigned long *choices) { - unsigned long supported_profiles; - int err; + set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); + set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices); + set_bit(PLATFORM_PROFILE_BALANCED, choices); + set_bit(PLATFORM_PROFILE_QUIET, choices); + set_bit(PLATFORM_PROFILE_LOW_POWER, choices); - err = WMID_gaming_get_misc_setting(ACER_WMID_MISC_SETTING_SUPPORTED_PROFILES, - (u8 *)&supported_profiles); - if (err) - return err; - - /* Iterate through supported profiles in order of increasing performance */ - if (test_bit(ACER_PREDATOR_V4_THERMAL_PROFILE_ECO, &supported_profiles)) { - set_bit(PLATFORM_PROFILE_LOW_POWER, choices); - acer_predator_v4_max_perf = ACER_PREDATOR_V4_THERMAL_PROFILE_ECO; - last_non_turbo_profile = ACER_PREDATOR_V4_THERMAL_PROFILE_ECO; - } - - if (test_bit(ACER_PREDATOR_V4_THERMAL_PROFILE_QUIET, &supported_profiles)) { - set_bit(PLATFORM_PROFILE_QUIET, choices); - acer_predator_v4_max_perf = ACER_PREDATOR_V4_THERMAL_PROFILE_QUIET; - last_non_turbo_profile = ACER_PREDATOR_V4_THERMAL_PROFILE_QUIET; - } - - if (test_bit(ACER_PREDATOR_V4_THERMAL_PROFILE_BALANCED, &supported_profiles)) { - set_bit(PLATFORM_PROFILE_BALANCED, choices); - acer_predator_v4_max_perf = ACER_PREDATOR_V4_THERMAL_PROFILE_BALANCED; - last_non_turbo_profile = ACER_PREDATOR_V4_THERMAL_PROFILE_BALANCED; - } - - if (test_bit(ACER_PREDATOR_V4_THERMAL_PROFILE_PERFORMANCE, &supported_profiles)) { - set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices); - acer_predator_v4_max_perf = ACER_PREDATOR_V4_THERMAL_PROFILE_PERFORMANCE; - - /* We only use this profile as a fallback option in case no prior - * profile is supported. - */ - if (last_non_turbo_profile < 0) - last_non_turbo_profile = ACER_PREDATOR_V4_THERMAL_PROFILE_PERFORMANCE; - } - - if (test_bit(ACER_PREDATOR_V4_THERMAL_PROFILE_TURBO, &supported_profiles)) { - set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); - acer_predator_v4_max_perf = ACER_PREDATOR_V4_THERMAL_PROFILE_TURBO; - - /* We need to handle the hypothetical case where only the turbo profile - * is supported. In this case the turbo toggle will essentially be a - * no-op. - */ - if (last_non_turbo_profile < 0) - last_non_turbo_profile = ACER_PREDATOR_V4_THERMAL_PROFILE_TURBO; - } + /* Set default non-turbo profile */ + last_non_turbo_profile = ACER_PREDATOR_V4_THERMAL_PROFILE_BALANCED; return 0; } @@ -2108,19 +2065,15 @@ static int acer_thermal_profile_change(void) if (cycle_gaming_thermal_profile) { platform_profile_cycle(); } else { - /* Do nothing if no suitable platform profiles where found */ - if (last_non_turbo_profile < 0) - return 0; - err = WMID_gaming_get_misc_setting( ACER_WMID_MISC_SETTING_PLATFORM_PROFILE, ¤t_tp); if (err) return err; - if (current_tp == acer_predator_v4_max_perf) + if (current_tp == ACER_PREDATOR_V4_THERMAL_PROFILE_TURBO) tp = last_non_turbo_profile; else - tp = acer_predator_v4_max_perf; + tp = ACER_PREDATOR_V4_THERMAL_PROFILE_TURBO; err = WMID_gaming_set_misc_setting( ACER_WMID_MISC_SETTING_PLATFORM_PROFILE, tp); @@ -2128,7 +2081,7 @@ static int acer_thermal_profile_change(void) return err; /* Store last profile for toggle */ - if (current_tp != acer_predator_v4_max_perf) + if (current_tp != ACER_PREDATOR_V4_THERMAL_PROFILE_TURBO) last_non_turbo_profile = current_tp; platform_profile_notify(platform_profile_device); From 95a7c5000956f939b86d8b00b8e6b8345f4a9b65 Mon Sep 17 00:00:00 2001 From: Coly Li Date: Thu, 28 Aug 2025 23:48:35 +0800 Subject: [PATCH 0778/1292] bcache: change maintainer's email address Change to my new email address on fnnas.com. Signed-off-by: Coly Li Link: https://lore.kernel.org/r/20250828154835.32926-1-colyli@kernel.org Signed-off-by: Jens Axboe --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa457..b47daf498a97bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4205,7 +4205,7 @@ W: http://www.baycom.org/~tom/ham/ham.html F: drivers/net/hamradio/baycom* BCACHE (BLOCK LAYER CACHE) -M: Coly Li +M: Coly Li M: Kent Overstreet L: linux-bcache@vger.kernel.org S: Maintained From 112f7d3cff02e357c2f7a116fd7ab6a366ed27f4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 16:11:00 +0200 Subject: [PATCH 0779/1292] ALSA: hda: Avoid binding with SOF for SKL/KBL platforms For Intel SKL and KBL platforms, it may be bound with one of three HD-audio drivers (AVS, SOF and legacy). AVS is the preferred one when DMIC is detected, and that's how it's defined in the snd-intel-dspcfg config table. But, when AVS driver is disabled (CONFIG_SND_SOC_INTEL_AVS=n), the device may be bound freely with either SOF or legacy driver. Before 6.17, the legacy driver took it primarily, but on 6.17, likely due to the recent code shuffling, SOF driver seems taking it at first, and fails to probe. For avoiding the regression, we should enforce to bind those with the legacy HD-audio drvier when AVS is disabled. This patch adds the extra two entries in intel-dspcfg table that are applied only when CONFIG_SND_SOC_INTEL_AVS=n, for binding with the legacy driver. Note that there are entries for APL in that config table block, but APL may be supported by SOF for certain setups, so the choice can't be exclusive. Hence this patch includes only SKL and KBL. Link: https://bugzilla.suse.com/show_bug.cgi?id=1248121 Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20250828141101.16294-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/core/intel-dsp-config.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/hda/core/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c index 00f184917623d6..c15284742899ff 100644 --- a/sound/hda/core/intel-dsp-config.c +++ b/sound/hda/core/intel-dsp-config.c @@ -116,6 +116,13 @@ static const struct config_entry config_table[] = { .flags = FLAG_SST, .device = PCI_DEVICE_ID_INTEL_HDA_FCL, }, +#else /* AVS disabled; force to legacy as SOF doesn't work for SKL or KBL */ + { + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, + }, + { + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, + }, #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { From b720269334f55f2e683fbb8f1f065a12f2c72eb6 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 13:19:23 +0100 Subject: [PATCH 0780/1292] KVM: arm64: Check for SYSREGS_ON_CPU before accessing the 32bit state Just like c6e35dff58d3 ("KVM: arm64: Check for SYSREGS_ON_CPU before accessing the CPU state") fixed the 64bit state access, add a check for the 32bit state actually being on the CPU before writing it. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20250817121926.217900-2-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/exception.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c index 95d186e0bf54f8..3e67333197ab2a 100644 --- a/arch/arm64/kvm/hyp/exception.c +++ b/arch/arm64/kvm/hyp/exception.c @@ -59,7 +59,7 @@ static void __vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long target_mode, static void __vcpu_write_spsr_abt(struct kvm_vcpu *vcpu, u64 val) { - if (has_vhe()) + if (has_vhe() && vcpu_get_flag(vcpu, SYSREGS_ON_CPU)) write_sysreg(val, spsr_abt); else vcpu->arch.ctxt.spsr_abt = val; @@ -67,7 +67,7 @@ static void __vcpu_write_spsr_abt(struct kvm_vcpu *vcpu, u64 val) static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val) { - if (has_vhe()) + if (has_vhe() && vcpu_get_flag(vcpu, SYSREGS_ON_CPU)) write_sysreg(val, spsr_und); else vcpu->arch.ctxt.spsr_und = val; From e3f6836a632e6d68201b6bc6e02bda92b00f3f57 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 13:19:24 +0100 Subject: [PATCH 0781/1292] KVM: arm64: Simplify sysreg access on exception delivery Distinguishing between NV and VHE is slightly pointless, and only serves as an extra complication, or a way to introduce bugs, such as the way SPSR_EL1 gets written without checking for the state being resident. Get rid if this silly distinction, and fix the bug in one go. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20250817121926.217900-3-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/hyp/exception.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c index 3e67333197ab2a..bef40ddb16dbc2 100644 --- a/arch/arm64/kvm/hyp/exception.c +++ b/arch/arm64/kvm/hyp/exception.c @@ -22,36 +22,28 @@ static inline u64 __vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) { - u64 val; - - if (unlikely(vcpu_has_nv(vcpu))) + if (has_vhe()) return vcpu_read_sys_reg(vcpu, reg); - else if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) && - __vcpu_read_sys_reg_from_cpu(reg, &val)) - return val; return __vcpu_sys_reg(vcpu, reg); } static inline void __vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg) { - if (unlikely(vcpu_has_nv(vcpu))) + if (has_vhe()) vcpu_write_sys_reg(vcpu, val, reg); - else if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU) || - !__vcpu_write_sys_reg_to_cpu(val, reg)) + else __vcpu_assign_sys_reg(vcpu, reg, val); } static void __vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long target_mode, u64 val) { - if (unlikely(vcpu_has_nv(vcpu))) { + if (has_vhe()) { if (target_mode == PSR_MODE_EL1h) vcpu_write_sys_reg(vcpu, val, SPSR_EL1); else vcpu_write_sys_reg(vcpu, val, SPSR_EL2); - } else if (has_vhe()) { - write_sysreg_el1(val, SYS_SPSR); } else { __vcpu_assign_sys_reg(vcpu, SPSR_EL1, val); } From ec0ab059d4359b2dad69f4ef90fa58a0bcdef525 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 13:19:25 +0100 Subject: [PATCH 0782/1292] KVM: arm64: Fix vcpu_{read,write}_sys_reg() accessors Volodymyr reports (again!) that under some circumstances (E2H==0, walking S1 PTs), PAR_EL1 doesn't report the value of the latest walk in the CPU register, but that instead the value is written to the backing store. Further investigation indicates that the root cause of this is that a group of registers (PAR_EL1, TPIDR*_EL{0,1}, the *32_EL2 dregs) should always be considered as "on CPU", as they are not remapped between EL1 and EL2. We fail to treat them accordingly, and end-up considering that the register (PAR_EL1 in this example) should be written to memory instead of in the register. While it would be possible to quickly work around it, it is obvious that the way we track these things at the moment is pretty horrible, and could do with some improvement. Revamp the whole thing by: - defining a location for a register (memory, cpu), potentially depending on the state of the vcpu - define a transformation for this register (mapped register, potential translation, special register needing some particular attention) - convey this information in a structure that can be easily passed around As a result, the accessors themselves become much simpler, as the state is explicit instead of being driven by hard-to-understand conventions. We get rid of the "pure EL2 register" notion, which wasn't very useful, and add sanitisation of the values by applying the RESx masks as required, something that was missing so far. And of course, we add the missing registers to the list, with the indication that they are always loaded. Reported-by: Volodymyr Babchuk Signed-off-by: Marc Zyngier Fixes: fedc612314acf ("KVM: arm64: nv: Handle virtual EL2 registers in vcpu_read/write_sys_reg()") Link: https://lore.kernel.org/r/20250806141707.3479194-3-volodymyr_babchuk@epam.com Link: https://lore.kernel.org/r/20250817121926.217900-4-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 4 +- arch/arm64/kvm/sys_regs.c | 270 ++++++++++++++++++------------ 2 files changed, 162 insertions(+), 112 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index d373d555a69ba3..2de44dc630b5c0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1158,8 +1158,8 @@ u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64); __v; \ }) -u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg); -void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg); +u64 vcpu_read_sys_reg(const struct kvm_vcpu *, enum vcpu_sysreg); +void vcpu_write_sys_reg(struct kvm_vcpu *, u64, enum vcpu_sysreg); static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val) { diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index e387d1dfed1e64..fe7260eebcbc09 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -82,43 +82,105 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu, "sys_reg write to read-only register"); } -#define PURE_EL2_SYSREG(el2) \ - case el2: { \ - *el1r = el2; \ - return true; \ +enum sr_loc_attr { + SR_LOC_MEMORY = 0, /* Register definitely in memory */ + SR_LOC_LOADED = BIT(0), /* Register on CPU, unless it cannot */ + SR_LOC_MAPPED = BIT(1), /* Register in a different CPU register */ + SR_LOC_XLATED = BIT(2), /* Register translated to fit another reg */ + SR_LOC_SPECIAL = BIT(3), /* Demanding register, implies loaded */ +}; + +struct sr_loc { + enum sr_loc_attr loc; + enum vcpu_sysreg map_reg; + u64 (*xlate)(u64); +}; + +static enum sr_loc_attr locate_direct_register(const struct kvm_vcpu *vcpu, + enum vcpu_sysreg reg) +{ + switch (reg) { + case SCTLR_EL1: + case CPACR_EL1: + case TTBR0_EL1: + case TTBR1_EL1: + case TCR_EL1: + case TCR2_EL1: + case PIR_EL1: + case PIRE0_EL1: + case POR_EL1: + case ESR_EL1: + case AFSR0_EL1: + case AFSR1_EL1: + case FAR_EL1: + case MAIR_EL1: + case VBAR_EL1: + case CONTEXTIDR_EL1: + case AMAIR_EL1: + case CNTKCTL_EL1: + case ELR_EL1: + case SPSR_EL1: + case ZCR_EL1: + case SCTLR2_EL1: + /* + * EL1 registers which have an ELx2 mapping are loaded if + * we're not in hypervisor context. + */ + return is_hyp_ctxt(vcpu) ? SR_LOC_MEMORY : SR_LOC_LOADED; + + case TPIDR_EL0: + case TPIDRRO_EL0: + case TPIDR_EL1: + case PAR_EL1: + case DACR32_EL2: + case IFSR32_EL2: + case DBGVCR32_EL2: + /* These registers are always loaded, no matter what */ + return SR_LOC_LOADED; + + default: + /* Non-mapped EL2 registers are by definition in memory. */ + return SR_LOC_MEMORY; } +} -#define MAPPED_EL2_SYSREG(el2, el1, fn) \ - case el2: { \ - *xlate = fn; \ - *el1r = el1; \ - return true; \ +static void locate_mapped_el2_register(const struct kvm_vcpu *vcpu, + enum vcpu_sysreg reg, + enum vcpu_sysreg map_reg, + u64 (*xlate)(u64), + struct sr_loc *loc) +{ + if (!is_hyp_ctxt(vcpu)) { + loc->loc = SR_LOC_MEMORY; + return; } -static bool get_el2_to_el1_mapping(unsigned int reg, - unsigned int *el1r, u64 (**xlate)(u64)) + loc->loc = SR_LOC_LOADED | SR_LOC_MAPPED; + loc->map_reg = map_reg; + + WARN_ON(locate_direct_register(vcpu, map_reg) != SR_LOC_MEMORY); + + if (xlate != NULL && !vcpu_el2_e2h_is_set(vcpu)) { + loc->loc |= SR_LOC_XLATED; + loc->xlate = xlate; + } +} + +#define MAPPED_EL2_SYSREG(r, m, t) \ + case r: { \ + locate_mapped_el2_register(vcpu, r, m, t, loc); \ + break; \ + } + +static void locate_register(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg, + struct sr_loc *loc) { + if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU)) { + loc->loc = SR_LOC_MEMORY; + return; + } + switch (reg) { - PURE_EL2_SYSREG( VPIDR_EL2 ); - PURE_EL2_SYSREG( VMPIDR_EL2 ); - PURE_EL2_SYSREG( ACTLR_EL2 ); - PURE_EL2_SYSREG( HCR_EL2 ); - PURE_EL2_SYSREG( MDCR_EL2 ); - PURE_EL2_SYSREG( HSTR_EL2 ); - PURE_EL2_SYSREG( HACR_EL2 ); - PURE_EL2_SYSREG( VTTBR_EL2 ); - PURE_EL2_SYSREG( VTCR_EL2 ); - PURE_EL2_SYSREG( TPIDR_EL2 ); - PURE_EL2_SYSREG( HPFAR_EL2 ); - PURE_EL2_SYSREG( HCRX_EL2 ); - PURE_EL2_SYSREG( HFGRTR_EL2 ); - PURE_EL2_SYSREG( HFGWTR_EL2 ); - PURE_EL2_SYSREG( HFGITR_EL2 ); - PURE_EL2_SYSREG( HDFGRTR_EL2 ); - PURE_EL2_SYSREG( HDFGWTR_EL2 ); - PURE_EL2_SYSREG( HAFGRTR_EL2 ); - PURE_EL2_SYSREG( CNTVOFF_EL2 ); - PURE_EL2_SYSREG( CNTHCTL_EL2 ); MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1, translate_sctlr_el2_to_sctlr_el1 ); MAPPED_EL2_SYSREG(CPTR_EL2, CPACR_EL1, @@ -144,125 +206,113 @@ static bool get_el2_to_el1_mapping(unsigned int reg, MAPPED_EL2_SYSREG(ZCR_EL2, ZCR_EL1, NULL ); MAPPED_EL2_SYSREG(CONTEXTIDR_EL2, CONTEXTIDR_EL1, NULL ); MAPPED_EL2_SYSREG(SCTLR2_EL2, SCTLR2_EL1, NULL ); + case CNTHCTL_EL2: + /* CNTHCTL_EL2 is super special, until we support NV2.1 */ + loc->loc = ((is_hyp_ctxt(vcpu) && vcpu_el2_e2h_is_set(vcpu)) ? + SR_LOC_SPECIAL : SR_LOC_MEMORY); + break; default: - return false; + loc->loc = locate_direct_register(vcpu, reg); } } -u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) +u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg) { - u64 val = 0x8badf00d8badf00d; - u64 (*xlate)(u64) = NULL; - unsigned int el1r; + struct sr_loc loc = {}; + + locate_register(vcpu, reg, &loc); + + WARN_ON_ONCE(!has_vhe() && loc.loc != SR_LOC_MEMORY); - if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU)) - goto memory_read; + if (loc.loc & SR_LOC_SPECIAL) { + u64 val; - if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) { - if (!is_hyp_ctxt(vcpu)) - goto memory_read; + WARN_ON_ONCE(loc.loc & ~SR_LOC_SPECIAL); /* - * CNTHCTL_EL2 requires some special treatment to - * account for the bits that can be set via CNTKCTL_EL1. + * CNTHCTL_EL2 requires some special treatment to account + * for the bits that can be set via CNTKCTL_EL1 when E2H==1. */ switch (reg) { case CNTHCTL_EL2: - if (vcpu_el2_e2h_is_set(vcpu)) { - val = read_sysreg_el1(SYS_CNTKCTL); - val &= CNTKCTL_VALID_BITS; - val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS; - return val; - } - break; + val = read_sysreg_el1(SYS_CNTKCTL); + val &= CNTKCTL_VALID_BITS; + val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS; + return val; + default: + WARN_ON_ONCE(1); } + } - /* - * If this register does not have an EL1 counterpart, - * then read the stored EL2 version. - */ - if (reg == el1r) - goto memory_read; + if (loc.loc & SR_LOC_LOADED) { + enum vcpu_sysreg map_reg = reg; + u64 val = 0x8badf00d8badf00d; - /* - * If we have a non-VHE guest and that the sysreg - * requires translation to be used at EL1, use the - * in-memory copy instead. - */ - if (!vcpu_el2_e2h_is_set(vcpu) && xlate) - goto memory_read; + if (loc.loc & SR_LOC_MAPPED) + map_reg = loc.map_reg; - /* Get the current version of the EL1 counterpart. */ - WARN_ON(!__vcpu_read_sys_reg_from_cpu(el1r, &val)); - if (reg >= __SANITISED_REG_START__) - val = kvm_vcpu_apply_reg_masks(vcpu, reg, val); + if (!(loc.loc & SR_LOC_XLATED) && + __vcpu_read_sys_reg_from_cpu(map_reg, &val)) { + if (reg >= __SANITISED_REG_START__) + val = kvm_vcpu_apply_reg_masks(vcpu, reg, val); - return val; + return val; + } } - /* EL1 register can't be on the CPU if the guest is in vEL2. */ - if (unlikely(is_hyp_ctxt(vcpu))) - goto memory_read; - - if (__vcpu_read_sys_reg_from_cpu(reg, &val)) - return val; - -memory_read: return __vcpu_sys_reg(vcpu, reg); } -void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg) +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, enum vcpu_sysreg reg) { - u64 (*xlate)(u64) = NULL; - unsigned int el1r; + struct sr_loc loc = {}; - if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU)) - goto memory_write; + locate_register(vcpu, reg, &loc); - if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) { - if (!is_hyp_ctxt(vcpu)) - goto memory_write; + WARN_ON_ONCE(!has_vhe() && loc.loc != SR_LOC_MEMORY); - /* - * Always store a copy of the write to memory to avoid having - * to reverse-translate virtual EL2 system registers for a - * non-VHE guest hypervisor. - */ - __vcpu_assign_sys_reg(vcpu, reg, val); + if (loc.loc & SR_LOC_SPECIAL) { + + WARN_ON_ONCE(loc.loc & ~SR_LOC_SPECIAL); switch (reg) { case CNTHCTL_EL2: /* - * If E2H=0, CNHTCTL_EL2 is a pure shadow register. - * Otherwise, some of the bits are backed by + * If E2H=1, some of the bits are backed by * CNTKCTL_EL1, while the rest is kept in memory. * Yes, this is fun stuff. */ - if (vcpu_el2_e2h_is_set(vcpu)) - write_sysreg_el1(val, SYS_CNTKCTL); - return; + write_sysreg_el1(val, SYS_CNTKCTL); + break; + default: + WARN_ON_ONCE(1); } + } - /* No EL1 counterpart? We're done here.? */ - if (reg == el1r) - return; + if (loc.loc & SR_LOC_LOADED) { + enum vcpu_sysreg map_reg = reg; + u64 xlated_val; - if (!vcpu_el2_e2h_is_set(vcpu) && xlate) - val = xlate(val); + if (reg >= __SANITISED_REG_START__) + val = kvm_vcpu_apply_reg_masks(vcpu, reg, val); - /* Redirect this to the EL1 version of the register. */ - WARN_ON(!__vcpu_write_sys_reg_to_cpu(val, el1r)); - return; - } + if (loc.loc & SR_LOC_MAPPED) + map_reg = loc.map_reg; - /* EL1 register can't be on the CPU if the guest is in vEL2. */ - if (unlikely(is_hyp_ctxt(vcpu))) - goto memory_write; + if (loc.loc & SR_LOC_XLATED) + xlated_val = loc.xlate(val); + else + xlated_val = val; - if (__vcpu_write_sys_reg_to_cpu(val, reg)) - return; + __vcpu_write_sys_reg_to_cpu(xlated_val, map_reg); + + /* + * Fall through to write the backing store anyway, which + * allows translated registers to be directly read without a + * reverse translation. + */ + } -memory_write: __vcpu_assign_sys_reg(vcpu, reg, val); } From 3328d17e70545f83515b07851302d48c85c466b0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 17 Aug 2025 13:19:26 +0100 Subject: [PATCH 0783/1292] KVM: arm64: Remove __vcpu_{read,write}_sys_reg_{from,to}_cpu() There is no point having __vcpu_{read,write}_sys_reg_{from,to}_cpu() exposed to the rest of the kernel, as the only callers are in sys_regs.c. Move them where they below, which is another opportunity to simplify things a bit. Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20250817121926.217900-5-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 107 ------------------------------ arch/arm64/kvm/sys_regs.c | 84 +++++++++++++++++++++-- 2 files changed, 80 insertions(+), 111 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 2de44dc630b5c0..46900f1084ff2e 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1161,113 +1161,6 @@ u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64); u64 vcpu_read_sys_reg(const struct kvm_vcpu *, enum vcpu_sysreg); void vcpu_write_sys_reg(struct kvm_vcpu *, u64, enum vcpu_sysreg); -static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val) -{ - /* - * *** VHE ONLY *** - * - * System registers listed in the switch are not saved on every - * exit from the guest but are only saved on vcpu_put. - * - * SYSREGS_ON_CPU *MUST* be checked before using this helper. - * - * Note that MPIDR_EL1 for the guest is set by KVM via VMPIDR_EL2 but - * should never be listed below, because the guest cannot modify its - * own MPIDR_EL1 and MPIDR_EL1 is accessed for VCPU A from VCPU B's - * thread when emulating cross-VCPU communication. - */ - if (!has_vhe()) - return false; - - switch (reg) { - case SCTLR_EL1: *val = read_sysreg_s(SYS_SCTLR_EL12); break; - case CPACR_EL1: *val = read_sysreg_s(SYS_CPACR_EL12); break; - case TTBR0_EL1: *val = read_sysreg_s(SYS_TTBR0_EL12); break; - case TTBR1_EL1: *val = read_sysreg_s(SYS_TTBR1_EL12); break; - case TCR_EL1: *val = read_sysreg_s(SYS_TCR_EL12); break; - case TCR2_EL1: *val = read_sysreg_s(SYS_TCR2_EL12); break; - case PIR_EL1: *val = read_sysreg_s(SYS_PIR_EL12); break; - case PIRE0_EL1: *val = read_sysreg_s(SYS_PIRE0_EL12); break; - case POR_EL1: *val = read_sysreg_s(SYS_POR_EL12); break; - case ESR_EL1: *val = read_sysreg_s(SYS_ESR_EL12); break; - case AFSR0_EL1: *val = read_sysreg_s(SYS_AFSR0_EL12); break; - case AFSR1_EL1: *val = read_sysreg_s(SYS_AFSR1_EL12); break; - case FAR_EL1: *val = read_sysreg_s(SYS_FAR_EL12); break; - case MAIR_EL1: *val = read_sysreg_s(SYS_MAIR_EL12); break; - case VBAR_EL1: *val = read_sysreg_s(SYS_VBAR_EL12); break; - case CONTEXTIDR_EL1: *val = read_sysreg_s(SYS_CONTEXTIDR_EL12);break; - case TPIDR_EL0: *val = read_sysreg_s(SYS_TPIDR_EL0); break; - case TPIDRRO_EL0: *val = read_sysreg_s(SYS_TPIDRRO_EL0); break; - case TPIDR_EL1: *val = read_sysreg_s(SYS_TPIDR_EL1); break; - case AMAIR_EL1: *val = read_sysreg_s(SYS_AMAIR_EL12); break; - case CNTKCTL_EL1: *val = read_sysreg_s(SYS_CNTKCTL_EL12); break; - case ELR_EL1: *val = read_sysreg_s(SYS_ELR_EL12); break; - case SPSR_EL1: *val = read_sysreg_s(SYS_SPSR_EL12); break; - case PAR_EL1: *val = read_sysreg_par(); break; - case DACR32_EL2: *val = read_sysreg_s(SYS_DACR32_EL2); break; - case IFSR32_EL2: *val = read_sysreg_s(SYS_IFSR32_EL2); break; - case DBGVCR32_EL2: *val = read_sysreg_s(SYS_DBGVCR32_EL2); break; - case ZCR_EL1: *val = read_sysreg_s(SYS_ZCR_EL12); break; - case SCTLR2_EL1: *val = read_sysreg_s(SYS_SCTLR2_EL12); break; - default: return false; - } - - return true; -} - -static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg) -{ - /* - * *** VHE ONLY *** - * - * System registers listed in the switch are not restored on every - * entry to the guest but are only restored on vcpu_load. - * - * SYSREGS_ON_CPU *MUST* be checked before using this helper. - * - * Note that MPIDR_EL1 for the guest is set by KVM via VMPIDR_EL2 but - * should never be listed below, because the MPIDR should only be set - * once, before running the VCPU, and never changed later. - */ - if (!has_vhe()) - return false; - - switch (reg) { - case SCTLR_EL1: write_sysreg_s(val, SYS_SCTLR_EL12); break; - case CPACR_EL1: write_sysreg_s(val, SYS_CPACR_EL12); break; - case TTBR0_EL1: write_sysreg_s(val, SYS_TTBR0_EL12); break; - case TTBR1_EL1: write_sysreg_s(val, SYS_TTBR1_EL12); break; - case TCR_EL1: write_sysreg_s(val, SYS_TCR_EL12); break; - case TCR2_EL1: write_sysreg_s(val, SYS_TCR2_EL12); break; - case PIR_EL1: write_sysreg_s(val, SYS_PIR_EL12); break; - case PIRE0_EL1: write_sysreg_s(val, SYS_PIRE0_EL12); break; - case POR_EL1: write_sysreg_s(val, SYS_POR_EL12); break; - case ESR_EL1: write_sysreg_s(val, SYS_ESR_EL12); break; - case AFSR0_EL1: write_sysreg_s(val, SYS_AFSR0_EL12); break; - case AFSR1_EL1: write_sysreg_s(val, SYS_AFSR1_EL12); break; - case FAR_EL1: write_sysreg_s(val, SYS_FAR_EL12); break; - case MAIR_EL1: write_sysreg_s(val, SYS_MAIR_EL12); break; - case VBAR_EL1: write_sysreg_s(val, SYS_VBAR_EL12); break; - case CONTEXTIDR_EL1: write_sysreg_s(val, SYS_CONTEXTIDR_EL12);break; - case TPIDR_EL0: write_sysreg_s(val, SYS_TPIDR_EL0); break; - case TPIDRRO_EL0: write_sysreg_s(val, SYS_TPIDRRO_EL0); break; - case TPIDR_EL1: write_sysreg_s(val, SYS_TPIDR_EL1); break; - case AMAIR_EL1: write_sysreg_s(val, SYS_AMAIR_EL12); break; - case CNTKCTL_EL1: write_sysreg_s(val, SYS_CNTKCTL_EL12); break; - case ELR_EL1: write_sysreg_s(val, SYS_ELR_EL12); break; - case SPSR_EL1: write_sysreg_s(val, SYS_SPSR_EL12); break; - case PAR_EL1: write_sysreg_s(val, SYS_PAR_EL1); break; - case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break; - case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break; - case DBGVCR32_EL2: write_sysreg_s(val, SYS_DBGVCR32_EL2); break; - case ZCR_EL1: write_sysreg_s(val, SYS_ZCR_EL12); break; - case SCTLR2_EL1: write_sysreg_s(val, SYS_SCTLR2_EL12); break; - default: return false; - } - - return true; -} - struct kvm_vm_stat { struct kvm_vm_stat_generic generic; }; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index fe7260eebcbc09..cc0dbc45f14494 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -216,6 +216,82 @@ static void locate_register(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg, } } +static u64 read_sr_from_cpu(enum vcpu_sysreg reg) +{ + u64 val = 0x8badf00d8badf00d; + + switch (reg) { + case SCTLR_EL1: val = read_sysreg_s(SYS_SCTLR_EL12); break; + case CPACR_EL1: val = read_sysreg_s(SYS_CPACR_EL12); break; + case TTBR0_EL1: val = read_sysreg_s(SYS_TTBR0_EL12); break; + case TTBR1_EL1: val = read_sysreg_s(SYS_TTBR1_EL12); break; + case TCR_EL1: val = read_sysreg_s(SYS_TCR_EL12); break; + case TCR2_EL1: val = read_sysreg_s(SYS_TCR2_EL12); break; + case PIR_EL1: val = read_sysreg_s(SYS_PIR_EL12); break; + case PIRE0_EL1: val = read_sysreg_s(SYS_PIRE0_EL12); break; + case POR_EL1: val = read_sysreg_s(SYS_POR_EL12); break; + case ESR_EL1: val = read_sysreg_s(SYS_ESR_EL12); break; + case AFSR0_EL1: val = read_sysreg_s(SYS_AFSR0_EL12); break; + case AFSR1_EL1: val = read_sysreg_s(SYS_AFSR1_EL12); break; + case FAR_EL1: val = read_sysreg_s(SYS_FAR_EL12); break; + case MAIR_EL1: val = read_sysreg_s(SYS_MAIR_EL12); break; + case VBAR_EL1: val = read_sysreg_s(SYS_VBAR_EL12); break; + case CONTEXTIDR_EL1: val = read_sysreg_s(SYS_CONTEXTIDR_EL12);break; + case AMAIR_EL1: val = read_sysreg_s(SYS_AMAIR_EL12); break; + case CNTKCTL_EL1: val = read_sysreg_s(SYS_CNTKCTL_EL12); break; + case ELR_EL1: val = read_sysreg_s(SYS_ELR_EL12); break; + case SPSR_EL1: val = read_sysreg_s(SYS_SPSR_EL12); break; + case ZCR_EL1: val = read_sysreg_s(SYS_ZCR_EL12); break; + case SCTLR2_EL1: val = read_sysreg_s(SYS_SCTLR2_EL12); break; + case TPIDR_EL0: val = read_sysreg_s(SYS_TPIDR_EL0); break; + case TPIDRRO_EL0: val = read_sysreg_s(SYS_TPIDRRO_EL0); break; + case TPIDR_EL1: val = read_sysreg_s(SYS_TPIDR_EL1); break; + case PAR_EL1: val = read_sysreg_par(); break; + case DACR32_EL2: val = read_sysreg_s(SYS_DACR32_EL2); break; + case IFSR32_EL2: val = read_sysreg_s(SYS_IFSR32_EL2); break; + case DBGVCR32_EL2: val = read_sysreg_s(SYS_DBGVCR32_EL2); break; + default: WARN_ON_ONCE(1); + } + + return val; +} + +static void write_sr_to_cpu(enum vcpu_sysreg reg, u64 val) +{ + switch (reg) { + case SCTLR_EL1: write_sysreg_s(val, SYS_SCTLR_EL12); break; + case CPACR_EL1: write_sysreg_s(val, SYS_CPACR_EL12); break; + case TTBR0_EL1: write_sysreg_s(val, SYS_TTBR0_EL12); break; + case TTBR1_EL1: write_sysreg_s(val, SYS_TTBR1_EL12); break; + case TCR_EL1: write_sysreg_s(val, SYS_TCR_EL12); break; + case TCR2_EL1: write_sysreg_s(val, SYS_TCR2_EL12); break; + case PIR_EL1: write_sysreg_s(val, SYS_PIR_EL12); break; + case PIRE0_EL1: write_sysreg_s(val, SYS_PIRE0_EL12); break; + case POR_EL1: write_sysreg_s(val, SYS_POR_EL12); break; + case ESR_EL1: write_sysreg_s(val, SYS_ESR_EL12); break; + case AFSR0_EL1: write_sysreg_s(val, SYS_AFSR0_EL12); break; + case AFSR1_EL1: write_sysreg_s(val, SYS_AFSR1_EL12); break; + case FAR_EL1: write_sysreg_s(val, SYS_FAR_EL12); break; + case MAIR_EL1: write_sysreg_s(val, SYS_MAIR_EL12); break; + case VBAR_EL1: write_sysreg_s(val, SYS_VBAR_EL12); break; + case CONTEXTIDR_EL1: write_sysreg_s(val, SYS_CONTEXTIDR_EL12);break; + case AMAIR_EL1: write_sysreg_s(val, SYS_AMAIR_EL12); break; + case CNTKCTL_EL1: write_sysreg_s(val, SYS_CNTKCTL_EL12); break; + case ELR_EL1: write_sysreg_s(val, SYS_ELR_EL12); break; + case SPSR_EL1: write_sysreg_s(val, SYS_SPSR_EL12); break; + case ZCR_EL1: write_sysreg_s(val, SYS_ZCR_EL12); break; + case SCTLR2_EL1: write_sysreg_s(val, SYS_SCTLR2_EL12); break; + case TPIDR_EL0: write_sysreg_s(val, SYS_TPIDR_EL0); break; + case TPIDRRO_EL0: write_sysreg_s(val, SYS_TPIDRRO_EL0); break; + case TPIDR_EL1: write_sysreg_s(val, SYS_TPIDR_EL1); break; + case PAR_EL1: write_sysreg_s(val, SYS_PAR_EL1); break; + case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break; + case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break; + case DBGVCR32_EL2: write_sysreg_s(val, SYS_DBGVCR32_EL2); break; + default: WARN_ON_ONCE(1); + } +} + u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg) { struct sr_loc loc = {}; @@ -246,13 +322,13 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg) if (loc.loc & SR_LOC_LOADED) { enum vcpu_sysreg map_reg = reg; - u64 val = 0x8badf00d8badf00d; if (loc.loc & SR_LOC_MAPPED) map_reg = loc.map_reg; - if (!(loc.loc & SR_LOC_XLATED) && - __vcpu_read_sys_reg_from_cpu(map_reg, &val)) { + if (!(loc.loc & SR_LOC_XLATED)) { + u64 val = read_sr_from_cpu(map_reg); + if (reg >= __SANITISED_REG_START__) val = kvm_vcpu_apply_reg_masks(vcpu, reg, val); @@ -304,7 +380,7 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, enum vcpu_sysreg reg) else xlated_val = val; - __vcpu_write_sys_reg_to_cpu(xlated_val, map_reg); + write_sr_to_cpu(map_reg, xlated_val); /* * Fall through to write the backing store anyway, which From 3e7fd1febc3156d3d98fba229399a13b12d69707 Mon Sep 17 00:00:00 2001 From: Ajye Huang Date: Tue, 26 Aug 2025 23:40:40 +0800 Subject: [PATCH 0784/1292] ASoC: SOF: Intel: WCL: Add the sdw_process_wakeen op Add the missing op in the device description to avoid issues with jack detection. Fixes: 6b04629ae97a ("ASoC: SOF: Intel: add initial support for WCL") Acked-by: Peter Ujfalusi Signed-off-by: Ajye Huang Message-ID: <20250826154040.2723998-1-ajye_huang@compal.corp-partner.google.com> Signed-off-by: Mark Brown --- sound/soc/sof/intel/ptl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c index 1bc1f54c470df7..4633cd01e7dd4b 100644 --- a/sound/soc/sof/intel/ptl.c +++ b/sound/soc/sof/intel/ptl.c @@ -143,6 +143,7 @@ const struct sof_intel_dsp_desc wcl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_ext, .check_sdw_irq = lnl_dsp_check_sdw_irq, .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, + .sdw_process_wakeen = hda_sdw_process_wakeen_common, .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, .power_down_dsp = mtl_power_down_dsp, From ee372e645178802be7cb35263de941db7b2c5354 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 9 Aug 2025 15:48:10 +0100 Subject: [PATCH 0785/1292] KVM: arm64: nv: Fix ATS12 handling of single-stage translation Volodymyr reports that using a Xen DomU as a nested guest (where HCR_EL2.E2H == 0), ATS12 results in a translation that stops at the L2's S1, which isn't something you'd normally expects. Comparing the code against the spec proves to be illuminating, and suggests that the author of such code must have been tired, cross-eyed, drunk, or maybe all of the above. The gist of it is that, apart from HCR_EL2.VM or HCR_EL2.DC being 0, only the use of the EL2&0 translation regime limits the walk to S1 only, and that we must finish the S2 walk in any other case. Which solves the above issue, as E2H==0 indicates that ATS12 walks the EL1&0 translation regime. Explicitly checking for EL2&0 fixes this. Reported-by: Volodymyr Babchuk Suggested-by: Oliver Upton Signed-off-by: Marc Zyngier Fixes: be04cebf3e788 ("KVM: arm64: nv: Add emulation of AT S12E{0,1}{R,W}") Link: https://lore.kernel.org/r/20250806141707.3479194-2-volodymyr_babchuk@epam.com Link: https://lore.kernel.org/r/20250809144811.2314038-2-maz@kernel.org Signed-off-by: Oliver Upton --- arch/arm64/kvm/at.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 0e561053394938..d71ca4ddc9d1e5 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -1420,10 +1420,10 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) return; /* - * If we only have a single stage of translation (E2H=0 or - * TGE=1), exit early. Same thing if {VM,DC}=={0,0}. + * If we only have a single stage of translation (EL2&0), exit + * early. Same thing if {VM,DC}=={0,0}. */ - if (!vcpu_el2_e2h_is_set(vcpu) || vcpu_el2_tge_is_set(vcpu) || + if (compute_translation_regime(vcpu, op) == TR_EL20 || !(vcpu_read_sys_reg(vcpu, HCR_EL2) & (HCR_VM | HCR_DC))) return; From ebf2bfec412ad293a0b118fb1a20a551088ebc9b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 28 Aug 2025 15:16:16 -0700 Subject: [PATCH 0786/1292] MAINTAINERS: mark bcachefs externally maintained As per many long discussion threads, public and private. Signed-off-by: Linus Torvalds --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fed6cd812d796a..adcbb094ebd59e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4216,7 +4216,7 @@ F: drivers/md/bcache/ BCACHEFS M: Kent Overstreet L: linux-bcachefs@vger.kernel.org -S: Supported +S: Externally maintained C: irc://irc.oftc.net/bcache P: Documentation/filesystems/bcachefs/SubmittingPatches.rst T: git https://evilpiepirate.org/git/bcachefs.git From c34414883f773412964404d77cd2fea04c6f7d60 Mon Sep 17 00:00:00 2001 From: Louis-Alexis Eyraud Date: Mon, 18 Aug 2025 16:17:52 +0200 Subject: [PATCH 0787/1292] drm/mediatek: mtk_hdmi: Fix inverted parameters in some regmap_update_bits calls In mtk_hdmi driver, a recent change replaced custom register access function calls by regmap ones, but two replacements by regmap_update_bits were done incorrectly, because original offset and mask parameters were inverted, so fix them. Fixes: d6e25b3590a0 ("drm/mediatek: hdmi: Use regmap instead of iomem for main registers") Signed-off-by: Louis-Alexis Eyraud Reviewed-by: CK Hu Link: https://patchwork.kernel.org/project/dri-devel/patch/20250818-mt8173-fix-hdmi-issue-v1-1-55aff9b0295d@collabora.com/ Signed-off-by: Chun-Kuang Hu --- drivers/gpu/drm/mediatek/mtk_hdmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 845fd8aa43c3c9..b766dd5e6c8de6 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -182,8 +182,8 @@ static inline struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b) static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black) { - regmap_update_bits(hdmi->regs, VIDEO_SOURCE_SEL, - VIDEO_CFG_4, black ? GEN_RGB : NORMAL_PATH); + regmap_update_bits(hdmi->regs, VIDEO_CFG_4, + VIDEO_SOURCE_SEL, black ? GEN_RGB : NORMAL_PATH); } static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) @@ -310,8 +310,8 @@ static void mtk_hdmi_hw_send_info_frame(struct mtk_hdmi *hdmi, u8 *buffer, static void mtk_hdmi_hw_send_aud_packet(struct mtk_hdmi *hdmi, bool enable) { - regmap_update_bits(hdmi->regs, AUDIO_PACKET_OFF, - GRL_SHIFT_R2, enable ? 0 : AUDIO_PACKET_OFF); + regmap_update_bits(hdmi->regs, GRL_SHIFT_R2, + AUDIO_PACKET_OFF, enable ? 0 : AUDIO_PACKET_OFF); } static void mtk_hdmi_hw_config_sys(struct mtk_hdmi *hdmi) From eaa9c1f31aef4d92d0ea6c9ecde33ea08733182a Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Wed, 27 Aug 2025 10:31:48 +0800 Subject: [PATCH 0788/1292] cpufreq: brcmstb-avs: Use scope-based cleanup helper Replace the manual cpufreq_cpu_put() with __free(put_cpufreq_policy) annotation for policy references. This reduces the risk of reference counting mistakes and aligns the code with the latest kernel style. No functional change intended. Signed-off-by: Zihuan Zhang [ Viresh: Minor changes to commit log ] Signed-off-by: Viresh Kumar --- drivers/cpufreq/brcmstb-avs-cpufreq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index 5940d262374f05..71450cca8e9f45 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -480,7 +480,7 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv) static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); struct private_data *priv; if (!policy) @@ -488,8 +488,6 @@ static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) priv = policy->driver_data; - cpufreq_cpu_put(policy); - return brcm_avs_get_frequency(priv->base); } From c8dc2368b23e1a9f11be4c941e13f3985195d0c9 Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Wed, 27 Aug 2025 10:31:49 +0800 Subject: [PATCH 0789/1292] cpufreq: CPPC: Use scope-based cleanup helper Replace the manual cpufreq_cpu_put() with __free(put_cpufreq_policy) annotation for policy references. This reduces the risk of reference counting mistakes and aligns the code with the latest kernel style. No functional change intended. Signed-off-by: Zihuan Zhang [ Viresh: Minor changes ] Signed-off-by: Viresh Kumar --- drivers/cpufreq/cppc_cpufreq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index ecbeb12f46e64a..12de0ac7bbaff0 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -722,8 +722,8 @@ static int cppc_get_perf_ctrs_sample(int cpu, static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) { + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); struct cppc_cpudata *cpu_data; u64 delivered_perf; int ret; @@ -733,8 +733,6 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) cpu_data = policy->driver_data; - cpufreq_cpu_put(policy); - ret = cppc_get_perf_ctrs_sample(cpu, &fb_ctrs_t0, &fb_ctrs_t1); if (ret) { if (ret == -EFAULT) From 95102e0cc15688ddffc8da1f15cfec2276fa45e5 Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Wed, 27 Aug 2025 10:31:54 +0800 Subject: [PATCH 0790/1292] cpufreq: s5pv210: Use scope-based cleanup helper Replace the manual cpufreq_cpu_put() with __free(put_cpufreq_policy) annotation for policy references. This reduces the risk of reference counting mistakes and aligns the code with the latest kernel style. No functional change intended. Signed-off-by: Zihuan Zhang [ Viresh: Minor changes ] Signed-off-by: Viresh Kumar --- drivers/cpufreq/s5pv210-cpufreq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 76c888ed8d160a..4215621deb3fe8 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -554,17 +554,15 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy) static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(0); int ret; - struct cpufreq_policy *policy; - policy = cpufreq_cpu_get(0); if (!policy) { pr_debug("cpufreq: get no policy for cpu0\n"); return NOTIFY_BAD; } ret = cpufreq_driver_target(policy, SLEEP_FREQ, 0); - cpufreq_cpu_put(policy); if (ret < 0) return NOTIFY_BAD; From 4aeda901d6896344c5b0b3a8428c4a830007ea85 Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Wed, 27 Aug 2025 10:31:52 +0800 Subject: [PATCH 0791/1292] cpufreq: mediatek: Use scope-based cleanup helper Replace the manual cpufreq_cpu_put() with __free(put_cpufreq_policy) annotation for policy references. This reduces the risk of reference counting mistakes and aligns the code with the latest kernel style. No functional change intended. Signed-off-by: Zihuan Zhang [ Viresh: Minor changes ] Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index f3f02c4b6888b4..fae062a6431fb6 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -320,7 +320,6 @@ static int mtk_cpufreq_opp_notifier(struct notifier_block *nb, struct dev_pm_opp *new_opp; struct mtk_cpu_dvfs_info *info; unsigned long freq, volt; - struct cpufreq_policy *policy; int ret = 0; info = container_of(nb, struct mtk_cpu_dvfs_info, opp_nb); @@ -353,12 +352,12 @@ static int mtk_cpufreq_opp_notifier(struct notifier_block *nb, } dev_pm_opp_put(new_opp); - policy = cpufreq_cpu_get(info->opp_cpu); - if (policy) { + + struct cpufreq_policy *policy __free(put_cpufreq_policy) + = cpufreq_cpu_get(info->opp_cpu); + if (policy) cpufreq_driver_target(policy, freq / 1000, CPUFREQ_RELATION_L); - cpufreq_cpu_put(policy); - } } } From 7bc0084632dda2907ff1d021dff36ffbdd83468c Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Wed, 27 Aug 2025 10:31:55 +0800 Subject: [PATCH 0792/1292] cpufreq: tegra186: Use scope-based cleanup helper Replace the manual cpufreq_cpu_put() with __free(put_cpufreq_policy) annotation for policy references. This reduces the risk of reference counting mistakes and aligns the code with the latest kernel style. No functional change intended. Signed-off-by: Zihuan Zhang [ Viresh: Minor changes ] Signed-off-by: Viresh Kumar --- drivers/cpufreq/tegra186-cpufreq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c index cbabb726c6645d..4270686fc3e3eb 100644 --- a/drivers/cpufreq/tegra186-cpufreq.c +++ b/drivers/cpufreq/tegra186-cpufreq.c @@ -103,13 +103,12 @@ static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy, static unsigned int tegra186_cpufreq_get(unsigned int cpu) { + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); struct tegra186_cpufreq_data *data = cpufreq_get_driver_data(); struct tegra186_cpufreq_cluster *cluster; - struct cpufreq_policy *policy; unsigned int edvd_offset, cluster_id; u32 ndiv; - policy = cpufreq_cpu_get(cpu); if (!policy) return 0; @@ -117,7 +116,6 @@ static unsigned int tegra186_cpufreq_get(unsigned int cpu) ndiv = readl(data->regs + edvd_offset) & EDVD_CORE_VOLT_FREQ_F_MASK; cluster_id = data->cpus[policy->cpu].bpmp_cluster_id; cluster = &data->clusters[cluster_id]; - cpufreq_cpu_put(policy); return (cluster->ref_clk_khz * ndiv) / cluster->div; } From 2cbe4ac193ed7172cfd825c0cc46ce4a41be4ba1 Mon Sep 17 00:00:00 2001 From: qaqland Date: Fri, 29 Aug 2025 14:40:48 +0800 Subject: [PATCH 0793/1292] ALSA: usb-audio: Add mute TLV for playback volumes on more devices Applying the quirk of that, the lowest Playback mixer volume setting mutes the audio output, on more devices. Suggested-by: Cryolitia PukNgae Signed-off-by: qaqland Link: https://patch.msgid.link/20250829-sound_quirk-v1-1-745529b44440@uniontech.com Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 8bc1e247cdf1af..766db7d00cbc95 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2199,6 +2199,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_SET_IFACE_FIRST), DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x0572, 0x1b08, /* Conexant Systems (Rockwell), Inc. */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x0572, 0x1b09, /* Conexant Systems (Rockwell), Inc. */ QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x05a3, 0x9420, /* ELP HD USB Camera */ @@ -2243,6 +2245,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */ QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0bda, 0x498a, /* Realtek Semiconductor Corp. */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0c45, 0x636b, /* Microdia JP001 USB Camera */ @@ -2259,6 +2263,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x12d1, 0x3a07, /* Huawei Technologies Co., Ltd. */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ @@ -2349,6 +2355,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x2a70, 0x1881, /* OnePlus Technology (Shenzhen) Co., Ltd. BE02T */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */ QUIRK_FLAG_GENERIC_IMPLICIT_FB), DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */ @@ -2365,6 +2373,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */ QUIRK_FLAG_IGNORE_CTL_ERROR), + DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */ + QUIRK_FLAG_MIXER_MIN_MUTE), DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */ From 6158a321c051095024e8306c8996b79e5f7f79b6 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 29 Aug 2025 11:29:07 +0300 Subject: [PATCH 0794/1292] ASoC: SOF: Intel: split codec mask detect and programming UNSOL We only need to detect codec mask in probe, but need to program UNSOL in probe and resume. We will detect codec mask and program UNSOL separately in the follow up commit. Signed-off-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Peter Ujfalusi Message-ID: <20250829082908.2693-2-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-codec.c | 3 --- sound/soc/sof/intel/hda-ctrl.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 2f9925830d1d53..37674ea452d6a2 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -260,9 +260,6 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev) sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) return; - /* Accept unsolicited responses */ - snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); - /* detect codecs */ if (!bus->codec_mask) { bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 4f34fd919a00aa..f43eb2a21f48da 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -220,6 +220,9 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) } usleep_range(1000, 1200); + /* Accept unsolicited responses */ + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); + hda_codec_detect_mask(sdev); /* clear stream status */ From 5c39bc498f5ff7ef016abf3f16698f3e8db79677 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 29 Aug 2025 11:29:08 +0300 Subject: [PATCH 0795/1292] ASoC: SOF: Intel: only detect codecs when HDA DSP probe SDW codecs use the global HDaudio WAKEEN/STS to detect wakes since LNL. But the wake event is handled in the SDW driver. We should only clear WAKESTS for the HDA and IDISP codecs that was detected when HDA DSP probe. The SoundWire codec will be included in the codec_mask if we read the STATESTS register when a SoundWire codec wake event happens. The commit avoid updating bus->codec_mask in resume to not clear WAKESTS of SoundWire codecs. Signed-off-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Peter Ujfalusi Message-ID: <20250829082908.2693-3-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 5 +++-- sound/soc/sof/intel/hda-dsp.c | 2 +- sound/soc/sof/intel/hda.c | 2 +- sound/soc/sof/intel/hda.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index f43eb2a21f48da..8332d4bda5581f 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -183,7 +183,7 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) } EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON"); -int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) { struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *stream; @@ -223,7 +223,8 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) /* Accept unsolicited responses */ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); - hda_codec_detect_mask(sdev); + if (detect_codec) + hda_codec_detect_mask(sdev); /* clear stream status */ list_for_each_entry(stream, &bus->stream_list, list) { diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f64e8a6a9a33c2..3ab6d5ce63298f 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -870,7 +870,7 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); /* reset and start hda controller */ - ret = hda_dsp_ctrl_init_chip(sdev); + ret = hda_dsp_ctrl_init_chip(sdev, false); if (ret < 0) { dev_err(sdev->dev, "error: failed to start controller after resume\n"); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c387efec41e93f..52e86fa6007788 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -616,7 +616,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); /* Init HDA controller after i915 init */ - ret = hda_dsp_ctrl_init_chip(sdev); + ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index e14f82c0831fad..28daf0a3b98484 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -757,7 +757,7 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); -int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev); +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec); void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev); /* * HDA bus operations. From f522da9ab56c96db8703b2ea0f09be7cdc3bffeb Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 29 Aug 2025 14:55:22 +0700 Subject: [PATCH 0796/1292] ASoC: doc: Internally link to Writing an ALSA Driver docs ASoC codec and platform driver docs contain reference to writing ALSA driver docs, as an external link. Use :doc: directive for the job instead. Signed-off-by: Bagas Sanjaya Message-ID: <20250829075524.45635-13-bagasdotme@gmail.com> Signed-off-by: Mark Brown --- Documentation/sound/soc/codec.rst | 4 ++-- Documentation/sound/soc/platform.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/soc/codec.rst b/Documentation/sound/soc/codec.rst index af973c4cac9309..b9d87a4f929b5d 100644 --- a/Documentation/sound/soc/codec.rst +++ b/Documentation/sound/soc/codec.rst @@ -131,8 +131,8 @@ The codec driver also supports the following ALSA PCM operations:- int (*prepare)(struct snd_pcm_substream *); }; -Please refer to the ALSA driver PCM documentation for details. -https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html +Please refer to the :doc:`ALSA driver PCM documentation +<../kernel-api/writing-an-alsa-driver>` for details. DAPM description diff --git a/Documentation/sound/soc/platform.rst b/Documentation/sound/soc/platform.rst index 7036630eaf016c..bd21d0a4dd9b0b 100644 --- a/Documentation/sound/soc/platform.rst +++ b/Documentation/sound/soc/platform.rst @@ -45,8 +45,8 @@ snd_soc_component_driver:- ... }; -Please refer to the ALSA driver documentation for details of audio DMA. -https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html +Please refer to the :doc:`ALSA driver documentation +<../kernel-api/writing-an-alsa-driver>` for details of audio DMA. An example DMA driver is soc/pxa/pxa2xx-pcm.c From 78811dd56def1479777c9823f3c2139739ef5bf5 Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Fri, 29 Aug 2025 16:46:06 +0800 Subject: [PATCH 0797/1292] ALSA: docs: Add documents for recently changes in snd-usb-audio Changed: - ignore_ctl_error - lowlatency - skip_validation - quirk_flags[19:24] [ corrected a typo -- tiwai ] Signed-off-by: Cryolitia PukNgae Link: https://patch.msgid.link/20250829-sound-doc-v1-1-e0110452b03d@uniontech.com Signed-off-by: Takashi Iwai --- Documentation/sound/alsa-configuration.rst | 29 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index a45174d165ebde..062b86522e4d9c 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -2253,8 +2253,15 @@ device_setup Default: 0x0000 ignore_ctl_error Ignore any USB-controller regarding mixer interface (default: no) + ``ignore_ctl_error=1`` may help when you get an error at accessing + the mixer element such as URB error -22. This happens on some + buggy USB device or the controller. This workaround corresponds to + the ``quirk_flags`` bit 14, too. autoclock Enable auto-clock selection for UAC2 devices (default: yes) +lowlatency + Enable low latency playback mode (default: yes). + Could disable it to switch back to the old mode if face a regression. quirk_alias Quirk alias list, pass strings like ``0123abcd:5678beef``, which applies the existing quirk for the device 5678:beef to a new @@ -2284,6 +2291,11 @@ delayed_register The driver prints a message like "Found post-registration device assignment: 1234abcd:04" for such a device, so that user can notice the need. +skip_validation + Skip unit descriptor validation (default: no). + The option is used to ignores the validation errors with the hexdump + of the unit descriptor instead of a driver probe error, so that we + can check its details. quirk_flags Contains the bit flags for various device specific workarounds. Applied to the corresponding card index. @@ -2307,6 +2319,16 @@ quirk_flags * bit 16: Set up the interface at first like UAC1 * bit 17: Apply the generic implicit feedback sync mode * bit 18: Don't apply implicit feedback sync mode + * bit 19: Don't closed interface during setting sample rate + * bit 20: Force an interface reset whenever stopping & restarting + a stream + * bit 21: Do not set PCM rate (frequency) when only one rate is + available for the given endpoint. + * bit 22: Set the fixed resolution 16 for Mic Capture Volume + * bit 23: Set the fixed resolution 384 for Mic Capture Volume + * bit 24: Set minimum volume control value as mute for devices + where the lowest playback value represents muted state instead + of minimum audible volume This module supports multiple devices, autoprobe and hotplugging. @@ -2314,10 +2336,9 @@ NB: ``nrpacks`` parameter can be modified dynamically via sysfs. Don't put the value over 20. Changing via sysfs has no sanity check. -NB: ``ignore_ctl_error=1`` may help when you get an error at accessing -the mixer element such as URB error -22. This happens on some -buggy USB device or the controller. This workaround corresponds to -the ``quirk_flags`` bit 14, too. +NB: ``ignore_ctl_error=1`` just provides a quick way to work around the +issues. If you have a buggy device that requires these quirks, please +report it to the upstream. NB: ``quirk_alias`` option is provided only for testing / development. If you want to have a proper support, contact to upstream for From 5d8c9c987fbdd65677315198c2b1f35a440d7cdf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:41 +0200 Subject: [PATCH 0798/1292] ALSA: hda: Introduce auto cleanup macros for PM The temporary power up/down of the codec via snd_hda_power_up() and _down() (or snd_hda_power_up_pm() and _down_pm()) is seen in various places. This patch introduces simple auto-cleanup macros for those call patterns, so that the drivers don't have to call the corresponding power-down calls explicitly. Namely, err = snd_hda_power_up(codec); if (err < 0) return err; .... snd_power_down(codec); can drop the *_down() call by replacing with CLASS(snd_hda_power, pm)(codec); if (pm.err < 0) return pm.err; Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-2-tiwai@suse.de --- include/sound/hda_codec.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 006d4e4a8195d0..5d9f0ef228af10 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -503,6 +503,36 @@ static inline bool hda_codec_need_resume(struct hda_codec *codec) return !codec->relaxed_resume && codec->jacktbl.used; } +/* + * PM with auto-cleanup: call like CLASS(snd_hda_power, pm)(codec) + * If the error handling is needed, refer pm.err. + */ +struct __hda_power_obj { + struct hda_codec *codec; + int err; +}; + +static inline struct __hda_power_obj __snd_hda_power_up(struct hda_codec *codec) +{ + struct __hda_power_obj T = { .codec = codec }; + T.err = snd_hda_power_up(codec); + return T; +} + +static inline struct __hda_power_obj __snd_hda_power_up_pm(struct hda_codec *codec) +{ + struct __hda_power_obj T = { .codec = codec }; + T.err = snd_hda_power_up_pm(codec); + return T; +} + +DEFINE_CLASS(snd_hda_power, struct __hda_power_obj, + snd_hda_power_down((_T).codec), __snd_hda_power_up(codec), + struct hda_codec *codec) +DEFINE_CLASS(snd_hda_power_pm, struct __hda_power_obj, + snd_hda_power_down_pm((_T).codec), __snd_hda_power_up_pm(codec), + struct hda_codec *codec) + #ifdef CONFIG_SND_HDA_PATCH_LOADER /* * patch firmware From e056e8e14c2e21956974712f737734e453cdb8dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:42 +0200 Subject: [PATCH 0799/1292] ALSA: hda/ca0132: Use cleanup macros for PM controls The new macro CLASS(snd_hda_power) can replace the manual snd_hda_power_up() and _down() calls as well as the *_pm_*() variants gracefully. Merely code cleanups and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-3-tiwai@suse.de --- sound/hda/codecs/ca0132.c | 125 +++++++++++++++----------------------- 1 file changed, 48 insertions(+), 77 deletions(-) diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c index b7d456e16c93f0..d2a6759b5effeb 100644 --- a/sound/hda/codecs/ca0132.c +++ b/sound/hda/codecs/ca0132.c @@ -4236,21 +4236,19 @@ static const unsigned int equalizer_vals_lookup[] = { static int tuning_ctl_set(struct hda_codec *codec, hda_nid_t nid, const unsigned int *lookup, int idx) { - int i = 0; + int i; - for (i = 0; i < TUNING_CTLS_COUNT; i++) - if (nid == ca0132_tuning_ctls[i].nid) - goto found; + for (i = 0; i < TUNING_CTLS_COUNT; i++) { + if (nid == ca0132_tuning_ctls[i].nid) { + CLASS(snd_hda_power, pm)(codec); + dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20, + ca0132_tuning_ctls[i].req, + &(lookup[idx]), sizeof(unsigned int)); + return 1; + } + } return -EINVAL; -found: - snd_hda_power_up(codec); - dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20, - ca0132_tuning_ctls[i].req, - &(lookup[idx]), sizeof(unsigned int)); - snd_hda_power_down(codec); - - return 1; } static int tuning_ctl_get(struct snd_kcontrol *kcontrol, @@ -4465,7 +4463,7 @@ static int ca0132_select_out(struct hda_codec *codec) codec_dbg(codec, "ca0132_select_out\n"); - snd_hda_power_up_pm(codec); + CLASS(snd_hda_power_pm, pm)(codec); auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; @@ -4486,12 +4484,12 @@ static int ca0132_select_out(struct hda_codec *codec) tmp = FLOAT_ONE; err = dspio_set_uint_param(codec, 0x80, 0x04, tmp); if (err < 0) - goto exit; + return err; /*enable speaker EQ*/ tmp = FLOAT_ONE; err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp); if (err < 0) - goto exit; + return err; /* Setup EAPD */ snd_hda_codec_write(codec, spec->out_pins[1], 0, @@ -4519,12 +4517,12 @@ static int ca0132_select_out(struct hda_codec *codec) tmp = FLOAT_ZERO; err = dspio_set_uint_param(codec, 0x80, 0x04, tmp); if (err < 0) - goto exit; + return err; /*disable speaker EQ*/ tmp = FLOAT_ZERO; err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp); if (err < 0) - goto exit; + return err; /* Setup EAPD */ snd_hda_codec_write(codec, spec->out_pins[0], 0, @@ -4548,10 +4546,7 @@ static int ca0132_select_out(struct hda_codec *codec) pin_ctl | PIN_HP); } -exit: - snd_hda_power_down_pm(codec); - - return err < 0 ? err : 0; + return 0; } static int ae5_headphone_gain_set(struct hda_codec *codec, long val); @@ -4775,7 +4770,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) codec_dbg(codec, "%s\n", __func__); - snd_hda_power_up_pm(codec); + CLASS(snd_hda_power_pm, pm)(codec); auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; @@ -4800,11 +4795,11 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /* Begin DSP output switch, mute DSP volume. */ err = dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_MUTE, FLOAT_ONE); if (err < 0) - goto exit; + return err; err = ca0132_alt_select_out_quirk_set(codec); if (err < 0) - goto exit; + return err; switch (spec->cur_out_type) { case SPEAKER_OUT: @@ -4835,7 +4830,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) err = dspio_set_uint_param(codec, 0x80, 0x04, tmp); if (err < 0) - goto exit; + return err; break; case HEADPHONE_OUT: @@ -4862,7 +4857,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ZERO); if (err < 0) - goto exit; + return err; break; } /* @@ -4877,7 +4872,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /* Set speaker EQ bypass attenuation to 0. */ err = dspio_set_uint_param(codec, 0x8f, 0x01, FLOAT_ZERO); if (err < 0) - goto exit; + return err; /* * Although unused on all cards but the AE series, this is always set @@ -4886,7 +4881,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) err = dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_USE_SPEAKER_EQ, FLOAT_ZERO); if (err < 0) - goto exit; + return err; if (spec->cur_out_type == SPEAKER_OUT) err = ca0132_alt_surround_set_bass_redirection(codec, @@ -4894,24 +4889,21 @@ static int ca0132_alt_select_out(struct hda_codec *codec) else err = ca0132_alt_surround_set_bass_redirection(codec, 0); if (err < 0) - goto exit; + return err; /* Unmute DSP now that we're done with output selection. */ err = dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_MUTE, FLOAT_ZERO); if (err < 0) - goto exit; + return err; if (spec->cur_out_type == SPEAKER_OUT) { err = ca0132_alt_set_full_range_speaker(codec); if (err < 0) - goto exit; + return err; } -exit: - snd_hda_power_down_pm(codec); - - return err < 0 ? err : 0; + return 0; } static void ca0132_unsol_hp_delayed(struct work_struct *work) @@ -5059,7 +5051,7 @@ static int ca0132_select_mic(struct hda_codec *codec) codec_dbg(codec, "ca0132_select_mic\n"); - snd_hda_power_up_pm(codec); + CLASS(snd_hda_power_pm, pm)(codec); auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID]; @@ -5092,8 +5084,6 @@ static int ca0132_select_mic(struct hda_codec *codec) ca0132_effects_set(codec, VOICE_FOCUS, 0); } - snd_hda_power_down_pm(codec); - return 0; } @@ -5110,7 +5100,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec) codec_dbg(codec, "%s\n", __func__); - snd_hda_power_up_pm(codec); + CLASS(snd_hda_power_pm, pm)(codec); chipio_set_stream_control(codec, 0x03, 0); chipio_set_stream_control(codec, 0x04, 0); @@ -5273,7 +5263,6 @@ static int ca0132_alt_select_in(struct hda_codec *codec) } ca0132_cvoice_switch_set(codec); - snd_hda_power_down_pm(codec); return 0; } @@ -5611,12 +5600,10 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, static void ca0132_alt_bass_redirection_xover_set(struct hda_codec *codec, long idx) { - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); dspio_set_param(codec, 0x96, 0x20, SPEAKER_BASS_REDIRECT_XOVER_FREQ, &(float_xbass_xover_lookup[idx]), sizeof(unsigned int)); - - snd_hda_power_down(codec); } /* @@ -5642,7 +5629,7 @@ static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid, else y = 1; - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); if (nid == XBASS_XOVER) { for (i = 0; i < OUT_EFFECTS_COUNT; i++) if (ca0132_effects[i].nid == X_BASS) @@ -5662,8 +5649,6 @@ static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid, &(lookup[idx]), sizeof(unsigned int)); } - snd_hda_power_down(codec); - return 0; } @@ -6342,12 +6327,11 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, hda_nid_t nid = get_amp_nid(kcontrol); int ch = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value; - int changed = 1; codec_dbg(codec, "ca0132_switch_put: nid=0x%x, val=%ld\n", nid, *valp); - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); /* vnode */ if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) { if (ch & 1) { @@ -6358,30 +6342,26 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, spec->vnode_rswitch[nid - VNODE_START_NID] = *valp; valp++; } - changed = ca0132_vnode_switch_set(kcontrol, ucontrol); - goto exit; + return ca0132_vnode_switch_set(kcontrol, ucontrol); } /* PE */ if (nid == PLAY_ENHANCEMENT) { spec->effects_switch[nid - EFFECT_START_NID] = *valp; - changed = ca0132_pe_switch_set(codec); - goto exit; + return ca0132_pe_switch_set(codec); } /* CrystalVoice */ if (nid == CRYSTAL_VOICE) { spec->effects_switch[nid - EFFECT_START_NID] = *valp; - changed = ca0132_cvoice_switch_set(codec); - goto exit; + return ca0132_cvoice_switch_set(codec); } /* out and in effects */ if (((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) || ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID))) { spec->effects_switch[nid - EFFECT_START_NID] = *valp; - changed = ca0132_effects_set(codec, nid, *valp); - goto exit; + return ca0132_effects_set(codec, nid, *valp); } /* mic boost */ @@ -6389,24 +6369,22 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, spec->cur_mic_boost = *valp; if (ca0132_use_alt_functions(spec)) { if (spec->in_enum_val != REAR_LINE_IN) - changed = ca0132_mic_boost_set(codec, *valp); + return ca0132_mic_boost_set(codec, *valp); } else { /* Mic boost does not apply to Digital Mic */ if (spec->cur_mic_type != DIGITAL_MIC) - changed = ca0132_mic_boost_set(codec, *valp); + return ca0132_mic_boost_set(codec, *valp); } - goto exit; + return 1; } if (nid == ZXR_HEADPHONE_GAIN) { spec->zxr_gain_set = *valp; if (spec->cur_out_type == HEADPHONE_OUT) - changed = zxr_headphone_gain_set(codec, *valp); + return zxr_headphone_gain_set(codec, *valp); else - changed = 0; - - goto exit; + return 0; } if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) { @@ -6414,7 +6392,7 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, if (spec->cur_out_type == SPEAKER_OUT) ca0132_alt_set_full_range_speaker(codec); - changed = 0; + return 0; } if (nid == BASS_REDIRECTION) { @@ -6422,12 +6400,10 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, if (spec->cur_out_type == SPEAKER_OUT) ca0132_alt_surround_set_bass_redirection(codec, *valp); - changed = 0; + return 0; } -exit: - snd_hda_power_down(codec); - return changed; + return 1; } /* @@ -6555,7 +6531,7 @@ static int ca0132_volume_put(struct snd_kcontrol *kcontrol, int dir = get_amp_direction(kcontrol); unsigned long pval; - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); mutex_lock(&codec->control_mutex); pval = kcontrol->private_value; kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch, @@ -6563,7 +6539,6 @@ static int ca0132_volume_put(struct snd_kcontrol *kcontrol, changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); kcontrol->private_value = pval; mutex_unlock(&codec->control_mutex); - snd_hda_power_down(codec); } return changed; @@ -6604,12 +6579,11 @@ static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol, valp++; } - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); ca0132_alt_dsp_volume_put(codec, vnid); mutex_lock(&codec->control_mutex); changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); mutex_unlock(&codec->control_mutex); - snd_hda_power_down(codec); return changed; } @@ -8664,14 +8638,13 @@ static void ca0132_process_dsp_response(struct hda_codec *codec, struct ca0132_spec *spec = codec->spec; codec_dbg(codec, "ca0132_process_dsp_response\n"); - snd_hda_power_up_pm(codec); + CLASS(snd_hda_power_pm, pm)(codec); if (spec->wait_scp) { if (dspio_get_response_data(codec) >= 0) spec->wait_scp = 0; } dspio_clear_response_queue(codec); - snd_hda_power_down_pm(codec); } static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) @@ -9546,7 +9519,7 @@ static int ca0132_init(struct hda_codec *codec) if (ca0132_use_pci_mmio(spec)) ca0132_mmio_init(codec); - snd_hda_power_up_pm(codec); + CLASS(snd_hda_power_pm, pm)(codec); if (ca0132_quirk(spec) == QUIRK_AE5 || ca0132_quirk(spec) == QUIRK_AE7) ae5_register_set(codec); @@ -9626,8 +9599,6 @@ static int ca0132_init(struct hda_codec *codec) ca0132_pe_switch_set(codec); } - snd_hda_power_down_pm(codec); - return 0; } From 264145020b243b354668fe0da4de2d6092c13978 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:43 +0200 Subject: [PATCH 0800/1292] ALSA: hda/hdmi: Use cleanup macros for PM controls The new macro CLASS(snd_hda_power_pm) can replace the manual snd_hda_power_up_pm() and _down() calls gracefully. Merely code cleanups and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-4-tiwai@suse.de --- sound/hda/codecs/hdmi/hdmi.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c index b5d840d9892b95..4b5d20f0fbe4e2 100644 --- a/sound/hda/codecs/hdmi/hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -1270,16 +1270,15 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, * the unsolicited response to avoid custom WARs. */ int present; - int ret; #ifdef CONFIG_PM if (dev->power.runtime_status == RPM_SUSPENDING) return; #endif - ret = snd_hda_power_up_pm(codec); - if (ret < 0 && pm_runtime_suspended(dev)) - goto out; + CLASS(snd_hda_power_pm, pm)(codec); + if (pm.err < 0 && pm_runtime_suspended(dev)) + return; present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); @@ -1302,8 +1301,6 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, update_eld(codec, per_pin, eld, repoll); mutex_unlock(&per_pin->lock); - out: - snd_hda_power_down_pm(codec); } static void silent_stream_enable(struct hda_codec *codec, @@ -1318,11 +1315,10 @@ static void silent_stream_enable(struct hda_codec *codec, * have to be done without mutex held. */ - err = snd_hda_power_up_pm(codec); - if (err < 0 && err != -EACCES) { + CLASS(snd_hda_power_pm, pm)(codec); + if (pm.err < 0 && pm.err != -EACCES) { codec_err(codec, - "Failed to power up codec for silent stream enable ret=[%d]\n", err); - snd_hda_power_down_pm(codec); + "Failed to power up codec for silent stream enable ret=[%d]\n", pm.err); return; } @@ -1361,8 +1357,6 @@ static void silent_stream_enable(struct hda_codec *codec, unlock_out: mutex_unlock(&per_pin->lock); - - snd_hda_power_down_pm(codec); } static void silent_stream_disable(struct hda_codec *codec, @@ -1370,14 +1364,13 @@ static void silent_stream_disable(struct hda_codec *codec, { struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_cvt *per_cvt; - int cvt_idx, err; + int cvt_idx; - err = snd_hda_power_up_pm(codec); - if (err < 0 && err != -EACCES) { + CLASS(snd_hda_power_pm, pm)(codec); + if (pm.err < 0 && pm.err != -EACCES) { codec_err(codec, "Failed to power up codec for silent stream disable ret=[%d]\n", - err); - snd_hda_power_down_pm(codec); + pm.err); return; } @@ -1401,8 +1394,6 @@ static void silent_stream_disable(struct hda_codec *codec, unlock_out: mutex_unlock(&per_pin->lock); - - snd_hda_power_down_pm(codec); } /* update ELD and jack state via audio component */ From cee9102fcdf4d2bff4ea4b46f70cba1ff7c8accb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:44 +0200 Subject: [PATCH 0801/1292] ALSA: hda/realtek: Use cleanup macros for PM controls The new macro CLASS(snd_hda_power_pm) can replace the manual snd_hda_power_up_pm() and _down() calls gracefully. Merely code cleanups and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-5-tiwai@suse.de --- sound/hda/codecs/realtek/alc269.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 0323606b3d6d9b..e2e65845d329c5 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -1224,9 +1224,8 @@ static void alc_update_vref_led(struct hda_codec *codec, hda_nid_t pin, pinval &= ~AC_PINCTL_VREFEN; pinval |= on ? AC_PINCTL_VREF_80 : AC_PINCTL_VREF_HIZ; /* temporarily power up/down for setting VREF */ - snd_hda_power_up_pm(codec); + CLASS(snd_hda_power_pm, pm)(codec); snd_hda_set_pin_ctl_cache(codec, pin, pinval); - snd_hda_power_down_pm(codec); } /* update mute-LED according to the speaker mute state via mic VREF pin */ From 8dad6b3dac2794c52d63b2336138392eddc17936 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:45 +0200 Subject: [PATCH 0802/1292] ALSA: hda/common: Use cleanup macros for PM controls The new macro CLASS(snd_hda_power_pm) can replace the manual snd_hda_power_up_pm() and _down() calls gracefully. A part of the code in codec_exec_verb() is factored out to a function, so that the auto-cleanup can be well scoped. Merely cleanups and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-6-tiwai@suse.de --- sound/hda/common/codec.c | 30 +++++++++++++++++++----------- sound/hda/common/proc.c | 4 +--- sound/hda/common/sysfs.c | 11 ++++------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 7a72d4c7ae914a..3e692dd6725e17 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -32,6 +32,23 @@ #define codec_has_clkstop(codec) \ ((codec)->core.power_caps & AC_PWRST_CLKSTOP) +static int call_exec_verb(struct hda_bus *bus, struct hda_codec *codec, + unsigned int cmd, unsigned int flags, + unsigned int *res) +{ + int err; + + CLASS(snd_hda_power_pm, pm)(codec); + mutex_lock(&bus->core.cmd_mutex); + if (flags & HDA_RW_NO_RESPONSE_FALLBACK) + bus->no_response_fallback = 1; + err = snd_hdac_bus_exec_verb_unlocked(&bus->core, codec->core.addr, + cmd, res); + bus->no_response_fallback = 0; + mutex_unlock(&bus->core.cmd_mutex); + return err; +} + /* * Send and receive a verb - passed to exec_verb override for hdac_device */ @@ -46,15 +63,7 @@ static int codec_exec_verb(struct hdac_device *dev, unsigned int cmd, return -1; again: - snd_hda_power_up_pm(codec); - mutex_lock(&bus->core.cmd_mutex); - if (flags & HDA_RW_NO_RESPONSE_FALLBACK) - bus->no_response_fallback = 1; - err = snd_hdac_bus_exec_verb_unlocked(&bus->core, codec->core.addr, - cmd, res); - bus->no_response_fallback = 0; - mutex_unlock(&bus->core.cmd_mutex); - snd_hda_power_down_pm(codec); + err = call_exec_verb(bus, codec, cmd, flags, res); if (!codec_in_pm(codec) && res && err == -EAGAIN) { if (bus->response_reset) { codec_dbg(codec, @@ -633,12 +642,11 @@ static void hda_jackpoll_work(struct work_struct *work) return; /* the power-up/down sequence triggers the runtime resume */ - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); /* update jacks manually if polling is required, too */ snd_hda_jack_set_dirty_all(codec); snd_hda_jack_poll_all(codec); schedule_delayed_work(&codec->jackpoll_work, codec->jackpoll_interval); - snd_hda_power_down(codec); } /* release all pincfg lists */ diff --git a/sound/hda/common/proc.c b/sound/hda/common/proc.c index d36195f73d45b3..5f3f61519ba646 100644 --- a/sound/hda/common/proc.c +++ b/sound/hda/common/proc.c @@ -781,7 +781,7 @@ static void print_codec_info(struct snd_info_entry *entry, fg = codec->core.afg; if (!fg) return; - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); snd_iprintf(buffer, "Default PCM:\n"); print_pcm_caps(buffer, codec, fg); snd_iprintf(buffer, "Default Amp-In caps: "); @@ -794,7 +794,6 @@ static void print_codec_info(struct snd_info_entry *entry, nodes = snd_hda_get_sub_nodes(codec, fg, &nid); if (! nid || nodes < 0) { snd_iprintf(buffer, "Invalid AFG subtree\n"); - snd_hda_power_down(codec); return; } @@ -931,7 +930,6 @@ static void print_codec_info(struct snd_info_entry *entry, kfree(conn); } - snd_hda_power_down(codec); } /* diff --git a/sound/hda/common/sysfs.c b/sound/hda/common/sysfs.c index 140e24bf4d7fc5..0d464d4dd7c94c 100644 --- a/sound/hda/common/sysfs.c +++ b/sound/hda/common/sysfs.c @@ -129,21 +129,18 @@ static int reconfig_codec(struct hda_codec *codec) { int err; - snd_hda_power_up(codec); + CLASS(snd_hda_power, pm)(codec); codec_info(codec, "hda-codec: reconfiguring\n"); err = snd_hda_codec_reset(codec); if (err < 0) { codec_err(codec, "The codec is being used, can't reconfigure.\n"); - goto error; + return err; } err = device_reprobe(hda_codec_dev(codec)); if (err < 0) - goto error; - err = snd_card_register(codec->card); - error: - snd_hda_power_down(codec); - return err; + return err; + return snd_card_register(codec->card); } /* From a23160c87986732590e68c1788e9b4929950ef67 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:46 +0200 Subject: [PATCH 0803/1292] ALSA: hda: Use auto cleanup macros for DSP loader locks There are temporary DSP locking/unlocking patterns found in various places, and those can be cleaned up nicely with the guard() macro calling snd_hdac_dsp_lock() and *_unlock(). Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-7-tiwai@suse.de --- include/sound/hdaudio.h | 1 + sound/hda/common/controller.c | 47 +++++++++++++++-------------------- sound/hda/core/stream.c | 11 +++----- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index d38234f8fe4469..4e0c1d8af09f76 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -651,6 +651,7 @@ int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value); #define snd_hdac_dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex) #define snd_hdac_dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex) #define snd_hdac_stream_is_locked(dev) ((dev)->locked) +DEFINE_GUARD(snd_hdac_dsp_lock, struct hdac_stream *, snd_hdac_dsp_lock(_T), snd_hdac_dsp_unlock(_T)) /* DSP loader helpers */ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, unsigned int byte_size, struct snd_dma_buffer *bufp); diff --git a/sound/hda/common/controller.c b/sound/hda/common/controller.c index 84387ed761be97..ceab8625bb1f52 100644 --- a/sound/hda/common/controller.c +++ b/sound/hda/common/controller.c @@ -32,8 +32,11 @@ #include "controller_trace.h" /* DSP lock helpers */ -#define dsp_lock(dev) snd_hdac_dsp_lock(azx_stream(dev)) -#define dsp_unlock(dev) snd_hdac_dsp_unlock(azx_stream(dev)) +#ifdef CONFIG_SND_HDA_DSP_LOADER +#define guard_dsp_lock(dev) guard(snd_hdac_dsp_lock)(azx_stream(dev)) +#else +#define guard_dsp_lock(dev) do {} while (0) +#endif #define dsp_is_locked(dev) snd_hdac_stream_is_locked(azx_stream(dev)) /* assign a stream for the PCM */ @@ -110,14 +113,11 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); struct hdac_stream *hdas = azx_stream(azx_dev); - int ret = 0; trace_azx_pcm_hw_params(chip, azx_dev); - dsp_lock(azx_dev); - if (dsp_is_locked(azx_dev)) { - ret = -EBUSY; - goto unlock; - } + guard_dsp_lock(azx_dev); + if (dsp_is_locked(azx_dev)) + return -EBUSY; /* Set up BDLEs here, return -ENOMEM if too many BDLEs are required */ hdas->bufsize = params_buffer_bytes(hw_params); @@ -127,11 +127,9 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, (hw_params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && (hw_params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); if (snd_hdac_stream_setup_periods(hdas) < 0) - ret = -ENOMEM; + return -ENOMEM; -unlock: - dsp_unlock(azx_dev); - return ret; + return 0; } static int azx_pcm_hw_free(struct snd_pcm_substream *substream) @@ -141,14 +139,13 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); /* reset BDL address */ - dsp_lock(azx_dev); + guard_dsp_lock(azx_dev); if (!dsp_is_locked(azx_dev)) snd_hdac_stream_cleanup(azx_stream(azx_dev)); snd_hda_codec_cleanup(apcm->codec, hinfo, substream); azx_stream(azx_dev)->prepared = 0; - dsp_unlock(azx_dev); return 0; } @@ -166,11 +163,9 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) unsigned short ctls = spdif ? spdif->ctls : 0; trace_azx_pcm_prepare(chip, azx_dev); - dsp_lock(azx_dev); - if (dsp_is_locked(azx_dev)) { - err = -EBUSY; - goto unlock; - } + guard_dsp_lock(azx_dev); + if (dsp_is_locked(azx_dev)) + return -EBUSY; snd_hdac_stream_reset(azx_stream(azx_dev)); bits = snd_hdac_stream_format_bits(runtime->format, SNDRV_PCM_SUBFORMAT_STD, hinfo->maxbps); @@ -180,13 +175,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) dev_err(chip->card->dev, "invalid format_val, rate=%d, ch=%d, format=%d\n", runtime->rate, runtime->channels, runtime->format); - err = -EINVAL; - goto unlock; + return -EINVAL; } err = snd_hdac_stream_set_params(azx_stream(azx_dev), format_val); if (err < 0) - goto unlock; + return err; snd_hdac_stream_setup(azx_stream(azx_dev), false); @@ -197,12 +191,11 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) stream_tag -= chip->capture_streams; err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, azx_dev->core.format_val, substream); + if (err < 0) + return err; - unlock: - if (!err) - azx_stream(azx_dev)->prepared = 1; - dsp_unlock(azx_dev); - return err; + azx_stream(azx_dev)->prepared = 1; + return 0; } static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c index 4a87bef8834f9c..0caeebcc591a0a 100644 --- a/sound/hda/core/stream.c +++ b/sound/hda/core/stream.c @@ -922,12 +922,11 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, struct hdac_bus *bus = azx_dev->bus; int err; - snd_hdac_dsp_lock(azx_dev); + guard(snd_hdac_dsp_lock)(azx_dev); spin_lock_irq(&bus->reg_lock); if (azx_dev->running || azx_dev->locked) { spin_unlock_irq(&bus->reg_lock); - err = -EBUSY; - goto unlock; + return -EBUSY; } azx_dev->locked = true; spin_unlock_irq(&bus->reg_lock); @@ -951,7 +950,6 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, goto error; snd_hdac_stream_setup(azx_dev, true); - snd_hdac_dsp_unlock(azx_dev); return azx_dev->stream_tag; error: @@ -960,8 +958,6 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, spin_lock_irq(&bus->reg_lock); azx_dev->locked = false; spin_unlock_irq(&bus->reg_lock); - unlock: - snd_hdac_dsp_unlock(azx_dev); return err; } EXPORT_SYMBOL_GPL(snd_hdac_dsp_prepare); @@ -993,7 +989,7 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev, if (!dmab->area || !azx_dev->locked) return; - snd_hdac_dsp_lock(azx_dev); + guard(snd_hdac_dsp_lock)(azx_dev); /* reset BDL address */ snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0); snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0); @@ -1008,7 +1004,6 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev, spin_lock_irq(&bus->reg_lock); azx_dev->locked = false; spin_unlock_irq(&bus->reg_lock); - snd_hdac_dsp_unlock(azx_dev); } EXPORT_SYMBOL_GPL(snd_hdac_dsp_cleanup); #endif /* CONFIG_SND_HDA_DSP_LOADER */ From 62dd3851d2450a5fb2259da1f0391b5870e07577 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:47 +0200 Subject: [PATCH 0804/1292] ALSA: hda/common: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-8-tiwai@suse.de --- sound/hda/common/codec.c | 89 +++++++++++++++-------------------- sound/hda/common/controller.c | 24 +++++----- sound/hda/common/sysfs.c | 66 ++++++++++---------------- 3 files changed, 74 insertions(+), 105 deletions(-) diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 3e692dd6725e17..022086f8d4df60 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -39,13 +39,12 @@ static int call_exec_verb(struct hda_bus *bus, struct hda_codec *codec, int err; CLASS(snd_hda_power_pm, pm)(codec); - mutex_lock(&bus->core.cmd_mutex); + guard(mutex)(&bus->core.cmd_mutex); if (flags & HDA_RW_NO_RESPONSE_FALLBACK) bus->no_response_fallback = 1; err = snd_hdac_bus_exec_verb_unlocked(&bus->core, codec->core.addr, cmd, res); bus->no_response_fallback = 0; - mutex_unlock(&bus->core.cmd_mutex); return err; } @@ -531,11 +530,11 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) #ifdef CONFIG_SND_HDA_RECONFIG { unsigned int cfg = 0; - mutex_lock(&codec->user_mutex); - pin = look_up_pincfg(codec, &codec->user_pins, nid); - if (pin) - cfg = pin->cfg; - mutex_unlock(&codec->user_mutex); + scoped_guard(mutex, &codec->user_mutex) { + pin = look_up_pincfg(codec, &codec->user_pins, nid); + if (pin) + cfg = pin->cfg; + } if (cfg) return cfg; } @@ -2179,13 +2178,12 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, if (WARN_ON(codec->spdif_out.used <= idx)) return -EINVAL; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); spdif = snd_array_elem(&codec->spdif_out, idx); ucontrol->value.iec958.status[0] = spdif->status & 0xff; ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff; ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff; ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff; - mutex_unlock(&codec->spdif_mutex); return 0; } @@ -2288,7 +2286,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, if (WARN_ON(codec->spdif_out.used <= idx)) return -EINVAL; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); spdif = snd_array_elem(&codec->spdif_out, idx); nid = spdif->nid; spdif->status = ucontrol->value.iec958.status[0] | @@ -2301,7 +2299,6 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, spdif->ctls = val; if (change && nid != (u16)-1) set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); - mutex_unlock(&codec->spdif_mutex); return change; } @@ -2316,10 +2313,9 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, if (WARN_ON(codec->spdif_out.used <= idx)) return -EINVAL; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); spdif = snd_array_elem(&codec->spdif_out, idx); ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE; - mutex_unlock(&codec->spdif_mutex); return 0; } @@ -2346,7 +2342,7 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, if (WARN_ON(codec->spdif_out.used <= idx)) return -EINVAL; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); spdif = snd_array_elem(&codec->spdif_out, idx); nid = spdif->nid; val = spdif->ctls & ~AC_DIG1_ENABLE; @@ -2356,7 +2352,6 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, spdif->ctls = val; if (change && nid != (u16)-1) set_spdif_ctls(codec, nid, val & 0xff, -1); - mutex_unlock(&codec->spdif_mutex); return change; } @@ -2501,10 +2496,9 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) if (WARN_ON(codec->spdif_out.used <= idx)) return; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); spdif = snd_array_elem(&codec->spdif_out, idx); spdif->nid = (u16)-1; - mutex_unlock(&codec->spdif_mutex); } EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign); @@ -2523,14 +2517,13 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) if (WARN_ON(codec->spdif_out.used <= idx)) return; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); spdif = snd_array_elem(&codec->spdif_out, idx); if (spdif->nid != nid) { spdif->nid = nid; val = spdif->ctls; set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff); } - mutex_unlock(&codec->spdif_mutex); } EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign); @@ -2605,14 +2598,13 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, unsigned int val = !!ucontrol->value.integer.value[0]; int change; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); change = codec->spdif_in_enable != val; if (change) { codec->spdif_in_enable = val; snd_hdac_regmap_write(&codec->core, nid, AC_VERB_SET_DIGI_CONVERT_1, val); } - mutex_unlock(&codec->spdif_mutex); return change; } @@ -3182,7 +3174,8 @@ int snd_hda_codec_prepare(struct hda_codec *codec, struct snd_pcm_substream *substream) { int ret; - mutex_lock(&codec->bus->prepare_mutex); + + guard(mutex)(&codec->bus->prepare_mutex); if (hinfo->ops.prepare) ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); @@ -3190,7 +3183,6 @@ int snd_hda_codec_prepare(struct hda_codec *codec, ret = -ENODEV; if (ret >= 0) purify_inactive_streams(codec); - mutex_unlock(&codec->bus->prepare_mutex); return ret; } EXPORT_SYMBOL_GPL(snd_hda_codec_prepare); @@ -3207,10 +3199,9 @@ void snd_hda_codec_cleanup(struct hda_codec *codec, struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { - mutex_lock(&codec->bus->prepare_mutex); + guard(mutex)(&codec->bus->prepare_mutex); if (hinfo->ops.cleanup) hinfo->ops.cleanup(hinfo, codec, substream); - mutex_unlock(&codec->bus->prepare_mutex); } EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup); @@ -3640,12 +3631,11 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout) { - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) /* already opened as analog dup; reset it once */ cleanup_dig_out_stream(codec, mout->dig_out_nid); mout->dig_out_used = HDA_DIG_EXCLUSIVE; - mutex_unlock(&codec->spdif_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open); @@ -3664,9 +3654,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, unsigned int format, struct snd_pcm_substream *substream) { - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); - mutex_unlock(&codec->spdif_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); @@ -3679,9 +3668,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) { - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); cleanup_dig_out_stream(codec, mout->dig_out_nid); - mutex_unlock(&codec->spdif_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup); @@ -3694,9 +3682,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup); int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout) { - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); mout->dig_out_used = 0; - mutex_unlock(&codec->spdif_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close); @@ -3736,7 +3723,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, NULL, &mout->spdif_maxbps); } - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); if (mout->share_spdif) { if ((runtime->hw.rates & mout->spdif_rates) && (runtime->hw.formats & mout->spdif_formats)) { @@ -3749,7 +3736,6 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, /* FIXME: need notify? */ } } - mutex_unlock(&codec->spdif_mutex); } return snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); @@ -3778,23 +3764,23 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_spdif_out *spdif; int i; - mutex_lock(&codec->spdif_mutex); - spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); - if (mout->dig_out_nid && mout->share_spdif && - mout->dig_out_used != HDA_DIG_EXCLUSIVE) { - if (chs == 2 && spdif != NULL && - snd_hda_is_supported_format(codec, mout->dig_out_nid, - format) && - !(spdif->status & IEC958_AES0_NONAUDIO)) { - mout->dig_out_used = HDA_DIG_ANALOG_DUP; - setup_dig_out_stream(codec, mout->dig_out_nid, - stream_tag, format); - } else { - mout->dig_out_used = 0; - cleanup_dig_out_stream(codec, mout->dig_out_nid); + scoped_guard(mutex, &codec->spdif_mutex) { + spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); + if (mout->dig_out_nid && mout->share_spdif && + mout->dig_out_used != HDA_DIG_EXCLUSIVE) { + if (chs == 2 && spdif != NULL && + snd_hda_is_supported_format(codec, mout->dig_out_nid, + format) && + !(spdif->status & IEC958_AES0_NONAUDIO)) { + mout->dig_out_used = HDA_DIG_ANALOG_DUP; + setup_dig_out_stream(codec, mout->dig_out_nid, + stream_tag, format); + } else { + mout->dig_out_used = 0; + cleanup_dig_out_stream(codec, mout->dig_out_nid); + } } } - mutex_unlock(&codec->spdif_mutex); /* front */ snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, @@ -3861,12 +3847,11 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, if (mout->extra_out_nid[i]) snd_hda_codec_cleanup_stream(codec, mout->extra_out_nid[i]); - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { cleanup_dig_out_stream(codec, mout->dig_out_nid); mout->dig_out_used = 0; } - mutex_unlock(&codec->spdif_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup); diff --git a/sound/hda/common/controller.c b/sound/hda/common/controller.c index ceab8625bb1f52..a5693c9ca400c3 100644 --- a/sound/hda/common/controller.c +++ b/sound/hda/common/controller.c @@ -96,12 +96,12 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) struct azx_dev *azx_dev = get_azx_dev(substream); trace_azx_pcm_close(chip, azx_dev); - mutex_lock(&chip->open_mutex); - azx_release_device(azx_dev); - if (hinfo->ops.close) - hinfo->ops.close(hinfo, apcm->codec, substream); - snd_hda_power_down(apcm->codec); - mutex_unlock(&chip->open_mutex); + scoped_guard(mutex, &chip->open_mutex) { + azx_release_device(azx_dev); + if (hinfo->ops.close) + hinfo->ops.close(hinfo, apcm->codec, substream); + snd_hda_power_down(apcm->codec); + } snd_hda_codec_pcm_put(apcm->info); return 0; } @@ -1129,12 +1129,12 @@ static int probe_codec(struct azx *chip, int addr) int err; unsigned int res = -1; - mutex_lock(&bus->cmd_mutex); - chip->probing = 1; - azx_send_cmd(bus, cmd); - err = azx_get_response(bus, addr, &res); - chip->probing = 0; - mutex_unlock(&bus->cmd_mutex); + scoped_guard(mutex, &bus->cmd_mutex) { + chip->probing = 1; + azx_send_cmd(bus, cmd); + err = azx_get_response(bus, addr, &res); + chip->probing = 0; + } if (err < 0 || res == -1) return -EIO; dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr); diff --git a/sound/hda/common/sysfs.c b/sound/hda/common/sysfs.c index 0d464d4dd7c94c..555c16ea60a5ba 100644 --- a/sound/hda/common/sysfs.c +++ b/sound/hda/common/sysfs.c @@ -81,12 +81,12 @@ static ssize_t pin_configs_show(struct hda_codec *codec, { const struct hda_pincfg *pin; int i, len = 0; - mutex_lock(&codec->user_mutex); + + guard(mutex)(&codec->user_mutex); snd_array_for_each(list, i, pin) { len += sysfs_emit_at(buf, len, "0x%02x 0x%08x\n", pin->nid, pin->cfg); } - mutex_unlock(&codec->user_mutex); return len; } @@ -215,12 +215,12 @@ static ssize_t init_verbs_show(struct device *dev, struct hda_codec *codec = dev_get_drvdata(dev); const struct hda_verb *v; int i, len = 0; - mutex_lock(&codec->user_mutex); + + guard(mutex)(&codec->user_mutex); snd_array_for_each(&codec->init_verbs, i, v) { len += sysfs_emit_at(buf, len, "0x%02x 0x%03x 0x%04x\n", v->nid, v->verb, v->param); } - mutex_unlock(&codec->user_mutex); return len; } @@ -233,16 +233,13 @@ static int parse_init_verbs(struct hda_codec *codec, const char *buf) return -EINVAL; if (!nid || !verb) return -EINVAL; - mutex_lock(&codec->user_mutex); + guard(mutex)(&codec->user_mutex); v = snd_array_new(&codec->init_verbs); - if (!v) { - mutex_unlock(&codec->user_mutex); + if (!v) return -ENOMEM; - } v->nid = nid; v->verb = verb; v->param = param; - mutex_unlock(&codec->user_mutex); return 0; } @@ -264,12 +261,12 @@ static ssize_t hints_show(struct device *dev, struct hda_codec *codec = dev_get_drvdata(dev); const struct hda_hint *hint; int i, len = 0; - mutex_lock(&codec->user_mutex); + + guard(mutex)(&codec->user_mutex); snd_array_for_each(&codec->hints, i, hint) { len += sysfs_emit_at(buf, len, "%s = %s\n", hint->key, hint->val); } - mutex_unlock(&codec->user_mutex); return len; } @@ -324,7 +321,7 @@ static int parse_hints(struct hda_codec *codec, const char *buf) val = skip_spaces(val); remove_trail_spaces(key); remove_trail_spaces(val); - mutex_lock(&codec->user_mutex); + guard(mutex)(&codec->user_mutex); hint = get_hint(codec, key); if (hint) { /* replace */ @@ -345,7 +342,6 @@ static int parse_hints(struct hda_codec *codec, const char *buf) err = -ENOMEM; } unlock: - mutex_unlock(&codec->user_mutex); if (err) kfree(key); return err; @@ -372,16 +368,14 @@ static ssize_t user_pin_configs_show(struct device *dev, static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) { - int nid, cfg, err; + int nid, cfg; if (sscanf(buf, "%i %i", &nid, &cfg) != 2) return -EINVAL; if (!nid) return -EINVAL; - mutex_lock(&codec->user_mutex); - err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); - mutex_unlock(&codec->user_mutex); - return err; + guard(mutex)(&codec->user_mutex); + return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); } static ssize_t user_pin_configs_store(struct device *dev, @@ -429,26 +423,19 @@ EXPORT_SYMBOL_GPL(snd_hda_get_hint); int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) { const char *p; - int ret; - mutex_lock(&codec->user_mutex); + guard(mutex)(&codec->user_mutex); p = snd_hda_get_hint(codec, key); if (!p || !*p) - ret = -ENOENT; - else { - switch (toupper(*p)) { - case 'T': /* true */ - case 'Y': /* yes */ - case '1': - ret = 1; - break; - default: - ret = 0; - break; - } + return -ENOENT; + switch (toupper(*p)) { + case 'T': /* true */ + case 'Y': /* yes */ + case '1': + return 1; + default: + return 0; } - mutex_unlock(&codec->user_mutex); - return ret; } EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint); @@ -466,20 +453,17 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) { const char *p; unsigned long val; - int ret; - mutex_lock(&codec->user_mutex); + guard(mutex)(&codec->user_mutex); p = snd_hda_get_hint(codec, key); if (!p) - ret = -ENOENT; + return -ENOENT; else if (kstrtoul(p, 0, &val)) - ret = -EINVAL; + return -EINVAL; else { *valp = val; - ret = 0; + return 0; } - mutex_unlock(&codec->user_mutex); - return ret; } EXPORT_SYMBOL_GPL(snd_hda_get_int_hint); #endif /* CONFIG_SND_HDA_RECONFIG */ From 0a930d8732fc076600c4b346a83d9b0a190aeaf0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:48 +0200 Subject: [PATCH 0805/1292] ALSA: hda/core: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-9-tiwai@suse.de --- sound/hda/core/bus.c | 8 ++------ sound/hda/core/component.c | 6 ++---- sound/hda/core/device.c | 23 ++++++++++------------ sound/hda/core/ext/controller.c | 6 ++---- sound/hda/core/regmap.c | 35 +++++++++++---------------------- 5 files changed, 27 insertions(+), 51 deletions(-) diff --git a/sound/hda/core/bus.c b/sound/hda/core/bus.c index d497414a5538fa..9b196c915f3783 100644 --- a/sound/hda/core/bus.c +++ b/sound/hda/core/bus.c @@ -87,12 +87,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_exit); int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr, unsigned int cmd, unsigned int *res) { - int err; - - mutex_lock(&bus->cmd_mutex); - err = snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res); - mutex_unlock(&bus->cmd_mutex); - return err; + guard(mutex)(&bus->cmd_mutex); + return snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res); } /** diff --git a/sound/hda/core/component.c b/sound/hda/core/component.c index 9c82a2864a2fbe..04755903880e6b 100644 --- a/sound/hda/core/component.c +++ b/sound/hda/core/component.c @@ -69,14 +69,14 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) dev_dbg(bus->dev, "display power %s\n", str_enable_disable(enable)); - mutex_lock(&bus->lock); + guard(mutex)(&bus->lock); if (enable) set_bit(idx, &bus->display_power_status); else clear_bit(idx, &bus->display_power_status); if (!acomp || !acomp->ops) - goto unlock; + return; if (bus->display_power_status) { if (!bus->display_power_active) { @@ -99,8 +99,6 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) bus->display_power_active = 0; } } - unlock: - mutex_unlock(&bus->lock); } EXPORT_SYMBOL_GPL(snd_hdac_display_power); diff --git a/sound/hda/core/device.c b/sound/hda/core/device.c index 018f9e176b1b8b..160c8d0453b0e4 100644 --- a/sound/hda/core/device.c +++ b/sound/hda/core/device.c @@ -147,9 +147,9 @@ int snd_hdac_device_register(struct hdac_device *codec) err = device_add(&codec->dev); if (err < 0) return err; - mutex_lock(&codec->widget_lock); - err = hda_widget_sysfs_init(codec); - mutex_unlock(&codec->widget_lock); + scoped_guard(mutex, &codec->widget_lock) { + err = hda_widget_sysfs_init(codec); + } if (err < 0) { device_del(&codec->dev); return err; @@ -166,9 +166,9 @@ EXPORT_SYMBOL_GPL(snd_hdac_device_register); void snd_hdac_device_unregister(struct hdac_device *codec) { if (device_is_registered(&codec->dev)) { - mutex_lock(&codec->widget_lock); - hda_widget_sysfs_exit(codec); - mutex_unlock(&codec->widget_lock); + scoped_guard(mutex, &codec->widget_lock) { + hda_widget_sysfs_exit(codec); + } device_del(&codec->dev); snd_hdac_bus_remove_device(codec->bus, codec); } @@ -411,25 +411,22 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec) * Serialize against multiple threads trying to update the sysfs * widgets array. */ - mutex_lock(&codec->widget_lock); + guard(mutex)(&codec->widget_lock); nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); if (!start_nid || nums <= 0 || nums >= 0xff) { dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", codec->afg); - err = -EINVAL; - goto unlock; + return -EINVAL; } err = hda_widget_sysfs_reinit(codec, start_nid, nums); if (err < 0) - goto unlock; + return err; codec->num_nodes = nums; codec->start_nid = start_nid; codec->end_nid = start_nid + nums; -unlock: - mutex_unlock(&codec->widget_lock); - return err; + return 0; } EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); diff --git a/sound/hda/core/ext/controller.c b/sound/hda/core/ext/controller.c index c84754434d1627..9eea3ea2dae0d5 100644 --- a/sound/hda/core/ext/controller.c +++ b/sound/hda/core/ext/controller.c @@ -300,7 +300,7 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, unsigned long codec_mask; int ret = 0; - mutex_lock(&bus->lock); + guard(mutex)(&bus->lock); /* * if we move from 0 to 1, count will be 1 so power up this link @@ -331,7 +331,6 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, bus->codec_mask = codec_mask; } - mutex_unlock(&bus->lock); return ret; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get); @@ -343,7 +342,7 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *hlink_tmp; bool link_up = false; - mutex_lock(&bus->lock); + guard(mutex)(&bus->lock); /* * if we move from 1 to 0, count will be 0 @@ -369,7 +368,6 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, } } - mutex_unlock(&bus->lock); return ret; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put); diff --git a/sound/hda/core/regmap.c b/sound/hda/core/regmap.c index 97cee096a2864f..e7b866fc52c157 100644 --- a/sound/hda/core/regmap.c +++ b/sound/hda/core/regmap.c @@ -425,15 +425,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb); static int reg_raw_write(struct hdac_device *codec, unsigned int reg, unsigned int val) { - int err; - - mutex_lock(&codec->regmap_lock); + guard(mutex)(&codec->regmap_lock); if (!codec->regmap) - err = hda_reg_write(codec, reg, val); + return hda_reg_write(codec, reg, val); else - err = regmap_write(codec->regmap, reg, val); - mutex_unlock(&codec->regmap_lock); - return err; + return regmap_write(codec->regmap, reg, val); } /* a helper macro to call @func_call; retry with power-up if failed */ @@ -466,15 +462,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw); static int reg_raw_read(struct hdac_device *codec, unsigned int reg, unsigned int *val, bool uncached) { - int err; - - mutex_lock(&codec->regmap_lock); + guard(mutex)(&codec->regmap_lock); if (uncached || !codec->regmap) - err = hda_reg_read(codec, reg, val); + return hda_reg_read(codec, reg, val); else - err = regmap_read(codec->regmap, reg, val); - mutex_unlock(&codec->regmap_lock); - return err; + return regmap_read(codec->regmap, reg, val); } static int __snd_hdac_regmap_read_raw(struct hdac_device *codec, @@ -515,7 +507,7 @@ static int reg_raw_update(struct hdac_device *codec, unsigned int reg, bool change; int err; - mutex_lock(&codec->regmap_lock); + guard(mutex)(&codec->regmap_lock); if (codec->regmap) { err = regmap_update_bits_check(codec->regmap, reg, mask, val, &change); @@ -533,7 +525,6 @@ static int reg_raw_update(struct hdac_device *codec, unsigned int reg, } } } - mutex_unlock(&codec->regmap_lock); return err; } @@ -556,17 +547,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw); static int reg_raw_update_once(struct hdac_device *codec, unsigned int reg, unsigned int mask, unsigned int val) { - int err = 0; - if (!codec->regmap) return reg_raw_update(codec, reg, mask, val); - mutex_lock(&codec->regmap_lock); + guard(mutex)(&codec->regmap_lock); /* Discard any updates to already initialised registers. */ if (!regcache_reg_cached(codec->regmap, reg)) - err = regmap_update_bits(codec->regmap, reg, mask, val); - mutex_unlock(&codec->regmap_lock); - return err; + return regmap_update_bits(codec->regmap, reg, mask, val); + return 0; } /** @@ -593,9 +581,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw_once); */ void snd_hdac_regmap_sync(struct hdac_device *codec) { - mutex_lock(&codec->regmap_lock); + guard(mutex)(&codec->regmap_lock); if (codec->regmap) regcache_sync(codec->regmap); - mutex_unlock(&codec->regmap_lock); } EXPORT_SYMBOL_GPL(snd_hdac_regmap_sync); From a56ec9d33ee9c8f61ccc6a54548f34e10415c3d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:49 +0200 Subject: [PATCH 0806/1292] ALSA: hda/ca0132: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-10-tiwai@suse.de --- sound/hda/codecs/ca0132.c | 170 ++++++++++++++------------------------ 1 file changed, 60 insertions(+), 110 deletions(-) diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c index d2a6759b5effeb..dd054aedd501c3 100644 --- a/sound/hda/codecs/ca0132.c +++ b/sound/hda/codecs/ca0132.c @@ -1684,20 +1684,14 @@ static int chipio_write(struct hda_codec *codec, struct ca0132_spec *spec = codec->spec; int err; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); /* write the address, and if successful proceed to write data */ err = chipio_write_address(codec, chip_addx); if (err < 0) - goto exit; - - err = chipio_write_data(codec, data); - if (err < 0) - goto exit; + return err; -exit: - mutex_unlock(&spec->chipio_mutex); - return err; + return chipio_write_data(codec, data); } /* @@ -1735,16 +1729,12 @@ static int chipio_write_multiple(struct hda_codec *codec, struct ca0132_spec *spec = codec->spec; int status; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); status = chipio_write_address(codec, chip_addx); if (status < 0) - goto error; - - status = chipio_write_data_multiple(codec, data, count); -error: - mutex_unlock(&spec->chipio_mutex); + return status; - return status; + return chipio_write_data_multiple(codec, data, count); } /* @@ -1757,20 +1747,14 @@ static int chipio_read(struct hda_codec *codec, struct ca0132_spec *spec = codec->spec; int err; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); /* write the address, and if successful proceed to write data */ err = chipio_write_address(codec, chip_addx); if (err < 0) - goto exit; - - err = chipio_read_data(codec, data); - if (err < 0) - goto exit; + return err; -exit: - mutex_unlock(&spec->chipio_mutex); - return err; + return chipio_read_data(codec, data); } /* @@ -1803,7 +1787,7 @@ static void chipio_set_control_param(struct hda_codec *codec, snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, VENDOR_CHIPIO_PARAM_SET, val); } else { - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) { snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, VENDOR_CHIPIO_PARAM_EX_ID_SET, @@ -1812,7 +1796,6 @@ static void chipio_set_control_param(struct hda_codec *codec, VENDOR_CHIPIO_PARAM_EX_VALUE_SET, param_val); } - mutex_unlock(&spec->chipio_mutex); } } @@ -1977,12 +1960,10 @@ static void chipio_8051_write_exram(struct hda_codec *codec, { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); chipio_8051_set_address(codec, addr); chipio_8051_set_data(codec, data); - - mutex_unlock(&spec->chipio_mutex); } static void chipio_8051_write_exram_no_mutex(struct hda_codec *codec, @@ -2005,12 +1986,10 @@ static void chipio_8051_write_pll_pmu(struct hda_codec *codec, { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); chipio_8051_set_address(codec, addr & 0xff); chipio_8051_set_data_pll(codec, data); - - mutex_unlock(&spec->chipio_mutex); } static void chipio_8051_write_pll_pmu_no_mutex(struct hda_codec *codec, @@ -2027,13 +2006,11 @@ static void chipio_enable_clocks(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); chipio_8051_write_pll_pmu_no_mutex(codec, 0x00, 0xff); chipio_8051_write_pll_pmu_no_mutex(codec, 0x05, 0x0b); chipio_8051_write_pll_pmu_no_mutex(codec, 0x06, 0xff); - - mutex_unlock(&spec->chipio_mutex); } /* @@ -2084,22 +2061,20 @@ static int dspio_write(struct hda_codec *codec, unsigned int scp_data) dspio_write_wait(codec); - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW, scp_data & 0xffff); if (status < 0) - goto error; + return status; status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH, scp_data >> 16); if (status < 0) - goto error; + return status; /* OK, now check if the write itself has executed*/ status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, VENDOR_DSPIO_STATUS, 0); -error: - mutex_unlock(&spec->chipio_mutex); return (status == VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL) ? -EIO : 0; @@ -5584,13 +5559,12 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, int ch = get_amp_channels(kcontrol); unsigned long pval; - mutex_lock(&codec->control_mutex); + guard(mutex)(&codec->control_mutex); pval = kcontrol->private_value; kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch, 0, dir); ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); } return ret; @@ -6459,22 +6433,22 @@ static int ca0132_volume_info(struct snd_kcontrol *kcontrol, case VNID_SPK: /* follow shared_out info */ nid = spec->shared_out_nid; - mutex_lock(&codec->control_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); - err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); + scoped_guard(mutex, &codec->control_mutex) { + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + kcontrol->private_value = pval; + } break; case VNID_MIC: /* follow shared_mic info */ nid = spec->shared_mic_nid; - mutex_lock(&codec->control_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); - err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); + scoped_guard(mutex, &codec->control_mutex) { + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + kcontrol->private_value = pval; + } break; default: err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); @@ -6532,13 +6506,12 @@ static int ca0132_volume_put(struct snd_kcontrol *kcontrol, unsigned long pval; CLASS(snd_hda_power, pm)(codec); - mutex_lock(&codec->control_mutex); + guard(mutex)(&codec->control_mutex); pval = kcontrol->private_value; kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch, 0, dir); changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); } return changed; @@ -6558,7 +6531,6 @@ static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol, int ch = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value; hda_nid_t vnid = 0; - int changed; switch (nid) { case 0x02: @@ -6581,11 +6553,8 @@ static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol, CLASS(snd_hda_power, pm)(codec); ca0132_alt_dsp_volume_put(codec, vnid); - mutex_lock(&codec->control_mutex); - changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); - mutex_unlock(&codec->control_mutex); - - return changed; + guard(mutex)(&codec->control_mutex); + return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); } static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, @@ -6603,22 +6572,22 @@ static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, case VNID_SPK: /* follow shared_out tlv */ nid = spec->shared_out_nid; - mutex_lock(&codec->control_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); - err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); + scoped_guard(mutex, &codec->control_mutex) { + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + kcontrol->private_value = pval; + } break; case VNID_MIC: /* follow shared_mic tlv */ nid = spec->shared_mic_nid; - mutex_lock(&codec->control_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); - err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); + scoped_guard(mutex, &codec->control_mutex) { + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + kcontrol->private_value = pval; + } break; default: err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); @@ -7500,12 +7469,10 @@ static void ca0132_init_analog_mic2(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); chipio_8051_write_exram_no_mutex(codec, 0x1920, 0x00); chipio_8051_write_exram_no_mutex(codec, 0x192d, 0x00); - - mutex_unlock(&spec->chipio_mutex); } static void ca0132_refresh_widget_caps(struct hda_codec *codec) @@ -7595,19 +7562,17 @@ static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec) * Check if any of the default streams are active, and if they are, * stop them. */ - mutex_lock(&spec->chipio_mutex); + scoped_guard(mutex, &spec->chipio_mutex) { + for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) { + chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp); - for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) { - chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp); - - if (tmp) { - chipio_set_stream_control(codec, - dsp_dma_stream_ids[i], 0); + if (tmp) { + chipio_set_stream_control(codec, + dsp_dma_stream_ids[i], 0); + } } } - mutex_unlock(&spec->chipio_mutex); - /* * If all DSP streams are inactive, there should be no active DSP DMA * channels. Check and make sure this is the case, and if it isn't, @@ -7615,7 +7580,7 @@ static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec) */ ca0132_alt_free_active_dma_channels(codec); - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); /* Make sure stream 0x0c is six channels. */ chipio_set_stream_channels(codec, 0x0c, 6); @@ -7627,8 +7592,6 @@ static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec) /* Give the DSP some time to setup the DMA channel. */ msleep(75); } - - mutex_unlock(&spec->chipio_mutex); } /* @@ -7820,7 +7783,7 @@ static void sbz_connect_streams(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); codec_dbg(codec, "Connect Streams entered, mutex locked and loaded.\n"); @@ -7835,8 +7798,6 @@ static void sbz_connect_streams(struct hda_codec *codec) chipio_set_stream_control(codec, 0x14, 1); codec_dbg(codec, "Connect Streams exited, mutex released.\n"); - - mutex_unlock(&spec->chipio_mutex); } /* @@ -7850,7 +7811,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) const struct chipio_stream_remap_data *dsp_out_remap_data; struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); codec_dbg(codec, "Startup Data entered, mutex locked and loaded.\n"); /* Remap DAC0's output ports. */ @@ -7875,7 +7836,6 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) chipio_remap_stream(codec, dsp_out_remap_data); codec_dbg(codec, "Startup Data exited, mutex released.\n"); - mutex_unlock(&spec->chipio_mutex); } static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec) @@ -7967,7 +7927,7 @@ static void ae5_post_dsp_stream_setup(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81); @@ -7985,15 +7945,13 @@ static void ae5_post_dsp_stream_setup(struct hda_codec *codec) chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7); ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80); - - mutex_unlock(&spec->chipio_mutex); } static void ae5_post_dsp_startup_data(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); chipio_write_no_mutex(codec, 0x189000, 0x0001f101); chipio_write_no_mutex(codec, 0x189004, 0x0001f101); @@ -8017,15 +7975,13 @@ static void ae5_post_dsp_startup_data(struct hda_codec *codec) ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00); ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00); - - mutex_unlock(&spec->chipio_mutex); } static void ae7_post_dsp_setup_ports(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); /* Seems to share the same port remapping as the SBZ. */ chipio_remap_stream(codec, &stream_remap_data[1]); @@ -8038,15 +7994,13 @@ static void ae7_post_dsp_setup_ports(struct hda_codec *codec) ca0113_mmio_command_set(codec, 0x48, 0x12, 0xff); ca0113_mmio_command_set(codec, 0x48, 0x13, 0xff); ca0113_mmio_command_set(codec, 0x48, 0x14, 0x7f); - - mutex_unlock(&spec->chipio_mutex); } static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81); ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00); @@ -8061,8 +8015,6 @@ static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec) chipio_set_stream_control(codec, 0x18, 1); chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4); - - mutex_unlock(&spec->chipio_mutex); } static void ae7_post_dsp_pll_setup(struct hda_codec *codec) @@ -8090,7 +8042,7 @@ static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec) }; unsigned int i; - mutex_lock(&spec->chipio_mutex); + guard(mutex)(&spec->chipio_mutex); chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7); @@ -8152,8 +8104,6 @@ static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec) */ ae7_post_dsp_pll_setup(codec); chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7); - - mutex_unlock(&spec->chipio_mutex); } /* From 2387cf78f5fd84b72880ad15a5627f9d91fe9e98 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:50 +0200 Subject: [PATCH 0807/1292] ALSA: hda/hdmi: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-11-tiwai@suse.de --- sound/hda/codecs/hdmi/hdmi.c | 170 +++++++++++------------------ sound/hda/codecs/hdmi/nvhdmi-mcp.c | 3 +- 2 files changed, 63 insertions(+), 110 deletions(-) diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c index 4b5d20f0fbe4e2..d02a475622086b 100644 --- a/sound/hda/codecs/hdmi/hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -145,18 +145,15 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; pcm_idx = kcontrol->private_value; - mutex_lock(&spec->pcm_lock); + guard(mutex)(&spec->pcm_lock); per_pin = pcm_idx_to_pin(spec, pcm_idx); if (!per_pin) { /* no pin is bound to the pcm */ uinfo->count = 0; - goto unlock; + return 0; } eld = &per_pin->sink_eld; uinfo->count = eld->eld_valid ? eld->eld_size : 0; - - unlock: - mutex_unlock(&spec->pcm_lock); return 0; } @@ -168,24 +165,22 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, struct hdmi_spec_per_pin *per_pin; struct hdmi_eld *eld; int pcm_idx; - int err = 0; pcm_idx = kcontrol->private_value; - mutex_lock(&spec->pcm_lock); + guard(mutex)(&spec->pcm_lock); per_pin = pcm_idx_to_pin(spec, pcm_idx); if (!per_pin) { /* no pin is bound to the pcm */ memset(ucontrol->value.bytes.data, 0, ARRAY_SIZE(ucontrol->value.bytes.data)); - goto unlock; + return 0; } eld = &per_pin->sink_eld; if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) || eld->eld_size > ELD_MAX_SIZE) { snd_BUG(); - err = -EINVAL; - goto unlock; + return -EINVAL; } memset(ucontrol->value.bytes.data, 0, @@ -193,10 +188,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, if (eld->eld_valid) memcpy(ucontrol->value.bytes.data, eld->eld_buffer, eld->eld_size); - - unlock: - mutex_unlock(&spec->pcm_lock); - return err; + return 0; } static const struct snd_kcontrol_new eld_bytes_ctl = { @@ -295,10 +287,9 @@ static void print_eld_info(struct snd_info_entry *entry, { struct hdmi_spec_per_pin *per_pin = entry->private_data; - mutex_lock(&per_pin->lock); + guard(mutex)(&per_pin->lock); snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer, per_pin->pin_nid, per_pin->dev_id, per_pin->cvt_nid); - mutex_unlock(&per_pin->lock); } static void write_eld_info(struct snd_info_entry *entry, @@ -306,9 +297,8 @@ static void write_eld_info(struct snd_info_entry *entry, { struct hdmi_spec_per_pin *per_pin = entry->private_data; - mutex_lock(&per_pin->lock); + guard(mutex)(&per_pin->lock); snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer); - mutex_unlock(&per_pin->lock); } static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) @@ -599,9 +589,8 @@ void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec, if (pin_idx < 0) return; - mutex_lock(&spec->pcm_lock); + guard(mutex)(&spec->pcm_lock); hdmi_present_sense(get_pin(spec, pin_idx), 1); - mutex_unlock(&spec->pcm_lock); } EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_check_presence_and_report, "SND_HDA_CODEC_HDMI"); @@ -907,19 +896,17 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, if (pcm_idx < 0) return -EINVAL; - mutex_lock(&spec->pcm_lock); + guard(mutex)(&spec->pcm_lock); pin_idx = hinfo_to_pin_index(codec, hinfo); /* no pin is assigned to the PCM * PA need pcm open successfully when probe */ - if (pin_idx < 0) { - err = hdmi_pcm_open_no_pin(hinfo, codec, substream); - goto unlock; - } + if (pin_idx < 0) + return hdmi_pcm_open_no_pin(hinfo, codec, substream); err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, false); if (err < 0) - goto unlock; + return err; per_cvt = get_cvt(spec, cvt_idx); /* Claim converter */ @@ -960,8 +947,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, per_cvt->assigned = false; hinfo->nid = 0; snd_hda_spdif_ctls_unassign(codec, pcm_idx); - err = -ENODEV; - goto unlock; + return -ENODEV; } } @@ -973,9 +959,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); - unlock: - mutex_unlock(&spec->pcm_lock); - return err; + return 0; } /* @@ -1282,7 +1266,7 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); - mutex_lock(&per_pin->lock); + guard(mutex)(&per_pin->lock); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); if (eld->monitor_present) eld->eld_valid = !!(present & AC_PINSENSE_ELDV); @@ -1300,7 +1284,6 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, } update_eld(codec, per_pin, eld, repoll); - mutex_unlock(&per_pin->lock); } static void silent_stream_enable(struct hda_codec *codec, @@ -1322,19 +1305,18 @@ static void silent_stream_enable(struct hda_codec *codec, return; } - mutex_lock(&per_pin->lock); + guard(mutex)(&per_pin->lock); if (per_pin->setup) { codec_dbg(codec, "hdmi: PCM already open, no silent stream\n"); - err = -EBUSY; - goto unlock_out; + return; } pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id); err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, true); if (err) { codec_err(codec, "hdmi: no free converter to enable silent mode\n"); - goto unlock_out; + return; } per_cvt = get_cvt(spec, cvt_idx); @@ -1354,9 +1336,6 @@ static void silent_stream_enable(struct hda_codec *codec, pin_cvt_fixup(codec, per_pin, 0); spec->ops.silent_stream(codec, per_pin, true); - - unlock_out: - mutex_unlock(&per_pin->lock); } static void silent_stream_disable(struct hda_codec *codec, @@ -1374,9 +1353,9 @@ static void silent_stream_disable(struct hda_codec *codec, return; } - mutex_lock(&per_pin->lock); + guard(mutex)(&per_pin->lock); if (!per_pin->silent_stream) - goto unlock_out; + return; codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n", per_pin->pin_nid, per_pin->cvt_nid); @@ -1391,9 +1370,6 @@ static void silent_stream_disable(struct hda_codec *codec, per_pin->cvt_nid = 0; per_pin->silent_stream = false; - - unlock_out: - mutex_unlock(&per_pin->lock); } /* update ELD and jack state via audio component */ @@ -1404,16 +1380,16 @@ static void sync_eld_via_acomp(struct hda_codec *codec, struct hdmi_eld *eld = &spec->temp_eld; bool monitor_prev, monitor_next; - mutex_lock(&per_pin->lock); - eld->monitor_present = false; - monitor_prev = per_pin->sink_eld.monitor_present; - eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, - per_pin->dev_id, &eld->monitor_present, - eld->eld_buffer, ELD_MAX_SIZE); - eld->eld_valid = (eld->eld_size > 0); - update_eld(codec, per_pin, eld, 0); - monitor_next = per_pin->sink_eld.monitor_present; - mutex_unlock(&per_pin->lock); + scoped_guard(mutex, &per_pin->lock) { + eld->monitor_present = false; + monitor_prev = per_pin->sink_eld.monitor_present; + eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, + per_pin->dev_id, &eld->monitor_present, + eld->eld_buffer, ELD_MAX_SIZE); + eld->eld_valid = (eld->eld_size > 0); + update_eld(codec, per_pin, eld, 0); + monitor_next = per_pin->sink_eld.monitor_present; + } if (spec->silent_stream_type) { if (!monitor_prev && monitor_next) @@ -1449,9 +1425,8 @@ static void hdmi_repoll_eld(struct work_struct *work) if (per_pin->repoll_count++ > 6) per_pin->repoll_count = 0; - mutex_lock(&spec->pcm_lock); + guard(mutex)(&spec->pcm_lock); hdmi_present_sense(per_pin, per_pin->repoll_count); - mutex_unlock(&spec->pcm_lock); } static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) @@ -1645,20 +1620,15 @@ EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_parse_codec, "SND_HDA_CODEC_HDMI"); static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) { struct hda_spdif_out *spdif; - bool non_pcm; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid); /* Add sanity check to pass klockwork check. * This should never happen. */ - if (WARN_ON(spdif == NULL)) { - mutex_unlock(&codec->spdif_mutex); + if (WARN_ON(spdif == NULL)) return true; - } - non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO); - mutex_unlock(&codec->spdif_mutex); - return non_pcm; + return !!(spdif->status & IEC958_AES0_NONAUDIO); } /* @@ -1678,9 +1648,8 @@ int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_runtime *runtime = substream->runtime; bool non_pcm; int pinctl, stripe; - int err = 0; - mutex_lock(&spec->pcm_lock); + guard(mutex)(&spec->pcm_lock); pin_idx = hinfo_to_pin_index(codec, hinfo); if (pin_idx < 0) { /* when pcm is not bound to a pin skip pin setup and return 0 @@ -1689,7 +1658,7 @@ int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo, pin_cvt_fixup(codec, NULL, cvt_nid); snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format); - goto unlock; + return 0; } per_pin = get_pin(spec, pin_idx); @@ -1711,20 +1680,20 @@ int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo, per_pin->dev_id, runtime->rate); non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); - mutex_lock(&per_pin->lock); - per_pin->channels = substream->runtime->channels; - per_pin->setup = true; + scoped_guard(mutex, &per_pin->lock) { + per_pin->channels = substream->runtime->channels; + per_pin->setup = true; + + if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) { + stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core, + substream); + snd_hda_codec_write(codec, cvt_nid, 0, + AC_VERB_SET_STRIPE_CONTROL, + stripe); + } - if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) { - stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core, - substream); - snd_hda_codec_write(codec, cvt_nid, 0, - AC_VERB_SET_STRIPE_CONTROL, - stripe); + snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); } - - snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); - mutex_unlock(&per_pin->lock); if (spec->dyn_pin_out) { snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id); @@ -1736,11 +1705,8 @@ int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo, } /* snd_hda_set_dev_select() has been called before */ - err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid, - per_pin->dev_id, stream_tag, format); - unlock: - mutex_unlock(&spec->pcm_lock); - return err; + return spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid, + per_pin->dev_id, stream_tag, format); } EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_pcm_prepare, "SND_HDA_CODEC_HDMI"); @@ -1762,20 +1728,15 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, struct hdmi_spec_per_cvt *per_cvt; struct hdmi_spec_per_pin *per_pin; int pinctl; - int err = 0; - mutex_lock(&spec->pcm_lock); + guard(mutex)(&spec->pcm_lock); if (hinfo->nid) { pcm_idx = hinfo_to_pcm_index(codec, hinfo); - if (snd_BUG_ON(pcm_idx < 0)) { - err = -EINVAL; - goto unlock; - } + if (snd_BUG_ON(pcm_idx < 0)) + return -EINVAL; cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid); - if (snd_BUG_ON(cvt_idx < 0)) { - err = -EINVAL; - goto unlock; - } + if (snd_BUG_ON(cvt_idx < 0)) + return -EINVAL; per_cvt = get_cvt(spec, cvt_idx); per_cvt->assigned = false; hinfo->nid = 0; @@ -1790,7 +1751,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, * hdmi_pcm_open() */ if (pin_idx < 0) - goto unlock; + return 0; per_pin = get_pin(spec, pin_idx); @@ -1804,19 +1765,15 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, pinctl & ~PIN_OUT); } - mutex_lock(&per_pin->lock); + guard(mutex)(&per_pin->lock); per_pin->chmap_set = false; memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); per_pin->setup = false; per_pin->channels = 0; - mutex_unlock(&per_pin->lock); } -unlock: - mutex_unlock(&spec->pcm_lock); - - return err; + return 0; } static const struct hda_pcm_ops generic_ops = { @@ -1861,12 +1818,11 @@ static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, if (!per_pin) return; - mutex_lock(&per_pin->lock); + guard(mutex)(&per_pin->lock); per_pin->chmap_set = true; memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap)); if (prepared) snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); - mutex_unlock(&per_pin->lock); } static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) @@ -2035,7 +1991,7 @@ int snd_hda_hdmi_generic_init(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; - mutex_lock(&spec->bind_lock); + guard(mutex)(&spec->bind_lock); for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; @@ -2048,7 +2004,6 @@ int snd_hda_hdmi_generic_init(struct hda_codec *codec) snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id, jack_callback); } - mutex_unlock(&spec->bind_lock); return 0; } EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_init, "SND_HDA_CODEC_HDMI"); @@ -2219,7 +2174,7 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp, int i; spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops); - mutex_lock(&spec->bind_lock); + guard(mutex)(&spec->bind_lock); spec->use_acomp_notifier = use_acomp; spec->codec->relaxed_resume = use_acomp; spec->codec->bus->keep_power = 0; @@ -2229,7 +2184,6 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp, get_pin(spec, i)->pin_nid, get_pin(spec, i)->dev_id, use_acomp); - mutex_unlock(&spec->bind_lock); } /* enable / disable the notifier via master bind / unbind */ diff --git a/sound/hda/codecs/hdmi/nvhdmi-mcp.c b/sound/hda/codecs/hdmi/nvhdmi-mcp.c index fbcea6d1850e62..8fd8d76fa72f85 100644 --- a/sound/hda/codecs/hdmi/nvhdmi-mcp.c +++ b/sound/hda/codecs/hdmi/nvhdmi-mcp.c @@ -131,7 +131,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_spdif_out *spdif; struct hdmi_spec_per_cvt *per_cvt; - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex); per_cvt = get_cvt(spec, 0); spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid); @@ -215,7 +215,6 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs); - mutex_unlock(&codec->spdif_mutex); return 0; } From ece590486b59d434544c809d4e176fa4056dfcbc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:51 +0200 Subject: [PATCH 0808/1292] ALSA: hda/realtek: Use guard() for mutex locks and COEF locks Replace the manual mutex lock/unlock pairs with guard(). Also, introduce the guard() for coef_mutex_lock() and _unlock() pairs, and replace accordingly, too. The coef_mutex_lock() and *_unlock() are moved to readtek.h as static inline functions along with it. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-12-tiwai@suse.de --- sound/hda/codecs/realtek/alc268.c | 3 +-- sound/hda/codecs/realtek/realtek.c | 37 ++++-------------------------- sound/hda/codecs/realtek/realtek.h | 21 +++++++++++++++++ 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/sound/hda/codecs/realtek/alc268.c b/sound/hda/codecs/realtek/alc268.c index e489cdc98eb886..4b565fb7bd1c6a 100644 --- a/sound/hda/codecs/realtek/alc268.c +++ b/sound/hda/codecs/realtek/alc268.c @@ -12,7 +12,7 @@ static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol, unsigned long pval; int err; - mutex_lock(&codec->control_mutex); + guard(mutex)(&codec->control_mutex); pval = kcontrol->private_value; kcontrol->private_value = (pval & ~0xff) | 0x0f; err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); @@ -21,7 +21,6 @@ static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol, err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); } kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); return err; } diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c index b6feccfd45a9bf..d40de0e8a9a398 100644 --- a/sound/hda/codecs/realtek/realtek.c +++ b/sound/hda/codecs/realtek/realtek.c @@ -7,26 +7,6 @@ #include #include "realtek.h" -/* - * COEF access helper functions - */ - -static void coef_mutex_lock(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - snd_hda_power_up_pm(codec); - mutex_lock(&spec->coef_mutex); -} - -static void coef_mutex_unlock(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - mutex_unlock(&spec->coef_mutex); - snd_hda_power_down_pm(codec); -} - static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, unsigned int coef_idx) { @@ -40,12 +20,8 @@ static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, unsigned int coef_idx) { - unsigned int val; - - coef_mutex_lock(codec); - val = __alc_read_coefex_idx(codec, nid, coef_idx); - coef_mutex_unlock(codec); - return val; + guard(coef_mutex)(codec); + return __alc_read_coefex_idx(codec, nid, coef_idx); } EXPORT_SYMBOL_NS_GPL(alc_read_coefex_idx, "SND_HDA_CODEC_REALTEK"); @@ -59,9 +35,8 @@ static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, unsigned int coef_idx, unsigned int coef_val) { - coef_mutex_lock(codec); + guard(coef_mutex)(codec); __alc_write_coefex_idx(codec, nid, coef_idx, coef_val); - coef_mutex_unlock(codec); } EXPORT_SYMBOL_NS_GPL(alc_write_coefex_idx, "SND_HDA_CODEC_REALTEK"); @@ -80,9 +55,8 @@ void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, unsigned int coef_idx, unsigned int mask, unsigned int bits_set) { - coef_mutex_lock(codec); + guard(coef_mutex)(codec); __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set); - coef_mutex_unlock(codec); } EXPORT_SYMBOL_NS_GPL(alc_update_coefex_idx, "SND_HDA_CODEC_REALTEK"); @@ -99,7 +73,7 @@ EXPORT_SYMBOL_NS_GPL(alc_get_coef0, "SND_HDA_CODEC_REALTEK"); void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw) { - coef_mutex_lock(codec); + guard(coef_mutex)(codec); for (; fw->nid; fw++) { if (fw->mask == (unsigned short)-1) __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val); @@ -107,7 +81,6 @@ void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw) __alc_update_coefex_idx(codec, fw->nid, fw->idx, fw->mask, fw->val); } - coef_mutex_unlock(codec); } EXPORT_SYMBOL_NS_GPL(alc_process_coef_fw, "SND_HDA_CODEC_REALTEK"); diff --git a/sound/hda/codecs/realtek/realtek.h b/sound/hda/codecs/realtek/realtek.h index ee893da0c486a6..b2a919904c4c27 100644 --- a/sound/hda/codecs/realtek/realtek.h +++ b/sound/hda/codecs/realtek/realtek.h @@ -295,4 +295,25 @@ void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, void alc_fixup_dell_xps13(struct hda_codec *codec, const struct hda_fixup *fix, int action); +/* + * COEF access helper functions + */ +static inline void coef_mutex_lock(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_power_up_pm(codec); + mutex_lock(&spec->coef_mutex); +} + +static inline void coef_mutex_unlock(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + mutex_unlock(&spec->coef_mutex); + snd_hda_power_down_pm(codec); +} + +DEFINE_GUARD(coef_mutex, struct hda_codec *, coef_mutex_lock(_T), coef_mutex_unlock(_T)) + #endif /* __HDA_REALTEK_H */ From d1c374866cb42063303db48d8a6dd340858a4c9c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:52 +0200 Subject: [PATCH 0809/1292] ALSA: hda/cs35l41: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-13-tiwai@suse.de --- sound/hda/codecs/side-codecs/cs35l41_hda.c | 110 +++++++++------------ 1 file changed, 47 insertions(+), 63 deletions(-) diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c index 37f2cdc8ce8243..c04208e685a05e 100644 --- a/sound/hda/codecs/side-codecs/cs35l41_hda.c +++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c @@ -624,11 +624,10 @@ static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41) cancel_work_sync(&cs35l41->fw_load_work); - mutex_lock(&cs35l41->fw_mutex); + guard(mutex)(&cs35l41->fw_mutex); cs35l41_shutdown_dsp(cs35l41); cs_dsp_remove(dsp); cs35l41->halo_initialized = false; - mutex_unlock(&cs35l41->fw_mutex); } /* Protection release cycle to get the speaker out of Safe-Mode */ @@ -790,9 +789,9 @@ static void cs35l41_hda_pre_playback_hook(struct device *dev, int action) switch (action) { case HDA_GEN_PCM_ACT_CLEANUP: - mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_pause_start(dev); - mutex_unlock(&cs35l41->fw_mutex); + scoped_guard(mutex, &cs35l41->fw_mutex) { + cs35l41_hda_pause_start(dev); + } break; default: break; @@ -813,24 +812,24 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) pm_runtime_get_sync(dev); break; case HDA_GEN_PCM_ACT_PREPARE: - mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_play_start(dev); - mutex_unlock(&cs35l41->fw_mutex); + scoped_guard(mutex, &cs35l41->fw_mutex) { + cs35l41_hda_play_start(dev); + } break; case HDA_GEN_PCM_ACT_CLEANUP: - mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_pause_done(dev); - mutex_unlock(&cs35l41->fw_mutex); + scoped_guard(mutex, &cs35l41->fw_mutex) { + cs35l41_hda_pause_done(dev); + } break; case HDA_GEN_PCM_ACT_CLOSE: - mutex_lock(&cs35l41->fw_mutex); - if (!cs35l41->cs_dsp.running && cs35l41->request_fw_load && - !cs35l41->fw_request_ongoing) { - dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n"); - cs35l41->fw_request_ongoing = true; - schedule_work(&cs35l41->fw_load_work); + scoped_guard(mutex, &cs35l41->fw_mutex) { + if (!cs35l41->cs_dsp.running && cs35l41->request_fw_load && + !cs35l41->fw_request_ongoing) { + dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n"); + cs35l41->fw_request_ongoing = true; + schedule_work(&cs35l41->fw_load_work); + } } - mutex_unlock(&cs35l41->fw_mutex); /* * Playback must be finished for all amps before we start runtime suspend. @@ -849,9 +848,9 @@ static void cs35l41_hda_post_playback_hook(struct device *dev, int action) switch (action) { case HDA_GEN_PCM_ACT_PREPARE: - mutex_lock(&cs35l41->fw_mutex); - cs35l41_hda_play_done(dev); - mutex_unlock(&cs35l41->fw_mutex); + scoped_guard(mutex, &cs35l41->fw_mutex) { + cs35l41_hda_play_done(dev); + } break; default: break; @@ -917,13 +916,12 @@ static int cs35l41_verify_id(struct cs35l41_hda *cs35l41, unsigned int *regid, u static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41) { - mutex_lock(&cs35l41->fw_mutex); + guard(mutex)(&cs35l41->fw_mutex); if (cs35l41->cs_dsp.running) { cs35l41->cs_dsp.running = false; cs35l41->cs_dsp.booted = false; } regcache_mark_dirty(cs35l41->regmap); - mutex_unlock(&cs35l41->fw_mutex); return 0; } @@ -939,10 +937,9 @@ static int cs35l41_system_suspend_prep(struct device *dev) return 0; /* don't block the whole system suspend */ } - mutex_lock(&cs35l41->fw_mutex); + guard(mutex)(&cs35l41->fw_mutex); if (cs35l41->playback_started) cs35l41_hda_pause_start(dev); - mutex_unlock(&cs35l41->fw_mutex); return 0; } @@ -959,10 +956,10 @@ static int cs35l41_system_suspend(struct device *dev) return 0; /* don't block the whole system suspend */ } - mutex_lock(&cs35l41->fw_mutex); - if (cs35l41->playback_started) - cs35l41_hda_pause_done(dev); - mutex_unlock(&cs35l41->fw_mutex); + scoped_guard(mutex, &cs35l41->fw_mutex) { + if (cs35l41->playback_started) + cs35l41_hda_pause_done(dev); + } ret = pm_runtime_force_suspend(dev); if (ret) { @@ -1047,13 +1044,12 @@ static int cs35l41_system_resume(struct device *dev) return ret; } - mutex_lock(&cs35l41->fw_mutex); + guard(mutex)(&cs35l41->fw_mutex); if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) { cs35l41->fw_request_ongoing = true; schedule_work(&cs35l41->fw_load_work); } - mutex_unlock(&cs35l41->fw_mutex); return ret; } @@ -1070,7 +1066,7 @@ static int cs35l41_runtime_idle(struct device *dev) static int cs35l41_runtime_suspend(struct device *dev) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); - int ret = 0; + int ret; dev_dbg(cs35l41->dev, "Runtime Suspend\n"); @@ -1079,13 +1075,13 @@ static int cs35l41_runtime_suspend(struct device *dev) return 0; } - mutex_lock(&cs35l41->fw_mutex); + guard(mutex)(&cs35l41->fw_mutex); if (cs35l41->cs_dsp.running) { ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type); if (ret) - goto err; + return ret; } else { cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); } @@ -1093,17 +1089,14 @@ static int cs35l41_runtime_suspend(struct device *dev) regcache_cache_only(cs35l41->regmap, true); regcache_mark_dirty(cs35l41->regmap); -err: - mutex_unlock(&cs35l41->fw_mutex); - - return ret; + return 0; } static int cs35l41_runtime_resume(struct device *dev) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); unsigned int regid, reg_revid; - int ret = 0; + int ret; dev_dbg(cs35l41->dev, "Runtime Resume\n"); @@ -1112,7 +1105,7 @@ static int cs35l41_runtime_resume(struct device *dev) return 0; } - mutex_lock(&cs35l41->fw_mutex); + guard(mutex)(&cs35l41->fw_mutex); regcache_cache_only(cs35l41->regmap, false); @@ -1120,13 +1113,13 @@ static int cs35l41_runtime_resume(struct device *dev) ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); if (ret) { dev_warn(cs35l41->dev, "Unable to exit Hibernate."); - goto err; + return ret; } } ret = cs35l41_verify_id(cs35l41, ®id, ®_revid); if (ret) - goto err; + return ret; /* Test key needs to be unlocked to allow the OTP settings to re-apply */ cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap); @@ -1134,7 +1127,7 @@ static int cs35l41_runtime_resume(struct device *dev) cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap); if (ret) { dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret); - goto err; + return ret; } if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) @@ -1142,22 +1135,14 @@ static int cs35l41_runtime_resume(struct device *dev) dev_dbg(cs35l41->dev, "CS35L41 Resumed (%x), Revision: %02X\n", regid, reg_revid); -err: - mutex_unlock(&cs35l41->fw_mutex); - - return ret; + return 0; } static int cs35l41_hda_read_ctl(struct cs_dsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - int ret; - - mutex_lock(&dsp->pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len); - mutex_unlock(&dsp->pwr_lock); - - return ret; + guard(mutex)(&dsp->pwr_lock); + return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len); } static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) @@ -1272,16 +1257,15 @@ static void cs35l41_fw_load_work(struct work_struct *work) pm_runtime_get_sync(cs35l41->dev); - mutex_lock(&cs35l41->fw_mutex); - - /* Recheck if playback is ongoing, mutex will block playback during firmware loading */ - if (cs35l41->playback_started) - dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n"); - else - cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load); + scoped_guard(mutex, &cs35l41->fw_mutex) { + /* Recheck if playback is ongoing, mutex will block playback during firmware loading */ + if (cs35l41->playback_started) + dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n"); + else + cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load); - cs35l41->fw_request_ongoing = false; - mutex_unlock(&cs35l41->fw_mutex); + cs35l41->fw_request_ongoing = false; + } pm_runtime_put_autosuspend(cs35l41->dev); } From 6f27e5f029fb665efa53cd3aa9310b915c537495 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:53 +0200 Subject: [PATCH 0810/1292] ALSA: hda/tas2781: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-14-tiwai@suse.de --- .../hda/codecs/side-codecs/tas2781_hda_i2c.c | 53 ++++++------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index ed7771ab947532..fb343916149083 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -158,16 +158,16 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) switch (action) { case HDA_GEN_PCM_ACT_OPEN: pm_runtime_get_sync(dev); - mutex_lock(&tas_hda->priv->codec_lock); - tasdevice_tuning_switch(tas_hda->priv, 0); - tas_hda->priv->playback_started = true; - mutex_unlock(&tas_hda->priv->codec_lock); + scoped_guard(mutex, &tas_hda->priv->codec_lock) { + tasdevice_tuning_switch(tas_hda->priv, 0); + tas_hda->priv->playback_started = true; + } break; case HDA_GEN_PCM_ACT_CLOSE: - mutex_lock(&tas_hda->priv->codec_lock); - tasdevice_tuning_switch(tas_hda->priv, 1); - tas_hda->priv->playback_started = false; - mutex_unlock(&tas_hda->priv->codec_lock); + scoped_guard(mutex, &tas_hda->priv->codec_lock) { + tasdevice_tuning_switch(tas_hda->priv, 1); + tas_hda->priv->playback_started = false; + } pm_runtime_put_autosuspend(dev); break; @@ -184,15 +184,13 @@ static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; int ret; - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc); dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n", __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); - mutex_unlock(&tas_priv->codec_lock); - return ret; } @@ -202,19 +200,14 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int ret; - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n", __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); /* The check of the given value is in tasdevice_amp_putvol. */ - ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc); - - mutex_unlock(&tas_priv->codec_lock); - - return ret; + return tasdevice_amp_putvol(tas_priv, ucontrol, mc); } static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, @@ -222,14 +215,12 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status; dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__, kcontrol->id.name, tas_priv->force_fwload_status); - mutex_unlock(&tas_priv->codec_lock); - return 0; } @@ -239,7 +230,7 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); bool change, val = (bool)ucontrol->value.integer.value[0]; - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__, kcontrol->id.name, @@ -252,8 +243,6 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, tas_priv->force_fwload_status = val; } - mutex_unlock(&tas_priv->codec_lock); - return change; } @@ -711,7 +700,7 @@ static int tas2781_runtime_suspend(struct device *dev) dev_dbg(tas_hda->dev, "Runtime Suspend\n"); - mutex_lock(&tas_hda->priv->codec_lock); + guard(mutex)(&tas_hda->priv->codec_lock); /* The driver powers up the amplifiers at module load time. * Stop the playback if it's unused. @@ -721,8 +710,6 @@ static int tas2781_runtime_suspend(struct device *dev) tas_hda->priv->playback_started = false; } - mutex_unlock(&tas_hda->priv->codec_lock); - return 0; } @@ -732,12 +719,10 @@ static int tas2781_runtime_resume(struct device *dev) dev_dbg(tas_hda->dev, "Runtime Resume\n"); - mutex_lock(&tas_hda->priv->codec_lock); + guard(mutex)(&tas_hda->priv->codec_lock); tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); - mutex_unlock(&tas_hda->priv->codec_lock); - return 0; } @@ -747,14 +732,12 @@ static int tas2781_system_suspend(struct device *dev) dev_dbg(tas_hda->priv->dev, "System Suspend\n"); - mutex_lock(&tas_hda->priv->codec_lock); + guard(mutex)(&tas_hda->priv->codec_lock); /* Shutdown chip before system suspend */ if (tas_hda->priv->playback_started) tasdevice_tuning_switch(tas_hda->priv, 1); - mutex_unlock(&tas_hda->priv->codec_lock); - /* * Reset GPIO may be shared, so cannot reset here. * However beyond this point, amps may be powered down. @@ -769,7 +752,7 @@ static int tas2781_system_resume(struct device *dev) dev_dbg(tas_hda->priv->dev, "System Resume\n"); - mutex_lock(&tas_hda->priv->codec_lock); + guard(mutex)(&tas_hda->priv->codec_lock); for (i = 0; i < tas_hda->priv->ndev; i++) { tas_hda->priv->tasdevice[i].cur_book = -1; @@ -782,8 +765,6 @@ static int tas2781_system_resume(struct device *dev) if (tas_hda->priv->playback_started) tasdevice_tuning_switch(tas_hda->priv, 0); - mutex_unlock(&tas_hda->priv->codec_lock); - return 0; } From 68e51065315c40c34948d118bc04506209074879 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:54 +0200 Subject: [PATCH 0811/1292] ALSA: hda/cs8409: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-15-tiwai@suse.de --- sound/hda/codecs/cirrus/cs8409.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/sound/hda/codecs/cirrus/cs8409.c b/sound/hda/codecs/cirrus/cs8409.c index e32b462cdc5e35..2c02d3be89eed2 100644 --- a/sound/hda/codecs/cirrus/cs8409.c +++ b/sound/hda/codecs/cirrus/cs8409.c @@ -92,13 +92,12 @@ static void cs8409_disable_i2c_clock(struct hda_codec *codec) { struct cs8409_spec *spec = codec->spec; - mutex_lock(&spec->i2c_mux); + guard(mutex)(&spec->i2c_mux); if (spec->i2c_clck_enabled) { cs8409_vendor_coef_set(spec->codec, 0x0, cs8409_vendor_coef_get(spec->codec, 0x0) & 0xfffffff7); spec->i2c_clck_enabled = 0; } - mutex_unlock(&spec->i2c_mux); } /* @@ -204,7 +203,7 @@ static int cs8409_i2c_read(struct sub_codec *scodec, unsigned int addr) if (scodec->suspended) return -EPERM; - mutex_lock(&spec->i2c_mux); + guard(mutex)(&spec->i2c_mux); cs8409_enable_i2c_clock(codec); cs8409_set_i2c_dev_addr(codec, scodec->addr); @@ -219,12 +218,9 @@ static int cs8409_i2c_read(struct sub_codec *scodec, unsigned int addr) /* Register in bits 15-8 and the data in 7-0 */ read_data = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD); - mutex_unlock(&spec->i2c_mux); - return read_data & 0x0ff; error: - mutex_unlock(&spec->i2c_mux); codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr); return -EIO; } @@ -247,7 +243,7 @@ static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_para if (scodec->suspended) return -EPERM; - mutex_lock(&spec->i2c_mux); + guard(mutex)(&spec->i2c_mux); cs8409_set_i2c_dev_addr(codec, scodec->addr); for (i = 0; i < count; i++) { @@ -264,12 +260,9 @@ static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_para seq[i].value = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD) & 0xff; } - mutex_unlock(&spec->i2c_mux); - return 0; error: - mutex_unlock(&spec->i2c_mux); codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr); return -EIO; } @@ -291,7 +284,7 @@ static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigne if (scodec->suspended) return -EPERM; - mutex_lock(&spec->i2c_mux); + guard(mutex)(&spec->i2c_mux); cs8409_enable_i2c_clock(codec); cs8409_set_i2c_dev_addr(codec, scodec->addr); @@ -305,11 +298,9 @@ static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigne if (cs8409_i2c_wait_complete(codec) < 0) goto error; - mutex_unlock(&spec->i2c_mux); return 0; error: - mutex_unlock(&spec->i2c_mux); codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr); return -EIO; } @@ -333,7 +324,7 @@ static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i if (scodec->suspended) return -EPERM; - mutex_lock(&spec->i2c_mux); + guard(mutex)(&spec->i2c_mux); cs8409_set_i2c_dev_addr(codec, scodec->addr); for (i = 0; i < count; i++) { @@ -353,12 +344,9 @@ static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i fsleep(seq[i].delay); } - mutex_unlock(&spec->i2c_mux); - return 0; error: - mutex_unlock(&spec->i2c_mux); codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr); return -EIO; } From 129cb64e39892982beb0059da2037d3f58b27065 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:55 +0200 Subject: [PATCH 0812/1292] ALSA: hda/component: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-16-tiwai@suse.de --- sound/hda/codecs/side-codecs/hda_component.c | 15 ++++----------- sound/hda/codecs/side-codecs/hda_component.h | 3 +-- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/sound/hda/codecs/side-codecs/hda_component.c b/sound/hda/codecs/side-codecs/hda_component.c index 71860e2d637716..bcf47a301697cd 100644 --- a/sound/hda/codecs/side-codecs/hda_component.c +++ b/sound/hda/codecs/side-codecs/hda_component.c @@ -21,13 +21,12 @@ void hda_component_acpi_device_notify(struct hda_component_parent *parent, struct hda_component *comp; int i; - mutex_lock(&parent->mutex); + guard(mutex)(&parent->mutex); for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { comp = hda_component_from_index(parent, i); if (comp->dev && comp->acpi_notify) comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev); } - mutex_unlock(&parent->mutex); } EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, "SND_HDA_SCODEC_COMPONENT"); @@ -89,7 +88,7 @@ void hda_component_manager_playback_hook(struct hda_component_parent *parent, in struct hda_component *comp; int i; - mutex_lock(&parent->mutex); + guard(mutex)(&parent->mutex); for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { comp = hda_component_from_index(parent, i); if (comp->dev && comp->pre_playback_hook) @@ -105,7 +104,6 @@ void hda_component_manager_playback_hook(struct hda_component_parent *parent, in if (comp->dev && comp->post_playback_hook) comp->post_playback_hook(comp->dev, action); } - mutex_unlock(&parent->mutex); } EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, "SND_HDA_SCODEC_COMPONENT"); @@ -138,16 +136,11 @@ static int hda_comp_match_dev_name(struct device *dev, void *data) int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent) { - int ret; - /* Init shared and component specific data */ memset(parent->comps, 0, sizeof(parent->comps)); - mutex_lock(&parent->mutex); - ret = component_bind_all(hda_codec_dev(cdc), parent); - mutex_unlock(&parent->mutex); - - return ret; + guard(mutex)(&parent->mutex); + return component_bind_all(hda_codec_dev(cdc), parent); } EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, "SND_HDA_SCODEC_COMPONENT"); diff --git a/sound/hda/codecs/side-codecs/hda_component.h b/sound/hda/codecs/side-codecs/hda_component.h index 7ee37154749fe3..075137a73baec5 100644 --- a/sound/hda/codecs/side-codecs/hda_component.h +++ b/sound/hda/codecs/side-codecs/hda_component.h @@ -95,9 +95,8 @@ static inline struct hda_component *hda_component_from_index(struct hda_componen static inline void hda_component_manager_unbind(struct hda_codec *cdc, struct hda_component_parent *parent) { - mutex_lock(&parent->mutex); + guard(mutex)(&parent->mutex); component_unbind_all(hda_codec_dev(cdc), parent); - mutex_unlock(&parent->mutex); } #endif /* ifndef __HDA_COMPONENT_H__ */ From 2d0a1051de4334bafc4e7d497c48da1abe46bc9d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:56 +0200 Subject: [PATCH 0813/1292] ALSA: hda/generic: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-17-tiwai@suse.de --- sound/hda/codecs/generic.c | 69 +++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c index a44beefe3e971a..e1324f9671dd49 100644 --- a/sound/hda/codecs/generic.c +++ b/sound/hda/codecs/generic.c @@ -1118,12 +1118,11 @@ static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol, unsigned long pval; int err; - mutex_lock(&codec->control_mutex); + guard(mutex)(&codec->control_mutex); pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); return err; } @@ -1136,7 +1135,7 @@ static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, sync_auto_mute_bits(kcontrol, ucontrol); - mutex_lock(&codec->control_mutex); + guard(mutex)(&codec->control_mutex); pval = kcontrol->private_value; indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; for (i = 0; i < indices; i++) { @@ -1148,7 +1147,6 @@ static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, change |= err; } kcontrol->private_value = pval; - mutex_unlock(&codec->control_mutex); return err < 0 ? err : change; } @@ -2249,11 +2247,9 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol, unsigned int select = ucontrol->value.enumerated.item[0]; int ret = 0; - mutex_lock(&spec->pcm_mutex); - if (spec->active_streams) { - ret = -EBUSY; - goto unlock; - } + guard(mutex)(&spec->pcm_mutex); + if (spec->active_streams) + return -EBUSY; if (spec->indep_hp_enabled != select) { hda_nid_t *dacp; @@ -2285,8 +2281,6 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol, call_hp_automute(codec, NULL); ret = 1; } - unlock: - mutex_unlock(&spec->pcm_mutex); return ret; } @@ -3475,22 +3469,20 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol, imux = &spec->input_mux; adc_idx = kcontrol->id.index; - mutex_lock(&codec->control_mutex); - for (i = 0; i < imux->num_items; i++) { - path = get_input_path(codec, adc_idx, i); - if (!path || !path->ctls[type]) - continue; - kcontrol->private_value = path->ctls[type]; - ret = func(kcontrol, ucontrol); - if (ret < 0) { - err = ret; - break; + scoped_guard(mutex, &codec->control_mutex) { + for (i = 0; i < imux->num_items; i++) { + path = get_input_path(codec, adc_idx, i); + if (!path || !path->ctls[type]) + continue; + kcontrol->private_value = path->ctls[type]; + ret = func(kcontrol, ucontrol); + if (ret < 0) + return ret; + if (ret > 0) + err = 1; } - if (ret > 0) - err = 1; } - mutex_unlock(&codec->control_mutex); - if (err >= 0 && spec->cap_sync_hook) + if (spec->cap_sync_hook) spec->cap_sync_hook(codec, kcontrol, ucontrol); return err; } @@ -5332,17 +5324,17 @@ static int playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_gen_spec *spec = codec->spec; int err; - mutex_lock(&spec->pcm_mutex); + guard(mutex)(&spec->pcm_mutex); err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, hinfo); - if (!err) { - spec->active_streams |= 1 << STREAM_MULTI_OUT; - call_pcm_playback_hook(hinfo, codec, substream, - HDA_GEN_PCM_ACT_OPEN); - } - mutex_unlock(&spec->pcm_mutex); - return err; + if (err < 0) + return err; + + spec->active_streams |= 1 << STREAM_MULTI_OUT; + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_OPEN); + return 0; } static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -5381,11 +5373,11 @@ static int playback_pcm_close(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct hda_gen_spec *spec = codec->spec; - mutex_lock(&spec->pcm_mutex); + + guard(mutex)(&spec->pcm_mutex); spec->active_streams &= ~(1 << STREAM_MULTI_OUT); call_pcm_playback_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); - mutex_unlock(&spec->pcm_mutex); return 0; } @@ -5434,14 +5426,13 @@ static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_gen_spec *spec = codec->spec; int err = 0; - mutex_lock(&spec->pcm_mutex); + guard(mutex)(&spec->pcm_mutex); if (spec->indep_hp && !spec->indep_hp_enabled) err = -EBUSY; else spec->active_streams |= 1 << STREAM_INDEP_HP; call_pcm_playback_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); - mutex_unlock(&spec->pcm_mutex); return err; } @@ -5450,11 +5441,11 @@ static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct hda_gen_spec *spec = codec->spec; - mutex_lock(&spec->pcm_mutex); + + guard(mutex)(&spec->pcm_mutex); spec->active_streams &= ~(1 << STREAM_INDEP_HP); call_pcm_playback_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); - mutex_unlock(&spec->pcm_mutex); return 0; } From d2a8792b9747e5a08194957db24491c237740565 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:57 +0200 Subject: [PATCH 0814/1292] ALSA: hda/analog: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-18-tiwai@suse.de --- sound/hda/codecs/analog.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/hda/codecs/analog.c b/sound/hda/codecs/analog.c index 33aaeb44c4dce1..357ad5a6c0db52 100644 --- a/sound/hda/codecs/analog.c +++ b/sound/hda/codecs/analog.c @@ -727,7 +727,7 @@ static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol, if (spec->cur_smux == val) return 0; - mutex_lock(&codec->control_mutex); + guard(mutex)(&codec->control_mutex); path = snd_hda_get_path_from_idx(codec, spec->smux_paths[spec->cur_smux]); if (path) @@ -736,7 +736,6 @@ static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol, if (path) snd_hda_activate_path(codec, path, true, true); spec->cur_smux = val; - mutex_unlock(&codec->control_mutex); return 1; } From 59195f13ee61566091989d9d048b2768671c7b27 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:58 +0200 Subject: [PATCH 0815/1292] ALSA: hda/intel: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-19-tiwai@suse.de --- sound/hda/controllers/intel.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index 1bb3ff55b1151d..1e13678428d26a 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -915,17 +915,17 @@ static void azx_shutdown_chip(struct azx *chip) static void azx_add_card_list(struct azx *chip) { struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - mutex_lock(&card_list_lock); + + guard(mutex)(&card_list_lock); list_add(&hda->list, &card_list); - mutex_unlock(&card_list_lock); } static void azx_del_card_list(struct azx *chip) { struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - mutex_lock(&card_list_lock); + + guard(mutex)(&card_list_lock); list_del_init(&hda->list); - mutex_unlock(&card_list_lock); } /* trigger power-save check at writing parameter */ @@ -942,7 +942,7 @@ static int __maybe_unused param_set_xint(const char *val, const struct kernel_pa if (pm_blacklist > 0) return 0; - mutex_lock(&card_list_lock); + guard(mutex)(&card_list_lock); list_for_each_entry(hda, &card_list, list) { chip = &hda->chip; if (!hda->probe_continued || chip->disabled || @@ -950,7 +950,6 @@ static int __maybe_unused param_set_xint(const char *val, const struct kernel_pa continue; snd_hda_set_power_save(&chip->bus, power_save * 1000); } - mutex_unlock(&card_list_lock); return 0; } From b0550d4c2dd8353f59e06139b8f3045782ce115d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:28:59 +0200 Subject: [PATCH 0816/1292] ALSA: hda/common: Use auto cleanup for temporary buffers The release of temporary kmalloced buffers can be nicely handled via the standard __free(kfree). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-20-tiwai@suse.de --- sound/hda/common/codec.c | 4 ++-- sound/hda/common/sysfs.c | 33 ++++++++++++--------------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 022086f8d4df60..f6c9230f04ccd5 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -1858,14 +1858,14 @@ static int check_follower_present(struct hda_codec *codec, /* call kctl->put with the given value(s) */ static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) { - struct snd_ctl_elem_value *ucontrol; + struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; + ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); if (!ucontrol) return -ENOMEM; ucontrol->value.integer.value[0] = val; ucontrol->value.integer.value[1] = val; kctl->put(kctl, ucontrol); - kfree(ucontrol); return 0; } diff --git a/sound/hda/common/sysfs.c b/sound/hda/common/sysfs.c index 555c16ea60a5ba..f8c8483fd5e5f3 100644 --- a/sound/hda/common/sysfs.c +++ b/sound/hda/common/sysfs.c @@ -299,9 +299,9 @@ static void remove_trail_spaces(char *str) static int parse_hints(struct hda_codec *codec, const char *buf) { - char *key, *val; + char *key __free(kfree) = NULL; + char *val; struct hda_hint *hint; - int err = 0; buf = skip_spaces(buf); if (!*buf || *buf == '#' || *buf == '\n') @@ -313,10 +313,8 @@ static int parse_hints(struct hda_codec *codec, const char *buf) return -ENOMEM; /* extract key and val */ val = strchr(key, '='); - if (!val) { - kfree(key); + if (!val) return -EINVAL; - } *val++ = 0; val = skip_spaces(val); remove_trail_spaces(key); @@ -326,25 +324,18 @@ static int parse_hints(struct hda_codec *codec, const char *buf) if (hint) { /* replace */ kfree(hint->key); - hint->key = key; - hint->val = val; - goto unlock; + goto replace; } /* allocate a new hint entry */ if (codec->hints.used >= MAX_HINTS) - hint = NULL; - else - hint = snd_array_new(&codec->hints); - if (hint) { - hint->key = key; - hint->val = val; - } else { - err = -ENOMEM; - } - unlock: - if (err) - kfree(key); - return err; + return -ENOMEM; + hint = snd_array_new(&codec->hints); + if (!hint) + return -ENOMEM; + replace: + hint->key = no_free_ptr(key); + hint->val = val; + return 0; } static ssize_t hints_store(struct device *dev, From 6b12178fa06f534ff973948cffb97587ce8b1265 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:29:00 +0200 Subject: [PATCH 0817/1292] ALSA: hda/realtek: Use auto cleanup for temporary buffers The release of temporary kmalloced buffers can be nicely handled via the standard __free(kfree). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-21-tiwai@suse.de --- sound/hda/codecs/realtek/realtek.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c index d40de0e8a9a398..ca377a5adadb5b 100644 --- a/sound/hda/codecs/realtek/realtek.c +++ b/sound/hda/codecs/realtek/realtek.c @@ -215,7 +215,7 @@ void alc_update_knob_master(struct hda_codec *codec, { unsigned int val; struct snd_kcontrol *kctl; - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume"); if (!kctl) @@ -229,7 +229,6 @@ void alc_update_knob_master(struct hda_codec *codec, uctl->value.integer.value[0] = val; uctl->value.integer.value[1] = val; kctl->put(kctl, uctl); - kfree(uctl); } EXPORT_SYMBOL_NS_GPL(alc_update_knob_master, "SND_HDA_CODEC_REALTEK"); From ee0b0f5d32fe33562228096ed8edd4999be35092 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:29:01 +0200 Subject: [PATCH 0818/1292] ALSA: hda/generic: Use auto cleanup for temporary buffers The release of temporary kmalloced buffers can be nicely handled via the standard __free(kfree). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-22-tiwai@suse.de --- sound/hda/codecs/generic.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c index e1324f9671dd49..7bcf9aef8275f9 100644 --- a/sound/hda/codecs/generic.c +++ b/sound/hda/codecs/generic.c @@ -1984,7 +1984,7 @@ static int parse_output_paths(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg *best_cfg; + struct auto_pin_cfg *best_cfg __free(kfree) = NULL; unsigned int val; int best_badness = INT_MAX; int badness; @@ -2000,10 +2000,8 @@ static int parse_output_paths(struct hda_codec *codec) for (;;) { badness = fill_and_eval_dacs(codec, fill_hardwired, fill_mio_first); - if (badness < 0) { - kfree(best_cfg); + if (badness < 0) return badness; - } debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", cfg->line_out_type, fill_hardwired, fill_mio_first, badness); @@ -2096,7 +2094,6 @@ static int parse_output_paths(struct hda_codec *codec) if (spec->indep_hp && !indep_hp_possible(codec)) spec->indep_hp = 0; - kfree(best_cfg); return 0; } From 3a4a4d06f7a69ae081f1c6b969ae0534b0c69539 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:29:02 +0200 Subject: [PATCH 0819/1292] ALSA: hda/ext: Use guard() for spinlocks Replace the manual spin lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-23-tiwai@suse.de --- sound/hda/core/ext/stream.c | 38 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/sound/hda/core/ext/stream.c b/sound/hda/core/ext/stream.c index a3ac738f1130bb..b4759198e51db7 100644 --- a/sound/hda/core/ext/stream.c +++ b/sound/hda/core/ext/stream.c @@ -163,9 +163,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple_locked); void snd_hdac_ext_stream_decouple(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, bool decouple) { - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); snd_hdac_ext_stream_decouple_locked(bus, hext_stream, decouple); - spin_unlock_irq(&bus->reg_lock); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple); @@ -265,7 +264,7 @@ hdac_ext_link_dma_stream_assign(struct hdac_bus *bus, return NULL; } - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); list_for_each_entry(hstream, &bus->stream_list, list) { struct hdac_ext_stream *hext_stream = container_of(hstream, struct hdac_ext_stream, @@ -285,7 +284,6 @@ hdac_ext_link_dma_stream_assign(struct hdac_bus *bus, res->link_locked = 1; res->link_substream = substream; } - spin_unlock_irq(&bus->reg_lock); return res; } @@ -301,7 +299,7 @@ hdac_ext_host_dma_stream_assign(struct hdac_bus *bus, return NULL; } - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); list_for_each_entry(hstream, &bus->stream_list, list) { struct hdac_ext_stream *hext_stream = container_of(hstream, struct hdac_ext_stream, @@ -320,7 +318,6 @@ hdac_ext_host_dma_stream_assign(struct hdac_bus *bus, res->hstream.running = 0; res->hstream.substream = substream; } - spin_unlock_irq(&bus->reg_lock); return res; } @@ -387,22 +384,22 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type) break; case HDAC_EXT_STREAM_TYPE_HOST: - spin_lock_irq(&bus->reg_lock); - /* couple link only if not in use */ - if (!hext_stream->link_locked) - snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false); - snd_hdac_stream_release_locked(&hext_stream->hstream); - spin_unlock_irq(&bus->reg_lock); + scoped_guard(spinlock_irq, &bus->reg_lock) { + /* couple link only if not in use */ + if (!hext_stream->link_locked) + snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false); + snd_hdac_stream_release_locked(&hext_stream->hstream); + } break; case HDAC_EXT_STREAM_TYPE_LINK: - spin_lock_irq(&bus->reg_lock); - /* couple host only if not in use */ - if (!hext_stream->hstream.opened) - snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false); - hext_stream->link_locked = 0; - hext_stream->link_substream = NULL; - spin_unlock_irq(&bus->reg_lock); + scoped_guard(spinlock_irq, &bus->reg_lock) { + /* couple host only if not in use */ + if (!hext_stream->hstream.opened) + snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false); + hext_stream->link_locked = 0; + hext_stream->link_substream = NULL; + } break; default: @@ -427,7 +424,7 @@ struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus, struct hdac_ext_stream *res = NULL; struct hdac_stream *hstream; - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); list_for_each_entry(hstream, &bus->stream_list, list) { struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); @@ -446,7 +443,6 @@ struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus, res->hstream.running = 0; res->hstream.cstream = cstream; } - spin_unlock_irq(&bus->reg_lock); return res; } From 39f374ce54ca239ce02f05c26637917502bd694f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:29:03 +0200 Subject: [PATCH 0820/1292] ALSA: hda/core: Use guard() for spinlocks Replace the manual spin lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-24-tiwai@suse.de --- sound/hda/core/controller.c | 58 +++++++++++++++---------------------- sound/hda/core/stream.c | 25 +++++++--------- 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c index b5c833b9f8b9ca..a7c00ad801170c 100644 --- a/sound/hda/core/controller.c +++ b/sound/hda/core/controller.c @@ -44,7 +44,7 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus) { WARN_ON_ONCE(!bus->rb.area); - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); /* CORB set up */ bus->corb.addr = bus->rb.addr; bus->corb.buf = (__le32 *)bus->rb.area; @@ -86,7 +86,6 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus) snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); /* Accept unsolicited responses */ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); - spin_unlock_irq(&bus->reg_lock); } EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io); @@ -112,18 +111,17 @@ static void hdac_wait_for_cmd_dmas(struct hdac_bus *bus) */ void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus) { - spin_lock_irq(&bus->reg_lock); - /* disable ringbuffer DMAs */ - snd_hdac_chip_writeb(bus, RIRBCTL, 0); - snd_hdac_chip_writeb(bus, CORBCTL, 0); - spin_unlock_irq(&bus->reg_lock); + scoped_guard(spinlock_irq, &bus->reg_lock) { + /* disable ringbuffer DMAs */ + snd_hdac_chip_writeb(bus, RIRBCTL, 0); + snd_hdac_chip_writeb(bus, CORBCTL, 0); + } hdac_wait_for_cmd_dmas(bus); - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); /* disable unsolicited responses */ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, 0); - spin_unlock_irq(&bus->reg_lock); } EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_cmd_io); @@ -171,9 +169,8 @@ static int snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsigned int val) { unsigned int addr = azx_command_addr(val); int timeout = 50; - int ret = -EIO; - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); while (timeout--) { /* check ICB bit */ @@ -184,8 +181,7 @@ static int snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsigned int val) /* Set ICB bit */ snd_hdac_chip_updatew(bus, IRS, AZX_IRS_BUSY, AZX_IRS_BUSY); - ret = snd_hdac_bus_wait_for_pio_response(bus, addr); - goto out; + return snd_hdac_bus_wait_for_pio_response(bus, addr); } udelay(1); } @@ -193,10 +189,7 @@ static int snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsigned int val) dev_dbg_ratelimited(bus->dev, "send_cmd_pio timeout: IRS=%#x, val=%#x\n", snd_hdac_chip_readw(bus, IRS), val); -out: - spin_unlock_irq(&bus->reg_lock); - - return ret; + return -EIO; } /** @@ -228,7 +221,7 @@ static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val) unsigned int addr = azx_command_addr(val); unsigned int wp, rp; - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); bus->last_cmd[azx_command_addr(val)] = val; @@ -236,7 +229,6 @@ static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val) wp = snd_hdac_chip_readw(bus, CORBWP); if (wp == 0xffff) { /* something wrong, controller likely turned to D3 */ - spin_unlock_irq(&bus->reg_lock); return -EIO; } wp++; @@ -245,7 +237,6 @@ static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val) rp = snd_hdac_chip_readw(bus, CORBRP); if (wp == rp) { /* oops, it's full */ - spin_unlock_irq(&bus->reg_lock); return -EAGAIN; } @@ -253,8 +244,6 @@ static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val) bus->corb.buf[wp] = cpu_to_le32(val); snd_hdac_chip_writew(bus, CORBWP, wp); - spin_unlock_irq(&bus->reg_lock); - return 0; } @@ -333,21 +322,20 @@ static int snd_hdac_bus_get_response_rirb(struct hdac_bus *bus, timeout = jiffies + msecs_to_jiffies(1000); for (loopcounter = 0;; loopcounter++) { - spin_lock_irq(&bus->reg_lock); - if (!bus->polling_mode) - prepare_to_wait(&bus->rirb_wq, &wait, - TASK_UNINTERRUPTIBLE); - if (bus->polling_mode) - snd_hdac_bus_update_rirb(bus); - if (!bus->rirb.cmds[addr]) { - if (res) - *res = bus->rirb.res[addr]; /* the last value */ + scoped_guard(spinlock_irq, &bus->reg_lock) { if (!bus->polling_mode) - finish_wait(&bus->rirb_wq, &wait); - spin_unlock_irq(&bus->reg_lock); - return 0; + prepare_to_wait(&bus->rirb_wq, &wait, + TASK_UNINTERRUPTIBLE); + if (bus->polling_mode) + snd_hdac_bus_update_rirb(bus); + if (!bus->rirb.cmds[addr]) { + if (res) + *res = bus->rirb.res[addr]; /* the last value */ + if (!bus->polling_mode) + finish_wait(&bus->rirb_wq, &wait); + return 0; + } } - spin_unlock_irq(&bus->reg_lock); if (time_after(jiffies, timeout)) break; #define LOOP_COUNT_MAX 3000 diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c index 0caeebcc591a0a..579ec544ef4a48 100644 --- a/sound/hda/core/stream.c +++ b/sound/hda/core/stream.c @@ -370,7 +370,7 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus, if (substream->pcm) key |= (substream->pcm->device << 16); - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); list_for_each_entry(azx_dev, &bus->stream_list, list) { if (azx_dev->direction != substream->stream) continue; @@ -389,7 +389,6 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus, res->assigned_key = key; res->substream = substream; } - spin_unlock_irq(&bus->reg_lock); return res; } EXPORT_SYMBOL_GPL(snd_hdac_stream_assign); @@ -419,9 +418,8 @@ void snd_hdac_stream_release(struct hdac_stream *azx_dev) { struct hdac_bus *bus = azx_dev->bus; - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); snd_hdac_stream_release_locked(azx_dev); - spin_unlock_irq(&bus->reg_lock); } EXPORT_SYMBOL_GPL(snd_hdac_stream_release); @@ -923,13 +921,11 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, int err; guard(snd_hdac_dsp_lock)(azx_dev); - spin_lock_irq(&bus->reg_lock); - if (azx_dev->running || azx_dev->locked) { - spin_unlock_irq(&bus->reg_lock); - return -EBUSY; + scoped_guard(spinlock_irq, &bus->reg_lock) { + if (azx_dev->running || azx_dev->locked) + return -EBUSY; + azx_dev->locked = true; } - azx_dev->locked = true; - spin_unlock_irq(&bus->reg_lock); err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev, byte_size, bufp); @@ -955,9 +951,9 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, error: snd_dma_free_pages(bufp); err_alloc: - spin_lock_irq(&bus->reg_lock); - azx_dev->locked = false; - spin_unlock_irq(&bus->reg_lock); + scoped_guard(spinlock_irq, &bus->reg_lock) { + azx_dev->locked = false; + } return err; } EXPORT_SYMBOL_GPL(snd_hdac_dsp_prepare); @@ -1001,9 +997,8 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev, snd_dma_free_pages(dmab); dmab->area = NULL; - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); azx_dev->locked = false; - spin_unlock_irq(&bus->reg_lock); } EXPORT_SYMBOL_GPL(snd_hdac_dsp_cleanup); #endif /* CONFIG_SND_HDA_DSP_LOADER */ From 3cafe16317761bf4ea94ee6be1616dd873f698fb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:29:04 +0200 Subject: [PATCH 0821/1292] ALSA: hda/common: Use guard() for spinlocks Replace the manual spin lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-25-tiwai@suse.de --- sound/hda/common/codec.c | 10 ++----- sound/hda/common/controller.c | 53 +++++++++++++++-------------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index f6c9230f04ccd5..c6d44168c7f9de 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -1748,9 +1748,9 @@ int snd_hda_lock_devices(struct hda_bus *bus) struct snd_card *card = bus->card; struct hda_codec *codec; - spin_lock(&card->files_lock); + guard(spinlock)(&card->files_lock); if (card->shutdown) - goto err_unlock; + return -EINVAL; card->shutdown = 1; if (!list_empty(&card->ctl_files)) goto err_clear; @@ -1765,13 +1765,10 @@ int snd_hda_lock_devices(struct hda_bus *bus) goto err_clear; } } - spin_unlock(&card->files_lock); return 0; err_clear: card->shutdown = 0; - err_unlock: - spin_unlock(&card->files_lock); return -EINVAL; } EXPORT_SYMBOL_GPL(snd_hda_lock_devices); @@ -1784,9 +1781,8 @@ void snd_hda_unlock_devices(struct hda_bus *bus) { struct snd_card *card = bus->card; - spin_lock(&card->files_lock); + guard(spinlock)(&card->files_lock); card->shutdown = 0; - spin_unlock(&card->files_lock); } EXPORT_SYMBOL_GPL(snd_hda_unlock_devices); diff --git a/sound/hda/common/controller.c b/sound/hda/common/controller.c index a5693c9ca400c3..b1cfd9bd4dcb78 100644 --- a/sound/hda/common/controller.c +++ b/sound/hda/common/controller.c @@ -245,31 +245,29 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_pcm_trigger_done(s, substream); } - spin_lock(&bus->reg_lock); + scoped_guard(spinlock, &bus->reg_lock) { + /* first, set SYNC bits of corresponding streams */ + snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg); - /* first, set SYNC bits of corresponding streams */ - snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg); - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (start) { - azx_dev->insufficient = 1; - snd_hdac_stream_start(azx_stream(azx_dev)); - } else { - snd_hdac_stream_stop(azx_stream(azx_dev)); + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_dev = get_azx_dev(s); + if (start) { + azx_dev->insufficient = 1; + snd_hdac_stream_start(azx_stream(azx_dev)); + } else { + snd_hdac_stream_stop(azx_stream(azx_dev)); + } } } - spin_unlock(&bus->reg_lock); snd_hdac_stream_sync(hstr, start, sbits); - spin_lock(&bus->reg_lock); + guard(spinlock)(&bus->reg_lock); /* reset SYNC bits */ snd_hdac_stream_sync_trigger(hstr, false, sbits, sync_reg); snd_hdac_stream_timecounter_init(hstr, sbits, start); - spin_unlock(&bus->reg_lock); return 0; } @@ -964,19 +962,18 @@ int snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format, azx_dev = azx_get_dsp_loader_dev(chip); hstr = azx_stream(azx_dev); - spin_lock_irq(&bus->reg_lock); - if (hstr->opened) { - chip->saved_azx_dev = *azx_dev; - saved = true; + scoped_guard(spinlock_irq, &bus->reg_lock) { + if (hstr->opened) { + chip->saved_azx_dev = *azx_dev; + saved = true; + } } - spin_unlock_irq(&bus->reg_lock); err = snd_hdac_dsp_prepare(hstr, format, byte_size, bufp); if (err < 0) { - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); if (saved) *azx_dev = chip->saved_azx_dev; - spin_unlock_irq(&bus->reg_lock); return err; } @@ -1007,11 +1004,10 @@ void snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, return; snd_hdac_dsp_cleanup(hstr, dmab); - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); if (hstr->opened) *azx_dev = chip->saved_azx_dev; hstr->locked = false; - spin_unlock_irq(&bus->reg_lock); } EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_cleanup); #endif /* CONFIG_SND_HDA_DSP_LOADER */ @@ -1072,10 +1068,10 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) if (!pm_runtime_active(chip->card->dev)) return IRQ_NONE; - spin_lock(&bus->reg_lock); + guard(spinlock)(&bus->reg_lock); if (chip->disabled) - goto unlock; + return IRQ_NONE; do { status = azx_readl(chip, INTSTS); @@ -1107,9 +1103,6 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) } } while (active && ++repeat < 10); - unlock: - spin_unlock(&bus->reg_lock); - return IRQ_RETVAL(handled); } EXPORT_SYMBOL_GPL(azx_interrupt); From cb8fc4337c7e9e8c3431d51c107f32fffd6f2318 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 09:29:05 +0200 Subject: [PATCH 0822/1292] ALSA: hda/intel: Use guard() for spinlocks Replace the manual spin lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827072916.31933-26-tiwai@suse.de --- sound/hda/controllers/intel.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index 1e13678428d26a..48c52a207024a3 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -764,12 +764,11 @@ static void azx_clear_irq_pending(struct azx *chip) struct hdac_bus *bus = azx_bus(chip); struct hdac_stream *s; - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); list_for_each_entry(s, &bus->stream_list, list) { struct azx_dev *azx_dev = stream_to_azx_dev(s); azx_dev->irq_pending = 0; } - spin_unlock_irq(&bus->reg_lock); } static int azx_acquire_irq(struct azx *chip, int do_disconnect) From df2e8107f037a87459ffc0eadb0b19e2611913f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:07 +0200 Subject: [PATCH 0823/1292] ALSA: seq: Simplify internal command operation from OSS layer snd_seq_client_ioctl_lock() and *_unlock() are used only from a single function of the OSS layer, and it's just to wrap the call of snd_seq_kernel_client_ctl(). Provide another variant of snd_seq_kernel_client_ctl() that takes the locks internally and drop the ugly snd_seq_client_ioctl_lock() and *_unlock() implementations, instead. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-2-tiwai@suse.de --- sound/core/seq/oss/seq_oss_device.h | 7 +-- sound/core/seq/seq_clientmgr.c | 77 +++++++++++++---------------- sound/core/seq/seq_clientmgr.h | 3 +- 3 files changed, 35 insertions(+), 52 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index 6163a00bc8de12..935cf3df0b30f8 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -137,12 +137,7 @@ snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int a static inline int snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg) { - int err; - - snd_seq_client_ioctl_lock(dp->cseq); - err = snd_seq_kernel_client_ctl(dp->cseq, type, arg); - snd_seq_client_ioctl_unlock(dp->cseq); - return err; + return snd_seq_kernel_client_ioctl(dp->cseq, type, arg); } /* fill the addresses in header */ diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index aa9c956d258196..7787f46616264f 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -182,41 +182,6 @@ static struct snd_seq_client *client_load_and_use_ptr(int clientid) return client_use_ptr(clientid, IS_ENABLED(CONFIG_MODULES)); } -/* Take refcount and perform ioctl_mutex lock on the given client; - * used only for OSS sequencer - * Unlock via snd_seq_client_ioctl_unlock() below - */ -bool snd_seq_client_ioctl_lock(int clientid) -{ - struct snd_seq_client *client; - - client = client_load_and_use_ptr(clientid); - if (!client) - return false; - mutex_lock(&client->ioctl_mutex); - /* The client isn't unrefed here; see snd_seq_client_ioctl_unlock() */ - return true; -} -EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock); - -/* Unlock and unref the given client; for OSS sequencer use only */ -void snd_seq_client_ioctl_unlock(int clientid) -{ - struct snd_seq_client *client; - - client = snd_seq_client_use_ptr(clientid); - if (WARN_ON(!client)) - return; - mutex_unlock(&client->ioctl_mutex); - /* The doubly unrefs below are intentional; the first one releases the - * leftover from snd_seq_client_ioctl_lock() above, and the second one - * is for releasing snd_seq_client_use_ptr() in this function - */ - snd_seq_client_unlock(client); - snd_seq_client_unlock(client); -} -EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock); - static void usage_alloc(struct snd_seq_usage *res, int num) { res->cur += num; @@ -2558,6 +2523,21 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, } EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); +static int call_seq_client_ctl(struct snd_seq_client *client, + unsigned int cmd, void *arg) +{ + const struct ioctl_handler *handler; + + for (handler = ioctl_handlers; handler->cmd > 0; ++handler) { + if (handler->cmd == cmd) + return handler->func(client, arg); + } + + pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n", + cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); + return -ENOTTY; +} + /** * snd_seq_kernel_client_ctl - operate a command for a client with data in * kernel space. @@ -2572,24 +2552,33 @@ EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); */ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) { - const struct ioctl_handler *handler; struct snd_seq_client *client; client = clientptr(clientid); if (client == NULL) return -ENXIO; - for (handler = ioctl_handlers; handler->cmd > 0; ++handler) { - if (handler->cmd == cmd) - return handler->func(client, arg); - } - - pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n", - cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); - return -ENOTTY; + return call_seq_client_ctl(client, cmd, arg); } EXPORT_SYMBOL(snd_seq_kernel_client_ctl); +/* a similar like above but taking locks; used only from OSS sequencer layer */ +int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg) +{ + struct snd_seq_client *client; + int ret; + + client = client_load_and_use_ptr(clientid); + if (!client) + return -ENXIO; + mutex_lock(&client->ioctl_mutex); + ret = call_seq_client_ctl(client, cmd, arg); + mutex_unlock(&client->ioctl_mutex); + snd_seq_client_unlock(client); + return ret; +} +EXPORT_SYMBOL_GPL(snd_seq_kernel_client_ioctl); + /* exported (for OSS emulator) */ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait) { diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index 915b1017286e70..7d0758e72aa98d 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -94,8 +94,7 @@ int __snd_seq_deliver_single_event(struct snd_seq_client *dest, int atomic, int hop); /* only for OSS sequencer */ -bool snd_seq_client_ioctl_lock(int clientid); -void snd_seq_client_ioctl_unlock(int clientid); +int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg); extern int seq_client_load[15]; From e7b318eb97f47c451411c703eebe6fb15e0bd5eb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:08 +0200 Subject: [PATCH 0824/1292] ALSA: seq: Clean up spin lock with guard() Use guard() for spin locks to manage the sequencer client locking. The code about the refcounting was modified with the new snd_seq_client_ref() and *_unref() helpers instead of the ugly goto, too. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-3-tiwai@suse.de --- sound/core/seq/seq_clientmgr.c | 77 +++++++++++++++------------------- sound/core/seq/seq_clientmgr.h | 14 ++++++- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 7787f46616264f..89f99e713a2f8a 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -108,7 +108,6 @@ static struct snd_seq_client *clientptr(int clientid) static struct snd_seq_client *client_use_ptr(int clientid, bool load_module) { - unsigned long flags; struct snd_seq_client *client; if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) { @@ -116,15 +115,13 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module) clientid); return NULL; } - spin_lock_irqsave(&clients_lock, flags); - client = clientptr(clientid); - if (client) - goto __lock; - if (clienttablock[clientid]) { - spin_unlock_irqrestore(&clients_lock, flags); - return NULL; + scoped_guard(spinlock_irqsave, &clients_lock) { + client = clientptr(clientid); + if (client) + return snd_seq_client_ref(client); + if (clienttablock[clientid]) + return NULL; } - spin_unlock_irqrestore(&clients_lock, flags); #ifdef CONFIG_MODULES if (load_module) { static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS); @@ -153,19 +150,14 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module) snd_seq_device_load_drivers(); } } - spin_lock_irqsave(&clients_lock, flags); - client = clientptr(clientid); - if (client) - goto __lock; - spin_unlock_irqrestore(&clients_lock, flags); + scoped_guard(spinlock_irqsave, &clients_lock) { + client = clientptr(clientid); + if (client) + return snd_seq_client_ref(client); + } } #endif return NULL; - - __lock: - snd_use_lock_use(&client->use_lock); - spin_unlock_irqrestore(&clients_lock, flags); - return client; } /* get snd_seq_client object for the given id quickly */ @@ -227,25 +219,24 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) client->ump_endpoint_port = -1; /* find free slot in the client table */ - spin_lock_irq(&clients_lock); - if (client_index < 0) { - for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN; - c < SNDRV_SEQ_MAX_CLIENTS; - c++) { - if (clienttab[c] || clienttablock[c]) - continue; - clienttab[client->number = c] = client; - spin_unlock_irq(&clients_lock); - return client; - } - } else { - if (clienttab[client_index] == NULL && !clienttablock[client_index]) { - clienttab[client->number = client_index] = client; - spin_unlock_irq(&clients_lock); - return client; + scoped_guard(spinlock_irq, &clients_lock) { + if (client_index < 0) { + for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN; + c < SNDRV_SEQ_MAX_CLIENTS; + c++) { + if (clienttab[c] || clienttablock[c]) + continue; + clienttab[client->number = c] = client; + return client; + } + } else { + if (clienttab[client_index] == NULL && !clienttablock[client_index]) { + clienttab[client->number = client_index] = client; + return client; + } } } - spin_unlock_irq(&clients_lock); + snd_seq_pool_delete(&client->pool); kfree(client); return NULL; /* no free slot found or busy, return failure code */ @@ -256,18 +247,18 @@ static int seq_free_client1(struct snd_seq_client *client) { if (!client) return 0; - spin_lock_irq(&clients_lock); - clienttablock[client->number] = 1; - clienttab[client->number] = NULL; - spin_unlock_irq(&clients_lock); + scoped_guard(spinlock_irq, &clients_lock) { + clienttablock[client->number] = 1; + clienttab[client->number] = NULL; + } snd_seq_delete_all_ports(client); snd_seq_queue_client_leave(client->number); snd_use_lock_sync(&client->use_lock); if (client->pool) snd_seq_pool_delete(&client->pool); - spin_lock_irq(&clients_lock); - clienttablock[client->number] = 0; - spin_unlock_irq(&clients_lock); + scoped_guard(spinlock_irq, &clients_lock) { + clienttablock[client->number] = 0; + } return 0; } diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index 7d0758e72aa98d..b42afb887daf63 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -78,8 +78,20 @@ void snd_sequencer_device_done(void); /* get locked pointer to client */ struct snd_seq_client *snd_seq_client_use_ptr(int clientid); +static inline struct snd_seq_client * +snd_seq_client_ref(struct snd_seq_client *client) +{ + snd_use_lock_use(&client->use_lock); + return client; +} + /* unlock pointer to client */ -#define snd_seq_client_unlock(client) snd_use_lock_free(&(client)->use_lock) +static inline void snd_seq_client_unref(struct snd_seq_client *client) +{ + snd_use_lock_free(&client->use_lock); +} + +#define snd_seq_client_unlock(c) snd_seq_client_unref(c) /* dispatch event to client(s) */ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop); From d7cd16143bd8796f526806bfced721bd00dbb43e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:09 +0200 Subject: [PATCH 0825/1292] ALSA: seq: Use guard() for mutex and rwsem locks There are a few manual calls of mutex and rwsem lock/unlock pairs in seq_clientmngr.c, and those can be replaced nicely with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-4-tiwai@suse.de --- sound/core/seq/seq_clientmgr.c | 230 ++++++++++++++++----------------- 1 file changed, 110 insertions(+), 120 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 89f99e713a2f8a..5a67c4b2b644b2 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -265,23 +265,23 @@ static int seq_free_client1(struct snd_seq_client *client) static void seq_free_client(struct snd_seq_client * client) { - mutex_lock(®ister_mutex); - switch (client->type) { - case NO_CLIENT: - pr_warn("ALSA: seq: Trying to free unused client %d\n", - client->number); - break; - case USER_CLIENT: - case KERNEL_CLIENT: - seq_free_client1(client); - usage_free(&client_usage, 1); - break; + scoped_guard(mutex, ®ister_mutex) { + switch (client->type) { + case NO_CLIENT: + pr_warn("ALSA: seq: Trying to free unused client %d\n", + client->number); + break; + case USER_CLIENT: + case KERNEL_CLIENT: + seq_free_client1(client); + usage_free(&client_usage, 1); + break; - default: - pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n", - client->number, client->type); + default: + pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n", + client->number, client->type); + } } - mutex_unlock(®ister_mutex); snd_seq_system_client_ev_client_exit(client->number); } @@ -302,37 +302,34 @@ static int snd_seq_open(struct inode *inode, struct file *file) if (err < 0) return err; - mutex_lock(®ister_mutex); - client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS); - if (!client) { - mutex_unlock(®ister_mutex); - return -ENOMEM; /* failure code */ - } - - mode = snd_seq_file_flags(file); - if (mode & SNDRV_SEQ_LFLG_INPUT) - client->accept_input = 1; - if (mode & SNDRV_SEQ_LFLG_OUTPUT) - client->accept_output = 1; - - user = &client->data.user; - user->fifo = NULL; - user->fifo_pool_size = 0; - - if (mode & SNDRV_SEQ_LFLG_INPUT) { - user->fifo_pool_size = SNDRV_SEQ_DEFAULT_CLIENT_EVENTS; - user->fifo = snd_seq_fifo_new(user->fifo_pool_size); - if (user->fifo == NULL) { - seq_free_client1(client); - kfree(client); - mutex_unlock(®ister_mutex); - return -ENOMEM; + scoped_guard(mutex, ®ister_mutex) { + client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS); + if (!client) + return -ENOMEM; /* failure code */ + + mode = snd_seq_file_flags(file); + if (mode & SNDRV_SEQ_LFLG_INPUT) + client->accept_input = 1; + if (mode & SNDRV_SEQ_LFLG_OUTPUT) + client->accept_output = 1; + + user = &client->data.user; + user->fifo = NULL; + user->fifo_pool_size = 0; + + if (mode & SNDRV_SEQ_LFLG_INPUT) { + user->fifo_pool_size = SNDRV_SEQ_DEFAULT_CLIENT_EVENTS; + user->fifo = snd_seq_fifo_new(user->fifo_pool_size); + if (user->fifo == NULL) { + seq_free_client1(client); + kfree(client); + return -ENOMEM; + } } - } - usage_alloc(&client_usage, 1); - client->type = USER_CLIENT; - mutex_unlock(®ister_mutex); + usage_alloc(&client_usage, 1); + client->type = USER_CLIENT; + } c = client->number; file->private_data = client; @@ -2180,50 +2177,50 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, if (!cptr) return -ENOENT; - mutex_lock(&cptr->ioctl_mutex); - if (!cptr->midi_version) { - err = -EBADFD; - goto error; - } - - if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) { - if (!cptr->ump_info) - p = NULL; - else - p = cptr->ump_info[type]; - if (!p) { - err = -ENODEV; - goto error; - } - if (copy_to_user(argp->info, p, size)) { - err = -EFAULT; - goto error; - } - } else { - if (cptr->type != USER_CLIENT) { + scoped_guard(mutex, &cptr->ioctl_mutex) { + if (!cptr->midi_version) { err = -EBADFD; goto error; } - if (!cptr->ump_info) { - cptr->ump_info = kcalloc(NUM_UMP_INFOS, - sizeof(void *), GFP_KERNEL); + + if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) { + if (!cptr->ump_info) + p = NULL; + else + p = cptr->ump_info[type]; + if (!p) { + err = -ENODEV; + goto error; + } + if (copy_to_user(argp->info, p, size)) { + err = -EFAULT; + goto error; + } + } else { + if (cptr->type != USER_CLIENT) { + err = -EBADFD; + goto error; + } if (!cptr->ump_info) { - err = -ENOMEM; + cptr->ump_info = kcalloc(NUM_UMP_INFOS, + sizeof(void *), GFP_KERNEL); + if (!cptr->ump_info) { + err = -ENOMEM; + goto error; + } + } + p = memdup_user(argp->info, size); + if (IS_ERR(p)) { + err = PTR_ERR(p); goto error; } + kfree(cptr->ump_info[type]); + terminate_ump_info_strings(p, type); + cptr->ump_info[type] = p; } - p = memdup_user(argp->info, size); - if (IS_ERR(p)) { - err = PTR_ERR(p); - goto error; - } - kfree(cptr->ump_info[type]); - terminate_ump_info_strings(p, type); - cptr->ump_info[type] = p; } error: - mutex_unlock(&cptr->ioctl_mutex); snd_seq_client_unlock(cptr); if (!err && cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO) { if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) @@ -2337,9 +2334,9 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd, return -EFAULT; } - mutex_lock(&client->ioctl_mutex); - err = handler->func(client, &buf); - mutex_unlock(&client->ioctl_mutex); + scoped_guard(mutex, &client->ioctl_mutex) { + err = handler->func(client, &buf); + } if (err >= 0) { /* Some commands includes a bug in 'dir' field. */ if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT || @@ -2376,34 +2373,32 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index, if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS) return -EINVAL; - mutex_lock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) { - if (card) { - client_index += SNDRV_SEQ_GLOBAL_CLIENTS - + card->number * SNDRV_SEQ_CLIENTS_PER_CARD; - if (client_index >= SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN) - client_index = -1; - } + if (card) { + client_index += SNDRV_SEQ_GLOBAL_CLIENTS + + card->number * SNDRV_SEQ_CLIENTS_PER_CARD; + if (client_index >= SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN) + client_index = -1; + } - /* empty write queue as default */ - client = seq_create_client1(client_index, 0); - if (client == NULL) { - mutex_unlock(®ister_mutex); - return -EBUSY; /* failure code */ - } - usage_alloc(&client_usage, 1); + /* empty write queue as default */ + client = seq_create_client1(client_index, 0); + if (client == NULL) + return -EBUSY; /* failure code */ + usage_alloc(&client_usage, 1); - client->accept_input = 1; - client->accept_output = 1; - client->data.kernel.card = card; - client->user_pversion = SNDRV_SEQ_VERSION; + client->accept_input = 1; + client->accept_output = 1; + client->data.kernel.card = card; + client->user_pversion = SNDRV_SEQ_VERSION; - va_start(args, name_fmt); - vsnprintf(client->name, sizeof(client->name), name_fmt, args); - va_end(args); + va_start(args, name_fmt); + vsnprintf(client->name, sizeof(client->name), name_fmt, args); + va_end(args); - client->type = KERNEL_CLIENT; - mutex_unlock(®ister_mutex); + client->type = KERNEL_CLIENT; + } /* make others aware this new client */ snd_seq_system_client_ev_client_start(client->number); @@ -2465,11 +2460,10 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, if (!cptr->accept_output) { result = -EPERM; } else { /* send it */ - mutex_lock(&cptr->ioctl_mutex); + guard(mutex)(&cptr->ioctl_mutex); result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, false, 0, &cptr->ioctl_mutex); - mutex_unlock(&cptr->ioctl_mutex); } snd_seq_client_unlock(cptr); @@ -2562,9 +2556,9 @@ int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg) client = client_load_and_use_ptr(clientid); if (!client) return -ENXIO; - mutex_lock(&client->ioctl_mutex); - ret = call_seq_client_ctl(client, cmd, arg); - mutex_unlock(&client->ioctl_mutex); + scoped_guard(mutex, &client->ioctl_mutex) { + ret = call_seq_client_ctl(client, cmd, arg); + } snd_seq_client_unlock(client); return ret; } @@ -2614,11 +2608,9 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer, struct snd_seq_subscribers *s; int count = 0; - down_read(&group->list_mutex); - if (list_empty(&group->list_head)) { - up_read(&group->list_mutex); + guard(rwsem_read)(&group->list_mutex); + if (list_empty(&group->list_head)) return; - } snd_iprintf(buffer, msg); list_for_each(p, &group->list_head) { if (is_src) @@ -2635,7 +2627,6 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer, if (group->exclusive) snd_iprintf(buffer, "[ex]"); } - up_read(&group->list_mutex); snd_iprintf(buffer, "\n"); } @@ -2661,7 +2652,7 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, { struct snd_seq_client_port *p; - mutex_lock(&client->ports_mutex); + guard(mutex)(&client->ports_mutex); list_for_each_entry(p, &client->ports_list_head, list) { if (p->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) continue; @@ -2680,7 +2671,6 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: "); snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: "); } - mutex_unlock(&client->ports_mutex); } static const char *midi_version_string(unsigned int version) @@ -2777,10 +2767,10 @@ int __init snd_sequencer_device_init(void) return err; dev_set_name(seq_dev, "seq"); - mutex_lock(®ister_mutex); - err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, - &snd_seq_f_ops, NULL, seq_dev); - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) { + err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, + &snd_seq_f_ops, NULL, seq_dev); + } if (err < 0) { put_device(seq_dev); return err; From 99e16633958b50ab4f9b6d171aca2c7be7bcab8c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:10 +0200 Subject: [PATCH 0826/1292] ALSA: seq: Use auto-cleanup for client refcounting The current code manages the refcount of client in a way like: snd_seq_client *client; client = clientptr(id); .... snd_seq_client_unlock(client); Now we introduce an auto-cleanup macro to manage the unlock implicitly, namely, the above will be replaced like: snd_seq_client *client __free(snd_seq_client) = NULL; client = clientptr(id); and we can forget the unref call. A part of the code in snd_seq_deliver_single_event() is factored out to a function, so that the auto-cleanups can be applied cleanly. This also allows us to replace some left mutex lock/unlock with guard(), and also reduce scoped_guard() to the normal guard(), too. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-5-tiwai@suse.de --- sound/core/seq/seq_clientmgr.c | 214 +++++++++++++-------------------- sound/core/seq/seq_clientmgr.h | 2 +- sound/core/seq/seq_ports.c | 16 +-- 3 files changed, 86 insertions(+), 146 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 5a67c4b2b644b2..5b14d70ba87a20 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -495,24 +495,21 @@ static int check_port_perm(struct snd_seq_client_port *port, unsigned int flags) */ static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event) { - struct snd_seq_client *dest; + struct snd_seq_client *dest __free(snd_seq_client) = NULL; dest = snd_seq_client_use_ptr(event->dest.client); if (dest == NULL) return NULL; if (! dest->accept_input) - goto __not_avail; + return NULL; if (snd_seq_ev_is_ump(event)) - return dest; /* ok - no filter checks */ + return no_free_ptr(dest); /* ok - no filter checks */ if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) && ! test_bit(event->type, dest->event_filter)) - goto __not_avail; + return NULL; - return dest; /* ok - accessible */ -__not_avail: - snd_seq_client_unlock(dest); - return NULL; + return no_free_ptr(dest); /* ok - accessible */ } @@ -609,23 +606,14 @@ int __snd_seq_deliver_single_event(struct snd_seq_client *dest, return 0; } -/* - * deliver an event to the specified destination. - * if filter is non-zero, client filter bitmap is tested. - * - * RETURN VALUE: 0 : if succeeded - * <0 : error - */ -static int snd_seq_deliver_single_event(struct snd_seq_client *client, - struct snd_seq_event *event, - int atomic, int hop) +/* deliver a single event; called from snd_seq_deliver_single_event() */ +static int _snd_seq_deliver_single_event(struct snd_seq_client *client, + struct snd_seq_event *event, + int atomic, int hop) { - struct snd_seq_client *dest = NULL; + struct snd_seq_client *dest __free(snd_seq_client) = NULL; struct snd_seq_client_port *dest_port = NULL; int result = -ENOENT; - int direct; - - direct = snd_seq_ev_is_direct(event); dest = get_event_dest_client(event); if (dest == NULL) @@ -639,7 +627,7 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, result = -EPERM; goto __skip; } - + if (dest_port->timestamping) update_timestamp_of_queue(event, dest_port->time_queue, dest_port->time_real); @@ -670,12 +658,24 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, __skip: if (dest_port) snd_seq_port_unlock(dest_port); - if (dest) - snd_seq_client_unlock(dest); + return result; +} - if (result < 0 && !direct) { - result = bounce_error_event(client, event, result, atomic, hop); - } +/* + * deliver an event to the specified destination. + * if filter is non-zero, client filter bitmap is tested. + * + * RETURN VALUE: 0 : if succeeded + * <0 : error + */ +static int snd_seq_deliver_single_event(struct snd_seq_client *client, + struct snd_seq_event *event, + int atomic, int hop) +{ + int result = _snd_seq_deliver_single_event(client, event, atomic, hop); + + if (result < 0 && !snd_seq_ev_is_direct(event)) + return bounce_error_event(client, event, result, atomic, hop); return result; } @@ -817,7 +817,7 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e */ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) { - struct snd_seq_client *client; + struct snd_seq_client *client __free(snd_seq_client) = NULL; int result; if (snd_BUG_ON(!cell)) @@ -879,7 +879,6 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) snd_seq_cell_free(cell); } - snd_seq_client_unlock(client); return result; } @@ -1171,8 +1170,7 @@ static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void *arg) static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg) { struct snd_seq_running_info *info = arg; - struct snd_seq_client *cptr; - int err = 0; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; /* requested client number */ cptr = client_load_and_use_ptr(info->client); @@ -1180,25 +1178,16 @@ static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg) return -ENOENT; /* don't change !!! */ #ifdef SNDRV_BIG_ENDIAN - if (!info->big_endian) { - err = -EINVAL; - goto __err; - } + if (!info->big_endian) + return -EINVAL; #else - if (info->big_endian) { - err = -EINVAL; - goto __err; - } - + if (info->big_endian) + return -EINVAL; #endif - if (info->cpu_mode > sizeof(long)) { - err = -EINVAL; - goto __err; - } + if (info->cpu_mode > sizeof(long)) + return -EINVAL; cptr->convert32 = (info->cpu_mode < sizeof(long)); - __err: - snd_seq_client_unlock(cptr); - return err; + return 0; } /* CLIENT_INFO ioctl() */ @@ -1234,7 +1223,7 @@ static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client, void *arg) { struct snd_seq_client_info *client_info = arg; - struct snd_seq_client *cptr; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; /* requested client number */ cptr = client_load_and_use_ptr(client_info->client); @@ -1242,8 +1231,6 @@ static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client, return -ENOENT; /* don't change !!! */ get_client_info(cptr, client_info); - snd_seq_client_unlock(cptr); - return 0; } @@ -1373,7 +1360,7 @@ static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg) static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) { struct snd_seq_port_info *info = arg; - struct snd_seq_client *cptr; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; struct snd_seq_client_port *port; cptr = client_load_and_use_ptr(info->addr.client); @@ -1381,16 +1368,12 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) return -ENXIO; port = snd_seq_port_use_ptr(cptr, info->addr.port); - if (port == NULL) { - snd_seq_client_unlock(cptr); + if (port == NULL) return -ENOENT; /* don't change */ - } /* get port info */ snd_seq_get_port_info(port, info); snd_seq_port_unlock(port); - snd_seq_client_unlock(cptr); - return 0; } @@ -1478,9 +1461,10 @@ int snd_seq_client_notify_subscription(int client, int port, static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, void *arg) { - struct snd_seq_port_subscribe *subs = arg; int result = -EINVAL; - struct snd_seq_client *receiver = NULL, *sender = NULL; + struct snd_seq_port_subscribe *subs = arg; + struct snd_seq_client *receiver __free(snd_seq_client) = NULL; + struct snd_seq_client *sender __free(snd_seq_client) = NULL; struct snd_seq_client_port *sport = NULL, *dport = NULL; receiver = client_load_and_use_ptr(subs->dest.client); @@ -1510,10 +1494,6 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, snd_seq_port_unlock(sport); if (dport) snd_seq_port_unlock(dport); - if (sender) - snd_seq_client_unlock(sender); - if (receiver) - snd_seq_client_unlock(receiver); return result; } @@ -1524,9 +1504,10 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, void *arg) { - struct snd_seq_port_subscribe *subs = arg; int result = -ENXIO; - struct snd_seq_client *receiver = NULL, *sender = NULL; + struct snd_seq_port_subscribe *subs = arg; + struct snd_seq_client *receiver __free(snd_seq_client) = NULL; + struct snd_seq_client *sender __free(snd_seq_client) = NULL; struct snd_seq_client_port *sport = NULL, *dport = NULL; receiver = snd_seq_client_use_ptr(subs->dest.client); @@ -1555,10 +1536,6 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, snd_seq_port_unlock(sport); if (dport) snd_seq_port_unlock(dport); - if (sender) - snd_seq_client_unlock(sender); - if (receiver) - snd_seq_client_unlock(receiver); return result; } @@ -1849,7 +1826,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client, void *arg) { struct snd_seq_client_pool *info = arg; - struct snd_seq_client *cptr; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; cptr = client_load_and_use_ptr(info->client); if (cptr == NULL) @@ -1868,7 +1845,6 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client, info->input_pool = 0; info->input_free = 0; } - snd_seq_client_unlock(cptr); return 0; } @@ -1951,7 +1927,7 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, { struct snd_seq_port_subscribe *subs = arg; int result; - struct snd_seq_client *sender = NULL; + struct snd_seq_client *sender __free(snd_seq_client) = NULL; struct snd_seq_client_port *sport = NULL; result = -EINVAL; @@ -1966,8 +1942,6 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, __end: if (sport) snd_seq_port_unlock(sport); - if (sender) - snd_seq_client_unlock(sender); return result; } @@ -1980,7 +1954,7 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) { struct snd_seq_query_subs *subs = arg; int result = -ENXIO; - struct snd_seq_client *cptr = NULL; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; struct snd_seq_client_port *port = NULL; struct snd_seq_port_subs_info *group; struct list_head *p; @@ -2031,8 +2005,6 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) __end: if (port) snd_seq_port_unlock(port); - if (cptr) - snd_seq_client_unlock(cptr); return result; } @@ -2045,7 +2017,7 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client, void *arg) { struct snd_seq_client_info *info = arg; - struct snd_seq_client *cptr = NULL; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; /* search for next client */ if (info->client < INT_MAX) @@ -2054,16 +2026,12 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client, info->client = 0; for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) { cptr = client_load_and_use_ptr(info->client); - if (cptr) - break; /* found */ + if (cptr) { + get_client_info(cptr, info); + return 0; /* found */ + } } - if (cptr == NULL) - return -ENOENT; - - get_client_info(cptr, info); - snd_seq_client_unlock(cptr); - - return 0; + return -ENOENT; } /* @@ -2073,7 +2041,7 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, void *arg) { struct snd_seq_port_info *info = arg; - struct snd_seq_client *cptr; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; struct snd_seq_client_port *port = NULL; cptr = client_load_and_use_ptr(info->addr.client); @@ -2083,16 +2051,13 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, /* search for next port */ info->addr.port++; port = snd_seq_port_query_nearest(cptr, info); - if (port == NULL) { - snd_seq_client_unlock(cptr); + if (port == NULL) return -ENOENT; - } /* get port info */ info->addr = port->addr; snd_seq_get_port_info(port, info); snd_seq_port_unlock(port); - snd_seq_client_unlock(cptr); return 0; } @@ -2157,7 +2122,7 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, { struct snd_seq_client_ump_info __user *argp = (struct snd_seq_client_ump_info __user *)arg; - struct snd_seq_client *cptr; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; int client, type, err = 0; size_t size; void *p; @@ -2180,7 +2145,7 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, scoped_guard(mutex, &cptr->ioctl_mutex) { if (!cptr->midi_version) { err = -EBADFD; - goto error; + break; } if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) { @@ -2190,38 +2155,36 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, p = cptr->ump_info[type]; if (!p) { err = -ENODEV; - goto error; + break; } if (copy_to_user(argp->info, p, size)) { err = -EFAULT; - goto error; + break; } } else { if (cptr->type != USER_CLIENT) { err = -EBADFD; - goto error; + break; } if (!cptr->ump_info) { cptr->ump_info = kcalloc(NUM_UMP_INFOS, sizeof(void *), GFP_KERNEL); if (!cptr->ump_info) { err = -ENOMEM; - goto error; + break; } } p = memdup_user(argp->info, size); if (IS_ERR(p)) { err = PTR_ERR(p); - goto error; + break; } kfree(cptr->ump_info[type]); terminate_ump_info_strings(p, type); cptr->ump_info[type] = p; } - } - error: - snd_seq_client_unlock(cptr); + } if (!err && cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO) { if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) snd_seq_system_ump_notify(client, 0, @@ -2434,8 +2397,7 @@ EXPORT_SYMBOL(snd_seq_delete_kernel_client); int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, struct file *file, bool blocking) { - struct snd_seq_client *cptr; - int result; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; if (snd_BUG_ON(!ev)) return -EINVAL; @@ -2458,16 +2420,13 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, return -EINVAL; if (!cptr->accept_output) { - result = -EPERM; + return -EPERM; } else { /* send it */ guard(mutex)(&cptr->ioctl_mutex); - result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, - false, 0, - &cptr->ioctl_mutex); + return snd_seq_client_enqueue_event(cptr, ev, file, blocking, + false, 0, + &cptr->ioctl_mutex); } - - snd_seq_client_unlock(cptr); - return result; } EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); @@ -2481,8 +2440,7 @@ EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, int atomic, int hop) { - struct snd_seq_client *cptr; - int result; + struct snd_seq_client *cptr __free(snd_seq_client) = NULL; if (snd_BUG_ON(!ev)) return -EINVAL; @@ -2499,12 +2457,9 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, return -EINVAL; if (!cptr->accept_output) - result = -EPERM; + return -EPERM; else - result = snd_seq_deliver_event(cptr, ev, atomic, hop); - - snd_seq_client_unlock(cptr); - return result; + return snd_seq_deliver_event(cptr, ev, atomic, hop); } EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); @@ -2550,17 +2505,13 @@ EXPORT_SYMBOL(snd_seq_kernel_client_ctl); /* a similar like above but taking locks; used only from OSS sequencer layer */ int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg) { - struct snd_seq_client *client; - int ret; + struct snd_seq_client *client __free(snd_seq_client) = NULL; client = client_load_and_use_ptr(clientid); if (!client) return -ENXIO; - scoped_guard(mutex, &client->ioctl_mutex) { - ret = call_seq_client_ctl(client, cmd, arg); - } - snd_seq_client_unlock(client); - return ret; + guard(mutex)(&client->ioctl_mutex); + return call_seq_client_ctl(client, cmd, arg); } EXPORT_SYMBOL_GPL(snd_seq_kernel_client_ioctl); @@ -2590,7 +2541,7 @@ EXPORT_SYMBOL_GPL(snd_seq_kernel_client_get); void snd_seq_kernel_client_put(struct snd_seq_client *cptr) { if (cptr) - snd_seq_client_unlock(cptr); + snd_seq_client_unref(cptr); } EXPORT_SYMBOL_GPL(snd_seq_kernel_client_put); @@ -2692,7 +2643,6 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { int c; - struct snd_seq_client *client; snd_iprintf(buffer, "Client info\n"); snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur); @@ -2702,15 +2652,15 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, /* list the client table */ for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) { + struct snd_seq_client *client __free(snd_seq_client) = NULL; + client = client_load_and_use_ptr(c); if (client == NULL) continue; - if (client->type == NO_CLIENT) { - snd_seq_client_unlock(client); + if (client->type == NO_CLIENT) continue; - } - mutex_lock(&client->ioctl_mutex); + guard(mutex)(&client->ioctl_mutex); snd_iprintf(buffer, "Client %3d : \"%s\" [%s %s]\n", c, client->name, client->type == USER_CLIENT ? "User" : "Kernel", @@ -2728,8 +2678,6 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, snd_iprintf(buffer, " Input pool :\n"); snd_seq_info_pool(buffer, client->data.user.fifo->pool, " "); } - mutex_unlock(&client->ioctl_mutex); - snd_seq_client_unlock(client); } } #endif /* CONFIG_SND_PROC_FS */ diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index b42afb887daf63..ece02c58db702d 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -91,7 +91,7 @@ static inline void snd_seq_client_unref(struct snd_seq_client *client) snd_use_lock_free(&client->use_lock); } -#define snd_seq_client_unlock(c) snd_seq_client_unref(c) +DEFINE_FREE(snd_seq_client, struct snd_seq_client *, if (!IS_ERR_OR_NULL(_T)) snd_seq_client_unref(_T)) /* dispatch event to client(s) */ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop); diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index cc2f8e846584e9..446d67c0fd6769 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -178,17 +178,10 @@ static int unsubscribe_port(struct snd_seq_client *client, static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, struct snd_seq_client **cp) { - struct snd_seq_client_port *p; *cp = snd_seq_client_use_ptr(addr->client); - if (*cp) { - p = snd_seq_port_use_ptr(*cp, addr->port); - if (! p) { - snd_seq_client_unlock(*cp); - *cp = NULL; - } - return p; - } - return NULL; + if (!*cp) + return NULL; + return snd_seq_port_use_ptr(*cp, addr->port); } static void delete_and_unsubscribe_port(struct snd_seq_client *client, @@ -218,7 +211,7 @@ static void clear_subscriber_list(struct snd_seq_client *client, list_for_each_safe(p, n, &grp->list_head) { struct snd_seq_subscribers *subs; - struct snd_seq_client *c; + struct snd_seq_client *c __free(snd_seq_client) = NULL; struct snd_seq_client_port *aport; subs = get_subscriber(p, is_src); @@ -242,7 +235,6 @@ static void clear_subscriber_list(struct snd_seq_client *client, delete_and_unsubscribe_port(c, aport, subs, !is_src, true); kfree(subs); snd_seq_port_unlock(aport); - snd_seq_client_unlock(c); } } From 0869afc958a05e8413dfac3c4a6a456bc0b2fd66 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:11 +0200 Subject: [PATCH 0827/1292] ALSA: seq: Clean up port locking with auto cleanup Like the previous change in seq_clientmgr.c, introduce a new auto-cleanup macro for the snd_seq_port_unlock(), and apply it appropriately. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-6-tiwai@suse.de --- sound/core/seq/seq_clientmgr.c | 141 ++++++++++++--------------------- sound/core/seq/seq_ports.c | 3 +- sound/core/seq/seq_ports.h | 2 + 3 files changed, 53 insertions(+), 93 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 5b14d70ba87a20..18424f56251a16 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -612,21 +612,18 @@ static int _snd_seq_deliver_single_event(struct snd_seq_client *client, int atomic, int hop) { struct snd_seq_client *dest __free(snd_seq_client) = NULL; - struct snd_seq_client_port *dest_port = NULL; - int result = -ENOENT; + struct snd_seq_client_port *dest_port __free(snd_seq_port) = NULL; dest = get_event_dest_client(event); if (dest == NULL) - goto __skip; + return -ENOENT; dest_port = snd_seq_port_use_ptr(dest, event->dest.port); if (dest_port == NULL) - goto __skip; + return -ENOENT; /* check permission */ - if (! check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE)) { - result = -EPERM; - goto __skip; - } + if (!check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE)) + return -EPERM; if (dest_port->timestamping) update_timestamp_of_queue(event, dest_port->time_queue, @@ -634,31 +631,21 @@ static int _snd_seq_deliver_single_event(struct snd_seq_client *client, #if IS_ENABLED(CONFIG_SND_SEQ_UMP) if (snd_seq_ev_is_ump(event)) { - if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) { - result = snd_seq_deliver_from_ump(client, dest, dest_port, - event, atomic, hop); - goto __skip; - } else if (dest->type == USER_CLIENT && - !snd_seq_client_is_ump(dest)) { - result = 0; // drop the event - goto __skip; - } - } else if (snd_seq_client_is_ump(dest)) { - if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) { - result = snd_seq_deliver_to_ump(client, dest, dest_port, + if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) + return snd_seq_deliver_from_ump(client, dest, dest_port, event, atomic, hop); - goto __skip; - } + else if (dest->type == USER_CLIENT && + !snd_seq_client_is_ump(dest)) + return 0; // drop the event + } else if (snd_seq_client_is_ump(dest)) { + if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) + return snd_seq_deliver_to_ump(client, dest, dest_port, + event, atomic, hop); } #endif /* CONFIG_SND_SEQ_UMP */ - result = __snd_seq_deliver_single_event(dest, dest_port, event, - atomic, hop); - - __skip: - if (dest_port) - snd_seq_port_unlock(dest_port); - return result; + return __snd_seq_deliver_single_event(dest, dest_port, event, + atomic, hop); } /* @@ -687,7 +674,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, struct snd_seq_event *event, int port, int atomic, int hop) { - struct snd_seq_client_port *src_port; + struct snd_seq_client_port *src_port __free(snd_seq_port) = NULL; struct snd_seq_subscribers *subs; int err, result = 0, num_ev = 0; union __snd_seq_event event_saved; @@ -734,7 +721,6 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, read_unlock(&grp->list_lock); else up_read(&grp->list_mutex); - snd_seq_port_unlock(src_port); memcpy(event, &event_saved, saved_size); return (result < 0) ? result : num_ev; } @@ -902,10 +888,10 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, event->queue = SNDRV_SEQ_QUEUE_DIRECT; } else if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) { /* check presence of source port */ - struct snd_seq_client_port *src_port = snd_seq_port_use_ptr(client, event->source.port); - if (src_port == NULL) + struct snd_seq_client_port *src_port __free(snd_seq_port) = + snd_seq_port_use_ptr(client, event->source.port); + if (!src_port) return -EINVAL; - snd_seq_port_unlock(src_port); } /* direct event processing without enqueued */ @@ -1361,7 +1347,7 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) { struct snd_seq_port_info *info = arg; struct snd_seq_client *cptr __free(snd_seq_client) = NULL; - struct snd_seq_client_port *port; + struct snd_seq_client_port *port __free(snd_seq_port) = NULL; cptr = client_load_and_use_ptr(info->addr.client); if (cptr == NULL) @@ -1373,7 +1359,6 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) /* get port info */ snd_seq_get_port_info(port, info); - snd_seq_port_unlock(port); return 0; } @@ -1384,14 +1369,13 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg) static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, void *arg) { struct snd_seq_port_info *info = arg; - struct snd_seq_client_port *port; + struct snd_seq_client_port *port __free(snd_seq_port) = NULL; if (info->addr.client != client->number) /* only set our own ports ! */ return -EPERM; port = snd_seq_port_use_ptr(client, info->addr.port); if (port) { snd_seq_set_port_info(port, info); - snd_seq_port_unlock(port); /* notify the change */ snd_seq_system_client_ev_port_change(info->addr.client, info->addr.port); @@ -1461,39 +1445,35 @@ int snd_seq_client_notify_subscription(int client, int port, static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, void *arg) { - int result = -EINVAL; struct snd_seq_port_subscribe *subs = arg; struct snd_seq_client *receiver __free(snd_seq_client) = NULL; struct snd_seq_client *sender __free(snd_seq_client) = NULL; - struct snd_seq_client_port *sport = NULL, *dport = NULL; + struct snd_seq_client_port *sport __free(snd_seq_port) = NULL; + struct snd_seq_client_port *dport __free(snd_seq_port) = NULL; + int result; receiver = client_load_and_use_ptr(subs->dest.client); if (!receiver) - goto __end; + return -EINVAL; sender = client_load_and_use_ptr(subs->sender.client); if (!sender) - goto __end; + return -EINVAL; sport = snd_seq_port_use_ptr(sender, subs->sender.port); if (!sport) - goto __end; + return -EINVAL; dport = snd_seq_port_use_ptr(receiver, subs->dest.port); if (!dport) - goto __end; + return -EINVAL; result = check_subscription_permission(client, sport, dport, subs); if (result < 0) - goto __end; + return result; /* connect them */ result = snd_seq_port_connect(client, sender, sport, receiver, dport, subs); if (! result) /* broadcast announce */ snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0, subs, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED); - __end: - if (sport) - snd_seq_port_unlock(sport); - if (dport) - snd_seq_port_unlock(dport); return result; } @@ -1504,38 +1484,34 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, void *arg) { - int result = -ENXIO; struct snd_seq_port_subscribe *subs = arg; struct snd_seq_client *receiver __free(snd_seq_client) = NULL; struct snd_seq_client *sender __free(snd_seq_client) = NULL; - struct snd_seq_client_port *sport = NULL, *dport = NULL; + struct snd_seq_client_port *sport __free(snd_seq_port) = NULL; + struct snd_seq_client_port *dport __free(snd_seq_port) = NULL; + int result; receiver = snd_seq_client_use_ptr(subs->dest.client); if (!receiver) - goto __end; + return -ENXIO; sender = snd_seq_client_use_ptr(subs->sender.client); if (!sender) - goto __end; + return -ENXIO; sport = snd_seq_port_use_ptr(sender, subs->sender.port); if (!sport) - goto __end; + return -ENXIO; dport = snd_seq_port_use_ptr(receiver, subs->dest.port); if (!dport) - goto __end; + return -ENXIO; result = check_subscription_permission(client, sport, dport, subs); if (result < 0) - goto __end; + return result; result = snd_seq_port_disconnect(client, sender, sport, receiver, dport, subs); if (! result) /* broadcast announce */ snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0, subs, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED); - __end: - if (sport) - snd_seq_port_unlock(sport); - if (dport) - snd_seq_port_unlock(dport); return result; } @@ -1926,24 +1902,16 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, void *arg) { struct snd_seq_port_subscribe *subs = arg; - int result; struct snd_seq_client *sender __free(snd_seq_client) = NULL; - struct snd_seq_client_port *sport = NULL; + struct snd_seq_client_port *sport __free(snd_seq_port) = NULL; - result = -EINVAL; sender = client_load_and_use_ptr(subs->sender.client); if (!sender) - goto __end; + return -EINVAL; sport = snd_seq_port_use_ptr(sender, subs->sender.port); if (!sport) - goto __end; - result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest, - subs); - __end: - if (sport) - snd_seq_port_unlock(sport); - - return result; + return -EINVAL; + return snd_seq_port_get_subscription(&sport->c_src, &subs->dest, subs); } @@ -1953,19 +1921,18 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) { struct snd_seq_query_subs *subs = arg; - int result = -ENXIO; struct snd_seq_client *cptr __free(snd_seq_client) = NULL; - struct snd_seq_client_port *port = NULL; + struct snd_seq_client_port *port __free(snd_seq_port) = NULL; struct snd_seq_port_subs_info *group; struct list_head *p; int i; cptr = client_load_and_use_ptr(subs->root.client); if (!cptr) - goto __end; + return -ENXIO; port = snd_seq_port_use_ptr(cptr, subs->root.port); if (!port) - goto __end; + return -ENXIO; switch (subs->type) { case SNDRV_SEQ_QUERY_SUBS_READ: @@ -1975,14 +1942,13 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) group = &port->c_dest; break; default: - goto __end; + return -ENXIO; } - down_read(&group->list_mutex); + guard(rwsem_read)(&group->list_mutex); /* search for the subscriber */ subs->num_subs = group->count; i = 0; - result = -ENOENT; list_for_each(p, &group->list_head) { if (i++ == subs->index) { /* found! */ @@ -1996,17 +1962,11 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) } subs->flags = s->info.flags; subs->queue = s->info.queue; - result = 0; - break; + return 0; } } - up_read(&group->list_mutex); - - __end: - if (port) - snd_seq_port_unlock(port); - return result; + return -ENOENT; } @@ -2042,7 +2002,7 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, { struct snd_seq_port_info *info = arg; struct snd_seq_client *cptr __free(snd_seq_client) = NULL; - struct snd_seq_client_port *port = NULL; + struct snd_seq_client_port *port __free(snd_seq_port) = NULL; cptr = client_load_and_use_ptr(info->addr.client); if (cptr == NULL) @@ -2057,7 +2017,6 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, /* get port info */ info->addr = port->addr; snd_seq_get_port_info(port, info); - snd_seq_port_unlock(port); return 0; } diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 446d67c0fd6769..40fa379847e573 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -212,7 +212,7 @@ static void clear_subscriber_list(struct snd_seq_client *client, list_for_each_safe(p, n, &grp->list_head) { struct snd_seq_subscribers *subs; struct snd_seq_client *c __free(snd_seq_client) = NULL; - struct snd_seq_client_port *aport; + struct snd_seq_client_port *aport __free(snd_seq_port) = NULL; subs = get_subscriber(p, is_src); if (is_src) @@ -234,7 +234,6 @@ static void clear_subscriber_list(struct snd_seq_client *client, /* ok we got the connected port */ delete_and_unsubscribe_port(c, aport, subs, !is_src, true); kfree(subs); - snd_seq_port_unlock(aport); } } diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h index b3b35018cb8209..40ed6cf7cb90bb 100644 --- a/sound/core/seq/seq_ports.h +++ b/sound/core/seq/seq_ports.h @@ -96,6 +96,8 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl /* unlock the port */ #define snd_seq_port_unlock(port) snd_use_lock_free(&(port)->use_lock) +DEFINE_FREE(snd_seq_port, struct snd_seq_client_port *, if (!IS_ERR_OR_NULL(_T)) snd_seq_port_unlock(_T)) + /* create a port, port number or a negative error code is returned */ int snd_seq_create_port(struct snd_seq_client *client, int port_index, struct snd_seq_client_port **port_ret); From 04a86185b7853971786d1d4b375b5544edd8d44d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:12 +0200 Subject: [PATCH 0828/1292] ALSA: seq: Clean up queue locking with auto cleanup Yet more cleanup with the auto-cleanup macro: now we replace the queuefree() calls with the magic pointer attribute __free(snd_seq_queue). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-7-tiwai@suse.de --- sound/core/seq/seq_clientmgr.c | 37 ++++++----------- sound/core/seq/seq_queue.c | 76 ++++++++++------------------------ sound/core/seq/seq_queue.h | 2 + sound/core/seq/seq_timer.c | 5 +-- 4 files changed, 39 insertions(+), 81 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 18424f56251a16..38ad5bbd270695 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -566,7 +566,7 @@ static int bounce_error_event(struct snd_seq_client *client, static int update_timestamp_of_queue(struct snd_seq_event *event, int queue, int real_time) { - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; q = queueptr(queue); if (! q) @@ -580,7 +580,6 @@ static int update_timestamp_of_queue(struct snd_seq_event *event, event->time.tick = snd_seq_timer_get_cur_tick(q->timer); event->flags |= SNDRV_SEQ_TIME_STAMP_TICK; } - queuefree(q); return 1; } @@ -1520,7 +1519,7 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg) { struct snd_seq_queue_info *info = arg; - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; q = snd_seq_queue_alloc(client->number, info->locked, info->flags); if (IS_ERR(q)) @@ -1534,7 +1533,6 @@ static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg) if (!info->name[0]) snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue); strscpy(q->name, info->name, sizeof(q->name)); - snd_use_lock_free(&q->use_lock); return 0; } @@ -1552,7 +1550,7 @@ static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client, void *arg) { struct snd_seq_queue_info *info = arg; - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; q = queueptr(info->queue); if (q == NULL) @@ -1563,7 +1561,6 @@ static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client, info->owner = q->owner; info->locked = q->locked; strscpy(info->name, q->name, sizeof(info->name)); - queuefree(q); return 0; } @@ -1573,7 +1570,7 @@ static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client, void *arg) { struct snd_seq_queue_info *info = arg; - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; if (info->owner != client->number) return -EINVAL; @@ -1591,12 +1588,9 @@ static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client, q = queueptr(info->queue); if (! q) return -EINVAL; - if (q->owner != client->number) { - queuefree(q); + if (q->owner != client->number) return -EPERM; - } strscpy(q->name, info->name, sizeof(q->name)); - queuefree(q); return 0; } @@ -1606,7 +1600,7 @@ static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client, void *arg) { struct snd_seq_queue_info *info = arg; - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; q = snd_seq_queue_find_name(info->name); if (q == NULL) @@ -1614,7 +1608,6 @@ static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client, info->queue = q->queue; info->owner = q->owner; info->locked = q->locked; - queuefree(q); return 0; } @@ -1624,7 +1617,7 @@ static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client, void *arg) { struct snd_seq_queue_status *status = arg; - struct snd_seq_queue *queue; + struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; struct snd_seq_timer *tmr; queue = queueptr(status->queue); @@ -1642,7 +1635,6 @@ static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client, status->running = tmr->running; status->flags = queue->flags; - queuefree(queue); return 0; } @@ -1653,7 +1645,7 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client, void *arg) { struct snd_seq_queue_tempo *tempo = arg; - struct snd_seq_queue *queue; + struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; struct snd_seq_timer *tmr; queue = queueptr(tempo->queue); @@ -1670,7 +1662,6 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client, tempo->skew_base = tmr->skew_base; if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 4)) tempo->tempo_base = tmr->tempo_base; - queuefree(queue); return 0; } @@ -1703,14 +1694,14 @@ static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client, void *arg) { struct snd_seq_queue_timer *timer = arg; - struct snd_seq_queue *queue; + struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; struct snd_seq_timer *tmr; queue = queueptr(timer->queue); if (queue == NULL) return -EINVAL; - mutex_lock(&queue->timer_mutex); + guard(mutex)(&queue->timer_mutex); tmr = queue->timer; memset(timer, 0, sizeof(*timer)); timer->queue = queue->queue; @@ -1720,8 +1711,6 @@ static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client, timer->u.alsa.id = tmr->alsa_id; timer->u.alsa.resolution = tmr->preferred_resolution; } - mutex_unlock(&queue->timer_mutex); - queuefree(queue); return 0; } @@ -1738,13 +1727,13 @@ static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client, return -EINVAL; if (snd_seq_queue_check_access(timer->queue, client->number)) { - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; struct snd_seq_timer *tmr; q = queueptr(timer->queue); if (q == NULL) return -ENXIO; - mutex_lock(&q->timer_mutex); + guard(mutex)(&q->timer_mutex); tmr = q->timer; snd_seq_queue_timer_close(timer->queue); tmr->type = timer->type; @@ -1753,8 +1742,6 @@ static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client, tmr->preferred_resolution = timer->u.alsa.resolution; } result = snd_seq_queue_timer_open(timer->queue); - mutex_unlock(&q->timer_mutex); - queuefree(q); } else { return -EPERM; } diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 10add922323dab..f5c0e401c8ae56 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -209,14 +209,13 @@ struct snd_seq_queue *queueptr(int queueid) struct snd_seq_queue *snd_seq_queue_find_name(char *name) { int i; - struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; q = queueptr(i); if (q) { if (strncmp(q->name, name, sizeof(q->name)) == 0) - return q; - queuefree(q); + return no_free_ptr(q); } } return NULL; @@ -286,7 +285,7 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop) { int dest, err; - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; if (snd_BUG_ON(!cell)) return -EINVAL; @@ -321,16 +320,12 @@ int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop) break; } - if (err < 0) { - queuefree(q); /* unlock */ + if (err < 0) return err; - } /* trigger dispatching */ snd_seq_check_queue(q, atomic, hop); - queuefree(q); /* unlock */ - return 0; } @@ -366,15 +361,12 @@ static inline void queue_access_unlock(struct snd_seq_queue *q) /* exported - only checking permission */ int snd_seq_queue_check_access(int queueid, int client) { - struct snd_seq_queue *q = queueptr(queueid); - int access_ok; + struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(queueid); if (! q) return 0; - scoped_guard(spinlock_irqsave, &q->owner_lock) - access_ok = check_access(q, client); - queuefree(q); - return access_ok; + guard(spinlock_irqsave)(&q->owner_lock); + return check_access(q, client); } /*----------------------------------------------------------------*/ @@ -384,22 +376,19 @@ int snd_seq_queue_check_access(int queueid, int client) */ int snd_seq_queue_set_owner(int queueid, int client, int locked) { - struct snd_seq_queue *q = queueptr(queueid); + struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(queueid); if (q == NULL) return -EINVAL; - if (! queue_access_lock(q, client)) { - queuefree(q); + if (!queue_access_lock(q, client)) return -EPERM; - } scoped_guard(spinlock_irqsave, &q->owner_lock) { q->locked = locked ? 1 : 0; q->owner = client; } queue_access_unlock(q); - queuefree(q); return 0; } @@ -414,7 +403,7 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked) int snd_seq_queue_timer_open(int queueid) { int result = 0; - struct snd_seq_queue *queue; + struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; struct snd_seq_timer *tmr; queue = queueptr(queueid); @@ -426,7 +415,6 @@ int snd_seq_queue_timer_open(int queueid) snd_seq_timer_defaults(tmr); result = snd_seq_timer_open(queue); } - queuefree(queue); return result; } @@ -435,14 +423,13 @@ int snd_seq_queue_timer_open(int queueid) */ int snd_seq_queue_timer_close(int queueid) { - struct snd_seq_queue *queue; + struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; int result = 0; queue = queueptr(queueid); if (queue == NULL) return -EINVAL; snd_seq_timer_close(queue); - queuefree(queue); return result; } @@ -450,15 +437,13 @@ int snd_seq_queue_timer_close(int queueid) int snd_seq_queue_timer_set_tempo(int queueid, int client, struct snd_seq_queue_tempo *info) { - struct snd_seq_queue *q = queueptr(queueid); + struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(queueid); int result; if (q == NULL) return -EINVAL; - if (! queue_access_lock(q, client)) { - queuefree(q); + if (!queue_access_lock(q, client)) return -EPERM; - } result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq, info->tempo_base); @@ -466,7 +451,6 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, result = snd_seq_timer_set_skew(q->timer, info->skew_value, info->skew_base); queue_access_unlock(q); - queuefree(q); return result; } @@ -495,15 +479,13 @@ static void queue_use(struct snd_seq_queue *queue, int client, int use) */ int snd_seq_queue_use(int queueid, int client, int use) { - struct snd_seq_queue *queue; + struct snd_seq_queue *queue __free(snd_seq_queue) = NULL; queue = queueptr(queueid); if (queue == NULL) return -EINVAL; - mutex_lock(&queue->timer_mutex); + guard(mutex)(&queue->timer_mutex); queue_use(queue, client, use); - mutex_unlock(&queue->timer_mutex); - queuefree(queue); return 0; } @@ -514,15 +496,12 @@ int snd_seq_queue_use(int queueid, int client, int use) */ int snd_seq_queue_is_used(int queueid, int client) { - struct snd_seq_queue *q; - int result; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; q = queueptr(queueid); if (q == NULL) return -EINVAL; /* invalid queue */ - result = test_bit(client, q->clients_bitmap) ? 1 : 0; - queuefree(q); - return result; + return test_bit(client, q->clients_bitmap) ? 1 : 0; } @@ -535,11 +514,10 @@ int snd_seq_queue_is_used(int queueid, int client) void snd_seq_queue_client_leave(int client) { int i; - struct snd_seq_queue *q; /* delete own queues from queue list */ for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - q = queue_list_remove(i, client); + struct snd_seq_queue *q = queue_list_remove(i, client); if (q) queue_delete(q); } @@ -548,7 +526,7 @@ void snd_seq_queue_client_leave(int client) * they are not owned by this client */ for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - q = queueptr(i); + struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(i); if (!q) continue; if (test_bit(client, q->clients_bitmap)) { @@ -556,7 +534,6 @@ void snd_seq_queue_client_leave(int client) snd_seq_prioq_leave(q->timeq, client, 0); snd_seq_queue_use(q->queue, client, 0); } - queuefree(q); } } @@ -568,10 +545,9 @@ void snd_seq_queue_client_leave(int client) void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info) { int i; - struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - q = queueptr(i); + struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(i); if (!q) continue; if (test_bit(client, q->clients_bitmap) && @@ -580,7 +556,6 @@ void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info) snd_seq_prioq_remove_events(q->tickq, client, info); snd_seq_prioq_remove_events(q->timeq, client, info); } - queuefree(q); } } @@ -667,7 +642,7 @@ static void snd_seq_queue_process_event(struct snd_seq_queue *q, */ int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop) { - struct snd_seq_queue *q; + struct snd_seq_queue *q __free(snd_seq_queue) = NULL; if (snd_BUG_ON(!ev)) return -EINVAL; @@ -676,15 +651,12 @@ int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop) if (q == NULL) return -EINVAL; - if (! queue_access_lock(q, ev->source.client)) { - queuefree(q); + if (!queue_access_lock(q, ev->source.client)) return -EPERM; - } snd_seq_queue_process_event(q, ev, atomic, hop); queue_access_unlock(q); - queuefree(q); return 0; } @@ -697,13 +669,12 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { int i, bpm; - struct snd_seq_queue *q; struct snd_seq_timer *tmr; bool locked; int owner; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - q = queueptr(i); + struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(i); if (!q) continue; @@ -731,7 +702,6 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec); snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick); snd_iprintf(buffer, "\n"); - queuefree(q); } } #endif /* CONFIG_SND_PROC_FS */ diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index b81379c9af43e6..afcd3c5484a631 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h @@ -73,6 +73,8 @@ struct snd_seq_queue *queueptr(int queueid); /* unlock */ #define queuefree(q) snd_use_lock_free(&(q)->use_lock) +DEFINE_FREE(snd_seq_queue, struct snd_seq_queue *, if (!IS_ERR_OR_NULL(_T)) queuefree(_T)) + /* return the (first) queue matching with the specified name */ struct snd_seq_queue *snd_seq_queue_find_name(char *name); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index c9f0392ac7f156..29b018a212fc31 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -440,13 +440,13 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { int idx; - struct snd_seq_queue *q; struct snd_seq_timer *tmr; struct snd_timer_instance *ti; unsigned long resolution; for (idx = 0; idx < SNDRV_SEQ_MAX_QUEUES; idx++) { - q = queueptr(idx); + struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(idx); + if (q == NULL) continue; scoped_guard(mutex, &q->timer_mutex) { @@ -461,7 +461,6 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); } - queuefree(q); } } #endif /* CONFIG_SND_PROC_FS */ From 9314e34e37292f2d3d43dcc8a7f54366b4c0811d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:13 +0200 Subject: [PATCH 0829/1292] ALSA: seq: Clean up fifo locking with guard Yet more cleanup, now for seq_fifo.c about its refcount calls; the manual refcount calls (either snd_use_lock_*() or snd_seq_fifo_lock()) are replaced with guard(snd_seq_fifo). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-8-tiwai@suse.de --- sound/core/seq/seq_clientmgr.c | 3 +-- sound/core/seq/seq_fifo.c | 15 ++++----------- sound/core/seq/seq_fifo.h | 1 + 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 38ad5bbd270695..f9a6e497f997cc 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -416,7 +416,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, cell = NULL; err = 0; - snd_seq_fifo_lock(fifo); + guard(snd_seq_fifo)(fifo); if (IS_ENABLED(CONFIG_SND_SEQ_UMP) && client->midi_version > 0) aligned_size = sizeof(struct snd_seq_ump_event); @@ -474,7 +474,6 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, if (err == -EAGAIN && result > 0) err = 0; } - snd_seq_fifo_unlock(fifo); return (err < 0) ? err : result; } diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 3a10b081f129c3..f23c6b7ae2403c 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -106,12 +106,11 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, if (snd_BUG_ON(!f)) return -EINVAL; - snd_use_lock_use(&f->use_lock); + guard(snd_seq_fifo)(f); err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */ if (err < 0) { if ((err == -ENOMEM) || (err == -EAGAIN)) atomic_inc(&f->overflow); - snd_use_lock_free(&f->use_lock); return err; } @@ -130,8 +129,6 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, if (waitqueue_active(&f->input_sleep)) wake_up(&f->input_sleep); - snd_use_lock_free(&f->use_lock); - return 0; /* success */ } @@ -263,14 +260,10 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize) /* get the number of unused cells safely */ int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f) { - int cells; - if (!f) return 0; - snd_use_lock_use(&f->use_lock); - scoped_guard(spinlock_irqsave, &f->lock) - cells = snd_seq_unused_cells(f->pool); - snd_use_lock_free(&f->use_lock); - return cells; + guard(snd_seq_fifo)(f); + guard(spinlock_irqsave)(&f->lock); + return snd_seq_unused_cells(f->pool); } diff --git a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h index b56a7b897c9c31..4c9c49127746b9 100644 --- a/sound/core/seq/seq_fifo.h +++ b/sound/core/seq/seq_fifo.h @@ -37,6 +37,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, struct snd_seq_event *event); /* lock fifo from release */ #define snd_seq_fifo_lock(fifo) snd_use_lock_use(&(fifo)->use_lock) #define snd_seq_fifo_unlock(fifo) snd_use_lock_free(&(fifo)->use_lock) +DEFINE_GUARD(snd_seq_fifo, struct snd_seq_fifo *, snd_seq_fifo_lock(_T), snd_seq_fifo_unlock(_T)) /* get a cell from fifo - fifo should be locked */ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f, struct snd_seq_event_cell **cellp, int nonblock); From 1291fc664d2320af332e0f6b3c28a1a4e125fee9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:14 +0200 Subject: [PATCH 0830/1292] ALSA: seq: oss: Clean up core code with guard() Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-9-tiwai@suse.de --- sound/core/seq/oss/seq_oss.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 77c1214acd90dc..02d30d8b6c3a82 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -117,18 +117,15 @@ static DEFINE_MUTEX(register_mutex); static int odev_open(struct inode *inode, struct file *file) { - int level, rc; + int level; if (iminor(inode) == SNDRV_MINOR_OSS_MUSIC) level = SNDRV_SEQ_OSS_MODE_MUSIC; else level = SNDRV_SEQ_OSS_MODE_SYNTH; - mutex_lock(®ister_mutex); - rc = snd_seq_oss_open(file, level); - mutex_unlock(®ister_mutex); - - return rc; + guard(mutex)(®ister_mutex); + return snd_seq_oss_open(file, level); } static int @@ -140,10 +137,8 @@ odev_release(struct inode *inode, struct file *file) if (!dp) return 0; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); snd_seq_oss_release(dp); - mutex_unlock(®ister_mutex); - return 0; } @@ -229,13 +224,12 @@ register_device(void) { int rc; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0, &seq_oss_f_ops, NULL); if (rc < 0) { pr_err("ALSA: seq_oss: can't register device seq\n"); - mutex_unlock(®ister_mutex); return rc; } rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, @@ -244,22 +238,19 @@ register_device(void) if (rc < 0) { pr_err("ALSA: seq_oss: can't register device music\n"); snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0); - mutex_unlock(®ister_mutex); return rc; } - mutex_unlock(®ister_mutex); return 0; } static void unregister_device(void) { - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0) pr_err("ALSA: seq_oss: error unregister device music\n"); if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0) pr_err("ALSA: seq_oss: error unregister device seq\n"); - mutex_unlock(®ister_mutex); } /* @@ -273,12 +264,11 @@ static struct snd_info_entry *info_entry; static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf) { - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR); snd_seq_oss_system_info_read(buf); snd_seq_oss_synth_info_read(buf); snd_seq_oss_midi_info_read(buf); - mutex_unlock(®ister_mutex); } From 895a46e034f9aa11779c66f0bb41c51f50b265ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:15 +0200 Subject: [PATCH 0831/1292] ALSA: seq: oss/midi: Cleanup with guard and auto-cleanup Use the auto-cleanup for the refcount management of seq_oss_midi object. The explicit call of snd_use_lock_free() is dropped by the magic __free(seq_oss_midi) attribute. Along with that, replace the manual mutex and spin locks with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-10-tiwai@suse.de --- sound/core/seq/oss/seq_oss_midi.c | 116 ++++++++++-------------------- 1 file changed, 36 insertions(+), 80 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index f8e247d9e5c99f..023e5d0a4351da 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -40,6 +40,7 @@ struct seq_oss_midi { struct mutex open_mutex; }; +DEFINE_FREE(seq_oss_midi, struct seq_oss_midi *, if (!IS_ERR_OR_NULL(_T)) snd_use_lock_free(&(_T)->use_lock)) /* * midi device table @@ -90,13 +91,11 @@ static struct seq_oss_midi * get_mdev(int dev) { struct seq_oss_midi *mdev; - unsigned long flags; - spin_lock_irqsave(®ister_lock, flags); + guard(spinlock_irqsave)(®ister_lock); mdev = midi_devs[dev]; if (mdev) snd_use_lock_use(&mdev->use_lock); - spin_unlock_irqrestore(®ister_lock, flags); return mdev; } @@ -108,19 +107,16 @@ find_slot(int client, int port) { int i; struct seq_oss_midi *mdev; - unsigned long flags; - spin_lock_irqsave(®ister_lock, flags); + guard(spinlock_irqsave)(®ister_lock); for (i = 0; i < max_midi_devs; i++) { mdev = midi_devs[i]; if (mdev && mdev->client == client && mdev->port == port) { /* found! */ snd_use_lock_use(&mdev->use_lock); - spin_unlock_irqrestore(®ister_lock, flags); return mdev; } } - spin_unlock_irqrestore(®ister_lock, flags); return NULL; } @@ -135,7 +131,6 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) { int i; struct seq_oss_midi *mdev; - unsigned long flags; /* the port must include generic midi */ if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC)) @@ -185,14 +180,13 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) /* * look for en empty slot */ - spin_lock_irqsave(®ister_lock, flags); + guard(spinlock_irqsave)(®ister_lock); for (i = 0; i < max_midi_devs; i++) { if (midi_devs[i] == NULL) break; } if (i >= max_midi_devs) { if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) { - spin_unlock_irqrestore(®ister_lock, flags); snd_midi_event_free(mdev->coder); kfree(mdev); return -ENOMEM; @@ -201,7 +195,6 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) } mdev->seq_device = i; midi_devs[mdev->seq_device] = mdev; - spin_unlock_irqrestore(®ister_lock, flags); return 0; } @@ -213,26 +206,24 @@ int snd_seq_oss_midi_check_exit_port(int client, int port) { struct seq_oss_midi *mdev; - unsigned long flags; int index; mdev = find_slot(client, port); if (mdev) { - spin_lock_irqsave(®ister_lock, flags); - midi_devs[mdev->seq_device] = NULL; - spin_unlock_irqrestore(®ister_lock, flags); + scoped_guard(spinlock_irqsave, ®ister_lock) { + midi_devs[mdev->seq_device] = NULL; + } snd_use_lock_free(&mdev->use_lock); snd_use_lock_sync(&mdev->use_lock); snd_midi_event_free(mdev->coder); kfree(mdev); } - spin_lock_irqsave(®ister_lock, flags); + guard(spinlock_irqsave)(®ister_lock); for (index = max_midi_devs - 1; index >= 0; index--) { if (midi_devs[index]) break; } max_midi_devs = index + 1; - spin_unlock_irqrestore(®ister_lock, flags); return 0; } @@ -245,9 +236,8 @@ snd_seq_oss_midi_clear_all(void) { int i; struct seq_oss_midi *mdev; - unsigned long flags; - spin_lock_irqsave(®ister_lock, flags); + guard(spinlock_irqsave)(®ister_lock); for (i = 0; i < max_midi_devs; i++) { mdev = midi_devs[i]; if (mdev) { @@ -257,7 +247,6 @@ snd_seq_oss_midi_clear_all(void) } } max_midi_devs = 0; - spin_unlock_irqrestore(®ister_lock, flags); } @@ -267,9 +256,8 @@ snd_seq_oss_midi_clear_all(void) void snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp) { - spin_lock_irq(®ister_lock); + guard(spinlock_irq)(®ister_lock); dp->max_mididev = max_midi_devs; - spin_unlock_irq(®ister_lock); } /* @@ -317,20 +305,17 @@ int snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) { int perm; - struct seq_oss_midi *mdev; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; struct snd_seq_port_subscribe subs; - int err; mdev = get_mididev(dp, dev); if (!mdev) return -ENODEV; - mutex_lock(&mdev->open_mutex); + guard(mutex)(&mdev->open_mutex); /* already used? */ - if (mdev->opened && mdev->devinfo != dp) { - err = -EBUSY; - goto unlock; - } + if (mdev->opened && mdev->devinfo != dp) + return -EBUSY; perm = 0; if (is_write_mode(fmode)) @@ -338,16 +323,12 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) if (is_read_mode(fmode)) perm |= PERM_READ; perm &= mdev->flags; - if (perm == 0) { - err = -ENXIO; - goto unlock; - } + if (perm == 0) + return -ENXIO; /* already opened? */ - if ((mdev->opened & perm) == perm) { - err = 0; - goto unlock; - } + if ((mdev->opened & perm) == perm) + return 0; perm &= ~mdev->opened; @@ -370,18 +351,11 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) mdev->opened |= PERM_READ; } - if (! mdev->opened) { - err = -ENXIO; - goto unlock; - } + if (!mdev->opened) + return -ENXIO; mdev->devinfo = dp; - err = 0; - - unlock: - mutex_unlock(&mdev->open_mutex); - snd_use_lock_free(&mdev->use_lock); - return err; + return 0; } /* @@ -390,15 +364,15 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) int snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) { - struct seq_oss_midi *mdev; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; struct snd_seq_port_subscribe subs; mdev = get_mididev(dp, dev); if (!mdev) return -ENODEV; - mutex_lock(&mdev->open_mutex); + guard(mutex)(&mdev->open_mutex); if (!mdev->opened || mdev->devinfo != dp) - goto unlock; + return 0; memset(&subs, 0, sizeof(subs)); if (mdev->opened & PERM_WRITE) { @@ -416,10 +390,6 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) mdev->opened = 0; mdev->devinfo = NULL; - - unlock: - mutex_unlock(&mdev->open_mutex); - snd_use_lock_free(&mdev->use_lock); return 0; } @@ -429,7 +399,7 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) int snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) { - struct seq_oss_midi *mdev; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; int mode; mdev = get_mididev(dp, dev); @@ -442,7 +412,6 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) if (mdev->opened & PERM_READ) mode |= SNDRV_SEQ_OSS_FILE_READ; - snd_use_lock_free(&mdev->use_lock); return mode; } @@ -453,15 +422,13 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) void snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) { - struct seq_oss_midi *mdev; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; mdev = get_mididev(dp, dev); if (!mdev) return; - if (! mdev->opened) { - snd_use_lock_free(&mdev->use_lock); + if (!mdev->opened) return; - } if (mdev->opened & PERM_WRITE) { struct snd_seq_event ev; @@ -492,7 +459,6 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) } } // snd_seq_oss_midi_close(dp, dev); - snd_use_lock_free(&mdev->use_lock); } @@ -502,14 +468,13 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) void snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr) { - struct seq_oss_midi *mdev; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; mdev = get_mididev(dp, dev); if (!mdev) return; addr->client = mdev->client; addr->port = mdev->port; - snd_use_lock_free(&mdev->use_lock); } @@ -520,26 +485,20 @@ int snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data) { struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data; - struct seq_oss_midi *mdev; - int rc; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; if (dp->readq == NULL) return 0; mdev = find_slot(ev->source.client, ev->source.port); if (!mdev) return 0; - if (! (mdev->opened & PERM_READ)) { - snd_use_lock_free(&mdev->use_lock); + if (!(mdev->opened & PERM_READ)) return 0; - } if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) - rc = send_synth_event(dp, ev, mdev->seq_device); + return send_synth_event(dp, ev, mdev->seq_device); else - rc = send_midi_event(dp, ev, mdev); - - snd_use_lock_free(&mdev->use_lock); - return rc; + return send_midi_event(dp, ev, mdev); } /* @@ -636,17 +595,15 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq int snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev) { - struct seq_oss_midi *mdev; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; mdev = get_mididev(dp, dev); if (!mdev) return -ENODEV; if (snd_midi_event_encode_byte(mdev->coder, c, ev)) { snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); - snd_use_lock_free(&mdev->use_lock); return 0; } - snd_use_lock_free(&mdev->use_lock); return -EINVAL; } @@ -656,7 +613,7 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru int snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf) { - struct seq_oss_midi *mdev; + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; mdev = get_mididev(dp, dev); if (!mdev) @@ -665,7 +622,6 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info inf->dev_type = 0; /* FIXME: ?? */ inf->capabilities = 0; /* FIXME: ?? */ strscpy(inf->name, mdev->name, sizeof(inf->name)); - snd_use_lock_free(&mdev->use_lock); return 0; } @@ -692,10 +648,11 @@ void snd_seq_oss_midi_info_read(struct snd_info_buffer *buf) { int i; - struct seq_oss_midi *mdev; snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs); for (i = 0; i < max_midi_devs; i++) { + struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL; + snd_iprintf(buf, "\nmidi %d: ", i); mdev = get_mdev(i); if (mdev == NULL) { @@ -707,7 +664,6 @@ snd_seq_oss_midi_info_read(struct snd_info_buffer *buf) snd_iprintf(buf, " capability %s / opened %s\n", capmode_str(mdev->flags), capmode_str(mdev->opened)); - snd_use_lock_free(&mdev->use_lock); } } #endif /* CONFIG_SND_PROC_FS */ From 80ccbe91adab52a2b9a0e8b31663d4ec2a914a77 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:16 +0200 Subject: [PATCH 0832/1292] ALSA: seq: oss/synth: Clean up with guard and auto cleanup Use the auto-cleanup for the refcount management of seq_oss_synth object. The explicit call of snd_use_lock_free() is dropped by the magic __free(seq_oss_synth) attribute. Along with that, replace the manual mutex and spin locks with guard(). Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-11-tiwai@suse.de --- sound/core/seq/oss/seq_oss_synth.c | 125 ++++++++++++----------------- 1 file changed, 52 insertions(+), 73 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 9de47e098b2910..8c4e5913c7e69a 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -44,6 +44,7 @@ struct seq_oss_synth { snd_use_lock_t use_lock; }; +DEFINE_FREE(seq_oss_synth, struct seq_oss_synth *, if (!IS_ERR_OR_NULL(_T)) snd_use_lock_free(&(_T)->use_lock)) /* * device table @@ -85,7 +86,6 @@ snd_seq_oss_synth_probe(struct device *_dev) int i; struct seq_oss_synth *rec; struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); - unsigned long flags; rec = kzalloc(sizeof(*rec), GFP_KERNEL); if (!rec) @@ -103,23 +103,22 @@ snd_seq_oss_synth_probe(struct device *_dev) strscpy(rec->name, dev->name, sizeof(rec->name)); /* registration */ - spin_lock_irqsave(®ister_lock, flags); - for (i = 0; i < max_synth_devs; i++) { - if (synth_devs[i] == NULL) - break; - } - if (i >= max_synth_devs) { - if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) { - spin_unlock_irqrestore(®ister_lock, flags); - pr_err("ALSA: seq_oss: no more synth slot\n"); - kfree(rec); - return -ENOMEM; + scoped_guard(spinlock_irqsave, ®ister_lock) { + for (i = 0; i < max_synth_devs; i++) { + if (synth_devs[i] == NULL) + break; } - max_synth_devs++; + if (i >= max_synth_devs) { + if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) { + pr_err("ALSA: seq_oss: no more synth slot\n"); + kfree(rec); + return -ENOMEM; + } + max_synth_devs++; + } + rec->seq_device = i; + synth_devs[i] = rec; } - rec->seq_device = i; - synth_devs[i] = rec; - spin_unlock_irqrestore(®ister_lock, flags); dev->driver_data = rec; #ifdef SNDRV_OSS_INFO_DEV_SYNTH if (i < SNDRV_CARDS) @@ -135,27 +134,25 @@ snd_seq_oss_synth_remove(struct device *_dev) struct snd_seq_device *dev = to_seq_dev(_dev); int index; struct seq_oss_synth *rec = dev->driver_data; - unsigned long flags; - spin_lock_irqsave(®ister_lock, flags); - for (index = 0; index < max_synth_devs; index++) { - if (synth_devs[index] == rec) - break; - } - if (index >= max_synth_devs) { - spin_unlock_irqrestore(®ister_lock, flags); - pr_err("ALSA: seq_oss: can't unregister synth\n"); - return -EINVAL; - } - synth_devs[index] = NULL; - if (index == max_synth_devs - 1) { - for (index--; index >= 0; index--) { - if (synth_devs[index]) + scoped_guard(spinlock_irqsave, ®ister_lock) { + for (index = 0; index < max_synth_devs; index++) { + if (synth_devs[index] == rec) break; } - max_synth_devs = index + 1; + if (index >= max_synth_devs) { + pr_err("ALSA: seq_oss: can't unregister synth\n"); + return -EINVAL; + } + synth_devs[index] = NULL; + if (index == max_synth_devs - 1) { + for (index--; index >= 0; index--) { + if (synth_devs[index]) + break; + } + max_synth_devs = index + 1; + } } - spin_unlock_irqrestore(®ister_lock, flags); #ifdef SNDRV_OSS_INFO_DEV_SYNTH if (rec->seq_device < SNDRV_CARDS) snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device); @@ -174,13 +171,11 @@ static struct seq_oss_synth * get_sdev(int dev) { struct seq_oss_synth *rec; - unsigned long flags; - spin_lock_irqsave(®ister_lock, flags); + guard(spinlock_irqsave)(®ister_lock); rec = synth_devs[dev]; if (rec) snd_use_lock_use(&rec->use_lock); - spin_unlock_irqrestore(®ister_lock, flags); return rec; } @@ -193,20 +188,18 @@ void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp) { int i; - struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; dp->max_synthdev = max_synth_devs; dp->synth_opened = 0; memset(dp->synths, 0, sizeof(dp->synths)); for (i = 0; i < dp->max_synthdev; i++) { - rec = get_sdev(i); + struct seq_oss_synth *rec __free(seq_oss_synth) = get_sdev(i); + if (rec == NULL) continue; - if (rec->oper.open == NULL || rec->oper.close == NULL) { - snd_use_lock_free(&rec->use_lock); + if (rec->oper.open == NULL || rec->oper.close == NULL) continue; - } info = &dp->synths[i]; info->arg.app_index = dp->port; info->arg.file_mode = dp->file_mode; @@ -216,13 +209,10 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp) else info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS; info->opened = 0; - if (!try_module_get(rec->oper.owner)) { - snd_use_lock_free(&rec->use_lock); + if (!try_module_get(rec->oper.owner)) continue; - } if (rec->oper.open(&info->arg, rec->private_data) < 0) { module_put(rec->oper.owner); - snd_use_lock_free(&rec->use_lock); continue; } info->nr_voices = rec->nr_voices; @@ -231,7 +221,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp) if (!info->ch) { rec->oper.close(&info->arg); module_put(rec->oper.owner); - snd_use_lock_free(&rec->use_lock); continue; } reset_channels(info); @@ -239,7 +228,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp) info->opened++; rec->opened++; dp->synth_opened++; - snd_use_lock_free(&rec->use_lock); } } @@ -286,7 +274,6 @@ void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) { int i; - struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) @@ -301,7 +288,9 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) midi_synth_dev.opened--; } } else { - rec = get_sdev(i); + struct seq_oss_synth *rec __free(seq_oss_synth) = + get_sdev(i); + if (rec == NULL) continue; if (rec->opened > 0) { @@ -309,7 +298,6 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) module_put(rec->oper.owner); rec->opened = 0; } - snd_use_lock_free(&rec->use_lock); } kfree(info->ch); info->ch = NULL; @@ -380,7 +368,7 @@ reset_channels(struct seq_oss_synthinfo *info) void snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) { - struct seq_oss_synth *rec; + struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; struct seq_oss_synthinfo *info; info = get_synthinfo_nospec(dp, dev); @@ -416,7 +404,6 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) ev.type = SNDRV_SEQ_EVENT_RESET; snd_seq_oss_dispatch(dp, &ev, 0, 0); } - snd_use_lock_free(&rec->use_lock); } @@ -428,9 +415,8 @@ int snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c) { - struct seq_oss_synth *rec; + struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; struct seq_oss_synthinfo *info; - int rc; info = get_synthinfo_nospec(dp, dev); if (!info) @@ -443,11 +429,9 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, return -ENXIO; if (rec->oper.load_patch == NULL) - rc = -ENXIO; + return -ENXIO; else - rc = rec->oper.load_patch(&info->arg, fmt, buf, p, c); - snd_use_lock_free(&rec->use_lock); - return rc; + return rec->oper.load_patch(&info->arg, fmt, buf, p, c); } /* @@ -456,13 +440,11 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, struct seq_oss_synthinfo * snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev) { - struct seq_oss_synth *rec; + struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; rec = get_synthdev(dp, dev); - if (rec) { - snd_use_lock_free(&rec->use_lock); + if (rec) return get_synthinfo_nospec(dp, dev); - } return NULL; } @@ -513,9 +495,8 @@ snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event int snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr) { - struct seq_oss_synth *rec; + struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; struct seq_oss_synthinfo *info; - int rc; info = get_synthinfo_nospec(dp, dev); if (!info || info->is_midi) @@ -524,11 +505,9 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u if (!rec) return -ENXIO; if (rec->oper.ioctl == NULL) - rc = -ENXIO; + return -ENXIO; else - rc = rec->oper.ioctl(&info->arg, cmd, addr); - snd_use_lock_free(&rec->use_lock); - return rc; + return rec->oper.ioctl(&info->arg, cmd, addr); } @@ -555,7 +534,6 @@ snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char * int snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_info *inf) { - struct seq_oss_synth *rec; struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev); if (!info) @@ -571,7 +549,9 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in inf->device = dev; strscpy(inf->name, minf.name, sizeof(inf->name)); } else { - rec = get_synthdev(dp, dev); + struct seq_oss_synth *rec __free(seq_oss_synth) = + get_synthdev(dp, dev); + if (!rec) return -ENXIO; inf->synth_type = rec->synth_type; @@ -579,7 +559,6 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in inf->nr_voices = rec->nr_voices; inf->device = dev; strscpy(inf->name, rec->name, sizeof(inf->name)); - snd_use_lock_free(&rec->use_lock); } return 0; } @@ -593,10 +572,11 @@ void snd_seq_oss_synth_info_read(struct snd_info_buffer *buf) { int i; - struct seq_oss_synth *rec; snd_iprintf(buf, "\nNumber of synth devices: %d\n", max_synth_devs); for (i = 0; i < max_synth_devs; i++) { + struct seq_oss_synth *rec __free(seq_oss_synth) = NULL; + snd_iprintf(buf, "\nsynth %d: ", i); rec = get_sdev(i); if (rec == NULL) { @@ -610,7 +590,6 @@ snd_seq_oss_synth_info_read(struct snd_info_buffer *buf) snd_iprintf(buf, " capabilities : ioctl %s / load_patch %s\n", str_enabled_disabled((long)rec->oper.ioctl), str_enabled_disabled((long)rec->oper.load_patch)); - snd_use_lock_free(&rec->use_lock); } } #endif /* CONFIG_SND_PROC_FS */ From da24e6b3c251d6ef6964b78f198f6dfd5385d372 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Aug 2025 10:05:17 +0200 Subject: [PATCH 0833/1292] ALSA: seq: oss/rw: Cleanup with guard Replace the manual spin lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250827080520.7544-12-tiwai@suse.de --- sound/core/seq/oss/seq_oss_readq.c | 10 ++-------- sound/core/seq/oss/seq_oss_writeq.c | 5 +---- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c index f0db5d3dcba470..bbaf72e70b3593 100644 --- a/sound/core/seq/oss/seq_oss_readq.c +++ b/sound/core/seq/oss/seq_oss_readq.c @@ -140,13 +140,9 @@ int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev, int snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); - if (q->qlen >= q->maxlen - 1) { - spin_unlock_irqrestore(&q->lock, flags); + guard(spinlock_irqsave)(&q->lock); + if (q->qlen >= q->maxlen - 1) return -ENOMEM; - } memcpy(&q->q[q->tail], ev, sizeof(*ev)); q->tail = (q->tail + 1) % q->maxlen; @@ -155,8 +151,6 @@ snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev) /* wake up sleeper */ wake_up(&q->midi_sleep); - spin_unlock_irqrestore(&q->lock, flags); - return 0; } diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 3e3209ce53b1c0..a93ff8315b8e95 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -122,13 +122,10 @@ snd_seq_oss_writeq_sync(struct seq_oss_writeq *q) void snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time) { - unsigned long flags; - - spin_lock_irqsave(&q->sync_lock, flags); + guard(spinlock_irqsave)(&q->sync_lock); q->sync_time = time; q->sync_event_put = 0; wake_up(&q->sync_sleep); - spin_unlock_irqrestore(&q->sync_lock, flags); } From 6ad299a9b968e1c63988e2a327295e522cf6bbf5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Aug 2025 13:53:03 +0300 Subject: [PATCH 0834/1292] ASoC: SOF: ipc4-pcm: Add fixup for channels We can have modules in path which can change the number of channels and in this case the BE params needs to be adjusted to configure the DAI according to the copier configuration. Signed-off-by: Peter Ujfalusi Reviewed-by: Seppo Ingalsuo Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Message-ID: <20250829105305.31818-2-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 374dc10d10fd52..cb9a06792a47cd 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -727,6 +727,58 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, return 0; } +static int sof_ipc4_pcm_dai_link_fixup_channels(struct snd_sof_dev *sdev, + struct snd_pcm_hw_params *params, + struct sof_ipc4_copier *ipc4_copier) +{ + struct sof_ipc4_pin_format *pin_fmts = ipc4_copier->available_fmt.input_pin_fmts; + struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + int num_input_formats = ipc4_copier->available_fmt.num_input_formats; + unsigned int fe_channels = params_channels(params); + bool fe_be_match = false; + bool single_be_channels = true; + unsigned int be_channels, val; + int i; + + if (WARN_ON_ONCE(!num_input_formats)) + return -EINVAL; + + /* + * Copier does not change channels, so we + * need to only consider the input pin information. + */ + be_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(pin_fmts[0].audio_fmt.fmt_cfg); + for (i = 0; i < num_input_formats; i++) { + val = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(pin_fmts[i].audio_fmt.fmt_cfg); + + if (val != be_channels) + single_be_channels = false; + + if (val == fe_channels) { + fe_be_match = true; + break; + } + } + + /* + * If channels is different than FE channels, topology must contain a + * module which can change the number of channels. But we do require + * topology to define a single channels in the DAI copier config in + * this case (FE channels may be variable). + */ + if (!fe_be_match) { + if (!single_be_channels) { + dev_err(sdev->dev, "Unable to select channels for DAI link\n"); + return -EINVAL; + } + + channels->min = be_channels; + channels->max = be_channels; + } + + return 0; +} + static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -790,6 +842,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, if (ret) return ret; + ret = sof_ipc4_pcm_dai_link_fixup_channels(sdev, params, ipc4_copier); + if (ret) + return ret; + if (single_bitdepth) { snd_mask_none(fmt); valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(ipc4_fmt->fmt_cfg); From c04c2e829649ab8fe5f1cfe5d7cbb34ab0463231 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 29 Aug 2025 13:53:04 +0300 Subject: [PATCH 0835/1292] ASoC: SOF: ipc4-topology: Add support for 8-bit formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch enables use of 8-bit unsigned, A-law, and mu-law sample formats with IPC4 SOF. The ipc4-topology.h is updated with IPC4 sample types. The purpose is to convert ALSA types to IPC4 types. The functions of_ipc4_update_hw_params(), sof_ipc4_get_valid_bits(), and new function sof_ipc4_get_sample_type() are updated to handle the sample type conversions. The function sof_ipc4_prepare_copier_module() is updated to set the DMA SCS bit for all non 32 bits sample types. The change to function sof_ipc4_get_valid_bits() returns 8 bits for these ALSA formats. The change to function sof_ipc4_prepare_copier_module() is needed to handle properly all non 32-bit formats with SCS bit set. To support playback with new 8 bits types, the sof_ipc4_init_input_audio_fmt() function is updated to get the sample type and use it in search for copier input pin format. To support capture, the sof_ipc4_init_output_audio_fmt() is updated similarly. Since the function uses separate out_ref_type argument, instead of single parameters struct, the out_ref_type needs to be added to every user of the function. Therefore functions sof_ipc4_prepare_copier_module(), sof_ipc4_prepare_gain_module(), sof_ipc4_prepare_mixer_module(), sof_ipc4_prepare_src_module(), and sof_ipc4_prepare_process_module() are updated to set the out_ref_type. Signed-off-by: Seppo Ingalsuo Reviewed-by: PĆ©ter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Message-ID: <20250829105305.31818-3-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 126 +++++++++++++++++++++++++++++----- sound/soc/sof/ipc4-topology.h | 9 +++ 2 files changed, 116 insertions(+), 19 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 591ee30551baa8..47cc76328c23ba 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1292,6 +1292,23 @@ static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, return 0; } +static u32 sof_ipc4_fmt_cfg_to_type(u32 fmt_cfg) +{ + /* Fetch the sample type from the fmt for 8 and 32 bit formats */ + u32 __bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt_cfg); + + if (__bits == 8 || __bits == 32) + return SOF_IPC4_AUDIO_FORMAT_CFG_SAMPLE_TYPE(fmt_cfg); + + /* + * Return LSB integer type for 20 and 24 formats as the firmware is + * handling the LSB/MSB alignment internally, for the kernel this + * should not be taken into account, we treat them as LSB to match with + * the format we support on the PCM side. + */ + return SOF_IPC4_TYPE_LSB_INTEGER; +} + /* update hw_params based on the audio stream format */ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params, struct sof_ipc4_audio_format *fmt, u32 param_to_update) @@ -1300,10 +1317,27 @@ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) { int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + int type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg); snd_pcm_format_t snd_fmt; struct snd_mask *m; switch (valid_bits) { + case 8: + switch (type) { + case SOF_IPC4_TYPE_A_LAW: + snd_fmt = SNDRV_PCM_FORMAT_A_LAW; + break; + case SOF_IPC4_TYPE_MU_LAW: + snd_fmt = SNDRV_PCM_FORMAT_MU_LAW; + break; + case SOF_IPC4_TYPE_UNSIGNED_INTEGER: + snd_fmt = SNDRV_PCM_FORMAT_U8; + break; + default: + dev_err(sdev->dev, "Unsupported PCM 8-bit IPC4 type %d\n", type); + return -EINVAL; + } + break; case 16: snd_fmt = SNDRV_PCM_FORMAT_S16_LE; break; @@ -1375,7 +1409,7 @@ static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, struct sof_ipc4_base_module_cfg *base_config, struct sof_ipc4_available_audio_format *available_fmt, u32 out_ref_rate, u32 out_ref_channels, - u32 out_ref_valid_bits) + u32 out_ref_valid_bits, u32 out_ref_type) { struct sof_ipc4_pin_format *pin_fmts = available_fmt->output_pin_fmts; u32 pin_fmts_size = available_fmt->num_output_formats; @@ -1401,19 +1435,22 @@ static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, for (i = 0; i < pin_fmts_size; i++) { struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt; - u32 _out_rate, _out_channels, _out_valid_bits; + u32 _out_rate, _out_channels, _out_valid_bits, _out_type; _out_rate = fmt->sampling_frequency; _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + _out_type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg); if (_out_rate == out_ref_rate && _out_channels == out_ref_channels && - _out_valid_bits == out_ref_valid_bits) + _out_valid_bits == out_ref_valid_bits && _out_type == out_ref_type) goto out_fmt; } - dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", - __func__, out_ref_rate, out_ref_valid_bits, out_ref_channels); + dev_err(sdev->dev, + "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n", + __func__, out_ref_rate, out_ref_valid_bits, out_ref_channels, + out_ref_type); return -EINVAL; @@ -1426,6 +1463,10 @@ static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) { switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + return 8; case SNDRV_PCM_FORMAT_S16_LE: return 16; case SNDRV_PCM_FORMAT_S24_LE: @@ -1438,6 +1479,26 @@ static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_p } } +static int sof_ipc4_get_sample_type(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) +{ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_A_LAW: + return SOF_IPC4_TYPE_A_LAW; + case SNDRV_PCM_FORMAT_MU_LAW: + return SOF_IPC4_TYPE_MU_LAW; + case SNDRV_PCM_FORMAT_U8: + return SOF_IPC4_TYPE_UNSIGNED_INTEGER; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + return SOF_IPC4_TYPE_LSB_INTEGER; + default: + dev_err(sdev->dev, "invalid pcm sample type %d\n", params_format(params)); + return -EINVAL; + } +} + static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, struct sof_ipc4_base_module_cfg *base_config, @@ -1449,8 +1510,10 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, u32 valid_bits; u32 channels; u32 rate; + u32 type; bool single_format; int sample_valid_bits; + int sample_type; int i = 0; if (!pin_fmts_size) { @@ -1466,6 +1529,10 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, if (sample_valid_bits < 0) return sample_valid_bits; + sample_type = sof_ipc4_get_sample_type(sdev, params); + if (sample_type < 0) + return sample_type; + /* * Search supported input audio formats with pin index 0 to match rate, channels and * sample_valid_bits from reference params @@ -1479,14 +1546,17 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, rate = fmt->sampling_frequency; channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg); if (params_rate(params) == rate && params_channels(params) == channels && - sample_valid_bits == valid_bits) + sample_valid_bits == valid_bits && sample_type == type) break; } if (i == pin_fmts_size) { - dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", - __func__, params_rate(params), sample_valid_bits, params_channels(params)); + dev_err(sdev->dev, + "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n", + __func__, params_rate(params), sample_valid_bits, + params_channels(params), sample_type); return -EINVAL; } @@ -1882,7 +1952,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, int *ipc_config_size; u32 **data; int ipc_size, ret, out_ref_valid_bits; - u32 out_ref_rate, out_ref_channels; + u32 out_ref_rate, out_ref_channels, out_ref_type; u32 deep_buffer_dma_ms = 0; bool single_output_bitdepth; int i; @@ -1923,10 +1993,13 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, host_dma_id = platform_params->stream_tag - 1; pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id); - /* Set SCS bit for S16_LE format only */ if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE) pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK; + /* Set SCS bit for 8 and 16 bit formats */ + if (params_physical_width(fe_params) <= 16) + pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK; + /* * Despite its name the bitfield 'fifo_size' is used to define DMA buffer * size. The expression calculates 2ms buffer size. @@ -2051,6 +2124,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); if (!single_output_bitdepth) out_ref_valid_bits = @@ -2061,6 +2135,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, case snd_soc_dapm_dai_in: out_ref_rate = params_rate(fe_params); out_ref_channels = params_channels(fe_params); + out_ref_type = sof_ipc4_get_sample_type(sdev, fe_params); + if (out_ref_type < 0) + return out_ref_type; + if (!single_output_bitdepth) { out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); if (out_ref_valid_bits < 0) @@ -2085,12 +2163,14 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt; out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + out_ref_type = sof_ipc4_fmt_cfg_to_type(out_fmt->fmt_cfg); } output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, &copier_data->base_config, available_fmt, out_ref_rate, - out_ref_channels, out_ref_valid_bits); + out_ref_channels, out_ref_valid_bits, + out_ref_type); if (output_fmt_index < 0) return output_fmt_index; @@ -2319,7 +2399,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct sof_ipc4_gain *gain = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; struct sof_ipc4_audio_format *in_fmt; - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; + u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; int input_fmt_index, output_fmt_index; input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, @@ -2333,13 +2413,15 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, &gain->data.base_config, available_fmt, out_ref_rate, out_ref_channels, - out_ref_valid_bits); + out_ref_valid_bits, + out_ref_type); if (output_fmt_index < 0) return output_fmt_index; @@ -2362,7 +2444,7 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, struct sof_ipc4_mixer *mixer = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; struct sof_ipc4_audio_format *in_fmt; - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; + u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; int input_fmt_index, output_fmt_index; input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, @@ -2376,13 +2458,15 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, &mixer->base_config, available_fmt, out_ref_rate, out_ref_channels, - out_ref_valid_bits); + out_ref_valid_bits, + out_ref_type); if (output_fmt_index < 0) return output_fmt_index; @@ -2406,7 +2490,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *in_audio_fmt; - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; + u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; int output_fmt_index, input_fmt_index; input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, @@ -2433,6 +2517,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, in_audio_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg); + out_ref_type = sof_ipc4_fmt_cfg_to_type(in_audio_fmt->fmt_cfg); /* * For capture, the SRC module should convert the rate to match the rate requested by the @@ -2446,7 +2531,8 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, available_fmt, out_ref_rate, out_ref_channels, - out_ref_valid_bits); + out_ref_valid_bits, + out_ref_type); if (output_fmt_index < 0) return output_fmt_index; @@ -2570,20 +2656,22 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, struct sof_ipc4_audio_format *in_fmt; struct sof_ipc4_pin_format *pin_fmt; u32 out_ref_rate, out_ref_channels; - int out_ref_valid_bits; + int out_ref_valid_bits, out_ref_type; in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, &process->base_config, available_fmt, out_ref_rate, out_ref_channels, - out_ref_valid_bits); + out_ref_valid_bits, + out_ref_type); if (output_fmt_index < 0) return output_fmt_index; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 14ba58d2be03f8..537b97d227662c 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -41,6 +41,15 @@ #define SOF_IPC4_FW_MAX_PAGE_COUNT 20 #define SOF_IPC4_FW_MAX_QUEUE_COUNT 8 +/* IPC4 sample types */ +#define SOF_IPC4_TYPE_MSB_INTEGER 0 +#define SOF_IPC4_TYPE_LSB_INTEGER 1 +#define SOF_IPC4_TYPE_SIGNED_INTEGER 2 +#define SOF_IPC4_TYPE_UNSIGNED_INTEGER 3 +#define SOF_IPC4_TYPE_FLOAT 4 +#define SOF_IPC4_TYPE_A_LAW 5 +#define SOF_IPC4_TYPE_MU_LAW 6 + /* Node index and mask applicable for host copier and ALH/HDA type DAI copiers */ #define SOF_IPC4_NODE_INDEX_MASK 0xFF #define SOF_IPC4_NODE_INDEX(x) ((x) & SOF_IPC4_NODE_INDEX_MASK) From f7c41911ad744177d8289820f01009dc93d8f91c Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 29 Aug 2025 13:53:05 +0300 Subject: [PATCH 0836/1292] ASoC: SOF: ipc4-topology: Add support for float sample type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for FLOAT_LE ALSA type for playback and capture for IPC4 systems. Functions sof_ipc4_update_hw_params(), sof_ipc4_get_valid_bits() and sof_ipc4_get_sample_type() are updated to handle SOF_IPC4_TYPE_FLOAT and SNDRV_PCM_FORMAT_FLOAT_LE. Signed-off-by: Seppo Ingalsuo Reviewed-by: PĆ©ter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Message-ID: <20250829105305.31818-4-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 47cc76328c23ba..d934165fda114b 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1345,7 +1345,17 @@ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw snd_fmt = SNDRV_PCM_FORMAT_S24_LE; break; case 32: - snd_fmt = SNDRV_PCM_FORMAT_S32_LE; + switch (type) { + case SOF_IPC4_TYPE_LSB_INTEGER: + snd_fmt = SNDRV_PCM_FORMAT_S32_LE; + break; + case SOF_IPC4_TYPE_FLOAT: + snd_fmt = SNDRV_PCM_FORMAT_FLOAT_LE; + break; + default: + dev_err(sdev->dev, "Unsupported PCM 32-bit IPC4 type %d\n", type); + return -EINVAL; + } break; default: dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits); @@ -1473,6 +1483,8 @@ static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_p return 24; case SNDRV_PCM_FORMAT_S32_LE: return 32; + case SNDRV_PCM_FORMAT_FLOAT_LE: + return 32; default: dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); return -EINVAL; @@ -1493,6 +1505,8 @@ static int sof_ipc4_get_sample_type(struct snd_sof_dev *sdev, struct snd_pcm_hw_ case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: return SOF_IPC4_TYPE_LSB_INTEGER; + case SNDRV_PCM_FORMAT_FLOAT_LE: + return SOF_IPC4_TYPE_FLOAT; default: dev_err(sdev->dev, "invalid pcm sample type %d\n", params_format(params)); return -EINVAL; From 4f17845526626deda2cab181db7e19cf9265a0b3 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 29 Aug 2025 12:30:18 +0300 Subject: [PATCH 0837/1292] ASoC: SOF: sof-client-probes-ipc4: Implement ipc4_probes_points_info Upgrade the struct sof_probes_ipc_ops points_info() method from dummy implementation to a working implementation. The actual functionality requires that the DSP FW supports the IPC request. The support was just recently added. If its not there an IPC failure is reported in the logs. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Message-ID: <20250829093022.32094-2-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes-ipc4.c | 53 +++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index 603aed222480ff..b719ffa8051b03 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -8,7 +8,6 @@ #include #include #include -#include "sof-priv.h" #include "ipc4-priv.h" #include "sof-client.h" #include "sof-client-probes.h" @@ -55,6 +54,11 @@ struct sof_ipc4_probe_point { u32 stream_tag; } __packed __aligned(4); +struct sof_ipc4_probe_info { + unsigned int num_elems; + DECLARE_FLEX_ARRAY(struct sof_ipc4_probe_point, points); +} __packed; + #define INVALID_PIPELINE_ID 0xFF /** @@ -169,16 +173,53 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev) * @desc: Returned list of active probes * @num_desc: Returned count of active probes * @return: 0 on success, negative error code on error - * - * Dummy implementation returning empty list of probes. */ static int ipc4_probes_points_info(struct sof_client_dev *cdev, struct sof_probe_point_desc **desc, size_t *num_desc) { - /* TODO: Firmware side implementation needed first */ - *desc = NULL; - *num_desc = 0; + struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev); + struct device *dev = &cdev->auxdev.dev; + struct sof_ipc4_probe_info *info; + struct sof_ipc4_msg msg; + int i, ret; + + if (!mentry) + return -ENODEV; + + msg.primary = mentry->id; + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS); + + msg.data_size = sof_client_get_ipc_max_payload_size(cdev); + msg.data_ptr = kzalloc(msg.data_size, GFP_KERNEL); + if (!msg.data_ptr) + return -ENOMEM; + + ret = sof_client_ipc_set_get_data(cdev, &msg, false); + if (ret) { + kfree(msg.data_ptr); + return ret; + } + info = msg.data_ptr; + *num_desc = info->num_elems; + dev_dbg(dev, "%s: got %zu probe points", __func__, *num_desc); + + *desc = kzalloc(*num_desc * sizeof(**desc), GFP_KERNEL); + if (!*desc) { + kfree(msg.data_ptr); + return -ENOMEM; + } + + for (i = 0; i < *num_desc; i++) { + (*desc)[i].buffer_id = info->points[i].point_id; + (*desc)[i].purpose = info->points[i].purpose; + (*desc)[i].stream_tag = info->points[i].stream_tag; + } + kfree(msg.data_ptr); + return 0; } From 782d4613171e271b1e28ee1db9616beb8e6ad8a1 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 29 Aug 2025 12:30:19 +0300 Subject: [PATCH 0838/1292] ASoC: SOF: IPC4: Add GET macros for module id and module instance id Add SOF_IPC4_MOD_INSTANCE_GET() and SOF_IPC4_MOD_ID_GET() for getting the ids from ipc4 header presentation. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Message-ID: <20250829093022.32094-3-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index e85c7afd85a4d3..15fac532688e28 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -326,10 +326,14 @@ struct sof_ipc4_base_module_cfg { #define SOF_IPC4_MOD_INSTANCE_SHIFT 16 #define SOF_IPC4_MOD_INSTANCE_MASK GENMASK(23, 16) #define SOF_IPC4_MOD_INSTANCE(x) ((x) << SOF_IPC4_MOD_INSTANCE_SHIFT) +#define SOF_IPC4_MOD_INSTANCE_GET(x) (((x) & SOF_IPC4_MOD_INSTANCE_MASK) \ + >> SOF_IPC4_MOD_INSTANCE_SHIFT) #define SOF_IPC4_MOD_ID_SHIFT 0 #define SOF_IPC4_MOD_ID_MASK GENMASK(15, 0) #define SOF_IPC4_MOD_ID(x) ((x) << SOF_IPC4_MOD_ID_SHIFT) +#define SOF_IPC4_MOD_ID_GET(x) (((x) & SOF_IPC4_MOD_ID_MASK) \ + >> SOF_IPC4_MOD_ID_SHIFT) /* init module ipc msg */ #define SOF_IPC4_MOD_EXT_PARAM_SIZE_SHIFT 0 From e6cf5e44ce1eed7aa72e7fb0cbff054e3f1dec0d Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 29 Aug 2025 12:30:20 +0300 Subject: [PATCH 0839/1292] ASoC: SOF: sof-client: Add sof_client_ipc4_find_swidget_by_id() Add sof_client_ipc4_find_swidget_by_id() for finding widgets from SOF client devices. The motivation is to decode probes debugfs output to be more readable. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Message-ID: <20250829093022.32094-4-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/sof-client.c | 13 +++++++++++++ sound/soc/sof/sof-client.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 4c7951338c66f6..4d0acb8f85cde6 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -353,6 +353,19 @@ struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, return NULL; } EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT"); + +struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev, + u32 module_id, int instance_id) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) + return sof_ipc4_find_swidget_by_ids(sdev, module_id, instance_id); + dev_err(sdev->dev, "Only supported with IPC4\n"); + + return NULL; +} +EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_swidget_by_id, "SND_SOC_SOF_CLIENT"); #endif int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h index b6ccc2cd69e52c..c3741b92a26f0c 100644 --- a/sound/soc/sof/sof-client.h +++ b/sound/soc/sof/sof-client.h @@ -47,6 +47,8 @@ int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg, bool set); struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *u); +struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev, + u32 module_id, int instance_id); struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev); struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev); From b6082647f7222c05d34db94455a4e81981c51da1 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 29 Aug 2025 12:30:21 +0300 Subject: [PATCH 0840/1292] ASoC: SOF: sof-client-probes-ipc4: Human readable debugfs "probe_points" The current output of three integers is not very human readable. Use ipc4 functions to describe in more detail what the struct sof_probe_point_desc buffer_id is actually referring to in an ipc4 SOF system. Before this commit the "probe_points" debugfs file could read as: Id: 0x01000004 Purpose: 0 Node id: 0x100 Id: 0x00000006 Purpose: 0 Node id: 0x100 And after in the same situation in an ipc4 system it reads: 0x7,0x0,0x100 gain.1.1 input buf idx 0 (connected) 0x1000005,0x0,0x100 host-copier.0.playback output buf idx 0 (connected) The triplet in the beginning of the line can be used to reinserted the probe point again by writing it into "probe_points" debugfs file, if its first removed by writing the fist number in "probe_points_remove". The last number is ignored when creating a probe point. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Message-ID: <20250829093022.32094-5-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes-ipc4.c | 57 ++++++++++++++++++++++++++ sound/soc/sof/sof-client-probes.c | 16 ++++++-- sound/soc/sof/sof-client-probes.h | 2 + 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index b719ffa8051b03..0b974e6268bb77 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -8,6 +8,7 @@ #include #include #include +#include "sof-audio.h" #include "ipc4-priv.h" #include "sof-client.h" #include "sof-client-probes.h" @@ -48,6 +49,15 @@ enum sof_ipc4_probe_type { SOF_IPC4_PROBE_TYPE_INTERNAL }; +#define SOF_IPC4_PROBE_TYPE_SHIFT 24 +#define SOF_IPC4_PROBE_TYPE_MASK GENMASK(25, 24) +#define SOF_IPC4_PROBE_TYPE_GET(x) (((x) & SOF_IPC4_PROBE_TYPE_MASK) \ + >> SOF_IPC4_PROBE_TYPE_SHIFT) +#define SOF_IPC4_PROBE_IDX_SHIFT 26 +#define SOF_IPC4_PROBE_IDX_MASK GENMASK(31, 26) +#define SOF_IPC4_PROBE_IDX_GET(x) (((x) & SOF_IPC4_PROBE_IDX_MASK) \ + >> SOF_IPC4_PROBE_IDX_SHIFT) + struct sof_ipc4_probe_point { u32 point_id; u32 purpose; @@ -61,6 +71,20 @@ struct sof_ipc4_probe_info { #define INVALID_PIPELINE_ID 0xFF +static const char *sof_probe_ipc4_type_string(u32 type) +{ + switch (type) { + case SOF_IPC4_PROBE_TYPE_INPUT: + return "input"; + case SOF_IPC4_PROBE_TYPE_OUTPUT: + return "output"; + case SOF_IPC4_PROBE_TYPE_INTERNAL: + return "internal"; + default: + return "UNKNOWN"; + } +} + /** * sof_ipc4_probe_get_module_info - Get IPC4 module info for probe module * @cdev: SOF client device @@ -223,6 +247,38 @@ static int ipc4_probes_points_info(struct sof_client_dev *cdev, return 0; } +/** + * ipc4_probes_point_print - Human readable print of probe point descriptor + * @cdev: SOF client device + * @buf: Buffer to print to + * @size: Available bytes in buffer + * @desc: Describes the probe point to print + * @return: Number of bytes printed or an error code (snprintf return value) + */ +static int ipc4_probes_point_print(struct sof_client_dev *cdev, char *buf, size_t size, + struct sof_probe_point_desc *desc) +{ + struct device *dev = &cdev->auxdev.dev; + struct snd_sof_widget *swidget; + int ret; + + swidget = sof_client_ipc4_find_swidget_by_id(cdev, SOF_IPC4_MOD_ID_GET(desc->buffer_id), + SOF_IPC4_MOD_INSTANCE_GET(desc->buffer_id)); + if (!swidget) + dev_err(dev, "%s: Failed to find widget for module %lu.%lu\n", + __func__, SOF_IPC4_MOD_ID_GET(desc->buffer_id), + SOF_IPC4_MOD_INSTANCE_GET(desc->buffer_id)); + + ret = snprintf(buf, size, "%#x,%#x,%#x\t%s %s buf idx %lu %s\n", + desc->buffer_id, desc->purpose, desc->stream_tag, + swidget ? swidget->widget->name : "", + sof_probe_ipc4_type_string(SOF_IPC4_PROBE_TYPE_GET(desc->buffer_id)), + SOF_IPC4_PROBE_IDX_GET(desc->buffer_id), + desc->stream_tag ? "(connected)" : ""); + + return ret; +} + /** * ipc4_probes_points_add - connect specified probes * @cdev: SOF client device @@ -327,6 +383,7 @@ const struct sof_probes_ipc_ops ipc4_probe_ops = { .init = ipc4_probes_init, .deinit = ipc4_probes_deinit, .points_info = ipc4_probes_points_info, + .point_print = ipc4_probes_point_print, .points_add = ipc4_probes_points_add, .points_remove = ipc4_probes_points_remove, }; diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 663c0d3c314c66..242fa19a82ec64 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -17,8 +17,14 @@ #include #include +#include #include "sof-client.h" #include "sof-client-probes.h" +#include "sof-audio.h" + +#ifdef CONFIG_SND_SOC_SOF_IPC4 +#include "ipc4-priv.h" +#endif #define SOF_PROBES_SUSPEND_DELAY_MS 3000 /* only extraction supported for now */ @@ -223,9 +229,13 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, for (i = 0; i < num_desc; i++) { offset = strlen(buf); remaining = PAGE_SIZE - offset; - ret = snprintf(buf + offset, remaining, - "Id: %#010x Purpose: %u Node id: %#x\n", - desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag); + if (ipc->point_print) + ret = ipc->point_print(cdev, buf + offset, remaining, &desc[i]); + else + ret = snprintf(buf + offset, remaining, + "Id: %#010x Purpose: %u Node id: %#x\n", + desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag); + if (ret < 0 || ret >= remaining) { /* truncate the output buffer at the last full line */ buf[offset] = '\0'; diff --git a/sound/soc/sof/sof-client-probes.h b/sound/soc/sof/sof-client-probes.h index da04d65b8d995e..c445e435aa35bd 100644 --- a/sound/soc/sof/sof-client-probes.h +++ b/sound/soc/sof/sof-client-probes.h @@ -41,6 +41,8 @@ struct sof_probes_ipc_ops { int (*points_info)(struct sof_client_dev *cdev, struct sof_probe_point_desc **desc, size_t *num_desc); + int (*point_print)(struct sof_client_dev *cdev, char *buf, size_t size, + struct sof_probe_point_desc *desc); int (*points_add)(struct sof_client_dev *cdev, struct sof_probe_point_desc *desc, size_t num_desc); From d57d27171c92e9049d5301785fb38de127b28fbf Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 29 Aug 2025 12:30:22 +0300 Subject: [PATCH 0841/1292] ASoC: SOF: sof-client-probes: Add available points_info(), IPC4 only Add another debugfs file, "probe_points_available", that shows all the available probe points in the SOF FW at the time of query. The probe points are there only when an active SOF stream exists in the system. However, the stream identifiers are persistent in the sense that the same probe point identifiers always appear with the same playback or capture command in the same system configuration. The output, when reading "probe_points_available", may look like this: 0x1000005,0x0,0x100 host-copier.0.playback output buf idx 0 (connected) 0x7,0x0,0x100 gain.1.1 input buf idx 0 (connected) 0x1000007,0x0,0x0 gain.1.1 output buf idx 0 0x3,0x0,0x0 mixin.1.1 input buf idx 0 0x1000003,0x0,0x0 mixin.1.1 output buf idx 0 0x4,0x0,0x0 mixout.2.1 input buf idx 0 0x1000004,0x0,0x0 mixout.2.1 output buf idx 0 0x10007,0x0,0x0 gain.2.1 input buf idx 0 0x1010007,0x0,0x0 gain.2.1 output buf idx 0 0x11,0x0,0x0 smart_amp.2.1 input buf idx 0 0x1000011,0x0,0x0 smart_amp.2.1 output buf idx 0 0x10005,0x0,0x0 dai-copier.SSP.NoCodec-0.playback input buf idx 0 The triplet at the beginning of a line can be copy-pasted as such to "probe_points" debugfs file for adding a probe point. The rest of the line tries to give human readable explanation of what this probe point is. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Message-ID: <20250829093022.32094-6-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes-ipc3.c | 25 ++++++++++----- sound/soc/sof/sof-client-probes-ipc4.c | 28 ++++++++++++++--- sound/soc/sof/sof-client-probes.c | 42 ++++++++++++++++++++++---- sound/soc/sof/sof-client-probes.h | 7 ++++- 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/sof-client-probes-ipc3.c b/sound/soc/sof/sof-client-probes-ipc3.c index 816df745c9afce..a78ec0954a6188 100644 --- a/sound/soc/sof/sof-client-probes-ipc3.c +++ b/sound/soc/sof/sof-client-probes-ipc3.c @@ -100,9 +100,11 @@ static int ipc3_probes_deinit(struct sof_client_dev *cdev) } static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd, - void **params, size_t *num_params) + void **params, size_t *num_params, + enum sof_probe_info_type type) { size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev); + struct device *dev = &cdev->auxdev.dev; struct sof_ipc_probe_info_params msg = {{{0}}}; struct sof_ipc_probe_info_params *reply; size_t bytes; @@ -111,6 +113,11 @@ static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd, *params = NULL; *num_params = 0; + if (type != PROBES_INFO_ACTIVE_PROBES) { + dev_err(dev, "%s: info type %u not supported", __func__, type); + return -EOPNOTSUPP; + } + reply = kzalloc(max_msg_size, GFP_KERNEL); if (!reply) return -ENOMEM; @@ -142,21 +149,25 @@ static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd, } /** - * ipc3_probes_points_info - retrieve list of active probe points + * ipc3_probes_points_info - retrieve list of probe points * @cdev: SOF client device * @desc: Returned list of active probes * @num_desc: Returned count of active probes + * @type: Either PROBES_INFO_ACTIVE_PROBES or PROBES_INFO_AVAILABE_PROBES + * + * If type is PROBES_INFO_ACTIVE_PROBES, host sends PROBE_POINT_INFO + * request to obtain list of active probe points, valid for + * disconnection when given probe is no longer required. * - * Host sends PROBE_POINT_INFO request to obtain list of active probe - * points, valid for disconnection when given probe is no longer - * required. + * Type PROBES_INFO_AVAILABE_PROBES is not yet supported. */ static int ipc3_probes_points_info(struct sof_client_dev *cdev, struct sof_probe_point_desc **desc, - size_t *num_desc) + size_t *num_desc, + enum sof_probe_info_type type) { return ipc3_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO, - (void **)desc, num_desc); + (void **)desc, num_desc, type); } /** diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index 0b974e6268bb77..758a56d271d77a 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -28,6 +28,7 @@ enum sof_ipc4_probe_runtime_param { SOF_IPC4_PROBE_INJECTION_DMA_DETACH, SOF_IPC4_PROBE_POINTS, SOF_IPC4_PROBE_POINTS_DISCONNECT, + SOF_IPC4_PROBE_POINTS_AVAILABLE, }; struct sof_ipc4_probe_gtw_cfg { @@ -192,30 +193,49 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev) } /** - * ipc4_probes_points_info - retrieve list of active probe points + * ipc4_probes_points_info - retrieve list of probe points * @cdev: SOF client device * @desc: Returned list of active probes * @num_desc: Returned count of active probes + * @type: Either PROBES_INFO_ACTIVE_PROBES or PROBES_INFO_AVAILABE_PROBES * @return: 0 on success, negative error code on error + * + * Returns list if active probe points if type is + * PROBES_INFO_ACTIVE_PROBES, or list of all available probe points if + * type is PROBES_INFO_AVAILABE_PROBES. */ static int ipc4_probes_points_info(struct sof_client_dev *cdev, struct sof_probe_point_desc **desc, - size_t *num_desc) + size_t *num_desc, + enum sof_probe_info_type type) { struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev); struct device *dev = &cdev->auxdev.dev; struct sof_ipc4_probe_info *info; struct sof_ipc4_msg msg; + u32 param_id; int i, ret; if (!mentry) return -ENODEV; + switch (type) { + case PROBES_INFO_ACTIVE_PROBES: + param_id = SOF_IPC4_PROBE_POINTS; + break; + case PROBES_INFO_AVAILABE_PROBES: + param_id = SOF_IPC4_PROBE_POINTS_AVAILABLE; + break; + default: + dev_err(dev, "%s: info type %u not supported", __func__, type); + return -EOPNOTSUPP; + } + msg.primary = mentry->id; msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); - msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS); + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(param_id); msg.data_size = sof_client_get_ipc_max_payload_size(cdev); msg.data_ptr = kzalloc(msg.data_size, GFP_KERNEL); @@ -299,7 +319,7 @@ static int ipc4_probes_points_add(struct sof_client_dev *cdev, int i, ret; if (!mentry) - return -ENODEV; + return -EOPNOTSUPP; /* The sof_probe_point_desc and sof_ipc4_probe_point structs * are of same size and even the integers are the same in the diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 242fa19a82ec64..3ca8460774bb4d 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -75,7 +75,8 @@ static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream, int i, ret; /* disconnect all probe points */ - ret = ipc->points_info(cdev, &desc, &num_desc); + ret = ipc->points_info(cdev, &desc, &num_desc, + PROBES_INFO_ACTIVE_PROBES); if (ret < 0) { dev_err(dai->dev, "Failed to get probe points: %d\n", ret); goto exit; @@ -195,7 +196,8 @@ static const struct snd_compress_ops sof_probes_compressed_ops = { }; static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos, + enum sof_probe_info_type type) { struct sof_client_dev *cdev = file->private_data; struct sof_probes_priv *priv = cdev->data; @@ -222,7 +224,7 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, goto exit; } - ret = ipc->points_info(cdev, &desc, &num_desc); + ret = ipc->points_info(cdev, &desc, &num_desc, type); if (ret < 0) goto pm_error; @@ -257,6 +259,22 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, return ret; } +static ssize_t sof_probes_dfs_active_points_read(struct file *file, + char __user *to, + size_t count, loff_t *ppos) +{ + return sof_probes_dfs_points_read(file, to, count, ppos, + PROBES_INFO_ACTIVE_PROBES); +} + +static ssize_t sof_probes_dfs_available_points_read(struct file *file, + char __user *to, + size_t count, loff_t *ppos) +{ + return sof_probes_dfs_points_read(file, to, count, ppos, + PROBES_INFO_AVAILABE_PROBES); +} + static ssize_t sof_probes_dfs_points_write(struct file *file, const char __user *from, size_t count, loff_t *ppos) @@ -306,15 +324,23 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from, return ret; } -static const struct file_operations sof_probes_points_fops = { +static const struct file_operations sof_probes_active_points_fops = { .open = simple_open, - .read = sof_probes_dfs_points_read, + .read = sof_probes_dfs_active_points_read, .write = sof_probes_dfs_points_write, .llseek = default_llseek, .owner = THIS_MODULE, }; +static const struct file_operations sof_probes_available_points_fops = { + .open = simple_open, + .read = sof_probes_dfs_available_points_read, + .llseek = default_llseek, + + .owner = THIS_MODULE, +}; + static ssize_t sof_probes_dfs_points_remove_write(struct file *file, const char __user *from, size_t count, loff_t *ppos) @@ -459,13 +485,17 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev, /* create read-write probes_points debugfs entry */ priv->dfs_points = debugfs_create_file("probe_points", 0644, dfsroot, - cdev, &sof_probes_points_fops); + cdev, &sof_probes_active_points_fops); /* create read-write probe_points_remove debugfs entry */ priv->dfs_points_remove = debugfs_create_file("probe_points_remove", 0644, dfsroot, cdev, &sof_probes_points_remove_fops); + /* create read-write probes_points debugfs entry */ + priv->dfs_points = debugfs_create_file("probe_points_available", 0644, dfsroot, + cdev, &sof_probes_available_points_fops); + links = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*links), GFP_KERNEL); cpus = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*cpus), GFP_KERNEL); if (!links || !cpus) { diff --git a/sound/soc/sof/sof-client-probes.h b/sound/soc/sof/sof-client-probes.h index c445e435aa35bd..5fb95553ea53a1 100644 --- a/sound/soc/sof/sof-client-probes.h +++ b/sound/soc/sof/sof-client-probes.h @@ -34,13 +34,18 @@ struct sof_probe_point_desc { unsigned int stream_tag; } __packed; +enum sof_probe_info_type { + PROBES_INFO_ACTIVE_PROBES, + PROBES_INFO_AVAILABE_PROBES, +}; + struct sof_probes_ipc_ops { int (*init)(struct sof_client_dev *cdev, u32 stream_tag, size_t buffer_size); int (*deinit)(struct sof_client_dev *cdev); int (*points_info)(struct sof_client_dev *cdev, struct sof_probe_point_desc **desc, - size_t *num_desc); + size_t *num_desc, enum sof_probe_info_type type); int (*point_print)(struct sof_client_dev *cdev, char *buf, size_t size, struct sof_probe_point_desc *desc); int (*points_add)(struct sof_client_dev *cdev, From 850c5dfb17b381f30c4052a68c43da5abc678e74 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Aug 2025 13:25:09 +0300 Subject: [PATCH 0842/1292] ASoC: SOF: sof-client: Convert sof_client_dev_to_sof_dev into function Remove the sof_client_dev_to_sof_dev() from the header file and add it as a function in sof-client.c to avoid it's use by client drivers. At the same time mark the sdev and list of sof_client_dev as restricted fro core use only. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Message-ID: <20250829102510.15159-2-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/sof-client.c | 6 ++++++ sound/soc/sof/sof-client.h | 6 ++---- sound/soc/sof/sof-priv.h | 9 +++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 4c7951338c66f6..2db12753f79ee4 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -611,3 +611,9 @@ enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) return sdev->fw_state; } EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, "SND_SOC_SOF_CLIENT"); + +struct snd_sof_dev *sof_client_dev_to_sof_dev(struct sof_client_dev *cdev) +{ + return cdev->sdev; +} +EXPORT_SYMBOL_NS_GPL(sof_client_dev_to_sof_dev, "SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h index b6ccc2cd69e52c..8b267b0b9ff12f 100644 --- a/sound/soc/sof/sof-client.h +++ b/sound/soc/sof/sof-client.h @@ -18,8 +18,8 @@ struct sof_ipc4_fw_module; /** * struct sof_client_dev - SOF client device * @auxdev: auxiliary device - * @sdev: pointer to SOF core device struct - * @list: item in SOF core client dev list + * @sdev: pointer to SOF core device struct, resticted for core use only + * @list: item in SOF core client dev list, resticted for core use only * @data: device specific data */ struct sof_client_dev { @@ -29,8 +29,6 @@ struct sof_client_dev { void *data; }; -#define sof_client_dev_to_sof_dev(cdev) ((cdev)->sdev) - #define auxiliary_dev_to_sof_client_dev(auxiliary_dev) \ container_of(auxiliary_dev, struct sof_client_dev, auxdev) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index abbb5ee7e08c8c..0f624d8cde201b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -838,7 +838,11 @@ int sof_stream_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* SOF client support */ +struct sof_client_dev; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_CLIENT) +struct snd_sof_dev *sof_client_dev_to_sof_dev(struct sof_client_dev *cdev); + int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, const void *data, size_t size); void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id); @@ -849,6 +853,11 @@ void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev); int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state); int sof_resume_clients(struct snd_sof_dev *sdev); #else /* CONFIG_SND_SOC_SOF_CLIENT */ +static inline struct snd_sof_dev * +sof_client_dev_to_sof_dev(struct sof_client_dev *cdev) { + return NULL; +} + static inline int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, const void *data, size_t size) { From 07752abfa5dbf7cb4d9ce69fa94dc3b12bc597d9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Aug 2025 13:25:10 +0300 Subject: [PATCH 0843/1292] ASoC: SOF: sof-client: Introduce sof_client_dev_entry structure Introduce a new internal structure for wrapping the sof_client_dev and move members away from the client visible struct that they must not access, let alone see (sdev and the list). The changes are mechanical in nature and contained within sof-client core code, no functional change or change in behavior is introduced. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Message-ID: <20250829102510.15159-3-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- sound/soc/sof/sof-client.c | 101 +++++++++++++++++++++++++------------ sound/soc/sof/sof-client.h | 4 -- 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 2db12753f79ee4..12be97540e4c7d 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -45,13 +45,30 @@ struct sof_state_event_entry { struct list_head list; }; +/** + * struct sof_client_dev_entry - client device entry for internal management use + * @sdev: pointer to SOF core device struct + * @list: item in SOF core client dev list + * @client_dev: SOF client device + */ +struct sof_client_dev_entry { + struct snd_sof_dev *sdev; + struct list_head list; + + struct sof_client_dev client_dev; +}; + +#define cdev_to_centry(cdev) \ + container_of(cdev, struct sof_client_dev_entry, client_dev) + static void sof_client_auxdev_release(struct device *dev) { struct auxiliary_device *auxdev = to_auxiliary_dev(dev); struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev); + struct sof_client_dev_entry *centry = cdev_to_centry(cdev); kfree(cdev->auxdev.dev.platform_data); - kfree(cdev); + kfree(centry); } static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data, @@ -208,15 +225,18 @@ void sof_unregister_clients(struct snd_sof_dev *sdev) int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, const void *data, size_t size) { + struct sof_client_dev_entry *centry; struct auxiliary_device *auxdev; struct sof_client_dev *cdev; int ret; - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (!cdev) + centry = kzalloc(sizeof(*centry), GFP_KERNEL); + if (!centry) return -ENOMEM; - cdev->sdev = sdev; + cdev = ¢ry->client_dev; + + centry->sdev = sdev; auxdev = &cdev->auxdev; auxdev->name = name; auxdev->dev.parent = sdev->dev; @@ -246,7 +266,7 @@ int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, /* add to list of SOF client devices */ mutex_lock(&sdev->ipc_client_mutex); - list_add(&cdev->list, &sdev->ipc_client_list); + list_add(¢ry->list, &sdev->ipc_client_list); mutex_unlock(&sdev->ipc_client_mutex); return 0; @@ -255,7 +275,7 @@ int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, kfree(cdev->auxdev.dev.platform_data); err_dev_add_data: - kfree(cdev); + kfree(centry); return ret; } @@ -263,7 +283,7 @@ EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, "SND_SOC_SOF_CLIENT"); void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id) { - struct sof_client_dev *cdev; + struct sof_client_dev_entry *centry; mutex_lock(&sdev->ipc_client_mutex); @@ -271,9 +291,11 @@ void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 i * sof_client_auxdev_release() will be invoked to free up memory * allocations through put_device() */ - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { + list_for_each_entry(centry, &sdev->ipc_client_list, list) { + struct sof_client_dev *cdev = ¢ry->client_dev; + if (!strcmp(cdev->auxdev.name, name) && cdev->auxdev.id == id) { - list_del(&cdev->list); + list_del(¢ry->list); auxiliary_device_delete(&cdev->auxdev); auxiliary_device_uninit(&cdev->auxdev); break; @@ -287,15 +309,17 @@ EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, void *reply_data, size_t reply_bytes) { - if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { struct sof_ipc_cmd_hdr *hdr = ipc_msg; - return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, hdr->size, + return sof_ipc_tx_message(sdev->ipc, ipc_msg, hdr->size, reply_data, reply_bytes); - } else if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { + } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_msg *msg = ipc_msg; - return sof_ipc_tx_message(cdev->sdev->ipc, ipc_msg, msg->data_size, + return sof_ipc_tx_message(sdev->ipc, ipc_msg, msg->data_size, reply_data, reply_bytes); } @@ -305,16 +329,18 @@ EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_rx_message(struct sof_client_dev *cdev, void *ipc_msg, void *msg_buf) { + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + if (IS_ENABLED(CONFIG_SND_SOC_SOF_IPC3) && - cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { + sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { struct sof_ipc_cmd_hdr *hdr = ipc_msg; if (hdr->size < sizeof(hdr)) { - dev_err(cdev->sdev->dev, "The received message size is invalid\n"); + dev_err(sdev->dev, "The received message size is invalid\n"); return -EINVAL; } - sof_ipc3_do_rx_work(cdev->sdev, ipc_msg, msg_buf); + sof_ipc3_do_rx_work(sdev, ipc_msg, msg_buf); return 0; } @@ -325,16 +351,17 @@ EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg, bool set) { - if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { struct sof_ipc_cmd_hdr *hdr = ipc_msg; - return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, hdr->size, - set); - } else if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { + return sof_ipc_set_get_data(sdev->ipc, ipc_msg, hdr->size, set); + } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { struct sof_ipc4_msg *msg = ipc_msg; - return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, - msg->data_size, set); + return sof_ipc_set_get_data(sdev->ipc, ipc_msg, msg->data_size, + set); } return -EINVAL; @@ -344,7 +371,7 @@ EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, "SND_SOC_SOF_CLIENT"); #ifdef CONFIG_SND_SOC_SOF_IPC4 struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *uuid) { - struct snd_sof_dev *sdev = c->sdev; + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(c); if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) return sof_ipc4_find_module_by_uuid(sdev, uuid); @@ -358,11 +385,13 @@ EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT"); int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) { const struct auxiliary_driver *adrv; - struct sof_client_dev *cdev; + struct sof_client_dev_entry *centry; mutex_lock(&sdev->ipc_client_mutex); - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { + list_for_each_entry(centry, &sdev->ipc_client_list, list) { + struct sof_client_dev *cdev = ¢ry->client_dev; + /* Skip devices without loaded driver */ if (!cdev->auxdev.dev.driver) continue; @@ -381,11 +410,13 @@ EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, "SND_SOC_SOF_CLIENT"); int sof_resume_clients(struct snd_sof_dev *sdev) { const struct auxiliary_driver *adrv; - struct sof_client_dev *cdev; + struct sof_client_dev_entry *centry; mutex_lock(&sdev->ipc_client_mutex); - list_for_each_entry(cdev, &sdev->ipc_client_list, list) { + list_for_each_entry(centry, &sdev->ipc_client_list, list) { + struct sof_client_dev *cdev = ¢ry->client_dev; + /* Skip devices without loaded driver */ if (!cdev->auxdev.dev.driver) continue; @@ -403,14 +434,18 @@ EXPORT_SYMBOL_NS_GPL(sof_resume_clients, "SND_SOC_SOF_CLIENT"); struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) { - return cdev->sdev->debugfs_root; + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->debugfs_root; } EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, "SND_SOC_SOF_CLIENT"); /* DMA buffer allocation in client drivers must use the core SOF device */ struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) { - return cdev->sdev->dev; + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + + return sdev->dev; } EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, "SND_SOC_SOF_CLIENT"); @@ -498,10 +533,10 @@ int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, if (!callback) return -EINVAL; - if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) { if (!(ipc_msg_type & SOF_GLB_TYPE_MASK)) return -EINVAL; - } else if (cdev->sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { + } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { if (!(ipc_msg_type & SOF_IPC4_NOTIFICATION_TYPE_MASK)) return -EINVAL; } else { @@ -614,6 +649,8 @@ EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, "SND_SOC_SOF_CLIENT"); struct snd_sof_dev *sof_client_dev_to_sof_dev(struct sof_client_dev *cdev) { - return cdev->sdev; + struct sof_client_dev_entry *centry = cdev_to_centry(cdev); + + return centry->sdev; } EXPORT_SYMBOL_NS_GPL(sof_client_dev_to_sof_dev, "SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h index 8b267b0b9ff12f..6e9dd77f7c9b0e 100644 --- a/sound/soc/sof/sof-client.h +++ b/sound/soc/sof/sof-client.h @@ -18,14 +18,10 @@ struct sof_ipc4_fw_module; /** * struct sof_client_dev - SOF client device * @auxdev: auxiliary device - * @sdev: pointer to SOF core device struct, resticted for core use only - * @list: item in SOF core client dev list, resticted for core use only * @data: device specific data */ struct sof_client_dev { struct auxiliary_device auxdev; - struct snd_sof_dev *sdev; - struct list_head list; void *data; }; From 89e7353f522f5cf70cb48c01ce2dcdcb275b8022 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Mon, 25 Aug 2025 12:53:28 +0100 Subject: [PATCH 0844/1292] spi: microchip-core-qspi: stop checking viability of op->max_freq in supports_op callback In commit 13529647743d9 ("spi: microchip-core-qspi: Support per spi-mem operation frequency switches") the logic for checking the viability of op->max_freq in mchp_coreqspi_setup_clock() was copied into mchp_coreqspi_supports_op(). Unfortunately, op->max_freq is not valid when this function is called during probe but is instead zero. Accordingly, baud_rate_val is calculated to be INT_MAX due to division by zero, causing probe of the attached memory device to fail. Seemingly spi-microchip-core-qspi was the only driver that had such a modification made to its supports_op callback when the per_op_freq capability was added, so just remove it to restore prior functionality. CC: stable@vger.kernel.org Reported-by: Valentina Fernandez Fixes: 13529647743d9 ("spi: microchip-core-qspi: Support per spi-mem operation frequency switches") Signed-off-by: Conor Dooley Message-ID: <20250825-during-ploy-939bdd068593@spud> Signed-off-by: Mark Brown --- drivers/spi/spi-microchip-core-qspi.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c index d13a9b755c7f8a..8dc98b17f77b58 100644 --- a/drivers/spi/spi-microchip-core-qspi.c +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -531,10 +531,6 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { - struct mchp_coreqspi *qspi = spi_controller_get_devdata(mem->spi->controller); - unsigned long clk_hz; - u32 baud_rate_val; - if (!spi_mem_default_supports_op(mem, op)) return false; @@ -557,14 +553,6 @@ static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_ return false; } - clk_hz = clk_get_rate(qspi->clk); - if (!clk_hz) - return false; - - baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq); - if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) - return false; - return true; } From aa28991fd5dc4c01a40caab2bd9af8c5e06f9899 Mon Sep 17 00:00:00 2001 From: David Arcari Date: Fri, 29 Aug 2025 07:38:59 -0400 Subject: [PATCH 0845/1292] platform/x86/intel: power-domains: Use topology_logical_package_id() for package ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, tpmi_get_logical_id() calls topology_physical_package_id() to set the pkg_id of the info structure. Since some VM hosts assign non contiguous package IDs, topology_physical_package_id() can return a larger value than topology_max_packages(). This will result in an invalid reference into tpmi_power_domain_mask[] as that is allocatead based on topology_max_packages() as the maximum package ID. Fixes: 17ca2780458c ("platform/x86/intel: TPMI domain id and CPU mapping") Signed-off-by: David Arcari Acked-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250829113859.1772827-1-darcari@redhat.com Reviewed-by: Ilpo JƤrvinen Signed-off-by: Ilpo JƤrvinen --- drivers/platform/x86/intel/tpmi_power_domains.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/tpmi_power_domains.c b/drivers/platform/x86/intel/tpmi_power_domains.c index 9d8247bb9cfa57..8641353b2e0617 100644 --- a/drivers/platform/x86/intel/tpmi_power_domains.c +++ b/drivers/platform/x86/intel/tpmi_power_domains.c @@ -178,7 +178,7 @@ static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info) info->punit_thread_id = FIELD_GET(LP_ID_MASK, data); info->punit_core_id = FIELD_GET(MODULE_ID_MASK, data); - info->pkg_id = topology_physical_package_id(cpu); + info->pkg_id = topology_logical_package_id(cpu); info->linux_cpu = cpu; return 0; From 1180c79fbf36e4c02e76ae4658509523437e52a4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 30 Jul 2025 23:17:15 +0300 Subject: [PATCH 0846/1292] hwmon: mlxreg-fan: Prevent fans from getting stuck at 0 RPM The fans controlled by the driver can get stuck at 0 RPM if they are configured below a 20% duty cycle. The driver tries to avoid this by enforcing a minimum duty cycle of 20%, but this is done after the fans are registered with the thermal subsystem. This is too late as the thermal subsystem can set their current state before the driver is able to enforce the minimum duty cycle. Fix by setting the minimum duty cycle before registering the fans with the thermal subsystem. Fixes: d7efb2ebc7b3 ("hwmon: (mlxreg-fan) Extend driver to support multiply cooling devices") Reported-by: Nikolay Aleksandrov Tested-by: Nikolay Aleksandrov Signed-off-by: Ido Schimmel Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20250730201715.1111133-1-vadimp@nvidia.com Signed-off-by: Guenter Roeck --- drivers/hwmon/mlxreg-fan.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c index a5f89aab3fb4d2..c25a54d5b39ad5 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -561,15 +561,14 @@ static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan) if (!pwm->connected) continue; pwm->fan = fan; + /* Set minimal PWM speed. */ + pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY); pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i], pwm, &mlxreg_fan_cooling_ops); if (IS_ERR(pwm->cdev)) { dev_err(dev, "Failed to register cooling device\n"); return PTR_ERR(pwm->cdev); } - - /* Set minimal PWM speed. */ - pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY); } return 0; From 98fd069dd87386d87eaf439e3c7b5767618926d2 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 29 Aug 2025 15:05:10 +1200 Subject: [PATCH 0847/1292] hwmon: (ina238) Correctly clamp temperature ina238_write_temp() was attempting to clamp the user input but was throwing away the result. Ensure that we clamp the value to the appropriate range before it is converted into a register value. Fixes: 0d9f596b1fe3 ("hwmon: (ina238) Modify the calculation formula to adapt to different chips") Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20250829030512.1179998-3-chris.packham@alliedtelesis.co.nz Signed-off-by: Guenter Roeck --- drivers/hwmon/ina238.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 5a394eeff6767d..4d3dc018ead9a4 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -572,7 +572,7 @@ static int ina238_write_temp(struct device *dev, u32 attr, long val) return -EOPNOTSUPP; /* Signed */ - regval = clamp_val(val, -40000, 125000); + val = clamp_val(val, -40000, 125000); regval = div_s64(val * 10000, data->config->temp_lsb) << data->config->temp_shift; regval = clamp_val(regval, S16_MIN, S16_MAX) & (0xffff << data->config->temp_shift); From 2d41a4bfee6e9941ff19728c691ab00d19cf882a Mon Sep 17 00:00:00 2001 From: "Jesse.Zhang" Date: Wed, 27 Aug 2025 13:29:17 +0800 Subject: [PATCH 0848/1292] drm/amdgpu/sdma: bump firmware version checks for user queue support Using the previous firmware could lead to problems with PROTECTED_FENCE_SIGNAL commands, specifically causing register conflicts between MCU_DBG0 and MCU_DBG1. The updated firmware versions ensure proper alignment and unification of the SDMA_SUBOP_PROTECTED_FENCE_SIGNAL value with SDMA 7.x, resolving these hardware coordination issues Fixes: e8cca30d8b34 ("drm/amdgpu/sdma6: add ucode version checks for userq support") Acked-by: Alex Deucher Signed-off-by: Jesse Zhang Signed-off-by: Alex Deucher (cherry picked from commit aab8b689aded255425db3d80c0030d1ba02fe2ef) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index e6d8eddda2bfa6..db6e41967f126b 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -1377,7 +1377,7 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block) switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) { case IP_VERSION(6, 0, 0): - if ((adev->sdma.instance[0].fw_version >= 24) && !adev->sdma.disable_uq) + if ((adev->sdma.instance[0].fw_version >= 27) && !adev->sdma.disable_uq) adev->userq_funcs[AMDGPU_HW_IP_DMA] = &userq_mes_funcs; break; case IP_VERSION(6, 0, 1): @@ -1385,11 +1385,11 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block) adev->userq_funcs[AMDGPU_HW_IP_DMA] = &userq_mes_funcs; break; case IP_VERSION(6, 0, 2): - if ((adev->sdma.instance[0].fw_version >= 21) && !adev->sdma.disable_uq) + if ((adev->sdma.instance[0].fw_version >= 23) && !adev->sdma.disable_uq) adev->userq_funcs[AMDGPU_HW_IP_DMA] = &userq_mes_funcs; break; case IP_VERSION(6, 0, 3): - if ((adev->sdma.instance[0].fw_version >= 25) && !adev->sdma.disable_uq) + if ((adev->sdma.instance[0].fw_version >= 27) && !adev->sdma.disable_uq) adev->userq_funcs[AMDGPU_HW_IP_DMA] = &userq_mes_funcs; break; case IP_VERSION(6, 1, 0): From 5171848bdfb8bf87f38331d3f8c0fd5e2b676d3e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 27 Aug 2025 14:24:31 -0400 Subject: [PATCH 0849/1292] drm/amdgpu/mes11: make MES_MISC_OP_CHANGE_CONFIG failure non-fatal If the firmware is too old, just warn and return success. Fixes: 27b791514789 ("drm/amdgpu/mes: keep enforce isolation up to date") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4414 Cc: shaoyun.Liu@amd.com Reviewed-by: Shaoyun.liu Signed-off-by: Alex Deucher (cherry picked from commit 9f28af76fab0948b59673f69c10aeec47de11c60) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 28eb846280dd40..3f6a828cad8ad8 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -641,8 +641,9 @@ static int mes_v11_0_misc_op(struct amdgpu_mes *mes, break; case MES_MISC_OP_CHANGE_CONFIG: if ((mes->adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) < 0x63) { - dev_err(mes->adev->dev, "MES FW version must be larger than 0x63 to support limit single process feature.\n"); - return -EINVAL; + dev_warn_once(mes->adev->dev, + "MES FW version must be larger than 0x63 to support limit single process feature.\n"); + return 0; } misc_pkt.opcode = MESAPI_MISC__CHANGE_CONFIG; misc_pkt.change_config.opcode = From a8b79b09185de868e478eb1b6f1fd8deddb0604d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 28 Aug 2025 09:37:05 -0500 Subject: [PATCH 0850/1292] drm/amd: Re-enable common modes for eDP and LVDS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Why] Although compositors will add their own modes, Xorg won't use it's own modes and will only stick to modes advertised by the driver. This mean a user that used to pick 1024x768 could no longer access it unless the panel's native resolution was 1024x768. [How] Revert commit 6d396e7ac1ce3 ("drm/amd/display: Disable common modes for LVDS") and commit 7948afb46af92 ("drm/amd/display: Disable common modes for eDP"). The panel will still use scaling for any non-native modes due to commit 978fa2f6d0b12 ("drm/amd/display: Use scaling for non-native resolutions on eDP") Reported-by: Marek Marczykowski-Górecki Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4538 Acked-by: Alex Deucher Link: https://lore.kernel.org/r/20250828140856.2887993-1-superm1@kernel.org Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher (cherry picked from commit c2fbf72fe3c2d08856e834ca43328a8829a261d8) --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a0ca3b2c6bd878..7808a647a306c2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8381,8 +8381,7 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) drm_add_modes_noedid(connector, 1920, 1080); } else { amdgpu_dm_connector_ddc_get_modes(connector, drm_edid); - if (encoder && (connector->connector_type != DRM_MODE_CONNECTOR_eDP) && - (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)) + if (encoder) amdgpu_dm_connector_add_common_modes(encoder, connector); amdgpu_dm_connector_add_freesync_modes(connector, drm_edid); } From 71403f58b4bb6c13b71c05505593a355f697fd94 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 6 Aug 2025 10:47:50 -0400 Subject: [PATCH 0851/1292] drm/amdgpu: drop hw access in non-DC audio fini We already disable the audio pins in hw_fini so there is no need to do it again in sw_fini. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4481 Cc: oushixiong Signed-off-by: Alex Deucher (cherry picked from commit 5eeb16ca727f11278b2917fd4311a7d7efb0bbd6) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 5 ----- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 5 ----- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 5 ----- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 5 ----- 4 files changed, 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index bf7c22f81cda34..ba73518f5cdf36 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -1462,17 +1462,12 @@ static int dce_v10_0_audio_init(struct amdgpu_device *adev) static void dce_v10_0_audio_fini(struct amdgpu_device *adev) { - int i; - if (!amdgpu_audio) return; if (!adev->mode_info.audio.enabled) return; - for (i = 0; i < adev->mode_info.audio.num_pins; i++) - dce_v10_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false); - adev->mode_info.audio.enabled = false; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 47e05783c4a0e3..b01d88d078fa2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -1511,17 +1511,12 @@ static int dce_v11_0_audio_init(struct amdgpu_device *adev) static void dce_v11_0_audio_fini(struct amdgpu_device *adev) { - int i; - if (!amdgpu_audio) return; if (!adev->mode_info.audio.enabled) return; - for (i = 0; i < adev->mode_info.audio.num_pins; i++) - dce_v11_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false); - adev->mode_info.audio.enabled = false; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 276c025c4c03db..81760a26f2ffca 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1451,17 +1451,12 @@ static int dce_v6_0_audio_init(struct amdgpu_device *adev) static void dce_v6_0_audio_fini(struct amdgpu_device *adev) { - int i; - if (!amdgpu_audio) return; if (!adev->mode_info.audio.enabled) return; - for (i = 0; i < adev->mode_info.audio.num_pins; i++) - dce_v6_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false); - adev->mode_info.audio.enabled = false; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index e62ccf9eb73de5..19a265bd4d1966 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1443,17 +1443,12 @@ static int dce_v8_0_audio_init(struct amdgpu_device *adev) static void dce_v8_0_audio_fini(struct amdgpu_device *adev) { - int i; - if (!amdgpu_audio) return; if (!adev->mode_info.audio.enabled) return; - for (i = 0; i < adev->mode_info.audio.num_pins; i++) - dce_v8_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false); - adev->mode_info.audio.enabled = false; } From 3ebf766c35464ebdeefb6068246267147503dc04 Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Wed, 20 Aug 2025 15:46:52 -0400 Subject: [PATCH 0852/1292] drm/amd/display: Clear the CUR_ENABLE register on DCN314 w/out DPP PG [Why&How] ON DCN314, clearing DPP SW structure without power gating it can cause a double cursor in full screen with non-native scaling. A W/A that clears CURSOR0_CONTROL cursor_enable flag if dcn10_plane_atomic_power_down is called and DPP power gating is disabled. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4168 Reviewed-by: Sun peng (Leo) Li Signed-off-by: Ivan Lipski Signed-off-by: Alex Hung Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 645f74f1dc119dad5a2c7bbc05cc315e76883011) Cc: stable@vger.kernel.org --- .../drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c | 9 +++ .../drm/amd/display/dc/dpp/dcn10/dcn10_dpp.h | 2 + .../drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c | 1 + .../amd/display/dc/hwss/dcn314/dcn314_hwseq.c | 72 +++++++++++++++++++ .../amd/display/dc/hwss/dcn314/dcn314_hwseq.h | 2 + .../amd/display/dc/hwss/dcn314/dcn314_init.c | 1 + drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 3 + 7 files changed, 90 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c index 75fb77bca83ba2..01480a04f85ef5 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c @@ -520,6 +520,15 @@ void dpp1_dppclk_control( REG_UPDATE(DPP_CONTROL, DPP_CLOCK_ENABLE, 0); } +void dpp_force_disable_cursor(struct dpp *dpp_base) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + /* Force disable cursor */ + REG_UPDATE(CURSOR0_CONTROL, CUR0_ENABLE, 0); + dpp_base->pos.cur0_ctl.bits.cur0_enable = 0; +} + static const struct dpp_funcs dcn10_dpp_funcs = { .dpp_read_state = dpp_read_state, .dpp_reset = dpp_reset, diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.h index c48139bed11f51..f466182963f756 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.h @@ -1525,4 +1525,6 @@ void dpp1_construct(struct dcn10_dpp *dpp1, void dpp1_cm_get_gamut_remap(struct dpp *dpp_base, struct dpp_grph_csc_adjustment *adjust); +void dpp_force_disable_cursor(struct dpp *dpp_base); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c index 2d70586cef4027..09be2a90cc79dc 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c @@ -1494,6 +1494,7 @@ static struct dpp_funcs dcn30_dpp_funcs = { .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp3_set_hdr_multiplier, .dpp_get_gamut_remap = dpp3_cm_get_gamut_remap, + .dpp_force_disable_cursor = dpp_force_disable_cursor, }; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c index e68f21fd5f0fb4..56098453395055 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c @@ -528,3 +528,75 @@ void dcn314_disable_link_output(struct dc_link *link, apply_symclk_on_tx_off_wa(link); } + +/** + * dcn314_dpp_pg_control - DPP power gate control. + * + * @hws: dce_hwseq reference. + * @dpp_inst: DPP instance reference. + * @power_on: true if we want to enable power gate, false otherwise. + * + * Enable or disable power gate in the specific DPP instance. + * If power gating is disabled, will force disable cursor in the DPP instance. + */ +void dcn314_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + + if (hws->ctx->dc->debug.disable_dpp_power_gate) { + /* Workaround for DCN314 with disabled power gating */ + if (!power_on) { + + /* Force disable cursor if power gating is disabled */ + struct dpp *dpp = hws->ctx->dc->res_pool->dpps[dpp_inst]; + if (dpp && dpp->funcs->dpp_force_disable_cursor) + dpp->funcs->dpp_force_disable_cursor(dpp); + } + return; + } + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; + + switch (dpp_inst) { + case 0: /* DPP0 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, + DOMAIN1_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN1_PG_STATUS, + DOMAIN1_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DPP1 */ + REG_UPDATE(DOMAIN3_PG_CONFIG, + DOMAIN3_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN3_PG_STATUS, + DOMAIN3_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DPP2 */ + REG_UPDATE(DOMAIN5_PG_CONFIG, + DOMAIN5_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN5_PG_STATUS, + DOMAIN5_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DPP3 */ + REG_UPDATE(DOMAIN7_PG_CONFIG, + DOMAIN7_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN7_PG_STATUS, + DOMAIN7_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h index 2305ad282f218b..6c072d0274ea37 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h @@ -47,4 +47,6 @@ void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, void dcn314_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); +void dcn314_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on); + #endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c index f5112742edf9b4..9f454fa90e65db 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c @@ -141,6 +141,7 @@ static const struct hwseq_private_funcs dcn314_private_funcs = { .enable_power_gating_plane = dcn314_enable_power_gating_plane, .dpp_root_clock_control = dcn314_dpp_root_clock_control, .hubp_pg_control = dcn31_hubp_pg_control, + .dpp_pg_control = dcn314_dpp_pg_control, .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .update_odm = dcn314_update_odm, .dsc_pg_control = dcn314_dsc_pg_control, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 0c5675d1c59368..1b7c085dc2cc1e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -349,6 +349,9 @@ struct dpp_funcs { struct dpp *dpp_base, enum dc_color_space color_space, struct dc_csc_transform cursor_csc_color_matrix); + + void (*dpp_force_disable_cursor)(struct dpp *dpp_base); + }; From 0ef5c4e4dbbfcebaa9b2eca18097b43016727dfe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 29 Aug 2025 12:16:32 +1000 Subject: [PATCH 0853/1292] nouveau: fix disabling the nonstall irq due to storm code Nouveau has code that when it gets an IRQ with no allowed handler it disables it to avoid storms. However with nonstall interrupts, we often disable them from the drm driver, but still request their emission via the push submission. Just don't disable nonstall irqs ever in normal operation, the event handling code will filter them out, and the driver will just enable/disable them at load time. This fixes timeouts we've been seeing on/off for a long time, but they became a lot more noticeable on Blackwell. This doesn't fix all of them, there is a subsequent fence emission fix to fix the last few. Fixes: 3ebd64aa3c4f ("drm/nouveau/intr: support multiple trees, and explicit interfaces") Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie Link: https://lore.kernel.org/r/20250829021633.1674524-1-airlied@gmail.com [ Fix a typo and a minor checkpatch.pl warning; remove "v2" from commit subject. - Danilo ] Signed-off-by: Danilo Krummrich --- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 2 ++ .../gpu/drm/nouveau/nvkm/engine/fifo/ga100.c | 23 ++++++++++++------- .../gpu/drm/nouveau/nvkm/engine/fifo/ga102.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/priv.h | 2 ++ .../nouveau/nvkm/subdev/gsp/rm/r535/fifo.c | 1 + 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index fdffa0391b31c0..6fd4e60634fbe4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -350,6 +350,8 @@ nvkm_fifo_dtor(struct nvkm_engine *engine) nvkm_chid_unref(&fifo->chid); nvkm_event_fini(&fifo->nonstall.event); + if (fifo->func->nonstall_dtor) + fifo->func->nonstall_dtor(fifo); mutex_destroy(&fifo->mutex); if (fifo->func->dtor) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c index e74493a4569edb..6848a56f20c076 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c @@ -517,19 +517,11 @@ ga100_fifo_nonstall_intr(struct nvkm_inth *inth) static void ga100_fifo_nonstall_block(struct nvkm_event *event, int type, int index) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); - struct nvkm_runl *runl = nvkm_runl_get(fifo, index, 0); - - nvkm_inth_block(&runl->nonstall.inth); } static void ga100_fifo_nonstall_allow(struct nvkm_event *event, int type, int index) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event); - struct nvkm_runl *runl = nvkm_runl_get(fifo, index, 0); - - nvkm_inth_allow(&runl->nonstall.inth); } const struct nvkm_event_func @@ -564,12 +556,26 @@ ga100_fifo_nonstall_ctor(struct nvkm_fifo *fifo) if (ret) return ret; + nvkm_inth_allow(&runl->nonstall.inth); + nr = max(nr, runl->id + 1); } return nr; } +void +ga100_fifo_nonstall_dtor(struct nvkm_fifo *fifo) +{ + struct nvkm_runl *runl; + + nvkm_runl_foreach(runl, fifo) { + if (runl->nonstall.vector < 0) + continue; + nvkm_inth_block(&runl->nonstall.inth); + } +} + int ga100_fifo_runl_ctor(struct nvkm_fifo *fifo) { @@ -599,6 +605,7 @@ ga100_fifo = { .runl_ctor = ga100_fifo_runl_ctor, .mmu_fault = &tu102_fifo_mmu_fault, .nonstall_ctor = ga100_fifo_nonstall_ctor, + .nonstall_dtor = ga100_fifo_nonstall_dtor, .nonstall = &ga100_fifo_nonstall, .runl = &ga100_runl, .runq = &ga100_runq, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c index 755235f55b3aca..18a0b1f4eab76a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga102.c @@ -30,6 +30,7 @@ ga102_fifo = { .runl_ctor = ga100_fifo_runl_ctor, .mmu_fault = &tu102_fifo_mmu_fault, .nonstall_ctor = ga100_fifo_nonstall_ctor, + .nonstall_dtor = ga100_fifo_nonstall_dtor, .nonstall = &ga100_fifo_nonstall, .runl = &ga100_runl, .runq = &ga100_runq, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h index 5e81ae1953290d..fff1428ef267ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -41,6 +41,7 @@ struct nvkm_fifo_func { void (*start)(struct nvkm_fifo *, unsigned long *); int (*nonstall_ctor)(struct nvkm_fifo *); + void (*nonstall_dtor)(struct nvkm_fifo *); const struct nvkm_event_func *nonstall; const struct nvkm_runl_func *runl; @@ -200,6 +201,7 @@ u32 tu102_chan_doorbell_handle(struct nvkm_chan *); int ga100_fifo_runl_ctor(struct nvkm_fifo *); int ga100_fifo_nonstall_ctor(struct nvkm_fifo *); +void ga100_fifo_nonstall_dtor(struct nvkm_fifo *); extern const struct nvkm_event_func ga100_fifo_nonstall; extern const struct nvkm_runl_func ga100_runl; extern const struct nvkm_runq_func ga100_runq; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fifo.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fifo.c index 1ac5628c5140e6..4ed54b386a60f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fifo.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fifo.c @@ -601,6 +601,7 @@ r535_fifo_new(const struct nvkm_fifo_func *hw, struct nvkm_device *device, rm->chan.func = &r535_chan; rm->nonstall = &ga100_fifo_nonstall; rm->nonstall_ctor = ga100_fifo_nonstall_ctor; + rm->nonstall_dtor = ga100_fifo_nonstall_dtor; return nvkm_fifo_new_(rm, device, type, inst, pfifo); } From 2cb66ae6040fd3cb058c3391b180f378fc0e3e2f Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Fri, 29 Aug 2025 12:16:33 +1000 Subject: [PATCH 0854/1292] nouveau: Membar before between semaphore writes and the interrupt This ensures that the memory write and the interrupt are properly ordered and we won't wake up the kernel before the semaphore write has hit memory. Fixes: b1ca384772b6 ("drm/nouveau/gv100-: switch to volta semaphore methods") Cc: stable@vger.kernel.org Signed-off-by: Faith Ekstrand Signed-off-by: Dave Airlie Link: https://lore.kernel.org/r/20250829021633.1674524-2-airlied@gmail.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nouveau/gv100_fence.c | 7 +- .../drm/nouveau/include/nvhw/class/clc36f.h | 85 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/gv100_fence.c b/drivers/gpu/drm/nouveau/gv100_fence.c index cccdeca72002e0..317e516c4ec729 100644 --- a/drivers/gpu/drm/nouveau/gv100_fence.c +++ b/drivers/gpu/drm/nouveau/gv100_fence.c @@ -18,7 +18,7 @@ gv100_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence) struct nvif_push *push = &chan->chan.push; int ret; - ret = PUSH_WAIT(push, 8); + ret = PUSH_WAIT(push, 13); if (ret) return ret; @@ -32,6 +32,11 @@ gv100_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence) NVDEF(NVC36F, SEM_EXECUTE, PAYLOAD_SIZE, 32BIT) | NVDEF(NVC36F, SEM_EXECUTE, RELEASE_TIMESTAMP, DIS)); + PUSH_MTHD(push, NVC36F, MEM_OP_A, 0, + MEM_OP_B, 0, + MEM_OP_C, NVDEF(NVC36F, MEM_OP_C, MEMBAR_TYPE, SYS_MEMBAR), + MEM_OP_D, NVDEF(NVC36F, MEM_OP_D, OPERATION, MEMBAR)); + PUSH_MTHD(push, NVC36F, NON_STALL_INTERRUPT, 0); PUSH_KICK(push); diff --git a/drivers/gpu/drm/nouveau/include/nvhw/class/clc36f.h b/drivers/gpu/drm/nouveau/include/nvhw/class/clc36f.h index 8735dda4c8a714..338f74b9f501ea 100644 --- a/drivers/gpu/drm/nouveau/include/nvhw/class/clc36f.h +++ b/drivers/gpu/drm/nouveau/include/nvhw/class/clc36f.h @@ -7,6 +7,91 @@ #define NVC36F_NON_STALL_INTERRUPT (0x00000020) #define NVC36F_NON_STALL_INTERRUPT_HANDLE 31:0 +// NOTE - MEM_OP_A and MEM_OP_B have been replaced in gp100 with methods for +// specifying the page address for a targeted TLB invalidate and the uTLB for +// a targeted REPLAY_CANCEL for UVM. +// The previous MEM_OP_A/B functionality is in MEM_OP_C/D, with slightly +// rearranged fields. +#define NVC36F_MEM_OP_A (0x00000028) +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_CANCEL_TARGET_CLIENT_UNIT_ID 5:0 // only relevant for REPLAY_CANCEL_TARGETED +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_INVALIDATION_SIZE 5:0 // Used to specify size of invalidate, used for invalidates which are not of the REPLAY_CANCEL_TARGETED type +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_CANCEL_TARGET_GPC_ID 10:6 // only relevant for REPLAY_CANCEL_TARGETED +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_CANCEL_MMU_ENGINE_ID 6:0 // only relevant for REPLAY_CANCEL_VA_GLOBAL +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_SYSMEMBAR 11:11 +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_SYSMEMBAR_EN 0x00000001 +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_SYSMEMBAR_DIS 0x00000000 +#define NVC36F_MEM_OP_A_TLB_INVALIDATE_TARGET_ADDR_LO 31:12 +#define NVC36F_MEM_OP_B (0x0000002c) +#define NVC36F_MEM_OP_B_TLB_INVALIDATE_TARGET_ADDR_HI 31:0 +#define NVC36F_MEM_OP_C (0x00000030) +#define NVC36F_MEM_OP_C_MEMBAR_TYPE 2:0 +#define NVC36F_MEM_OP_C_MEMBAR_TYPE_SYS_MEMBAR 0x00000000 +#define NVC36F_MEM_OP_C_MEMBAR_TYPE_MEMBAR 0x00000001 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB 0:0 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB_ONE 0x00000000 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB_ALL 0x00000001 // Probably nonsensical for MMU_TLB_INVALIDATE_TARGETED +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_GPC 1:1 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_GPC_ENABLE 0x00000000 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_GPC_DISABLE 0x00000001 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_REPLAY 4:2 // only relevant if GPC ENABLE +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_REPLAY_NONE 0x00000000 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_REPLAY_START 0x00000001 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_REPLAY_START_ACK_ALL 0x00000002 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_REPLAY_CANCEL_TARGETED 0x00000003 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_REPLAY_CANCEL_GLOBAL 0x00000004 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_REPLAY_CANCEL_VA_GLOBAL 0x00000005 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACK_TYPE 6:5 // only relevant if GPC ENABLE +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACK_TYPE_NONE 0x00000000 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACK_TYPE_GLOBALLY 0x00000001 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACK_TYPE_INTRANODE 0x00000002 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE 9:7 //only relevant for REPLAY_CANCEL_VA_GLOBAL +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_READ 0 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_WRITE 1 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_ATOMIC_STRONG 2 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_RSVRVD 3 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_ATOMIC_WEAK 4 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_ATOMIC_ALL 5 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_WRITE_AND_ATOMIC 6 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_ACCESS_TYPE_VIRT_ALL 7 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL 9:7 // Invalidate affects this level and all below +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_ALL 0x00000000 // Invalidate tlb caches at all levels of the page table +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_PTE_ONLY 0x00000001 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_UP_TO_PDE0 0x00000002 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_UP_TO_PDE1 0x00000003 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_UP_TO_PDE2 0x00000004 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_UP_TO_PDE3 0x00000005 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_UP_TO_PDE4 0x00000006 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PAGE_TABLE_LEVEL_UP_TO_PDE5 0x00000007 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB_APERTURE 11:10 // only relevant if PDB_ONE +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB_APERTURE_VID_MEM 0x00000000 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB_APERTURE_SYS_MEM_COHERENT 0x00000002 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB_APERTURE_SYS_MEM_NONCOHERENT 0x00000003 +#define NVC36F_MEM_OP_C_TLB_INVALIDATE_PDB_ADDR_LO 31:12 // only relevant if PDB_ONE +#define NVC36F_MEM_OP_C_ACCESS_COUNTER_CLR_TARGETED_NOTIFY_TAG 19:0 +// MEM_OP_D MUST be preceded by MEM_OPs A-C. +#define NVC36F_MEM_OP_D (0x00000034) +#define NVC36F_MEM_OP_D_TLB_INVALIDATE_PDB_ADDR_HI 26:0 // only relevant if PDB_ONE +#define NVC36F_MEM_OP_D_OPERATION 31:27 +#define NVC36F_MEM_OP_D_OPERATION_MEMBAR 0x00000005 +#define NVC36F_MEM_OP_D_OPERATION_MMU_TLB_INVALIDATE 0x00000009 +#define NVC36F_MEM_OP_D_OPERATION_MMU_TLB_INVALIDATE_TARGETED 0x0000000a +#define NVC36F_MEM_OP_D_OPERATION_L2_PEERMEM_INVALIDATE 0x0000000d +#define NVC36F_MEM_OP_D_OPERATION_L2_SYSMEM_INVALIDATE 0x0000000e +// CLEAN_LINES is an alias for Tegra/GPU IP usage +#define NVC36F_MEM_OP_B_OPERATION_L2_INVALIDATE_CLEAN_LINES 0x0000000e +#define NVC36F_MEM_OP_D_OPERATION_L2_CLEAN_COMPTAGS 0x0000000f +#define NVC36F_MEM_OP_D_OPERATION_L2_FLUSH_DIRTY 0x00000010 +#define NVC36F_MEM_OP_D_OPERATION_L2_WAIT_FOR_SYS_PENDING_READS 0x00000015 +#define NVC36F_MEM_OP_D_OPERATION_ACCESS_COUNTER_CLR 0x00000016 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TYPE 1:0 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TYPE_MIMC 0x00000000 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TYPE_MOMC 0x00000001 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TYPE_ALL 0x00000002 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TYPE_TARGETED 0x00000003 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TARGETED_TYPE 2:2 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TARGETED_TYPE_MIMC 0x00000000 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TARGETED_TYPE_MOMC 0x00000001 +#define NVC36F_MEM_OP_D_ACCESS_COUNTER_CLR_TARGETED_BANK 6:3 #define NVC36F_SEM_ADDR_LO (0x0000005c) #define NVC36F_SEM_ADDR_LO_OFFSET 31:2 #define NVC36F_SEM_ADDR_HI (0x00000060) From 28010791193a4503f054e8d69a950ef815deb539 Mon Sep 17 00:00:00 2001 From: Ivan Pravdin Date: Wed, 27 Aug 2025 10:53:25 -0400 Subject: [PATCH 0855/1292] Bluetooth: vhci: Prevent use-after-free by removing debugfs files early Move the creation of debugfs files into a dedicated function, and ensure they are explicitly removed during vhci_release(), before associated data structures are freed. Previously, debugfs files such as "force_suspend", "force_wakeup", and others were created under hdev->debugfs but not removed in vhci_release(). Since vhci_release() frees the backing vhci_data structure, any access to these files after release would result in use-after-free errors. Although hdev->debugfs is later freed in hci_release_dev(), user can access files after vhci_data is freed but before hdev->debugfs is released. Fixes: ab4e4380d4e1 ("Bluetooth: Add vhci devcoredump support") Signed-off-by: Ivan Pravdin Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_vhci.c | 57 ++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index f7d8c3c00655a8..2fef08254d78d9 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -380,6 +380,28 @@ static const struct file_operations force_devcoredump_fops = { .write = force_devcd_write, }; +static void vhci_debugfs_init(struct vhci_data *data) +{ + struct hci_dev *hdev = data->hdev; + + debugfs_create_file("force_suspend", 0644, hdev->debugfs, data, + &force_suspend_fops); + + debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data, + &force_wakeup_fops); + + if (IS_ENABLED(CONFIG_BT_MSFTEXT)) + debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data, + &msft_opcode_fops); + + if (IS_ENABLED(CONFIG_BT_AOSPEXT)) + debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data, + &aosp_capable_fops); + + debugfs_create_file("force_devcoredump", 0644, hdev->debugfs, data, + &force_devcoredump_fops); +} + static int __vhci_create_device(struct vhci_data *data, __u8 opcode) { struct hci_dev *hdev; @@ -434,22 +456,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) return -EBUSY; } - debugfs_create_file("force_suspend", 0644, hdev->debugfs, data, - &force_suspend_fops); - - debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data, - &force_wakeup_fops); - - if (IS_ENABLED(CONFIG_BT_MSFTEXT)) - debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data, - &msft_opcode_fops); - - if (IS_ENABLED(CONFIG_BT_AOSPEXT)) - debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data, - &aosp_capable_fops); - - debugfs_create_file("force_devcoredump", 0644, hdev->debugfs, data, - &force_devcoredump_fops); + if (!IS_ERR_OR_NULL(hdev->debugfs)) + vhci_debugfs_init(data); hci_skb_pkt_type(skb) = HCI_VENDOR_PKT; @@ -651,6 +659,21 @@ static int vhci_open(struct inode *inode, struct file *file) return 0; } +static void vhci_debugfs_remove(struct hci_dev *hdev) +{ + debugfs_lookup_and_remove("force_suspend", hdev->debugfs); + + debugfs_lookup_and_remove("force_wakeup", hdev->debugfs); + + if (IS_ENABLED(CONFIG_BT_MSFTEXT)) + debugfs_lookup_and_remove("msft_opcode", hdev->debugfs); + + if (IS_ENABLED(CONFIG_BT_AOSPEXT)) + debugfs_lookup_and_remove("aosp_capable", hdev->debugfs); + + debugfs_lookup_and_remove("force_devcoredump", hdev->debugfs); +} + static int vhci_release(struct inode *inode, struct file *file) { struct vhci_data *data = file->private_data; @@ -662,6 +685,8 @@ static int vhci_release(struct inode *inode, struct file *file) hdev = data->hdev; if (hdev) { + if (!IS_ERR_OR_NULL(hdev->debugfs)) + vhci_debugfs_remove(hdev); hci_unregister_dev(hdev); hci_free_dev(hdev); } From 862c628108562d8c7a516a900034823b381d3cba Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 27 Aug 2025 20:40:14 +0000 Subject: [PATCH 0856/1292] Bluetooth: Fix use-after-free in l2cap_sock_cleanup_listen() syzbot reported the splat below without a repro. In the splat, a single thread calling bt_accept_dequeue() freed sk and touched it after that. The root cause would be the racy l2cap_sock_cleanup_listen() call added by the cited commit. bt_accept_dequeue() is called under lock_sock() except for l2cap_sock_release(). Two threads could see the same socket during the list iteration in bt_accept_dequeue(): CPU1 CPU2 (close()) ---- ---- sock_hold(sk) sock_hold(sk); lock_sock(sk) <-- block close() sock_put(sk) bt_accept_unlink(sk) sock_put(sk) <-- refcnt by bt_accept_enqueue() release_sock(sk) lock_sock(sk) sock_put(sk) bt_accept_unlink(sk) sock_put(sk) <-- last refcnt bt_accept_unlink(sk) <-- UAF Depending on the timing, the other thread could show up in the "Freed by task" part. Let's call l2cap_sock_cleanup_listen() under lock_sock() in l2cap_sock_release(). [0]: BUG: KASAN: slab-use-after-free in debug_spin_lock_before kernel/locking/spinlock_debug.c:86 [inline] BUG: KASAN: slab-use-after-free in do_raw_spin_lock+0x26f/0x2b0 kernel/locking/spinlock_debug.c:115 Read of size 4 at addr ffff88803b7eb1c4 by task syz.5.3276/16995 CPU: 3 UID: 0 PID: 16995 Comm: syz.5.3276 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 Call Trace: __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xcd/0x630 mm/kasan/report.c:482 kasan_report+0xe0/0x110 mm/kasan/report.c:595 debug_spin_lock_before kernel/locking/spinlock_debug.c:86 [inline] do_raw_spin_lock+0x26f/0x2b0 kernel/locking/spinlock_debug.c:115 spin_lock_bh include/linux/spinlock.h:356 [inline] release_sock+0x21/0x220 net/core/sock.c:3746 bt_accept_dequeue+0x505/0x600 net/bluetooth/af_bluetooth.c:312 l2cap_sock_cleanup_listen+0x5c/0x2a0 net/bluetooth/l2cap_sock.c:1451 l2cap_sock_release+0x5c/0x210 net/bluetooth/l2cap_sock.c:1425 __sock_release+0xb3/0x270 net/socket.c:649 sock_close+0x1c/0x30 net/socket.c:1439 __fput+0x3ff/0xb70 fs/file_table.c:468 task_work_run+0x14d/0x240 kernel/task_work.c:227 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] exit_to_user_mode_loop+0xeb/0x110 kernel/entry/common.c:43 exit_to_user_mode_prepare include/linux/irq-entry-common.h:225 [inline] syscall_exit_to_user_mode_work include/linux/entry-common.h:175 [inline] syscall_exit_to_user_mode include/linux/entry-common.h:210 [inline] do_syscall_64+0x3f6/0x4c0 arch/x86/entry/syscall_64.c:100 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f2accf8ebe9 Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffdb6cb1378 EFLAGS: 00000246 ORIG_RAX: 00000000000001b4 RAX: 0000000000000000 RBX: 00000000000426fb RCX: 00007f2accf8ebe9 RDX: 0000000000000000 RSI: 000000000000001e RDI: 0000000000000003 RBP: 00007f2acd1b7da0 R08: 0000000000000001 R09: 00000012b6cb166f R10: 0000001b30e20000 R11: 0000000000000246 R12: 00007f2acd1b609c R13: 00007f2acd1b6090 R14: ffffffffffffffff R15: 00007ffdb6cb1490 Allocated by task 5326: kasan_save_stack+0x33/0x60 mm/kasan/common.c:47 kasan_save_track+0x14/0x30 mm/kasan/common.c:68 poison_kmalloc_redzone mm/kasan/common.c:388 [inline] __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:405 kasan_kmalloc include/linux/kasan.h:260 [inline] __do_kmalloc_node mm/slub.c:4365 [inline] __kmalloc_noprof+0x223/0x510 mm/slub.c:4377 kmalloc_noprof include/linux/slab.h:909 [inline] sk_prot_alloc+0x1a8/0x2a0 net/core/sock.c:2239 sk_alloc+0x36/0xc20 net/core/sock.c:2295 bt_sock_alloc+0x3b/0x3a0 net/bluetooth/af_bluetooth.c:151 l2cap_sock_alloc.constprop.0+0x33/0x1d0 net/bluetooth/l2cap_sock.c:1894 l2cap_sock_new_connection_cb+0x101/0x240 net/bluetooth/l2cap_sock.c:1482 l2cap_connect_cfm+0x4c4/0xf80 net/bluetooth/l2cap_core.c:7287 hci_connect_cfm include/net/bluetooth/hci_core.h:2050 [inline] hci_remote_features_evt+0x4dd/0x970 net/bluetooth/hci_event.c:3712 hci_event_func net/bluetooth/hci_event.c:7519 [inline] hci_event_packet+0xa0d/0x11c0 net/bluetooth/hci_event.c:7573 hci_rx_work+0x2c5/0x16b0 net/bluetooth/hci_core.c:4071 process_one_work+0x9cf/0x1b70 kernel/workqueue.c:3236 process_scheduled_works kernel/workqueue.c:3319 [inline] worker_thread+0x6c8/0xf10 kernel/workqueue.c:3400 kthread+0x3c2/0x780 kernel/kthread.c:463 ret_from_fork+0x5d7/0x6f0 arch/x86/kernel/process.c:148 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 Freed by task 16995: kasan_save_stack+0x33/0x60 mm/kasan/common.c:47 kasan_save_track+0x14/0x30 mm/kasan/common.c:68 kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:576 poison_slab_object mm/kasan/common.c:243 [inline] __kasan_slab_free+0x60/0x70 mm/kasan/common.c:275 kasan_slab_free include/linux/kasan.h:233 [inline] slab_free_hook mm/slub.c:2417 [inline] slab_free mm/slub.c:4680 [inline] kfree+0x2b4/0x4d0 mm/slub.c:4879 sk_prot_free net/core/sock.c:2278 [inline] __sk_destruct+0x75f/0x9a0 net/core/sock.c:2373 sk_destruct+0xc2/0xf0 net/core/sock.c:2401 __sk_free+0xf4/0x3e0 net/core/sock.c:2412 sk_free+0x6a/0x90 net/core/sock.c:2423 sock_put include/net/sock.h:1960 [inline] bt_accept_unlink+0x245/0x2e0 net/bluetooth/af_bluetooth.c:262 bt_accept_dequeue+0x517/0x600 net/bluetooth/af_bluetooth.c:308 l2cap_sock_cleanup_listen+0x5c/0x2a0 net/bluetooth/l2cap_sock.c:1451 l2cap_sock_release+0x5c/0x210 net/bluetooth/l2cap_sock.c:1425 __sock_release+0xb3/0x270 net/socket.c:649 sock_close+0x1c/0x30 net/socket.c:1439 __fput+0x3ff/0xb70 fs/file_table.c:468 task_work_run+0x14d/0x240 kernel/task_work.c:227 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] exit_to_user_mode_loop+0xeb/0x110 kernel/entry/common.c:43 exit_to_user_mode_prepare include/linux/irq-entry-common.h:225 [inline] syscall_exit_to_user_mode_work include/linux/entry-common.h:175 [inline] syscall_exit_to_user_mode include/linux/entry-common.h:210 [inline] do_syscall_64+0x3f6/0x4c0 arch/x86/entry/syscall_64.c:100 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: 1728137b33c0 ("Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb") Reported-by: syzbot+e5e64cdf8e92046dd3e1@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-bluetooth/68af6b9d.a70a0220.3cafd4.0032.GAE@google.com/ Signed-off-by: Kuniyuki Iwashima Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/l2cap_sock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f4257c4d30525f..814fb8610ac437 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1422,7 +1422,10 @@ static int l2cap_sock_release(struct socket *sock) if (!sk) return 0; + lock_sock_nested(sk, L2CAP_NESTING_PARENT); l2cap_sock_cleanup_listen(sk); + release_sock(sk); + bt_sock_unlink(&l2cap_sk_list, sk); err = l2cap_sock_shutdown(sock, SHUT_RDWR); From 3d439e1ec3368fae17db379354bd7a9e568ca0ab Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 29 Aug 2025 18:11:01 +0300 Subject: [PATCH 0857/1292] ASoC: sof: ipc4-topology: Add support to sched_domain attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SOF_TKN_COMP_SCHED_DOMAIN and connect it to struct snd_sof_widget comp_domain member, with new get_token_comp_domain() function. The logic is such that if the topology attribute is not present in the widget node the corresponding IPC4 extension value is taken from the module's manifest like before. But if the attribute is found and recognized its value overrides what is there in the manifest. Signed-off-by: Jyri Sarha Reviewed-by: PĆ©ter Ujfalusi Reviewed-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi Message-ID: <20250829151101.27327-1-peter.ujfalusi@linux.intel.com> Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 2 ++ sound/soc/sof/ipc4-topology.c | 44 ++++++++++++++++++++++++++++++++- sound/soc/sof/ipc4-topology.h | 7 ++++++ sound/soc/sof/sof-audio.h | 3 +++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index c28c766270de01..9ce72fbd6f113a 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -106,6 +106,8 @@ */ #define SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME 417 +#define SOF_TKN_COMP_SCHED_DOMAIN 418 + /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 #define SOF_TKN_INTEL_SSP_MCLK_ID 501 diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 591ee30551baa8..74a1319d4bd218 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -38,6 +38,36 @@ MODULE_PARM_DESC(ipc4_ignore_cpc, static DEFINE_IDA(alh_group_ida); static DEFINE_IDA(pipeline_ida); +struct sof_comp_domains { + const char *name; + enum sof_comp_domain domain; +}; + +static const struct sof_comp_domains sof_domains[] = { + { "LL", SOF_COMP_DOMAIN_LL, }, + { "DP", SOF_COMP_DOMAIN_DP, } +}; + +static enum sof_comp_domain find_domain(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_domains); i++) { + if (strcmp(name, sof_domains[i].name) == 0) + return sof_domains[i].domain; + } + /* No valid value found, fall back to manifest value */ + return SOF_COMP_DOMAIN_UNSET; +} + +static int get_token_comp_domain(void *elem, void *object, u32 offset) +{ + u32 *val = (u32 *)((u8 *)object + offset); + + *val = find_domain((const char *)elem); + return 0; +} + static const struct sof_topology_token ipc4_sched_tokens[] = { {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc4_pipeline, lp_mode)}, @@ -127,6 +157,8 @@ static const struct sof_topology_token comp_ext_tokens[] = { offsetof(struct snd_sof_widget, uuid)}, {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct snd_sof_widget, core)}, + {SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain, + offsetof(struct snd_sof_widget, comp_domain)}, }; static const struct sof_topology_token gain_tokens[] = { @@ -497,7 +529,17 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); - type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0; + switch (swidget->comp_domain) { + case SOF_COMP_DOMAIN_LL: + type = 0; + break; + case SOF_COMP_DOMAIN_DP: + type = 1; + break; + default: + type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0; + break; + } msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); return 0; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 14ba58d2be03f8..e8e8482333147f 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -109,6 +109,13 @@ enum sof_ipc4_copier_module_config_params { SOF_IPC4_COPIER_MODULE_CFG_ATTENUATION, }; +/* Scheduling domain, unset, Low Latency, or Data Processing */ +enum sof_comp_domain { + SOF_COMP_DOMAIN_UNSET = 0, /* Take domain value from manifest */ + SOF_COMP_DOMAIN_LL, /* Low Latency scheduling domain */ + SOF_COMP_DOMAIN_DP, /* Data Processing scheduling domain */ +}; + struct sof_ipc4_copier_config_set_sink_format { /* Id of sink */ u32 sink_id; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 36ab75e11779d2..db6973c8eac311 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -451,6 +451,9 @@ struct snd_sof_widget { */ bool dynamic_pipeline_widget; + /* Scheduling domain (enum sof_comp_domain), unset, Low Latency, or Data Processing */ + u32 comp_domain; + struct snd_soc_dapm_widget *widget; struct list_head list; /* list in sdev widget list */ struct snd_sof_pipeline *spipe; From 86a9b1250602d877a393dcbab5f42472f77ac0f7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 7 Aug 2025 14:36:28 -0700 Subject: [PATCH 0858/1292] hardening: Require clang 20.1.0 for __counted_by After an innocuous change in -next that modified a structure that contains __counted_by, clang-19 start crashing when building certain files in drivers/gpu/drm/xe. When assertions are enabled, the more descriptive failure is: clang: clang/lib/AST/RecordLayoutBuilder.cpp:3335: const ASTRecordLayout &clang::ASTContext::getASTRecordLayout(const RecordDecl *) const: Assertion `D && "Cannot get layout of forward declarations!"' failed. According to a reverse bisect, a tangential change to the LLVM IR generation phase of clang during the LLVM 20 development cycle [1] resolves this problem. Bump the version of clang that enables CONFIG_CC_HAS_COUNTED_BY to 20.1.0 to ensure that this issue cannot be hit. Link: https://github.com/llvm/llvm-project/commit/160fb1121cdf703c3ef5e61fb26c5659eb581489 [1] Signed-off-by: Nathan Chancellor Reviewed-by: Justin Stitt Link: https://lore.kernel.org/r/20250807-fix-counted_by-clang-19-v1-1-902c86c1d515@kernel.org Signed-off-by: Kees Cook --- init/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 83632025121937..d811cad02a7509 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -117,10 +117,11 @@ config CC_HAS_NO_PROFILE_FN_ATTR config CC_HAS_COUNTED_BY bool - # clang needs to be at least 19.1.3 to avoid __bdos miscalculations - # https://github.com/llvm/llvm-project/pull/110497 - # https://github.com/llvm/llvm-project/pull/112636 - default y if CC_IS_CLANG && CLANG_VERSION >= 190103 + # clang needs to be at least 20.1.0 to avoid potential crashes + # when building structures that contain __counted_by + # https://github.com/ClangBuiltLinux/linux/issues/2114 + # https://github.com/llvm/llvm-project/commit/160fb1121cdf703c3ef5e61fb26c5659eb581489 + default y if CC_IS_CLANG && CLANG_VERSION >= 200100 # supported since gcc 15.1.0 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896 default y if CC_IS_GCC && GCC_VERSION >= 150100 From d6a367ec6c96fc8e61b4d67e69df03565ec69fb7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 28 Aug 2025 23:49:18 +0200 Subject: [PATCH 0859/1292] netfilter: nft_flowtable.sh: re-run with random mtu sizes Jakub says: nft_flowtable.sh is one of the most flake-atious test for netdev CI currently :( The root cause is two-fold: 1. the failing part of the test is supposed to make sure that ip fragments are forwarded for offloaded flows. (flowtable has to pass them to classic forward path). path mtu discovery for these subtests is disabled. 2. nft_flowtable.sh has two passes. One with fixed mtus/file size and one where link mtus and file sizes are random. The CI failures all have same pattern: re-run with random mtus and file size: -o 27663 -l 4117 -r 10089 -s 54384840 [..] PASS: dscp_egress: dscp packet counters match FAIL: file mismatch for ns1 -> ns2 In some cases this error triggers a bit ealier, sometimes in a later subtest: re-run with random mtus and file size: -o 20201 -l 4555 -r 12657 -s 9405856 [..] PASS: dscp_egress: dscp packet counters match PASS: dscp_fwd: dscp packet counters match 2025/08/17 20:37:52 socat[18954] E write(7, 0x560716b96000, 8192): Broken pipe FAIL: file mismatch for ns1 -> ns2 -rw------- 1 root root 9405856 Aug 17 20:36 /tmp/tmp.2n63vlTrQe But all logs I saw show same scenario: 1. Failing tests have pmtu discovery off (i.e., ip fragmentation) 2. The test file is much larger than first-pass default (2M Byte) 3. peers have much larger MTUs compared to the 'network'. These errors are very reproducible when re-running the test with the same commandline arguments. The timeout became much more prominent with 1d2fbaad7cd8 ("tcp: stronger sk_rcvbuf checks"): reassembled packets typically have a skb->truesize more than double the skb length. As that commit is intentional and pmtud-off with large-tcp-packets-as-fragments is not normal adjust the test to use a smaller file for the pmtu-off subtests. While at it, add more information to pass/fail messages and also run the dscp alteration subtest with pmtu discovery enabled. Link: https://netdev.bots.linux.dev/contest.html?test=nft-flowtable-sh Fixes: f84ab634904c ("selftests: netfilter: nft_flowtable.sh: re-run with random mtu sizes") Reported-by: Jakub Kicinski Closes: https://lore.kernel.org/netdev/20250822071330.4168f0db@kernel.org/ Signed-off-by: Florian Westphal Link: https://patch.msgid.link/20250828214918.3385-1-fw@strlen.de Signed-off-by: Jakub Kicinski --- .../selftests/net/netfilter/nft_flowtable.sh | 113 ++++++++++++------ 1 file changed, 76 insertions(+), 37 deletions(-) diff --git a/tools/testing/selftests/net/netfilter/nft_flowtable.sh b/tools/testing/selftests/net/netfilter/nft_flowtable.sh index a4ee5496f2a17c..45832df982950c 100755 --- a/tools/testing/selftests/net/netfilter/nft_flowtable.sh +++ b/tools/testing/selftests/net/netfilter/nft_flowtable.sh @@ -20,6 +20,7 @@ ret=0 SOCAT_TIMEOUT=60 nsin="" +nsin_small="" ns1out="" ns2out="" @@ -36,7 +37,7 @@ cleanup() { cleanup_all_ns - rm -f "$nsin" "$ns1out" "$ns2out" + rm -f "$nsin" "$nsin_small" "$ns1out" "$ns2out" [ "$log_netns" -eq 0 ] && sysctl -q net.netfilter.nf_log_all_netns="$log_netns" } @@ -72,6 +73,7 @@ lmtu=1500 rmtu=2000 filesize=$((2 * 1024 * 1024)) +filesize_small=$((filesize / 16)) usage(){ echo "nft_flowtable.sh [OPTIONS]" @@ -89,7 +91,10 @@ do o) omtu=$OPTARG;; l) lmtu=$OPTARG;; r) rmtu=$OPTARG;; - s) filesize=$OPTARG;; + s) + filesize=$OPTARG + filesize_small=$((OPTARG / 16)) + ;; *) usage;; esac done @@ -215,6 +220,7 @@ if ! ip netns exec "$ns2" ping -c 1 -q 10.0.1.99 > /dev/null; then fi nsin=$(mktemp) +nsin_small=$(mktemp) ns1out=$(mktemp) ns2out=$(mktemp) @@ -265,6 +271,7 @@ check_counters() check_dscp() { local what=$1 + local pmtud="$2" local ok=1 local counter @@ -277,37 +284,39 @@ check_dscp() local pc4z=${counter%*bytes*} local pc4z=${pc4z#*packets} + local failmsg="FAIL: pmtu $pmtu: $what counters do not match, expected" + case "$what" in "dscp_none") if [ "$pc4" -gt 0 ] || [ "$pc4z" -eq 0 ]; then - echo "FAIL: dscp counters do not match, expected dscp3 == 0, dscp0 > 0, but got $pc4,$pc4z" 1>&2 + echo "$failmsg dscp3 == 0, dscp0 > 0, but got $pc4,$pc4z" 1>&2 ret=1 ok=0 fi ;; "dscp_fwd") if [ "$pc4" -eq 0 ] || [ "$pc4z" -eq 0 ]; then - echo "FAIL: dscp counters do not match, expected dscp3 and dscp0 > 0 but got $pc4,$pc4z" 1>&2 + echo "$failmsg dscp3 and dscp0 > 0 but got $pc4,$pc4z" 1>&2 ret=1 ok=0 fi ;; "dscp_ingress") if [ "$pc4" -eq 0 ] || [ "$pc4z" -gt 0 ]; then - echo "FAIL: dscp counters do not match, expected dscp3 > 0, dscp0 == 0 but got $pc4,$pc4z" 1>&2 + echo "$failmsg dscp3 > 0, dscp0 == 0 but got $pc4,$pc4z" 1>&2 ret=1 ok=0 fi ;; "dscp_egress") if [ "$pc4" -eq 0 ] || [ "$pc4z" -gt 0 ]; then - echo "FAIL: dscp counters do not match, expected dscp3 > 0, dscp0 == 0 but got $pc4,$pc4z" 1>&2 + echo "$failmsg dscp3 > 0, dscp0 == 0 but got $pc4,$pc4z" 1>&2 ret=1 ok=0 fi ;; *) - echo "FAIL: Unknown DSCP check" 1>&2 + echo "$failmsg: Unknown DSCP check" 1>&2 ret=1 ok=0 esac @@ -319,9 +328,9 @@ check_dscp() check_transfer() { - in=$1 - out=$2 - what=$3 + local in=$1 + local out=$2 + local what=$3 if ! cmp "$in" "$out" > /dev/null 2>&1; then echo "FAIL: file mismatch for $what" 1>&2 @@ -342,25 +351,39 @@ test_tcp_forwarding_ip() { local nsa=$1 local nsb=$2 - local dstip=$3 - local dstport=$4 + local pmtu=$3 + local dstip=$4 + local dstport=$5 local lret=0 + local socatc + local socatl + local infile="$nsin" + + if [ $pmtu -eq 0 ]; then + infile="$nsin_small" + fi - timeout "$SOCAT_TIMEOUT" ip netns exec "$nsb" socat -4 TCP-LISTEN:12345,reuseaddr STDIO < "$nsin" > "$ns2out" & + timeout "$SOCAT_TIMEOUT" ip netns exec "$nsb" socat -4 TCP-LISTEN:12345,reuseaddr STDIO < "$infile" > "$ns2out" & lpid=$! busywait 1000 listener_ready - timeout "$SOCAT_TIMEOUT" ip netns exec "$nsa" socat -4 TCP:"$dstip":"$dstport" STDIO < "$nsin" > "$ns1out" + timeout "$SOCAT_TIMEOUT" ip netns exec "$nsa" socat -4 TCP:"$dstip":"$dstport" STDIO < "$infile" > "$ns1out" + socatc=$? wait $lpid + socatl=$? - if ! check_transfer "$nsin" "$ns2out" "ns1 -> ns2"; then + if [ $socatl -ne 0 ] || [ $socatc -ne 0 ];then + rc=1 + fi + + if ! check_transfer "$infile" "$ns2out" "ns1 -> ns2"; then lret=1 ret=1 fi - if ! check_transfer "$nsin" "$ns1out" "ns1 <- ns2"; then + if ! check_transfer "$infile" "$ns1out" "ns1 <- ns2"; then lret=1 ret=1 fi @@ -370,14 +393,16 @@ test_tcp_forwarding_ip() test_tcp_forwarding() { - test_tcp_forwarding_ip "$1" "$2" 10.0.2.99 12345 + local pmtu="$3" + + test_tcp_forwarding_ip "$1" "$2" "$pmtu" 10.0.2.99 12345 return $? } test_tcp_forwarding_set_dscp() { - check_dscp "dscp_none" + local pmtu="$3" ip netns exec "$nsr1" nft -f - <&2 @@ -489,8 +519,9 @@ table ip nat { } EOF +check_dscp "dscp_none" "0" if ! test_tcp_forwarding_set_dscp "$ns1" "$ns2" 0 ""; then - echo "FAIL: flow offload for ns1/ns2 with dscp update" 1>&2 + echo "FAIL: flow offload for ns1/ns2 with dscp update and no pmtu discovery" 1>&2 exit 0 fi @@ -512,6 +543,14 @@ ip netns exec "$ns2" sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null # are lower than file size and packets were forwarded via flowtable layer. # For earlier tests (large mtus), packets cannot be handled via flowtable # (except pure acks and other small packets). +ip netns exec "$nsr1" nft reset counters table inet filter >/dev/null +ip netns exec "$ns2" nft reset counters table inet filter >/dev/null + +if ! test_tcp_forwarding_set_dscp "$ns1" "$ns2" 1 ""; then + echo "FAIL: flow offload for ns1/ns2 with dscp update and pmtu discovery" 1>&2 + exit 0 +fi + ip netns exec "$nsr1" nft reset counters table inet filter >/dev/null if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 ""; then @@ -644,7 +683,7 @@ ip -net "$ns2" route del 192.168.10.1 via 10.0.2.1 ip -net "$ns2" route add default via 10.0.2.1 ip -net "$ns2" route add default via dead:2::1 -if test_tcp_forwarding "$ns1" "$ns2"; then +if test_tcp_forwarding "$ns1" "$ns2" 1; then check_counters "ipsec tunnel mode for ns1/ns2" else echo "FAIL: ipsec tunnel mode for ns1/ns2" @@ -668,7 +707,7 @@ if [ "$1" = "" ]; then fi echo "re-run with random mtus and file size: -o $o -l $l -r $r -s $filesize" - $0 -o "$o" -l "$l" -r "$r" -s "$filesize" + $0 -o "$o" -l "$l" -r "$r" -s "$filesize" || ret=1 fi exit $ret From 9f74c0ea9b26d1505d55b61e36b1623dd347e1d1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Aug 2025 16:23:52 +0000 Subject: [PATCH 0860/1292] net_sched: gen_estimator: fix est_timer() vs CONFIG_PREEMPT_RT=y syzbot reported a WARNING in est_timer() [1] Problem here is that with CONFIG_PREEMPT_RT=y, timer callbacks can be preempted. Adopt preempt_disable_nested()/preempt_enable_nested() to fix this. [1] WARNING: CPU: 0 PID: 16 at ./include/linux/seqlock.h:221 __seqprop_assert include/linux/seqlock.h:221 [inline] WARNING: CPU: 0 PID: 16 at ./include/linux/seqlock.h:221 est_timer+0x6dc/0x9f0 net/core/gen_estimator.c:93 Modules linked in: CPU: 0 UID: 0 PID: 16 Comm: ktimers/0 Not tainted syzkaller #0 PREEMPT_{RT,(full)} Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/12/2025 RIP: 0010:__seqprop_assert include/linux/seqlock.h:221 [inline] RIP: 0010:est_timer+0x6dc/0x9f0 net/core/gen_estimator.c:93 Call Trace: call_timer_fn+0x17e/0x5f0 kernel/time/timer.c:1747 expire_timers kernel/time/timer.c:1798 [inline] __run_timers kernel/time/timer.c:2372 [inline] __run_timer_base+0x648/0x970 kernel/time/timer.c:2384 run_timer_base kernel/time/timer.c:2393 [inline] run_timer_softirq+0xb7/0x180 kernel/time/timer.c:2403 handle_softirqs+0x22c/0x710 kernel/softirq.c:579 __do_softirq kernel/softirq.c:613 [inline] run_ktimerd+0xcf/0x190 kernel/softirq.c:1043 smpboot_thread_fn+0x53f/0xa60 kernel/smpboot.c:160 kthread+0x70e/0x8a0 kernel/kthread.c:463 ret_from_fork+0x3fc/0x770 arch/x86/kernel/process.c:148 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 Fixes: d2d6422f8bd1 ("x86: Allow to enable PREEMPT_RT.") Reported-by: syzbot+72db9ee39db57c3fecc5@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/68adf6fa.a70a0220.3cafd4.0000.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Reviewed-by: Sebastian Andrzej Siewior Link: https://patch.msgid.link/20250827162352.3960779-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/core/gen_estimator.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 7d426a8e29f30b..f112156db587ba 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -90,10 +90,12 @@ static void est_timer(struct timer_list *t) rate = (b_packets - est->last_packets) << (10 - est->intvl_log); rate = (rate >> est->ewma_log) - (est->avpps >> est->ewma_log); + preempt_disable_nested(); write_seqcount_begin(&est->seq); est->avbps += brate; est->avpps += rate; write_seqcount_end(&est->seq); + preempt_enable_nested(); est->last_bytes = b_bytes; est->last_packets = b_packets; From b79e498080b170fd94fc83bca2471f450811549b Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Wed, 27 Aug 2025 12:26:43 -0700 Subject: [PATCH 0861/1292] xirc2ps_cs: fix register access when enabling FullDuplex The current code incorrectly passes (XIRCREG1_ECR | FullDuplex) as the register address to GetByte(), instead of fetching the register value and OR-ing it with FullDuplex. This results in an invalid register access. Fix it by reading XIRCREG1_ECR first, then or-ing with FullDuplex before writing it back. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Alok Tiwari Reviewed-by: Simon Horman Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20250827192645.658496-1-alok.a.tiwari@oracle.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xircom/xirc2ps_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c index a31d5d5e65936d..97e88886253f54 100644 --- a/drivers/net/ethernet/xircom/xirc2ps_cs.c +++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c @@ -1576,7 +1576,7 @@ do_reset(struct net_device *dev, int full) msleep(40); /* wait 40 msec to let it complete */ } if (full_duplex) - PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR | FullDuplex)); + PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR) | FullDuplex); } else { /* No MII */ SelectPage(0); value = GetByte(XIRCREG_ESR); /* read the ESR */ From 8bf935cf789872350b04c1a6468b0a509f67afb2 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Thu, 28 Aug 2025 16:29:49 +0800 Subject: [PATCH 0862/1292] ptp: ocp: fix use-after-free bugs causing by ptp_ocp_watchdog The ptp_ocp_detach() only shuts down the watchdog timer if it is pending. However, if the timer handler is already running, the timer_delete_sync() is not called. This leads to race conditions where the devlink that contains the ptp_ocp is deallocated while the timer handler is still accessing it, resulting in use-after-free bugs. The following details one of the race scenarios. (thread 1) | (thread 2) ptp_ocp_remove() | ptp_ocp_detach() | ptp_ocp_watchdog() if (timer_pending(&bp->watchdog))| bp = timer_container_of() timer_delete_sync() | | devlink_free(devlink) //free | | bp-> //use Resolve this by unconditionally calling timer_delete_sync() to ensure the timer is reliably deactivated, preventing any access after free. Fixes: 773bda964921 ("ptp: ocp: Expose various resources on the timecard.") Signed-off-by: Duoming Zhou Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20250828082949.28189-1-duoming@zju.edu.cn Signed-off-by: Jakub Kicinski --- drivers/ptp/ptp_ocp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index d39073dc4072d2..4e1286ce05c9af 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -4557,8 +4557,7 @@ ptp_ocp_detach(struct ptp_ocp *bp) ptp_ocp_debugfs_remove_device(bp); ptp_ocp_detach_sysfs(bp); ptp_ocp_attr_group_del(bp); - if (timer_pending(&bp->watchdog)) - timer_delete_sync(&bp->watchdog); + timer_delete_sync(&bp->watchdog); if (bp->ts0) ptp_ocp_unregister_ext(bp->ts0); if (bp->ts1) From 0704a3da7ce50f972e898bbda88d2692a22922d9 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 28 Aug 2025 16:14:57 +0800 Subject: [PATCH 0863/1292] mISDN: Fix memory leak in dsp_hwec_enable() dsp_hwec_enable() allocates dup pointer by kstrdup(arg), but then it updates dup variable by strsep(&dup, ","). As a result when it calls kfree(dup), the dup variable may be a modified pointer that no longer points to the original allocated memory, causing a memory leak. The issue is the same pattern as fixed in commit c6a502c22999 ("mISDN: Fix memory leak in dsp_pipeline_build()"). Fixes: 9a4381618262 ("mISDN: Remove VLAs") Signed-off-by: Miaoqian Lin Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250828081457.36061-1-linmq006@gmail.com Signed-off-by: Jakub Kicinski --- drivers/isdn/mISDN/dsp_hwec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c index 0b3f29195330ac..0cd216e28f0090 100644 --- a/drivers/isdn/mISDN/dsp_hwec.c +++ b/drivers/isdn/mISDN/dsp_hwec.c @@ -51,14 +51,14 @@ void dsp_hwec_enable(struct dsp *dsp, const char *arg) goto _do; { - char *dup, *tok, *name, *val; + char *dup, *next, *tok, *name, *val; int tmp; - dup = kstrdup(arg, GFP_ATOMIC); + dup = next = kstrdup(arg, GFP_ATOMIC); if (!dup) return; - while ((tok = strsep(&dup, ","))) { + while ((tok = strsep(&next, ","))) { if (!strlen(tok)) continue; name = strsep(&tok, "="); From b3852ae3105ec1048535707545d23c1e519c190f Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 27 Aug 2025 13:53:39 +0200 Subject: [PATCH 0864/1292] net: ethernet: oa_tc6: Handle failure of spi_setup There is no guarantee that spi_setup succeed, so properly handle the error case. Fixes: aa58bec064ab ("net: ethernet: oa_tc6: implement register write operation") Signed-off-by: Stefan Wahren Cc: stable@kernel.org Reviewed-by: Andrew Lunn Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20250827115341.34608-2-wahrenst@gmx.net Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/oa_tc6.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index db200e4ec284d7..91a906a7918a25 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -1249,7 +1249,8 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev) /* Set the SPI controller to pump at realtime priority */ tc6->spi->rt = true; - spi_setup(tc6->spi); + if (spi_setup(tc6->spi) < 0) + return NULL; tc6->spi_ctrl_tx_buf = devm_kzalloc(&tc6->spi->dev, OA_TC6_CTRL_SPI_BUF_SIZE, From c7217963eb779be0a7627dd2121152fa6786ecf7 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 27 Aug 2025 13:53:40 +0200 Subject: [PATCH 0865/1292] microchip: lan865x: Fix module autoloading Add MODULE_DEVICE_TABLE(), so modules could be properly autoloaded based on the alias from spi_device_id table. While at this, fix the misleading variable name (spidev is unrelated to this driver). Fixes: 5cd2340cb6a3 ("microchip: lan865x: add driver support for Microchip's LAN865X MAC-PHY") Signed-off-by: Stefan Wahren Cc: stable@kernel.org Reviewed-by: Andrew Lunn Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20250827115341.34608-3-wahrenst@gmx.net Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan865x/lan865x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net/ethernet/microchip/lan865x/lan865x.c index 84c41f19356126..9d94c8fb8b9112 100644 --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c @@ -423,10 +423,11 @@ static void lan865x_remove(struct spi_device *spi) free_netdev(priv->netdev); } -static const struct spi_device_id spidev_spi_ids[] = { +static const struct spi_device_id lan865x_ids[] = { { .name = "lan8650" }, {}, }; +MODULE_DEVICE_TABLE(spi, lan865x_ids); static const struct of_device_id lan865x_dt_ids[] = { { .compatible = "microchip,lan8650" }, @@ -441,7 +442,7 @@ static struct spi_driver lan865x_driver = { }, .probe = lan865x_probe, .remove = lan865x_remove, - .id_table = spidev_spi_ids, + .id_table = lan865x_ids, }; module_spi_driver(lan865x_driver); From ca47c44d36a9ad3268d17f89789104a471c07f81 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 27 Aug 2025 13:53:41 +0200 Subject: [PATCH 0866/1292] microchip: lan865x: Fix LAN8651 autoloading Add missing IDs for LAN8651 devices, which are also defined in the DT bindings. Fixes: 5cd2340cb6a3 ("microchip: lan865x: add driver support for Microchip's LAN865X MAC-PHY") Signed-off-by: Stefan Wahren Cc: stable@kernel.org Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20250827115341.34608-4-wahrenst@gmx.net Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan865x/lan865x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net/ethernet/microchip/lan865x/lan865x.c index 9d94c8fb8b9112..79b800d2b72c28 100644 --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c @@ -425,12 +425,14 @@ static void lan865x_remove(struct spi_device *spi) static const struct spi_device_id lan865x_ids[] = { { .name = "lan8650" }, + { .name = "lan8651" }, {}, }; MODULE_DEVICE_TABLE(spi, lan865x_ids); static const struct of_device_id lan865x_dt_ids[] = { { .compatible = "microchip,lan8650" }, + { .compatible = "microchip,lan8651" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, lan865x_dt_ids); From aea3493246c474bc917d124d6fb627663ab6bef0 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 30 Aug 2025 08:37:49 +0900 Subject: [PATCH 0867/1292] ALSA: firewire-motu: drop EPOLLOUT from poll return values as write is not supported The ALSA HwDep character device of the firewire-motu driver incorrectly returns EPOLLOUT in poll(2), even though the driver implements no operation for write(2). This misleads userspace applications to believe write() is allowed, potentially resulting in unnecessarily wakeups. This issue dates back to the driver's initial code added by a commit 71c3797779d3 ("ALSA: firewire-motu: add hwdep interface"), and persisted when POLLOUT was updated to EPOLLOUT by a commit a9a08845e9ac ('vfs: do bulk POLL* -> EPOLL* replacement("").'). This commit fixes the bug. Signed-off-by: Takashi Sakamoto Link: https://patch.msgid.link/20250829233749.366222-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-hwdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c index 1ed60618220d27..fa2685665db3af 100644 --- a/sound/firewire/motu/motu-hwdep.c +++ b/sound/firewire/motu/motu-hwdep.c @@ -111,7 +111,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, events = 0; spin_unlock_irq(&motu->lock); - return events | EPOLLOUT; + return events; } static int hwdep_get_info(struct snd_motu *motu, void __user *arg) From e5a00dafc7e06ab1b20fd4c1535cfa9b9940061e Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 29 Aug 2025 18:04:49 +0200 Subject: [PATCH 0868/1292] ALSA: hda: tas2781: fix tas2563 EFI data endianness Before conversion to unify the calibration data management, the tas2563_apply_calib() function performed the big endian conversion and wrote the calibration data to the device. The writing is now done by the common tasdev_load_calibrated_data() function, but without conversion. Put the values into the calibration data buffer with the expected endianness. Fixes: 4fe238513407 ("ALSA: hda/tas2781: Move and unified the calibrated-data getting function for SPI and I2C into the tas2781_hda lib") Cc: Signed-off-by: Gergo Koteles Link: https://patch.msgid.link/20250829160450.66623-1-soyer@irl.hu Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index 7143926c2c30f3..46a43f0352aa1a 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -310,6 +310,7 @@ static int tas2563_save_calibration(struct tas2781_hda *h) struct cali_reg *r = &cd->cali_reg_array; unsigned int offset = 0; unsigned char *data; + __be32 bedata; efi_status_t status; unsigned int attr; int ret, i, j, k; @@ -351,6 +352,8 @@ static int tas2563_save_calibration(struct tas2781_hda *h) i, j, status); return -EINVAL; } + bedata = cpu_to_be32(*(uint32_t *)&data[offset]); + memcpy(&data[offset], &bedata, sizeof(bedata)); offset += TAS2563_CAL_DATA_SIZE; } } From d5f8458e34a331e5b228de142145e62ac5bfda34 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Fri, 29 Aug 2025 18:04:50 +0200 Subject: [PATCH 0869/1292] ALSA: hda: tas2781: reorder tas2563 calibration variables The tasdev_load_calibrated_data() function expects the calibration data values in the cali_data buffer as R0, R0Low, InvR0, Power, TLim which is not the same as what tas2563_save_calibration() writes to the buffer. Reorder the EFI variables in the tas2563_save_calibration() function to put the values in the buffer in the correct order. Fixes: 4fe238513407 ("ALSA: hda/tas2781: Move and unified the calibrated-data getting function for SPI and I2C into the tas2781_hda lib") Cc: Signed-off-by: Gergo Koteles Link: https://patch.msgid.link/20250829160450.66623-2-soyer@irl.hu Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index 46a43f0352aa1a..45a70fbf620537 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -300,7 +300,7 @@ static int tas2563_save_calibration(struct tas2781_hda *h) { efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO]; char *vars[TASDEV_CALIB_N] = { - "R0_%d", "InvR0_%d", "R0_Low_%d", "Power_%d", "TLim_%d" + "R0_%d", "R0_Low_%d", "InvR0_%d", "Power_%d", "TLim_%d" }; efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX]; unsigned long max_size = TAS2563_CAL_DATA_SIZE; From 34d988f095f238114968c3fb7cf7fb7e38cb91f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:05 +0200 Subject: [PATCH 0870/1292] ALSA: firewire: bebob: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-2-tiwai@suse.de --- sound/firewire/bebob/bebob.c | 36 +++++++-------- sound/firewire/bebob/bebob_maudio.c | 42 +++++++---------- sound/firewire/bebob/bebob_midi.c | 24 +++++----- sound/firewire/bebob/bebob_pcm.c | 70 +++++++++++++---------------- 4 files changed, 73 insertions(+), 99 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 4ebaeff164552e..01e2c4cc03d4d5 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -122,9 +122,9 @@ bebob_card_free(struct snd_card *card) { struct snd_bebob *bebob = card->private_data; - mutex_lock(&devices_mutex); - clear_bit(bebob->card_index, devices_used); - mutex_unlock(&devices_mutex); + scoped_guard(mutex, &devices_mutex) { + clear_bit(bebob->card_index, devices_used); + } snd_bebob_stream_destroy_duplex(bebob); @@ -207,25 +207,21 @@ static int bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *en return -ENODEV; } - mutex_lock(&devices_mutex); - for (card_index = 0; card_index < SNDRV_CARDS; card_index++) { - if (!test_bit(card_index, devices_used) && enable[card_index]) - break; - } - if (card_index >= SNDRV_CARDS) { - mutex_unlock(&devices_mutex); - return -ENOENT; - } + scoped_guard(mutex, &devices_mutex) { + for (card_index = 0; card_index < SNDRV_CARDS; card_index++) { + if (!test_bit(card_index, devices_used) && enable[card_index]) + break; + } + if (card_index >= SNDRV_CARDS) + return -ENOENT; - err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE, - sizeof(*bebob), &card); - if (err < 0) { - mutex_unlock(&devices_mutex); - return err; + err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE, + sizeof(*bebob), &card); + if (err < 0) + return err; + card->private_free = bebob_card_free; + set_bit(card_index, devices_used); } - card->private_free = bebob_card_free; - set_bit(card_index, devices_used); - mutex_unlock(&devices_mutex); bebob = card->private_data; bebob->unit = fw_unit_get(unit); diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index 177699e1be115f..376a9a17547956 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -265,7 +265,7 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814) if (!params) return -ENOMEM; - mutex_lock(&bebob->mutex); + guard(mutex)(&bebob->mutex); bebob->maudio_special_quirk = (void *)params; params->is1814 = is1814; @@ -277,12 +277,12 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814) if (err < 0) { dev_err(&bebob->unit->device, "fail to initialize clock params: %d\n", err); - goto end; + return err; } err = add_special_controls(bebob); if (err < 0) - goto end; + return err; special_stream_formation_set(bebob); @@ -293,8 +293,6 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814) bebob->midi_input_ports = 2; bebob->midi_output_ports = 2; } -end: - mutex_unlock(&bebob->mutex); return err; } @@ -383,14 +381,12 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl, if (id >= ARRAY_SIZE(special_clk_types)) return -EINVAL; - mutex_lock(&bebob->mutex); + guard(mutex)(&bebob->mutex); err = avc_maudio_set_special_clk(bebob, id, params->dig_in_fmt, params->dig_out_fmt, params->clk_lock); - mutex_unlock(&bebob->mutex); - if (err >= 0) err = 1; @@ -456,14 +452,14 @@ static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl, unsigned int dig_in_iface; int err, val; - mutex_lock(&bebob->mutex); + guard(mutex)(&bebob->mutex); err = avc_audio_get_selector(bebob->unit, 0x00, 0x04, &dig_in_iface); if (err < 0) { dev_err(&bebob->unit->device, "fail to get digital input interface: %d\n", err); - goto end; + return err; } /* encoded id for user value */ @@ -474,9 +470,7 @@ static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl, val = 2; uval->value.enumerated.item[0] = val; -end: - mutex_unlock(&bebob->mutex); - return err; + return 0; } static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uval) @@ -494,7 +488,7 @@ static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl, dig_in_fmt = (id >> 1) & 0x01; dig_in_iface = id & 0x01; - mutex_lock(&bebob->mutex); + guard(mutex)(&bebob->mutex); err = avc_maudio_set_special_clk(bebob, params->clk_src, @@ -502,24 +496,19 @@ static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl, params->dig_out_fmt, params->clk_lock); if (err < 0) - goto end; + return err; /* For ADAT, optical interface is only available. */ - if (params->dig_in_fmt > 0) { - err = 1; - goto end; - } + if (params->dig_in_fmt > 0) + return 1; /* For S/PDIF, optical/coaxial interfaces are selectable. */ err = avc_audio_set_selector(bebob->unit, 0x00, 0x04, dig_in_iface); if (err < 0) dev_err(&bebob->unit->device, "fail to set digital input interface: %d\n", err); - err = 1; -end: special_stream_formation_set(bebob); - mutex_unlock(&bebob->mutex); - return err; + return 1; } static const struct snd_kcontrol_new special_dig_in_iface_ctl = { .name = "Digital Input Interface", @@ -546,9 +535,9 @@ static int special_dig_out_iface_ctl_get(struct snd_kcontrol *kctl, { struct snd_bebob *bebob = snd_kcontrol_chip(kctl); struct special_params *params = bebob->maudio_special_quirk; - mutex_lock(&bebob->mutex); + + guard(mutex)(&bebob->mutex); uval->value.enumerated.item[0] = params->dig_out_fmt; - mutex_unlock(&bebob->mutex); return 0; } static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl, @@ -563,7 +552,7 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl, if (id >= ARRAY_SIZE(special_dig_out_iface_labels)) return -EINVAL; - mutex_lock(&bebob->mutex); + guard(mutex)(&bebob->mutex); err = avc_maudio_set_special_clk(bebob, params->clk_src, @@ -574,7 +563,6 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl, err = 1; } - mutex_unlock(&bebob->mutex); return err; } static const struct snd_kcontrol_new special_dig_out_iface_ctl = { diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index b1425bf98c3bef..5fd2d363de521e 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -16,15 +16,15 @@ static int midi_open(struct snd_rawmidi_substream *substream) if (err < 0) return err; - mutex_lock(&bebob->mutex); - err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0); - if (err >= 0) { - ++bebob->substreams_counter; - err = snd_bebob_stream_start_duplex(bebob); - if (err < 0) - --bebob->substreams_counter; + scoped_guard(mutex, &bebob->mutex) { + err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0); + if (err >= 0) { + ++bebob->substreams_counter; + err = snd_bebob_stream_start_duplex(bebob); + if (err < 0) + --bebob->substreams_counter; + } } - mutex_unlock(&bebob->mutex); if (err < 0) snd_bebob_stream_lock_release(bebob); @@ -35,10 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream) { struct snd_bebob *bebob = substream->rmidi->private_data; - mutex_lock(&bebob->mutex); - bebob->substreams_counter--; - snd_bebob_stream_stop_duplex(bebob); - mutex_unlock(&bebob->mutex); + scoped_guard(mutex, &bebob->mutex) { + bebob->substreams_counter--; + snd_bebob_stream_stop_duplex(bebob); + } snd_bebob_stream_lock_release(bebob); return 0; diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 360ebf3c4ca274..692d33bac2d2a8 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -149,49 +149,42 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - mutex_lock(&bebob->mutex); - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL || - (bebob->substreams_counter > 0 && d->events_per_period > 0)) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - unsigned int sampling_rate; - - err = spec->get(bebob, &sampling_rate); - if (err < 0) { - mutex_unlock(&bebob->mutex); - dev_err(&bebob->unit->device, - "fail to get sampling rate: %d\n", err); - goto err_locked; - } - - substream->runtime->hw.rate_min = sampling_rate; - substream->runtime->hw.rate_max = sampling_rate; - - if (frames_per_period > 0) { - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); + scoped_guard(mutex, &bebob->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL || + (bebob->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + unsigned int sampling_rate; + + err = spec->get(bebob, &sampling_rate); if (err < 0) { - mutex_unlock(&bebob->mutex); + dev_err(&bebob->unit->device, + "fail to get sampling rate: %d\n", err); goto err_locked; } - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) { - mutex_unlock(&bebob->mutex); - goto err_locked; + substream->runtime->hw.rate_min = sampling_rate; + substream->runtime->hw.rate_max = sampling_rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; } } } - mutex_unlock(&bebob->mutex); - snd_pcm_set_sync(substream); return 0; @@ -219,12 +212,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&bebob->mutex); + guard(mutex)(&bebob->mutex); err = snd_bebob_stream_reserve_duplex(bebob, rate, frames_per_period, frames_per_buffer); if (err >= 0) ++bebob->substreams_counter; - mutex_unlock(&bebob->mutex); } return err; @@ -234,15 +226,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; - mutex_lock(&bebob->mutex); + guard(mutex)(&bebob->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) bebob->substreams_counter--; snd_bebob_stream_stop_duplex(bebob); - mutex_unlock(&bebob->mutex); - return 0; } From 089843177f35de2d020be6aa35c00a843873a538 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:06 +0200 Subject: [PATCH 0871/1292] ALSA: firewire: dice: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-3-tiwai@suse.de --- sound/firewire/dice/dice-midi.c | 28 +++++----- sound/firewire/dice/dice-pcm.c | 93 +++++++++++++++------------------ sound/firewire/dice/dice.c | 3 +- 3 files changed, 54 insertions(+), 70 deletions(-) diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index 78988e44b8bcd2..9ca975c556ca71 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -15,18 +15,16 @@ static int midi_open(struct snd_rawmidi_substream *substream) if (err < 0) return err; - mutex_lock(&dice->mutex); - - err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0); - if (err >= 0) { - ++dice->substreams_counter; - err = snd_dice_stream_start_duplex(dice); - if (err < 0) - --dice->substreams_counter; + scoped_guard(mutex, &dice->mutex) { + err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0); + if (err >= 0) { + ++dice->substreams_counter; + err = snd_dice_stream_start_duplex(dice); + if (err < 0) + --dice->substreams_counter; + } } - mutex_unlock(&dice->mutex); - if (err < 0) snd_dice_stream_lock_release(dice); @@ -37,12 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream) { struct snd_dice *dice = substream->rmidi->private_data; - mutex_lock(&dice->mutex); - - --dice->substreams_counter; - snd_dice_stream_stop_duplex(dice); - - mutex_unlock(&dice->mutex); + scoped_guard(mutex, &dice->mutex) { + --dice->substreams_counter; + snd_dice_stream_stop_duplex(dice); + } snd_dice_stream_lock_release(dice); return 0; diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index cfc19bd0d5dd4e..d5319cd2cc6f1a 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -196,53 +196,45 @@ static int pcm_open(struct snd_pcm_substream *substream) break; } - mutex_lock(&dice->mutex); - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if (!internal || - (dice->substreams_counter > 0 && d->events_per_period > 0)) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - unsigned int rate; - - err = snd_dice_transaction_get_rate(dice, &rate); - if (err < 0) { - mutex_unlock(&dice->mutex); - goto err_locked; - } - - substream->runtime->hw.rate_min = rate; - substream->runtime->hw.rate_max = rate; - - if (frames_per_period > 0) { - // For double_pcm_frame quirk. - if (rate > 96000 && !dice->disable_double_pcm_frames) { - frames_per_period *= 2; - frames_per_buffer *= 2; - } - - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); - if (err < 0) { - mutex_unlock(&dice->mutex); + scoped_guard(mutex, &dice->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (!internal || + (dice->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + unsigned int rate; + + err = snd_dice_transaction_get_rate(dice, &rate); + if (err < 0) goto err_locked; - } - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) { - mutex_unlock(&dice->mutex); - goto err_locked; + substream->runtime->hw.rate_min = rate; + substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + // For double_pcm_frame quirk. + if (rate > 96000 && !dice->disable_double_pcm_frames) { + frames_per_period *= 2; + frames_per_buffer *= 2; + } + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; } } } - mutex_unlock(&dice->mutex); - snd_pcm_set_sync(substream); return 0; @@ -271,7 +263,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, unsigned int events_per_period = params_period_size(hw_params); unsigned int events_per_buffer = params_buffer_size(hw_params); - mutex_lock(&dice->mutex); + guard(mutex)(&dice->mutex); // For double_pcm_frame quirk. if (rate > 96000 && !dice->disable_double_pcm_frames) { events_per_period /= 2; @@ -281,7 +273,6 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, events_per_period, events_per_buffer); if (err >= 0) ++dice->substreams_counter; - mutex_unlock(&dice->mutex); } return err; @@ -291,15 +282,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; - mutex_lock(&dice->mutex); + guard(mutex)(&dice->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --dice->substreams_counter; snd_dice_stream_stop_duplex(dice); - mutex_unlock(&dice->mutex); - return 0; } @@ -309,9 +298,9 @@ static int capture_prepare(struct snd_pcm_substream *substream) struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; int err; - mutex_lock(&dice->mutex); - err = snd_dice_stream_start_duplex(dice); - mutex_unlock(&dice->mutex); + scoped_guard(mutex, &dice->mutex) { + err = snd_dice_stream_start_duplex(dice); + } if (err >= 0) amdtp_stream_pcm_prepare(stream); @@ -323,9 +312,9 @@ static int playback_prepare(struct snd_pcm_substream *substream) struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; int err; - mutex_lock(&dice->mutex); - err = snd_dice_stream_start_duplex(dice); - mutex_unlock(&dice->mutex); + scoped_guard(mutex, &dice->mutex) { + err = snd_dice_stream_start_duplex(dice); + } if (err >= 0) amdtp_stream_pcm_prepare(stream); diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 9675ec14271d04..bcbe80344328e7 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -238,9 +238,8 @@ static void dice_bus_reset(struct fw_unit *unit) /* The handler address register becomes initialized. */ snd_dice_transaction_reinit(dice); - mutex_lock(&dice->mutex); + guard(mutex)(&dice->mutex); snd_dice_stream_update_duplex(dice); - mutex_unlock(&dice->mutex); } #define DICE_INTERFACE 0x000001 From a4b45e101d14718f534541c6a32ddfb26dc76a6d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:07 +0200 Subject: [PATCH 0872/1292] ALSA: firewire: digi00x: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-4-tiwai@suse.de --- sound/firewire/digi00x/digi00x-midi.c | 24 ++++----- sound/firewire/digi00x/digi00x-pcm.c | 77 +++++++++++---------------- sound/firewire/digi00x/digi00x.c | 3 +- 3 files changed, 44 insertions(+), 60 deletions(-) diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index 8f4bace16050a1..0f6ca58cc4a0d5 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c @@ -16,15 +16,15 @@ static int midi_open(struct snd_rawmidi_substream *substream) if (err < 0) return err; - mutex_lock(&dg00x->mutex); - err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0); - if (err >= 0) { - ++dg00x->substreams_counter; - err = snd_dg00x_stream_start_duplex(dg00x); - if (err < 0) - --dg00x->substreams_counter; + scoped_guard(mutex, &dg00x->mutex) { + err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0); + if (err >= 0) { + ++dg00x->substreams_counter; + err = snd_dg00x_stream_start_duplex(dg00x); + if (err < 0) + --dg00x->substreams_counter; + } } - mutex_unlock(&dg00x->mutex); if (err < 0) snd_dg00x_stream_lock_release(dg00x); @@ -35,10 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream) { struct snd_dg00x *dg00x = substream->rmidi->private_data; - mutex_lock(&dg00x->mutex); - --dg00x->substreams_counter; - snd_dg00x_stream_stop_duplex(dg00x); - mutex_unlock(&dg00x->mutex); + scoped_guard(mutex, &dg00x->mutex) { + --dg00x->substreams_counter; + snd_dg00x_stream_stop_duplex(dg00x); + } snd_dg00x_stream_lock_release(dg00x); return 0; diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 85e65cbc00c4b4..75f81545d50c36 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -127,46 +127,38 @@ static int pcm_open(struct snd_pcm_substream *substream) } } - mutex_lock(&dg00x->mutex); - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if ((clock != SND_DG00X_CLOCK_INTERNAL) || - (dg00x->substreams_counter > 0 && d->events_per_period > 0)) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - unsigned int rate; - - err = snd_dg00x_stream_get_external_rate(dg00x, &rate); - if (err < 0) { - mutex_unlock(&dg00x->mutex); - goto err_locked; - } - substream->runtime->hw.rate_min = rate; - substream->runtime->hw.rate_max = rate; - - if (frames_per_period > 0) { - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); - if (err < 0) { - mutex_unlock(&dg00x->mutex); - goto err_locked; - } - - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) { - mutex_unlock(&dg00x->mutex); + scoped_guard(mutex, &dg00x->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if ((clock != SND_DG00X_CLOCK_INTERNAL) || + (dg00x->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + unsigned int rate; + + err = snd_dg00x_stream_get_external_rate(dg00x, &rate); + if (err < 0) goto err_locked; + substream->runtime->hw.rate_min = rate; + substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; } } } - mutex_unlock(&dg00x->mutex); - snd_pcm_set_sync(substream); return 0; @@ -195,12 +187,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&dg00x->mutex); + guard(mutex)(&dg00x->mutex); err = snd_dg00x_stream_reserve_duplex(dg00x, rate, frames_per_period, frames_per_buffer); if (err >= 0) ++dg00x->substreams_counter; - mutex_unlock(&dg00x->mutex); } return err; @@ -210,15 +201,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_dg00x *dg00x = substream->private_data; - mutex_lock(&dg00x->mutex); + guard(mutex)(&dg00x->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --dg00x->substreams_counter; snd_dg00x_stream_stop_duplex(dg00x); - mutex_unlock(&dg00x->mutex); - return 0; } @@ -227,14 +216,12 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) struct snd_dg00x *dg00x = substream->private_data; int err; - mutex_lock(&dg00x->mutex); + guard(mutex)(&dg00x->mutex); err = snd_dg00x_stream_start_duplex(dg00x); if (err >= 0) amdtp_stream_pcm_prepare(&dg00x->tx_stream); - mutex_unlock(&dg00x->mutex); - return err; } @@ -243,7 +230,7 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream) struct snd_dg00x *dg00x = substream->private_data; int err; - mutex_lock(&dg00x->mutex); + guard(mutex)(&dg00x->mutex); err = snd_dg00x_stream_start_duplex(dg00x); if (err >= 0) { @@ -251,8 +238,6 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream) amdtp_dot_reset(&dg00x->rx_stream); } - mutex_unlock(&dg00x->mutex); - return err; } diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index cebc35dcf8cd1a..f73a9fc8adb17b 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -116,9 +116,8 @@ static void snd_dg00x_update(struct fw_unit *unit) snd_dg00x_transaction_reregister(dg00x); - mutex_lock(&dg00x->mutex); + guard(mutex)(&dg00x->mutex); snd_dg00x_stream_update_duplex(dg00x); - mutex_unlock(&dg00x->mutex); } static void snd_dg00x_remove(struct fw_unit *unit) From 760c91a25af4f240d199cf719f008e7a98ab246b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:08 +0200 Subject: [PATCH 0873/1292] ALSA: firewire: fireworks: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-5-tiwai@suse.de --- sound/firewire/fireworks/fireworks.c | 41 ++++++-------- sound/firewire/fireworks/fireworks_midi.c | 29 +++++----- sound/firewire/fireworks/fireworks_pcm.c | 69 ++++++++++------------- 3 files changed, 61 insertions(+), 78 deletions(-) diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 69f722244362ef..3378c7dce88a2c 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -188,9 +188,9 @@ efw_card_free(struct snd_card *card) { struct snd_efw *efw = card->private_data; - mutex_lock(&devices_mutex); - clear_bit(efw->card_index, devices_used); - mutex_unlock(&devices_mutex); + scoped_guard(mutex, &devices_mutex) { + clear_bit(efw->card_index, devices_used); + } snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); @@ -207,25 +207,21 @@ static int efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entr int err; // check registered cards. - mutex_lock(&devices_mutex); - for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) { - if (!test_bit(card_index, devices_used) && enable[card_index]) - break; - } - if (card_index >= SNDRV_CARDS) { - mutex_unlock(&devices_mutex); - return -ENOENT; - } - - err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE, - sizeof(*efw), &card); - if (err < 0) { - mutex_unlock(&devices_mutex); - return err; + scoped_guard(mutex, &devices_mutex) { + for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) { + if (!test_bit(card_index, devices_used) && enable[card_index]) + break; + } + if (card_index >= SNDRV_CARDS) + return -ENOENT; + + err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE, + sizeof(*efw), &card); + if (err < 0) + return err; + card->private_free = efw_card_free; + set_bit(card_index, devices_used); } - card->private_free = efw_card_free; - set_bit(card_index, devices_used); - mutex_unlock(&devices_mutex); efw = card->private_data; efw->unit = fw_unit_get(unit); @@ -287,9 +283,8 @@ static void efw_update(struct fw_unit *unit) snd_efw_transaction_bus_reset(efw->unit); - mutex_lock(&efw->mutex); + guard(mutex)(&efw->mutex); snd_efw_stream_update_duplex(efw); - mutex_unlock(&efw->mutex); } static void efw_remove(struct fw_unit *unit) diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index 350bf4d299c200..90fe809a26c0b2 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -14,20 +14,19 @@ static int midi_open(struct snd_rawmidi_substream *substream) err = snd_efw_stream_lock_try(efw); if (err < 0) - goto end; - - mutex_lock(&efw->mutex); - err = snd_efw_stream_reserve_duplex(efw, 0, 0, 0); - if (err >= 0) { - ++efw->substreams_counter; - err = snd_efw_stream_start_duplex(efw); - if (err < 0) - --efw->substreams_counter; + return err; + + scoped_guard(mutex, &efw->mutex) { + err = snd_efw_stream_reserve_duplex(efw, 0, 0, 0); + if (err >= 0) { + ++efw->substreams_counter; + err = snd_efw_stream_start_duplex(efw); + if (err < 0) + --efw->substreams_counter; + } } - mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); -end: return err; } @@ -35,10 +34,10 @@ static int midi_close(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; - mutex_lock(&efw->mutex); - --efw->substreams_counter; - snd_efw_stream_stop_duplex(efw); - mutex_unlock(&efw->mutex); + scoped_guard(mutex, &efw->mutex) { + --efw->substreams_counter; + snd_efw_stream_stop_duplex(efw); + } snd_efw_stream_lock_release(efw); return 0; diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index eaf7778211de10..9399293a9fe985 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -189,46 +189,38 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - mutex_lock(&efw->mutex); - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) || - (efw->substreams_counter > 0 && d->events_per_period > 0)) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - unsigned int sampling_rate; - - err = snd_efw_command_get_sampling_rate(efw, &sampling_rate); - if (err < 0) { - mutex_unlock(&efw->mutex); - goto err_locked; - } - substream->runtime->hw.rate_min = sampling_rate; - substream->runtime->hw.rate_max = sampling_rate; - - if (frames_per_period > 0) { - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); - if (err < 0) { - mutex_unlock(&efw->mutex); - goto err_locked; - } - - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) { - mutex_unlock(&efw->mutex); + scoped_guard(mutex, &efw->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) || + (efw->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + unsigned int sampling_rate; + + err = snd_efw_command_get_sampling_rate(efw, &sampling_rate); + if (err < 0) goto err_locked; + substream->runtime->hw.rate_min = sampling_rate; + substream->runtime->hw.rate_max = sampling_rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; } } } - mutex_unlock(&efw->mutex); - snd_pcm_set_sync(substream); return 0; @@ -255,12 +247,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&efw->mutex); + guard(mutex)(&efw->mutex); err = snd_efw_stream_reserve_duplex(efw, rate, frames_per_period, frames_per_buffer); if (err >= 0) ++efw->substreams_counter; - mutex_unlock(&efw->mutex); } return err; @@ -270,15 +261,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - mutex_lock(&efw->mutex); + guard(mutex)(&efw->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --efw->substreams_counter; snd_efw_stream_stop_duplex(efw); - mutex_unlock(&efw->mutex); - return 0; } From b9ac651964c9a719cd5fba2ec99f3afb6f159232 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:09 +0200 Subject: [PATCH 0874/1292] ALSA: firewire: motu: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-6-tiwai@suse.de --- sound/firewire/motu/motu-midi.c | 28 +++++----- sound/firewire/motu/motu-pcm.c | 92 +++++++++++++++------------------ 2 files changed, 55 insertions(+), 65 deletions(-) diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c index eebc7e790ee2ab..18c5734e999fb2 100644 --- a/sound/firewire/motu/motu-midi.c +++ b/sound/firewire/motu/motu-midi.c @@ -15,18 +15,16 @@ static int midi_open(struct snd_rawmidi_substream *substream) if (err < 0) return err; - mutex_lock(&motu->mutex); - - err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0); - if (err >= 0) { - ++motu->substreams_counter; - err = snd_motu_stream_start_duplex(motu); - if (err < 0) - --motu->substreams_counter; + scoped_guard(mutex, &motu->mutex) { + err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0); + if (err >= 0) { + ++motu->substreams_counter; + err = snd_motu_stream_start_duplex(motu); + if (err < 0) + --motu->substreams_counter; + } } - mutex_unlock(&motu->mutex); - if (err < 0) snd_motu_stream_lock_release(motu); @@ -37,12 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream) { struct snd_motu *motu = substream->rmidi->private_data; - mutex_lock(&motu->mutex); - - --motu->substreams_counter; - snd_motu_stream_stop_duplex(motu); - - mutex_unlock(&motu->mutex); + scoped_guard(mutex, &motu->mutex) { + --motu->substreams_counter; + snd_motu_stream_stop_duplex(motu); + } snd_motu_stream_lock_release(motu); return 0; diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 7b4d476af348f3..600c571edf0224 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -138,59 +138,56 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) return err; - mutex_lock(&motu->mutex); - - err = snd_motu_stream_cache_packet_formats(motu); - if (err < 0) - goto err_locked; - - err = init_hw_info(motu, substream); - if (err < 0) - goto err_locked; + scoped_guard(mutex, &motu->mutex) { + err = snd_motu_stream_cache_packet_formats(motu); + if (err < 0) + goto err_locked; - err = snd_motu_protocol_get_clock_source(motu, &src); - if (err < 0) - goto err_locked; - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL && - src != SND_MOTU_CLOCK_SOURCE_SPH) || - (motu->substreams_counter > 0 && d->events_per_period > 0)) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - unsigned int rate; - - err = snd_motu_protocol_get_clock_rate(motu, &rate); + err = init_hw_info(motu, substream); if (err < 0) goto err_locked; - substream->runtime->hw.rate_min = rate; - substream->runtime->hw.rate_max = rate; + err = snd_motu_protocol_get_clock_source(motu, &src); + if (err < 0) + goto err_locked; - if (frames_per_period > 0) { - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL && + src != SND_MOTU_CLOCK_SOURCE_SPH) || + (motu->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + unsigned int rate; + + err = snd_motu_protocol_get_clock_rate(motu, &rate); if (err < 0) goto err_locked; - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) - goto err_locked; + substream->runtime->hw.rate_min = rate; + substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; + } } } snd_pcm_set_sync(substream); - mutex_unlock(&motu->mutex); - return 0; err_locked: - mutex_unlock(&motu->mutex); snd_motu_stream_lock_release(motu); return err; } @@ -215,12 +212,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&motu->mutex); + guard(mutex)(&motu->mutex); err = snd_motu_stream_reserve_duplex(motu, rate, frames_per_period, frames_per_buffer); if (err >= 0) ++motu->substreams_counter; - mutex_unlock(&motu->mutex); } return err; @@ -230,15 +226,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_motu *motu = substream->private_data; - mutex_lock(&motu->mutex); + guard(mutex)(&motu->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --motu->substreams_counter; snd_motu_stream_stop_duplex(motu); - mutex_unlock(&motu->mutex); - return 0; } @@ -247,9 +241,9 @@ static int capture_prepare(struct snd_pcm_substream *substream) struct snd_motu *motu = substream->private_data; int err; - mutex_lock(&motu->mutex); - err = snd_motu_stream_start_duplex(motu); - mutex_unlock(&motu->mutex); + scoped_guard(mutex, &motu->mutex) { + err = snd_motu_stream_start_duplex(motu); + } if (err >= 0) amdtp_stream_pcm_prepare(&motu->tx_stream); @@ -260,9 +254,9 @@ static int playback_prepare(struct snd_pcm_substream *substream) struct snd_motu *motu = substream->private_data; int err; - mutex_lock(&motu->mutex); - err = snd_motu_stream_start_duplex(motu); - mutex_unlock(&motu->mutex); + scoped_guard(mutex, &motu->mutex) { + err = snd_motu_stream_start_duplex(motu); + } if (err >= 0) amdtp_stream_pcm_prepare(&motu->rx_stream); From 751298f88e0b6a040930c51e57a5e4bd305b276e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:10 +0200 Subject: [PATCH 0875/1292] ALSA: firewire: oxfw: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-7-tiwai@suse.de --- sound/firewire/oxfw/oxfw-midi.c | 52 ++++++++----------- sound/firewire/oxfw/oxfw-pcm.c | 92 ++++++++++++++------------------- sound/firewire/oxfw/oxfw.c | 3 +- 3 files changed, 61 insertions(+), 86 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index c215fa6f7a0371..7f757f02a877c5 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -16,18 +16,16 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) if (err < 0) return err; - mutex_lock(&oxfw->mutex); - - err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0); - if (err >= 0) { - ++oxfw->substreams_count; - err = snd_oxfw_stream_start_duplex(oxfw); - if (err < 0) - --oxfw->substreams_count; + scoped_guard(mutex, &oxfw->mutex) { + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0); + if (err >= 0) { + ++oxfw->substreams_count; + err = snd_oxfw_stream_start_duplex(oxfw); + if (err < 0) + --oxfw->substreams_count; + } } - mutex_unlock(&oxfw->mutex); - if (err < 0) snd_oxfw_stream_lock_release(oxfw); @@ -43,16 +41,14 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) if (err < 0) return err; - mutex_lock(&oxfw->mutex); - - err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0); - if (err >= 0) { - ++oxfw->substreams_count; - err = snd_oxfw_stream_start_duplex(oxfw); + scoped_guard(mutex, &oxfw->mutex) { + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0); + if (err >= 0) { + ++oxfw->substreams_count; + err = snd_oxfw_stream_start_duplex(oxfw); + } } - mutex_unlock(&oxfw->mutex); - if (err < 0) snd_oxfw_stream_lock_release(oxfw); @@ -63,12 +59,10 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream) { struct snd_oxfw *oxfw = substream->rmidi->private_data; - mutex_lock(&oxfw->mutex); - - --oxfw->substreams_count; - snd_oxfw_stream_stop_duplex(oxfw); - - mutex_unlock(&oxfw->mutex); + scoped_guard(mutex, &oxfw->mutex) { + --oxfw->substreams_count; + snd_oxfw_stream_stop_duplex(oxfw); + } snd_oxfw_stream_lock_release(oxfw); return 0; @@ -78,12 +72,10 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) { struct snd_oxfw *oxfw = substream->rmidi->private_data; - mutex_lock(&oxfw->mutex); - - --oxfw->substreams_count; - snd_oxfw_stream_stop_duplex(oxfw); - - mutex_unlock(&oxfw->mutex); + scoped_guard(mutex, &oxfw->mutex) { + --oxfw->substreams_count; + snd_oxfw_stream_stop_duplex(oxfw); + } snd_oxfw_stream_lock_release(oxfw); return 0; diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index e13dc817fc2808..774b8a7637951d 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -181,42 +181,34 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - mutex_lock(&oxfw->mutex); - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if (oxfw->substreams_count > 0 && d->events_per_period > 0) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - - err = limit_to_current_params(substream); - if (err < 0) { - mutex_unlock(&oxfw->mutex); - goto err_locked; - } - - if (frames_per_period > 0) { - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); - if (err < 0) { - mutex_unlock(&oxfw->mutex); + scoped_guard(mutex, &oxfw->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (oxfw->substreams_count > 0 && d->events_per_period > 0) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + + err = limit_to_current_params(substream); + if (err < 0) goto err_locked; - } - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) { - mutex_unlock(&oxfw->mutex); - goto err_locked; + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; } } } - mutex_unlock(&oxfw->mutex); - snd_pcm_set_sync(substream); return 0; @@ -245,13 +237,12 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&oxfw->mutex); + guard(mutex)(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, rate, channels, frames_per_period, frames_per_buffer); if (err >= 0) ++oxfw->substreams_count; - mutex_unlock(&oxfw->mutex); } return err; @@ -268,13 +259,12 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&oxfw->mutex); + guard(mutex)(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, rate, channels, frames_per_period, frames_per_buffer); if (err >= 0) ++oxfw->substreams_count; - mutex_unlock(&oxfw->mutex); } return err; @@ -284,30 +274,26 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - mutex_lock(&oxfw->mutex); + guard(mutex)(&oxfw->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw); - mutex_unlock(&oxfw->mutex); - return 0; } static int pcm_playback_hw_free(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - mutex_lock(&oxfw->mutex); + guard(mutex)(&oxfw->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw); - mutex_unlock(&oxfw->mutex); - return 0; } @@ -316,30 +302,28 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) struct snd_oxfw *oxfw = substream->private_data; int err; - mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_duplex(oxfw); - mutex_unlock(&oxfw->mutex); - if (err < 0) - goto end; + scoped_guard(mutex, &oxfw->mutex) { + err = snd_oxfw_stream_start_duplex(oxfw); + if (err < 0) + return err; + } amdtp_stream_pcm_prepare(&oxfw->tx_stream); -end: - return err; + return 0; } static int pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; int err; - mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_duplex(oxfw); - mutex_unlock(&oxfw->mutex); - if (err < 0) - goto end; + scoped_guard(mutex, &oxfw->mutex) { + err = snd_oxfw_stream_start_duplex(oxfw); + if (err < 0) + return err; + } amdtp_stream_pcm_prepare(&oxfw->rx_stream); -end: - return err; + return 0; } static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 7a985f3cb8f619..5039bd79b18ed3 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -283,9 +283,8 @@ static void oxfw_bus_reset(struct fw_unit *unit) fcp_bus_reset(oxfw->unit); if (oxfw->has_output || oxfw->has_input) { - mutex_lock(&oxfw->mutex); + guard(mutex)(&oxfw->mutex); snd_oxfw_stream_update_duplex(oxfw); - mutex_unlock(&oxfw->mutex); } if (oxfw->quirks & SND_OXFW_QUIRK_SCS_TRANSACTION) From 61a5f22fb15129a90d3be6a32ce8131cb84db002 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:11 +0200 Subject: [PATCH 0876/1292] ALSA: firewire: tascam: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-8-tiwai@suse.de --- sound/firewire/tascam/tascam-pcm.c | 75 ++++++++++++------------------ sound/firewire/tascam/tascam.c | 3 +- 2 files changed, 31 insertions(+), 47 deletions(-) diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index a73003ac11e67c..d885fef0c8cae7 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -59,43 +59,35 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - mutex_lock(&tscm->mutex); - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - unsigned int rate; - - err = snd_tscm_stream_get_rate(tscm, &rate); - if (err < 0) { - mutex_unlock(&tscm->mutex); - goto err_locked; - } - substream->runtime->hw.rate_min = rate; - substream->runtime->hw.rate_max = rate; - - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); - if (err < 0) { - mutex_unlock(&tscm->mutex); - goto err_locked; - } - - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) { - mutex_unlock(&tscm->mutex); - goto err_locked; + scoped_guard(mutex, &tscm->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + unsigned int rate; + + err = snd_tscm_stream_get_rate(tscm, &rate); + if (err < 0) + goto err_locked; + substream->runtime->hw.rate_min = rate; + substream->runtime->hw.rate_max = rate; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto err_locked; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto err_locked; } } - mutex_unlock(&tscm->mutex); - snd_pcm_set_sync(substream); return 0; @@ -124,12 +116,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&tscm->mutex); + guard(mutex)(&tscm->mutex); err = snd_tscm_stream_reserve_duplex(tscm, rate, frames_per_period, frames_per_buffer); if (err >= 0) ++tscm->substreams_counter; - mutex_unlock(&tscm->mutex); } return err; @@ -139,15 +130,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_tscm *tscm = substream->private_data; - mutex_lock(&tscm->mutex); + guard(mutex)(&tscm->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --tscm->substreams_counter; snd_tscm_stream_stop_duplex(tscm); - mutex_unlock(&tscm->mutex); - return 0; } @@ -157,14 +146,12 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - mutex_lock(&tscm->mutex); + guard(mutex)(&tscm->mutex); err = snd_tscm_stream_start_duplex(tscm, runtime->rate); if (err >= 0) amdtp_stream_pcm_prepare(&tscm->tx_stream); - mutex_unlock(&tscm->mutex); - return err; } @@ -174,14 +161,12 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - mutex_lock(&tscm->mutex); + guard(mutex)(&tscm->mutex); err = snd_tscm_stream_start_duplex(tscm, runtime->rate); if (err >= 0) amdtp_stream_pcm_prepare(&tscm->rx_stream); - mutex_unlock(&tscm->mutex); - return err; } diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 4f68bb4c58bcd4..f4092df8650c3f 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -158,9 +158,8 @@ static void snd_tscm_update(struct fw_unit *unit) snd_tscm_transaction_reregister(tscm); - mutex_lock(&tscm->mutex); + guard(mutex)(&tscm->mutex); snd_tscm_stream_update_duplex(tscm); - mutex_unlock(&tscm->mutex); } static void snd_tscm_remove(struct fw_unit *unit) From a1c55ef6e959a3336e319e786428ad8cca900f77 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:12 +0200 Subject: [PATCH 0877/1292] ALSA: firewire: fireface: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-9-tiwai@suse.de --- sound/firewire/fireface/ff-pcm.c | 92 ++++++++++++++------------------ 1 file changed, 39 insertions(+), 53 deletions(-) diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 63457d24a288d8..7ad8204fbfe8bc 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -156,56 +156,49 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto release_lock; - mutex_lock(&ff->mutex); - - // When source of clock is not internal or any stream is reserved for - // transmission of PCM frames, the available sampling rate is limited - // at current one. - if (src != SND_FF_CLOCK_SRC_INTERNAL) { - for (i = 0; i < CIP_SFC_COUNT; ++i) { - if (amdtp_rate_table[i] == rate) - break; - } - - // The unit is configured at sampling frequency which packet - // streaming engine can't support. - if (i >= CIP_SFC_COUNT) { - mutex_unlock(&ff->mutex); - err = -EIO; - goto release_lock; - } - - substream->runtime->hw.rate_min = rate; - substream->runtime->hw.rate_max = rate; - } else { - if (ff->substreams_counter > 0) { - unsigned int frames_per_period = d->events_per_period; - unsigned int frames_per_buffer = d->events_per_buffer; - - rate = amdtp_rate_table[ff->rx_stream.sfc]; - substream->runtime->hw.rate_min = rate; - substream->runtime->hw.rate_max = rate; + scoped_guard(mutex, &ff->mutex) { + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (src != SND_FF_CLOCK_SRC_INTERNAL) { + for (i = 0; i < CIP_SFC_COUNT; ++i) { + if (amdtp_rate_table[i] == rate) + break; + } - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - frames_per_period, frames_per_period); - if (err < 0) { - mutex_unlock(&ff->mutex); + // The unit is configured at sampling frequency which packet + // streaming engine can't support. + if (i >= CIP_SFC_COUNT) { + err = -EIO; goto release_lock; } - err = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - frames_per_buffer, frames_per_buffer); - if (err < 0) { - mutex_unlock(&ff->mutex); - goto release_lock; + substream->runtime->hw.rate_min = rate; + substream->runtime->hw.rate_max = rate; + } else { + if (ff->substreams_counter > 0) { + unsigned int frames_per_period = d->events_per_period; + unsigned int frames_per_buffer = d->events_per_buffer; + + rate = amdtp_rate_table[ff->rx_stream.sfc]; + substream->runtime->hw.rate_min = rate; + substream->runtime->hw.rate_max = rate; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) + goto release_lock; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + frames_per_buffer, frames_per_buffer); + if (err < 0) + goto release_lock; } } } - mutex_unlock(&ff->mutex); - snd_pcm_set_sync(substream); return 0; @@ -235,12 +228,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); - mutex_lock(&ff->mutex); + guard(mutex)(&ff->mutex); err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period, frames_per_buffer); if (err >= 0) ++ff->substreams_counter; - mutex_unlock(&ff->mutex); } return err; @@ -250,15 +242,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_ff *ff = substream->private_data; - mutex_lock(&ff->mutex); + guard(mutex)(&ff->mutex); if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --ff->substreams_counter; snd_ff_stream_stop_duplex(ff); - mutex_unlock(&ff->mutex); - return 0; } @@ -268,14 +258,12 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - mutex_lock(&ff->mutex); + guard(mutex)(&ff->mutex); err = snd_ff_stream_start_duplex(ff, runtime->rate); if (err >= 0) amdtp_stream_pcm_prepare(&ff->tx_stream); - mutex_unlock(&ff->mutex); - return err; } @@ -285,14 +273,12 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - mutex_lock(&ff->mutex); + guard(mutex)(&ff->mutex); err = snd_ff_stream_start_duplex(ff, runtime->rate); if (err >= 0) amdtp_stream_pcm_prepare(&ff->rx_stream); - mutex_unlock(&ff->mutex); - return err; } From b8ed2b143263625a01c2796e0c636d47804585aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:13 +0200 Subject: [PATCH 0878/1292] ALSA: firewire: isight: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-10-tiwai@suse.de --- sound/firewire/isight.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index ee574b5d7406bb..2b7f071d593b95 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -327,9 +327,8 @@ static int isight_hw_free(struct snd_pcm_substream *substream) WRITE_ONCE(isight->pcm_active, false); - mutex_lock(&isight->mutex); + guard(mutex)(&isight->mutex); isight_stop_streaming(isight); - mutex_unlock(&isight->mutex); return 0; } @@ -400,16 +399,12 @@ static int isight_start_streaming(struct isight *isight) static int isight_prepare(struct snd_pcm_substream *substream) { struct isight *isight = substream->private_data; - int err; isight->buffer_pointer = 0; isight->period_counter = 0; - mutex_lock(&isight->mutex); - err = isight_start_streaming(isight); - mutex_unlock(&isight->mutex); - - return err; + guard(mutex)(&isight->mutex); + return isight_start_streaming(isight); } static int isight_trigger(struct snd_pcm_substream *substream, int cmd) @@ -677,9 +672,8 @@ static void isight_bus_reset(struct fw_unit *unit) if (fw_iso_resources_update(&isight->resources) < 0) { isight_pcm_abort(isight); - mutex_lock(&isight->mutex); + guard(mutex)(&isight->mutex); isight_stop_streaming(isight); - mutex_unlock(&isight->mutex); } } @@ -691,9 +685,9 @@ static void isight_remove(struct fw_unit *unit) snd_card_disconnect(isight->card); - mutex_lock(&isight->mutex); - isight_stop_streaming(isight); - mutex_unlock(&isight->mutex); + scoped_guard(mutex, &isight->mutex) { + isight_stop_streaming(isight); + } // Block till all of ALSA character devices are released. snd_card_free(isight->card); From 6061b4accb812e9c5888b64cd1764fece9626ea6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:14 +0200 Subject: [PATCH 0879/1292] ALSA: firewire: lib: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-11-tiwai@suse.de --- sound/firewire/amdtp-stream.c | 28 ++++++------------- sound/firewire/cmp.c | 37 +++++++------------------ sound/firewire/iso-resources.c | 50 ++++++++++++++-------------------- 3 files changed, 38 insertions(+), 77 deletions(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 7fc51f829eccac..5cdc34877fc191 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1688,20 +1688,16 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, struct pkt_desc *descs; int i, type, tag, err; - mutex_lock(&s->mutex); + guard(mutex)(&s->mutex); if (WARN_ON(amdtp_stream_running(s) || - (s->data_block_quadlets < 1))) { - err = -EBADFD; - goto err_unlock; - } + (s->data_block_quadlets < 1))) + return -EBADFD; if (s->direction == AMDTP_IN_STREAM) { // NOTE: IT context should be used for constant IRQ. - if (is_irq_target) { - err = -EINVAL; - goto err_unlock; - } + if (is_irq_target) + return -EINVAL; s->data_block_counter = UINT_MAX; } else { @@ -1725,7 +1721,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, err = iso_packets_buffer_init(&s->buffer, s->unit, queue_size, max_ctx_payload_size, dir); if (err < 0) - goto err_unlock; + return err; s->queue_size = queue_size; s->context = fw_iso_context_create(fw_parent_device(s->unit)->card, @@ -1846,8 +1842,6 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, if (err < 0) goto err_pkt_descs; - mutex_unlock(&s->mutex); - return 0; err_pkt_descs: kfree(s->packet_descs); @@ -1863,8 +1857,6 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, s->context = ERR_PTR(-1); err_buffer: iso_packets_buffer_destroy(&s->buffer, s->unit); -err_unlock: - mutex_unlock(&s->mutex); return err; } @@ -1934,12 +1926,10 @@ EXPORT_SYMBOL(amdtp_stream_update); */ static void amdtp_stream_stop(struct amdtp_stream *s) { - mutex_lock(&s->mutex); + guard(mutex)(&s->mutex); - if (!amdtp_stream_running(s)) { - mutex_unlock(&s->mutex); + if (!amdtp_stream_running(s)) return; - } cancel_work_sync(&s->period_work); fw_iso_context_stop(s->context); @@ -1955,8 +1945,6 @@ static void amdtp_stream_stop(struct amdtp_stream *s) if (s->domain->replay.enable) kfree(s->ctx_data.tx.cache.descs); } - - mutex_unlock(&s->mutex); } /** diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index f5028a061a91ff..b2b76c7c71b341 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -188,32 +188,23 @@ EXPORT_SYMBOL(cmp_connection_destroy); int cmp_connection_reserve(struct cmp_connection *c, unsigned int max_payload_bytes) { - int err; - - mutex_lock(&c->mutex); + guard(mutex)(&c->mutex); - if (WARN_ON(c->resources.allocated)) { - err = -EBUSY; - goto end; - } + if (WARN_ON(c->resources.allocated)) + return -EBUSY; c->speed = min(c->max_speed, fw_parent_device(c->resources.unit)->max_speed); - err = fw_iso_resources_allocate(&c->resources, max_payload_bytes, - c->speed); -end: - mutex_unlock(&c->mutex); - - return err; + return fw_iso_resources_allocate(&c->resources, max_payload_bytes, + c->speed); } EXPORT_SYMBOL(cmp_connection_reserve); void cmp_connection_release(struct cmp_connection *c) { - mutex_lock(&c->mutex); + guard(mutex)(&c->mutex); fw_iso_resources_free(&c->resources); - mutex_unlock(&c->mutex); } EXPORT_SYMBOL(cmp_connection_release); @@ -304,12 +295,10 @@ int cmp_connection_establish(struct cmp_connection *c) { int err; - mutex_lock(&c->mutex); + guard(mutex)(&c->mutex); - if (WARN_ON(c->connected)) { - mutex_unlock(&c->mutex); + if (WARN_ON(c->connected)) return -EISCONN; - } retry_after_bus_reset: if (c->direction == CMP_OUTPUT) @@ -327,8 +316,6 @@ int cmp_connection_establish(struct cmp_connection *c) if (err >= 0) c->connected = true; - mutex_unlock(&c->mutex); - return err; } EXPORT_SYMBOL(cmp_connection_establish); @@ -350,19 +337,15 @@ void cmp_connection_break(struct cmp_connection *c) { int err; - mutex_lock(&c->mutex); + guard(mutex)(&c->mutex); - if (!c->connected) { - mutex_unlock(&c->mutex); + if (!c->connected) return; - } err = pcr_modify(c, pcr_break_modify, NULL, SUCCEED_ON_BUS_RESET); if (err < 0) cmp_error(c, "plug is still connected\n"); c->connected = false; - - mutex_unlock(&c->mutex); } EXPORT_SYMBOL(cmp_connection_break); diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c index 84f71b2eaa826e..b47ee029d688bb 100644 --- a/sound/firewire/iso-resources.c +++ b/sound/firewire/iso-resources.c @@ -123,29 +123,25 @@ int fw_iso_resources_allocate(struct fw_iso_resources *r, if (err < 0) return err; - mutex_lock(&r->mutex); - - bandwidth = r->bandwidth + r->bandwidth_overhead; - fw_iso_resource_manage(card, r->generation, r->channels_mask, - &channel, &bandwidth, true); - if (channel == -EAGAIN) { - mutex_unlock(&r->mutex); - goto retry_after_bus_reset; - } - if (channel >= 0) { - r->channel = channel; - r->allocated = true; - } else { - if (channel == -EBUSY) - dev_err(&r->unit->device, - "isochronous resources exhausted\n"); - else - dev_err(&r->unit->device, - "isochronous resource allocation failed\n"); + scoped_guard(mutex, &r->mutex) { + bandwidth = r->bandwidth + r->bandwidth_overhead; + fw_iso_resource_manage(card, r->generation, r->channels_mask, + &channel, &bandwidth, true); + if (channel == -EAGAIN) + goto retry_after_bus_reset; + if (channel >= 0) { + r->channel = channel; + r->allocated = true; + } else { + if (channel == -EBUSY) + dev_err(&r->unit->device, + "isochronous resources exhausted\n"); + else + dev_err(&r->unit->device, + "isochronous resource allocation failed\n"); + } } - mutex_unlock(&r->mutex); - return channel; } EXPORT_SYMBOL(fw_iso_resources_allocate); @@ -166,12 +162,10 @@ int fw_iso_resources_update(struct fw_iso_resources *r) struct fw_card *card = fw_parent_device(r->unit)->card; int bandwidth, channel; - mutex_lock(&r->mutex); + guard(mutex)(&r->mutex); - if (!r->allocated) { - mutex_unlock(&r->mutex); + if (!r->allocated) return 0; - } spin_lock_irq(&card->lock); r->generation = card->generation; @@ -196,8 +190,6 @@ int fw_iso_resources_update(struct fw_iso_resources *r) "isochronous resource allocation failed\n"); } - mutex_unlock(&r->mutex); - return channel; } EXPORT_SYMBOL(fw_iso_resources_update); @@ -218,7 +210,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r) return; card = fw_parent_device(r->unit)->card; - mutex_lock(&r->mutex); + guard(mutex)(&r->mutex); if (r->allocated) { bandwidth = r->bandwidth + r->bandwidth_overhead; @@ -230,7 +222,5 @@ void fw_iso_resources_free(struct fw_iso_resources *r) r->allocated = false; } - - mutex_unlock(&r->mutex); } EXPORT_SYMBOL(fw_iso_resources_free); From 9c2ca41d573c26c5b7b83149f81b2b17076e8d94 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:15 +0200 Subject: [PATCH 0880/1292] ALSA: firewire: bebob: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-12-tiwai@suse.de --- sound/firewire/bebob/bebob_hwdep.c | 37 ++++++++--------------------- sound/firewire/bebob/bebob_midi.c | 10 ++------ sound/firewire/bebob/bebob_stream.c | 21 +++++----------- 3 files changed, 18 insertions(+), 50 deletions(-) diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c index 5779e99a6bb23f..216d1fceb6e737 100644 --- a/sound/firewire/bebob/bebob_hwdep.c +++ b/sound/firewire/bebob/bebob_hwdep.c @@ -53,18 +53,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_bebob *bebob = hwdep->private_data; - __poll_t events; poll_wait(file, &bebob->hwdep_wait, wait); - spin_lock_irq(&bebob->lock); + guard(spinlock_irq)(&bebob->lock); if (bebob->dev_lock_changed) - events = EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; else - events = 0; - spin_unlock_irq(&bebob->lock); - - return events; + return 0; } static int @@ -90,39 +86,27 @@ hwdep_get_info(struct snd_bebob *bebob, void __user *arg) static int hwdep_lock(struct snd_bebob *bebob) { - int err; - - spin_lock_irq(&bebob->lock); + guard(spinlock_irq)(&bebob->lock); if (bebob->dev_lock_count == 0) { bebob->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&bebob->lock); - - return err; } static int hwdep_unlock(struct snd_bebob *bebob) { - int err; - - spin_lock_irq(&bebob->lock); + guard(spinlock_irq)(&bebob->lock); if (bebob->dev_lock_count == -1) { bebob->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&bebob->lock); - - return err; } static int @@ -130,10 +114,9 @@ hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_bebob *bebob = hwdep->private_data; - spin_lock_irq(&bebob->lock); + guard(spinlock_irq)(&bebob->lock); if (bebob->dev_lock_count == -1) bebob->dev_lock_count = 0; - spin_unlock_irq(&bebob->lock); return 0; } diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index 5fd2d363de521e..678631f31d3c56 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -47,9 +47,8 @@ static int midi_close(struct snd_rawmidi_substream *substream) static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_bebob *bebob = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&bebob->lock, flags); + guard(spinlock_irqsave)(&bebob->lock); if (up) amdtp_am824_midi_trigger(&bebob->tx_stream, @@ -57,16 +56,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&bebob->tx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&bebob->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_bebob *bebob = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&bebob->lock, flags); + guard(spinlock_irqsave)(&bebob->lock); if (up) amdtp_am824_midi_trigger(&bebob->rx_stream, @@ -74,8 +70,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&bebob->rx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&bebob->lock, flags); } static void set_midi_substream_names(struct snd_bebob *bebob, diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 8629b14ded7664..449cb17717f02f 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -964,33 +964,24 @@ void snd_bebob_stream_lock_changed(struct snd_bebob *bebob) int snd_bebob_stream_lock_try(struct snd_bebob *bebob) { - int err; - - spin_lock_irq(&bebob->lock); + guard(spinlock_irq)(&bebob->lock); /* user land lock this */ - if (bebob->dev_lock_count < 0) { - err = -EBUSY; - goto end; - } + if (bebob->dev_lock_count < 0) + return -EBUSY; /* this is the first time */ if (bebob->dev_lock_count++ == 0) snd_bebob_stream_lock_changed(bebob); - err = 0; -end: - spin_unlock_irq(&bebob->lock); - return err; + return 0; } void snd_bebob_stream_lock_release(struct snd_bebob *bebob) { - spin_lock_irq(&bebob->lock); + guard(spinlock_irq)(&bebob->lock); if (WARN_ON(bebob->dev_lock_count <= 0)) - goto end; + return; if (--bebob->dev_lock_count == 0) snd_bebob_stream_lock_changed(bebob); -end: - spin_unlock_irq(&bebob->lock); } From 17653c9128ec8a32fefbb052ba841792b5f56c5a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:16 +0200 Subject: [PATCH 0881/1292] ALSA: firewire: dice: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-13-tiwai@suse.de --- sound/firewire/dice/dice-hwdep.c | 37 +++++++------------------- sound/firewire/dice/dice-midi.c | 10 ++----- sound/firewire/dice/dice-stream.c | 21 +++++---------- sound/firewire/dice/dice-transaction.c | 7 +++-- 4 files changed, 21 insertions(+), 54 deletions(-) diff --git a/sound/firewire/dice/dice-hwdep.c b/sound/firewire/dice/dice-hwdep.c index d165dd427bd3b9..747ff09524837d 100644 --- a/sound/firewire/dice/dice-hwdep.c +++ b/sound/firewire/dice/dice-hwdep.c @@ -55,18 +55,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_dice *dice = hwdep->private_data; - __poll_t events; poll_wait(file, &dice->hwdep_wait, wait); - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); if (dice->dev_lock_changed || dice->notification_bits != 0) - events = EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; else - events = 0; - spin_unlock_irq(&dice->lock); - - return events; + return 0; } static int hwdep_get_info(struct snd_dice *dice, void __user *arg) @@ -90,48 +86,35 @@ static int hwdep_get_info(struct snd_dice *dice, void __user *arg) static int hwdep_lock(struct snd_dice *dice) { - int err; - - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); if (dice->dev_lock_count == 0) { dice->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&dice->lock); - - return err; } static int hwdep_unlock(struct snd_dice *dice) { - int err; - - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); if (dice->dev_lock_count == -1) { dice->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&dice->lock); - - return err; } static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_dice *dice = hwdep->private_data; - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); if (dice->dev_lock_count == -1) dice->dev_lock_count = 0; - spin_unlock_irq(&dice->lock); return 0; } diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index 9ca975c556ca71..722bce3793453b 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -47,9 +47,8 @@ static int midi_close(struct snd_rawmidi_substream *substream) static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_dice *dice = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&dice->lock, flags); + guard(spinlock_irqsave)(&dice->lock); if (up) amdtp_am824_midi_trigger(&dice->tx_stream[0], @@ -57,16 +56,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&dice->tx_stream[0], substrm->number, NULL); - - spin_unlock_irqrestore(&dice->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_dice *dice = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&dice->lock, flags); + guard(spinlock_irqsave)(&dice->lock); if (up) amdtp_am824_midi_trigger(&dice->rx_stream[0], @@ -74,8 +70,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&dice->rx_stream[0], substrm->number, NULL); - - spin_unlock_irqrestore(&dice->lock, flags); } static void set_midi_substream_names(struct snd_dice *dice, diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 4c677c8546c71a..d5ffe7c8299329 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -677,32 +677,23 @@ static void dice_lock_changed(struct snd_dice *dice) int snd_dice_stream_lock_try(struct snd_dice *dice) { - int err; - - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); - if (dice->dev_lock_count < 0) { - err = -EBUSY; - goto out; - } + if (dice->dev_lock_count < 0) + return -EBUSY; if (dice->dev_lock_count++ == 0) dice_lock_changed(dice); - err = 0; -out: - spin_unlock_irq(&dice->lock); - return err; + return 0; } void snd_dice_stream_lock_release(struct snd_dice *dice) { - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); if (WARN_ON(dice->dev_lock_count <= 0)) - goto out; + return; if (--dice->dev_lock_count == 0) dice_lock_changed(dice); -out: - spin_unlock_irq(&dice->lock); } diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index 92941ef83cd5c5..a3f7dfa990a4e5 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c @@ -136,7 +136,6 @@ static void dice_notification(struct fw_card *card, struct fw_request *request, { struct snd_dice *dice = callback_data; u32 bits; - unsigned long flags; if (tcode != TCODE_WRITE_QUADLET_REQUEST) { fw_send_response(card, request, RCODE_TYPE_ERROR); @@ -149,9 +148,9 @@ static void dice_notification(struct fw_card *card, struct fw_request *request, bits = be32_to_cpup(data); - spin_lock_irqsave(&dice->lock, flags); - dice->notification_bits |= bits; - spin_unlock_irqrestore(&dice->lock, flags); + scoped_guard(spinlock_irqsave, &dice->lock) { + dice->notification_bits |= bits; + } fw_send_response(card, request, RCODE_COMPLETE); From 0385fd947b89e3c027f15fe46cf6cc943c260020 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:17 +0200 Subject: [PATCH 0882/1292] ALSA: firewire: digi00x: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-14-tiwai@suse.de --- sound/firewire/digi00x/digi00x-hwdep.c | 37 ++++++-------------- sound/firewire/digi00x/digi00x-midi.c | 10 ++---- sound/firewire/digi00x/digi00x-stream.c | 21 ++++------- sound/firewire/digi00x/digi00x-transaction.c | 8 ++--- 4 files changed, 21 insertions(+), 55 deletions(-) diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c index b150607c0a0d13..435d18417cf038 100644 --- a/sound/firewire/digi00x/digi00x-hwdep.c +++ b/sound/firewire/digi00x/digi00x-hwdep.c @@ -63,18 +63,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_dg00x *dg00x = hwdep->private_data; - __poll_t events; poll_wait(file, &dg00x->hwdep_wait, wait); - spin_lock_irq(&dg00x->lock); + guard(spinlock_irq)(&dg00x->lock); if (dg00x->dev_lock_changed || dg00x->msg) - events = EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; else - events = 0; - spin_unlock_irq(&dg00x->lock); - - return events; + return 0; } static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg) @@ -98,48 +94,35 @@ static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg) static int hwdep_lock(struct snd_dg00x *dg00x) { - int err; - - spin_lock_irq(&dg00x->lock); + guard(spinlock_irq)(&dg00x->lock); if (dg00x->dev_lock_count == 0) { dg00x->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&dg00x->lock); - - return err; } static int hwdep_unlock(struct snd_dg00x *dg00x) { - int err; - - spin_lock_irq(&dg00x->lock); + guard(spinlock_irq)(&dg00x->lock); if (dg00x->dev_lock_count == -1) { dg00x->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&dg00x->lock); - - return err; } static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_dg00x *dg00x = hwdep->private_data; - spin_lock_irq(&dg00x->lock); + guard(spinlock_irq)(&dg00x->lock); if (dg00x->dev_lock_count == -1) dg00x->dev_lock_count = 0; - spin_unlock_irq(&dg00x->lock); return 0; } diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index 0f6ca58cc4a0d5..bcdaf003514b81 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c @@ -49,21 +49,18 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substream, { struct snd_dg00x *dg00x = substream->rmidi->private_data; unsigned int port; - unsigned long flags; if (substream->rmidi->device == 0) port = substream->number; else port = 2; - spin_lock_irqsave(&dg00x->lock, flags); + guard(spinlock_irqsave)(&dg00x->lock); if (up) amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream); else amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL); - - spin_unlock_irqrestore(&dg00x->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substream, @@ -71,21 +68,18 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substream, { struct snd_dg00x *dg00x = substream->rmidi->private_data; unsigned int port; - unsigned long flags; if (substream->rmidi->device == 0) port = substream->number; else port = 2; - spin_lock_irqsave(&dg00x->lock, flags); + guard(spinlock_irqsave)(&dg00x->lock); if (up) amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream); else amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL); - - spin_unlock_irqrestore(&dg00x->lock, flags); } static void set_substream_names(struct snd_dg00x *dg00x, diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 295163bb8abb62..250ffdb26ebdd2 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -427,33 +427,24 @@ void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x) int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x) { - int err; - - spin_lock_irq(&dg00x->lock); + guard(spinlock_irq)(&dg00x->lock); /* user land lock this */ - if (dg00x->dev_lock_count < 0) { - err = -EBUSY; - goto end; - } + if (dg00x->dev_lock_count < 0) + return -EBUSY; /* this is the first time */ if (dg00x->dev_lock_count++ == 0) snd_dg00x_stream_lock_changed(dg00x); - err = 0; -end: - spin_unlock_irq(&dg00x->lock); - return err; + return 0; } void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x) { - spin_lock_irq(&dg00x->lock); + guard(spinlock_irq)(&dg00x->lock); if (WARN_ON(dg00x->dev_lock_count <= 0)) - goto end; + return; if (--dg00x->dev_lock_count == 0) snd_dg00x_stream_lock_changed(dg00x); -end: - spin_unlock_irq(&dg00x->lock); } diff --git a/sound/firewire/digi00x/digi00x-transaction.c b/sound/firewire/digi00x/digi00x-transaction.c index cf0bcf1c595631..8a1667159930da 100644 --- a/sound/firewire/digi00x/digi00x-transaction.c +++ b/sound/firewire/digi00x/digi00x-transaction.c @@ -11,11 +11,9 @@ static void handle_unknown_message(struct snd_dg00x *dg00x, unsigned long long offset, __be32 *buf) { - unsigned long flags; - - spin_lock_irqsave(&dg00x->lock, flags); - dg00x->msg = be32_to_cpu(*buf); - spin_unlock_irqrestore(&dg00x->lock, flags); + scoped_guard(spinlock_irqsave, &dg00x->lock) { + dg00x->msg = be32_to_cpu(*buf); + } wake_up(&dg00x->hwdep_wait); } From 05af2f70691b073cee54b6822e0f4f314364de68 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:18 +0200 Subject: [PATCH 0883/1292] ALSA: firewire: fireface: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-15-tiwai@suse.de --- sound/firewire/fireface/ff-hwdep.c | 37 +++++++----------------- sound/firewire/fireface/ff-midi.c | 10 ++----- sound/firewire/fireface/ff-stream.c | 21 ++++---------- sound/firewire/fireface/ff-transaction.c | 4 +-- 4 files changed, 19 insertions(+), 53 deletions(-) diff --git a/sound/firewire/fireface/ff-hwdep.c b/sound/firewire/fireface/ff-hwdep.c index ca5c5dee71f289..5976abf2e1ab09 100644 --- a/sound/firewire/fireface/ff-hwdep.c +++ b/sound/firewire/fireface/ff-hwdep.c @@ -72,18 +72,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_ff *ff = hwdep->private_data; - __poll_t events; poll_wait(file, &ff->hwdep_wait, wait); - spin_lock_irq(&ff->lock); + guard(spinlock_irq)(&ff->lock); if (ff->dev_lock_changed || has_msg(ff)) - events = EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; else - events = 0; - spin_unlock_irq(&ff->lock); - - return events; + return 0; } static int hwdep_get_info(struct snd_ff *ff, void __user *arg) @@ -107,48 +103,35 @@ static int hwdep_get_info(struct snd_ff *ff, void __user *arg) static int hwdep_lock(struct snd_ff *ff) { - int err; - - spin_lock_irq(&ff->lock); + guard(spinlock_irq)(&ff->lock); if (ff->dev_lock_count == 0) { ff->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&ff->lock); - - return err; } static int hwdep_unlock(struct snd_ff *ff) { - int err; - - spin_lock_irq(&ff->lock); + guard(spinlock_irq)(&ff->lock); if (ff->dev_lock_count == -1) { ff->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&ff->lock); - - return err; } static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_ff *ff = hwdep->private_data; - spin_lock_irq(&ff->lock); + guard(spinlock_irq)(&ff->lock); if (ff->dev_lock_count == -1) ff->dev_lock_count = 0; - spin_unlock_irq(&ff->lock); return 0; } diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c index da3054fdcc7d66..9f6aa490e5bf25 100644 --- a/sound/firewire/fireface/ff-midi.c +++ b/sound/firewire/fireface/ff-midi.c @@ -46,31 +46,25 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_ff *ff = substream->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&ff->lock, flags); + guard(spinlock_irqsave)(&ff->lock); if (up) WRITE_ONCE(ff->tx_midi_substreams[substream->number], substream); else WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL); - - spin_unlock_irqrestore(&ff->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_ff *ff = substream->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&ff->lock, flags); + guard(spinlock_irqsave)(&ff->lock); if (up || !ff->rx_midi_error[substream->number]) schedule_work(&ff->rx_midi_work[substream->number]); - - spin_unlock_irqrestore(&ff->lock, flags); } static void set_midi_substream_names(struct snd_rawmidi_str *stream, diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index 95bf405adb3d2b..ba42490f2b0e26 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -253,33 +253,24 @@ void snd_ff_stream_lock_changed(struct snd_ff *ff) int snd_ff_stream_lock_try(struct snd_ff *ff) { - int err; - - spin_lock_irq(&ff->lock); + guard(spinlock_irq)(&ff->lock); /* user land lock this */ - if (ff->dev_lock_count < 0) { - err = -EBUSY; - goto end; - } + if (ff->dev_lock_count < 0) + return -EBUSY; /* this is the first time */ if (ff->dev_lock_count++ == 0) snd_ff_stream_lock_changed(ff); - err = 0; -end: - spin_unlock_irq(&ff->lock); - return err; + return 0; } void snd_ff_stream_lock_release(struct snd_ff *ff) { - spin_lock_irq(&ff->lock); + guard(spinlock_irq)(&ff->lock); if (WARN_ON(ff->dev_lock_count <= 0)) - goto end; + return; if (--ff->dev_lock_count == 0) snd_ff_stream_lock_changed(ff); -end: - spin_unlock_irq(&ff->lock); } diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 6b89e39f4a43fd..436da0a3bdcc7a 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -132,15 +132,13 @@ static void handle_msg(struct fw_card *card, struct fw_request *request, int tco struct snd_ff *ff = callback_data; __le32 *buf = data; u32 tstamp = fw_request_get_timestamp(request); - unsigned long flag; fw_send_response(card, request, RCODE_COMPLETE); offset -= ff->async_handler.offset; - spin_lock_irqsave(&ff->lock, flag); + guard(spinlock_irqsave)(&ff->lock); ff->spec->protocol->handle_msg(ff, (unsigned int)offset, buf, length, tstamp); - spin_unlock_irqrestore(&ff->lock, flag); } static int allocate_own_address(struct snd_ff *ff, int i) From 0b8bf8d00f4015f85a9fd5799e39ba10b42fa5e3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:19 +0200 Subject: [PATCH 0884/1292] ALSA: firewire: fireworks: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-16-tiwai@suse.de --- sound/firewire/fireworks/fireworks_command.c | 16 ++++---- sound/firewire/fireworks/fireworks_hwdep.c | 41 ++++++------------- sound/firewire/fireworks/fireworks_midi.c | 10 +---- sound/firewire/fireworks/fireworks_stream.c | 21 +++------- .../fireworks/fireworks_transaction.c | 39 +++++++----------- 5 files changed, 42 insertions(+), 85 deletions(-) diff --git a/sound/firewire/fireworks/fireworks_command.c b/sound/firewire/fireworks/fireworks_command.c index 7e255fc2c6e405..2b595ee0bc357b 100644 --- a/sound/firewire/fireworks/fireworks_command.c +++ b/sound/firewire/fireworks/fireworks_command.c @@ -119,14 +119,14 @@ efw_transaction(struct snd_efw *efw, unsigned int category, return -ENOMEM; /* to keep consistency of sequence number */ - spin_lock(&efw->lock); - if ((efw->seqnum < KERNEL_SEQNUM_MIN) || - (efw->seqnum >= KERNEL_SEQNUM_MAX - 2)) - efw->seqnum = KERNEL_SEQNUM_MIN; - else - efw->seqnum += 2; - seqnum = efw->seqnum; - spin_unlock(&efw->lock); + scoped_guard(spinlock, &efw->lock) { + if ((efw->seqnum < KERNEL_SEQNUM_MIN) || + (efw->seqnum >= KERNEL_SEQNUM_MAX - 2)) + efw->seqnum = KERNEL_SEQNUM_MIN; + else + efw->seqnum += 2; + seqnum = efw->seqnum; + } /* fill transaction header fields */ cmd_bytes = sizeof(struct snd_efw_transaction) + param_bytes; diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c index 037833cd066ef5..7d6bd8ceeab39d 100644 --- a/sound/firewire/fireworks/fireworks_hwdep.c +++ b/sound/firewire/fireworks/fireworks_hwdep.c @@ -103,12 +103,10 @@ hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count, .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS, }; - spin_lock_irq(&efw->lock); - - event.lock_status.status = (efw->dev_lock_count > 0); - efw->dev_lock_changed = false; - - spin_unlock_irq(&efw->lock); + scoped_guard(spinlock_irq, &efw->lock) { + event.lock_status.status = (efw->dev_lock_count > 0); + efw->dev_lock_changed = false; + } count = min_t(long, count, sizeof(event.lock_status)); @@ -192,13 +190,11 @@ hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) poll_wait(file, &efw->hwdep_wait, wait); - spin_lock_irq(&efw->lock); + guard(spinlock_irq)(&efw->lock); if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr) events = EPOLLIN | EPOLLRDNORM; else events = 0; - spin_unlock_irq(&efw->lock); - return events | EPOLLOUT; } @@ -225,39 +221,27 @@ hwdep_get_info(struct snd_efw *efw, void __user *arg) static int hwdep_lock(struct snd_efw *efw) { - int err; - - spin_lock_irq(&efw->lock); + guard(spinlock_irq)(&efw->lock); if (efw->dev_lock_count == 0) { efw->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&efw->lock); - - return err; } static int hwdep_unlock(struct snd_efw *efw) { - int err; - - spin_lock_irq(&efw->lock); + guard(spinlock_irq)(&efw->lock); if (efw->dev_lock_count == -1) { efw->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&efw->lock); - - return err; } static int @@ -265,10 +249,9 @@ hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_efw *efw = hwdep->private_data; - spin_lock_irq(&efw->lock); + guard(spinlock_irq)(&efw->lock); if (efw->dev_lock_count == -1) efw->dev_lock_count = 0; - spin_unlock_irq(&efw->lock); return 0; } diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index 90fe809a26c0b2..405106a6aef908 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -46,9 +46,8 @@ static int midi_close(struct snd_rawmidi_substream *substream) static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_efw *efw = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&efw->lock, flags); + guard(spinlock_irqsave)(&efw->lock); if (up) amdtp_am824_midi_trigger(&efw->tx_stream, @@ -56,16 +55,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&efw->tx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&efw->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_efw *efw = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&efw->lock, flags); + guard(spinlock_irqsave)(&efw->lock); if (up) amdtp_am824_midi_trigger(&efw->rx_stream, @@ -73,8 +69,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&efw->rx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&efw->lock, flags); } static void set_midi_substream_names(struct snd_efw *efw, diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 53dbd4d4b0d02b..974084e1c083b3 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -345,33 +345,24 @@ void snd_efw_stream_lock_changed(struct snd_efw *efw) int snd_efw_stream_lock_try(struct snd_efw *efw) { - int err; - - spin_lock_irq(&efw->lock); + guard(spinlock_irq)(&efw->lock); /* user land lock this */ - if (efw->dev_lock_count < 0) { - err = -EBUSY; - goto end; - } + if (efw->dev_lock_count < 0) + return -EBUSY; /* this is the first time */ if (efw->dev_lock_count++ == 0) snd_efw_stream_lock_changed(efw); - err = 0; -end: - spin_unlock_irq(&efw->lock); - return err; + return 0; } void snd_efw_stream_lock_release(struct snd_efw *efw) { - spin_lock_irq(&efw->lock); + guard(spinlock_irq)(&efw->lock); if (WARN_ON(efw->dev_lock_count <= 0)) - goto end; + return; if (--efw->dev_lock_count == 0) snd_efw_stream_lock_changed(efw); -end: - spin_unlock_irq(&efw->lock); } diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c index 9f8c53b39f9584..5c859773fe0626 100644 --- a/sound/firewire/fireworks/fireworks_transaction.c +++ b/sound/firewire/fireworks/fireworks_transaction.c @@ -82,9 +82,9 @@ int snd_efw_transaction_run(struct fw_unit *unit, t.state = STATE_PENDING; init_waitqueue_head(&t.wait); - spin_lock_irq(&transaction_queues_lock); - list_add_tail(&t.list, &transaction_queues); - spin_unlock_irq(&transaction_queues_lock); + scoped_guard(spinlock_irq, &transaction_queues_lock) { + list_add_tail(&t.list, &transaction_queues); + } tries = 0; do { @@ -107,9 +107,9 @@ int snd_efw_transaction_run(struct fw_unit *unit, } } while (1); - spin_lock_irq(&transaction_queues_lock); - list_del(&t.list); - spin_unlock_irq(&transaction_queues_lock); + scoped_guard(spinlock_irq, &transaction_queues_lock) { + list_del(&t.list); + } return ret; } @@ -123,7 +123,7 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) t = (struct snd_efw_transaction *)data; length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length); - spin_lock(&efw->lock); + guard(spinlock)(&efw->lock); if (efw->push_ptr < efw->pull_ptr) capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr); @@ -134,7 +134,7 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) /* confirm enough space for this response */ if (capacity < length) { *rcode = RCODE_CONFLICT_ERROR; - goto end; + return; } /* copy to ring buffer */ @@ -157,8 +157,6 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) wake_up(&efw->hwdep_wait); *rcode = RCODE_COMPLETE; -end: - spin_unlock_irq(&efw->lock); } static void @@ -169,7 +167,7 @@ handle_resp_for_user(struct fw_card *card, int generation, int source, struct snd_efw *efw; unsigned int i; - spin_lock_irq(&instances_lock); + guard(spinlock_irq)(&instances_lock); for (i = 0; i < SNDRV_CARDS; i++) { efw = instances[i]; @@ -186,11 +184,9 @@ handle_resp_for_user(struct fw_card *card, int generation, int source, break; } if (i == SNDRV_CARDS) - goto end; + return; copy_resp_to_buf(efw, data, length, rcode); -end: - spin_unlock(&instances_lock); } static void @@ -199,9 +195,8 @@ handle_resp_for_kernel(struct fw_card *card, int generation, int source, { struct fw_device *device; struct transaction_queue *t; - unsigned long flags; - spin_lock_irqsave(&transaction_queues_lock, flags); + guard(spinlock_irqsave)(&transaction_queues_lock); list_for_each_entry(t, &transaction_queues, list) { device = fw_parent_device(t->unit); if ((device->card != card) || @@ -219,7 +214,6 @@ handle_resp_for_kernel(struct fw_card *card, int generation, int source, *rcode = RCODE_COMPLETE; } } - spin_unlock_irqrestore(&transaction_queues_lock, flags); } static void @@ -259,7 +253,7 @@ void snd_efw_transaction_add_instance(struct snd_efw *efw) { unsigned int i; - spin_lock_irq(&instances_lock); + guard(spinlock_irq)(&instances_lock); for (i = 0; i < SNDRV_CARDS; i++) { if (instances[i] != NULL) @@ -267,30 +261,26 @@ void snd_efw_transaction_add_instance(struct snd_efw *efw) instances[i] = efw; break; } - - spin_unlock_irq(&instances_lock); } void snd_efw_transaction_remove_instance(struct snd_efw *efw) { unsigned int i; - spin_lock_irq(&instances_lock); + guard(spinlock_irq)(&instances_lock); for (i = 0; i < SNDRV_CARDS; i++) { if (instances[i] != efw) continue; instances[i] = NULL; } - - spin_unlock_irq(&instances_lock); } void snd_efw_transaction_bus_reset(struct fw_unit *unit) { struct transaction_queue *t; - spin_lock_irq(&transaction_queues_lock); + guard(spinlock_irq)(&transaction_queues_lock); list_for_each_entry(t, &transaction_queues, list) { if ((t->unit == unit) && (t->state == STATE_PENDING)) { @@ -298,7 +288,6 @@ void snd_efw_transaction_bus_reset(struct fw_unit *unit) wake_up(&t->wait); } } - spin_unlock_irq(&transaction_queues_lock); } static struct fw_address_handler resp_register_handler = { From cae230e4d0a9a4234e042c8eaa19bb9b11879792 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:21 +0200 Subject: [PATCH 0885/1292] ALSA: firewire: oxfw: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-18-tiwai@suse.de --- sound/firewire/oxfw/oxfw-hwdep.c | 37 +++++++++---------------------- sound/firewire/oxfw/oxfw-midi.c | 10 ++------- sound/firewire/oxfw/oxfw-stream.c | 21 +++++------------- 3 files changed, 18 insertions(+), 50 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-hwdep.c b/sound/firewire/oxfw/oxfw-hwdep.c index 3be214d8a9228c..f8ac362fc73a8d 100644 --- a/sound/firewire/oxfw/oxfw-hwdep.c +++ b/sound/firewire/oxfw/oxfw-hwdep.c @@ -53,18 +53,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_oxfw *oxfw = hwdep->private_data; - __poll_t events; poll_wait(file, &oxfw->hwdep_wait, wait); - spin_lock_irq(&oxfw->lock); + guard(spinlock_irq)(&oxfw->lock); if (oxfw->dev_lock_changed) - events = EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; else - events = 0; - spin_unlock_irq(&oxfw->lock); - - return events; + return 0; } static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg) @@ -88,48 +84,35 @@ static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg) static int hwdep_lock(struct snd_oxfw *oxfw) { - int err; - - spin_lock_irq(&oxfw->lock); + guard(spinlock_irq)(&oxfw->lock); if (oxfw->dev_lock_count == 0) { oxfw->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&oxfw->lock); - - return err; } static int hwdep_unlock(struct snd_oxfw *oxfw) { - int err; - - spin_lock_irq(&oxfw->lock); + guard(spinlock_irq)(&oxfw->lock); if (oxfw->dev_lock_count == -1) { oxfw->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&oxfw->lock); - - return err; } static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_oxfw *oxfw = hwdep->private_data; - spin_lock_irq(&oxfw->lock); + guard(spinlock_irq)(&oxfw->lock); if (oxfw->dev_lock_count == -1) oxfw->dev_lock_count = 0; - spin_unlock_irq(&oxfw->lock); return 0; } diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 7f757f02a877c5..a16bf885f91877 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -84,9 +84,8 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_oxfw *oxfw = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&oxfw->lock, flags); + guard(spinlock_irqsave)(&oxfw->lock); if (up) amdtp_am824_midi_trigger(&oxfw->tx_stream, @@ -94,16 +93,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&oxfw->tx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&oxfw->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_oxfw *oxfw = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&oxfw->lock, flags); + guard(spinlock_irqsave)(&oxfw->lock); if (up) amdtp_am824_midi_trigger(&oxfw->rx_stream, @@ -111,8 +107,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_am824_midi_trigger(&oxfw->rx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&oxfw->lock, flags); } static void set_midi_substream_names(struct snd_oxfw *oxfw, diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 00f7feb91f9295..5e36d7153a7b60 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -866,33 +866,24 @@ void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw) int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw) { - int err; - - spin_lock_irq(&oxfw->lock); + guard(spinlock_irq)(&oxfw->lock); /* user land lock this */ - if (oxfw->dev_lock_count < 0) { - err = -EBUSY; - goto end; - } + if (oxfw->dev_lock_count < 0) + return -EBUSY; /* this is the first time */ if (oxfw->dev_lock_count++ == 0) snd_oxfw_stream_lock_changed(oxfw); - err = 0; -end: - spin_unlock_irq(&oxfw->lock); - return err; + return 0; } void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw) { - spin_lock_irq(&oxfw->lock); + guard(spinlock_irq)(&oxfw->lock); if (WARN_ON(oxfw->dev_lock_count <= 0)) - goto end; + return; if (--oxfw->dev_lock_count == 0) snd_oxfw_stream_lock_changed(oxfw); -end: - spin_unlock_irq(&oxfw->lock); } From 8885ab5f215cc99918b4b711c2d8578004ae5481 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:22 +0200 Subject: [PATCH 0886/1292] ALSA: firewire: tascam: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-19-tiwai@suse.de --- sound/firewire/tascam/amdtp-tascam.c | 17 ++++++------ sound/firewire/tascam/tascam-hwdep.c | 37 ++++++++------------------- sound/firewire/tascam/tascam-midi.c | 10 ++------ sound/firewire/tascam/tascam-stream.c | 21 +++++---------- 4 files changed, 26 insertions(+), 59 deletions(-) diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 079afa4bd3811b..59c339d9b5fb71 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -157,15 +157,14 @@ static void read_status_messages(struct amdtp_stream *s, if ((before ^ after) & mask) { struct snd_firewire_tascam_change *entry = &tscm->queue[tscm->push_pos]; - unsigned long flag; - - spin_lock_irqsave(&tscm->lock, flag); - entry->index = index; - entry->before = before; - entry->after = after; - if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT) - tscm->push_pos = 0; - spin_unlock_irqrestore(&tscm->lock, flag); + + scoped_guard(spinlock_irqsave, &tscm->lock) { + entry->index = index; + entry->before = before; + entry->after = after; + if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT) + tscm->push_pos = 0; + } wake_up(&tscm->hwdep_wait); } diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c index 8fc30cba29d531..867b4ea1096e13 100644 --- a/sound/firewire/tascam/tascam-hwdep.c +++ b/sound/firewire/tascam/tascam-hwdep.c @@ -130,18 +130,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_tscm *tscm = hwdep->private_data; - __poll_t events; poll_wait(file, &tscm->hwdep_wait, wait); - spin_lock_irq(&tscm->lock); + guard(spinlock_irq)(&tscm->lock); if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos) - events = EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; else - events = 0; - spin_unlock_irq(&tscm->lock); - - return events; + return 0; } static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg) @@ -165,38 +161,26 @@ static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg) static int hwdep_lock(struct snd_tscm *tscm) { - int err; - - spin_lock_irq(&tscm->lock); + guard(spinlock_irq)(&tscm->lock); if (tscm->dev_lock_count == 0) { tscm->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&tscm->lock); - - return err; } static int hwdep_unlock(struct snd_tscm *tscm) { - int err; - - spin_lock_irq(&tscm->lock); + guard(spinlock_irq)(&tscm->lock); if (tscm->dev_lock_count == -1) { tscm->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&tscm->lock); - - return err; } static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg) @@ -211,10 +195,9 @@ static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_tscm *tscm = hwdep->private_data; - spin_lock_irq(&tscm->lock); + guard(spinlock_irq)(&tscm->lock); if (tscm->dev_lock_count == -1) tscm->dev_lock_count = 0; - spin_unlock_irq(&tscm->lock); return 0; } diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c index c57fac4f196819..1bf9d7b3da339c 100644 --- a/sound/firewire/tascam/tascam-midi.c +++ b/sound/firewire/tascam/tascam-midi.c @@ -43,30 +43,24 @@ static void midi_playback_drain(struct snd_rawmidi_substream *substream) static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_tscm *tscm = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&tscm->lock, flags); + guard(spinlock_irqsave)(&tscm->lock); if (up) tscm->tx_midi_substreams[substrm->number] = substrm; else tscm->tx_midi_substreams[substrm->number] = NULL; - - spin_unlock_irqrestore(&tscm->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_tscm *tscm = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&tscm->lock, flags); + guard(spinlock_irqsave)(&tscm->lock); if (up) snd_fw_async_midi_port_run(&tscm->out_ports[substrm->number], substrm); - - spin_unlock_irqrestore(&tscm->lock, flags); } int snd_tscm_create_midi_devices(struct snd_tscm *tscm) diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index dfe783d01d7d20..9c8fddd7dee107 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -527,33 +527,24 @@ void snd_tscm_stream_lock_changed(struct snd_tscm *tscm) int snd_tscm_stream_lock_try(struct snd_tscm *tscm) { - int err; - - spin_lock_irq(&tscm->lock); + guard(spinlock_irq)(&tscm->lock); /* user land lock this */ - if (tscm->dev_lock_count < 0) { - err = -EBUSY; - goto end; - } + if (tscm->dev_lock_count < 0) + return -EBUSY; /* this is the first time */ if (tscm->dev_lock_count++ == 0) snd_tscm_stream_lock_changed(tscm); - err = 0; -end: - spin_unlock_irq(&tscm->lock); - return err; + return 0; } void snd_tscm_stream_lock_release(struct snd_tscm *tscm) { - spin_lock_irq(&tscm->lock); + guard(spinlock_irq)(&tscm->lock); if (WARN_ON(tscm->dev_lock_count <= 0)) - goto end; + return; if (--tscm->dev_lock_count == 0) snd_tscm_stream_lock_changed(tscm); -end: - spin_unlock_irq(&tscm->lock); } From 38ac99ff0ab15bf2231058168e988f66740c0785 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Aug 2025 15:27:23 +0200 Subject: [PATCH 0887/1292] ALSA: firewire: lib: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250828132802.9032-20-tiwai@suse.de --- sound/firewire/fcp.c | 19 ++++++++----------- sound/firewire/iso-resources.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c index df44dd5dc4b229..e60bfd0ee4accc 100644 --- a/sound/firewire/fcp.c +++ b/sound/firewire/fcp.c @@ -242,9 +242,9 @@ int fcp_avc_transaction(struct fw_unit *unit, init_waitqueue_head(&t.wait); t.deferrable = (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03); - spin_lock_irq(&transactions_lock); - list_add_tail(&t.list, &transactions); - spin_unlock_irq(&transactions_lock); + scoped_guard(spinlock_irq, &transactions_lock) { + list_add_tail(&t.list, &transactions); + } for (;;) { tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST @@ -280,9 +280,9 @@ int fcp_avc_transaction(struct fw_unit *unit, } } - spin_lock_irq(&transactions_lock); - list_del(&t.list); - spin_unlock_irq(&transactions_lock); + scoped_guard(spinlock_irq, &transactions_lock) { + list_del(&t.list); + } return ret; } @@ -300,7 +300,7 @@ void fcp_bus_reset(struct fw_unit *unit) { struct fcp_transaction *t; - spin_lock_irq(&transactions_lock); + guard(spinlock_irq)(&transactions_lock); list_for_each_entry(t, &transactions, list) { if (t->unit == unit && (t->state == STATE_PENDING || @@ -309,7 +309,6 @@ void fcp_bus_reset(struct fw_unit *unit) wake_up(&t->wait); } } - spin_unlock_irq(&transactions_lock); } EXPORT_SYMBOL(fcp_bus_reset); @@ -341,12 +340,11 @@ static void fcp_response(struct fw_card *card, struct fw_request *request, void *data, size_t length, void *callback_data) { struct fcp_transaction *t; - unsigned long flags; if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC) return; - spin_lock_irqsave(&transactions_lock, flags); + guard(spinlock_irqsave)(&transactions_lock); list_for_each_entry(t, &transactions, list) { struct fw_device *device = fw_parent_device(t->unit); if (device->card != card || @@ -370,7 +368,6 @@ static void fcp_response(struct fw_card *card, struct fw_request *request, wake_up(&t->wait); } } - spin_unlock_irqrestore(&transactions_lock, flags); } static struct fw_address_handler response_register_handler = { diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c index b47ee029d688bb..4f63279225c513 100644 --- a/sound/firewire/iso-resources.c +++ b/sound/firewire/iso-resources.c @@ -114,10 +114,10 @@ int fw_iso_resources_allocate(struct fw_iso_resources *r, r->bandwidth = packet_bandwidth(max_payload_bytes, speed); retry_after_bus_reset: - spin_lock_irq(&card->lock); - r->generation = card->generation; - r->bandwidth_overhead = current_bandwidth_overhead(card); - spin_unlock_irq(&card->lock); + scoped_guard(spinlock_irq, &card->lock) { + r->generation = card->generation; + r->bandwidth_overhead = current_bandwidth_overhead(card); + } err = wait_isoch_resource_delay_after_bus_reset(card); if (err < 0) @@ -167,10 +167,10 @@ int fw_iso_resources_update(struct fw_iso_resources *r) if (!r->allocated) return 0; - spin_lock_irq(&card->lock); - r->generation = card->generation; - r->bandwidth_overhead = current_bandwidth_overhead(card); - spin_unlock_irq(&card->lock); + scoped_guard(spinlock_irq, &card->lock) { + r->generation = card->generation; + r->bandwidth_overhead = current_bandwidth_overhead(card); + } bandwidth = r->bandwidth + r->bandwidth_overhead; From 914c62f21842420ec4118503e0da815faf0acdfe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 30 Aug 2025 10:03:50 +0200 Subject: [PATCH 0888/1292] ALSA: firewire: motu: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Takashi Sakamoto Link: https://patch.msgid.link/20250830080351.25600-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- .../motu/motu-command-dsp-message-parser.c | 9 +---- sound/firewire/motu/motu-hwdep.c | 37 +++++-------------- sound/firewire/motu/motu-midi.c | 10 +---- .../motu/motu-register-dsp-message-parser.c | 18 ++------- sound/firewire/motu/motu-stream.c | 21 +++-------- sound/firewire/motu/motu-transaction.c | 7 ++-- 6 files changed, 27 insertions(+), 75 deletions(-) diff --git a/sound/firewire/motu/motu-command-dsp-message-parser.c b/sound/firewire/motu/motu-command-dsp-message-parser.c index 5d8a86a12f1f45..c6440e6e360b7f 100644 --- a/sound/firewire/motu/motu-command-dsp-message-parser.c +++ b/sound/firewire/motu/motu-command-dsp-message-parser.c @@ -87,10 +87,9 @@ void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s, unsigned int data_block_quadlets = s->data_block_quadlets; struct msg_parser *parser = motu->message_parser; unsigned int interval = parser->interval; - unsigned long flags; int i; - spin_lock_irqsave(&parser->lock, flags); + guard(spinlock_irqsave)(&parser->lock); for (i = 0; i < count; ++i) { __be32 *buffer = desc->ctx_payload; @@ -168,17 +167,13 @@ void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s, } } } - - spin_unlock_irqrestore(&parser->lock, flags); } void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu, struct snd_firewire_motu_command_dsp_meter *meter) { struct msg_parser *parser = motu->message_parser; - unsigned long flags; - spin_lock_irqsave(&parser->lock, flags); + guard(spinlock_irqsave)(&parser->lock); memcpy(meter, &parser->meter, sizeof(*meter)); - spin_unlock_irqrestore(&parser->lock, flags); } diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c index fa2685665db3af..981c19430cb0fe 100644 --- a/sound/firewire/motu/motu-hwdep.c +++ b/sound/firewire/motu/motu-hwdep.c @@ -100,18 +100,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_motu *motu = hwdep->private_data; - __poll_t events; poll_wait(file, &motu->hwdep_wait, wait); - spin_lock_irq(&motu->lock); + guard(spinlock_irq)(&motu->lock); if (motu->dev_lock_changed || motu->msg || has_dsp_event(motu)) - events = EPOLLIN | EPOLLRDNORM; + return EPOLLIN | EPOLLRDNORM; else - events = 0; - spin_unlock_irq(&motu->lock); - - return events; + return 0; } static int hwdep_get_info(struct snd_motu *motu, void __user *arg) @@ -135,48 +131,35 @@ static int hwdep_get_info(struct snd_motu *motu, void __user *arg) static int hwdep_lock(struct snd_motu *motu) { - int err; - - spin_lock_irq(&motu->lock); + guard(spinlock_irq)(&motu->lock); if (motu->dev_lock_count == 0) { motu->dev_lock_count = -1; - err = 0; + return 0; } else { - err = -EBUSY; + return -EBUSY; } - - spin_unlock_irq(&motu->lock); - - return err; } static int hwdep_unlock(struct snd_motu *motu) { - int err; - - spin_lock_irq(&motu->lock); + guard(spinlock_irq)(&motu->lock); if (motu->dev_lock_count == -1) { motu->dev_lock_count = 0; - err = 0; + return 0; } else { - err = -EBADFD; + return -EBADFD; } - - spin_unlock_irq(&motu->lock); - - return err; } static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_motu *motu = hwdep->private_data; - spin_lock_irq(&motu->lock); + guard(spinlock_irq)(&motu->lock); if (motu->dev_lock_count == -1) motu->dev_lock_count = 0; - spin_unlock_irq(&motu->lock); return 0; } diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c index 18c5734e999fb2..85e3260f93490c 100644 --- a/sound/firewire/motu/motu-midi.c +++ b/sound/firewire/motu/motu-midi.c @@ -47,9 +47,8 @@ static int midi_close(struct snd_rawmidi_substream *substream) static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_motu *motu = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&motu->lock, flags); + guard(spinlock_irqsave)(&motu->lock); if (up) amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, @@ -57,16 +56,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&motu->lock, flags); } static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) { struct snd_motu *motu = substrm->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&motu->lock, flags); + guard(spinlock_irqsave)(&motu->lock); if (up) amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, @@ -74,8 +70,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) else amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, NULL); - - spin_unlock_irqrestore(&motu->lock, flags); } static void set_midi_substream_names(struct snd_motu *motu, diff --git a/sound/firewire/motu/motu-register-dsp-message-parser.c b/sound/firewire/motu/motu-register-dsp-message-parser.c index ef3b0b0f0dab9a..a8053e3ef06528 100644 --- a/sound/firewire/motu/motu-register-dsp-message-parser.c +++ b/sound/firewire/motu/motu-register-dsp-message-parser.c @@ -150,10 +150,9 @@ void snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s, struct msg_parser *parser = motu->message_parser; bool meter_pos_quirk = parser->meter_pos_quirk; unsigned int pos = parser->push_pos; - unsigned long flags; int i; - spin_lock_irqsave(&parser->lock, flags); + guard(spinlock_irqsave)(&parser->lock); for (i = 0; i < count; ++i) { __be32 *buffer = desc->ctx_payload; @@ -363,30 +362,24 @@ void snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s, if (pos != parser->push_pos) wake_up(&motu->hwdep_wait); - - spin_unlock_irqrestore(&parser->lock, flags); } void snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu, struct snd_firewire_motu_register_dsp_meter *meter) { struct msg_parser *parser = motu->message_parser; - unsigned long flags; - spin_lock_irqsave(&parser->lock, flags); + guard(spinlock_irqsave)(&parser->lock); memcpy(meter, &parser->meter, sizeof(*meter)); - spin_unlock_irqrestore(&parser->lock, flags); } void snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu, struct snd_firewire_motu_register_dsp_parameter *param) { struct msg_parser *parser = motu->message_parser; - unsigned long flags; - spin_lock_irqsave(&parser->lock, flags); + guard(spinlock_irqsave)(&parser->lock); memcpy(param, &parser->param, sizeof(*param)); - spin_unlock_irqrestore(&parser->lock, flags); } unsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu) @@ -403,12 +396,11 @@ bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 { struct msg_parser *parser = motu->message_parser; unsigned int pos = parser->pull_pos; - unsigned long flags; if (pos == parser->push_pos) return false; - spin_lock_irqsave(&parser->lock, flags); + guard(spinlock_irqsave)(&parser->lock); *event = parser->event_queue[pos]; @@ -417,7 +409,5 @@ bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 pos = 0; parser->pull_pos = pos; - spin_unlock_irqrestore(&parser->lock, flags); - return true; } diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 64aec9c3eefdd7..e5f21360cfb79e 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -407,32 +407,23 @@ static void motu_lock_changed(struct snd_motu *motu) int snd_motu_stream_lock_try(struct snd_motu *motu) { - int err; - - spin_lock_irq(&motu->lock); + guard(spinlock_irq)(&motu->lock); - if (motu->dev_lock_count < 0) { - err = -EBUSY; - goto out; - } + if (motu->dev_lock_count < 0) + return -EBUSY; if (motu->dev_lock_count++ == 0) motu_lock_changed(motu); - err = 0; -out: - spin_unlock_irq(&motu->lock); - return err; + return 0; } void snd_motu_stream_lock_release(struct snd_motu *motu) { - spin_lock_irq(&motu->lock); + guard(spinlock_irq)(&motu->lock); if (WARN_ON(motu->dev_lock_count <= 0)) - goto out; + return; if (--motu->dev_lock_count == 0) motu_lock_changed(motu); -out: - spin_unlock_irq(&motu->lock); } diff --git a/sound/firewire/motu/motu-transaction.c b/sound/firewire/motu/motu-transaction.c index 2dc1d6e59144d6..804f4208cf8167 100644 --- a/sound/firewire/motu/motu-transaction.c +++ b/sound/firewire/motu/motu-transaction.c @@ -51,7 +51,6 @@ static void handle_message(struct fw_card *card, struct fw_request *request, { struct snd_motu *motu = callback_data; __be32 *buf = (__be32 *)data; - unsigned long flags; if (tcode != TCODE_WRITE_QUADLET_REQUEST) { fw_send_response(card, request, RCODE_COMPLETE); @@ -63,9 +62,9 @@ static void handle_message(struct fw_card *card, struct fw_request *request, return; } - spin_lock_irqsave(&motu->lock, flags); - motu->msg = be32_to_cpu(*buf); - spin_unlock_irqrestore(&motu->lock, flags); + scoped_guard(spinlock_irqsave, &motu->lock) { + motu->msg = be32_to_cpu(*buf); + } fw_send_response(card, request, RCODE_COMPLETE); From ceca927c86e6f72f72d45487a34368bc9509431d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 29 Aug 2025 12:07:25 -0700 Subject: [PATCH 0889/1292] arm64: mm: Fix CFI failure due to kpti_ng_pgd_alloc function signature Seen during KPTI initialization: CFI failure at create_kpti_ng_temp_pgd+0x124/0xce8 (target: kpti_ng_pgd_alloc+0x0/0x14; expected type: 0xd61b88b6) The call site is alloc_init_pud() at arch/arm64/mm/mmu.c: pud_phys = pgtable_alloc(TABLE_PUD); alloc_init_pud() has the prototype: static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags) where the pgtable_alloc() prototype is declared. The target (kpti_ng_pgd_alloc) is used in arch/arm64/kernel/cpufeature.c: create_kpti_ng_temp_pgd(kpti_ng_temp_pgd, __pa(alloc), KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL, kpti_ng_pgd_alloc, 0); which is an alias for __create_pgd_mapping_locked() with prototype: extern __alias(__create_pgd_mapping_locked) void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot, phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags); __create_pgd_mapping_locked() passes the function pointer down: __create_pgd_mapping_locked() -> alloc_init_p4d() -> alloc_init_pud() But the target function (kpti_ng_pgd_alloc) has the wrong signature: static phys_addr_t __init kpti_ng_pgd_alloc(int shift); The "int" should be "enum pgtable_type". To make "enum pgtable_type" available to cpufeature.c, move enum pgtable_type definition from arch/arm64/mm/mmu.c to arch/arm64/include/asm/mmu.h. Adjust kpti_ng_pgd_alloc to use "enum pgtable_type" instead of "int". The function behavior remains identical (parameter is unused). Fixes: c64f46ee1377 ("arm64: mm: use enum to identify pgtable level instead of *_SHIFT") Cc: # 6.16.x Signed-off-by: Kees Cook Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20250829190721.it.373-kees@kernel.org Reviewed-by: Ryan Roberts Signed-off-by: Catalin Marinas --- arch/arm64/include/asm/mmu.h | 7 +++++++ arch/arm64/kernel/cpufeature.c | 5 +++-- arch/arm64/mm/mmu.c | 7 ------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 6e8aa8e726015e..49f1a810df1681 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -17,6 +17,13 @@ #include #include +enum pgtable_type { + TABLE_PTE, + TABLE_PMD, + TABLE_PUD, + TABLE_P4D, +}; + typedef struct { atomic64_t id; #ifdef CONFIG_COMPAT diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 9ad065f15f1d61..e49d142a281fe3 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -1945,11 +1946,11 @@ static bool has_pmuv3(const struct arm64_cpu_capabilities *entry, int scope) extern void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), int flags); + phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags); static phys_addr_t __initdata kpti_ng_temp_alloc; -static phys_addr_t __init kpti_ng_pgd_alloc(int shift) +static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type) { kpti_ng_temp_alloc -= PAGE_SIZE; return kpti_ng_temp_alloc; diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 34e5d78af076d0..1838015207404d 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -47,13 +47,6 @@ #define NO_CONT_MAPPINGS BIT(1) #define NO_EXEC_MAPPINGS BIT(2) /* assumes FEAT_HPDS is not used */ -enum pgtable_type { - TABLE_PTE, - TABLE_PMD, - TABLE_PUD, - TABLE_P4D, -}; - u64 kimage_voffset __ro_after_init; EXPORT_SYMBOL(kimage_voffset); From d82aa5d3501b25bfb7bc2a24a68ad0a83b2ad10b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 12 Aug 2025 15:49:27 +0100 Subject: [PATCH 0890/1292] kselftest/arm64: Don't open code SVE_PT_SIZE() in fp-ptrace In fp-trace when allocating a buffer to write SVE register data we open code the addition of the header size to the VL depeendent register data size, which lead to an underallocation bug when we cut'n'pasted the code for FPSIMD format writes. Use the SVE_PT_SIZE() macro that the kernel UAPI provides for this. Fixes: b84d2b27954f ("kselftest/arm64: Test FPSIMD format data writes via NT_ARM_SVE in fp-ptrace") Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20250812-arm64-fp-trace-macro-v1-1-317cfff986a5@kernel.org Signed-off-by: Catalin Marinas --- tools/testing/selftests/arm64/fp/fp-ptrace.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/arm64/fp/fp-ptrace.c b/tools/testing/selftests/arm64/fp/fp-ptrace.c index 124bc883365e44..cdd7a45c045d5f 100644 --- a/tools/testing/selftests/arm64/fp/fp-ptrace.c +++ b/tools/testing/selftests/arm64/fp/fp-ptrace.c @@ -1187,7 +1187,7 @@ static void sve_write_sve(pid_t child, struct test_config *config) if (!vl) return; - iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE); + iov.iov_len = SVE_PT_SIZE(vq, SVE_PT_REGS_SVE); iov.iov_base = malloc(iov.iov_len); if (!iov.iov_base) { ksft_print_msg("Failed allocating %lu byte SVE write buffer\n", @@ -1234,8 +1234,7 @@ static void sve_write_fpsimd(pid_t child, struct test_config *config) if (!vl) return; - iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, - SVE_PT_REGS_FPSIMD); + iov.iov_len = SVE_PT_SIZE(vq, SVE_PT_REGS_FPSIMD); iov.iov_base = malloc(iov.iov_len); if (!iov.iov_base) { ksft_print_msg("Failed allocating %lu byte SVE write buffer\n", From 9dba9a45c348e8460da97c450cddf70b2056deb3 Mon Sep 17 00:00:00 2001 From: John Evans Date: Thu, 28 Aug 2025 12:40:08 +0800 Subject: [PATCH 0891/1292] scsi: lpfc: Fix buffer free/clear order in deferred receive path Fix a use-after-free window by correcting the buffer release sequence in the deferred receive path. The code freed the RQ buffer first and only then cleared the context pointer under the lock. Concurrent paths (e.g., ABTS and the repost path) also inspect and release the same pointer under the lock, so the old order could lead to double-free/UAF. Note that the repost path already uses the correct pattern: detach the pointer under the lock, then free it after dropping the lock. The deferred path should do the same. Fixes: 472e146d1cf3 ("scsi: lpfc: Correct upcalling nvmet_fc transport during io done downcall") Cc: stable@vger.kernel.org Signed-off-by: John Evans Link: https://lore.kernel.org/r/20250828044008.743-1-evans1210144@gmail.com Reviewed-by: Justin Tee Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index fba2e62027b719..4cfc928bcf2d23 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1243,7 +1243,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, struct lpfc_nvmet_tgtport *tgtp; struct lpfc_async_xchg_ctx *ctxp = container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); - struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; + struct rqb_dmabuf *nvmebuf; struct lpfc_hba *phba = ctxp->phba; unsigned long iflag; @@ -1251,13 +1251,18 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, lpfc_nvmeio_data(phba, "NVMET DEFERRCV: xri x%x sz %d CPU %02x\n", ctxp->oxid, ctxp->size, raw_smp_processor_id()); + spin_lock_irqsave(&ctxp->ctxlock, iflag); + nvmebuf = ctxp->rqb_buffer; if (!nvmebuf) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, "6425 Defer rcv: no buffer oxid x%x: " "flg %x ste %x\n", ctxp->oxid, ctxp->flag, ctxp->state); return; } + ctxp->rqb_buffer = NULL; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); tgtp = phba->targetport->private; if (tgtp) @@ -1265,9 +1270,6 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, /* Free the nvmebuf since a new buffer already replaced it */ nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); - spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->rqb_buffer = NULL; - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); } /** From 708e2371f77a9d3f2f1d54d1ec835d71b9d0dafe Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 27 Aug 2025 19:35:50 +0800 Subject: [PATCH 0892/1292] scsi: sr: Reinstate rotational media flag Reinstate the rotational media flag for the CD-ROM driver. The flag has been cleared since commit bd4a633b6f7c ("block: move the nonrot flag to queue_limits") and this breaks some applications. Move queue limit configuration from get_sectorsize() to sr_revalidate_disk() and set the rotational flag. Cc: Christoph Hellwig Fixes: bd4a633b6f7c ("block: move the nonrot flag to queue_limits") Signed-off-by: Ming Lei Link: https://lore.kernel.org/r/20250827113550.2614535-1-ming.lei@redhat.com Signed-off-by: Martin K. Petersen --- drivers/scsi/sr.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index b17796d5ee6652..add13e30689838 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -475,13 +475,21 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) static int sr_revalidate_disk(struct scsi_cd *cd) { + struct request_queue *q = cd->device->request_queue; struct scsi_sense_hdr sshdr; + struct queue_limits lim; + int sector_size; /* if the unit is not ready, nothing more to do */ if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) return 0; sr_cd_check(&cd->cdi); - return get_sectorsize(cd); + sector_size = get_sectorsize(cd); + + lim = queue_limits_start_update(q); + lim.logical_block_size = sector_size; + lim.features |= BLK_FEAT_ROTATIONAL; + return queue_limits_commit_update_frozen(q, &lim); } static int sr_block_open(struct gendisk *disk, blk_mode_t mode) @@ -721,10 +729,8 @@ static int sr_probe(struct device *dev) static int get_sectorsize(struct scsi_cd *cd) { - struct request_queue *q = cd->device->request_queue; static const u8 cmd[10] = { READ_CAPACITY }; unsigned char buffer[8] = { }; - struct queue_limits lim; int err; int sector_size; struct scsi_failure failure_defs[] = { @@ -795,9 +801,7 @@ static int get_sectorsize(struct scsi_cd *cd) set_capacity(cd->disk, cd->capacity); } - lim = queue_limits_start_update(q); - lim.logical_block_size = sector_size; - return queue_limits_commit_update_frozen(q, &lim); + return sector_size; } static int get_capabilities(struct scsi_cd *cd) From d9b05321e21e4b218de4ce8a590bf375f58b6346 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 22 Aug 2025 16:12:38 +0200 Subject: [PATCH 0893/1292] futex: Move futex_hash_free() back to __mmput() To avoid a memory leak via mm_alloc() + mmdrop() the futex cleanup code has been moved to __mmdrop(). This resulted in a warnings if the futex hash table has been allocated via vmalloc() the mmdrop() was invoked from atomic context. The free path must stay in __mmput() to ensure it is invoked from preemptible context. In order to avoid the memory leak, delay the allocation of mm_struct::mm->futex_ref to futex_hash_allocate(). This works because neither the per-CPU counter nor the private hash has been allocated and therefore - futex_private_hash() callers (such as exit_pi_state_list()) don't acquire reference if there is no private hash yet. There is also no reference put. - Regular callers (futex_hash()) fallback to global hash. No reference counting here. The futex_ref member can be allocated in futex_hash_allocate() before the private hash itself is allocated. This happens either while the first thread is created or on request. In both cases the process has just a single thread so there can be either futex operation in progress or the request to create a private hash. Move futex_hash_free() back to __mmput(); Move the allocation of mm_struct::futex_ref to futex_hash_allocate(). [ bp: Fold a follow-up fix to prevent a use-after-free: https://lore.kernel.org/r/20250830213806.sEKuuGSm@linutronix.de ] Fixes: e703b7e247503 ("futex: Move futex cleanup to __mmdrop()") Closes: https://lore.kernel.org/all/20250821102721.6deae493@kernel.org/ Reported-by: Jakub Kicinski Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Borislav Petkov (AMD) Link: https://lkml.kernel.org/r/20250822141238.PfnkTjFb@linutronix.de --- kernel/fork.c | 2 +- kernel/futex/core.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index af673856499dca..c4ada32598bd5e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -689,7 +689,6 @@ void __mmdrop(struct mm_struct *mm) mm_pasid_drop(mm); mm_destroy_cid(mm); percpu_counter_destroy_many(mm->rss_stat, NR_MM_COUNTERS); - futex_hash_free(mm); free_mm(mm); } @@ -1138,6 +1137,7 @@ static inline void __mmput(struct mm_struct *mm) if (mm->binfmt) module_put(mm->binfmt->module); lru_gen_del_mm(mm); + futex_hash_free(mm); mmdrop(mm); } diff --git a/kernel/futex/core.c b/kernel/futex/core.c index d9bb5567af0c5c..125804fbb5cb17 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -1722,12 +1722,9 @@ int futex_mm_init(struct mm_struct *mm) RCU_INIT_POINTER(mm->futex_phash, NULL); mm->futex_phash_new = NULL; /* futex-ref */ + mm->futex_ref = NULL; atomic_long_set(&mm->futex_atomic, 0); mm->futex_batches = get_state_synchronize_rcu(); - mm->futex_ref = alloc_percpu(unsigned int); - if (!mm->futex_ref) - return -ENOMEM; - this_cpu_inc(*mm->futex_ref); /* 0 -> 1 */ return 0; } @@ -1801,6 +1798,17 @@ static int futex_hash_allocate(unsigned int hash_slots, unsigned int flags) } } + if (!mm->futex_ref) { + /* + * This will always be allocated by the first thread and + * therefore requires no locking. + */ + mm->futex_ref = alloc_percpu(unsigned int); + if (!mm->futex_ref) + return -ENOMEM; + this_cpu_inc(*mm->futex_ref); /* 0 -> 1 */ + } + fph = kvzalloc(struct_size(fph, queues, hash_slots), GFP_KERNEL_ACCOUNT | __GFP_NOWARN); if (!fph) From d77b6ff0ce35a6d0b0b7b9581bc3f76d041d4087 Mon Sep 17 00:00:00 2001 From: Stanislav Fort Date: Sun, 31 Aug 2025 16:56:23 +0200 Subject: [PATCH 0894/1292] batman-adv: fix OOB read/write in network-coding decode batadv_nc_skb_decode_packet() trusts coded_len and checks only against skb->len. XOR starts at sizeof(struct batadv_unicast_packet), reducing payload headroom, and the source skb length is not verified, allowing an out-of-bounds read and a small out-of-bounds write. Validate that coded_len fits within the payload area of both destination and source sk_buffs before XORing. Fixes: 2df5278b0267 ("batman-adv: network coding - receive coded packets and decode them") Cc: stable@vger.kernel.org Reported-by: Stanislav Fort Signed-off-by: Stanislav Fort Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/network-coding.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 9f56308779cc3a..af97d077369f9b 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -1687,7 +1687,12 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, coding_len = ntohs(coded_packet_tmp.coded_len); - if (coding_len > skb->len) + /* ensure dst buffer is large enough (payload only) */ + if (coding_len + h_size > skb->len) + return NULL; + + /* ensure src buffer is large enough (payload only) */ + if (coding_len + h_size > nc_packet->skb->len) return NULL; /* Here the magic is reversed: From c09461a0d24fba8a847a37a381626141da22d8ee Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 27 Aug 2025 13:12:16 +0000 Subject: [PATCH 0895/1292] rust: use the new name Location::file_as_c_str() in Rust >= 1.91.0 As part of the stabilization of Location::file_with_nul(), it was brought up that the with_nul() suffix usually means something else in Rust APIs, so the API is being renamed prior to stabilization [1]. Thus, use the new name on new rustc versions. Link: https://www.github.com/rust-lang/rust/pull/145928 [1] Signed-off-by: Alice Ryhl Reviewed-by: Boqun Feng Link: https://lore.kernel.org/r/20250827-file_as_c_str-v1-1-d3f5a3916a9c@google.com [ Kept `cfg` separation. Reworded slightly. - Miguel ] Signed-off-by: Miguel Ojeda --- init/Kconfig | 3 +++ rust/kernel/lib.rs | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 83632025121937..e7459cbea6ca80 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -145,6 +145,9 @@ config RUSTC_HAS_UNNECESSARY_TRANSMUTES config RUSTC_HAS_FILE_WITH_NUL def_bool RUSTC_VERSION >= 108900 +config RUSTC_HAS_FILE_AS_C_STR + def_bool RUSTC_VERSION >= 109100 + config PAHOLE_VERSION int default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE)) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ed53169e795c0b..fef97f2a50984f 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -296,7 +296,7 @@ macro_rules! asm { /// Gets the C string file name of a [`Location`]. /// -/// If `file_with_nul()` is not available, returns a string that warns about it. +/// If `Location::file_as_c_str()` is not available, returns a string that warns about it. /// /// [`Location`]: core::panic::Location /// @@ -310,8 +310,8 @@ macro_rules! asm { /// let caller = core::panic::Location::caller(); /// /// // Output: -/// // - A path like "rust/kernel/example.rs" if file_with_nul() is available. -/// // - "" otherwise. +/// // - A path like "rust/kernel/example.rs" if `file_as_c_str()` is available. +/// // - "" otherwise. /// let caller_file = file_from_location(caller); /// /// // Prints out the message with caller's file name. @@ -326,7 +326,12 @@ macro_rules! asm { /// ``` #[inline] pub fn file_from_location<'a>(loc: &'a core::panic::Location<'a>) -> &'a core::ffi::CStr { - #[cfg(CONFIG_RUSTC_HAS_FILE_WITH_NUL)] + #[cfg(CONFIG_RUSTC_HAS_FILE_AS_C_STR)] + { + loc.file_as_c_str() + } + + #[cfg(all(CONFIG_RUSTC_HAS_FILE_WITH_NUL, not(CONFIG_RUSTC_HAS_FILE_AS_C_STR)))] { loc.file_with_nul() } @@ -334,6 +339,6 @@ pub fn file_from_location<'a>(loc: &'a core::panic::Location<'a>) -> &'a core::f #[cfg(not(CONFIG_RUSTC_HAS_FILE_WITH_NUL))] { let _ = loc; - c"" + c"" } } From 8851e27d2cb947ea8bbbe8e812068f7bf5cbd00b Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Fri, 29 Aug 2025 21:55:25 +0200 Subject: [PATCH 0896/1292] rust: support Rust >= 1.91.0 target spec Starting with Rust 1.91.0 (expected 2025-10-30), the target spec format has changed the type of the `target-pointer-width` key from string to integer [1]. Thus conditionally use one or the other depending on the version. Cc: Waffle Maybe Link: https://github.com/rust-lang/rust/pull/144443 [1] Link: https://lore.kernel.org/r/20250829195525.721664-1-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- scripts/generate_rust_target.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 39c82908ff3a3f..38b3416bb9799e 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -225,7 +225,11 @@ fn main() { ts.push("features", features); ts.push("llvm-target", "x86_64-linux-gnu"); ts.push("supported-sanitizers", ["kcfi", "kernel-address"]); - ts.push("target-pointer-width", "64"); + if cfg.rustc_version_atleast(1, 91, 0) { + ts.push("target-pointer-width", 64); + } else { + ts.push("target-pointer-width", "64"); + } } else if cfg.has("X86_32") { // This only works on UML, as i386 otherwise needs regparm support in rustc if !cfg.has("UML") { @@ -245,7 +249,11 @@ fn main() { } ts.push("features", features); ts.push("llvm-target", "i386-unknown-linux-gnu"); - ts.push("target-pointer-width", "32"); + if cfg.rustc_version_atleast(1, 91, 0) { + ts.push("target-pointer-width", 32); + } else { + ts.push("target-pointer-width", "32"); + } } else if cfg.has("LOONGARCH") { panic!("loongarch uses the builtin rustc loongarch64-unknown-none-softfloat target"); } else { From b320789d6883cc00ac78ce83bccbfe7ed58afcf0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 31 Aug 2025 15:33:07 -0700 Subject: [PATCH 0897/1292] Linux 6.17-rc4 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 06c28b1d7e67a3..b9c66191325044 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = Baby Opossum Posse # *DOCUMENTATION* From 6976c7a69dafbb34a0d4814e2def9d3d7114836d Mon Sep 17 00:00:00 2001 From: Wang Zhaolong Date: Fri, 29 Aug 2025 08:59:59 +0800 Subject: [PATCH 0898/1292] smb: client: Fix NULL pointer dereference in cifs_debug_dirs_proc_show() Reading /proc/fs/cifs/open_dirs may hit a NULL dereference when tcon->cfids is NULL. Add NULL check before accessing cfids to prevent the crash. Reproduction: - Mount CIFS share - cat /proc/fs/cifs/open_dirs Fixes: 844e5c0eb176 ("smb3 client: add way to show directory leases for improved debugging") Signed-off-by: Wang Zhaolong Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index beb4f18f05ef1c..edb2e7f7fc23ad 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -304,6 +304,8 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v) list_for_each(tmp1, &ses->tcon_list) { tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); cfids = tcon->cfids; + if (!cfids) + continue; spin_lock(&cfids->cfid_list_lock); /* check lock ordering */ seq_printf(m, "Num entries: %d\n", cfids->num_entries); list_for_each_entry(cfid, &cfids->entries, entry) { @@ -319,8 +321,6 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v) seq_printf(m, "\n"); } spin_unlock(&cfids->cfid_list_lock); - - } } } From b5ee94ac651aa42612095c4a75ff7f5c47cd9315 Mon Sep 17 00:00:00 2001 From: Philipp Kerling Date: Wed, 20 Aug 2025 16:24:13 +0200 Subject: [PATCH 0899/1292] ksmbd: allow a filename to contain colons on SMB3.1.1 posix extensions If the client sends SMB2_CREATE_POSIX_CONTEXT to ksmbd, allow the filename to contain a colon (':'). This requires disabling the support for Alternate Data Streams (ADS), which are denoted by a colon-separated suffix to the filename on Windows. This should not be an issue, since this concept is not known to POSIX anyway and the client has to explicitly request a POSIX context to get this behavior. Link: https://lore.kernel.org/all/f9401718e2be2ab22058b45a6817db912784ef61.camel@rx2.rx-server.de/ Signed-off-by: Philipp Kerling Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 25 ++++++++++++++----------- fs/smb/server/vfs_cache.h | 2 ++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 0d92ce49aed7bf..a565fc36cee6df 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2951,18 +2951,19 @@ int smb2_open(struct ksmbd_work *work) } ksmbd_debug(SMB, "converted name = %s\n", name); - if (strchr(name, ':')) { - if (!test_share_config_flag(work->tcon->share_conf, - KSMBD_SHARE_FLAG_STREAMS)) { - rc = -EBADF; - goto err_out2; - } - rc = parse_stream_name(name, &stream_name, &s_type); - if (rc < 0) - goto err_out2; - } if (posix_ctxt == false) { + if (strchr(name, ':')) { + if (!test_share_config_flag(work->tcon->share_conf, + KSMBD_SHARE_FLAG_STREAMS)) { + rc = -EBADF; + goto err_out2; + } + rc = parse_stream_name(name, &stream_name, &s_type); + if (rc < 0) + goto err_out2; + } + rc = ksmbd_validate_filename(name); if (rc < 0) goto err_out2; @@ -3443,6 +3444,8 @@ int smb2_open(struct ksmbd_work *work) fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE | FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE)); + fp->is_posix_ctxt = posix_ctxt; + /* fp should be searchable through ksmbd_inode.m_fp_list * after daccess, saccess, attrib_only, and stream are * initialized. @@ -5988,7 +5991,7 @@ static int smb2_rename(struct ksmbd_work *work, if (IS_ERR(new_name)) return PTR_ERR(new_name); - if (strchr(new_name, ':')) { + if (fp->is_posix_ctxt == false && strchr(new_name, ':')) { int s_type; char *xattr_stream_name, *stream_name = NULL; size_t xattr_stream_size; diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h index 0708155b5caf4e..78b506c5ef03b7 100644 --- a/fs/smb/server/vfs_cache.h +++ b/fs/smb/server/vfs_cache.h @@ -112,6 +112,8 @@ struct ksmbd_file { bool is_durable; bool is_persistent; bool is_resilient; + + bool is_posix_ctxt; }; static inline void set_ctx_actor(struct dir_context *ctx, From 592532a77b736b5153e0c2e4c74aa50af0a352ab Mon Sep 17 00:00:00 2001 From: Dennis Beier Date: Sat, 30 Aug 2025 16:43:59 +0200 Subject: [PATCH 0900/1292] cpufreq/longhaul: handle NULL policy in longhaul_exit longhaul_exit() was calling cpufreq_cpu_get(0) without checking for a NULL policy pointer. On some systems, this could lead to a NULL dereference and a kernel warning or panic. This patch adds a check using unlikely() and returns early if the policy is NULL. Bugzilla: #219962 Signed-off-by: Dennis Beier Signed-off-by: Viresh Kumar --- drivers/cpufreq/longhaul.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index ba0e08c8486a6e..49e76b44468aa3 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -953,6 +953,9 @@ static void __exit longhaul_exit(void) struct cpufreq_policy *policy = cpufreq_cpu_get(0); int i; + if (unlikely(!policy)) + return; + for (i = 0; i < numscales; i++) { if (mults[i] == maxmult) { struct cpufreq_freqs freqs; From 0aee6faf5b2e7eacff632dc63bc9b25c5a19dd1d Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 25 Aug 2025 11:05:56 +0900 Subject: [PATCH 0901/1292] MAINTAINERS: Update Nobuhiro Iwamatsu's email address The company's email address has been changed, so update my email address in MAINTAINERS and .mailmap files. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Arnd Bergmann --- .mailmap | 1 + MAINTAINERS | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index a124aeed52a2a3..aa09e792017f77 100644 --- a/.mailmap +++ b/.mailmap @@ -589,6 +589,7 @@ Nikolay Aleksandrov Nikolay Aleksandrov Nikolay Aleksandrov Nikolay Aleksandrov +Nobuhiro Iwamatsu Odelu Kukatla Oleksandr Natalenko Oleksij Rempel diff --git a/MAINTAINERS b/MAINTAINERS index fed6cd812d796a..636547f581cbc3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3526,7 +3526,7 @@ F: Documentation/devicetree/bindings/arm/ti/nspire.yaml F: arch/arm/boot/dts/nspire/ ARM/TOSHIBA VISCONTI ARCHITECTURE -M: Nobuhiro Iwamatsu +M: Nobuhiro Iwamatsu L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwamatsu/linux-visconti.git From 850470a8413a8a78e772c4f6bd9fe81ec6bd5b0f Mon Sep 17 00:00:00 2001 From: yangshiguang Date: Sat, 30 Aug 2025 10:09:46 +0800 Subject: [PATCH 0902/1292] mm: slub: avoid wake up kswapd in set_track_prepare set_track_prepare() can incur lock recursion. The issue is that it is called from hrtimer_start_range_ns holding the per_cpu(hrtimer_bases)[n].lock, but when enabled CONFIG_DEBUG_OBJECTS_TIMERS, may wake up kswapd in set_track_prepare, and try to hold the per_cpu(hrtimer_bases)[n].lock. Avoid deadlock caused by implicitly waking up kswapd by passing in allocation flags, which do not contain __GFP_KSWAPD_RECLAIM in the debug_objects_fill_pool() case. Inside stack depot they are processed by gfp_nested_mask(). Since ___slab_alloc() has preemption disabled, we mask out __GFP_DIRECT_RECLAIM from the flags there. The oops looks something like: BUG: spinlock recursion on CPU#3, swapper/3/0 lock: 0xffffff8a4bf29c80, .magic: dead4ead, .owner: swapper/3/0, .owner_cpu: 3 Hardware name: Qualcomm Technologies, Inc. Popsicle based on SM8850 (DT) Call trace: spin_bug+0x0 _raw_spin_lock_irqsave+0x80 hrtimer_try_to_cancel+0x94 task_contending+0x10c enqueue_dl_entity+0x2a4 dl_server_start+0x74 enqueue_task_fair+0x568 enqueue_task+0xac do_activate_task+0x14c ttwu_do_activate+0xcc try_to_wake_up+0x6c8 default_wake_function+0x20 autoremove_wake_function+0x1c __wake_up+0xac wakeup_kswapd+0x19c wake_all_kswapds+0x78 __alloc_pages_slowpath+0x1ac __alloc_pages_noprof+0x298 stack_depot_save_flags+0x6b0 stack_depot_save+0x14 set_track_prepare+0x5c ___slab_alloc+0xccc __kmalloc_cache_noprof+0x470 __set_page_owner+0x2bc post_alloc_hook[jt]+0x1b8 prep_new_page+0x28 get_page_from_freelist+0x1edc __alloc_pages_noprof+0x13c alloc_slab_page+0x244 allocate_slab+0x7c ___slab_alloc+0x8e8 kmem_cache_alloc_noprof+0x450 debug_objects_fill_pool+0x22c debug_object_activate+0x40 enqueue_hrtimer[jt]+0xdc hrtimer_start_range_ns+0x5f8 ... Signed-off-by: yangshiguang Fixes: 5cf909c553e9 ("mm/slub: use stackdepot to save stack trace in objects") Cc: stable@vger.kernel.org Signed-off-by: Vlastimil Babka --- mm/slub.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 1787e4d51e483d..d257141896c953 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -962,19 +962,19 @@ static struct track *get_track(struct kmem_cache *s, void *object, } #ifdef CONFIG_STACKDEPOT -static noinline depot_stack_handle_t set_track_prepare(void) +static noinline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags) { depot_stack_handle_t handle; unsigned long entries[TRACK_ADDRS_COUNT]; unsigned int nr_entries; nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 3); - handle = stack_depot_save(entries, nr_entries, GFP_NOWAIT); + handle = stack_depot_save(entries, nr_entries, gfp_flags); return handle; } #else -static inline depot_stack_handle_t set_track_prepare(void) +static inline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags) { return 0; } @@ -996,9 +996,9 @@ static void set_track_update(struct kmem_cache *s, void *object, } static __always_inline void set_track(struct kmem_cache *s, void *object, - enum track_item alloc, unsigned long addr) + enum track_item alloc, unsigned long addr, gfp_t gfp_flags) { - depot_stack_handle_t handle = set_track_prepare(); + depot_stack_handle_t handle = set_track_prepare(gfp_flags); set_track_update(s, object, alloc, addr, handle); } @@ -1926,9 +1926,9 @@ static inline bool free_debug_processing(struct kmem_cache *s, static inline void slab_pad_check(struct kmem_cache *s, struct slab *slab) {} static inline int check_object(struct kmem_cache *s, struct slab *slab, void *object, u8 val) { return 1; } -static inline depot_stack_handle_t set_track_prepare(void) { return 0; } +static inline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags) { return 0; } static inline void set_track(struct kmem_cache *s, void *object, - enum track_item alloc, unsigned long addr) {} + enum track_item alloc, unsigned long addr, gfp_t gfp_flags) {} static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n, struct slab *slab) {} static inline void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, @@ -3881,9 +3881,14 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, * For debug caches here we had to go through * alloc_single_from_partial() so just store the * tracking info and return the object. + * + * Due to disabled preemption we need to disallow + * blocking. The flags are further adjusted by + * gfp_nested_mask() in stack_depot itself. */ if (s->flags & SLAB_STORE_USER) - set_track(s, freelist, TRACK_ALLOC, addr); + set_track(s, freelist, TRACK_ALLOC, addr, + gfpflags & ~(__GFP_DIRECT_RECLAIM)); return freelist; } @@ -3915,7 +3920,8 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, goto new_objects; if (s->flags & SLAB_STORE_USER) - set_track(s, freelist, TRACK_ALLOC, addr); + set_track(s, freelist, TRACK_ALLOC, addr, + gfpflags & ~(__GFP_DIRECT_RECLAIM)); return freelist; } @@ -4426,8 +4432,12 @@ static noinline void free_to_partial_list( unsigned long flags; depot_stack_handle_t handle = 0; + /* + * We cannot use GFP_NOWAIT as there are callsites where waking up + * kswapd could deadlock + */ if (s->flags & SLAB_STORE_USER) - handle = set_track_prepare(); + handle = set_track_prepare(__GFP_NOWARN); spin_lock_irqsave(&n->list_lock, flags); From 75e81743e3815a934f5ec688a9837bc5fa56dbb3 Mon Sep 17 00:00:00 2001 From: Harshit Shah Date: Thu, 28 Aug 2025 11:27:49 -0700 Subject: [PATCH 0903/1292] arm64: dts: axiado: Add missing UART aliases Axiado AX3000 EVK has total of 4 UART ports. Add missing alias for uart0, uart1, uart2. This fixes the probe failures on the remaining UARTs. Fixes: 1f7055779001 ("arm64: dts: axiado: Add initial support for AX3000 SoC and eval board") Reviewed-by: Krzysztof Kozlowski Signed-off-by: Harshit Shah Signed-off-by: Arnd Bergmann --- arch/arm64/boot/dts/axiado/ax3000-evk.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/axiado/ax3000-evk.dts b/arch/arm64/boot/dts/axiado/ax3000-evk.dts index 92101c5b534bfa..b86e969625573b 100644 --- a/arch/arm64/boot/dts/axiado/ax3000-evk.dts +++ b/arch/arm64/boot/dts/axiado/ax3000-evk.dts @@ -14,6 +14,9 @@ #size-cells = <2>; aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; serial3 = &uart3; }; From 5545d56fd1a9b1a3a0ac6b144afce5819f32a31b Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 17 Aug 2025 16:36:36 +0800 Subject: [PATCH 0904/1292] PM: hibernate: Use vmalloc_array() and vcalloc() to improve code Remove array_size() calls and replace vmalloc() and vzalloc() with vmalloc_array() and vcalloc() respectively to simplify the code in save_compressed_image() and load_compressed_image(). vmalloc_array() is also optimized better, resulting in less instructions being used, and vmalloc_array() handling overhead is lower [1]. Link: https://lore.kernel.org/lkml/abc66ec5-85a4-47e1-9759-2f60ab111971@vivo.com/ [1] Signed-off-by: Qianfeng Rong Link: https://patch.msgid.link/20250817083636.53872-1-rongqianfeng@vivo.com [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki --- kernel/power/swap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index ad13c461b657c5..0beff7eeaabaf8 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -712,7 +712,7 @@ static int save_compressed_image(struct swap_map_handle *handle, goto out_clean; } - data = vzalloc(array_size(nr_threads, sizeof(*data))); + data = vcalloc(nr_threads, sizeof(*data)); if (!data) { pr_err("Failed to allocate %s data\n", hib_comp_algo); ret = -ENOMEM; @@ -1225,14 +1225,14 @@ static int load_compressed_image(struct swap_map_handle *handle, nr_threads = num_online_cpus() - 1; nr_threads = clamp_val(nr_threads, 1, CMP_THREADS); - page = vmalloc(array_size(CMP_MAX_RD_PAGES, sizeof(*page))); + page = vmalloc_array(CMP_MAX_RD_PAGES, sizeof(*page)); if (!page) { pr_err("Failed to allocate %s page\n", hib_comp_algo); ret = -ENOMEM; goto out_clean; } - data = vzalloc(array_size(nr_threads, sizeof(*data))); + data = vcalloc(nr_threads, sizeof(*data)); if (!data) { pr_err("Failed to allocate %s data\n", hib_comp_algo); ret = -ENOMEM; From 98da8a4aecf584af011cdc67d9581deb21088f24 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Tue, 19 Aug 2025 18:40:38 +0800 Subject: [PATCH 0905/1292] PM: hibernate: Fix typo in memory bitmaps description comment Correct 'leave' to 'leaf' in memory bitmaps description comment. Signed-off-by: Li Jun Link: https://patch.msgid.link/20250819104038.1596952-1-lijun01@kylinos.cn [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- kernel/power/snapshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 501df0676a611a..645f42e4047892 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -363,7 +363,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size) * * One radix tree is represented by one struct mem_zone_bm_rtree. There are * two linked lists for the nodes of the tree, one for the inner nodes and - * one for the leave nodes. The linked leave nodes are used for fast linear + * one for the leaf nodes. The linked leaf nodes are used for fast linear * access of the memory bitmap. * * The struct rtree_node represents one node of the radix tree. From 750b54513f69f1046895346ea97cc3d96584355e Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 18 Aug 2025 23:08:04 +0200 Subject: [PATCH 0906/1292] MAINTAINERS: exclude defconfig from ARM64 PORT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patches for the arm64 defconfig are supposed to be sent to the SoC maintainers (e.g. a change in the generic arm64 defconfig required for Rockchip devices should be send to Heiko Stübner as he is listed as maintainer for "ARM/Rockchip SoC support") and not the ARM64 PORT maintainers. While we cannot easily describe this in MAINTAINERS, we can at least stop it from giving false information and make it behave the same way as for the MAINTAINERS file itself (which basically has the same rules), so that it just outputs the LKML for the ARM64 defconfig. Signed-off-by: Sebastian Reichel Acked-by: Will Deacon Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20250818-arm64-defconfig-v1-1-f589553c3d72@collabora.com Signed-off-by: Arnd Bergmann --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 636547f581cbc3..04a84ada4c198b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3667,6 +3667,7 @@ F: drivers/virt/coco/arm-cca-guest/ F: drivers/virt/coco/pkvm-guest/ F: tools/testing/selftests/arm64/ X: arch/arm64/boot/dts/ +X: arch/arm64/configs/defconfig ARROW SPEEDCHIPS XRS7000 SERIES ETHERNET SWITCH DRIVER M: George McCollister From 69a79ada8eb034ce016b5b78fb7d08d8687223de Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Fri, 8 Aug 2025 13:09:39 +0200 Subject: [PATCH 0907/1292] accel/ivpu: Prevent recovery work from being queued during device removal Use disable_work_sync() instead of cancel_work_sync() in ivpu_dev_fini() to ensure that no new recovery work items can be queued after device removal has started. Previously, recovery work could be scheduled even after canceling existing work, potentially leading to use-after-free bugs if recovery accessed freed resources. Rename ivpu_pm_cancel_recovery() to ivpu_pm_disable_recovery() to better reflect its new behavior. Fixes: 58cde80f45a2 ("accel/ivpu: Use dedicated work for job timeout detection") Cc: stable@vger.kernel.org # v6.8+ Signed-off-by: Karol Wachowski Reviewed-by: Lizhi Hou Signed-off-by: Jacek Lawrynowicz Link: https://lore.kernel.org/r/20250808110939.328366-1-jacek.lawrynowicz@linux.intel.com --- drivers/accel/ivpu/ivpu_drv.c | 2 +- drivers/accel/ivpu/ivpu_pm.c | 4 ++-- drivers/accel/ivpu/ivpu_pm.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 3d6d52492536aa..3289751b475733 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -677,7 +677,7 @@ static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev) static void ivpu_dev_fini(struct ivpu_device *vdev) { ivpu_jobs_abort_all(vdev); - ivpu_pm_cancel_recovery(vdev); + ivpu_pm_disable_recovery(vdev); ivpu_pm_disable(vdev); ivpu_prepare_for_reset(vdev); ivpu_shutdown(vdev); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index eacda1dbe84057..475ddc94f1cfe3 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -417,10 +417,10 @@ void ivpu_pm_init(struct ivpu_device *vdev) ivpu_dbg(vdev, PM, "Autosuspend delay = %d\n", delay); } -void ivpu_pm_cancel_recovery(struct ivpu_device *vdev) +void ivpu_pm_disable_recovery(struct ivpu_device *vdev) { drm_WARN_ON(&vdev->drm, delayed_work_pending(&vdev->pm->job_timeout_work)); - cancel_work_sync(&vdev->pm->recovery_work); + disable_work_sync(&vdev->pm->recovery_work); } void ivpu_pm_enable(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index 89b264cc0e3e78..a2aa7a27f32ef8 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -25,7 +25,7 @@ struct ivpu_pm_info { void ivpu_pm_init(struct ivpu_device *vdev); void ivpu_pm_enable(struct ivpu_device *vdev); void ivpu_pm_disable(struct ivpu_device *vdev); -void ivpu_pm_cancel_recovery(struct ivpu_device *vdev); +void ivpu_pm_disable_recovery(struct ivpu_device *vdev); int ivpu_pm_suspend_cb(struct device *dev); int ivpu_pm_resume_cb(struct device *dev); From 63ddc0a75b3b071f04f4bc277b2510eb06d21648 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 25 Aug 2025 09:27:08 +0200 Subject: [PATCH 0908/1292] arm64: dts: rockchip: fix USB on RADXA ROCK 5T The RADXA ROCK 5T board uses the same GPIO pin for controlling the USB host port regulator. This control pin was mistakenly left out of the ROCK 5T device tree. Reported-by: FUKAUMI Naoki Closes: https://libera.catirclogs.org/linux-rockchip/2025-08-25#38609886; Fixes: 0ea651de9b79 ("arm64: dts: rockchip: add ROCK 5T device tree") Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250825-rock5t-usb-fix-v1-1-de71954a1bb5@collabora.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts index 258c7400301d7f..6acc7a8a5a12ee 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts @@ -95,6 +95,12 @@ rockchip,pins = <4 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; }; }; + + usb { + vcc5v0_host_en: vcc5v0-host-en { + rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; }; &vcc3v3_pcie2x1l0 { @@ -103,3 +109,10 @@ pinctrl-0 = <&pcie2_0_vcc3v3_en>; status = "okay"; }; + +&vcc5v0_host { + enable-active-high; + gpio = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_host_en>; +}; From cc8e91054c0a778074ecffaf12bd0944e884d71c Mon Sep 17 00:00:00 2001 From: Tina Wuest Date: Mon, 1 Sep 2025 12:20:24 +0300 Subject: [PATCH 0909/1292] ALSA: usb-audio: Allow Focusrite devices to use low samplerates Commit 05f254a6369ac020fc0382a7cbd3ef64ad997c92 ("ALSA: usb-audio: Improve filtering of sample rates on Focusrite devices") changed the check for max_rate in a way which was overly restrictive, forcing devices to use very high samplerates if they support them, despite support existing for lower rates as well. This maintains the intended outcome (ensuring samplerates selected are supported) while allowing devices with higher maximum samplerates to be opened at all supported samplerates. This patch was tested with a Clarett+ 8Pre USB Fixes: 05f254a6369a ("ALSA: usb-audio: Improve filtering of sample rates on Focusrite devices") Signed-off-by: Tina Wuest Link: https://patch.msgid.link/20250901092024.140993-1-tina@wuest.me Signed-off-by: Takashi Iwai --- sound/usb/format.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/usb/format.c b/sound/usb/format.c index 0ee532acbb6034..ec95a063beb105 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -327,12 +327,16 @@ static bool focusrite_valid_sample_rate(struct snd_usb_audio *chip, max_rate = combine_quad(&fmt[6]); switch (max_rate) { + case 192000: + if (rate == 176400 || rate == 192000) + return true; + fallthrough; + case 96000: + if (rate == 88200 || rate == 96000) + return true; + fallthrough; case 48000: return (rate == 44100 || rate == 48000); - case 96000: - return (rate == 88200 || rate == 96000); - case 192000: - return (rate == 176400 || rate == 192000); default: usb_audio_info(chip, "%u:%d : unexpected max rate: %u\n", From bcd6659d4911c528381531472a0cefbd4003e29e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Sep 2025 13:50:08 +0200 Subject: [PATCH 0910/1292] ALSA: hda/hdmi: Add pin fix for another HP EliteDesk 800 G4 model It was reported that HP EliteDesk 800 G4 DM 65W (SSID 103c:845a) needs the similar quirk for enabling HDMI outputs, too. This patch adds the corresponding quirk entry. Cc: Link: https://patch.msgid.link/20250901115009.27498-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/codecs/hdmi/hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c index b5d840d9892b95..44576b30f69951 100644 --- a/sound/hda/codecs/hdmi/hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -1582,6 +1582,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) static const struct snd_pci_quirk force_connect_list[] = { SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1), SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1), + SND_PCI_QUIRK(0x103c, 0x845a, "HP EliteDesk 800 G4 DM 65W", 1), SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1), SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1), SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1), From 0a36f7d69dca0fd25ef66acda795b8b2b0228451 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:36 +0200 Subject: [PATCH 0911/1292] ALSA: ac97: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-2-tiwai@suse.de --- sound/pci/ac97/ac97_codec.c | 32 ++++++++++---------------------- sound/pci/ac97/ac97_patch.c | 9 +++------ sound/pci/ac97/ac97_pcm.c | 3 +-- sound/pci/ac97/ac97_proc.c | 10 ++++------ 4 files changed, 18 insertions(+), 36 deletions(-) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index cd60c856a92e90..c54bdefa5afeba 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -326,11 +326,10 @@ void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned sh { if (!snd_ac97_valid_reg(ac97, reg)) return; - mutex_lock(&ac97->reg_mutex); + guard(mutex)(&ac97->reg_mutex); ac97->regs[reg] = value; ac97->bus->ops->write(ac97, reg, value); set_bit(reg, ac97->reg_accessed); - mutex_unlock(&ac97->reg_mutex); } EXPORT_SYMBOL(snd_ac97_write_cache); @@ -353,14 +352,13 @@ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short va if (!snd_ac97_valid_reg(ac97, reg)) return -EINVAL; - mutex_lock(&ac97->reg_mutex); + guard(mutex)(&ac97->reg_mutex); change = ac97->regs[reg] != value; if (change) { ac97->regs[reg] = value; ac97->bus->ops->write(ac97, reg, value); } set_bit(reg, ac97->reg_accessed); - mutex_unlock(&ac97->reg_mutex); return change; } @@ -381,14 +379,10 @@ EXPORT_SYMBOL(snd_ac97_update); */ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value) { - int change; - if (!snd_ac97_valid_reg(ac97, reg)) return -EINVAL; - mutex_lock(&ac97->reg_mutex); - change = snd_ac97_update_bits_nolock(ac97, reg, mask, value); - mutex_unlock(&ac97->reg_mutex); - return change; + guard(mutex)(&ac97->reg_mutex); + return snd_ac97_update_bits_nolock(ac97, reg, mask, value); } EXPORT_SYMBOL(snd_ac97_update_bits); @@ -416,12 +410,12 @@ static int snd_ac97_ad18xx_update_pcm_bits(struct snd_ac97 *ac97, int codec, uns int change; unsigned short old, new, cfg; - mutex_lock(&ac97->page_mutex); + guard(mutex)(&ac97->page_mutex); old = ac97->spec.ad18xx.pcmreg[codec]; new = (old & ~mask) | (value & mask); change = old != new; if (change) { - mutex_lock(&ac97->reg_mutex); + guard(mutex)(&ac97->reg_mutex); cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG); ac97->spec.ad18xx.pcmreg[codec] = new; /* select single codec */ @@ -433,9 +427,7 @@ static int snd_ac97_ad18xx_update_pcm_bits(struct snd_ac97 *ac97, int codec, uns /* select all codecs */ ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG, cfg | 0x7000); - mutex_unlock(&ac97->reg_mutex); } - mutex_unlock(&ac97->page_mutex); return change; } @@ -716,12 +708,11 @@ static int snd_ac97_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); - mutex_lock(&ac97->reg_mutex); + guard(mutex)(&ac97->reg_mutex); ucontrol->value.iec958.status[0] = ac97->spdif_status & 0xff; ucontrol->value.iec958.status[1] = (ac97->spdif_status >> 8) & 0xff; ucontrol->value.iec958.status[2] = (ac97->spdif_status >> 16) & 0xff; ucontrol->value.iec958.status[3] = (ac97->spdif_status >> 24) & 0xff; - mutex_unlock(&ac97->reg_mutex); return 0; } @@ -760,7 +751,7 @@ static int snd_ac97_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ } } - mutex_lock(&ac97->reg_mutex); + guard(mutex)(&ac97->reg_mutex); change = ac97->spdif_status != new; ac97->spdif_status = new; @@ -794,7 +785,6 @@ static int snd_ac97_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ } } - mutex_unlock(&ac97->reg_mutex); return change; } @@ -811,7 +801,7 @@ static int snd_ac97_put_spsa(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ value = (ucontrol->value.integer.value[0] & mask); - mutex_lock(&ac97->reg_mutex); + guard(mutex)(&ac97->reg_mutex); mask <<= shift; value <<= shift; old = snd_ac97_read_cache(ac97, reg); @@ -825,7 +815,6 @@ static int snd_ac97_put_spsa(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ if (extst & AC97_EA_SPDIF) snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ } - mutex_unlock(&ac97->reg_mutex); return change; } @@ -936,10 +925,9 @@ static int snd_ac97_ad18xx_pcm_get_volume(struct snd_kcontrol *kcontrol, struct struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; - mutex_lock(&ac97->page_mutex); + guard(mutex)(&ac97->page_mutex); ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); - mutex_unlock(&ac97->page_mutex); return 0; } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 3002be9d88f306..64cc39dd20083c 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -54,12 +54,11 @@ static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsi unsigned short page_save; int ret; - mutex_lock(&ac97->page_mutex); + guard(mutex)(&ac97->page_mutex); page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK; snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page); ret = snd_ac97_update_bits(ac97, reg, mask, value); snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save); - mutex_unlock(&ac97->page_mutex); /* unlock paging */ return ret; } @@ -976,12 +975,11 @@ static int snd_ac97_stac9708_put_bias(struct snd_kcontrol *kcontrol, struct snd_ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); int err; - mutex_lock(&ac97->page_mutex); + guard(mutex)(&ac97->page_mutex); snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0xabba); err = snd_ac97_update_bits(ac97, AC97_SIGMATEL_BIAS2, 0x0010, (ucontrol->value.integer.value[0] & 1) << 4); snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0); - mutex_unlock(&ac97->page_mutex); return err; } @@ -3699,7 +3697,7 @@ static int snd_ac97_vt1618_UAJ_get(struct snd_kcontrol *kcontrol, unsigned short datpag, uaj; struct snd_ac97 *pac97 = snd_kcontrol_chip(kcontrol); - mutex_lock(&pac97->page_mutex); + guard(mutex)(&pac97->page_mutex); datpag = snd_ac97_read(pac97, AC97_INT_PAGING) & AC97_PAGE_MASK; snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, 0); @@ -3708,7 +3706,6 @@ static int snd_ac97_vt1618_UAJ_get(struct snd_kcontrol *kcontrol, vt1618_uaj[kcontrol->private_value].mask; snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, datpag); - mutex_unlock(&pac97->page_mutex); ucontrol->value.enumerated.item[0] = uaj >> vt1618_uaj[kcontrol->private_value].shift; diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index 5fee8e89790fbc..fa14a562fe8776 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -192,7 +192,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate) mask = AC97_SC_SPSR_MASK; } - mutex_lock(&ac97->reg_mutex); + guard(mutex)(&ac97->reg_mutex); old = snd_ac97_read(ac97, reg) & mask; if (old != bits) { snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); @@ -217,7 +217,6 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate) ac97->spdif_status = sbits; } snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); - mutex_unlock(&ac97->reg_mutex); return 0; } diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 2df3ba9a08dc5b..1c9d76994b3a4f 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -329,7 +329,7 @@ static void snd_ac97_proc_read(struct snd_info_entry *entry, struct snd_info_buf { struct snd_ac97 *ac97 = entry->private_data; - mutex_lock(&ac97->page_mutex); + guard(mutex)(&ac97->page_mutex); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; for (idx = 0; idx < 3; idx++) @@ -355,7 +355,6 @@ static void snd_ac97_proc_read(struct snd_info_entry *entry, struct snd_info_buf } else { snd_ac97_proc_read_main(ac97, buffer, 0); } - mutex_unlock(&ac97->page_mutex); } #ifdef CONFIG_SND_DEBUG @@ -365,7 +364,8 @@ static void snd_ac97_proc_regs_write(struct snd_info_entry *entry, struct snd_in struct snd_ac97 *ac97 = entry->private_data; char line[64]; unsigned int reg, val; - mutex_lock(&ac97->page_mutex); + + guard(mutex)(&ac97->page_mutex); while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; @@ -373,7 +373,6 @@ static void snd_ac97_proc_regs_write(struct snd_info_entry *entry, struct snd_in if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff) snd_ac97_write_cache(ac97, reg, val); } - mutex_unlock(&ac97->page_mutex); } #endif @@ -392,7 +391,7 @@ static void snd_ac97_proc_regs_read(struct snd_info_entry *entry, { struct snd_ac97 *ac97 = entry->private_data; - mutex_lock(&ac97->page_mutex); + guard(mutex)(&ac97->page_mutex); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; @@ -408,7 +407,6 @@ static void snd_ac97_proc_regs_read(struct snd_info_entry *entry, } else { snd_ac97_proc_regs_read_main(ac97, buffer, 0); } - mutex_unlock(&ac97->page_mutex); } void snd_ac97_proc_init(struct snd_ac97 * ac97) From fcee249f98d0b84d5d0222b47d30c93bbca08e17 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:37 +0200 Subject: [PATCH 0912/1292] ALSA: ac97: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-3-tiwai@suse.de --- sound/pci/ac97/ac97_pcm.c | 47 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index fa14a562fe8776..4715d88ff8f4eb 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -570,33 +570,31 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, return err; } } - spin_lock_irq(&pcm->bus->bus_lock); - for (i = 3; i < 12; i++) { - if (!(slots & (1 << i))) - continue; - ok_flag = 0; - for (cidx = 0; cidx < 4; cidx++) { - if (bus->used_slots[pcm->stream][cidx] & (1 << i)) { - spin_unlock_irq(&pcm->bus->bus_lock); - err = -EBUSY; - goto error; + scoped_guard(spinlock_irq, &pcm->bus->bus_lock) { + for (i = 3; i < 12; i++) { + if (!(slots & (1 << i))) + continue; + ok_flag = 0; + for (cidx = 0; cidx < 4; cidx++) { + if (bus->used_slots[pcm->stream][cidx] & (1 << i)) { + err = -EBUSY; + goto error; + } + if (pcm->r[r].rslots[cidx] & (1 << i)) { + bus->used_slots[pcm->stream][cidx] |= (1 << i); + ok_flag++; + } } - if (pcm->r[r].rslots[cidx] & (1 << i)) { - bus->used_slots[pcm->stream][cidx] |= (1 << i); - ok_flag++; + if (!ok_flag) { + dev_err(bus->card->dev, + "cannot find configuration for AC97 slot %i\n", + i); + err = -EAGAIN; + goto error; } } - if (!ok_flag) { - spin_unlock_irq(&pcm->bus->bus_lock); - dev_err(bus->card->dev, - "cannot find configuration for AC97 slot %i\n", - i); - err = -EAGAIN; - goto error; - } + pcm->cur_dbl = r; } - pcm->cur_dbl = r; - spin_unlock_irq(&pcm->bus->bus_lock); for (i = 3; i < 12; i++) { if (!(slots & (1 << i))) continue; @@ -664,7 +662,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) #endif bus = pcm->bus; - spin_lock_irq(&pcm->bus->bus_lock); + guard(spinlock_irq)(&pcm->bus->bus_lock); for (i = 3; i < 12; i++) { if (!(slots & (1 << i))) continue; @@ -673,7 +671,6 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) } pcm->aslots = 0; pcm->cur_dbl = 0; - spin_unlock_irq(&pcm->bus->bus_lock); return 0; } From ee7ddc5c01a9ce3e5de8cce28d6000b495efb53d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:38 +0200 Subject: [PATCH 0913/1292] ALSA: ali5451: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-4-tiwai@suse.de --- sound/pci/ali5451/ali5451.c | 92 +++++++++++++++---------------------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index a6e499e0ceda91..571d89a6a8da27 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -911,13 +911,12 @@ static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec, dev_dbg(codec->card->dev, "alloc_voice: type=%d rec=%d\n", type, rec); - spin_lock_irq(&codec->voice_alloc); + guard(spinlock_irq)(&codec->voice_alloc); if (type == SNDRV_ALI_VOICE_TYPE_PCM) { idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) : snd_ali_find_free_channel(codec,rec); if (idx < 0) { dev_err(codec->card->dev, "ali_alloc_voice: err.\n"); - spin_unlock_irq(&codec->voice_alloc); return NULL; } pvoice = &(codec->synth.voices[idx]); @@ -925,10 +924,8 @@ static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec, pvoice->use = 1; pvoice->pcm = 1; pvoice->mode = rec; - spin_unlock_irq(&codec->voice_alloc); return pvoice; } - spin_unlock_irq(&codec->voice_alloc); return NULL; } @@ -943,16 +940,16 @@ static void snd_ali_free_voice(struct snd_ali * codec, if (!pvoice->use) return; snd_ali_clear_voices(codec, pvoice->number, pvoice->number); - spin_lock_irq(&codec->voice_alloc); - private_free = pvoice->private_free; - private_data = pvoice->private_data; - pvoice->private_free = NULL; - pvoice->private_data = NULL; - if (pvoice->pcm) - snd_ali_free_channel_pcm(codec, pvoice->number); - pvoice->use = pvoice->pcm = pvoice->synth = 0; - pvoice->substream = NULL; - spin_unlock_irq(&codec->voice_alloc); + scoped_guard(spinlock_irq, &codec->voice_alloc) { + private_free = pvoice->private_free; + private_data = pvoice->private_data; + pvoice->private_free = NULL; + pvoice->private_data = NULL; + if (pvoice->pcm) + snd_ali_free_channel_pcm(codec, pvoice->number); + pvoice->use = pvoice->pcm = pvoice->synth = 0; + pvoice->substream = NULL; + } if (private_free) private_free(private_data); } @@ -1109,7 +1106,7 @@ static int snd_ali_trigger(struct snd_pcm_substream *substream, snd_pcm_trigger_done(s, substream); } } - spin_lock(&codec->reg_lock); + guard(spinlock)(&codec->reg_lock); if (!do_start) outl(what, ALI_REG(codec, ALI_STOP)); val = inl(ALI_REG(codec, ALI_AINTEN)); @@ -1121,7 +1118,6 @@ static int snd_ali_trigger(struct snd_pcm_substream *substream, if (do_start) outl(what, ALI_REG(codec, ALI_START)); dev_dbg(codec->card->dev, "trigger: what=%xh whati=%xh\n", what, whati); - spin_unlock(&codec->reg_lock); return 0; } @@ -1189,8 +1185,8 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream) dev_dbg(codec->card->dev, "playback_prepare ...\n"); - spin_lock_irq(&codec->reg_lock); - + guard(spinlock_irq)(&codec->reg_lock); + /* set Delta (rate) value */ Delta = snd_ali_convert_rate(runtime->rate, 0); @@ -1259,7 +1255,6 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream) CTRL, EC); } - spin_unlock_irq(&codec->reg_lock); return 0; } @@ -1360,14 +1355,11 @@ snd_ali_playback_pointer(struct snd_pcm_substream *substream) struct snd_ali_voice *pvoice = runtime->private_data; unsigned int cso; - spin_lock(&codec->reg_lock); - if (!pvoice->running) { - spin_unlock(&codec->reg_lock); + guard(spinlock)(&codec->reg_lock); + if (!pvoice->running) return 0; - } outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)); - spin_unlock(&codec->reg_lock); dev_dbg(codec->card->dev, "playback pointer returned cso=%xh.\n", cso); cso %= runtime->buffer_size; @@ -1382,14 +1374,11 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream) struct snd_ali_voice *pvoice = runtime->private_data; unsigned int cso; - spin_lock(&codec->reg_lock); - if (!pvoice->running) { - spin_unlock(&codec->reg_lock); + guard(spinlock)(&codec->reg_lock); + if (!pvoice->running) return 0; - } outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)); - spin_unlock(&codec->reg_lock); cso %= runtime->buffer_size; return cso; @@ -1693,7 +1682,7 @@ static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol, spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0; - spin_lock_irq(&codec->reg_lock); + guard(spinlock_irq)(&codec->reg_lock); switch (kcontrol->private_value) { case 0: spdif_enable = (codec->spdif_mask & 0x02) ? 1 : 0; @@ -1709,7 +1698,6 @@ static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol, break; } ucontrol->value.integer.value[0] = spdif_enable; - spin_unlock_irq(&codec->reg_lock); return 0; } @@ -1721,7 +1709,7 @@ static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol, spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0; - spin_lock_irq(&codec->reg_lock); + guard(spinlock_irq)(&codec->reg_lock); switch (kcontrol->private_value) { case 0: change = (codec->spdif_mask & 0x02) ? 1 : 0; @@ -1766,7 +1754,6 @@ static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol, default: break; } - spin_unlock_irq(&codec->reg_lock); return change; } @@ -1833,7 +1820,7 @@ static int ali_suspend(struct device *dev) for (i = 0; i < chip->num_of_codecs; i++) snd_ac97_suspend(chip->ac97[i]); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); im->regs[ALI_MISCINT >> 2] = inl(ALI_REG(chip, ALI_MISCINT)); /* im->regs[ALI_START >> 2] = inl(ALI_REG(chip, ALI_START)); */ @@ -1857,7 +1844,6 @@ static int ali_suspend(struct device *dev) /* stop all HW channel */ outl(0xffffffff, ALI_REG(chip, ALI_STOP)); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1868,27 +1854,25 @@ static int ali_resume(struct device *dev) struct snd_ali_image *im = &chip->image; int i, j; - spin_lock_irq(&chip->reg_lock); - - for (i = 0; i < ALI_CHANNELS; i++) { - outb(i, ALI_REG(chip, ALI_GC_CIR)); - for (j = 0; j < ALI_CHANNEL_REGS; j++) - outl(im->channel_regs[i][j], ALI_REG(chip, j*4 + 0xe0)); - } + scoped_guard(spinlock_irq, &chip->reg_lock) { + for (i = 0; i < ALI_CHANNELS; i++) { + outb(i, ALI_REG(chip, ALI_GC_CIR)); + for (j = 0; j < ALI_CHANNEL_REGS; j++) + outl(im->channel_regs[i][j], ALI_REG(chip, j*4 + 0xe0)); + } - for (i = 0; i < ALI_GLOBAL_REGS; i++) { - if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP) || - (i*4 == ALI_START)) - continue; - outl(im->regs[i], ALI_REG(chip, i*4)); + for (i = 0; i < ALI_GLOBAL_REGS; i++) { + if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP) || + (i*4 == ALI_START)) + continue; + outl(im->regs[i], ALI_REG(chip, i*4)); + } + + /* start HW channel */ + outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START)); + /* restore IRQ enable bits */ + outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT)); } - - /* start HW channel */ - outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START)); - /* restore IRQ enable bits */ - outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT)); - - spin_unlock_irq(&chip->reg_lock); for (i = 0 ; i < chip->num_of_codecs; i++) snd_ac97_resume(chip->ac97[i]); From e96f601e7dd01ae34144839c9757bd9a53e062fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:39 +0200 Subject: [PATCH 0914/1292] ALSA: azt3328: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-5-tiwai@suse.de --- sound/pci/azt3328.c | 145 ++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 79 deletions(-) diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index b33344f65b8c72..6cdf76e2b7d2e3 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1201,7 +1201,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, unsigned int channels ) { - unsigned long flags; u16 val = 0xff00; u8 freq = 0; @@ -1244,7 +1243,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, if (format_width == 16) val |= SOUNDFORMAT_FLAG_16BIT; - spin_lock_irqsave(codec->lock, flags); + guard(spinlock_irqsave)(codec->lock); /* set bitrate/format */ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); @@ -1266,8 +1265,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, DMA_EPILOGUE_SOMETHING | DMA_SOMETHING_ELSE ); - - spin_unlock_irqrestore(codec->lock, flags); } static inline void @@ -1373,8 +1370,6 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, if (!codec->running) { /* AZF3328 uses a two buffer pointer DMA transfer approach */ - unsigned long flags; - /* width 32bit (prevent overflow): */ u32 area_length; struct codec_setup_io { @@ -1405,11 +1400,10 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, /* build combined I/O buffer length word */ setup_io.dma_lengths = (area_length << 16) | (area_length); - spin_lock_irqsave(codec->lock, flags); + guard(spinlock_irqsave)(codec->lock); snd_azf3328_codec_outl_multi( codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3 ); - spin_unlock_irqrestore(codec->lock, flags); } } @@ -1464,48 +1458,48 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_pcm_format_width(runtime->format), runtime->channels); - spin_lock(codec->lock); - /* first, remember current value: */ - flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); + scoped_guard(spinlock, codec->lock) { + /* first, remember current value: */ + flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); - /* stop transfer */ - flags1 &= ~DMA_RESUME; - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); + /* stop transfer */ + flags1 &= ~DMA_RESUME; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); - /* FIXME: clear interrupts or what??? */ - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); - spin_unlock(codec->lock); + /* FIXME: clear interrupts or what??? */ + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); + } snd_azf3328_codec_setdmaa(chip, codec, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream) ); - spin_lock(codec->lock); + scoped_guard(spinlock, codec->lock) { #ifdef WIN9X - /* FIXME: enable playback/recording??? */ - flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); - - /* start transfer again */ - /* FIXME: what is this value (0x0010)??? */ - flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); + /* FIXME: enable playback/recording??? */ + flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); + + /* start transfer again */ + /* FIXME: what is this value (0x0010)??? */ + flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); #else /* NT4 */ - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, - 0x0000); - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, - DMA_RUN_SOMETHING1); - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, - DMA_RUN_SOMETHING1 | - DMA_RUN_SOMETHING2); - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, - DMA_RESUME | - SOMETHING_ALMOST_ALWAYS_SET | - DMA_EPILOGUE_SOMETHING | - DMA_SOMETHING_ELSE); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + 0x0000); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + DMA_RUN_SOMETHING1); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + DMA_RUN_SOMETHING1 | + DMA_RUN_SOMETHING2); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + DMA_RESUME | + SOMETHING_ALMOST_ALWAYS_SET | + DMA_EPILOGUE_SOMETHING | + DMA_SOMETHING_ELSE); #endif - spin_unlock(codec->lock); + } snd_azf3328_ctrl_codec_activity(chip, codec->type, 1); if (is_main_mixer_playback_codec) { @@ -1521,14 +1515,14 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_RESUME: dev_dbg(chip->card->dev, "PCM RESUME %s\n", codec->name); /* resume codec if we were active */ - spin_lock(codec->lock); - if (codec->running) - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, - snd_azf3328_codec_inw( - codec, IDX_IO_CODEC_DMA_FLAGS - ) | DMA_RESUME - ); - spin_unlock(codec->lock); + scoped_guard(spinlock, codec->lock) { + if (codec->running) + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + snd_azf3328_codec_inw( + codec, IDX_IO_CODEC_DMA_FLAGS + ) | DMA_RESUME + ); + } break; case SNDRV_PCM_TRIGGER_STOP: dev_dbg(chip->card->dev, "PCM STOP %s\n", codec->name); @@ -1541,22 +1535,22 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ); } - spin_lock(codec->lock); - /* first, remember current value: */ - flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); + scoped_guard(spinlock, codec->lock) { + /* first, remember current value: */ + flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); - /* stop transfer */ - flags1 &= ~DMA_RESUME; - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); + /* stop transfer */ + flags1 &= ~DMA_RESUME; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); - /* hmm, is this really required? we're resetting the same bit - * immediately thereafter... */ - flags1 |= DMA_RUN_SOMETHING1; - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); + /* hmm, is this really required? we're resetting the same bit + * immediately thereafter... */ + flags1 |= DMA_RUN_SOMETHING1; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); - flags1 &= ~DMA_RUN_SOMETHING1; - snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); - spin_unlock(codec->lock); + flags1 &= ~DMA_RUN_SOMETHING1; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); + } snd_azf3328_ctrl_codec_activity(chip, codec->type, 0); if (is_main_mixer_playback_codec) { @@ -1724,12 +1718,11 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, struct snd_azf3328 *chip = gameport_get_port_data(gameport); int i; u8 val; - unsigned long flags; if (snd_BUG_ON(!chip)) return 0; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE); *buttons = (~(val) >> 4) & 0xf; @@ -1766,7 +1759,6 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); - spin_unlock_irqrestore(&chip->reg_lock, flags); for (i = 0; i < ARRAY_SIZE(chip->axes); i++) { axes[i] = chip->axes[i]; @@ -1863,11 +1855,11 @@ snd_azf3328_pcm_interrupt(struct snd_azf3328 *chip, if (!(status & (1 << codec_type))) continue; - spin_lock(codec->lock); - which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); - /* ack all IRQ types immediately */ - snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); - spin_unlock(codec->lock); + scoped_guard(spinlock, codec->lock) { + which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); + /* ack all IRQ types immediately */ + snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); + } if (codec->substream) { snd_pcm_period_elapsed(codec->substream); @@ -1912,9 +1904,9 @@ snd_azf3328_interrupt(int irq, void *dev_id) if (chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); /* ACK timer */ - spin_lock(&chip->reg_lock); - snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); + } dev_dbg(chip->card->dev, "timer IRQ\n"); } @@ -2137,7 +2129,6 @@ static int snd_azf3328_timer_start(struct snd_timer *timer) { struct snd_azf3328 *chip; - unsigned long flags; unsigned int delay; chip = snd_timer_chip(timer); @@ -2152,9 +2143,8 @@ snd_azf3328_timer_start(struct snd_timer *timer) } dev_dbg(chip->card->dev, "setting timer countdown value %d\n", delay); delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -2162,10 +2152,9 @@ static int snd_azf3328_timer_stop(struct snd_timer *timer) { struct snd_azf3328 *chip; - unsigned long flags; chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); /* disable timer countdown and interrupt */ /* Hmm, should we write TIMER_IRQ_ACK here? YES indeed, otherwise a rogue timer operation - which prompts @@ -2174,7 +2163,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer) Simply manually poking 0x04 _once_ immediately successfully stops the hardware/ALSA interrupt activity. */ snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -2406,10 +2394,9 @@ snd_azf3328_create(struct snd_card *card, codec->running = true; snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); - spin_lock_irq(codec->lock); + guard(spinlock_irq)(codec->lock); snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, dma_init); - spin_unlock_irq(codec->lock); } return 0; From d701303bf465dce024f40f3969ad62ed4621d159 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:40 +0200 Subject: [PATCH 0915/1292] ALSA: ens137x: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-6-tiwai@suse.de --- sound/pci/ak4531_codec.c | 18 ++++++------------ sound/pci/ens1370.c | 13 ++++--------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c index e54812bfb2c6ee..cdad47e4098dc4 100644 --- a/sound/pci/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c @@ -77,9 +77,8 @@ static int snd_ak4531_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e int invert = (kcontrol->private_value >> 22) & 1; int val; - mutex_lock(&ak4531->reg_mutex); + guard(mutex)(&ak4531->reg_mutex); val = (ak4531->regs[reg] >> shift) & mask; - mutex_unlock(&ak4531->reg_mutex); if (invert) { val = mask - val; } @@ -102,11 +101,10 @@ static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e val = mask - val; } val <<= shift; - mutex_lock(&ak4531->reg_mutex); + guard(mutex)(&ak4531->reg_mutex); val = (ak4531->regs[reg] & ~(mask << shift)) | val; change = val != ak4531->regs[reg]; ak4531->write(ak4531, reg, ak4531->regs[reg] = val); - mutex_unlock(&ak4531->reg_mutex); return change; } @@ -146,10 +144,9 @@ static int snd_ak4531_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e int invert = (kcontrol->private_value >> 22) & 1; int left, right; - mutex_lock(&ak4531->reg_mutex); + guard(mutex)(&ak4531->reg_mutex); left = (ak4531->regs[left_reg] >> left_shift) & mask; right = (ak4531->regs[right_reg] >> right_shift) & mask; - mutex_unlock(&ak4531->reg_mutex); if (invert) { left = mask - left; right = mask - right; @@ -179,7 +176,7 @@ static int snd_ak4531_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e } left <<= left_shift; right <<= right_shift; - mutex_lock(&ak4531->reg_mutex); + guard(mutex)(&ak4531->reg_mutex); if (left_reg == right_reg) { left = (ak4531->regs[left_reg] & ~((mask << left_shift) | (mask << right_shift))) | left | right; change = left != ak4531->regs[left_reg]; @@ -191,7 +188,6 @@ static int snd_ak4531_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e ak4531->write(ak4531, left_reg, ak4531->regs[left_reg] = left); ak4531->write(ak4531, right_reg, ak4531->regs[right_reg] = right); } - mutex_unlock(&ak4531->reg_mutex); return change; } @@ -218,12 +214,11 @@ static int snd_ak4531_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl int left_shift = (kcontrol->private_value >> 16) & 0x0f; int right_shift = (kcontrol->private_value >> 24) & 0x0f; - mutex_lock(&ak4531->reg_mutex); + guard(mutex)(&ak4531->reg_mutex); ucontrol->value.integer.value[0] = (ak4531->regs[reg1] >> left_shift) & 1; ucontrol->value.integer.value[1] = (ak4531->regs[reg2] >> left_shift) & 1; ucontrol->value.integer.value[2] = (ak4531->regs[reg1] >> right_shift) & 1; ucontrol->value.integer.value[3] = (ak4531->regs[reg2] >> right_shift) & 1; - mutex_unlock(&ak4531->reg_mutex); return 0; } @@ -237,7 +232,7 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl int change; int val1, val2; - mutex_lock(&ak4531->reg_mutex); + guard(mutex)(&ak4531->reg_mutex); val1 = ak4531->regs[reg1] & ~((1 << left_shift) | (1 << right_shift)); val2 = ak4531->regs[reg2] & ~((1 << left_shift) | (1 << right_shift)); val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; @@ -247,7 +242,6 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl change = val1 != ak4531->regs[reg1] || val2 != ak4531->regs[reg2]; ak4531->write(ak4531, reg1, ak4531->regs[reg1] = val1); ak4531->write(ak4531, reg2, ak4531->regs[reg2] = val2); - mutex_unlock(&ak4531->reg_mutex); return change; } diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 82e10ecb919667..23a756ece3c5aa 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -596,7 +596,7 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97, unsigned int t, x, flag; flag = is_ev1938(ensoniq) ? EV_1938_CODEC_MAGIC : 0; - mutex_lock(&ensoniq->src_mutex); + guard(mutex)(&ensoniq->src_mutex); for (t = 0; t < POLL_COUNT; t++) { if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) { /* save the current state for latter */ @@ -622,11 +622,9 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97, /* restore SRC reg */ snd_es1371_wait_src_ready(ensoniq); outl(x, ES_REG(ensoniq, 1371_SMPRATE)); - mutex_unlock(&ensoniq->src_mutex); return; } } - mutex_unlock(&ensoniq->src_mutex); dev_err(ensoniq->card->dev, "codec write timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); } @@ -713,7 +711,7 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) { unsigned int n, truncm, freq; - mutex_lock(&ensoniq->src_mutex); + guard(mutex)(&ensoniq->src_mutex); n = rate / 3000; if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9))) n--; @@ -737,14 +735,13 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) snd_es1371_src_write(ensoniq, ES_SMPREG_ADC + ES_SMPREG_VFREQ_FRAC, freq & 0x7fff); snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC, n << 8); snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC + 1, n << 8); - mutex_unlock(&ensoniq->src_mutex); } static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate) { unsigned int freq, r; - mutex_lock(&ensoniq->src_mutex); + guard(mutex)(&ensoniq->src_mutex); freq = DIV_ROUND_CLOSEST(rate << 15, 3000); r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P2 | ES_1371_DIS_R1)) | @@ -758,14 +755,13 @@ static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate) r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P2 | ES_1371_DIS_R1)); outl(r, ES_REG(ensoniq, 1371_SMPRATE)); - mutex_unlock(&ensoniq->src_mutex); } static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate) { unsigned int freq, r; - mutex_lock(&ensoniq->src_mutex); + guard(mutex)(&ensoniq->src_mutex); freq = DIV_ROUND_CLOSEST(rate << 15, 3000); r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P1 | ES_1371_DIS_R1)) | @@ -780,7 +776,6 @@ static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate) r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE | ES_1371_DIS_P1 | ES_1371_DIS_R1)); outl(r, ES_REG(ensoniq, 1371_SMPRATE)); - mutex_unlock(&ensoniq->src_mutex); } #endif /* CHIP1371 */ From d062d6977ea3d8d4e0188ad05e329d9b129f1aa4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:41 +0200 Subject: [PATCH 0916/1292] ALSA: ens137x: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-7-tiwai@suse.de --- sound/pci/ens1370.c | 303 ++++++++++++++++++++------------------------ 1 file changed, 138 insertions(+), 165 deletions(-) diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 23a756ece3c5aa..657056a59175bc 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -799,13 +799,13 @@ static int snd_ensoniq_trigger(struct snd_pcm_substream *substream, int cmd) } else if (s == ensoniq->capture_substream) return -EINVAL; } - spin_lock(&ensoniq->reg_lock); - if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) - ensoniq->sctrl |= what; - else - ensoniq->sctrl &= ~what; - outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); - spin_unlock(&ensoniq->reg_lock); + scoped_guard(spinlock, &ensoniq->reg_lock) { + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) + ensoniq->sctrl |= what; + else + ensoniq->sctrl &= ~what; + outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); + } break; } case SNDRV_PCM_TRIGGER_START: @@ -825,13 +825,13 @@ static int snd_ensoniq_trigger(struct snd_pcm_substream *substream, int cmd) snd_pcm_trigger_done(s, substream); } } - spin_lock(&ensoniq->reg_lock); - if (cmd == SNDRV_PCM_TRIGGER_START) - ensoniq->ctrl |= what; - else - ensoniq->ctrl &= ~what; - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock(&ensoniq->reg_lock); + scoped_guard(spinlock, &ensoniq->reg_lock) { + if (cmd == SNDRV_PCM_TRIGGER_START) + ensoniq->ctrl |= what; + else + ensoniq->ctrl &= ~what; + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + } break; } default: @@ -856,36 +856,36 @@ static int snd_ensoniq_playback1_prepare(struct snd_pcm_substream *substream) mode |= 0x02; if (runtime->channels > 1) mode |= 0x01; - spin_lock_irq(&ensoniq->reg_lock); - ensoniq->ctrl &= ~ES_DAC1_EN; + scoped_guard(spinlock_irq, &ensoniq->reg_lock) { + ensoniq->ctrl &= ~ES_DAC1_EN; #ifdef CHIP1371 - /* 48k doesn't need SRC (it breaks AC3-passthru) */ - if (runtime->rate == 48000) - ensoniq->ctrl |= ES_1373_BYPASS_P1; - else - ensoniq->ctrl &= ~ES_1373_BYPASS_P1; + /* 48k doesn't need SRC (it breaks AC3-passthru) */ + if (runtime->rate == 48000) + ensoniq->ctrl |= ES_1373_BYPASS_P1; + else + ensoniq->ctrl &= ~ES_1373_BYPASS_P1; #endif - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); - outl(runtime->dma_addr, ES_REG(ensoniq, DAC1_FRAME)); - outl((ensoniq->p1_dma_size >> 2) - 1, ES_REG(ensoniq, DAC1_SIZE)); - ensoniq->sctrl &= ~(ES_P1_LOOP_SEL | ES_P1_PAUSE | ES_P1_SCT_RLD | ES_P1_MODEM); - ensoniq->sctrl |= ES_P1_INT_EN | ES_P1_MODEO(mode); - outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); - outl((ensoniq->p1_period_size >> snd_ensoniq_sample_shift[mode]) - 1, - ES_REG(ensoniq, DAC1_COUNT)); + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); + outl(runtime->dma_addr, ES_REG(ensoniq, DAC1_FRAME)); + outl((ensoniq->p1_dma_size >> 2) - 1, ES_REG(ensoniq, DAC1_SIZE)); + ensoniq->sctrl &= ~(ES_P1_LOOP_SEL | ES_P1_PAUSE | ES_P1_SCT_RLD | ES_P1_MODEM); + ensoniq->sctrl |= ES_P1_INT_EN | ES_P1_MODEO(mode); + outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); + outl((ensoniq->p1_period_size >> snd_ensoniq_sample_shift[mode]) - 1, + ES_REG(ensoniq, DAC1_COUNT)); #ifdef CHIP1370 - ensoniq->ctrl &= ~ES_1370_WTSRSELM; - switch (runtime->rate) { - case 5512: ensoniq->ctrl |= ES_1370_WTSRSEL(0); break; - case 11025: ensoniq->ctrl |= ES_1370_WTSRSEL(1); break; - case 22050: ensoniq->ctrl |= ES_1370_WTSRSEL(2); break; - case 44100: ensoniq->ctrl |= ES_1370_WTSRSEL(3); break; - default: snd_BUG(); - } + ensoniq->ctrl &= ~ES_1370_WTSRSELM; + switch (runtime->rate) { + case 5512: ensoniq->ctrl |= ES_1370_WTSRSEL(0); break; + case 11025: ensoniq->ctrl |= ES_1370_WTSRSEL(1); break; + case 22050: ensoniq->ctrl |= ES_1370_WTSRSEL(2); break; + case 44100: ensoniq->ctrl |= ES_1370_WTSRSEL(3); break; + default: snd_BUG(); + } #endif - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irq(&ensoniq->reg_lock); + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + } #ifndef CHIP1370 snd_es1371_dac1_rate(ensoniq, runtime->rate); #endif @@ -904,28 +904,28 @@ static int snd_ensoniq_playback2_prepare(struct snd_pcm_substream *substream) mode |= 0x02; if (runtime->channels > 1) mode |= 0x01; - spin_lock_irq(&ensoniq->reg_lock); - ensoniq->ctrl &= ~ES_DAC2_EN; - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); - outl(runtime->dma_addr, ES_REG(ensoniq, DAC2_FRAME)); - outl((ensoniq->p2_dma_size >> 2) - 1, ES_REG(ensoniq, DAC2_SIZE)); - ensoniq->sctrl &= ~(ES_P2_LOOP_SEL | ES_P2_PAUSE | ES_P2_DAC_SEN | - ES_P2_END_INCM | ES_P2_ST_INCM | ES_P2_MODEM); - ensoniq->sctrl |= ES_P2_INT_EN | ES_P2_MODEO(mode) | - ES_P2_END_INCO(mode & 2 ? 2 : 1) | ES_P2_ST_INCO(0); - outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); - outl((ensoniq->p2_period_size >> snd_ensoniq_sample_shift[mode]) - 1, - ES_REG(ensoniq, DAC2_COUNT)); + scoped_guard(spinlock_irq, &ensoniq->reg_lock) { + ensoniq->ctrl &= ~ES_DAC2_EN; + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); + outl(runtime->dma_addr, ES_REG(ensoniq, DAC2_FRAME)); + outl((ensoniq->p2_dma_size >> 2) - 1, ES_REG(ensoniq, DAC2_SIZE)); + ensoniq->sctrl &= ~(ES_P2_LOOP_SEL | ES_P2_PAUSE | ES_P2_DAC_SEN | + ES_P2_END_INCM | ES_P2_ST_INCM | ES_P2_MODEM); + ensoniq->sctrl |= ES_P2_INT_EN | ES_P2_MODEO(mode) | + ES_P2_END_INCO(mode & 2 ? 2 : 1) | ES_P2_ST_INCO(0); + outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); + outl((ensoniq->p2_period_size >> snd_ensoniq_sample_shift[mode]) - 1, + ES_REG(ensoniq, DAC2_COUNT)); #ifdef CHIP1370 - if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_CAPTURE)) { - ensoniq->ctrl &= ~ES_1370_PCLKDIVM; - ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate)); - ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_PLAY2; - } + if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_CAPTURE)) { + ensoniq->ctrl &= ~ES_1370_PCLKDIVM; + ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate)); + ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_PLAY2; + } #endif - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irq(&ensoniq->reg_lock); + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + } #ifndef CHIP1370 snd_es1371_dac2_rate(ensoniq, runtime->rate); #endif @@ -944,26 +944,26 @@ static int snd_ensoniq_capture_prepare(struct snd_pcm_substream *substream) mode |= 0x02; if (runtime->channels > 1) mode |= 0x01; - spin_lock_irq(&ensoniq->reg_lock); - ensoniq->ctrl &= ~ES_ADC_EN; - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE)); - outl(runtime->dma_addr, ES_REG(ensoniq, ADC_FRAME)); - outl((ensoniq->c_dma_size >> 2) - 1, ES_REG(ensoniq, ADC_SIZE)); - ensoniq->sctrl &= ~(ES_R1_LOOP_SEL | ES_R1_MODEM); - ensoniq->sctrl |= ES_R1_INT_EN | ES_R1_MODEO(mode); - outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); - outl((ensoniq->c_period_size >> snd_ensoniq_sample_shift[mode]) - 1, - ES_REG(ensoniq, ADC_COUNT)); + scoped_guard(spinlock_irq, &ensoniq->reg_lock) { + ensoniq->ctrl &= ~ES_ADC_EN; + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE)); + outl(runtime->dma_addr, ES_REG(ensoniq, ADC_FRAME)); + outl((ensoniq->c_dma_size >> 2) - 1, ES_REG(ensoniq, ADC_SIZE)); + ensoniq->sctrl &= ~(ES_R1_LOOP_SEL | ES_R1_MODEM); + ensoniq->sctrl |= ES_R1_INT_EN | ES_R1_MODEO(mode); + outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); + outl((ensoniq->c_period_size >> snd_ensoniq_sample_shift[mode]) - 1, + ES_REG(ensoniq, ADC_COUNT)); #ifdef CHIP1370 - if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_PLAY2)) { - ensoniq->ctrl &= ~ES_1370_PCLKDIVM; - ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate)); - ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_CAPTURE; - } + if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_PLAY2)) { + ensoniq->ctrl &= ~ES_1370_PCLKDIVM; + ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate)); + ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_CAPTURE; + } #endif - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irq(&ensoniq->reg_lock); + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + } #ifndef CHIP1370 snd_es1371_adc_rate(ensoniq, runtime->rate); #endif @@ -975,16 +975,14 @@ static snd_pcm_uframes_t snd_ensoniq_playback1_pointer(struct snd_pcm_substream struct ensoniq *ensoniq = snd_pcm_substream_chip(substream); size_t ptr; - spin_lock(&ensoniq->reg_lock); + guard(spinlock)(&ensoniq->reg_lock); if (inl(ES_REG(ensoniq, CONTROL)) & ES_DAC1_EN) { outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, DAC1_SIZE))); - ptr = bytes_to_frames(substream->runtime, ptr); + return bytes_to_frames(substream->runtime, ptr); } else { - ptr = 0; + return 0; } - spin_unlock(&ensoniq->reg_lock); - return ptr; } static snd_pcm_uframes_t snd_ensoniq_playback2_pointer(struct snd_pcm_substream *substream) @@ -992,16 +990,14 @@ static snd_pcm_uframes_t snd_ensoniq_playback2_pointer(struct snd_pcm_substream struct ensoniq *ensoniq = snd_pcm_substream_chip(substream); size_t ptr; - spin_lock(&ensoniq->reg_lock); + guard(spinlock)(&ensoniq->reg_lock); if (inl(ES_REG(ensoniq, CONTROL)) & ES_DAC2_EN) { outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE)); ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, DAC2_SIZE))); - ptr = bytes_to_frames(substream->runtime, ptr); + return bytes_to_frames(substream->runtime, ptr); } else { - ptr = 0; + return 0; } - spin_unlock(&ensoniq->reg_lock); - return ptr; } static snd_pcm_uframes_t snd_ensoniq_capture_pointer(struct snd_pcm_substream *substream) @@ -1009,16 +1005,14 @@ static snd_pcm_uframes_t snd_ensoniq_capture_pointer(struct snd_pcm_substream *s struct ensoniq *ensoniq = snd_pcm_substream_chip(substream); size_t ptr; - spin_lock(&ensoniq->reg_lock); + guard(spinlock)(&ensoniq->reg_lock); if (inl(ES_REG(ensoniq, CONTROL)) & ES_ADC_EN) { outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE)); ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, ADC_SIZE))); - ptr = bytes_to_frames(substream->runtime, ptr); + return bytes_to_frames(substream->runtime, ptr); } else { - ptr = 0; + return 0; } - spin_unlock(&ensoniq->reg_lock); - return ptr; } static const struct snd_pcm_hardware snd_ensoniq_playback1 = @@ -1096,10 +1090,10 @@ static int snd_ensoniq_playback1_open(struct snd_pcm_substream *substream) ensoniq->playback1_substream = substream; runtime->hw = snd_ensoniq_playback1; snd_pcm_set_sync(substream); - spin_lock_irq(&ensoniq->reg_lock); - if (ensoniq->spdif && ensoniq->playback2_substream == NULL) - ensoniq->spdif_stream = ensoniq->spdif_default; - spin_unlock_irq(&ensoniq->reg_lock); + scoped_guard(spinlock_irq, &ensoniq->reg_lock) { + if (ensoniq->spdif && ensoniq->playback2_substream == NULL) + ensoniq->spdif_stream = ensoniq->spdif_default; + } #ifdef CHIP1370 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_es1370_hw_constraints_rates); @@ -1119,10 +1113,10 @@ static int snd_ensoniq_playback2_open(struct snd_pcm_substream *substream) ensoniq->playback2_substream = substream; runtime->hw = snd_ensoniq_playback2; snd_pcm_set_sync(substream); - spin_lock_irq(&ensoniq->reg_lock); - if (ensoniq->spdif && ensoniq->playback1_substream == NULL) - ensoniq->spdif_stream = ensoniq->spdif_default; - spin_unlock_irq(&ensoniq->reg_lock); + scoped_guard(spinlock_irq, &ensoniq->reg_lock) { + if (ensoniq->spdif && ensoniq->playback1_substream == NULL) + ensoniq->spdif_stream = ensoniq->spdif_default; + } #ifdef CHIP1370 snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_es1370_hw_constraints_clock); @@ -1166,12 +1160,11 @@ static int snd_ensoniq_playback2_close(struct snd_pcm_substream *substream) struct ensoniq *ensoniq = snd_pcm_substream_chip(substream); ensoniq->playback2_substream = NULL; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); #ifdef CHIP1370 ensoniq->u.es1370.pclkdiv_lock &= ~ES_MODE_PLAY2; #endif ensoniq->mode &= ~ES_MODE_PLAY2; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1180,12 +1173,11 @@ static int snd_ensoniq_capture_close(struct snd_pcm_substream *substream) struct ensoniq *ensoniq = snd_pcm_substream_chip(substream); ensoniq->capture_substream = NULL; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); #ifdef CHIP1370 ensoniq->u.es1370.pclkdiv_lock &= ~ES_MODE_CAPTURE; #endif ensoniq->mode &= ~ES_MODE_CAPTURE; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1307,12 +1299,12 @@ static int snd_ens1373_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&ensoniq->reg_lock); + + guard(spinlock_irq)(&ensoniq->reg_lock); ucontrol->value.iec958.status[0] = (ensoniq->spdif_default >> 0) & 0xff; ucontrol->value.iec958.status[1] = (ensoniq->spdif_default >> 8) & 0xff; ucontrol->value.iec958.status[2] = (ensoniq->spdif_default >> 16) & 0xff; ucontrol->value.iec958.status[3] = (ensoniq->spdif_default >> 24) & 0xff; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1327,13 +1319,12 @@ static int snd_ens1373_spdif_default_put(struct snd_kcontrol *kcontrol, ((u32)ucontrol->value.iec958.status[1] << 8) | ((u32)ucontrol->value.iec958.status[2] << 16) | ((u32)ucontrol->value.iec958.status[3] << 24); - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); change = ensoniq->spdif_default != val; ensoniq->spdif_default = val; if (change && ensoniq->playback1_substream == NULL && ensoniq->playback2_substream == NULL) outl(val, ES_REG(ensoniq, CHANNEL_STATUS)); - spin_unlock_irq(&ensoniq->reg_lock); return change; } @@ -1351,12 +1342,12 @@ static int snd_ens1373_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&ensoniq->reg_lock); + + guard(spinlock_irq)(&ensoniq->reg_lock); ucontrol->value.iec958.status[0] = (ensoniq->spdif_stream >> 0) & 0xff; ucontrol->value.iec958.status[1] = (ensoniq->spdif_stream >> 8) & 0xff; ucontrol->value.iec958.status[2] = (ensoniq->spdif_stream >> 16) & 0xff; ucontrol->value.iec958.status[3] = (ensoniq->spdif_stream >> 24) & 0xff; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1371,13 +1362,12 @@ static int snd_ens1373_spdif_stream_put(struct snd_kcontrol *kcontrol, ((u32)ucontrol->value.iec958.status[1] << 8) | ((u32)ucontrol->value.iec958.status[2] << 16) | ((u32)ucontrol->value.iec958.status[3] << 24); - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); change = ensoniq->spdif_stream != val; ensoniq->spdif_stream = val; if (change && (ensoniq->playback1_substream != NULL || ensoniq->playback2_substream != NULL)) outl(val, ES_REG(ensoniq, CHANNEL_STATUS)); - spin_unlock_irq(&ensoniq->reg_lock); return change; } @@ -1392,9 +1382,8 @@ static int snd_es1371_spdif_get(struct snd_kcontrol *kcontrol, { struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1373_SPDIF_THRU ? 1 : 0; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1407,7 +1396,7 @@ static int snd_es1371_spdif_put(struct snd_kcontrol *kcontrol, nval1 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_THRU : 0; nval2 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_EN : 0; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); change = (ensoniq->ctrl & ES_1373_SPDIF_THRU) != nval1; ensoniq->ctrl &= ~ES_1373_SPDIF_THRU; ensoniq->ctrl |= nval1; @@ -1415,7 +1404,6 @@ static int snd_es1371_spdif_put(struct snd_kcontrol *kcontrol, ensoniq->cssr |= nval2; outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); - spin_unlock_irq(&ensoniq->reg_lock); return change; } @@ -1455,12 +1443,11 @@ static int snd_es1373_rear_get(struct snd_kcontrol *kcontrol, struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol); int val = 0; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); if ((ensoniq->cssr & (ES_1373_REAR_BIT27|ES_1373_REAR_BIT26| ES_1373_REAR_BIT24)) == ES_1373_REAR_BIT26) val = 1; ucontrol->value.integer.value[0] = val; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1473,13 +1460,12 @@ static int snd_es1373_rear_put(struct snd_kcontrol *kcontrol, nval1 = ucontrol->value.integer.value[0] ? ES_1373_REAR_BIT26 : (ES_1373_REAR_BIT27|ES_1373_REAR_BIT24); - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); change = (ensoniq->cssr & (ES_1373_REAR_BIT27| ES_1373_REAR_BIT26|ES_1373_REAR_BIT24)) != nval1; ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT26|ES_1373_REAR_BIT24); ensoniq->cssr |= nval1; outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); - spin_unlock_irq(&ensoniq->reg_lock); return change; } @@ -1500,11 +1486,10 @@ static int snd_es1373_line_get(struct snd_kcontrol *kcontrol, struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol); int val = 0; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); if (ensoniq->ctrl & ES_1371_GPIO_OUT(4)) val = 1; ucontrol->value.integer.value[0] = val; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1515,7 +1500,7 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol, int changed; unsigned int ctrl; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); ctrl = ensoniq->ctrl; if (ucontrol->value.integer.value[0]) ensoniq->ctrl |= ES_1371_GPIO_OUT(4); /* switch line-in -> rear out */ @@ -1524,7 +1509,6 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol, changed = (ctrl != ensoniq->ctrl); if (changed) outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irq(&ensoniq->reg_lock); return changed; } @@ -1660,9 +1644,8 @@ static int snd_ensoniq_control_get(struct snd_kcontrol *kcontrol, struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol); int mask = kcontrol->private_value; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); ucontrol->value.integer.value[0] = ensoniq->ctrl & mask ? 1 : 0; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -1675,12 +1658,11 @@ static int snd_ensoniq_control_put(struct snd_kcontrol *kcontrol, int change; nval = ucontrol->value.integer.value[0] ? mask : 0; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); change = (ensoniq->ctrl & mask) != nval; ensoniq->ctrl &= ~mask; ensoniq->ctrl |= nval; outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irq(&ensoniq->reg_lock); return change; } @@ -2074,19 +2056,19 @@ static void snd_ensoniq_midi_interrupt(struct ensoniq * ensoniq) if (rmidi == NULL) return; /* do Rx at first */ - spin_lock(&ensoniq->reg_lock); - mask = ensoniq->uartm & ES_MODE_INPUT ? ES_RXRDY : 0; - while (mask) { - status = inb(ES_REG(ensoniq, UART_STATUS)); - if ((status & mask) == 0) - break; - byte = inb(ES_REG(ensoniq, UART_DATA)); - snd_rawmidi_receive(ensoniq->midi_input, &byte, 1); + scoped_guard(spinlock, &ensoniq->reg_lock) { + mask = ensoniq->uartm & ES_MODE_INPUT ? ES_RXRDY : 0; + while (mask) { + status = inb(ES_REG(ensoniq, UART_STATUS)); + if ((status & mask) == 0) + break; + byte = inb(ES_REG(ensoniq, UART_DATA)); + snd_rawmidi_receive(ensoniq->midi_input, &byte, 1); + } } - spin_unlock(&ensoniq->reg_lock); /* do Tx at second */ - spin_lock(&ensoniq->reg_lock); + guard(spinlock)(&ensoniq->reg_lock); mask = ensoniq->uartm & ES_MODE_OUTPUT ? ES_TXRDY : 0; while (mask) { status = inb(ES_REG(ensoniq, UART_STATUS)); @@ -2100,14 +2082,13 @@ static void snd_ensoniq_midi_interrupt(struct ensoniq * ensoniq) outb(byte, ES_REG(ensoniq, UART_DATA)); } } - spin_unlock(&ensoniq->reg_lock); } static int snd_ensoniq_midi_input_open(struct snd_rawmidi_substream *substream) { struct ensoniq *ensoniq = substream->rmidi->private_data; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); ensoniq->uartm |= ES_MODE_INPUT; ensoniq->midi_input = substream; if (!(ensoniq->uartm & ES_MODE_OUTPUT)) { @@ -2115,7 +2096,6 @@ static int snd_ensoniq_midi_input_open(struct snd_rawmidi_substream *substream) outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL)); outl(ensoniq->ctrl |= ES_UART_EN, ES_REG(ensoniq, CONTROL)); } - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -2123,7 +2103,7 @@ static int snd_ensoniq_midi_input_close(struct snd_rawmidi_substream *substream) { struct ensoniq *ensoniq = substream->rmidi->private_data; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); if (!(ensoniq->uartm & ES_MODE_OUTPUT)) { outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL)); outl(ensoniq->ctrl &= ~ES_UART_EN, ES_REG(ensoniq, CONTROL)); @@ -2132,7 +2112,6 @@ static int snd_ensoniq_midi_input_close(struct snd_rawmidi_substream *substream) } ensoniq->midi_input = NULL; ensoniq->uartm &= ~ES_MODE_INPUT; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -2140,7 +2119,7 @@ static int snd_ensoniq_midi_output_open(struct snd_rawmidi_substream *substream) { struct ensoniq *ensoniq = substream->rmidi->private_data; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); ensoniq->uartm |= ES_MODE_OUTPUT; ensoniq->midi_output = substream; if (!(ensoniq->uartm & ES_MODE_INPUT)) { @@ -2148,7 +2127,6 @@ static int snd_ensoniq_midi_output_open(struct snd_rawmidi_substream *substream) outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL)); outl(ensoniq->ctrl |= ES_UART_EN, ES_REG(ensoniq, CONTROL)); } - spin_unlock_irq(&ensoniq->reg_lock); return 0; } @@ -2156,7 +2134,7 @@ static int snd_ensoniq_midi_output_close(struct snd_rawmidi_substream *substream { struct ensoniq *ensoniq = substream->rmidi->private_data; - spin_lock_irq(&ensoniq->reg_lock); + guard(spinlock_irq)(&ensoniq->reg_lock); if (!(ensoniq->uartm & ES_MODE_INPUT)) { outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL)); outl(ensoniq->ctrl &= ~ES_UART_EN, ES_REG(ensoniq, CONTROL)); @@ -2165,17 +2143,15 @@ static int snd_ensoniq_midi_output_close(struct snd_rawmidi_substream *substream } ensoniq->midi_output = NULL; ensoniq->uartm &= ~ES_MODE_OUTPUT; - spin_unlock_irq(&ensoniq->reg_lock); return 0; } static void snd_ensoniq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct ensoniq *ensoniq = substream->rmidi->private_data; int idx; - spin_lock_irqsave(&ensoniq->reg_lock, flags); + guard(spinlock_irqsave)(&ensoniq->reg_lock); if (up) { if ((ensoniq->uartc & ES_RXINTEN) == 0) { /* empty input FIFO */ @@ -2190,16 +2166,14 @@ static void snd_ensoniq_midi_input_trigger(struct snd_rawmidi_substream *substre outb(ensoniq->uartc, ES_REG(ensoniq, UART_CONTROL)); } } - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); } static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct ensoniq *ensoniq = substream->rmidi->private_data; unsigned char byte; - spin_lock_irqsave(&ensoniq->reg_lock, flags); + guard(spinlock_irqsave)(&ensoniq->reg_lock); if (up) { if (ES_TXINTENI(ensoniq->uartc) == 0) { ensoniq->uartc |= ES_TXINTENO(1); @@ -2220,7 +2194,6 @@ static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substr outb(ensoniq->uartc, ES_REG(ensoniq, UART_CONTROL)); } } - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); } static const struct snd_rawmidi_ops snd_ensoniq_midi_output = @@ -2271,17 +2244,17 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id) if (!(status & ES_INTR)) return IRQ_NONE; - spin_lock(&ensoniq->reg_lock); - sctrl = ensoniq->sctrl; - if (status & ES_DAC1) - sctrl &= ~ES_P1_INT_EN; - if (status & ES_DAC2) - sctrl &= ~ES_P2_INT_EN; - if (status & ES_ADC) - sctrl &= ~ES_R1_INT_EN; - outl(sctrl, ES_REG(ensoniq, SERIAL)); - outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); - spin_unlock(&ensoniq->reg_lock); + scoped_guard(spinlock, &ensoniq->reg_lock) { + sctrl = ensoniq->sctrl; + if (status & ES_DAC1) + sctrl &= ~ES_P1_INT_EN; + if (status & ES_DAC2) + sctrl &= ~ES_P2_INT_EN; + if (status & ES_ADC) + sctrl &= ~ES_R1_INT_EN; + outl(sctrl, ES_REG(ensoniq, SERIAL)); + outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); + } if (status & ES_UART) snd_ensoniq_midi_interrupt(ensoniq); From f28745ab9fc57aae02cf800362f76c2f2f89f170 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:42 +0200 Subject: [PATCH 0917/1292] ALSA: als300: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-8-tiwai@suse.de --- sound/pci/als300.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/sound/pci/als300.c b/sound/pci/als300.c index f9e8424dc77f87..733e84def5a709 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -402,7 +402,7 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream) unsigned short period_bytes = snd_pcm_lib_period_bytes(substream); unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL); tmp &= ~TRANSFER_START; @@ -419,7 +419,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream) runtime->dma_addr); snd_als300_gcr_write(chip->port, PLAYBACK_END, runtime->dma_addr + buffer_bytes - 1); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -431,7 +430,7 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream) unsigned short period_bytes = snd_pcm_lib_period_bytes(substream); unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL); tmp &= ~TRANSFER_START; @@ -448,7 +447,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream) runtime->dma_addr); snd_als300_gcr_write(chip->port, RECORD_END, runtime->dma_addr + buffer_bytes - 1); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -463,7 +461,7 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd) data = substream->runtime->private_data; reg = data->control_register; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -492,7 +490,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd) snd_als300_dbgplay("TRIGGER INVALID\n"); ret = -EINVAL; } - spin_unlock(&chip->reg_lock); return ret; } @@ -506,10 +503,10 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream) data = substream->runtime->private_data; period_bytes = snd_pcm_lib_period_bytes(substream); - spin_lock(&chip->reg_lock); - current_ptr = (u16) snd_als300_gcr_read(chip->port, - data->block_counter_register) + 4; - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + current_ptr = (u16) snd_als300_gcr_read(chip->port, + data->block_counter_register) + 4; + } if (current_ptr > period_bytes) current_ptr = 0; else @@ -563,10 +560,9 @@ static int snd_als300_new_pcm(struct snd_als300 *chip) static void snd_als300_init(struct snd_als300 *chip) { - unsigned long flags; u32 tmp; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16) & 0x0000000F; /* Setup DRAM */ @@ -591,7 +587,6 @@ static void snd_als300_init(struct snd_als300 *chip) tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL); snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL, tmp & ~TRANSFER_START); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static int snd_als300_create(struct snd_card *card, From fe0f9c2e72262bd9fb21ef5083840d51a7677a8e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:43 +0200 Subject: [PATCH 0918/1292] ALSA: als4000: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-9-tiwai@suse.de --- sound/pci/als4000.c | 68 +++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index eb159497c905a7..33034e07b3d680 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -369,14 +369,14 @@ static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream) count >>= 1; count--; - spin_lock_irq(&chip->reg_lock); - snd_als4000_set_rate(chip, runtime->rate); - snd_als4000_set_capture_dma(chip, runtime->dma_addr, size); - spin_unlock_irq(&chip->reg_lock); - spin_lock_irq(&chip->mixer_lock); - snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff); - snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8); - spin_unlock_irq(&chip->mixer_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + snd_als4000_set_rate(chip, runtime->rate); + snd_als4000_set_capture_dma(chip, runtime->dma_addr, size); + } + scoped_guard(spinlock_irq, &chip->mixer_lock) { + snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff); + snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8); + } return 0; } @@ -402,7 +402,7 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream) * reordering, ...). Something seems to get enabled on playback * that I haven't found out how to disable again, which then causes * the switching pops to reach the speakers the next time here. */ - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); snd_als4000_set_rate(chip, runtime->rate); snd_als4000_set_playback_dma(chip, runtime->dma_addr, size); @@ -413,7 +413,6 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream) snd_sbdsp_command(chip, count & 0xff); snd_sbdsp_command(chip, count >> 8); snd_sbdsp_command(chip, playback_cmd(chip).dma_off); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -429,7 +428,7 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int Probably need to take reg_lock as outer (or inner??) lock, too. (or serialize both lock operations? probably not, though... - racy?) */ - spin_lock(&chip->mixer_lock); + guard(spinlock)(&chip->mixer_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -447,7 +446,6 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int result = -EINVAL; break; } - spin_unlock(&chip->mixer_lock); return result; } @@ -456,7 +454,7 @@ static int snd_als4000_playback_trigger(struct snd_pcm_substream *substream, int struct snd_sb *chip = snd_pcm_substream_chip(substream); int result = 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -472,7 +470,6 @@ static int snd_als4000_playback_trigger(struct snd_pcm_substream *substream, int result = -EINVAL; break; } - spin_unlock(&chip->reg_lock); return result; } @@ -481,9 +478,9 @@ static snd_pcm_uframes_t snd_als4000_capture_pointer(struct snd_pcm_substream *s struct snd_sb *chip = snd_pcm_substream_chip(substream); unsigned int result; - spin_lock(&chip->reg_lock); - result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR); + } result &= 0xffff; return bytes_to_frames( substream->runtime, result ); } @@ -493,9 +490,9 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream * struct snd_sb *chip = snd_pcm_substream_chip(substream); unsigned result; - spin_lock(&chip->reg_lock); - result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR); + } result &= 0xffff; return bytes_to_frames( substream->runtime, result ); } @@ -536,10 +533,10 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id) snd_als4k_iobase_writeb(chip->alt_port, ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU, pci_irqstatus); - spin_lock(&chip->mixer_lock); - /* SPECS_PAGE: 20 */ - sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); - spin_unlock(&chip->mixer_lock); + scoped_guard(spinlock, &chip->mixer_lock) { + /* SPECS_PAGE: 20 */ + sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); + } if (sb_irqstatus & SB_IRQTYPE_8BIT) snd_sb_ack_8bit(chip); @@ -709,18 +706,18 @@ static void snd_als4000_configure(struct snd_sb *chip) int i; /* do some more configuration */ - spin_lock_irq(&chip->mixer_lock); - tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG); - snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG, - tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE); - /* always select DMA channel 0, since we do not actually use DMA - * SPECS_PAGE: 19/20 */ - snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0); - snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG, - tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE); - spin_unlock_irq(&chip->mixer_lock); + scoped_guard(spinlock_irq, &chip->mixer_lock) { + tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG); + snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG, + tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE); + /* always select DMA channel 0, since we do not actually use DMA + * SPECS_PAGE: 19/20 */ + snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0); + snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG, + tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE); + } - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); /* enable interrupts */ snd_als4k_gcr_write(chip, ALS4K_GCR8C_MISC_CTRL, ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE); @@ -731,7 +728,6 @@ static void snd_als4000_configure(struct snd_sb *chip) /* enable burst mode to prevent dropouts during high PCI bus usage */ snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL, (snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL) & ~0x07) | 0x04); - spin_unlock_irq(&chip->reg_lock); } #ifdef SUPPORT_JOYSTICK From 7f08b008afbc9bd17c8e3f7d275448417456192a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:44 +0200 Subject: [PATCH 0919/1292] ALSA: ad1889: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-10-tiwai@suse.de --- sound/pci/ad1889.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 020cbb467e7e68..f4ec404c0d15a2 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -353,7 +353,7 @@ snd_ad1889_playback_prepare(struct snd_pcm_substream *ss) reg |= AD_DS_WSMC_WAST; /* let's make sure we don't clobber ourselves */ - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); chip->wave.size = size; chip->wave.reg = reg; @@ -372,8 +372,6 @@ snd_ad1889_playback_prepare(struct snd_pcm_substream *ss) /* writes flush */ ad1889_readw(chip, AD_DS_WSMC); - spin_unlock_irq(&chip->lock); - dev_dbg(chip->card->dev, "prepare playback: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr, count, size, reg, rt->rate); @@ -403,7 +401,7 @@ snd_ad1889_capture_prepare(struct snd_pcm_substream *ss) reg |= AD_DS_RAMC_ADST; /* let's make sure we don't clobber ourselves */ - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); chip->ramc.size = size; chip->ramc.reg = reg; @@ -419,8 +417,6 @@ snd_ad1889_capture_prepare(struct snd_pcm_substream *ss) /* writes flush */ ad1889_readw(chip, AD_DS_RAMC); - spin_unlock_irq(&chip->lock); - dev_dbg(chip->card->dev, "prepare capture: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr, count, size, reg, rt->rate); @@ -775,7 +771,7 @@ snd_ad1889_free(struct snd_card *card) { struct snd_ad1889 *chip = card->private_data; - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); ad1889_mute(chip); @@ -785,8 +781,6 @@ snd_ad1889_free(struct snd_card *card) /* clear DISR. If we don't, we'd better jump off the Eiffel Tower */ ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI); ad1889_readl(chip, AD_DMA_DISR); /* flush, dammit! */ - - spin_unlock_irq(&chip->lock); } static int From 9608fe85ff21684c6c00f2658c2806dd4b2295f0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:45 +0200 Subject: [PATCH 0920/1292] ALSA: atiixp: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-11-tiwai@suse.de --- sound/pci/atiixp.c | 31 ++++++++++++------------------- sound/pci/atiixp_modem.c | 17 +++++------------ 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 4f544950ee7bf1..38c07f3de85021 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1073,9 +1073,8 @@ static int snd_atiixp_playback_open(struct snd_pcm_substream *substream) struct atiixp *chip = snd_pcm_substream_chip(substream); int err; - mutex_lock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); - mutex_unlock(&chip->open_mutex); if (err < 0) return err; substream->runtime->hw.channels_max = chip->max_channels; @@ -1089,11 +1088,9 @@ static int snd_atiixp_playback_open(struct snd_pcm_substream *substream) static int snd_atiixp_playback_close(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); - int err; - mutex_lock(&chip->open_mutex); - err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); - mutex_unlock(&chip->open_mutex); - return err; + + guard(mutex)(&chip->open_mutex); + return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); } static int snd_atiixp_capture_open(struct snd_pcm_substream *substream) @@ -1111,27 +1108,23 @@ static int snd_atiixp_capture_close(struct snd_pcm_substream *substream) static int snd_atiixp_spdif_open(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); - int err; - mutex_lock(&chip->open_mutex); + + guard(mutex)(&chip->open_mutex); if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */ - err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2); + return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2); else - err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1); - mutex_unlock(&chip->open_mutex); - return err; + return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1); } static int snd_atiixp_spdif_close(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); - int err; - mutex_lock(&chip->open_mutex); + + guard(mutex)(&chip->open_mutex); if (chip->spdif_over_aclink) - err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); + return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); else - err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]); - mutex_unlock(&chip->open_mutex); - return err; + return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]); } /* AC97 playback */ diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index f7417c2bb47765..81a53336699ed9 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -892,24 +892,17 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream, static int snd_atiixp_playback_open(struct snd_pcm_substream *substream) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); - int err; - mutex_lock(&chip->open_mutex); - err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); - mutex_unlock(&chip->open_mutex); - if (err < 0) - return err; - return 0; + guard(mutex)(&chip->open_mutex); + return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); } static int snd_atiixp_playback_close(struct snd_pcm_substream *substream) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); - int err; - mutex_lock(&chip->open_mutex); - err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); - mutex_unlock(&chip->open_mutex); - return err; + + guard(mutex)(&chip->open_mutex); + return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); } static int snd_atiixp_capture_open(struct snd_pcm_substream *substream) From 5f7e725e023ec91aa55d73de1889e1660fd62536 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:46 +0200 Subject: [PATCH 0921/1292] ALSA: atiixp: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-12-tiwai@suse.de --- sound/pci/atiixp.c | 38 ++++++++++++++++---------------------- sound/pci/atiixp_modem.c | 32 ++++++++++++++------------------ 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 38c07f3de85021..2a0c59d5afa58e 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -345,7 +345,6 @@ static int atiixp_build_dma_packets(struct atiixp *chip, struct atiixp_dma *dma, { unsigned int i; u32 addr, desc_addr; - unsigned long flags; if (periods > ATI_MAX_DESCRIPTORS) return -ENOMEM; @@ -363,11 +362,11 @@ static int atiixp_build_dma_packets(struct atiixp *chip, struct atiixp_dma *dma, return 0; /* reset DMA before changing the descriptor table */ - spin_lock_irqsave(&chip->reg_lock, flags); - writel(0, chip->remap_addr + dma->ops->llp_offset); - dma->ops->enable_dma(chip, 0); - dma->ops->enable_dma(chip, 1); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + writel(0, chip->remap_addr + dma->ops->llp_offset); + dma->ops->enable_dma(chip, 0); + dma->ops->enable_dma(chip, 1); + } /* fill the entries */ addr = (u32)substream->runtime->dma_addr; @@ -711,7 +710,7 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) !dma->ops->flush_dma)) return -EINVAL; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -745,7 +744,6 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_atiixp_check_bus_busy(chip); } } - spin_unlock(&chip->reg_lock); return err; } @@ -859,7 +857,7 @@ static int snd_atiixp_spdif_prepare(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); if (chip->spdif_over_aclink) { unsigned int data; /* enable slots 10/11 */ @@ -877,7 +875,6 @@ static int snd_atiixp_spdif_prepare(struct snd_pcm_substream *substream) atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, 0); atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF, 0); } - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -887,7 +884,7 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream) struct atiixp *chip = snd_pcm_substream_chip(substream); unsigned int data; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK; switch (substream->runtime->channels) { case 8: @@ -922,7 +919,6 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream) atiixp_update(chip, 6CH_REORDER, ATI_REG_6CH_REORDER_EN, substream->runtime->channels >= 6 ? ATI_REG_6CH_REORDER_EN: 0); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -931,11 +927,10 @@ static int snd_atiixp_capture_prepare(struct snd_pcm_substream *substream) { struct atiixp *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_IN, substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ? ATI_REG_CMD_INTERLEAVE_IN : 0); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1043,9 +1038,9 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream, runtime->private_data = dma; /* enable DMA bits */ - spin_lock_irq(&chip->reg_lock); - dma->ops->enable_dma(chip, 1); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + dma->ops->enable_dma(chip, 1); + } dma->opened = 1; return 0; @@ -1058,9 +1053,9 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream, /* disable DMA bits */ if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma)) return -EINVAL; - spin_lock_irq(&chip->reg_lock); - dma->ops->enable_dma(chip, 0); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + dma->ops->enable_dma(chip, 0); + } dma->substream = NULL; dma->opened = 0; return 0; @@ -1348,10 +1343,9 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) if (status & CODEC_CHECK_BITS) { unsigned int detected; detected = status & CODEC_CHECK_BITS; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); chip->codec_not_ready_bits |= detected; atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */ - spin_unlock(&chip->reg_lock); } /* ack */ diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 81a53336699ed9..91f31e2ad3d3b6 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -314,7 +314,6 @@ static int atiixp_build_dma_packets(struct atiixp_modem *chip, { unsigned int i; u32 addr, desc_addr; - unsigned long flags; if (periods > ATI_MAX_DESCRIPTORS) return -ENOMEM; @@ -330,11 +329,11 @@ static int atiixp_build_dma_packets(struct atiixp_modem *chip, return 0; /* reset DMA before changing the descriptor table */ - spin_lock_irqsave(&chip->reg_lock, flags); - writel(0, chip->remap_addr + dma->ops->llp_offset); - dma->ops->enable_dma(chip, 0); - dma->ops->enable_dma(chip, 1); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + writel(0, chip->remap_addr + dma->ops->llp_offset); + dma->ops->enable_dma(chip, 0); + dma->ops->enable_dma(chip, 1); + } /* fill the entries */ addr = (u32)substream->runtime->dma_addr; @@ -661,7 +660,7 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) !dma->ops->flush_dma)) return -EINVAL; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch(cmd) { case SNDRV_PCM_TRIGGER_START: dma->ops->enable_transfer(chip, 1); @@ -682,7 +681,6 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_atiixp_check_bus_busy(chip); } } - spin_unlock(&chip->reg_lock); return err; } @@ -753,13 +751,12 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream) struct atiixp_modem *chip = snd_pcm_substream_chip(substream); unsigned int data; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); /* set output threshold */ data = atiixp_read(chip, MODEM_OUT_FIFO); data &= ~ATI_REG_MODEM_OUT1_DMA_THRESHOLD_MASK; data |= 0x04 << ATI_REG_MODEM_OUT1_DMA_THRESHOLD_SHIFT; atiixp_write(chip, MODEM_OUT_FIFO, data); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -864,9 +861,9 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream, runtime->private_data = dma; /* enable DMA bits */ - spin_lock_irq(&chip->reg_lock); - dma->ops->enable_dma(chip, 1); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + dma->ops->enable_dma(chip, 1); + } dma->opened = 1; return 0; @@ -879,9 +876,9 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream, /* disable DMA bits */ if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma)) return -EINVAL; - spin_lock_irq(&chip->reg_lock); - dma->ops->enable_dma(chip, 0); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + dma->ops->enable_dma(chip, 0); + } dma->substream = NULL; dma->opened = 0; return 0; @@ -1013,10 +1010,9 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) if (status & CODEC_CHECK_BITS) { unsigned int detected; detected = status & CODEC_CHECK_BITS; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); chip->codec_not_ready_bits |= detected; atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */ - spin_unlock(&chip->reg_lock); } /* ack */ From ca10ce1caf1922e5fdd62ccaf525d96bd2eeb611 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:47 +0200 Subject: [PATCH 0922/1292] ALSA: aw2: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-13-tiwai@suse.de --- sound/pci/aw2/aw2-alsa.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 1d7aab14579e1d..bf9b3c84f554f7 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -347,7 +347,7 @@ static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; unsigned long period_size, buffer_size; - mutex_lock(&chip->mtx); + guard(mutex)(&chip->mtx); period_size = snd_pcm_lib_period_bytes(substream); buffer_size = snd_pcm_lib_buffer_bytes(substream); @@ -363,8 +363,6 @@ static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream) snd_pcm_period_elapsed, (void *)substream); - mutex_unlock(&chip->mtx); - return 0; } @@ -376,7 +374,7 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; unsigned long period_size, buffer_size; - mutex_lock(&chip->mtx); + guard(mutex)(&chip->mtx); period_size = snd_pcm_lib_period_bytes(substream); buffer_size = snd_pcm_lib_buffer_bytes(substream); @@ -392,8 +390,6 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream) snd_pcm_period_elapsed, (void *)substream); - mutex_unlock(&chip->mtx); - return 0; } From 290adc48a2328e8b380ad19a8b0d74a0aa20f606 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:48 +0200 Subject: [PATCH 0923/1292] ALSA: aw2: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-14-tiwai@suse.de --- sound/pci/aw2/aw2-alsa.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index bf9b3c84f554f7..e2c501f4394c1b 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -397,10 +397,10 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream) static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream, int cmd) { - int status = 0; struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream); struct aw2 *chip = pcm_device->chip; - spin_lock(&chip->reg_lock); + + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_aw2_saa7146_pcm_trigger_start_playback(&chip->saa7146, @@ -413,20 +413,19 @@ static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream, stream_number); break; default: - status = -EINVAL; + return -EINVAL; } - spin_unlock(&chip->reg_lock); - return status; + return 0; } /* capture trigger callback */ static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream, int cmd) { - int status = 0; struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream); struct aw2 *chip = pcm_device->chip; - spin_lock(&chip->reg_lock); + + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_aw2_saa7146_pcm_trigger_start_capture(&chip->saa7146, @@ -439,10 +438,9 @@ static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream, stream_number); break; default: - status = -EINVAL; + return -EINVAL; } - spin_unlock(&chip->reg_lock); - return status; + return 0; } /* playback pointer callback */ From 637a3999442d9b7a546b65791cdd7a8c6c082834 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:49 +0200 Subject: [PATCH 0924/1292] ALSA: bt87x: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-15-tiwai@suse.de --- sound/pci/bt87x.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index b70f6f4ffe676d..383def1f2af745 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -431,10 +431,10 @@ static int snd_bt87x_close(struct snd_pcm_substream *substream) { struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); - chip->reg_control |= CTL_A_PWRDN; - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + chip->reg_control |= CTL_A_PWRDN; + snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); + } chip->substream = NULL; clear_bit(0, &chip->opened); @@ -466,20 +466,19 @@ static int snd_bt87x_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int decimation; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->reg_control &= ~(CTL_DA_SDR_MASK | CTL_DA_SBR); decimation = (ANALOG_CLOCK + runtime->rate / 4) / runtime->rate; chip->reg_control |= decimation << CTL_DA_SDR_SHIFT; if (runtime->format == SNDRV_PCM_FORMAT_S8) chip->reg_control |= CTL_DA_SBR; snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - spin_unlock_irq(&chip->reg_lock); return 0; } static int snd_bt87x_start(struct snd_bt87x *chip) { - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); chip->current_line = 0; chip->reg_control |= CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN; snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->dma_risc.addr); @@ -487,18 +486,16 @@ static int snd_bt87x_start(struct snd_bt87x *chip) chip->line_bytes | (chip->lines << 16)); snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - spin_unlock(&chip->reg_lock); return 0; } static int snd_bt87x_stop(struct snd_bt87x *chip) { - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); chip->reg_control &= ~(CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); snd_bt87x_writel(chip, REG_INT_MASK, 0); snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); - spin_unlock(&chip->reg_lock); return 0; } @@ -560,13 +557,12 @@ static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol, u32 old_control; int changed; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_GAIN_MASK) | (value->value.integer.value[0] << CTL_A_GAIN_SHIFT); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = old_control != chip->reg_control; - spin_unlock_irq(&chip->reg_lock); return changed; } @@ -596,13 +592,12 @@ static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol, u32 old_control; int changed; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_G2X) | (value->value.integer.value[0] ? CTL_A_G2X : 0); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = chip->reg_control != old_control; - spin_unlock_irq(&chip->reg_lock); return changed; } @@ -638,13 +633,12 @@ static int snd_bt87x_capture_source_put(struct snd_kcontrol *kcontrol, u32 old_control; int changed; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_SEL_MASK) | (value->value.enumerated.item[0] << CTL_A_SEL_SHIFT); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = chip->reg_control != old_control; - spin_unlock_irq(&chip->reg_lock); return changed; } From 22ec1279269f13d794ecb5c81d298a316aa78d28 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:50 +0200 Subject: [PATCH 0925/1292] ALSA: ca0106: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-16-tiwai@suse.de --- sound/pci/ca0106/ca0106_main.c | 33 ++----- sound/pci/ca0106/ca0106_proc.c | 28 +++--- sound/pci/ca0106/ca_midi.c | 171 +++++++++++++++------------------ 3 files changed, 97 insertions(+), 135 deletions(-) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 24261879318187..41774e2ef53fea 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -332,16 +332,13 @@ unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu, unsigned int reg, unsigned int chn) { - unsigned long flags; - unsigned int regptr, val; + unsigned int regptr; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(regptr, emu->port + CA0106_PTR); - val = inl(emu->port + CA0106_DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); - return val; + return inl(emu->port + CA0106_DATA); } void snd_ca0106_ptr_write(struct snd_ca0106 *emu, @@ -350,14 +347,12 @@ void snd_ca0106_ptr_write(struct snd_ca0106 *emu, unsigned int data) { unsigned int regptr; - unsigned long flags; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(regptr, emu->port + CA0106_PTR); outl(data, emu->port + CA0106_DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } int snd_ca0106_spi_write(struct snd_ca0106 * emu, @@ -451,24 +446,20 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int intr_enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); intr_enable = inl(emu->port + CA0106_INTE) | intrenb; outl(intr_enable, emu->port + CA0106_INTE); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int intr_enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); intr_enable = inl(emu->port + CA0106_INTE) & ~intrenb; outl(intr_enable, emu->port + CA0106_INTE); - spin_unlock_irqrestore(&emu->emu_lock, flags); } @@ -1138,26 +1129,20 @@ static unsigned short snd_ca0106_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct snd_ca0106 *emu = ac97->private_data; - unsigned long flags; - unsigned short val; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outb(reg, emu->port + CA0106_AC97ADDRESS); - val = inw(emu->port + CA0106_AC97DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); - return val; + return inw(emu->port + CA0106_AC97DATA); } static void snd_ca0106_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct snd_ca0106 *emu = ac97->private_data; - unsigned long flags; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outb(reg, emu->port + CA0106_AC97ADDRESS); outw(val, emu->port + CA0106_AC97DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static int snd_ca0106_ac97(struct snd_ca0106 *chip) diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c99603e137e5fd..c181e495457937 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -281,16 +281,14 @@ static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_ca0106 *emu = entry->private_data; - unsigned long flags; char line[64]; u32 reg, val; while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; if (reg < 0x40 && val <= 0xffffffff) { - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(val, emu->port + (reg & 0xfffffffc)); - spin_unlock_irqrestore(&emu->emu_lock, flags); } } } @@ -300,13 +298,13 @@ static void snd_ca0106_proc_reg_read32(struct snd_info_entry *entry, { struct snd_ca0106 *emu = entry->private_data; unsigned long value; - unsigned long flags; int i; + snd_iprintf(buffer, "Registers:\n\n"); for(i = 0; i < 0x20; i+=4) { - spin_lock_irqsave(&emu->emu_lock, flags); - value = inl(emu->port + i); - spin_unlock_irqrestore(&emu->emu_lock, flags); + scoped_guard(spinlock_irqsave, &emu->emu_lock) { + value = inl(emu->port + i); + } snd_iprintf(buffer, "Register %02X: %08lX\n", i, value); } } @@ -316,13 +314,13 @@ static void snd_ca0106_proc_reg_read16(struct snd_info_entry *entry, { struct snd_ca0106 *emu = entry->private_data; unsigned int value; - unsigned long flags; int i; + snd_iprintf(buffer, "Registers:\n\n"); for(i = 0; i < 0x20; i+=2) { - spin_lock_irqsave(&emu->emu_lock, flags); - value = inw(emu->port + i); - spin_unlock_irqrestore(&emu->emu_lock, flags); + scoped_guard(spinlock_irqsave, &emu->emu_lock) { + value = inw(emu->port + i); + } snd_iprintf(buffer, "Register %02X: %04X\n", i, value); } } @@ -332,13 +330,13 @@ static void snd_ca0106_proc_reg_read8(struct snd_info_entry *entry, { struct snd_ca0106 *emu = entry->private_data; unsigned int value; - unsigned long flags; int i; + snd_iprintf(buffer, "Registers:\n\n"); for(i = 0; i < 0x20; i+=1) { - spin_lock_irqsave(&emu->emu_lock, flags); - value = inb(emu->port + i); - spin_unlock_irqrestore(&emu->emu_lock, flags); + scoped_guard(spinlock_irqsave, &emu->emu_lock) { + value = inb(emu->port + i); + } snd_iprintf(buffer, "Register %02X: %02X\n", i, value); } } diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index f9cec67f31ac67..6efd93abddb56b 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c @@ -45,58 +45,54 @@ static void ca_midi_interrupt(struct snd_ca_midi *midi, unsigned int status) return; } - spin_lock(&midi->input_lock); - if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) { - if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) { - ca_midi_clear_rx(midi); - } else { - byte = ca_midi_read_data(midi); - if(midi->substream_input) - snd_rawmidi_receive(midi->substream_input, &byte, 1); - - + scoped_guard(spinlock, &midi->input_lock) { + if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) { + if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) { + ca_midi_clear_rx(midi); + } else { + byte = ca_midi_read_data(midi); + if (midi->substream_input) + snd_rawmidi_receive(midi->substream_input, &byte, 1); + } } } - spin_unlock(&midi->input_lock); - spin_lock(&midi->output_lock); - if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) { - if (midi->substream_output && - snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { - ca_midi_write_data(midi, byte); - } else { - midi->interrupt_disable(midi,midi->tx_enable); + scoped_guard(spinlock, &midi->output_lock) { + if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) { + if (midi->substream_output && + snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { + ca_midi_write_data(midi, byte); + } else { + midi->interrupt_disable(midi, midi->tx_enable); + } } } - spin_unlock(&midi->output_lock); - } static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack) { - unsigned long flags; int timeout, ok; - spin_lock_irqsave(&midi->input_lock, flags); - ca_midi_write_data(midi, 0x00); - /* ca_midi_clear_rx(midi); */ - - ca_midi_write_cmd(midi, cmd); - if (ack) { - ok = 0; - timeout = 10000; - while (!ok && timeout-- > 0) { - if (ca_midi_input_avail(midi)) { - if (ca_midi_read_data(midi) == midi->ack) - ok = 1; + scoped_guard(spinlock_irqsave, &midi->input_lock) { + ca_midi_write_data(midi, 0x00); + /* ca_midi_clear_rx(midi); */ + + ca_midi_write_cmd(midi, cmd); + if (ack) { + ok = 0; + timeout = 10000; + while (!ok && timeout-- > 0) { + if (ca_midi_input_avail(midi)) { + if (ca_midi_read_data(midi) == midi->ack) + ok = 1; + } } - } - if (!ok && ca_midi_read_data(midi) == midi->ack) + if (!ok && ca_midi_read_data(midi) == midi->ack) + ok = 1; + } else { ok = 1; - } else { - ok = 1; + } } - spin_unlock_irqrestore(&midi->input_lock, flags); if (!ok) pr_err("ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n", cmd, @@ -108,83 +104,69 @@ static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack) static int ca_midi_input_open(struct snd_rawmidi_substream *substream) { struct snd_ca_midi *midi = substream->rmidi->private_data; - unsigned long flags; if (snd_BUG_ON(!midi->dev_id)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - midi->midi_mode |= CA_MIDI_MODE_INPUT; - midi->substream_input = substream; - if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - ca_midi_cmd(midi, midi->reset, 1); - ca_midi_cmd(midi, midi->enter_uart, 1); - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + midi->midi_mode |= CA_MIDI_MODE_INPUT; + midi->substream_input = substream; + if (midi->midi_mode & CA_MIDI_MODE_OUTPUT) + return 0; } + ca_midi_cmd(midi, midi->reset, 1); + ca_midi_cmd(midi, midi->enter_uart, 1); return 0; } static int ca_midi_output_open(struct snd_rawmidi_substream *substream) { struct snd_ca_midi *midi = substream->rmidi->private_data; - unsigned long flags; if (snd_BUG_ON(!midi->dev_id)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - midi->midi_mode |= CA_MIDI_MODE_OUTPUT; - midi->substream_output = substream; - if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - ca_midi_cmd(midi, midi->reset, 1); - ca_midi_cmd(midi, midi->enter_uart, 1); - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + midi->midi_mode |= CA_MIDI_MODE_OUTPUT; + midi->substream_output = substream; + if (midi->midi_mode & CA_MIDI_MODE_INPUT) + return 0; } + ca_midi_cmd(midi, midi->reset, 1); + ca_midi_cmd(midi, midi->enter_uart, 1); return 0; } static int ca_midi_input_close(struct snd_rawmidi_substream *substream) { struct snd_ca_midi *midi = substream->rmidi->private_data; - unsigned long flags; if (snd_BUG_ON(!midi->dev_id)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - midi->interrupt_disable(midi,midi->rx_enable); - midi->midi_mode &= ~CA_MIDI_MODE_INPUT; - midi->substream_input = NULL; - if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - ca_midi_cmd(midi, midi->reset, 0); - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + midi->interrupt_disable(midi, midi->rx_enable); + midi->midi_mode &= ~CA_MIDI_MODE_INPUT; + midi->substream_input = NULL; + if (midi->midi_mode & CA_MIDI_MODE_OUTPUT) + return 0; } + ca_midi_cmd(midi, midi->reset, 0); return 0; } static int ca_midi_output_close(struct snd_rawmidi_substream *substream) { struct snd_ca_midi *midi = substream->rmidi->private_data; - unsigned long flags; if (snd_BUG_ON(!midi->dev_id)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - - midi->interrupt_disable(midi,midi->tx_enable); - midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT; - midi->substream_output = NULL; - - if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - ca_midi_cmd(midi, midi->reset, 0); - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + midi->interrupt_disable(midi, midi->tx_enable); + midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT; + midi->substream_output = NULL; + if (midi->midi_mode & CA_MIDI_MODE_INPUT) + return 0; } + ca_midi_cmd(midi, midi->reset, 0); return 0; } @@ -205,7 +187,6 @@ static void ca_midi_input_trigger(struct snd_rawmidi_substream *substream, int u static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_ca_midi *midi = substream->rmidi->private_data; - unsigned long flags; if (snd_BUG_ON(!midi->dev_id)) return; @@ -214,25 +195,23 @@ static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int int max = 4; unsigned char byte; - spin_lock_irqsave(&midi->output_lock, flags); + scoped_guard(spinlock_irqsave, &midi->output_lock) { - /* try to send some amount of bytes here before interrupts */ - while (max > 0) { - if (ca_midi_output_ready(midi)) { - if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) || - snd_rawmidi_transmit(substream, &byte, 1) != 1) { - /* no more data */ - spin_unlock_irqrestore(&midi->output_lock, flags); - return; + /* try to send some amount of bytes here before interrupts */ + while (max > 0) { + if (ca_midi_output_ready(midi)) { + if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) || + snd_rawmidi_transmit(substream, &byte, 1) != 1) { + /* no more data */ + return; + } + ca_midi_write_data(midi, byte); + max--; + } else { + break; } - ca_midi_write_data(midi, byte); - max--; - } else { - break; } } - - spin_unlock_irqrestore(&midi->output_lock, flags); midi->interrupt_enable(midi,midi->tx_enable); } else { From d0d95e9bd8153508ce23159abd8a849d53b9fe15 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:51 +0200 Subject: [PATCH 0926/1292] ALSA: cmipci: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-17-tiwai@suse.de --- sound/pci/cmipci.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index c4ee550d7c96cc..cfd80a24580ce7 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -664,14 +664,11 @@ static int snd_cmipci_playback2_hw_params(struct snd_pcm_substream *substream, { struct cmipci *cm = snd_pcm_substream_chip(substream); if (params_channels(hw_params) > 2) { - mutex_lock(&cm->open_mutex); - if (cm->opened[CM_CH_PLAY]) { - mutex_unlock(&cm->open_mutex); + guard(mutex)(&cm->open_mutex); + if (cm->opened[CM_CH_PLAY]) return -EBUSY; - } /* reserve the channel A */ cm->opened[CM_CH_PLAY] = CM_OPEN_PLAYBACK_MULTI; - mutex_unlock(&cm->open_mutex); } return 0; } @@ -1582,11 +1579,9 @@ static int open_device_check(struct cmipci *cm, int mode, struct snd_pcm_substre * pcm framework doesn't pass file pointer before actually opened, * we can't know whether blocking mode or not in open callback.. */ - mutex_lock(&cm->open_mutex); - if (cm->opened[ch]) { - mutex_unlock(&cm->open_mutex); + guard(mutex)(&cm->open_mutex); + if (cm->opened[ch]) return -EBUSY; - } cm->opened[ch] = mode; cm->channel[ch].substream = subs; if (! (mode & CM_OPEN_DAC)) { @@ -1596,7 +1591,6 @@ static int open_device_check(struct cmipci *cm, int mode, struct snd_pcm_substre snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC); spin_unlock_irq(&cm->reg_lock); } - mutex_unlock(&cm->open_mutex); return 0; } @@ -1604,7 +1598,7 @@ static void close_device_check(struct cmipci *cm, int mode) { int ch = mode & CM_OPEN_CH_MASK; - mutex_lock(&cm->open_mutex); + guard(mutex)(&cm->open_mutex); if (cm->opened[ch] == mode) { if (cm->channel[ch].substream) { snd_cmipci_ch_reset(cm, ch); @@ -1620,7 +1614,6 @@ static void close_device_check(struct cmipci *cm, int mode) spin_unlock_irq(&cm->reg_lock); } } - mutex_unlock(&cm->open_mutex); } /* @@ -1685,7 +1678,7 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) if (err < 0) return err; runtime->hw = snd_cmipci_playback2; - mutex_lock(&cm->open_mutex); + guard(mutex)(&cm->open_mutex); if (! cm->opened[CM_CH_PLAY]) { if (cm->can_multi_ch) { runtime->hw.channels_max = cm->max_channels; @@ -1697,7 +1690,6 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_8); } } - mutex_unlock(&cm->open_mutex); if (cm->chip_version == 68) { runtime->hw.rates |= SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; From 40bc78567f63f5543e8cac4113ea493e9938fc3e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:52 +0200 Subject: [PATCH 0927/1292] ALSA: cmipci: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-18-tiwai@suse.de --- sound/pci/cmipci.c | 165 +++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 96 deletions(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index cfd80a24580ce7..0666be543474a2 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -712,7 +712,7 @@ static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int chann } if (cm->can_multi_ch) { - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); if (channels > 2) { snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); @@ -735,7 +735,6 @@ static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int chann snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); else snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); - spin_unlock_irq(&cm->reg_lock); } return 0; } @@ -776,7 +775,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, period_size = (period_size * runtime->channels) / 2; } - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); /* set buffer address */ reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1; @@ -842,7 +841,6 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, } rec->running = 0; - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -854,14 +852,13 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, int cmd) { unsigned int inthld, chen, reset, pause; - int result = 0; inthld = CM_CH0_INT_EN << rec->ch; chen = CM_CHEN0 << rec->ch; reset = CM_RST_CH0 << rec->ch; pause = CM_PAUSE0 << rec->ch; - spin_lock(&cm->reg_lock); + guard(spinlock)(&cm->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: rec->running = 1; @@ -893,11 +890,9 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); break; default: - result = -EINVAL; - break; + return -EINVAL; } - spin_unlock(&cm->reg_lock); - return result; + return 0; } /* @@ -987,10 +982,9 @@ static int snd_cmipci_spdif_default_get(struct snd_kcontrol *kcontrol, struct cmipci *chip = snd_kcontrol_chip(kcontrol); int i; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); for (i = 0; i < 4; i++) ucontrol->value.iec958.status[i] = (chip->dig_status >> (i * 8)) & 0xff; - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1002,12 +996,11 @@ static int snd_cmipci_spdif_default_put(struct snd_kcontrol *kcontrol, unsigned int val; val = 0; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); for (i = 0; i < 4; i++) val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); change = val != chip->dig_status; chip->dig_status = val; - spin_unlock_irq(&chip->reg_lock); return change; } @@ -1061,10 +1054,9 @@ static int snd_cmipci_spdif_stream_get(struct snd_kcontrol *kcontrol, struct cmipci *chip = snd_kcontrol_chip(kcontrol); int i; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); for (i = 0; i < 4; i++) ucontrol->value.iec958.status[i] = (chip->dig_pcm_status >> (i * 8)) & 0xff; - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1076,12 +1068,11 @@ static int snd_cmipci_spdif_stream_put(struct snd_kcontrol *kcontrol, unsigned int val; val = 0; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); for (i = 0; i < 4; i++) val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); change = val != chip->dig_pcm_status; chip->dig_pcm_status = val; - spin_unlock_irq(&chip->reg_lock); return change; } @@ -1225,7 +1216,7 @@ static int setup_spdif_playback(struct cmipci *cm, struct snd_pcm_substream *sub return err; } - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); cm->spdif_playback_avail = up; if (up) { /* they are controlled via "IEC958 Output Switch" */ @@ -1251,7 +1242,6 @@ static int setup_spdif_playback(struct cmipci *cm, struct snd_pcm_substream *sub snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); setup_ac3(cm, subs, 0, 0); } - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -1317,32 +1307,32 @@ static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec) /* configure for 16 bits, 2 channels, 8 kHz */ if (runtime->channels > 2) set_dac_channels(cm, rec, 2); - spin_lock_irq(&cm->reg_lock); - val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); - val &= ~(CM_ASFC_MASK << (rec->ch * 3)); - val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3); - snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); - val = snd_cmipci_read(cm, CM_REG_CHFORMAT); - val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); - val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); - if (cm->can_96k) - val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2)); - snd_cmipci_write(cm, CM_REG_CHFORMAT, val); + scoped_guard(spinlock_irq, &cm->reg_lock) { + val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); + val &= ~(CM_ASFC_MASK << (rec->ch * 3)); + val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3); + snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); + val = snd_cmipci_read(cm, CM_REG_CHFORMAT); + val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); + val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); + if (cm->can_96k) + val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2)); + snd_cmipci_write(cm, CM_REG_CHFORMAT, val); - /* start stream (we don't need interrupts) */ - cm->ctrl |= CM_CHEN0 << rec->ch; - snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); - spin_unlock_irq(&cm->reg_lock); + /* start stream (we don't need interrupts) */ + cm->ctrl |= CM_CHEN0 << rec->ch; + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); + } msleep(1); /* stop and reset stream */ - spin_lock_irq(&cm->reg_lock); - cm->ctrl &= ~(CM_CHEN0 << rec->ch); - val = CM_RST_CH0 << rec->ch; - snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val); - snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val); - spin_unlock_irq(&cm->reg_lock); + scoped_guard(spinlock_irq, &cm->reg_lock) { + cm->ctrl &= ~(CM_CHEN0 << rec->ch); + val = CM_RST_CH0 << rec->ch; + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val); + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val); + } rec->needs_silencing = 0; } @@ -1376,20 +1366,19 @@ static int snd_cmipci_capture_spdif_prepare(struct snd_pcm_substream *substream) { struct cmipci *cm = snd_pcm_substream_chip(substream); - spin_lock_irq(&cm->reg_lock); - snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); - if (cm->can_96k) { - if (substream->runtime->rate > 48000) - snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); + scoped_guard(spinlock_irq, &cm->reg_lock) { + snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); + if (cm->can_96k) { + if (substream->runtime->rate > 48000) + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); + else + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); + } + if (snd_pcm_format_width(substream->runtime->format) > 16) + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); else - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); } - if (snd_pcm_format_width(substream->runtime->format) > 16) - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); - else - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); - - spin_unlock_irq(&cm->reg_lock); return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream); } @@ -1398,10 +1387,9 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs) { struct cmipci *cm = snd_pcm_substream_chip(subs); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -1421,14 +1409,14 @@ static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id) return IRQ_NONE; /* acknowledge interrupt */ - spin_lock(&cm->reg_lock); - if (status & CM_CHINT0) - mask |= CM_CH0_INT_EN; - if (status & CM_CHINT1) - mask |= CM_CH1_INT_EN; - snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, mask); - snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, mask); - spin_unlock(&cm->reg_lock); + scoped_guard(spinlock, &cm->reg_lock) { + if (status & CM_CHINT0) + mask |= CM_CH0_INT_EN; + if (status & CM_CHINT1) + mask |= CM_CH1_INT_EN; + snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, mask); + snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, mask); + } if (cm->rmidi && (status & CM_UARTINT)) snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data); @@ -1587,9 +1575,8 @@ static int open_device_check(struct cmipci *cm, int mode, struct snd_pcm_substre if (! (mode & CM_OPEN_DAC)) { /* disable dual DAC mode */ cm->channel[ch].is_dac = 0; - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC); - spin_unlock_irq(&cm->reg_lock); } return 0; } @@ -1609,9 +1596,8 @@ static void close_device_check(struct cmipci *cm, int mode) if (! cm->channel[ch].is_dac) { /* enable dual DAC mode again */ cm->channel[ch].is_dac = 1; - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC); - spin_unlock_irq(&cm->reg_lock); } } } @@ -2002,7 +1988,7 @@ static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol, int val; cmipci_sb_reg_decode(®, kcontrol->private_value); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); val = (snd_cmipci_mixer_read(cm, reg.left_reg) >> reg.left_shift) & reg.mask; if (reg.invert) val = reg.mask - val; @@ -2013,7 +1999,6 @@ static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol, val = reg.mask - val; ucontrol->value.integer.value[1] = val; } - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -2037,7 +2022,7 @@ static int snd_cmipci_put_volume(struct snd_kcontrol *kcontrol, right <<= reg.right_shift; } else right = 0; - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); oleft = snd_cmipci_mixer_read(cm, reg.left_reg); left |= oleft & ~(reg.mask << reg.left_shift); change = left != oleft; @@ -2052,7 +2037,6 @@ static int snd_cmipci_put_volume(struct snd_kcontrol *kcontrol, snd_cmipci_mixer_write(cm, reg.right_reg, right); } else snd_cmipci_mixer_write(cm, reg.left_reg, left); - spin_unlock_irq(&cm->reg_lock); return change; } @@ -2084,10 +2068,9 @@ static int snd_cmipci_get_input_sw(struct snd_kcontrol *kcontrol, int val1, val2; cmipci_sb_reg_decode(®, kcontrol->private_value); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); val1 = snd_cmipci_mixer_read(cm, reg.left_reg); val2 = snd_cmipci_mixer_read(cm, reg.right_reg); - spin_unlock_irq(&cm->reg_lock); ucontrol->value.integer.value[0] = (val1 >> reg.left_shift) & 1; ucontrol->value.integer.value[1] = (val2 >> reg.left_shift) & 1; ucontrol->value.integer.value[2] = (val1 >> reg.right_shift) & 1; @@ -2104,7 +2087,7 @@ static int snd_cmipci_put_input_sw(struct snd_kcontrol *kcontrol, int val1, val2, oval1, oval2; cmipci_sb_reg_decode(®, kcontrol->private_value); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); oval1 = snd_cmipci_mixer_read(cm, reg.left_reg); oval2 = snd_cmipci_mixer_read(cm, reg.right_reg); val1 = oval1 & ~((1 << reg.left_shift) | (1 << reg.right_shift)); @@ -2116,7 +2099,6 @@ static int snd_cmipci_put_input_sw(struct snd_kcontrol *kcontrol, change = val1 != oval1 || val2 != oval2; snd_cmipci_mixer_write(cm, reg.left_reg, val1); snd_cmipci_mixer_write(cm, reg.right_reg, val2); - spin_unlock_irq(&cm->reg_lock); return change; } @@ -2174,7 +2156,7 @@ static int snd_cmipci_get_native_mixer(struct snd_kcontrol *kcontrol, unsigned char oreg, val; cmipci_sb_reg_decode(®, kcontrol->private_value); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); oreg = inb(cm->iobase + reg.left_reg); val = (oreg >> reg.left_shift) & reg.mask; if (reg.invert) @@ -2186,7 +2168,6 @@ static int snd_cmipci_get_native_mixer(struct snd_kcontrol *kcontrol, val = reg.mask - val; ucontrol->value.integer.value[1] = val; } - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -2198,7 +2179,7 @@ static int snd_cmipci_put_native_mixer(struct snd_kcontrol *kcontrol, unsigned char oreg, nreg, val; cmipci_sb_reg_decode(®, kcontrol->private_value); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); oreg = inb(cm->iobase + reg.left_reg); val = ucontrol->value.integer.value[0] & reg.mask; if (reg.invert) @@ -2213,7 +2194,6 @@ static int snd_cmipci_put_native_mixer(struct snd_kcontrol *kcontrol, nreg |= (val << reg.right_shift); } outb(nreg, cm->iobase + reg.left_reg); - spin_unlock_irq(&cm->reg_lock); return (nreg != oreg); } @@ -2300,10 +2280,9 @@ static int _snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol, unsigned int val; struct cmipci *cm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); if (args->ac3_sensitive && cm->mixer_insensitive) { ucontrol->value.integer.value[0] = 0; - spin_unlock_irq(&cm->reg_lock); return 0; } if (args->is_byte) @@ -2311,7 +2290,6 @@ static int _snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol, else val = snd_cmipci_read(cm, args->reg); ucontrol->value.integer.value[0] = ((val & args->mask) == args->mask_on) ? 1 : 0; - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -2333,10 +2311,9 @@ static int _snd_cmipci_uswitch_put(struct snd_kcontrol *kcontrol, int change; struct cmipci *cm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); if (args->ac3_sensitive && cm->mixer_insensitive) { /* ignored */ - spin_unlock_irq(&cm->reg_lock); return 0; } if (args->is_byte) @@ -2356,7 +2333,6 @@ static int _snd_cmipci_uswitch_put(struct snd_kcontrol *kcontrol, else snd_cmipci_write(cm, args->reg, val); } - spin_unlock_irq(&cm->reg_lock); return change; } @@ -2489,9 +2465,8 @@ static int snd_cmipci_line_in_mode_get(struct snd_kcontrol *kcontrol, { struct cmipci *cm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); ucontrol->value.enumerated.item[0] = get_line_in_mode(cm); - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -2501,7 +2476,7 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol, struct cmipci *cm = snd_kcontrol_chip(kcontrol); int change; - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); if (ucontrol->value.enumerated.item[0] == 2) change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CENTR2LIN | CM_BASE2LIN); else @@ -2510,7 +2485,6 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol, change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN); else change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN); - spin_unlock_irq(&cm->reg_lock); return change; } @@ -2526,11 +2500,11 @@ static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct cmipci *cm = snd_kcontrol_chip(kcontrol); + /* same bit as spdi_phase */ - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); ucontrol->value.enumerated.item[0] = (snd_cmipci_read_b(cm, CM_REG_MISC) & CM_SPDIF_INVERSE) ? 1 : 0; - spin_unlock_irq(&cm->reg_lock); return 0; } @@ -2540,12 +2514,11 @@ static int snd_cmipci_mic_in_mode_put(struct snd_kcontrol *kcontrol, struct cmipci *cm = snd_kcontrol_chip(kcontrol); int change; - spin_lock_irq(&cm->reg_lock); + guard(spinlock_irq)(&cm->reg_lock); if (ucontrol->value.enumerated.item[0]) change = snd_cmipci_set_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); else change = snd_cmipci_clear_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); - spin_unlock_irq(&cm->reg_lock); return change; } @@ -2627,9 +2600,9 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) strscpy(card->mixername, "CMedia PCI"); - spin_lock_irq(&cm->reg_lock); - snd_cmipci_mixer_write(cm, 0x00, 0x00); /* mixer reset */ - spin_unlock_irq(&cm->reg_lock); + scoped_guard(spinlock_irq, &cm->reg_lock) { + snd_cmipci_mixer_write(cm, 0x00, 0x00); /* mixer reset */ + } for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_mixers); idx++) { if (cm->chip_version == 68) { // 8768 has no PCM volume From 7a5127c2c8a5a4d281b34f66d2461bf2efa9bc4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:53 +0200 Subject: [PATCH 0928/1292] ALSA: cs4281: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-19-tiwai@suse.de --- sound/pci/cs4281.c | 53 +++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 31cb9cbe2f0318..c519fb9cdd1ee1 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -651,7 +651,7 @@ static int snd_cs4281_trigger(struct snd_pcm_substream *substream, int cmd) struct cs4281_dma *dma = substream->runtime->private_data; struct cs4281 *chip = snd_pcm_substream_chip(substream); - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: dma->valDCR |= BA0_DCR_MSK; @@ -678,13 +678,11 @@ static int snd_cs4281_trigger(struct snd_pcm_substream *substream, int cmd) dma->valFCR &= ~BA0_FCR_FEN; break; default: - spin_unlock(&chip->reg_lock); return -EINVAL; } snd_cs4281_pokeBA0(chip, dma->regDMR, dma->valDMR); snd_cs4281_pokeBA0(chip, dma->regFCR, dma->valFCR); snd_cs4281_pokeBA0(chip, dma->regDCR, dma->valDCR); - spin_unlock(&chip->reg_lock); return 0; } @@ -782,9 +780,8 @@ static int snd_cs4281_playback_prepare(struct snd_pcm_substream *substream) struct cs4281_dma *dma = runtime->private_data; struct cs4281 *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); snd_cs4281_mode(chip, dma, runtime, 0, 1); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -794,9 +791,8 @@ static int snd_cs4281_capture_prepare(struct snd_pcm_substream *substream) struct cs4281_dma *dma = runtime->private_data; struct cs4281 *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); snd_cs4281_mode(chip, dma, runtime, 1, 1); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1580,7 +1576,7 @@ static int snd_cs4281_midi_input_open(struct snd_rawmidi_substream *substream) { struct cs4281 *chip = substream->rmidi->private_data; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->midcr |= BA0_MIDCR_RXE; chip->midi_input = substream; if (!(chip->uartm & CS4281_MODE_OUTPUT)) { @@ -1588,7 +1584,6 @@ static int snd_cs4281_midi_input_open(struct snd_rawmidi_substream *substream) } else { snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr); } - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1596,7 +1591,7 @@ static int snd_cs4281_midi_input_close(struct snd_rawmidi_substream *substream) { struct cs4281 *chip = substream->rmidi->private_data; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->midcr &= ~(BA0_MIDCR_RXE | BA0_MIDCR_RIE); chip->midi_input = NULL; if (!(chip->uartm & CS4281_MODE_OUTPUT)) { @@ -1605,7 +1600,6 @@ static int snd_cs4281_midi_input_close(struct snd_rawmidi_substream *substream) snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr); } chip->uartm &= ~CS4281_MODE_INPUT; - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1613,7 +1607,7 @@ static int snd_cs4281_midi_output_open(struct snd_rawmidi_substream *substream) { struct cs4281 *chip = substream->rmidi->private_data; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->uartm |= CS4281_MODE_OUTPUT; chip->midcr |= BA0_MIDCR_TXE; chip->midi_output = substream; @@ -1622,7 +1616,6 @@ static int snd_cs4281_midi_output_open(struct snd_rawmidi_substream *substream) } else { snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr); } - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1630,7 +1623,7 @@ static int snd_cs4281_midi_output_close(struct snd_rawmidi_substream *substream) { struct cs4281 *chip = substream->rmidi->private_data; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->midcr &= ~(BA0_MIDCR_TXE | BA0_MIDCR_TIE); chip->midi_output = NULL; if (!(chip->uartm & CS4281_MODE_INPUT)) { @@ -1639,16 +1632,14 @@ static int snd_cs4281_midi_output_close(struct snd_rawmidi_substream *substream) snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr); } chip->uartm &= ~CS4281_MODE_OUTPUT; - spin_unlock_irq(&chip->reg_lock); return 0; } static void snd_cs4281_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct cs4281 *chip = substream->rmidi->private_data; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (up) { if ((chip->midcr & BA0_MIDCR_RIE) == 0) { chip->midcr |= BA0_MIDCR_RIE; @@ -1660,16 +1651,14 @@ static void snd_cs4281_midi_input_trigger(struct snd_rawmidi_substream *substrea snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr); } } - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct cs4281 *chip = substream->rmidi->private_data; unsigned char byte; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (up) { if ((chip->midcr & BA0_MIDCR_TIE) == 0) { chip->midcr |= BA0_MIDCR_TIE; @@ -1690,7 +1679,6 @@ static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substre snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr); } } - spin_unlock_irqrestore(&chip->reg_lock, flags); } static const struct snd_rawmidi_ops snd_cs4281_midi_output = @@ -1743,10 +1731,12 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id) } if (status & (BA0_HISR_DMA(0)|BA0_HISR_DMA(1)|BA0_HISR_DMA(2)|BA0_HISR_DMA(3))) { - for (dma = 0; dma < 4; dma++) + for (dma = 0; dma < 4; dma++) { + bool period_elapsed = false; + cdma = &chip->dma[dma]; + if (status & BA0_HISR_DMA(dma)) { - cdma = &chip->dma[dma]; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); /* ack DMA IRQ */ val = snd_cs4281_peekBA0(chip, cdma->regHDSR); /* workaround, sometimes CS4281 acknowledges */ @@ -1755,24 +1745,23 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id) if ((val & BA0_HDSR_DHTC) && !(cdma->frag & 1)) { cdma->frag--; chip->spurious_dhtc_irq++; - spin_unlock(&chip->reg_lock); continue; } if ((val & BA0_HDSR_DTC) && (cdma->frag & 1)) { cdma->frag--; chip->spurious_dtc_irq++; - spin_unlock(&chip->reg_lock); continue; } - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(cdma->substream); } + if (period_elapsed) + snd_pcm_period_elapsed(cdma->substream); + } } if ((status & BA0_HISR_MIDI) && chip->rmidi) { unsigned char c; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); while ((snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_RBE) == 0) { c = snd_cs4281_peekBA0(chip, BA0_MIDRP); if ((chip->midcr & BA0_MIDCR_RIE) == 0) @@ -1789,7 +1778,6 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id) } snd_cs4281_pokeBA0(chip, BA0_MIDWP, c); } - spin_unlock(&chip->reg_lock); } /* EOI to the PCI part... reenables interrupts */ @@ -1805,7 +1793,6 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id) static void snd_cs4281_opl3_command(struct snd_opl3 *opl3, unsigned short cmd, unsigned char val) { - unsigned long flags; struct cs4281 *chip = opl3->private_data; void __iomem *port; @@ -1814,15 +1801,13 @@ static void snd_cs4281_opl3_command(struct snd_opl3 *opl3, unsigned short cmd, else port = chip->ba0 + BA0_B0AP; /* left port */ - spin_lock_irqsave(&opl3->reg_lock, flags); + guard(spinlock_irqsave)(&opl3->reg_lock); writel((unsigned int)cmd, port); udelay(10); writel((unsigned int)val, port + 4); udelay(30); - - spin_unlock_irqrestore(&opl3->reg_lock, flags); } static int __snd_cs4281_probe(struct pci_dev *pci, From 02ba95351a88af7e9baaf477da1cfd647ef1a2c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:54 +0200 Subject: [PATCH 0929/1292] ALSA: cs46xx: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-20-tiwai@suse.de --- sound/pci/cs46xx/cs46xx_lib.c | 89 +++++++++++------------------ sound/pci/cs46xx/dsp_spos.c | 66 +++++++++------------ sound/pci/cs46xx/dsp_spos_scb_lib.c | 3 +- 3 files changed, 60 insertions(+), 98 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 85a7988cf82213..a87571d5b572c1 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1093,24 +1093,17 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, if (snd_BUG_ON(!sample_rate)) return -ENXIO; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); - if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) { - mutex_unlock(&chip->spos_mutex); + if (_cs46xx_adjust_sample_rate(chip, cpcm, sample_rate)) return -ENXIO; - } snd_BUG_ON(!cpcm->pcm_channel); - if (!cpcm->pcm_channel) { - mutex_unlock(&chip->spos_mutex); + if (!cpcm->pcm_channel) return -ENXIO; - } - - if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) { - mutex_unlock(&chip->spos_mutex); + if (cs46xx_dsp_pcm_channel_set_period(chip, cpcm->pcm_channel, period_size)) return -EINVAL; - } dev_dbg(chip->card->dev, "period_size (%d), periods (%d) buffer_size(%d)\n", @@ -1144,12 +1137,8 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, if (runtime->dma_area == cpcm->hw_buf.area) snd_pcm_set_runtime_buffer(substream, NULL); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (err < 0) { -#ifdef CONFIG_SND_CS46XX_NEW_DSP - mutex_unlock(&chip->spos_mutex); -#endif + if (err < 0) return err; - } #ifdef CONFIG_SND_CS46XX_NEW_DSP if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) { @@ -1169,10 +1158,6 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, } -#ifdef CONFIG_SND_CS46XX_NEW_DSP - mutex_unlock(&chip->spos_mutex); -#endif - return 0; } @@ -1495,16 +1480,14 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in cpcm->substream = substream; #ifdef CONFIG_SND_CS46XX_NEW_DSP - mutex_lock(&chip->spos_mutex); - cpcm->pcm_channel = NULL; - cpcm->pcm_channel_id = pcm_channel_id; - + scoped_guard(mutex, &chip->spos_mutex) { + cpcm->pcm_channel = NULL; + cpcm->pcm_channel_id = pcm_channel_id; + } snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_sizes); - - mutex_unlock(&chip->spos_mutex); #else chip->playback_pcm = cpcm; /* HACK */ #endif @@ -1541,9 +1524,9 @@ static int snd_cs46xx_playback_open_iec958(struct snd_pcm_substream *substream) dev_dbg(chip->card->dev, "open raw iec958 channel\n"); - mutex_lock(&chip->spos_mutex); - cs46xx_iec958_pre_open (chip); - mutex_unlock(&chip->spos_mutex); + scoped_guard(mutex, &chip->spos_mutex) { + cs46xx_iec958_pre_open(chip); + } return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL); } @@ -1559,9 +1542,9 @@ static int snd_cs46xx_playback_close_iec958(struct snd_pcm_substream *substream) err = snd_cs46xx_playback_close(substream); - mutex_lock(&chip->spos_mutex); - cs46xx_iec958_post_close (chip); - mutex_unlock(&chip->spos_mutex); + scoped_guard(mutex, &chip->spos_mutex) { + cs46xx_iec958_post_close(chip); + } return err; } @@ -1602,12 +1585,12 @@ static int snd_cs46xx_playback_close(struct snd_pcm_substream *substream) if (!cpcm) return -ENXIO; #ifdef CONFIG_SND_CS46XX_NEW_DSP - mutex_lock(&chip->spos_mutex); - if (cpcm->pcm_channel) { - cs46xx_dsp_destroy_pcm_channel(chip,cpcm->pcm_channel); - cpcm->pcm_channel = NULL; + scoped_guard(mutex, &chip->spos_mutex) { + if (cpcm->pcm_channel) { + cs46xx_dsp_destroy_pcm_channel(chip, cpcm->pcm_channel); + cpcm->pcm_channel = NULL; + } } - mutex_unlock(&chip->spos_mutex); #else chip->playback_pcm = NULL; #endif @@ -1982,15 +1965,15 @@ static int snd_cs46xx_iec958_put(struct snd_kcontrol *kcontrol, switch (kcontrol->private_value) { case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT: - mutex_lock(&chip->spos_mutex); - change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED); - if (ucontrol->value.integer.value[0] && !change) - cs46xx_dsp_enable_spdif_out(chip); - else if (change && !ucontrol->value.integer.value[0]) - cs46xx_dsp_disable_spdif_out(chip); - - res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED)); - mutex_unlock(&chip->spos_mutex); + scoped_guard(mutex, &chip->spos_mutex) { + change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED); + if (ucontrol->value.integer.value[0] && !change) + cs46xx_dsp_enable_spdif_out(chip); + else if (change && !ucontrol->value.integer.value[0]) + cs46xx_dsp_disable_spdif_out(chip); + + res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED)); + } break; case CS46XX_MIXER_SPDIF_INPUT_ELEMENT: change = chip->dsp_spos_instance->spdif_status_in; @@ -2131,12 +2114,11 @@ static int snd_cs46xx_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); struct dsp_spos_instance * ins = chip->dsp_spos_instance; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_default >> 24) & 0xff); ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_default >> 16) & 0xff); ucontrol->value.iec958.status[2] = 0; ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_default) & 0xff); - mutex_unlock(&chip->spos_mutex); return 0; } @@ -2149,7 +2131,7 @@ static int snd_cs46xx_spdif_default_put(struct snd_kcontrol *kcontrol, unsigned int val; int change; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[2]) << 16) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) | @@ -2163,8 +2145,6 @@ static int snd_cs46xx_spdif_default_put(struct snd_kcontrol *kcontrol, if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) ) cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val); - mutex_unlock(&chip->spos_mutex); - return change; } @@ -2184,12 +2164,11 @@ static int snd_cs46xx_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); struct dsp_spos_instance * ins = chip->dsp_spos_instance; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_stream >> 24) & 0xff); ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_stream >> 16) & 0xff); ucontrol->value.iec958.status[2] = 0; ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_stream) & 0xff); - mutex_unlock(&chip->spos_mutex); return 0; } @@ -2202,7 +2181,7 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, unsigned int val; int change; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[1]) << 16) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) | @@ -2216,8 +2195,6 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN ) cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val); - mutex_unlock(&chip->spos_mutex); - return change; } diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index e07f85322f1cef..a0f908bfe7fa88 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -283,7 +283,7 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) if (snd_BUG_ON(!ins)) return; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; @@ -297,7 +297,6 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) vfree(ins->symbol_table.symbols); kfree(ins->modules); kfree(ins); - mutex_unlock(&chip->spos_mutex); } static int dsp_load_parameter(struct snd_cs46xx *chip, @@ -525,7 +524,7 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry, struct dsp_spos_instance * ins = chip->dsp_spos_instance; int i,j; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); snd_iprintf(buffer, "MODULES:\n"); for ( i = 0; i < ins->nmodules; ++i ) { snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name); @@ -538,7 +537,6 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry, desc->segment_type,desc->offset, desc->size); } } - mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, @@ -549,7 +547,7 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, int i, j, col; void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); snd_iprintf(buffer, "TASK TREES:\n"); for ( i = 0; i < ins->ntask; ++i) { snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name); @@ -566,7 +564,6 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry, } snd_iprintf(buffer,"\n"); - mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, @@ -576,7 +573,7 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, struct dsp_spos_instance * ins = chip->dsp_spos_instance; int i; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); snd_iprintf(buffer, "SCB's:\n"); for ( i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) @@ -599,7 +596,6 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry, } snd_iprintf(buffer,"\n"); - mutex_unlock(&chip->spos_mutex); } static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry, @@ -831,14 +827,13 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) snd_info_set_text_ops(entry, chip, cs46xx_dsp_proc_scb_read); - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); /* register/update SCB's entries on proc */ for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i)); } - mutex_unlock(&chip->spos_mutex); return 0; } @@ -851,12 +846,13 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) if (!ins) return 0; - mutex_lock(&chip->spos_mutex); - for (i = 0; i < ins->nscb; ++i) { - if (ins->scbs[i].deleted) continue; - cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); + scoped_guard(mutex, &chip->spos_mutex) { + for (i = 0; i < ins->nscb; ++i) { + if (ins->scbs[i].deleted) + continue; + cs46xx_dsp_proc_free_scb_desc((ins->scbs + i)); + } } - mutex_unlock(&chip->spos_mutex); snd_info_free_entry(ins->proc_dsp_dir); ins->proc_dsp_dir = NULL; @@ -1677,7 +1673,7 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) if (snd_BUG_ON(!ins->spdif_in_src)) return -EINVAL; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) { /* time countdown enable */ @@ -1721,7 +1717,6 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) /* monitor state */ ins->spdif_status_in = 1; - mutex_unlock(&chip->spos_mutex); return 0; } @@ -1735,17 +1730,16 @@ int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip) if (snd_BUG_ON(!ins->spdif_in_src)) return -EINVAL; - mutex_lock(&chip->spos_mutex); - - /* Remove the asynchronous receiver SCB */ - cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb); - ins->asynch_rx_scb = NULL; + scoped_guard(mutex, &chip->spos_mutex) { + /* Remove the asynchronous receiver SCB */ + cs46xx_dsp_remove_scb(chip, ins->asynch_rx_scb); + ins->asynch_rx_scb = NULL; - cs46xx_src_unlink(chip,ins->spdif_in_src); + cs46xx_src_unlink(chip, ins->spdif_in_src); - /* monitor state */ - ins->spdif_status_in = 0; - mutex_unlock(&chip->spos_mutex); + /* monitor state */ + ins->spdif_status_in = 0; + } /* restore amplifier */ chip->active_ctrl(chip, -1); @@ -1763,10 +1757,9 @@ int cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip) if (snd_BUG_ON(!ins->ref_snoop_scb)) return -EINVAL; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR, "PCMSerialInput_Wave"); - mutex_unlock(&chip->spos_mutex); return 0; } @@ -1778,10 +1771,9 @@ int cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip) if (snd_BUG_ON(!ins->pcm_input)) return -EINVAL; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->pcm_input); ins->pcm_input = NULL; - mutex_unlock(&chip->spos_mutex); return 0; } @@ -1795,10 +1787,9 @@ int cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip) if (snd_BUG_ON(!ins->codec_in_scb)) return -EINVAL; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR, "PCMSerialInput_ADC"); - mutex_unlock(&chip->spos_mutex); return 0; } @@ -1810,10 +1801,9 @@ int cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip) if (snd_BUG_ON(!ins->adc_input)) return -EINVAL; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->adc_input); ins->adc_input = NULL; - mutex_unlock(&chip->spos_mutex); return 0; } @@ -1861,7 +1851,7 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right) struct dsp_spos_instance * ins = chip->dsp_spos_instance; struct dsp_scb_descriptor * scb; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); /* main output */ scb = ins->master_mix_scb->sub_list_ptr; @@ -1880,8 +1870,6 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right) ins->dac_volume_left = left; ins->dac_volume_right = right; - mutex_unlock(&chip->spos_mutex); - return 0; } @@ -1889,7 +1877,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); if (ins->asynch_rx_scb != NULL) cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb, @@ -1898,8 +1886,6 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right) ins->spdif_input_volume_left = left; ins->spdif_input_volume_right = right; - mutex_unlock(&chip->spos_mutex); - return 0; } diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 28faca268196fd..660ad19e5f183b 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -63,7 +63,7 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, int j,col; void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; - mutex_lock(&chip->spos_mutex); + guard(mutex)(&chip->spos_mutex); snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name); for (col = 0,j = 0;j < 0x10; j++,col++) { @@ -91,7 +91,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, scb->task_entry->address); snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count); - mutex_unlock(&chip->spos_mutex); } #endif From 0ba9da2d6f770509d3f1d37df23d2ca31d5df4ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:55 +0200 Subject: [PATCH 0930/1292] ALSA: cs46xx: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-21-tiwai@suse.de --- sound/pci/cs46xx/cs46xx_lib.c | 113 ++++++++++++---------------- sound/pci/cs46xx/dsp_spos.c | 4 +- sound/pci/cs46xx/dsp_spos_scb_lib.c | 60 +++++---------- 3 files changed, 69 insertions(+), 108 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index a87571d5b572c1..b96ab7fd464ceb 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -707,7 +707,6 @@ static void snd_cs46xx_proc_stop(struct snd_cs46xx *chip) static void snd_cs46xx_set_play_sample_rate(struct snd_cs46xx *chip, unsigned int rate) { - unsigned long flags; unsigned int tmp1, tmp2; unsigned int phiIncr; unsigned int correctionPerGOF, correctionPerSec; @@ -744,16 +743,14 @@ static void snd_cs46xx_set_play_sample_rate(struct snd_cs46xx *chip, unsigned in /* * Fill in the SampleRateConverter control block. */ - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_cs46xx_poke(chip, BA1_PSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); snd_cs46xx_poke(chip, BA1_PPI, phiIncr); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned int rate) { - unsigned long flags; unsigned int phiIncr, coeffIncr, tmp1, tmp2; unsigned int correctionPerGOF, correctionPerSec, initialDelay; unsigned int frameGroupLength, cnt; @@ -818,14 +815,14 @@ static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned /* * Fill in the VariDecimate control block. */ - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs46xx_poke(chip, BA1_CSRC, - ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); - snd_cs46xx_poke(chip, BA1_CCI, coeffIncr); - snd_cs46xx_poke(chip, BA1_CD, - (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); - snd_cs46xx_poke(chip, BA1_CPI, phiIncr); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_cs46xx_poke(chip, BA1_CSRC, + ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); + snd_cs46xx_poke(chip, BA1_CCI, coeffIncr); + snd_cs46xx_poke(chip, BA1_CD, + (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); + snd_cs46xx_poke(chip, BA1_CPI, phiIncr); + } /* * Figure out the frame group length for the write back task. Basically, @@ -848,13 +845,12 @@ static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned /* * Fill in the WriteBack control block. */ - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_cs46xx_poke(chip, BA1_CFG1, frameGroupLength); snd_cs46xx_poke(chip, BA1_CFG2, (0x00800000 | frameGroupLength)); snd_cs46xx_poke(chip, BA1_CCST, 0x0000FFFF); snd_cs46xx_poke(chip, BA1_CSPB, ((65536 * rate) / 24000)); snd_cs46xx_poke(chip, (BA1_CSPB + 4), 0x0000FFFF); - spin_unlock_irqrestore(&chip->reg_lock, flags); } /* @@ -969,15 +965,14 @@ static int snd_cs46xx_playback_trigger(struct snd_pcm_substream *substream, if (substream->runtime->periods != CS46XX_FRAGS) snd_cs46xx_playback_transfer(substream); #else - spin_lock(&chip->reg_lock); - if (substream->runtime->periods != CS46XX_FRAGS) - snd_cs46xx_playback_transfer(substream); - { unsigned int tmp; - tmp = snd_cs46xx_peek(chip, BA1_PCTL); - tmp &= 0x0000ffff; - snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp); + scoped_guard(spinlock, &chip->reg_lock) { + unsigned int tmp; + if (substream->runtime->periods != CS46XX_FRAGS) + snd_cs46xx_playback_transfer(substream); + tmp = snd_cs46xx_peek(chip, BA1_PCTL); + tmp &= 0x0000ffff; + snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp); } - spin_unlock(&chip->reg_lock); #endif break; case SNDRV_PCM_TRIGGER_STOP: @@ -990,13 +985,12 @@ static int snd_cs46xx_playback_trigger(struct snd_pcm_substream *substream, if (!cpcm->pcm_channel->unlinked) cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel); #else - spin_lock(&chip->reg_lock); - { unsigned int tmp; - tmp = snd_cs46xx_peek(chip, BA1_PCTL); - tmp &= 0x0000ffff; - snd_cs46xx_poke(chip, BA1_PCTL, tmp); + scoped_guard(spinlock, &chip->reg_lock) { + unsigned int tmp; + tmp = snd_cs46xx_peek(chip, BA1_PCTL); + tmp &= 0x0000ffff; + snd_cs46xx_poke(chip, BA1_PCTL, tmp); } - spin_unlock(&chip->reg_lock); #endif break; default: @@ -1012,9 +1006,8 @@ static int snd_cs46xx_capture_trigger(struct snd_pcm_substream *substream, { struct snd_cs46xx *chip = snd_pcm_substream_chip(substream); unsigned int tmp; - int result = 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -1029,12 +1022,9 @@ static int snd_cs46xx_capture_trigger(struct snd_pcm_substream *substream, snd_cs46xx_poke(chip, BA1_CCTL, tmp); break; default: - result = -EINVAL; - break; + return -EINVAL; } - spin_unlock(&chip->reg_lock); - - return result; + return 0; } #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -1371,7 +1361,7 @@ static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id) if ((status1 & HISR_MIDI) && chip->rmidi) { unsigned char c; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_RBE) == 0) { c = snd_cs46xx_peekBA0(chip, BA0_MIDRP); if ((chip->midcr & MIDCR_RIE) == 0) @@ -1388,7 +1378,6 @@ static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id) } snd_cs46xx_pokeBA0(chip, BA0_MIDWP, c); } - spin_unlock(&chip->reg_lock); } /* * EOI to the PCI part....reenables interrupts @@ -2509,7 +2498,7 @@ static int snd_cs46xx_midi_input_open(struct snd_rawmidi_substream *substream) struct snd_cs46xx *chip = substream->rmidi->private_data; chip->active_ctrl(chip, 1); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->uartm |= CS46XX_MODE_INPUT; chip->midcr |= MIDCR_RXE; chip->midi_input = substream; @@ -2518,7 +2507,6 @@ static int snd_cs46xx_midi_input_open(struct snd_rawmidi_substream *substream) } else { snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -2526,16 +2514,16 @@ static int snd_cs46xx_midi_input_close(struct snd_rawmidi_substream *substream) { struct snd_cs46xx *chip = substream->rmidi->private_data; - spin_lock_irq(&chip->reg_lock); - chip->midcr &= ~(MIDCR_RXE | MIDCR_RIE); - chip->midi_input = NULL; - if (!(chip->uartm & CS46XX_MODE_OUTPUT)) { - snd_cs46xx_midi_reset(chip); - } else { - snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); + scoped_guard(spinlock_irq, &chip->reg_lock) { + chip->midcr &= ~(MIDCR_RXE | MIDCR_RIE); + chip->midi_input = NULL; + if (!(chip->uartm & CS46XX_MODE_OUTPUT)) { + snd_cs46xx_midi_reset(chip); + } else { + snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); + } + chip->uartm &= ~CS46XX_MODE_INPUT; } - chip->uartm &= ~CS46XX_MODE_INPUT; - spin_unlock_irq(&chip->reg_lock); chip->active_ctrl(chip, -1); return 0; } @@ -2546,7 +2534,7 @@ static int snd_cs46xx_midi_output_open(struct snd_rawmidi_substream *substream) chip->active_ctrl(chip, 1); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->uartm |= CS46XX_MODE_OUTPUT; chip->midcr |= MIDCR_TXE; chip->midi_output = substream; @@ -2555,7 +2543,6 @@ static int snd_cs46xx_midi_output_open(struct snd_rawmidi_substream *substream) } else { snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -2563,26 +2550,25 @@ static int snd_cs46xx_midi_output_close(struct snd_rawmidi_substream *substream) { struct snd_cs46xx *chip = substream->rmidi->private_data; - spin_lock_irq(&chip->reg_lock); - chip->midcr &= ~(MIDCR_TXE | MIDCR_TIE); - chip->midi_output = NULL; - if (!(chip->uartm & CS46XX_MODE_INPUT)) { - snd_cs46xx_midi_reset(chip); - } else { - snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); + scoped_guard(spinlock_irq, &chip->reg_lock) { + chip->midcr &= ~(MIDCR_TXE | MIDCR_TIE); + chip->midi_output = NULL; + if (!(chip->uartm & CS46XX_MODE_INPUT)) { + snd_cs46xx_midi_reset(chip); + } else { + snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); + } + chip->uartm &= ~CS46XX_MODE_OUTPUT; } - chip->uartm &= ~CS46XX_MODE_OUTPUT; - spin_unlock_irq(&chip->reg_lock); chip->active_ctrl(chip, -1); return 0; } static void snd_cs46xx_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_cs46xx *chip = substream->rmidi->private_data; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (up) { if ((chip->midcr & MIDCR_RIE) == 0) { chip->midcr |= MIDCR_RIE; @@ -2594,16 +2580,14 @@ static void snd_cs46xx_midi_input_trigger(struct snd_rawmidi_substream *substrea snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } } - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_cs46xx *chip = substream->rmidi->private_data; unsigned char byte; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (up) { if ((chip->midcr & MIDCR_TIE) == 0) { chip->midcr |= MIDCR_TIE; @@ -2624,7 +2608,6 @@ static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substre snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } } - spin_unlock_irqrestore(&chip->reg_lock, flags); } static const struct snd_rawmidi_ops snd_cs46xx_midi_output = diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index a0f908bfe7fa88..3d34575a0e8f6c 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -1696,7 +1696,7 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) ins->spdif_in_src, SCB_ON_PARENT_SUBLIST_SCB); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); /* reset SPDIF input sample buffer pointer */ /*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2, @@ -1709,8 +1709,6 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip) /* unmute SRC volume */ cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff); - spin_unlock_irq(&chip->reg_lock); - /* set SPDIF input sample rate and unmute NOTE: only 48khz support for SPDIF input this time */ /* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */ diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 660ad19e5f183b..32ed415bf427cf 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -159,7 +159,6 @@ static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - unsigned long flags; /* check integrety */ if (snd_BUG_ON(scb->index < 0 || @@ -175,9 +174,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * goto _end; #endif - spin_lock_irqsave(&chip->reg_lock, flags); - _dsp_unlink_scb (chip,scb); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + _dsp_unlink_scb(chip, scb); + } cs46xx_dsp_proc_free_scb_desc(scb); if (snd_BUG_ON(!scb->scb_symbol)) @@ -262,8 +261,6 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u struct dsp_spos_instance * ins = chip->dsp_spos_instance; struct dsp_scb_descriptor * scb; - unsigned long flags; - if (snd_BUG_ON(!ins->the_null_scb)) return NULL; @@ -317,12 +314,10 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u snd_BUG(); } - spin_lock_irqsave(&chip->reg_lock, flags); - - /* update entry in DSP RAM */ - cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); - - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + /* update entry in DSP RAM */ + cs46xx_dsp_spos_update_scb(chip, scb->parent_scb_ptr); + } } @@ -1219,7 +1214,6 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, /* struct dsp_scb_descriptor * pcm_parent_scb; */ char scb_name[DSP_MAX_SCB_NAME]; int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0; - unsigned long flags; switch (pcm_channel_id) { case DSP_PCM_MAIN_CHANNEL: @@ -1356,7 +1350,7 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, return NULL; } - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ins->pcm_channels[pcm_index].sample_rate = sample_rate; ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb; ins->pcm_channels[pcm_index].src_scb = src_scb; @@ -1367,7 +1361,6 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, ins->pcm_channels[pcm_index].pcm_slot = pcm_index; ins->pcm_channels[pcm_index].mixer_scb = mixer_scb; ins->npcm_channels ++; - spin_unlock_irqrestore(&chip->reg_lock, flags); return (ins->pcm_channels + pcm_index); } @@ -1455,20 +1448,19 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip, struct dsp_pcm_channel_descriptor * pcm_channel) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - unsigned long flags; if (snd_BUG_ON(!pcm_channel->active || ins->npcm_channels <= 0 || pcm_channel->src_scb->ref_count <= 0)) return; - spin_lock_irqsave(&chip->reg_lock, flags); - pcm_channel->unlinked = 1; - pcm_channel->active = 0; - pcm_channel->private_data = NULL; - pcm_channel->src_scb->ref_count --; - ins->npcm_channels --; - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + pcm_channel->unlinked = 1; + pcm_channel->active = 0; + pcm_channel->private_data = NULL; + pcm_channel->src_scb->ref_count--; + ins->npcm_channels--; + } cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb); @@ -1487,22 +1479,17 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip, int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip, struct dsp_pcm_channel_descriptor * pcm_channel) { - unsigned long flags; - if (snd_BUG_ON(!pcm_channel->active || chip->dsp_spos_instance->npcm_channels <= 0)) return -EIO; - spin_lock_irqsave(&chip->reg_lock, flags); - if (pcm_channel->unlinked) { - spin_unlock_irqrestore(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); + if (pcm_channel->unlinked) return -EIO; - } pcm_channel->unlinked = 1; _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -1513,14 +1500,11 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, struct dsp_spos_instance * ins = chip->dsp_spos_instance; struct dsp_scb_descriptor * parent_scb; struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); - if (pcm_channel->unlinked == 0) { - spin_unlock_irqrestore(&chip->reg_lock, flags); + if (pcm_channel->unlinked == 0) return -EIO; - } parent_scb = src_scb; @@ -1541,7 +1525,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, cs46xx_dsp_spos_update_scb(chip,parent_scb); pcm_channel->unlinked = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -1574,17 +1557,14 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src) { - unsigned long flags; - if (snd_BUG_ON(!src->parent_scb_ptr)) return -EINVAL; /* mute SCB */ cs46xx_dsp_scb_set_volume (chip,src,0,0); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); _dsp_unlink_scb (chip,src); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } From e8eca9fec23f6ae66e5a776ea15b89c82da7ab73 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:56 +0200 Subject: [PATCH 0931/1292] ALSA: cs5535audio: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-22-tiwai@suse.de --- sound/pci/cs5535audio/cs5535audio.c | 14 ++++++++------ sound/pci/cs5535audio/cs5535audio_pcm.c | 12 ++++-------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 76566e7baea0a8..0ebf6c02b1effd 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -176,9 +176,10 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) static void process_bm0_irq(struct cs5535audio *cs5535au) { u8 bm_stat; - spin_lock(&cs5535au->reg_lock); - bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS); - spin_unlock(&cs5535au->reg_lock); + + scoped_guard(spinlock, &cs5535au->reg_lock) { + bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS); + } if (bm_stat & EOP) { snd_pcm_period_elapsed(cs5535au->playback_substream); } else { @@ -191,9 +192,10 @@ static void process_bm0_irq(struct cs5535audio *cs5535au) static void process_bm1_irq(struct cs5535audio *cs5535au) { u8 bm_stat; - spin_lock(&cs5535au->reg_lock); - bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS); - spin_unlock(&cs5535au->reg_lock); + + scoped_guard(spinlock, &cs5535au->reg_lock) { + bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS); + } if (bm_stat & EOP) snd_pcm_period_elapsed(cs5535au->capture_substream); } diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index f296b2c630265c..48b99a07e3bc18 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -150,10 +150,9 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, dma->substream = substream; dma->period_bytes = period_bytes; dma->periods = periods; - spin_lock_irq(&cs5535au->reg_lock); + guard(spinlock_irq)(&cs5535au->reg_lock); dma->ops->disable_dma(cs5535au); dma->ops->setup_prd(cs5535au, jmpprd_addr); - spin_unlock_irq(&cs5535au->reg_lock); return 0; } @@ -276,9 +275,8 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd) { struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); struct cs5535audio_dma *dma = substream->runtime->private_data; - int err = 0; - spin_lock(&cs5535au->reg_lock); + guard(spinlock)(&cs5535au->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: dma->ops->pause_dma(cs5535au); @@ -300,11 +298,9 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd) break; default: dev_err(cs5535au->card->dev, "unhandled trigger\n"); - err = -EINVAL; - break; + return -EINVAL; } - spin_unlock(&cs5535au->reg_lock); - return err; + return 0; } static snd_pcm_uframes_t snd_cs5535audio_pcm_pointer(struct snd_pcm_substream From e1d4c746bb46127efe541c3fc4b1034faf0a0adf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:57 +0200 Subject: [PATCH 0932/1292] ALSA: ctxfi: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-23-tiwai@suse.de --- sound/pci/ctxfi/ctatc.c | 28 +++++++++++++--------------- sound/pci/ctxfi/ctvmem.c | 16 ++++++---------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 2a3e9d8ba7dbe7..14779b383d9ea3 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -295,10 +295,10 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; for (i = 0; i < n_amixer; i++) { amixer = apcm->amixers[i]; - mutex_lock(&atc->atc_mutex); - amixer->ops->setup(amixer, &src->rsc, - INIT_VOL, atc->pcm[i+device*2]); - mutex_unlock(&atc->atc_mutex); + scoped_guard(mutex, &atc->atc_mutex) { + amixer->ops->setup(amixer, &src->rsc, + INIT_VOL, atc->pcm[i+device*2]); + } src = src->ops->next_interleave(src); if (!src) src = apcm->src; @@ -874,7 +874,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) return -ENOENT; } - mutex_lock(&atc->atc_mutex); + guard(mutex)(&atc->atc_mutex); dao->ops->get_spos(dao, &status); if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { status &= ~(IEC958_AES3_CON_FS << 24); @@ -884,7 +884,6 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) } if ((rate != atc->pll_rate) && (32000 != rate)) err = atc_pll_init(atc, rate); - mutex_unlock(&atc->atc_mutex); return err; } @@ -921,13 +920,13 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; } /* Connect to SPDIFOO */ - mutex_lock(&atc->atc_mutex); - dao = container_of(atc->daios[SPDIFOO], struct dao, daio); - amixer = apcm->amixers[0]; - dao->ops->set_left_input(dao, &amixer->rsc); - amixer = apcm->amixers[1]; - dao->ops->set_right_input(dao, &amixer->rsc); - mutex_unlock(&atc->atc_mutex); + scoped_guard(mutex, &atc->atc_mutex) { + dao = container_of(atc->daios[SPDIFOO], struct dao, daio); + amixer = apcm->amixers[0]; + dao->ops->set_left_input(dao, &amixer->rsc); + amixer = apcm->amixers[1]; + dao->ops->set_right_input(dao, &amixer->rsc); + } ct_timer_prepare(apcm->timer); @@ -1115,7 +1114,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) struct rsc *rscs[2] = {NULL}; unsigned int spos = 0; - mutex_lock(&atc->atc_mutex); + guard(mutex)(&atc->atc_mutex); dao = container_of(atc->daios[SPDIFOO], struct dao, daio); da_dsc.msr = state ? 1 : atc->msr; da_dsc.passthru = state ? 1 : 0; @@ -1133,7 +1132,6 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) } dao->ops->set_spos(dao, spos); dao->ops->commit_write(dao); - mutex_unlock(&atc->atc_mutex); return err; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 7a805c4a58e143..823d6e240a07c0 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -29,7 +29,7 @@ static struct ct_vm_block * get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc) { - struct ct_vm_block *block = NULL, *entry; + struct ct_vm_block *block, *entry; struct list_head *pos; size = CT_PAGE_ALIGN(size); @@ -39,26 +39,25 @@ get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc) return NULL; } - mutex_lock(&vm->lock); + guard(mutex)(&vm->lock); list_for_each(pos, &vm->unused) { entry = list_entry(pos, struct ct_vm_block, list); if (entry->size >= size) break; /* found a block that is big enough */ } if (pos == &vm->unused) - goto out; + return NULL; if (entry->size == size) { /* Move the vm node from unused list to used list directly */ list_move(&entry->list, &vm->used); vm->size -= size; - block = entry; - goto out; + return entry; } block = kzalloc(sizeof(*block), GFP_KERNEL); if (!block) - goto out; + return NULL; block->addr = entry->addr; block->size = size; @@ -67,8 +66,6 @@ get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc) entry->size -= size; vm->size -= size; - out: - mutex_unlock(&vm->lock); return block; } @@ -79,7 +76,7 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) block->size = CT_PAGE_ALIGN(block->size); - mutex_lock(&vm->lock); + guard(mutex)(&vm->lock); list_del(&block->list); vm->size += block->size; @@ -116,7 +113,6 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) pos = pre; pre = pos->prev; } - mutex_unlock(&vm->lock); } /* Map host addr (kmalloced/vmalloced) to device logical addr. */ From be9478bd3afcdd54b29cf4d02b70f04b04888e20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:58 +0200 Subject: [PATCH 0933/1292] ALSA: ctxfi: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-24-tiwai@suse.de --- sound/pci/ctxfi/ctamixer.c | 67 +++++++++++------------- sound/pci/ctxfi/ctdaio.c | 42 ++++++--------- sound/pci/ctxfi/cthw20k1.c | 39 +++----------- sound/pci/ctxfi/ctsrc.c | 101 +++++++++++++++---------------------- sound/pci/ctxfi/cttimer.c | 63 +++++++++-------------- 5 files changed, 115 insertions(+), 197 deletions(-) diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index 397900929aa659..bb465859263693 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -231,7 +231,6 @@ static int get_amixer_rsc(struct amixer_mgr *mgr, int err, i; unsigned int idx; struct amixer *amixer; - unsigned long flags; *ramixer = NULL; @@ -243,15 +242,15 @@ static int get_amixer_rsc(struct amixer_mgr *mgr, /* Check whether there are sufficient * amixer resources to meet request. */ err = 0; - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < desc->msr; i++) { - err = mgr_get_resource(&mgr->mgr, 1, &idx); - if (err) - break; + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i = 0; i < desc->msr; i++) { + err = mgr_get_resource(&mgr->mgr, 1, &idx); + if (err) + break; - amixer->idx[i] = idx; + amixer->idx[i] = idx; + } } - spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { dev_err(mgr->card->dev, "Can't meet AMIXER resource request!\n"); @@ -267,25 +266,23 @@ static int get_amixer_rsc(struct amixer_mgr *mgr, return 0; error: - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i--; i >= 0; i--) - mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i--; i >= 0; i--) + mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); + } - spin_unlock_irqrestore(&mgr->mgr_lock, flags); kfree(amixer); return err; } static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) { - unsigned long flags; int i; - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < amixer->rsc.msr; i++) - mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i = 0; i < amixer->rsc.msr; i++) + mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); + } amixer_rsc_uninit(amixer); kfree(amixer); @@ -387,7 +384,6 @@ static int get_sum_rsc(struct sum_mgr *mgr, int err, i; unsigned int idx; struct sum *sum; - unsigned long flags; *rsum = NULL; @@ -398,15 +394,15 @@ static int get_sum_rsc(struct sum_mgr *mgr, /* Check whether there are sufficient sum resources to meet request. */ err = 0; - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < desc->msr; i++) { - err = mgr_get_resource(&mgr->mgr, 1, &idx); - if (err) - break; + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i = 0; i < desc->msr; i++) { + err = mgr_get_resource(&mgr->mgr, 1, &idx); + if (err) + break; - sum->idx[i] = idx; + sum->idx[i] = idx; + } } - spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { dev_err(mgr->card->dev, "Can't meet SUM resource request!\n"); @@ -422,25 +418,22 @@ static int get_sum_rsc(struct sum_mgr *mgr, return 0; error: - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i--; i >= 0; i--) - mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i--; i >= 0; i--) + mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); + } kfree(sum); return err; } static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) { - unsigned long flags; int i; - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < sum->rsc.msr; i++) - mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i = 0; i < sum->rsc.msr; i++) + mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); + } sum_rsc_uninit(sum); kfree(sum); diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 806c4d7543877e..c0c3f8ab84677d 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -503,14 +503,13 @@ static int get_daio_rsc(struct daio_mgr *mgr, struct daio **rdaio) { int err; - unsigned long flags; *rdaio = NULL; /* Check whether there are sufficient daio resources to meet request. */ - spin_lock_irqsave(&mgr->mgr_lock, flags); - err = daio_mgr_get_rsc(&mgr->mgr, desc->type); - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + err = daio_mgr_get_rsc(&mgr->mgr, desc->type); + } if (err) { dev_err(mgr->card->dev, "Can't meet DAIO resource request!\n"); @@ -551,22 +550,20 @@ static int get_daio_rsc(struct daio_mgr *mgr, return 0; error: - spin_lock_irqsave(&mgr->mgr_lock, flags); - daio_mgr_put_rsc(&mgr->mgr, desc->type); - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + daio_mgr_put_rsc(&mgr->mgr, desc->type); + } return err; } static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio) { - unsigned long flags; - mgr->daio_disable(mgr, daio); mgr->commit_write(mgr); - spin_lock_irqsave(&mgr->mgr_lock, flags); - daio_mgr_put_rsc(&mgr->mgr, daio->type); - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + daio_mgr_put_rsc(&mgr->mgr, daio->type); + } if (daio->type <= DAIO_OUT_MAX) { dao_rsc_uninit(container_of(daio, struct dao, daio)); @@ -622,34 +619,26 @@ static int daio_map_op(void *data, struct imapper *entry) static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry) { - unsigned long flags; - int err; - - spin_lock_irqsave(&mgr->imap_lock, flags); + guard(spinlock_irqsave)(&mgr->imap_lock); if (!entry->addr && mgr->init_imap_added) { input_mapper_delete(&mgr->imappers, mgr->init_imap, daio_map_op, mgr); mgr->init_imap_added = 0; } - err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr); - spin_unlock_irqrestore(&mgr->imap_lock, flags); - - return err; + return input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr); } static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry) { - unsigned long flags; int err; - spin_lock_irqsave(&mgr->imap_lock, flags); + guard(spinlock_irqsave)(&mgr->imap_lock); err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr); if (list_empty(&mgr->imappers)) { input_mapper_add(&mgr->imappers, mgr->init_imap, daio_map_op, mgr); mgr->init_imap_added = 1; } - spin_unlock_irqrestore(&mgr->imap_lock, flags); return err; } @@ -719,12 +708,11 @@ int daio_mgr_create(struct hw *hw, void **rdaio_mgr) int daio_mgr_destroy(void *ptr) { struct daio_mgr *daio_mgr = ptr; - unsigned long flags; /* free daio input mapper list */ - spin_lock_irqsave(&daio_mgr->imap_lock, flags); - free_input_mapper_list(&daio_mgr->imappers); - spin_unlock_irqrestore(&daio_mgr->imap_lock, flags); + scoped_guard(spinlock_irqsave, &daio_mgr->imap_lock) { + free_input_mapper_list(&daio_mgr->imappers); + } rsc_mgr_uninit(&daio_mgr->mgr); kfree(daio_mgr); diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 9edbf5d8c3c70c..42b90c9b2ee9f1 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -2091,57 +2091,30 @@ static int hw_resume(struct hw *hw, struct card_conf *info) static u32 hw_read_20kx(struct hw *hw, u32 reg) { - u32 value; - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); + guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_20k1_lock); outl(reg, hw->io_base + 0x0); - value = inl(hw->io_base + 0x4); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); - - return value; + return inl(hw->io_base + 0x4); } static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) { - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); + guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_20k1_lock); outl(reg, hw->io_base + 0x0); outl(data, hw->io_base + 0x4); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); - } static u32 hw_read_pci(struct hw *hw, u32 reg) { - u32 value; - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); + guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_pci_lock); outl(reg, hw->io_base + 0x10); - value = inl(hw->io_base + 0x14); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); - - return value; + return inl(hw->io_base + 0x14); } static void hw_write_pci(struct hw *hw, u32 reg, u32 data) { - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); + guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_pci_lock); outl(reg, hw->io_base + 0x10); outl(data, hw->io_base + 0x14); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); } static const struct hw ct20k1_preset = { diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 159bd400806917..46afc9604c0829 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -414,18 +414,16 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) unsigned int idx = SRC_RESOURCE_NUM; int err; struct src *src; - unsigned long flags; *rsrc = NULL; /* Check whether there are sufficient src resources to meet request. */ - spin_lock_irqsave(&mgr->mgr_lock, flags); - if (MEMRD == desc->mode) - err = mgr_get_resource(&mgr->mgr, desc->multi, &idx); - else - err = mgr_get_resource(&mgr->mgr, 1, &idx); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + if (MEMRD == desc->mode) + err = mgr_get_resource(&mgr->mgr, desc->multi, &idx); + else + err = mgr_get_resource(&mgr->mgr, 1, &idx); + } if (err) { dev_err(mgr->card->dev, "Can't meet SRC resource request!\n"); @@ -454,29 +452,25 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) error2: kfree(src); error1: - spin_lock_irqsave(&mgr->mgr_lock, flags); - if (MEMRD == desc->mode) - mgr_put_resource(&mgr->mgr, desc->multi, idx); - else - mgr_put_resource(&mgr->mgr, 1, idx); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + if (MEMRD == desc->mode) + mgr_put_resource(&mgr->mgr, desc->multi, idx); + else + mgr_put_resource(&mgr->mgr, 1, idx); + } return err; } static int put_src_rsc(struct src_mgr *mgr, struct src *src) { - unsigned long flags; - - spin_lock_irqsave(&mgr->mgr_lock, flags); - src->rsc.ops->master(&src->rsc); - if (MEMRD == src->mode) - mgr_put_resource(&mgr->mgr, src->multi, - src->rsc.ops->index(&src->rsc)); - else - mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc)); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + src->rsc.ops->master(&src->rsc); + if (MEMRD == src->mode) + mgr_put_resource(&mgr->mgr, src->multi, + src->rsc.ops->index(&src->rsc)); + else + mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc)); + } src_rsc_uninit(src, mgr); kfree(src); @@ -714,7 +708,6 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr, int err, i; unsigned int idx; struct srcimp *srcimp; - unsigned long flags; *rsrcimp = NULL; @@ -725,15 +718,15 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr, /* Check whether there are sufficient SRCIMP resources. */ err = 0; - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < desc->msr; i++) { - err = mgr_get_resource(&mgr->mgr, 1, &idx); - if (err) - break; + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i = 0; i < desc->msr; i++) { + err = mgr_get_resource(&mgr->mgr, 1, &idx); + if (err) + break; - srcimp->idx[i] = idx; + srcimp->idx[i] = idx; + } } - spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { dev_err(mgr->card->dev, "Can't meet SRCIMP resource request!\n"); @@ -749,25 +742,22 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr, return 0; error1: - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i--; i >= 0; i--) - mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i--; i >= 0; i--) + mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); + } kfree(srcimp); return err; } static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp) { - unsigned long flags; int i; - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < srcimp->rsc.msr; i++) - mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); + scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { + for (i = 0; i < srcimp->rsc.msr; i++) + mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); + } srcimp_rsc_uninit(srcimp); kfree(srcimp); @@ -790,34 +780,26 @@ static int srcimp_map_op(void *data, struct imapper *entry) static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry) { - unsigned long flags; - int err; - - spin_lock_irqsave(&mgr->imap_lock, flags); + guard(spinlock_irqsave)(&mgr->imap_lock); if ((0 == entry->addr) && (mgr->init_imap_added)) { input_mapper_delete(&mgr->imappers, mgr->init_imap, srcimp_map_op, mgr); mgr->init_imap_added = 0; } - err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr); - spin_unlock_irqrestore(&mgr->imap_lock, flags); - - return err; + return input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr); } static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) { - unsigned long flags; int err; - spin_lock_irqsave(&mgr->imap_lock, flags); + guard(spinlock_irqsave)(&mgr->imap_lock); err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr); if (list_empty(&mgr->imappers)) { input_mapper_add(&mgr->imappers, mgr->init_imap, srcimp_map_op, mgr); mgr->init_imap_added = 1; } - spin_unlock_irqrestore(&mgr->imap_lock, flags); return err; } @@ -870,12 +852,11 @@ int srcimp_mgr_create(struct hw *hw, void **rsrcimp_mgr) int srcimp_mgr_destroy(void *ptr) { struct srcimp_mgr *srcimp_mgr = ptr; - unsigned long flags; /* free src input mapper list */ - spin_lock_irqsave(&srcimp_mgr->imap_lock, flags); - free_input_mapper_list(&srcimp_mgr->imappers); - spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags); + scoped_guard(spinlock_irqsave, &srcimp_mgr->imap_lock) { + free_input_mapper_list(&srcimp_mgr->imappers); + } rsc_mgr_uninit(&srcimp_mgr->mgr); kfree(srcimp_mgr); diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index fa6867adb42b5b..609b10320ff72f 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -68,7 +68,6 @@ static void ct_systimer_callback(struct timer_list *t) struct ct_atc_pcm *apcm = ti->apcm; unsigned int period_size = runtime->period_size; unsigned int buffer_size = runtime->buffer_size; - unsigned long flags; unsigned int position, dist, interval; position = substream->ops->pointer(substream); @@ -82,10 +81,9 @@ static void ct_systimer_callback(struct timer_list *t) * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */ interval = ((period_size - (position % period_size)) * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000; - spin_lock_irqsave(&ti->lock, flags); + guard(spinlock_irqsave)(&ti->lock); if (ti->running) mod_timer(&ti->timer, jiffies + interval); - spin_unlock_irqrestore(&ti->lock, flags); } static void ct_systimer_init(struct ct_timer_instance *ti) @@ -96,24 +94,19 @@ static void ct_systimer_init(struct ct_timer_instance *ti) static void ct_systimer_start(struct ct_timer_instance *ti) { struct snd_pcm_runtime *runtime = ti->substream->runtime; - unsigned long flags; - spin_lock_irqsave(&ti->lock, flags); + guard(spinlock_irqsave)(&ti->lock); ti->running = 1; mod_timer(&ti->timer, jiffies + (runtime->period_size * HZ + (runtime->rate - 1)) / runtime->rate); - spin_unlock_irqrestore(&ti->lock, flags); } static void ct_systimer_stop(struct ct_timer_instance *ti) { - unsigned long flags; - - spin_lock_irqsave(&ti->lock, flags); + guard(spinlock_irqsave)(&ti->lock); ti->running = 0; timer_delete(&ti->timer); - spin_unlock_irqrestore(&ti->lock, flags); } static void ct_systimer_prepare(struct ct_timer_instance *ti) @@ -229,25 +222,22 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update) static void ct_xfitimer_check_period(struct ct_timer *atimer) { struct ct_timer_instance *ti; - unsigned long flags; - spin_lock_irqsave(&atimer->list_lock, flags); + guard(spinlock_irqsave)(&atimer->list_lock); list_for_each_entry(ti, &atimer->instance_head, instance_list) { if (ti->running && ti->need_update) { ti->need_update = 0; ti->apcm->interrupt(ti->apcm); } } - spin_unlock_irqrestore(&atimer->list_lock, flags); } /* Handle timer-interrupt */ static void ct_xfitimer_callback(struct ct_timer *atimer) { int update; - unsigned long flags; - spin_lock_irqsave(&atimer->lock, flags); + guard(spinlock_irqsave)(&atimer->lock); atimer->irq_handling = 1; do { update = ct_xfitimer_reprogram(atimer, 1); @@ -257,7 +247,6 @@ static void ct_xfitimer_callback(struct ct_timer *atimer) spin_lock(&atimer->lock); } while (atimer->reprogram); atimer->irq_handling = 0; - spin_unlock_irqrestore(&atimer->lock, flags); } static void ct_xfitimer_prepare(struct ct_timer_instance *ti) @@ -271,45 +260,39 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti) /* start/stop the timer */ static void ct_xfitimer_update(struct ct_timer *atimer) { - unsigned long flags; - - spin_lock_irqsave(&atimer->lock, flags); + guard(spinlock_irqsave)(&atimer->lock); if (atimer->irq_handling) { /* reached from IRQ handler; let it handle later */ atimer->reprogram = 1; - spin_unlock_irqrestore(&atimer->lock, flags); return; } ct_xfitimer_irq_stop(atimer); ct_xfitimer_reprogram(atimer, 0); - spin_unlock_irqrestore(&atimer->lock, flags); } static void ct_xfitimer_start(struct ct_timer_instance *ti) { struct ct_timer *atimer = ti->timer_base; - unsigned long flags; - spin_lock_irqsave(&atimer->lock, flags); - if (list_empty(&ti->running_list)) - atimer->wc = ct_xfitimer_get_wc(atimer); - ti->running = 1; - ti->need_update = 0; - list_add(&ti->running_list, &atimer->running_head); - spin_unlock_irqrestore(&atimer->lock, flags); + scoped_guard(spinlock_irqsave, &atimer->lock) { + if (list_empty(&ti->running_list)) + atimer->wc = ct_xfitimer_get_wc(atimer); + ti->running = 1; + ti->need_update = 0; + list_add(&ti->running_list, &atimer->running_head); + } ct_xfitimer_update(atimer); } static void ct_xfitimer_stop(struct ct_timer_instance *ti) { struct ct_timer *atimer = ti->timer_base; - unsigned long flags; - spin_lock_irqsave(&atimer->lock, flags); - list_del_init(&ti->running_list); - ti->running = 0; - spin_unlock_irqrestore(&atimer->lock, flags); + scoped_guard(spinlock_irqsave, &atimer->lock) { + list_del_init(&ti->running_list); + ti->running = 0; + } ct_xfitimer_update(atimer); } @@ -347,9 +330,9 @@ ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm) if (atimer->ops->init) atimer->ops->init(ti); - spin_lock_irq(&atimer->list_lock); - list_add(&ti->instance_list, &atimer->instance_head); - spin_unlock_irq(&atimer->list_lock); + scoped_guard(spinlock_irq, &atimer->list_lock) { + list_add(&ti->instance_list, &atimer->instance_head); + } return ti; } @@ -382,9 +365,9 @@ void ct_timer_instance_free(struct ct_timer_instance *ti) if (atimer->ops->free_instance) atimer->ops->free_instance(ti); - spin_lock_irq(&atimer->list_lock); - list_del(&ti->instance_list); - spin_unlock_irq(&atimer->list_lock); + scoped_guard(spinlock_irq, &atimer->list_lock) { + list_del(&ti->instance_list); + } kfree(ti); } From 3eda594925f72c6846cf4785e700ab8e26e34bd1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:42:59 +0200 Subject: [PATCH 0934/1292] ALSA: echoaudio: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-25-tiwai@suse.de --- sound/pci/echoaudio/echoaudio.c | 36 +++++++++++++-------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 2b33ef588ac31e..4cfe8ad970698b 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -237,7 +237,7 @@ static int hw_rule_sample_rate(struct snd_pcm_hw_params *params, struct snd_interval fixed; int err; - mutex_lock(&chip->mode_mutex); + guard(mutex)(&chip->mode_mutex); if (chip->can_set_rate) { err = 0; @@ -247,7 +247,6 @@ static int hw_rule_sample_rate(struct snd_pcm_hw_params *params, err = snd_interval_refine(rate, &fixed); } - mutex_unlock(&chip->mode_mutex); return err; } @@ -415,7 +414,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) int err, max_channels; max_channels = num_digital_busses_in(chip) - substream->number; - mutex_lock(&chip->mode_mutex); + guard(mutex)(&chip->mode_mutex); if (chip->digital_mode == DIGITAL_MODE_ADAT) err = pcm_open(substream, max_channels); else /* If the card has ADAT, subtract the 6 channels @@ -424,24 +423,22 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT); if (err < 0) - goto din_exit; + return err; err = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_capture_channels_by_format, NULL, SNDRV_PCM_HW_PARAM_FORMAT, -1); if (err < 0) - goto din_exit; + return err; err = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, hw_rule_capture_format_by_channels, NULL, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (err < 0) - goto din_exit; + return err; -din_exit: - mutex_unlock(&chip->mode_mutex); - return err; + return 0; } @@ -454,7 +451,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) int err, max_channels; max_channels = num_digital_busses_out(chip) - substream->number; - mutex_lock(&chip->mode_mutex); + guard(mutex)(&chip->mode_mutex); if (chip->digital_mode == DIGITAL_MODE_ADAT) err = pcm_open(substream, max_channels); else /* If the card has ADAT, subtract the 6 channels @@ -463,7 +460,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT); if (err < 0) - goto dout_exit; + return err; err = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -471,18 +468,16 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) NULL, SNDRV_PCM_HW_PARAM_FORMAT, -1); if (err < 0) - goto dout_exit; + return err; err = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, hw_rule_playback_format_by_channels, NULL, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (err < 0) - goto dout_exit; + return err; -dout_exit: - mutex_unlock(&chip->mode_mutex); - return err; + return 0; } #endif /* !ECHOCARD_HAS_VMIXER */ @@ -499,7 +494,7 @@ static int pcm_close(struct snd_pcm_substream *substream) * freed by its callback */ - mutex_lock(&chip->mode_mutex); + guard(mutex)(&chip->mode_mutex); dev_dbg(chip->card->dev, "pcm_open opencount=%d can_set_rate=%d, rate_set=%d", chip->opencount, chip->can_set_rate, chip->rate_set); @@ -516,7 +511,6 @@ static int pcm_close(struct snd_pcm_substream *substream) break; } - mutex_unlock(&chip->mode_mutex); return 0; } @@ -1440,7 +1434,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, if (dmode != chip->digital_mode) { /* mode_mutex is required to make this operation atomic wrt pcm_digital_*_open() and set_input_clock() functions. */ - mutex_lock(&chip->mode_mutex); + guard(mutex)(&chip->mode_mutex); /* Do not allow the user to change the digital mode when a pcm device is open because it also changes the number of channels @@ -1460,7 +1454,6 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, if (changed >= 0) changed = 1; /* No errors */ } - mutex_unlock(&chip->mode_mutex); } return changed; } @@ -1573,13 +1566,12 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, return -EINVAL; dclock = chip->clock_source_list[eclock]; if (chip->input_clock != dclock) { - mutex_lock(&chip->mode_mutex); + guard(mutex)(&chip->mode_mutex); spin_lock_irq(&chip->lock); changed = set_input_clock(chip, dclock); if (!changed) changed = 1; /* no errors */ spin_unlock_irq(&chip->lock); - mutex_unlock(&chip->mode_mutex); } if (changed < 0) From 9bd92d6673426c0dc99f5f526fb029ee69de8d73 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:00 +0200 Subject: [PATCH 0935/1292] ALSA: echoaudio: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-26-tiwai@suse.de --- sound/pci/echoaudio/echoaudio.c | 92 ++++++++++++------------------ sound/pci/echoaudio/echoaudio_3g.c | 6 +- sound/pci/echoaudio/gina24_dsp.c | 3 +- sound/pci/echoaudio/layla24_dsp.c | 6 +- sound/pci/echoaudio/midi.c | 41 ++++++------- sound/pci/echoaudio/mona_dsp.c | 3 +- 6 files changed, 62 insertions(+), 89 deletions(-) diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 4cfe8ad970698b..f2c8602a1ad7d6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -531,22 +531,21 @@ static int init_engine(struct snd_pcm_substream *substream, /* Sets up che hardware. If it's already initialized, reset and * redo with the new parameters */ - spin_lock_irq(&chip->lock); - if (pipe->index >= 0) { - dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index); - err = free_pipes(chip, pipe); - snd_BUG_ON(err); - chip->substream[pipe->index] = NULL; - } + scoped_guard(spinlock_irq, &chip->lock) { + if (pipe->index >= 0) { + dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index); + err = free_pipes(chip, pipe); + snd_BUG_ON(err); + chip->substream[pipe->index] = NULL; + } - err = allocate_pipes(chip, pipe, pipe_index, interleave); - if (err < 0) { - spin_unlock_irq(&chip->lock); - dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n", - pipe_index, err); - return err; + err = allocate_pipes(chip, pipe, pipe_index, interleave); + if (err < 0) { + dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n", + pipe_index, err); + return err; + } } - spin_unlock_irq(&chip->lock); dev_dbg(chip->card->dev, "allocate_pipes()=%d\n", pipe_index); dev_dbg(chip->card->dev, @@ -594,9 +593,8 @@ static int init_engine(struct snd_pcm_substream *substream, smp_wmb(); chip->substream[pipe_index] = substream; chip->rate_set = 1; - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den); - spin_unlock_irq(&chip->lock); return 0; } @@ -658,14 +656,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) chip = snd_pcm_substream_chip(substream); pipe = (struct audiopipe *) substream->runtime->private_data; - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); if (pipe->index >= 0) { dev_dbg(chip->card->dev, "pcm_hw_free(%d)\n", pipe->index); free_pipes(chip, pipe); chip->substream[pipe->index] = NULL; pipe->index = -1; } - spin_unlock_irq(&chip->lock); return 0; } @@ -715,15 +712,12 @@ static int pcm_prepare(struct snd_pcm_substream *substream) * exclusive control */ - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); - if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index))) { - spin_unlock_irq(&chip->lock); + if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index))) return -EINVAL; - } set_audio_format(chip, pipe_index, &format); - spin_unlock_irq(&chip->lock); return 0; } @@ -747,7 +741,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) } } - spin_lock(&chip->lock); + guard(spinlock)(&chip->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_START: @@ -795,7 +789,6 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) default: err = -EINVAL; } - spin_unlock(&chip->lock); return err; } @@ -1012,7 +1005,7 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, changed = 0; chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); for (c = 0; c < num_busses_out(chip); c++) { gain = ucontrol->value.integer.value[c]; /* Ignore out of range values */ @@ -1025,7 +1018,6 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, } if (changed) update_output_line_level(chip); - spin_unlock_irq(&chip->lock); return changed; } @@ -1093,7 +1085,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, changed = 0; chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); for (c = 0; c < num_analog_busses_in(chip); c++) { gain = ucontrol->value.integer.value[c]; /* Ignore out of range values */ @@ -1106,7 +1098,6 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, } if (changed) update_input_line_level(chip); - spin_unlock_irq(&chip->lock); return changed; } @@ -1162,7 +1153,7 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol, changed = 0; chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); for (c = 0; c < num_analog_busses_out(chip); c++) { if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) { set_nominal_level(chip, c, @@ -1172,7 +1163,6 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol, } if (changed) update_output_line_level(chip); - spin_unlock_irq(&chip->lock); return changed; } @@ -1225,7 +1215,7 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol, changed = 0; chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); for (c = 0; c < num_analog_busses_in(chip); c++) { if (chip->nominal_level[bx_analog_in(chip) + c] != ucontrol->value.integer.value[c]) { @@ -1238,7 +1228,6 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol, update_output_line_level(chip); /* "Output" is not a mistake * here. */ - spin_unlock_irq(&chip->lock); return changed; } @@ -1298,10 +1287,9 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) return -EINVAL; if (chip->monitor_gain[out][in] != gain) { - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); set_monitor_gain(chip, out, in, gain); update_output_line_level(chip); - spin_unlock_irq(&chip->lock); changed = 1; } return changed; @@ -1361,10 +1349,9 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) return -EINVAL; if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) { - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]); update_vmixer_level(chip); - spin_unlock_irq(&chip->lock); changed = 1; } return changed; @@ -1500,9 +1487,8 @@ static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol, chip = snd_kcontrol_chip(kcontrol); mode = !!ucontrol->value.enumerated.item[0]; if (mode != chip->professional_spdif) { - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); set_professional_spdif(chip, mode); - spin_unlock_irq(&chip->lock); return 1; } return 0; @@ -1567,11 +1553,10 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, dclock = chip->clock_source_list[eclock]; if (chip->input_clock != dclock) { guard(mutex)(&chip->mode_mutex); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); changed = set_input_clock(chip, dclock); if (!changed) changed = 1; /* no errors */ - spin_unlock_irq(&chip->lock); } if (changed < 0) @@ -1615,9 +1600,8 @@ static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol, power = !!ucontrol->value.integer.value[0]; if (chip->phantom_power != power) { - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); changed = set_phantom_power(chip, power); - spin_unlock_irq(&chip->lock); if (changed == 0) changed = 1; /* no errors */ } @@ -1658,9 +1642,8 @@ static int snd_echo_automute_put(struct snd_kcontrol *kcontrol, automute = !!ucontrol->value.integer.value[0]; if (chip->digital_in_automute != automute) { - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); changed = set_input_auto_mute(chip, automute); - spin_unlock_irq(&chip->lock); if (changed == 0) changed = 1; /* no errors */ } @@ -1688,9 +1671,8 @@ static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, struct echoaudio *chip; chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); set_meters_on(chip, ucontrol->value.integer.value[0]); - spin_unlock_irq(&chip->lock); return 1; } @@ -2135,17 +2117,13 @@ static int snd_echo_suspend(struct device *dev) if (chip->midi_out) snd_echo_midi_output_trigger(chip->midi_out, 0); #endif - spin_lock_irq(&chip->lock); - if (wait_handshake(chip)) { - spin_unlock_irq(&chip->lock); - return -EIO; - } - clear_handshake(chip); - if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) { - spin_unlock_irq(&chip->lock); - return -EIO; + scoped_guard(spinlock_irq, &chip->lock) { + if (wait_handshake(chip)) + return -EIO; + clear_handshake(chip); + if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) + return -EIO; } - spin_unlock_irq(&chip->lock); chip->dsp_code = NULL; free_irq(chip->irq, chip); diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index 18b4d4b4d38df0..c9ee98ea3c71f6 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c @@ -119,7 +119,7 @@ static int set_digital_mode(struct echoaudio *chip, u8 mode) * updated by the DSP comm object. */ if (err >= 0 && previous_mode != mode && (previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) { - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); for (o = 0; o < num_busses_out(chip); o++) for (i = 0; i < num_busses_in(chip); i++) set_monitor_gain(chip, o, i, @@ -134,7 +134,6 @@ static int set_digital_mode(struct echoaudio *chip, u8 mode) for (o = 0; o < num_busses_out(chip); o++) set_output_gain(chip, o, chip->output_gain[o]); update_output_line_level(chip); - spin_unlock_irq(&chip->lock); } return err; @@ -396,7 +395,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) return -EINVAL; } - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); if (incompatible_clock) { chip->sample_rate = 48000; @@ -422,7 +421,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) } err = write_control_reg(chip, control_reg, get_frq_reg(chip), 1); - spin_unlock_irq(&chip->lock); if (err < 0) return err; chip->digital_mode = mode; diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 56e9d1b9b3309f..78fbac9f3eac68 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -305,7 +305,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) return -EINVAL; } - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); if (incompatible_clock) { /* Switch to 48KHz, internal */ chip->sample_rate = 48000; @@ -336,7 +336,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) } err = write_control_reg(chip, control_reg, true); - spin_unlock_irq(&chip->lock); if (err < 0) return err; chip->digital_mode = mode; diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index ef27805d63f6d1..decfccb1e803d6 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -358,16 +358,15 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) if (incompatible_clock) { /* Switch to 48KHz, internal */ chip->sample_rate = 48000; - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); set_input_clock(chip, ECHO_CLOCK_INTERNAL); - spin_unlock_irq(&chip->lock); } /* switch_asic() can sleep */ if (switch_asic(chip, asic) < 0) return -EIO; - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); /* Tweak the control register */ control_reg = le32_to_cpu(chip->comm_page->control_register); @@ -387,7 +386,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) } err = write_control_reg(chip, control_reg, true); - spin_unlock_irq(&chip->lock); if (err < 0) return err; chip->digital_mode = mode; diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 4ee230794b4eed..dd5212644844a0 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -167,9 +167,8 @@ static void snd_echo_midi_input_trigger(struct snd_rawmidi_substream *substream, struct echoaudio *chip = substream->rmidi->private_data; if (up != chip->midi_input_enabled) { - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); enable_midi_input(chip, up); - spin_unlock_irq(&chip->lock); chip->midi_input_enabled = up; } } @@ -201,14 +200,13 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream) static void snd_echo_midi_output_write(struct timer_list *t) { struct echoaudio *chip = timer_container_of(chip, t, timer); - unsigned long flags; int bytes, sent, time; unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1]; /* No interrupts are involved: we have to check at regular intervals if the card's output buffer has room for new data. */ sent = 0; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); chip->midi_full = 0; if (!snd_rawmidi_transmit_empty(chip->midi_out)) { bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf, @@ -242,7 +240,6 @@ static void snd_echo_midi_output_write(struct timer_list *t) dev_dbg(chip->card->dev, "Timer armed(%d)\n", ((time * HZ + 999) / 1000)); } - spin_unlock_irqrestore(&chip->lock, flags); } @@ -251,25 +248,29 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream int up) { struct echoaudio *chip = substream->rmidi->private_data; + bool remove_timer = false; dev_dbg(chip->card->dev, "snd_echo_midi_output_trigger(%d)\n", up); - spin_lock_irq(&chip->lock); - if (up) { - if (!chip->tinuse) { - timer_setup(&chip->timer, snd_echo_midi_output_write, - 0); - chip->tinuse = 1; - } - } else { - if (chip->tinuse) { - chip->tinuse = 0; - spin_unlock_irq(&chip->lock); - timer_delete_sync(&chip->timer); - dev_dbg(chip->card->dev, "Timer removed\n"); - return; + scoped_guard(spinlock_irq, &chip->lock) { + if (up) { + if (!chip->tinuse) { + timer_setup(&chip->timer, snd_echo_midi_output_write, + 0); + chip->tinuse = 1; + } + } else { + if (chip->tinuse) { + chip->tinuse = 0; + remove_timer = true; + } } } - spin_unlock_irq(&chip->lock); + + if (remove_timer) { + timer_delete_sync(&chip->timer); + dev_dbg(chip->card->dev, "Timer removed\n"); + return; + } if (up && !chip->midi_full) snd_echo_midi_output_write(&chip->timer); diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index f8e7bb6ce04011..9bb6a174745c07 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -381,7 +381,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) return -EINVAL; } - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); if (incompatible_clock) { /* Switch to 48KHz, internal */ chip->sample_rate = 48000; @@ -413,7 +413,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) } err = write_control_reg(chip, control_reg, false); - spin_unlock_irq(&chip->lock); if (err < 0) return err; chip->digital_mode = mode; From f44f745f753d55c2f4134b2e53996fdcc5cc7620 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:01 +0200 Subject: [PATCH 0936/1292] ALSA: emu10k1: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-27-tiwai@suse.de --- sound/pci/emu10k1/emufx.c | 35 +++++++++++++++-------------------- sound/pci/emu10k1/memory.c | 20 +++++--------------- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 7db0660e6b61f4..aaf488978b1812 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1026,12 +1026,12 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_code *icode, bool in_kernel) { - int err = 0; + int err; - mutex_lock(&emu->fx8010.lock); + guard(mutex)(&emu->fx8010.lock); err = snd_emu10k1_verify_controls(emu, icode, in_kernel); if (err < 0) - goto __error; + return err; strscpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); /* stop FX processor - this may be dangerous, but it's better to miss some samples than generate wrong ones - [jk] */ @@ -1042,27 +1042,25 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu, /* ok, do the main job */ err = snd_emu10k1_del_controls(emu, icode, in_kernel); if (err < 0) - goto __error; + return err; err = snd_emu10k1_gpr_poke(emu, icode, in_kernel); if (err < 0) - goto __error; + return err; err = snd_emu10k1_tram_poke(emu, icode, in_kernel); if (err < 0) - goto __error; + return err; err = snd_emu10k1_code_poke(emu, icode, in_kernel); if (err < 0) - goto __error; + return err; err = snd_emu10k1_add_controls(emu, icode, in_kernel); if (err < 0) - goto __error; + return err; /* start FX processor when the DSP code is updated */ if (emu->audigy) snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg); - __error: - mutex_unlock(&emu->fx8010.lock); - return err; + return 0; } static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu, @@ -1070,7 +1068,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu, { int err; - mutex_lock(&emu->fx8010.lock); + guard(mutex)(&emu->fx8010.lock); strscpy(icode->name, emu->fx8010.name, sizeof(icode->name)); /* ok, do the main job */ err = snd_emu10k1_gpr_peek(emu, icode); @@ -1080,7 +1078,6 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu, err = snd_emu10k1_code_peek(emu, icode); if (err >= 0) err = snd_emu10k1_list_controls(emu, icode); - mutex_unlock(&emu->fx8010.lock); return err; } @@ -1098,7 +1095,7 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu, if (ipcm->channels > 32) return -EINVAL; pcm = &emu->fx8010.pcm[ipcm->substream]; - mutex_lock(&emu->fx8010.lock); + guard(mutex)(&emu->fx8010.lock); spin_lock_irq(&emu->reg_lock); if (pcm->opened) { err = -EBUSY; @@ -1128,7 +1125,6 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu, } __error: spin_unlock_irq(&emu->reg_lock); - mutex_unlock(&emu->fx8010.lock); return err; } @@ -1144,7 +1140,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, ipcm->substream = array_index_nospec(ipcm->substream, EMU10K1_FX8010_PCM_COUNT); pcm = &emu->fx8010.pcm[ipcm->substream]; - mutex_lock(&emu->fx8010.lock); + guard(mutex)(&emu->fx8010.lock); spin_lock_irq(&emu->reg_lock); ipcm->channels = pcm->channels; ipcm->tram_start = pcm->tram_start; @@ -1160,7 +1156,6 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, ipcm->res1 = ipcm->res2 = 0; ipcm->pad = 0; spin_unlock_irq(&emu->reg_lock); - mutex_unlock(&emu->fx8010.lock); return err; } @@ -2547,9 +2542,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un return -EPERM; if (get_user(addr, (unsigned int __user *)argp)) return -EFAULT; - mutex_lock(&emu->fx8010.lock); - res = snd_emu10k1_fx8010_tram_setup(emu, addr); - mutex_unlock(&emu->fx8010.lock); + scoped_guard(mutex, &emu->fx8010.lock) { + res = snd_emu10k1_fx8010_tram_setup(emu, addr); + } return res; case SNDRV_EMU10K1_IOCTL_STOP: if (!capable(CAP_SYS_ADMIN)) diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index f6982bc6ff0d0e..3bccba48f82c11 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -315,12 +315,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (snd_BUG_ON(!hdr)) return NULL; - mutex_lock(&hdr->block_mutex); + guard(mutex)(&hdr->block_mutex); blk = search_empty(emu, runtime->dma_bytes); - if (blk == NULL) { - mutex_unlock(&hdr->block_mutex); + if (blk == NULL) return NULL; - } /* fill buffer addresses but pointers are not stored so that * snd_free_pci_page() is not called in synth_free() */ @@ -335,7 +333,6 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (! is_valid_page(emu, addr)) { dev_err_ratelimited(emu->card->dev, "emu: failure page = %d\n", idx); - mutex_unlock(&hdr->block_mutex); return NULL; } emu->page_addr_table[page] = addr; @@ -347,10 +344,8 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst err = snd_emu10k1_memblk_map(emu, blk); if (err < 0) { __snd_util_mem_free(hdr, (struct snd_util_memblk *)blk); - mutex_unlock(&hdr->block_mutex); return NULL; } - mutex_unlock(&hdr->block_mutex); return (struct snd_util_memblk *)blk; } @@ -407,19 +402,15 @@ snd_emu10k1_synth_alloc(struct snd_emu10k1 *hw, unsigned int size) struct snd_emu10k1_memblk *blk; struct snd_util_memhdr *hdr = hw->memhdr; - mutex_lock(&hdr->block_mutex); + guard(mutex)(&hdr->block_mutex); blk = (struct snd_emu10k1_memblk *)__snd_util_mem_alloc(hdr, size); - if (blk == NULL) { - mutex_unlock(&hdr->block_mutex); + if (blk == NULL) return NULL; - } if (synth_alloc_pages(hw, blk)) { __snd_util_mem_free(hdr, (struct snd_util_memblk *)blk); - mutex_unlock(&hdr->block_mutex); return NULL; } snd_emu10k1_memblk_map(hw, blk); - mutex_unlock(&hdr->block_mutex); return (struct snd_util_memblk *)blk; } @@ -435,14 +426,13 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk) struct snd_emu10k1_memblk *blk = (struct snd_emu10k1_memblk *)memblk; unsigned long flags; - mutex_lock(&hdr->block_mutex); + guard(mutex)(&hdr->block_mutex); spin_lock_irqsave(&emu->memblk_lock, flags); if (blk->mapped_page >= 0) unmap_memblk(emu, blk); spin_unlock_irqrestore(&emu->memblk_lock, flags); synth_free_pages(emu, blk); __snd_util_mem_free(hdr, memblk); - mutex_unlock(&hdr->block_mutex); return 0; } From 7c4a379e0622e7d8e7eb7dbc76445cdd6306aad8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:02 +0200 Subject: [PATCH 0937/1292] ALSA: emu10k1: Use guard() for emu1010 FPGA locking The snd_emu1010_fpga_lock() and _unlock() call pairs can be simplified gracefully with the introduction of guard(). Only code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-28-tiwai@suse.de --- include/sound/emu10k1.h | 3 +-- sound/pci/emu10k1/emu10k1_main.c | 15 +++++---------- sound/pci/emu10k1/emumixer.c | 15 ++++++--------- sound/pci/emu10k1/emuproc.c | 8 ++------ sound/pci/emu10k1/io.c | 3 +-- 5 files changed, 15 insertions(+), 29 deletions(-) diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 38db50b280eba5..4f94565c9d15af 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1842,8 +1842,7 @@ unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data); int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data); int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value); -static inline void snd_emu1010_fpga_lock(struct snd_emu10k1 *emu) { mutex_lock(&emu->emu1010.lock); }; -static inline void snd_emu1010_fpga_unlock(struct snd_emu10k1 *emu) { mutex_unlock(&emu->emu1010.lock); }; +DEFINE_GUARD(snd_emu1010_fpga_lock, struct snd_emu10k1 *, mutex_lock(&(_T)->emu1010.lock), mutex_unlock(&(_T)->emu1010.lock)) void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value); void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value); void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value); diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index bbe252b8916cd9..a3d028e4a212ba 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -768,7 +768,7 @@ static void emu1010_work(struct work_struct *work) return; #endif - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts); @@ -779,8 +779,6 @@ static void emu1010_work(struct work_struct *work) if (sts & EMU_HANA_IRQ_WCLK_CHANGED) emu1010_clock_event(emu); - - snd_emu1010_fpga_unlock(emu); } static void emu1010_interrupt(struct snd_emu10k1 *emu) @@ -814,13 +812,13 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) * Proper init follows in snd_emu10k1_init(). */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); dev_info(emu->card->dev, "emu1010: Loading Hana Firmware\n"); err = snd_emu1010_load_firmware(emu, 0, &emu->firmware); if (err < 0) { dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n"); - goto fail; + return err; } /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ @@ -830,8 +828,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) dev_info(emu->card->dev, "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg); - err = -ENODEV; - goto fail; + return -ENODEV; } dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n"); @@ -891,9 +888,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) // so it is safe to simply enable the outputs. snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); -fail: - snd_emu1010_fpga_unlock(emu); - return err; + return 0; } /* * Create the EMU10K1 instance diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index d665d5d1ad7c67..6d86584be75010 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -662,9 +662,8 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.output_source[channel] != val); if (change) { emu->emu1010.output_source[channel] = val; - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); snd_emu1010_output_source_apply(emu, channel, val); - snd_emu1010_fpga_unlock(emu); } return change; } @@ -708,9 +707,8 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.input_source[channel] != val); if (change) { emu->emu1010.input_source[channel] = val; - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); snd_emu1010_input_source_apply(emu, channel, val); - snd_emu1010_fpga_unlock(emu); } return change; } @@ -985,7 +983,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, val = ucontrol->value.enumerated.item[0] ; if (val >= emu_ci->num) return -EINVAL; - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); spin_lock_irq(&emu->reg_lock); change = (emu->emu1010.clock_source != val); if (change) { @@ -1002,7 +1000,6 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, } else { spin_unlock_irq(&emu->reg_lock); } - snd_emu1010_fpga_unlock(emu); return change; } @@ -2330,9 +2327,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, for (i = 0; i < emu_ri->n_outs; i++) emu->emu1010.output_source[i] = emu1010_map_source(emu_ri, emu_ri->out_dflts[i]); - snd_emu1010_fpga_lock(emu); - snd_emu1010_apply_sources(emu); - snd_emu1010_fpga_unlock(emu); + scoped_guard(snd_emu1010_fpga_lock, emu) { + snd_emu1010_apply_sources(emu); + } kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu); err = snd_ctl_add(card, kctl); diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index bd4734dc04cdc3..a12518dd4eed9b 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -166,7 +166,7 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, u32 value2; if (emu->card_capabilities->emu_model) { - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); // This represents the S/PDIF lock status on 0404b, which is // kinda weird and unhelpful, because monitoring it via IRQ is @@ -200,8 +200,6 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n", value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer", value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : ""); - - snd_emu1010_fpga_unlock(emu); } else { snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); @@ -464,7 +462,7 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, u32 value; int i; - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); snd_iprintf(buffer, "EMU1010 Registers:\n\n"); @@ -504,8 +502,6 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, snd_emu_proc_emu1010_link_read(emu, buffer, 0x701); } } - - snd_emu1010_fpga_unlock(emu); } static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index b60ab5671e00dc..69debe781177a8 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -297,9 +297,8 @@ void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value) { - snd_emu1010_fpga_lock(emu); + guard(snd_emu1010_fpga_lock)(emu); snd_emu1010_fpga_write_locked(emu, reg, value); - snd_emu1010_fpga_unlock(emu); } void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) From 3a0c3159f7fc4664aeb3a243bb245b3092b2420a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:03 +0200 Subject: [PATCH 0938/1292] ALSA: emu10k1: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-29-tiwai@suse.de --- sound/pci/emu10k1/emu10k1_main.c | 12 +- sound/pci/emu10k1/emu10k1_synth.c | 11 +- sound/pci/emu10k1/emufx.c | 46 +++----- sound/pci/emu10k1/emumixer.c | 56 ++++------ sound/pci/emu10k1/emumpu401.c | 175 +++++++++++++----------------- sound/pci/emu10k1/emupcm.c | 58 ++++------ sound/pci/emu10k1/emuproc.c | 11 +- sound/pci/emu10k1/io.c | 120 ++++++-------------- sound/pci/emu10k1/memory.c | 14 +-- sound/pci/emu10k1/p16v.c | 8 +- sound/pci/emu10k1/voice.c | 8 +- 11 files changed, 193 insertions(+), 326 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a3d028e4a212ba..b2fe2d164ba88f 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -745,12 +745,12 @@ static void emu1010_clock_event(struct snd_emu10k1 *emu) { struct snd_ctl_elem_id id; - spin_lock_irq(&emu->reg_lock); - // This is the only thing that can actually happen. - emu->emu1010.clock_source = emu->emu1010.clock_fallback; - emu->emu1010.wclock = 1 - emu->emu1010.clock_source; - snd_emu1010_update_clock(emu); - spin_unlock_irq(&emu->reg_lock); + scoped_guard(spinlock_irq, &emu->reg_lock) { + // This is the only thing that can actually happen. + emu->emu1010.clock_source = emu->emu1010.clock_fallback; + emu->emu1010.wclock = 1 - emu->emu1010.clock_source; + snd_emu1010_update_clock(emu); + } snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0); snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id); } diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 68dfcb24b88926..662d20eb968928 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c @@ -55,10 +55,9 @@ static int snd_emu10k1_synth_probe(struct device *_dev) return -ENOMEM; } - spin_lock_irq(&hw->voice_lock); + guard(spinlock_irq)(&hw->voice_lock); hw->synth = emux; hw->get_synth_voice = snd_emu10k1_synth_get_voice; - spin_unlock_irq(&hw->voice_lock); dev->driver_data = emux; @@ -77,10 +76,10 @@ static int snd_emu10k1_synth_remove(struct device *_dev) emux = dev->driver_data; hw = emux->hw; - spin_lock_irq(&hw->voice_lock); - hw->synth = NULL; - hw->get_synth_voice = NULL; - spin_unlock_irq(&hw->voice_lock); + scoped_guard(spinlock_irq, &hw->voice_lock) { + hw->synth = NULL; + hw->get_synth_voice = NULL; + } snd_emux_free(emux); return 0; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index aaf488978b1812..37af7bf7634751 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -440,13 +440,11 @@ int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu, void *private_data, struct snd_emu10k1_fx8010_irq *irq) { - unsigned long flags; - irq->handler = handler; irq->gpr_running = gpr_running; irq->private_data = private_data; irq->next = NULL; - spin_lock_irqsave(&emu->fx8010.irq_lock, flags); + guard(spinlock_irqsave)(&emu->fx8010.irq_lock); if (emu->fx8010.irq_handlers == NULL) { emu->fx8010.irq_handlers = irq; emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt; @@ -455,7 +453,6 @@ int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu, irq->next = emu->fx8010.irq_handlers; emu->fx8010.irq_handlers = irq; } - spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); return 0; } @@ -463,9 +460,8 @@ int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_irq *irq) { struct snd_emu10k1_fx8010_irq *tmp; - unsigned long flags; - spin_lock_irqsave(&emu->fx8010.irq_lock, flags); + guard(spinlock_irqsave)(&emu->fx8010.irq_lock); tmp = emu->fx8010.irq_handlers; if (tmp == irq) { emu->fx8010.irq_handlers = tmp->next; @@ -479,7 +475,6 @@ int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu, if (tmp) tmp->next = tmp->next->next; } - spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); return 0; } @@ -1085,7 +1080,6 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_pcm_rec *ipcm) { unsigned int i; - int err = 0; struct snd_emu10k1_fx8010_pcm *pcm; if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT) @@ -1096,19 +1090,15 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu, return -EINVAL; pcm = &emu->fx8010.pcm[ipcm->substream]; guard(mutex)(&emu->fx8010.lock); - spin_lock_irq(&emu->reg_lock); - if (pcm->opened) { - err = -EBUSY; - goto __error; - } + guard(spinlock_irq)(&emu->reg_lock); + if (pcm->opened) + return -EBUSY; if (ipcm->channels == 0) { /* remove */ pcm->valid = 0; } else { /* FIXME: we need to add universal code to the PCM transfer routine */ - if (ipcm->channels != 2) { - err = -EINVAL; - goto __error; - } + if (ipcm->channels != 2) + return -EINVAL; pcm->valid = 1; pcm->opened = 0; pcm->channels = ipcm->channels; @@ -1123,16 +1113,13 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu, for (i = 0; i < pcm->channels; i++) pcm->etram[i] = ipcm->etram[i]; } - __error: - spin_unlock_irq(&emu->reg_lock); - return err; + return 0; } static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_pcm_rec *ipcm) { unsigned int i; - int err = 0; struct snd_emu10k1_fx8010_pcm *pcm; if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT) @@ -1141,7 +1128,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, EMU10K1_FX8010_PCM_COUNT); pcm = &emu->fx8010.pcm[ipcm->substream]; guard(mutex)(&emu->fx8010.lock); - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); ipcm->channels = pcm->channels; ipcm->tram_start = pcm->tram_start; ipcm->buffer_size = pcm->buffer_size; @@ -1155,8 +1142,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, ipcm->etram[i] = pcm->etram[i]; ipcm->res1 = ipcm->res2 = 0; ipcm->pad = 0; - spin_unlock_irq(&emu->reg_lock); - return err; + return 0; } #define SND_EMU10K1_GPR_CONTROLS 44 @@ -2410,9 +2396,9 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size) } if ((emu->fx8010.etram_pages.bytes / 2) == size) return 0; - spin_lock_irq(&emu->emu_lock); - outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG); - spin_unlock_irq(&emu->emu_lock); + scoped_guard(spinlock_irq, &emu->emu_lock) { + outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG); + } snd_emu10k1_ptr_write(emu, TCB, 0, 0); snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K); if (emu->fx8010.etram_pages.area != NULL) { @@ -2428,9 +2414,9 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size) memset(emu->fx8010.etram_pages.area, 0, size * 2); snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr); snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg); - spin_lock_irq(&emu->emu_lock); - outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); - spin_unlock_irq(&emu->emu_lock); + scoped_guard(spinlock_irq, &emu->emu_lock) { + outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); + } } return 0; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 6d86584be75010..f4906ab30c023e 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -978,29 +978,25 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, const struct snd_emu1010_clock_info *emu_ci = &emu1010_clock_info[emu1010_idx(emu)]; unsigned int val; - int change = 0; val = ucontrol->value.enumerated.item[0] ; if (val >= emu_ci->num) return -EINVAL; guard(snd_emu1010_fpga_lock)(emu); - spin_lock_irq(&emu->reg_lock); - change = (emu->emu1010.clock_source != val); - if (change) { + scoped_guard(spinlock_irq, &emu->reg_lock) { + if (emu->emu1010.clock_source == val) + return 0; emu->emu1010.clock_source = val; emu->emu1010.wclock = emu_ci->vals[val]; snd_emu1010_update_clock(emu); snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE); snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock); - spin_unlock_irq(&emu->reg_lock); - - msleep(10); // Allow DLL to settle - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - } else { - spin_unlock_irq(&emu->reg_lock); } - return change; + + msleep(10); // Allow DLL to settle + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + return 1; } static const struct snd_kcontrol_new snd_emu1010_clock_source = @@ -1208,13 +1204,13 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, change = (emu->i2c_capture_source != source_id); if (change) { snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - spin_lock_irq(&emu->emu_lock); - gpio = inw(emu->port + A_IOCFG); - if (source_id==0) - outw(gpio | 0x4, emu->port + A_IOCFG); - else - outw(gpio & ~0x4, emu->port + A_IOCFG); - spin_unlock_irq(&emu->emu_lock); + scoped_guard(spinlock_irq, &emu->emu_lock) { + gpio = inw(emu->port + A_IOCFG); + if (source_id == 0) + outw(gpio | 0x4, emu->port + A_IOCFG); + else + outw(gpio & ~0x4, emu->port + A_IOCFG); + } ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ @@ -1375,14 +1371,13 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, } - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp = reg & ~A_SPDIF_RATE_MASK; tmp |= val; change = (tmp != reg); if (change) snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1506,7 +1501,7 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); for (voice = 0; voice < 3; voice++) for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; @@ -1526,7 +1521,6 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, &mix->send_routing[0][0]); } } - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1574,7 +1568,7 @@ static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, int change = 0, idx, val; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); for (idx = 0; idx < 3*num_efx; idx++) { val = ucontrol->value.integer.value[idx] & 255; if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { @@ -1593,7 +1587,6 @@ static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, &mix->send_volume[0][0]); } } - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1638,7 +1631,7 @@ static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int change = 0, idx, val; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); for (idx = 0; idx < 3; idx++) { unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff; val = uval * 0x8000U / 0xffffU; @@ -1655,7 +1648,6 @@ static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); } } - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1708,7 +1700,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[idx] & mask; if (mix->send_routing[0][idx] != val) { @@ -1723,7 +1715,6 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, &mix->send_routing[0][0]); } } - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1771,7 +1762,7 @@ static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, int change = 0, idx, val; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[idx] & 255; if (mix->send_volume[0][idx] != val) { @@ -1785,7 +1776,6 @@ static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, &mix->send_volume[0][0]); } } - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1830,7 +1820,7 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, int change = 0, val; unsigned uval; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); uval = ucontrol->value.integer.value[0] & 0x1ffff; val = uval * 0x8000U / 0xffffU; if (mix->attn[0] != val) { @@ -1842,7 +1832,6 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); } } - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1885,7 +1874,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, sw = ucontrol->value.integer.value[0]; if (emu->card_capabilities->invert_shared_spdif) sw = !sw; - spin_lock_irq(&emu->emu_lock); + guard(spinlock_irq)(&emu->emu_lock); if ( emu->card_capabilities->i2c_adc) { /* Do nothing for Audigy 2 ZS Notebook */ } else if (emu->audigy) { @@ -1906,7 +1895,6 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, reg |= val; outl(reg | val, emu->port + HCFG); } - spin_unlock_irq(&emu->emu_lock); return change; } diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index efff19bbc0e9cd..c102a3599225a4 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -68,28 +68,28 @@ static void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k return; } - spin_lock(&midi->input_lock); - if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { - if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { - mpu401_clear_rx(emu, midi); - } else { - byte = mpu401_read_data(emu, midi); - if (midi->substream_input) - snd_rawmidi_receive(midi->substream_input, &byte, 1); + scoped_guard(spinlock, &midi->input_lock) { + if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { + if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { + mpu401_clear_rx(emu, midi); + } else { + byte = mpu401_read_data(emu, midi); + if (midi->substream_input) + snd_rawmidi_receive(midi->substream_input, &byte, 1); + } } } - spin_unlock(&midi->input_lock); - spin_lock(&midi->output_lock); - if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { - if (midi->substream_output && - snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { - mpu401_write_data(emu, midi, byte); - } else { - snd_emu10k1_intr_disable(emu, midi->tx_enable); + scoped_guard(spinlock, &midi->output_lock) { + if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { + if (midi->substream_output && + snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { + mpu401_write_data(emu, midi, byte); + } else { + snd_emu10k1_intr_disable(emu, midi->tx_enable); + } } } - spin_unlock(&midi->output_lock); } static void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status) @@ -106,26 +106,26 @@ static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_mid { int timeout, ok; - spin_lock_irq(&midi->input_lock); - mpu401_write_data(emu, midi, 0x00); - /* mpu401_clear_rx(emu, midi); */ - - mpu401_write_cmd(emu, midi, cmd); - if (ack) { - ok = 0; - timeout = 10000; - while (!ok && timeout-- > 0) { - if (mpu401_input_avail(emu, midi)) { - if (mpu401_read_data(emu, midi) == MPU401_ACK) - ok = 1; + scoped_guard(spinlock_irq, &midi->input_lock) { + mpu401_write_data(emu, midi, 0x00); + /* mpu401_clear_rx(emu, midi); */ + + mpu401_write_cmd(emu, midi, cmd); + if (ack) { + ok = 0; + timeout = 10000; + while (!ok && timeout-- > 0) { + if (mpu401_input_avail(emu, midi)) { + if (mpu401_read_data(emu, midi) == MPU401_ACK) + ok = 1; + } } - } - if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) + if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) + ok = 1; + } else { ok = 1; - } else { - ok = 1; + } } - spin_unlock_irq(&midi->input_lock); if (!ok) { dev_err(emu->card->dev, "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", @@ -145,22 +145,17 @@ static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream) emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irq(&midi->open_lock); - midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT; - midi->substream_input = substream; - if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { - spin_unlock_irq(&midi->open_lock); - if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) - goto error_out; - if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) - goto error_out; - } else { - spin_unlock_irq(&midi->open_lock); + scoped_guard(spinlock_irq, &midi->open_lock) { + midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT; + midi->substream_input = substream; + if (midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) + return 0; } + if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) + return -EIO; + if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) + return -EIO; return 0; - -error_out: - return -EIO; } static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream) @@ -171,66 +166,53 @@ static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream) emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irq(&midi->open_lock); - midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT; - midi->substream_output = substream; - if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { - spin_unlock_irq(&midi->open_lock); - if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) - goto error_out; - if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) - goto error_out; - } else { - spin_unlock_irq(&midi->open_lock); + scoped_guard(spinlock_irq, &midi->open_lock) { + midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT; + midi->substream_output = substream; + if (midi->midi_mode & EMU10K1_MIDI_MODE_INPUT) + return 0; } + if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) + return -EIO; + if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) + return -EIO; return 0; - -error_out: - return -EIO; } static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irq(&midi->open_lock); - snd_emu10k1_intr_disable(emu, midi->rx_enable); - midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT; - midi->substream_input = NULL; - if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { - spin_unlock_irq(&midi->open_lock); - err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); - } else { - spin_unlock_irq(&midi->open_lock); + scoped_guard(spinlock_irq, &midi->open_lock) { + snd_emu10k1_intr_disable(emu, midi->rx_enable); + midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT; + midi->substream_input = NULL; + if (midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) + return 0; } - return err; + return snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irq(&midi->open_lock); - snd_emu10k1_intr_disable(emu, midi->tx_enable); - midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; - midi->substream_output = NULL; - if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { - spin_unlock_irq(&midi->open_lock); - err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); - } else { - spin_unlock_irq(&midi->open_lock); + scoped_guard(spinlock_irq, &midi->open_lock) { + snd_emu10k1_intr_disable(emu, midi->tx_enable); + midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; + midi->substream_output = NULL; + if (midi->midi_mode & EMU10K1_MIDI_MODE_INPUT) + return 0; } - return err; + return snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -261,22 +243,21 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr unsigned char byte; /* try to send some amount of bytes here before interrupts */ - spin_lock_irq(&midi->output_lock); - while (max > 0) { - if (mpu401_output_ready(emu, midi)) { - if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || - snd_rawmidi_transmit(substream, &byte, 1) != 1) { - /* no more data */ - spin_unlock_irq(&midi->output_lock); - return; + scoped_guard(spinlock_irq, &midi->output_lock) { + while (max > 0) { + if (mpu401_output_ready(emu, midi)) { + if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || + snd_rawmidi_transmit(substream, &byte, 1) != 1) { + /* no more data */ + return; + } + mpu401_write_data(emu, midi, byte); + max--; + } else { + break; } - mpu401_write_data(emu, midi, byte); - max--; - } else { - break; } } - spin_unlock_irq(&midi->output_lock); snd_emu10k1_intr_enable(emu, midi->tx_enable); } else { snd_emu10k1_intr_disable(emu, midi->tx_enable); diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 5414148057ea7f..071c75ba81fd7d 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -319,7 +319,7 @@ static void snd_emu10k1_pcm_init_voices(struct snd_emu10k1 *emu, unsigned int end_addr, struct snd_emu10k1_pcm_mixer *mix) { - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); snd_emu10k1_pcm_init_voice(emu, evoice, w_16, stereo, start_addr, end_addr, &mix->send_routing[stereo][0], @@ -329,7 +329,6 @@ static void snd_emu10k1_pcm_init_voices(struct snd_emu10k1 *emu, start_addr, end_addr, &mix->send_routing[2][0], &mix->send_volume[2][0]); - spin_unlock_irq(&emu->reg_lock); } static void snd_emu10k1_pcm_init_extra_voice(struct snd_emu10k1 *emu, @@ -726,14 +725,13 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, struct snd_emu10k1_pcm_mixer *mix; bool w_16 = snd_pcm_format_width(runtime->format) == 16; bool stereo = runtime->channels == 2; - int result = 0; /* dev_dbg(emu->card->dev, "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)) */ - spin_lock(&emu->reg_lock); + guard(spinlock)(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_emu10k1_playback_prepare_voices(emu, epcm, w_16, stereo, 1); @@ -755,11 +753,9 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, snd_emu10k1_playback_mute_voices(emu, epcm->voices[0], stereo); break; default: - result = -EINVAL; - break; + return -EINVAL; } - spin_unlock(&emu->reg_lock); - return result; + return 0; } static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, @@ -768,9 +764,8 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; - int result = 0; - spin_lock(&emu->reg_lock); + guard(spinlock)(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -829,10 +824,9 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, } break; default: - result = -EINVAL; + return -EINVAL; } - spin_unlock(&emu->reg_lock); - return result; + return 0; } static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *substream) @@ -923,7 +917,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, u64 mask; int result = 0; - spin_lock(&emu->reg_lock); + guard(spinlock)(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -950,7 +944,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, if (result == 0) { // The extra voice is allowed to lag a bit snd_emu10k1_playback_trigger_voice(emu, epcm->extra); - goto leave; + return 0; } snd_emu10k1_efx_playback_stop_voices( @@ -972,11 +966,8 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, epcm->resume_pos = snd_emu10k1_playback_pointer(substream); break; default: - result = -EINVAL; - break; + return -EINVAL; } -leave: - spin_unlock(&emu->reg_lock); return result; } @@ -1345,7 +1336,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) #endif runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; } else { - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); runtime->hw.channels_min = runtime->hw.channels_max = 0; for (idx = 0; idx < nefx; idx++) { if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { @@ -1355,7 +1346,6 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) } epcm->capture_cr_val = emu->efx_voices_mask[0]; epcm->capture_cr_val2 = emu->efx_voices_mask[1]; - spin_unlock_irq(&emu->reg_lock); } err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_efx_capture_channels); @@ -1539,12 +1529,11 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st if (bits == 9 || bits == 11 || bits == 13 || bits == 15 || bits > 16) return -EINVAL; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); change = (nval[0] != emu->efx_voices_mask[0]) || (nval[1] != emu->efx_voices_mask[1]); emu->efx_voices_mask[0] = nval[0]; emu->efx_voices_mask[1] = nval[1]; - spin_unlock_irq(&emu->reg_lock); return change; } @@ -1685,9 +1674,9 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; - int result = 0; + int result; - spin_lock(&emu->reg_lock); + guard(spinlock)(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* follow thru */ @@ -1707,7 +1696,7 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre #endif result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq); if (result < 0) - goto __err; + return result; snd_emu10k1_fx8010_playback_transfer(substream); /* roll the ball */ snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1); break; @@ -1720,12 +1709,9 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre pcm->tram_shift = 0; break; default: - result = -EINVAL; - break; + return -EINVAL; } - __err: - spin_unlock(&emu->reg_lock); - return result; + return 0; } static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(struct snd_pcm_substream *substream) @@ -1769,13 +1755,10 @@ static int snd_emu10k1_fx8010_playback_open(struct snd_pcm_substream *substream) runtime->hw = snd_emu10k1_fx8010_playback; runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels; runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2; - spin_lock_irq(&emu->reg_lock); - if (pcm->valid == 0) { - spin_unlock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); + if (pcm->valid == 0) return -ENODEV; - } pcm->opened = 1; - spin_unlock_irq(&emu->reg_lock); return 0; } @@ -1784,9 +1767,8 @@ static int snd_emu10k1_fx8010_playback_close(struct snd_pcm_substream *substream struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; - spin_lock_irq(&emu->reg_lock); + guard(spinlock_irq)(&emu->reg_lock); pcm->opened = 0; - spin_unlock_irq(&emu->reg_lock); return 0; } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index a12518dd4eed9b..f6186b5be04909 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -537,15 +537,13 @@ static unsigned int snd_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { - unsigned int regptr, val; + unsigned int regptr; regptr = (reg << 16) | chn; - spin_lock_irq(&emu->emu_lock); + guard(spinlock_irq)(&emu->emu_lock); outl(regptr, emu->port + iobase + PTR); - val = inl(emu->port + iobase + DATA); - spin_unlock_irq(&emu->emu_lock); - return val; + return inl(emu->port + iobase + DATA); } static void snd_ptr_write(struct snd_emu10k1 *emu, @@ -558,10 +556,9 @@ static void snd_ptr_write(struct snd_emu10k1 *emu, regptr = (reg << 16) | chn; - spin_lock_irq(&emu->emu_lock); + guard(spinlock_irq)(&emu->emu_lock); outl(regptr, emu->port + iobase + PTR); outl(data, emu->port + iobase + DATA); - spin_unlock_irq(&emu->emu_lock); } diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 69debe781177a8..9c897c3e8c2843 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -30,7 +30,6 @@ static inline bool check_ptr_reg(struct snd_emu10k1 *emu, unsigned int reg) unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { - unsigned long flags; unsigned int regptr, val; unsigned int mask; @@ -38,10 +37,10 @@ unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, un if (!check_ptr_reg(emu, regptr)) return 0; - spin_lock_irqsave(&emu->emu_lock, flags); - outl(regptr, emu->port + PTR); - val = inl(emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); + scoped_guard(spinlock_irqsave, &emu->emu_lock) { + outl(regptr, emu->port + PTR); + val = inl(emu->port + DATA); + } if (reg & 0xff000000) { unsigned char size, offset; @@ -61,13 +60,13 @@ EXPORT_SYMBOL(snd_emu10k1_ptr_read); void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data) { unsigned int regptr; - unsigned long flags; unsigned int mask; regptr = (reg << 16) | chn; if (!check_ptr_reg(emu, regptr)) return; + guard(spinlock_irqsave)(&emu->emu_lock); if (reg & 0xff000000) { unsigned char size, offset; @@ -79,15 +78,12 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i mask <<= offset; data <<= offset; - spin_lock_irqsave(&emu->emu_lock, flags); outl(regptr, emu->port + PTR); data |= inl(emu->port + DATA) & ~mask; } else { - spin_lock_irqsave(&emu->emu_lock, flags); outl(regptr, emu->port + PTR); } outl(data, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } EXPORT_SYMBOL(snd_emu10k1_ptr_write); @@ -96,7 +92,6 @@ void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, . { va_list va; u32 addr_mask; - unsigned long flags; if (snd_BUG_ON(!emu)) return; @@ -105,7 +100,7 @@ void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, . addr_mask = ~((emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK) >> 16); va_start(va, chn); - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); for (;;) { u32 data; u32 reg = va_arg(va, u32); @@ -117,7 +112,6 @@ void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, . outl((reg << 16) | chn, emu->port + PTR); outl(data, emu->port + DATA); } - spin_unlock_irqrestore(&emu->emu_lock, flags); va_end(va); } @@ -127,16 +121,13 @@ unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { - unsigned long flags; - unsigned int regptr, val; + unsigned int regptr; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(regptr, emu->port + PTR2); - val = inl(emu->port + DATA2); - spin_unlock_irqrestore(&emu->emu_lock, flags); - return val; + return inl(emu->port + DATA2); } void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, @@ -145,14 +136,12 @@ void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int data) { unsigned int regptr; - unsigned long flags; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(regptr, emu->port + PTR2); outl(data, emu->port + DATA2); - spin_unlock_irqrestore(&emu->emu_lock, flags); } int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, @@ -161,22 +150,19 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int reset, set; unsigned int reg, tmp; int n, result; - int err = 0; /* This function is not re-entrant, so protect against it. */ - spin_lock(&emu->spi_lock); + guard(spinlock)(&emu->spi_lock); if (emu->card_capabilities->ca0108_chip) reg = P17V_SPI; else { /* For other chip types the SPI register * is currently unknown. */ - err = 1; - goto spi_write_exit; + return 1; } if (data > 0xffff) { /* Only 16bit values allowed */ - err = 1; - goto spi_write_exit; + return 1; } tmp = snd_emu10k1_ptr20_read(emu, reg, 0); @@ -197,15 +183,11 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, } if (result) { /* Timed out */ - err = 1; - goto spi_write_exit; + return 1; } snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ - err = 0; -spi_write_exit: - spin_unlock(&emu->spi_lock); - return err; + return 0; } /* The ADC does not support i2c read, so only write is implemented */ @@ -217,7 +199,6 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, int timeout = 0; int status; int retry; - int err = 0; if ((reg > 0x7f) || (value > 0x1ff)) { dev_err(emu->card->dev, "i2c_write: invalid values.\n"); @@ -225,7 +206,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, } /* This function is not re-entrant, so protect against it. */ - spin_lock(&emu->i2c_lock); + guard(spinlock)(&emu->i2c_lock); tmp = reg << 25 | value << 16; @@ -264,11 +245,10 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n", status, reg, value); /* dump_stack(); */ - err = -EINVAL; + return -EINVAL; } - spin_unlock(&emu->i2c_lock); - return err; + return 0; } static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 value) @@ -476,32 +456,27 @@ void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock, void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); enable = inl(emu->port + INTE) | intrenb; outl(enable, emu->port + INTE); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); enable = inl(emu->port + INTE) & ~intrenb; outl(enable, emu->port + INTE); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; unsigned int val; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(CLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -512,15 +487,13 @@ void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenu val |= 1 << voicenum; } outl(val, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; unsigned int val; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(CLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -531,14 +504,11 @@ void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicen val &= ~(1 << voicenum); } outl(val, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; - - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(CLIPH << 16, emu->port + PTR); voicenum = 1 << (voicenum - 32); @@ -547,15 +517,13 @@ void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) voicenum = 1 << voicenum; } outl(voicenum, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; unsigned int val; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(HLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -566,15 +534,13 @@ void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned i val |= 1 << voicenum; } outl(val, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; unsigned int val; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(HLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -585,14 +551,11 @@ void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned val &= ~(1 << voicenum); } outl(val, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; - - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(HLIPH << 16, emu->port + PTR); voicenum = 1 << (voicenum - 32); @@ -601,16 +564,14 @@ void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum = 1 << voicenum; } outl(voicenum, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } #if 0 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; unsigned int sol; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(SOLEH << 16, emu->port + PTR); sol = inl(emu->port + DATA); @@ -621,15 +582,13 @@ void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voice sol |= 1 << voicenum; } outl(sol, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum) { - unsigned long flags; unsigned int sol; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); if (voicenum >= 32) { outl(SOLEH << 16, emu->port + PTR); sol = inl(emu->port + DATA); @@ -640,32 +599,25 @@ void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voi sol &= ~(1 << voicenum); } outl(sol, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } #endif void snd_emu10k1_voice_set_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices) { - unsigned long flags; - - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(SOLEL << 16, emu->port + PTR); outl(inl(emu->port + DATA) | (u32)voices, emu->port + DATA); outl(SOLEH << 16, emu->port + PTR); outl(inl(emu->port + DATA) | (u32)(voices >> 32), emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_voice_clear_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices) { - unsigned long flags; - - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(SOLEL << 16, emu->port + PTR); outl(inl(emu->port + DATA) & (u32)~voices, emu->port + DATA); outl(SOLEH << 16, emu->port + PTR); outl(inl(emu->port + DATA) & (u32)(~voices >> 32), emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } int snd_emu10k1_voice_clear_loop_stop_multiple_atomic(struct snd_emu10k1 *emu, u64 voices) @@ -748,23 +700,17 @@ void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait) unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct snd_emu10k1 *emu = ac97->private_data; - unsigned long flags; - unsigned short val; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outb(reg, emu->port + AC97ADDRESS); - val = inw(emu->port + AC97DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); - return val; + return inw(emu->port + AC97DATA); } void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data) { struct snd_emu10k1 *emu = ac97->private_data; - unsigned long flags; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outb(reg, emu->port + AC97ADDRESS); outw(data, emu->port + AC97DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 3bccba48f82c11..be889a4ccf9ac5 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -261,14 +261,12 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b int size; struct list_head *p, *nextp; struct snd_emu10k1_memblk *deleted; - unsigned long flags; - spin_lock_irqsave(&emu->memblk_lock, flags); + guard(spinlock_irqsave)(&emu->memblk_lock); if (blk->mapped_page >= 0) { /* update order link */ list_move_tail(&blk->mapped_order_link, &emu->mapped_order_link_head); - spin_unlock_irqrestore(&emu->memblk_lock, flags); return 0; } err = map_memblk(emu, blk); @@ -289,7 +287,6 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b } } } - spin_unlock_irqrestore(&emu->memblk_lock, flags); return err; } @@ -424,13 +421,12 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk) { struct snd_util_memhdr *hdr = emu->memhdr; struct snd_emu10k1_memblk *blk = (struct snd_emu10k1_memblk *)memblk; - unsigned long flags; guard(mutex)(&hdr->block_mutex); - spin_lock_irqsave(&emu->memblk_lock, flags); - if (blk->mapped_page >= 0) - unmap_memblk(emu, blk); - spin_unlock_irqrestore(&emu->memblk_lock, flags); + scoped_guard(spinlock_irqsave, &emu->memblk_lock) { + if (blk->mapped_page >= 0) + unmap_memblk(emu, blk); + } synth_free_pages(emu, blk); __snd_util_mem_free(hdr, memblk); return 0; diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index e774174d10de7a..b74128e6125411 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -342,24 +342,20 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) static void snd_p16v_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); enable = inl(emu->port + INTE2) | intrenb; outl(enable, emu->port + INTE2); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_p16v_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb) { - unsigned long flags; unsigned int disable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); disable = inl(emu->port + INTE2) & (~intrenb); outl(disable, emu->port + INTE2); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_p16v_interrupt(struct snd_emu10k1 *emu) diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 77fb5427aaed58..7fe1d1727768ba 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -77,7 +77,6 @@ static void voice_free(struct snd_emu10k1 *emu, int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int channels, struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice) { - unsigned long flags; int result; if (snd_BUG_ON(!rvoice)) @@ -87,7 +86,7 @@ int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int ch if (snd_BUG_ON(!channels)) return -EINVAL; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (int got = 0; got < channels; ) { result = voice_alloc(emu, type, count, epcm, &rvoice[got]); if (result == 0) { @@ -113,7 +112,6 @@ int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int ch } break; } - spin_unlock_irqrestore(&emu->voice_lock, flags); return result; } @@ -123,17 +121,15 @@ EXPORT_SYMBOL(snd_emu10k1_voice_alloc); int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice) { - unsigned long flags; int last; if (snd_BUG_ON(!pvoice)) return -EINVAL; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); do { last = pvoice->last; voice_free(emu, pvoice++); } while (!last); - spin_unlock_irqrestore(&emu->voice_lock, flags); return 0; } From 1af61c669b1c9ec42a152b8680dcdaf4bee30f09 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:04 +0200 Subject: [PATCH 0939/1292] ALSA: emu10k1x: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-30-tiwai@suse.de --- sound/pci/emu10k1/emu10k1x.c | 223 ++++++++++++++--------------------- 1 file changed, 89 insertions(+), 134 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 8c18ad98722368..9607a0f7174b08 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -281,16 +281,13 @@ static unsigned int snd_emu10k1x_ptr_read(struct emu10k1x * emu, unsigned int reg, unsigned int chn) { - unsigned long flags; - unsigned int regptr, val; + unsigned int regptr; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(regptr, emu->port + PTR); - val = inl(emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); - return val; + return inl(emu->port + DATA); } static void snd_emu10k1x_ptr_write(struct emu10k1x *emu, @@ -299,45 +296,36 @@ static void snd_emu10k1x_ptr_write(struct emu10k1x *emu, unsigned int data) { unsigned int regptr; - unsigned long flags; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(regptr, emu->port + PTR); outl(data, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_emu10k1x_intr_enable(struct emu10k1x *emu, unsigned int intrenb) { - unsigned long flags; unsigned int intr_enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); intr_enable = inl(emu->port + INTE) | intrenb; outl(intr_enable, emu->port + INTE); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_emu10k1x_intr_disable(struct emu10k1x *emu, unsigned int intrenb) { - unsigned long flags; unsigned int intr_enable; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); intr_enable = inl(emu->port + INTE) & ~intrenb; outl(intr_enable, emu->port + INTE); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_emu10k1x_gpio_write(struct emu10k1x *emu, unsigned int value) { - unsigned long flags; - - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outl(value, emu->port + GPIO); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static void snd_emu10k1x_pcm_free_substream(struct snd_pcm_runtime *runtime) @@ -694,26 +682,20 @@ static unsigned short snd_emu10k1x_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct emu10k1x *emu = ac97->private_data; - unsigned long flags; - unsigned short val; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outb(reg, emu->port + AC97ADDRESS); - val = inw(emu->port + AC97DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); - return val; + return inw(emu->port + AC97DATA); } static void snd_emu10k1x_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct emu10k1x *emu = ac97->private_data; - unsigned long flags; - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); outb(reg, emu->port + AC97ADDRESS); outw(val, emu->port + AC97DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } static int snd_emu10k1x_ac97(struct emu10k1x *chip) @@ -966,14 +948,12 @@ static void snd_emu10k1x_proc_reg_read(struct snd_info_entry *entry, { struct emu10k1x *emu = entry->private_data; unsigned long value,value1,value2; - unsigned long flags; int i; snd_iprintf(buffer, "Registers:\n\n"); for(i = 0; i < 0x20; i+=4) { - spin_lock_irqsave(&emu->emu_lock, flags); + guard(spinlock_irqsave)(&emu->emu_lock); value = inl(emu->port + i); - spin_unlock_irqrestore(&emu->emu_lock, flags); snd_iprintf(buffer, "Register %02X: %08lX\n", i, value); } snd_iprintf(buffer, "\nRegisters\n\n"); @@ -1206,28 +1186,28 @@ static void do_emu10k1x_midi_interrupt(struct emu10k1x *emu, return; } - spin_lock(&midi->input_lock); - if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { - if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { - mpu401_clear_rx(emu, midi); - } else { - byte = mpu401_read_data(emu, midi); - if (midi->substream_input) - snd_rawmidi_receive(midi->substream_input, &byte, 1); + scoped_guard(spinlock, &midi->input_lock) { + if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { + if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { + mpu401_clear_rx(emu, midi); + } else { + byte = mpu401_read_data(emu, midi); + if (midi->substream_input) + snd_rawmidi_receive(midi->substream_input, &byte, 1); + } } } - spin_unlock(&midi->input_lock); - spin_lock(&midi->output_lock); - if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { - if (midi->substream_output && - snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { - mpu401_write_data(emu, midi, byte); - } else { - snd_emu10k1x_intr_disable(emu, midi->tx_enable); + scoped_guard(spinlock, &midi->output_lock) { + if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { + if (midi->substream_output && + snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { + mpu401_write_data(emu, midi, byte); + } else { + snd_emu10k1x_intr_disable(emu, midi->tx_enable); + } } } - spin_unlock(&midi->output_lock); } static void snd_emu10k1x_midi_interrupt(struct emu10k1x *emu, unsigned int status) @@ -1238,29 +1218,28 @@ static void snd_emu10k1x_midi_interrupt(struct emu10k1x *emu, unsigned int statu static int snd_emu10k1x_midi_cmd(struct emu10k1x * emu, struct emu10k1x_midi *midi, unsigned char cmd, int ack) { - unsigned long flags; int timeout, ok; - spin_lock_irqsave(&midi->input_lock, flags); - mpu401_write_data(emu, midi, 0x00); - /* mpu401_clear_rx(emu, midi); */ - - mpu401_write_cmd(emu, midi, cmd); - if (ack) { - ok = 0; - timeout = 10000; - while (!ok && timeout-- > 0) { - if (mpu401_input_avail(emu, midi)) { - if (mpu401_read_data(emu, midi) == MPU401_ACK) - ok = 1; + scoped_guard(spinlock_irqsave, &midi->input_lock) { + mpu401_write_data(emu, midi, 0x00); + /* mpu401_clear_rx(emu, midi); */ + + mpu401_write_cmd(emu, midi, cmd); + if (ack) { + ok = 0; + timeout = 10000; + while (!ok && timeout-- > 0) { + if (mpu401_input_avail(emu, midi)) { + if (mpu401_read_data(emu, midi) == MPU401_ACK) + ok = 1; + } } - } - if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) + if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) + ok = 1; + } else { ok = 1; - } else { - ok = 1; + } } - spin_unlock_irqrestore(&midi->input_lock, flags); if (!ok) { dev_err(emu->card->dev, "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", @@ -1276,100 +1255,78 @@ static int snd_emu10k1x_midi_input_open(struct snd_rawmidi_substream *substream) { struct emu10k1x *emu; struct emu10k1x_midi *midi = substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT; - midi->substream_input = substream; - if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1)) - goto error_out; - if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) - goto error_out; - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT; + midi->substream_input = substream; + if (midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) + return 0; } + if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1)) + return -EIO; + if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) + return -EIO; return 0; - -error_out: - return -EIO; } static int snd_emu10k1x_midi_output_open(struct snd_rawmidi_substream *substream) { struct emu10k1x *emu; struct emu10k1x_midi *midi = substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT; - midi->substream_output = substream; - if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1)) - goto error_out; - if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) - goto error_out; - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT; + midi->substream_output = substream; + if (midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT) + return 0; } + if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1)) + return -EIO; + if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) + return -EIO; return 0; - -error_out: - return -EIO; } static int snd_emu10k1x_midi_input_close(struct snd_rawmidi_substream *substream) { struct emu10k1x *emu; struct emu10k1x_midi *midi = substream->rmidi->private_data; - unsigned long flags; - int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - snd_emu10k1x_intr_disable(emu, midi->rx_enable); - midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT; - midi->substream_input = NULL; - if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - err = snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + snd_emu10k1x_intr_disable(emu, midi->rx_enable); + midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT; + midi->substream_input = NULL; + if (midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) + return 0; } - return err; + return snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); } static int snd_emu10k1x_midi_output_close(struct snd_rawmidi_substream *substream) { struct emu10k1x *emu; struct emu10k1x_midi *midi = substream->rmidi->private_data; - unsigned long flags; - int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); - snd_emu10k1x_intr_disable(emu, midi->tx_enable); - midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT; - midi->substream_output = NULL; - if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); - err = snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); - } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + scoped_guard(spinlock_irqsave, &midi->open_lock) { + snd_emu10k1x_intr_disable(emu, midi->tx_enable); + midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT; + midi->substream_output = NULL; + if (midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT) + return 0; } - return err; + return snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); } static void snd_emu10k1x_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1390,7 +1347,6 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst { struct emu10k1x *emu; struct emu10k1x_midi *midi = substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) @@ -1401,22 +1357,21 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst unsigned char byte; /* try to send some amount of bytes here before interrupts */ - spin_lock_irqsave(&midi->output_lock, flags); - while (max > 0) { - if (mpu401_output_ready(emu, midi)) { - if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) || - snd_rawmidi_transmit(substream, &byte, 1) != 1) { - /* no more data */ - spin_unlock_irqrestore(&midi->output_lock, flags); - return; + scoped_guard(spinlock_irqsave, &midi->output_lock) { + while (max > 0) { + if (mpu401_output_ready(emu, midi)) { + if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) || + snd_rawmidi_transmit(substream, &byte, 1) != 1) { + /* no more data */ + return; + } + mpu401_write_data(emu, midi, byte); + max--; + } else { + break; } - mpu401_write_data(emu, midi, byte); - max--; - } else { - break; } } - spin_unlock_irqrestore(&midi->output_lock, flags); snd_emu10k1x_intr_enable(emu, midi->tx_enable); } else { snd_emu10k1x_intr_disable(emu, midi->tx_enable); From f9733d65a6617e0ec7985bfbfdca3c49cd8eb379 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:05 +0200 Subject: [PATCH 0940/1292] ALSA: es1938: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-31-tiwai@suse.de --- sound/pci/es1938.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 0ce7076206f92b..280125eff36245 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -237,11 +237,9 @@ MODULE_DEVICE_TABLE(pci, snd_es1938_ids); * -----------------------------------------------------------------*/ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsigned char val) { - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, SLSB_REG(chip, MIXERADDR)); outb(val, SLSB_REG(chip, MIXERDATA)); - spin_unlock_irqrestore(&chip->mixer_lock, flags); dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val); } @@ -251,11 +249,10 @@ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsig static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg) { int data; - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); + + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, SLSB_REG(chip, MIXERADDR)); data = inb(SLSB_REG(chip, MIXERDATA)); - spin_unlock_irqrestore(&chip->mixer_lock, flags); dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data); return data; } @@ -266,9 +263,9 @@ static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg) static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg, unsigned char mask, unsigned char val) { - unsigned long flags; unsigned char old, new, oval; - spin_lock_irqsave(&chip->mixer_lock, flags); + + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, SLSB_REG(chip, MIXERADDR)); old = inb(SLSB_REG(chip, MIXERDATA)); oval = old & mask; @@ -279,7 +276,6 @@ static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg, "Mixer reg %02x was %02x, set to %02x\n", reg, old, new); } - spin_unlock_irqrestore(&chip->mixer_lock, flags); return oval; } @@ -322,11 +318,9 @@ static int snd_es1938_get_byte(struct es1938 *chip) * -----------------------------------------------------------------*/ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned char val) { - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_es1938_write_cmd(chip, reg); snd_es1938_write_cmd(chip, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val); } @@ -336,12 +330,11 @@ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned ch static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg) { unsigned char val; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); snd_es1938_write_cmd(chip, ESS_CMD_READREG); snd_es1938_write_cmd(chip, reg); val = snd_es1938_get_byte(chip); - spin_unlock_irqrestore(&chip->reg_lock, flags); dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val); return val; } @@ -352,9 +345,9 @@ static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg) static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char mask, unsigned char val) { - unsigned long flags; unsigned char old, new, oval; - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); snd_es1938_write_cmd(chip, ESS_CMD_READREG); snd_es1938_write_cmd(chip, reg); old = snd_es1938_get_byte(chip); @@ -366,7 +359,6 @@ static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n", reg, old, new); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return oval; } From 819107cdebff9037e3dd9249823c81a212d8e528 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:06 +0200 Subject: [PATCH 0941/1292] ALSA: es1968: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-32-tiwai@suse.de --- sound/pci/es1968.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 624ba7d4756629..a9344c0bcf6b4d 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1318,12 +1318,11 @@ static int calc_available_memory_size(struct es1968 *chip) int max_size = 0; struct esm_memory *buf; - mutex_lock(&chip->memory_mutex); + guard(mutex)(&chip->memory_mutex); list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes > max_size) max_size = buf->buf.bytes; } - mutex_unlock(&chip->memory_mutex); if (max_size >= 128*1024) max_size = 127*1024; return max_size; @@ -1335,21 +1334,18 @@ static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size) struct esm_memory *buf; size = ALIGN(size, ESM_MEM_ALIGN); - mutex_lock(&chip->memory_mutex); + guard(mutex)(&chip->memory_mutex); list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes >= size) goto __found; } - mutex_unlock(&chip->memory_mutex); return NULL; __found: if (buf->buf.bytes > size) { struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL); - if (chunk == NULL) { - mutex_unlock(&chip->memory_mutex); + if (chunk == NULL) return NULL; - } chunk->buf = buf->buf; chunk->buf.bytes -= size; chunk->buf.area += size; @@ -1359,7 +1355,6 @@ static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size) list_add(&chunk->list, &buf->list); } buf->empty = 0; - mutex_unlock(&chip->memory_mutex); return buf; } @@ -1368,7 +1363,7 @@ static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf) { struct esm_memory *chunk; - mutex_lock(&chip->memory_mutex); + guard(mutex)(&chip->memory_mutex); buf->empty = 1; if (buf->list.prev != &chip->buf_list) { chunk = list_entry(buf->list.prev, struct esm_memory, list); @@ -1387,7 +1382,6 @@ static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf) kfree(chunk); } } - mutex_unlock(&chip->memory_mutex); } static void snd_es1968_free_dmabuf(struct es1968 *chip) From 3ea4db1f202813501f2068003fb512455cf56411 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:07 +0200 Subject: [PATCH 0942/1292] ALSA: es1968: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-33-tiwai@suse.de --- sound/pci/es1968.c | 146 +++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 92 deletions(-) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index a9344c0bcf6b4d..51aee2c4d461a9 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -574,10 +574,8 @@ static void __maestro_write(struct es1968 *chip, u16 reg, u16 data) static inline void maestro_write(struct es1968 *chip, u16 reg, u16 data) { - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); __maestro_write(chip, reg, data); - spin_unlock_irqrestore(&chip->reg_lock, flags); } /* no spinlock */ @@ -592,12 +590,8 @@ static u16 __maestro_read(struct es1968 *chip, u16 reg) static inline u16 maestro_read(struct es1968 *chip, u16 reg) { - unsigned long flags; - u16 result; - spin_lock_irqsave(&chip->reg_lock, flags); - result = __maestro_read(chip, reg); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return result; + guard(spinlock_irqsave)(&chip->reg_lock); + return __maestro_read(chip, reg); } /* Wait for the codec bus to be free */ @@ -693,10 +687,8 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat static void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data) { - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); __apu_set_register(chip, channel, reg, data); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg) @@ -710,62 +702,40 @@ static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg) static u16 apu_get_register(struct es1968 *chip, u16 channel, u8 reg) { - unsigned long flags; - u16 v; - spin_lock_irqsave(&chip->reg_lock, flags); - v = __apu_get_register(chip, channel, reg); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return v; + guard(spinlock_irqsave)(&chip->reg_lock); + return __apu_get_register(chip, channel, reg); } #if 0 /* ASSP is not supported */ static void assp_set_register(struct es1968 *chip, u32 reg, u32 value) { - unsigned long flags; - - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave),(&chip->reg_lock); outl(reg, chip->io_port + ASSP_INDEX); outl(value, chip->io_port + ASSP_DATA); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static u32 assp_get_register(struct es1968 *chip, u32 reg) { - unsigned long flags; - u32 value; - - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); outl(reg, chip->io_port + ASSP_INDEX); - value = inl(chip->io_port + ASSP_DATA); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - return value; + return inl(chip->io_port + ASSP_DATA); } #endif static void wave_set_register(struct es1968 *chip, u16 reg, u16 value) { - unsigned long flags; - - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); outw(reg, chip->io_port + WC_INDEX); outw(value, chip->io_port + WC_DATA); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static u16 wave_get_register(struct es1968 *chip, u16 reg) { - unsigned long flags; - u16 value; - - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); outw(reg, chip->io_port + WC_INDEX); - value = inw(chip->io_port + WC_DATA); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - return value; + return inw(chip->io_port + WC_DATA); } /* ******************* @@ -924,7 +894,7 @@ static inline void snd_es1968_trigger_apu(struct es1968 *esm, int apu, int mode) static void snd_es1968_pcm_start(struct es1968 *chip, struct esschan *es) { - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); __apu_set_register(chip, es->apu[0], 5, es->base[0]); snd_es1968_trigger_apu(chip, es->apu[0], es->apu_mode[0]); if (es->mode == ESM_MODE_CAPTURE) { @@ -939,19 +909,17 @@ static void snd_es1968_pcm_start(struct es1968 *chip, struct esschan *es) snd_es1968_trigger_apu(chip, es->apu[3], es->apu_mode[3]); } } - spin_unlock(&chip->reg_lock); } static void snd_es1968_pcm_stop(struct es1968 *chip, struct esschan *es) { - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); snd_es1968_trigger_apu(chip, es->apu[0], 0); snd_es1968_trigger_apu(chip, es->apu[1], 0); if (es->mode == ESM_MODE_CAPTURE) { snd_es1968_trigger_apu(chip, es->apu[2], 0); snd_es1968_trigger_apu(chip, es->apu[3], 0); } - spin_unlock(&chip->reg_lock); } /* set the wavecache control reg */ @@ -981,7 +949,6 @@ static void snd_es1968_playback_setup(struct es1968 *chip, struct esschan *es, int high_apu = 0; int channel, apu; int i, size; - unsigned long flags; u32 freq; size = es->dma_size >> es->wav_shift; @@ -1051,12 +1018,12 @@ static void snd_es1968_playback_setup(struct es1968 *chip, struct esschan *es, apu_set_register(chip, apu, 10, 0x8F08); } - spin_lock_irqsave(&chip->reg_lock, flags); - /* clear WP interrupts */ - outw(1, chip->io_port + 0x04); - /* enable WP ints */ - outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + /* clear WP interrupts */ + outw(1, chip->io_port + 0x04); + /* enable WP ints */ + outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); + } freq = runtime->rate; /* set frequency */ @@ -1127,7 +1094,6 @@ static void snd_es1968_capture_setup(struct es1968 *chip, struct esschan *es, { int size; u32 freq; - unsigned long flags; size = es->dma_size >> es->wav_shift; @@ -1179,12 +1145,11 @@ static void snd_es1968_capture_setup(struct es1968 *chip, struct esschan *es, snd_es1968_apu_set_freq(chip, es->apu[2], freq); snd_es1968_apu_set_freq(chip, es->apu[3], freq); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); /* clear WP interrupts */ outw(1, chip->io_port + 0x04); /* enable WP ints */ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); - spin_unlock_irqrestore(&chip->reg_lock, flags); } /******************* @@ -1228,7 +1193,7 @@ static int snd_es1968_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es = substream->runtime->private_data; - spin_lock(&chip->substream_lock); + guard(spinlock)(&chip->substream_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -1249,7 +1214,6 @@ static int snd_es1968_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_es1968_bob_dec(chip); break; } - spin_unlock(&chip->substream_lock); return 0; } @@ -1543,9 +1507,8 @@ static int snd_es1968_playback_open(struct snd_pcm_substream *substream) runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = calc_available_memory_size(chip); - spin_lock_irq(&chip->substream_lock); + guard(spinlock_irq)(&chip->substream_lock); list_add(&es->list, &chip->substream_list); - spin_unlock_irq(&chip->substream_lock); return 0; } @@ -1603,9 +1566,8 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) if (err < 0) return err; - spin_lock_irq(&chip->substream_lock); + guard(spinlock_irq)(&chip->substream_lock); list_add(&es->list, &chip->substream_list); - spin_unlock_irq(&chip->substream_lock); return 0; } @@ -1618,9 +1580,9 @@ static int snd_es1968_playback_close(struct snd_pcm_substream *substream) if (substream->runtime->private_data == NULL) return 0; es = substream->runtime->private_data; - spin_lock_irq(&chip->substream_lock); - list_del(&es->list); - spin_unlock_irq(&chip->substream_lock); + scoped_guard(spinlock_irq, &chip->substream_lock) { + list_del(&es->list); + } snd_es1968_free_apu_pair(chip, es->apu[0]); kfree(es); @@ -1635,9 +1597,9 @@ static int snd_es1968_capture_close(struct snd_pcm_substream *substream) if (substream->runtime->private_data == NULL) return 0; es = substream->runtime->private_data; - spin_lock_irq(&chip->substream_lock); - list_del(&es->list); - spin_unlock_irq(&chip->substream_lock); + scoped_guard(spinlock_irq, &chip->substream_lock) { + list_del(&es->list); + } snd_es1968_free_memory(chip, es->mixbuf); snd_es1968_free_apu_pair(chip, es->apu[0]); snd_es1968_free_apu_pair(chip, es->apu[2]); @@ -1718,29 +1680,29 @@ static void es1968_measure_clock(struct es1968 *chip) apu_set_register(chip, apu, 9, 0xD000); apu_set_register(chip, apu, 10, 0x8F08); apu_set_register(chip, apu, 11, 0x0000); - spin_lock_irq(&chip->reg_lock); - outw(1, chip->io_port + 0x04); /* clear WP interrupts */ - outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); /* enable WP ints */ - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + outw(1, chip->io_port + 0x04); /* clear WP interrupts */ + outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); /* enable WP ints */ + } snd_es1968_apu_set_freq(chip, apu, ((unsigned int)48000 << 16) / chip->clock); /* 48000 Hz */ chip->in_measurement = 1; chip->measure_apu = apu; - spin_lock_irq(&chip->reg_lock); - snd_es1968_bob_inc(chip, ESM_BOB_FREQ); - __apu_set_register(chip, apu, 5, pa & 0xffff); - snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR); - start_time = ktime_get(); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + snd_es1968_bob_inc(chip, ESM_BOB_FREQ); + __apu_set_register(chip, apu, 5, pa & 0xffff); + snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR); + start_time = ktime_get(); + } msleep(50); - spin_lock_irq(&chip->reg_lock); - offset = __apu_get_register(chip, apu, 5); - stop_time = ktime_get(); - snd_es1968_trigger_apu(chip, apu, 0); /* stop */ - snd_es1968_bob_dec(chip); - chip->in_measurement = 0; - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + offset = __apu_get_register(chip, apu, 5); + stop_time = ktime_get(); + snd_es1968_trigger_apu(chip, apu, 0); /* stop */ + snd_es1968_bob_dec(chip); + chip->in_measurement = 0; + } /* check the current position */ offset -= (pa & 0xffff); @@ -1964,15 +1926,15 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) if (event & ESM_SOUND_IRQ) { struct esschan *es; - spin_lock(&chip->substream_lock); - list_for_each_entry(es, &chip->substream_list, list) { - if (es->running) { - snd_es1968_update_pcm(chip, es); - if (es->fmt & ESS_FMT_STEREO) - snd_es1968_suppress_jitter(chip, es); + scoped_guard(spinlock, &chip->substream_lock) { + list_for_each_entry(es, &chip->substream_list, list) { + if (es->running) { + snd_es1968_update_pcm(chip, es); + if (es->fmt & ESS_FMT_STEREO) + snd_es1968_suppress_jitter(chip, es); + } } } - spin_unlock(&chip->substream_lock); if (chip->in_measurement) { unsigned int curp = __apu_get_register(chip, chip->measure_apu, 5); if (curp < chip->measure_lastpos) From 2b429331f55bf4d39a9be3357b0958d577bf9086 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:08 +0200 Subject: [PATCH 0943/1292] ALSA: fm801: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-34-tiwai@suse.de --- sound/pci/fm801.c | 71 ++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index cf40bd06b73414..4ca992449ea301 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -279,16 +279,14 @@ static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg, unsigned short mask, unsigned short value) { int change; - unsigned long flags; unsigned short old, new; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); old = fm801_ioread16(chip, reg); new = (old & ~mask) | value; change = old != new; if (change) fm801_iowrite16(chip, reg, new); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -393,7 +391,7 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream, { struct fm801 *chip = snd_pcm_substream_chip(substream); - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: chip->ply_ctrl &= ~(FM801_BUF1_LAST | @@ -414,12 +412,10 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream, chip->ply_ctrl &= ~FM801_PAUSE; break; default: - spin_unlock(&chip->reg_lock); snd_BUG(); return -EINVAL; } fm801_writew(chip, PLY_CTRL, chip->ply_ctrl); - spin_unlock(&chip->reg_lock); return 0; } @@ -428,7 +424,7 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream, { struct fm801 *chip = snd_pcm_substream_chip(substream); - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: chip->cap_ctrl &= ~(FM801_BUF1_LAST | @@ -449,12 +445,10 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream, chip->cap_ctrl &= ~FM801_PAUSE; break; default: - spin_unlock(&chip->reg_lock); snd_BUG(); return -EINVAL; } fm801_writew(chip, CAP_CTRL, chip->cap_ctrl); - spin_unlock(&chip->reg_lock); return 0; } @@ -465,7 +459,7 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream) chip->ply_size = snd_pcm_lib_buffer_bytes(substream); chip->ply_count = snd_pcm_lib_period_bytes(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->ply_ctrl &= ~(FM801_START | FM801_16BIT | FM801_STEREO | FM801_RATE_MASK | FM801_CHANNELS_MASK); @@ -487,7 +481,6 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream) fm801_writel(chip, PLY_BUF1, chip->ply_buffer); fm801_writel(chip, PLY_BUF2, chip->ply_buffer + (chip->ply_count % chip->ply_size)); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -498,7 +491,7 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream) chip->cap_size = snd_pcm_lib_buffer_bytes(substream); chip->cap_count = snd_pcm_lib_period_bytes(substream); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->cap_ctrl &= ~(FM801_START | FM801_16BIT | FM801_STEREO | FM801_RATE_MASK); if (snd_pcm_format_width(runtime->format) == 16) @@ -514,7 +507,6 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream) fm801_writel(chip, CAP_BUF1, chip->cap_buffer); fm801_writel(chip, CAP_BUF2, chip->cap_buffer + (chip->cap_count % chip->cap_size)); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -525,13 +517,12 @@ static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *su if (!(chip->ply_ctrl & FM801_START)) return 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); ptr = chip->ply_pos + (chip->ply_count - 1) - fm801_readw(chip, PLY_COUNT); if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_PLAYBACK) { ptr += chip->ply_count; ptr %= chip->ply_size; } - spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, ptr); } @@ -542,13 +533,12 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub if (!(chip->cap_ctrl & FM801_START)) return 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); ptr = chip->cap_pos + (chip->cap_count - 1) - fm801_readw(chip, CAP_COUNT); if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_CAPTURE) { ptr += chip->cap_count; ptr %= chip->cap_size; } - spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, ptr); } @@ -565,31 +555,31 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) /* ack first */ fm801_writew(chip, IRQ_STATUS, status); if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) { - spin_lock(&chip->reg_lock); - chip->ply_buf++; - chip->ply_pos += chip->ply_count; - chip->ply_pos %= chip->ply_size; - tmp = chip->ply_pos + chip->ply_count; - tmp %= chip->ply_size; - if (chip->ply_buf & 1) - fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp); - else - fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + chip->ply_buf++; + chip->ply_pos += chip->ply_count; + chip->ply_pos %= chip->ply_size; + tmp = chip->ply_pos + chip->ply_count; + tmp %= chip->ply_size; + if (chip->ply_buf & 1) + fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp); + else + fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp); + } snd_pcm_period_elapsed(chip->playback_substream); } if (chip->pcm && (status & FM801_IRQ_CAPTURE) && chip->capture_substream) { - spin_lock(&chip->reg_lock); - chip->cap_buf++; - chip->cap_pos += chip->cap_count; - chip->cap_pos %= chip->cap_size; - tmp = chip->cap_pos + chip->cap_count; - tmp %= chip->cap_size; - if (chip->cap_buf & 1) - fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp); - else - fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + chip->cap_buf++; + chip->cap_pos += chip->cap_count; + chip->cap_pos %= chip->cap_size; + tmp = chip->cap_pos + chip->cap_count; + tmp %= chip->cap_size; + if (chip->cap_buf & 1) + fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp); + else + fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp); + } snd_pcm_period_elapsed(chip->capture_substream); } if (chip->rmidi && (status & FM801_IRQ_MPU)) @@ -924,10 +914,9 @@ static int snd_fm801_get_double(struct snd_kcontrol *kcontrol, int invert = (kcontrol->private_value >> 24) & 0xff; long *value = ucontrol->value.integer.value; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); value[0] = (fm801_ioread16(chip, reg) >> shift_left) & mask; value[1] = (fm801_ioread16(chip, reg) >> shift_right) & mask; - spin_unlock_irq(&chip->reg_lock); if (invert) { value[0] = mask - value[0]; value[1] = mask - value[1]; From 9da230b3b2296df9c3d81fe6badab59a81c3d76f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:09 +0200 Subject: [PATCH 0944/1292] ALSA: ice1712: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-35-tiwai@suse.de --- sound/pci/ice1712/aureon.c | 27 ++++-------- sound/pci/ice1712/delta.c | 30 ++++++-------- sound/pci/ice1712/hoontech.c | 24 +++++------ sound/pci/ice1712/ice1724.c | 70 +++++++++++++++++--------------- sound/pci/ice1712/maya44.c | 18 +++----- sound/pci/ice1712/phase.c | 6 +-- sound/pci/ice1712/pontis.c | 70 +++++++++++++------------------- sound/pci/ice1712/prodigy192.c | 11 ++--- sound/pci/ice1712/prodigy_hifi.c | 56 +++++++++---------------- sound/pci/ice1712/quartet.c | 3 +- sound/pci/ice1712/wtm.c | 6 +-- 11 files changed, 132 insertions(+), 189 deletions(-) diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 027849329c1b06..b4c9e7d1160953 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -358,14 +358,13 @@ static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short vol; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F); ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F); if (kcontrol->private_value & AUREON_AC97_STEREO) ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F); - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -401,12 +400,11 @@ static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -439,11 +437,10 @@ static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ct { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -642,11 +639,10 @@ static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -704,9 +700,8 @@ static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -944,11 +939,10 @@ static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short val; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; val = val > PCM_MIN ? (val - PCM_MIN) : 0; ucontrol->value.integer.value[0] = val; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -984,12 +978,11 @@ static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va unsigned short val; int i; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { val = wm_get(ice, WM_ADC_GAIN + i); ucontrol->value.integer.value[i] = ~val>>5 & 0x1; } - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -1031,13 +1024,12 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val int i, idx; unsigned short vol; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { idx = WM_ADC_GAIN + i; vol = wm_get(ice, idx) & 0x1f; ucontrol->value.integer.value[i] = vol; } - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -1097,11 +1089,10 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short val; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); val = wm_get(ice, WM_ADC_MUX); ucontrol->value.enumerated.item[0] = val & 7; ucontrol->value.enumerated.item[1] = (val >> 4) & 7; - mutex_unlock(&ice->gpio_mutex); return 0; } diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 08adf4dd130343..fa484e2a9a7854 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -126,13 +126,12 @@ static int ap_cs8427_sendbytes(struct snd_i2c_device *device, unsigned char *byt int res = count; unsigned char tmp; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); tmp = ap_cs8427_codec_select(ice); ap_cs8427_write_byte(ice, (device->addr << 1) | 0, tmp); /* address + write mode */ while (count-- > 0) ap_cs8427_write_byte(ice, *bytes++, tmp); ap_cs8427_codec_deassert(ice, tmp); - mutex_unlock(&ice->gpio_mutex); return res; } @@ -143,13 +142,12 @@ static int ap_cs8427_readbytes(struct snd_i2c_device *device, unsigned char *byt int res = count; unsigned char tmp; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); tmp = ap_cs8427_codec_select(ice); ap_cs8427_write_byte(ice, (device->addr << 1) | 1, tmp); /* address + read mode */ while (count-- > 0) *bytes++ = ap_cs8427_read_byte(ice, tmp); ap_cs8427_codec_deassert(ice, tmp); - mutex_unlock(&ice->gpio_mutex); return res; } @@ -176,7 +174,7 @@ static void snd_ice1712_delta_cs8403_spdif_write(struct snd_ice1712 *ice, unsign /* send byte to transmitter */ mask1 = ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK; mask2 = ICE1712_DELTA_SPDIF_OUT_STAT_DATA; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); for (idx = 7; idx >= 0; idx--) { tmp &= ~(mask1 | mask2); @@ -190,7 +188,6 @@ static void snd_ice1712_delta_cs8403_spdif_write(struct snd_ice1712 *ice, unsign } tmp &= ~mask1; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); - mutex_unlock(&ice->gpio_mutex); } @@ -306,14 +303,13 @@ static void delta_1010_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) if (rate == 0) /* no hint - S/PDIF input is master, simply return */ return; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); tmp2 = tmp & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp2 |= ICE1712_DELTA_DFS; if (tmp != tmp2) snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp2); - mutex_unlock(&ice->gpio_mutex); } /* @@ -328,9 +324,9 @@ static void delta_ak4524_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) return; /* check before reset ak4524 to avoid unnecessary clicks */ - mutex_lock(&ice->gpio_mutex); - tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); - mutex_unlock(&ice->gpio_mutex); + scoped_guard(mutex, &ice->gpio_mutex) { + tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); + } tmp2 = tmp & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp2 |= ICE1712_DELTA_DFS; @@ -339,12 +335,12 @@ static void delta_ak4524_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) /* do it again */ snd_akm4xxx_reset(ak, 1); - mutex_lock(&ice->gpio_mutex); - tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS; - if (rate > 48000) - tmp |= ICE1712_DELTA_DFS; - snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); - mutex_unlock(&ice->gpio_mutex); + scoped_guard(mutex, &ice->gpio_mutex) { + tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS; + if (rate > 48000) + tmp |= ICE1712_DELTA_DFS; + snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); + } snd_akm4xxx_reset(ak, 0); } diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 46daeea8dc66e2..071f94dc7390f6 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c @@ -41,35 +41,35 @@ static void snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned cha static void snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); ICE1712_STDSP24_0_DAREAR(spec->boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); - mutex_unlock(&ice->gpio_mutex); } static void snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); ICE1712_STDSP24_3_MUTE(spec->boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); - mutex_unlock(&ice->gpio_mutex); } static void snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); ICE1712_STDSP24_3_INSEL(spec->boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); - mutex_unlock(&ice->gpio_mutex); } static void snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) { struct hoontech_spec *spec = ice->spec; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); /* select box */ ICE1712_STDSP24_0_BOX(spec->boxbits, box); @@ -111,15 +111,13 @@ static void snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, in ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); - - mutex_unlock(&ice->gpio_mutex); } static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) { struct hoontech_spec *spec = ice->spec; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); /* select box */ ICE1712_STDSP24_0_BOX(spec->boxbits, box); @@ -139,17 +137,15 @@ static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int m ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); - - mutex_unlock(&ice->gpio_mutex); } static void snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); ICE1712_STDSP24_3_MIDI2(spec->boxbits, activate); snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); - mutex_unlock(&ice->gpio_mutex); } static int hoontech_init(struct snd_ice1712 *ice, bool staudio) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 0445d2e8e5485d..5bf90e2fd19105 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -684,24 +684,21 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, return 0; } -static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int __snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); int i, chs; chs = params_channels(hw_params); - mutex_lock(&ice->open_mutex); /* mark surround channels */ if (substream == ice->playback_pro_substream) { /* PDMA0 can be multi-channel up to 8 */ chs = chs / 2 - 1; for (i = 0; i < chs; i++) { if (ice->pcm_reserved[i] && - ice->pcm_reserved[i] != substream) { - mutex_unlock(&ice->open_mutex); + ice->pcm_reserved[i] != substream) return -EBUSY; - } ice->pcm_reserved[i] = substream; } for (; i < 3; i++) { @@ -713,16 +710,28 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, /* check individual playback stream */ if (ice->playback_con_substream_ds[i] == substream) { if (ice->pcm_reserved[i] && - ice->pcm_reserved[i] != substream) { - mutex_unlock(&ice->open_mutex); + ice->pcm_reserved[i] != substream) return -EBUSY; - } ice->pcm_reserved[i] = substream; break; } } } - mutex_unlock(&ice->open_mutex); + + return 0; +} + +static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); + int err; + + scoped_guard(mutex, &ice->open_mutex) { + err = __snd_vt1724_pcm_hw_params(substream, hw_params); + if (err < 0) + return err; + } return snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); } @@ -732,12 +741,11 @@ static int snd_vt1724_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); int i; - mutex_lock(&ice->open_mutex); + guard(mutex)(&ice->open_mutex); /* unmark surround channels */ for (i = 0; i < 3; i++) if (ice->pcm_reserved[i] == substream) ice->pcm_reserved[i] = NULL; - mutex_unlock(&ice->open_mutex); return 0; } @@ -1013,18 +1021,18 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); set_rate_constraints(ice, substream); - mutex_lock(&ice->open_mutex); - /* calculate the currently available channels */ - num_indeps = ice->num_total_dacs / 2 - 1; - for (chs = 0; chs < num_indeps; chs++) { - if (ice->pcm_reserved[chs]) - break; + scoped_guard(mutex, &ice->open_mutex) { + /* calculate the currently available channels */ + num_indeps = ice->num_total_dacs / 2 - 1; + for (chs = 0; chs < num_indeps; chs++) { + if (ice->pcm_reserved[chs]) + break; + } + chs = (chs + 1) * 2; + runtime->hw.channels_max = chs; + if (chs > 2) /* channels must be even */ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); } - chs = (chs + 1) * 2; - runtime->hw.channels_max = chs; - if (chs > 2) /* channels must be even */ - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); - mutex_unlock(&ice->open_mutex); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, @@ -1367,13 +1375,11 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - mutex_lock(&ice->open_mutex); - /* already used by PDMA0? */ - if (ice->pcm_reserved[substream->number]) { - mutex_unlock(&ice->open_mutex); - return -EBUSY; /* FIXME: should handle blocking mode properly */ + scoped_guard(mutex, &ice->open_mutex) { + /* already used by PDMA0? */ + if (ice->pcm_reserved[substream->number]) + return -EBUSY; /* FIXME: should handle blocking mode properly */ } - mutex_unlock(&ice->open_mutex); runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number]; ice->playback_con_substream_ds[substream->number] = substream; runtime->hw = snd_vt1724_2ch_stereo; @@ -2220,13 +2226,12 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, { unsigned char val; - mutex_lock(&ice->i2c_mutex); + guard(mutex)(&ice->i2c_mutex); wait_i2c_busy(ice); outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); wait_i2c_busy(ice); val = inb(ICEREG1724(ice, I2C_DATA)); - mutex_unlock(&ice->i2c_mutex); /* dev_dbg(ice->card->dev, "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); */ @@ -2236,7 +2241,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, void snd_vt1724_write_i2c(struct snd_ice1712 *ice, unsigned char dev, unsigned char addr, unsigned char data) { - mutex_lock(&ice->i2c_mutex); + guard(mutex)(&ice->i2c_mutex); wait_i2c_busy(ice); /* dev_dbg(ice->card->dev, "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); @@ -2245,7 +2250,6 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice, outb(data, ICEREG1724(ice, I2C_DATA)); outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); wait_i2c_busy(ice); - mutex_unlock(&ice->i2c_mutex); } static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice, diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c index b46df18212516d..551f478c59c4ec 100644 --- a/sound/pci/ice1712/maya44.c +++ b/sound/pci/ice1712/maya44.c @@ -175,10 +175,9 @@ static int maya_vol_get(struct snd_kcontrol *kcontrol, &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; unsigned int idx = kcontrol->private_value; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); ucontrol->value.integer.value[0] = wm->volumes[idx][0]; ucontrol->value.integer.value[1] = wm->volumes[idx][1]; - mutex_unlock(&chip->mutex); return 0; } @@ -193,7 +192,7 @@ static int maya_vol_put(struct snd_kcontrol *kcontrol, unsigned int val, data; int ch, changed = 0; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); for (ch = 0; ch < 2; ch++) { val = ucontrol->value.integer.value[ch]; if (val > vol->maxval) @@ -213,7 +212,6 @@ static int maya_vol_put(struct snd_kcontrol *kcontrol, val ? 0 : vol->mux_bits[ch]); wm->volumes[idx][ch] = val; } - mutex_unlock(&chip->mutex); return changed; } @@ -250,7 +248,7 @@ static int maya_sw_put(struct snd_kcontrol *kcontrol, unsigned int mask, val; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); mask = 1 << idx; wm->switch_bits &= ~mask; val = ucontrol->value.integer.value[0]; @@ -260,7 +258,6 @@ static int maya_sw_put(struct snd_kcontrol *kcontrol, changed = wm8776_write_bits(chip->ice, wm, GET_SW_VAL_REG(kcontrol->private_value), mask, val ? mask : 0); - mutex_unlock(&chip->mutex); return changed; } @@ -315,14 +312,13 @@ static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol, unsigned int val, mask; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); mask = 1 << shift; val = ucontrol->value.integer.value[0]; if (GET_GPIO_VAL_INV(kcontrol->private_value)) val = !val; val = val ? mask : 0; changed = maya_set_gpio_bits(chip->ice, mask, val); - mutex_unlock(&chip->mutex); return changed; } @@ -369,11 +365,10 @@ static int maya_rec_src_put(struct snd_kcontrol *kcontrol, int sel = ucontrol->value.enumerated.item[0]; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = maya_set_gpio_bits(chip->ice, 1 << GPIO_MIC_RELAY, sel ? (1 << GPIO_MIC_RELAY) : 0); wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); - mutex_unlock(&chip->mutex); return changed; } @@ -635,12 +630,11 @@ static void set_rate(struct snd_ice1712 *ice, unsigned int rate) val |= 8; val |= ratio << 4; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); for (i = 0; i < 2; i++) wm8776_write_bits(ice, &chip->wm[i], WM8776_REG_MASTER_MODE_CONTROL, 0x180, val); - mutex_unlock(&chip->mutex); } /* diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 1e47e46ab8ac68..151b740ce66def 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -287,10 +287,9 @@ static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -638,11 +637,10 @@ static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned short val; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; val = val > PCM_MIN ? (val - PCM_MIN) : 0; ucontrol->value.integer.value[0] = val; - mutex_unlock(&ice->gpio_mutex); return 0; } diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 683909ca147c93..557473f0d59e23 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -112,13 +112,12 @@ static int wm_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short val; int i; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff; val = val > DAC_MIN ? (val - DAC_MIN) : 0; ucontrol->value.integer.value[i] = val; } - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -128,7 +127,7 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short oval, nval; int i, idx, change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { nval = ucontrol->value.integer.value[i]; nval = (nval ? (nval + DAC_MIN) : 0) & 0xff; @@ -140,7 +139,6 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val change = 1; } } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -167,13 +165,12 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short val; int i; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; val = val > ADC_MIN ? (val - ADC_MIN) : 0; ucontrol->value.integer.value[i] = val; } - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -183,7 +180,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short ovol, nvol; int i, idx, change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { nvol = ucontrol->value.integer.value[i]; nvol = nvol ? (nvol + ADC_MIN) : 0; @@ -194,7 +191,6 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val change = 1; } } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -208,9 +204,8 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int bit = kcontrol->private_value; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -221,7 +216,7 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val unsigned short oval, nval; int change; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); nval = oval = wm_get(ice, WM_ADC_MUX); if (ucontrol->value.integer.value[0]) nval |= (1 << bit); @@ -231,7 +226,6 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val if (change) { wm_put(ice, WM_ADC_MUX, nval); } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -244,9 +238,8 @@ static int wm_bypass_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -256,7 +249,7 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu unsigned short val, oval; int change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); val = oval = wm_get(ice, WM_OUT_MUX); if (ucontrol->value.integer.value[0]) val |= 0x04; @@ -266,7 +259,6 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu wm_put(ice, WM_OUT_MUX, val); change = 1; } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -279,9 +271,8 @@ static int wm_chswap_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -291,7 +282,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu unsigned short val, oval; int change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); oval = wm_get(ice, WM_DAC_CTRL1); val = oval & 0x0f; if (ucontrol->value.integer.value[0]) @@ -303,7 +294,6 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu wm_put_nocache(ice, WM_DAC_CTRL1, val); change = 1; } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -410,9 +400,8 @@ static int cs_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.enumerated.item[0] = ice->gpio.saved[0]; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -422,14 +411,13 @@ static int cs_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu unsigned char val; int change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); if (ucontrol->value.enumerated.item[0] != ice->gpio.saved[0]) { ice->gpio.saved[0] = ucontrol->value.enumerated.item[0] & 3; val = 0x80 | (ice->gpio.saved[0] << 3); spi_write(ice, CS_DEV, 0x04, val); change = 1; } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -449,10 +437,10 @@ static int pontis_gpio_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int pontis_gpio_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); /* 4-7 reserved */ ucontrol->value.integer.value[0] = (~ice->gpio.write_mask & 0xffff) | 0x00f0; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -461,22 +449,22 @@ static int pontis_gpio_mask_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int val; int changed; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); /* 4-7 reserved */ val = (~ucontrol->value.integer.value[0] & 0xffff) | 0x00f0; changed = val != ice->gpio.write_mask; ice->gpio.write_mask = val; - mutex_unlock(&ice->gpio_mutex); return changed; } static int pontis_gpio_dir_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); /* 4-7 reserved */ ucontrol->value.integer.value[0] = ice->gpio.direction & 0xff0f; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -485,23 +473,23 @@ static int pontis_gpio_dir_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int val; int changed; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); /* 4-7 reserved */ val = ucontrol->value.integer.value[0] & 0xff0f; changed = (val != ice->gpio.direction); ice->gpio.direction = val; - mutex_unlock(&ice->gpio_mutex); return changed; } static int pontis_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); ucontrol->value.integer.value[0] = snd_ice1712_gpio_read(ice) & 0xffff; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -510,7 +498,8 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int val, nval; int changed = 0; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); val = snd_ice1712_gpio_read(ice) & 0xffff; @@ -519,7 +508,6 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el snd_ice1712_gpio_write(ice, nval); changed = 1; } - mutex_unlock(&ice->gpio_mutex); return changed; } @@ -620,14 +608,14 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf struct snd_ice1712 *ice = entry->private_data; char line[64]; unsigned int reg, val; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; if (reg <= 0x17 && val <= 0xffff) wm_put(ice, reg, val); } - mutex_unlock(&ice->gpio_mutex); } static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) @@ -635,12 +623,11 @@ static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff struct snd_ice1712 *ice = entry->private_data; int reg, val; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (reg = 0; reg <= 0x17; reg++) { val = wm_get(ice, reg); snd_iprintf(buffer, "%02x = %04x\n", reg, val); } - mutex_unlock(&ice->gpio_mutex); } static void wm_proc_init(struct snd_ice1712 *ice) @@ -654,14 +641,13 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff struct snd_ice1712 *ice = entry->private_data; int reg, val; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (reg = 0; reg <= 0x26; reg++) { val = spi_read(ice, CS_DEV, reg); snd_iprintf(buffer, "%02x = %02x\n", reg, val); } val = spi_read(ice, CS_DEV, 0x7f); snd_iprintf(buffer, "%02x = %02x\n", 0x7f, val); - mutex_unlock(&ice->gpio_mutex); } static void cs_proc_init(struct snd_ice1712 *ice) diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index a12dafbf53ab24..cd7db2b65b515a 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -110,21 +110,19 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); struct prodigy192_spec *spec = ice->spec; - int idx, change; + int idx; if (kcontrol->private_value) idx = STAC946X_MASTER_VOLUME; else idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; /* due to possible conflicts with stac9460_set_rate_val, mutexing */ - mutex_lock(&spec->mute_mutex); + guard(mutex)(&spec->mute_mutex); /* dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, ucontrol->value.integer.value[0]); */ - change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); - mutex_unlock(&spec->mute_mutex); - return change; + return stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); } /* @@ -316,7 +314,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) return; /* change detected, setting master clock, muting first */ /* due to possible conflicts with mute controls - mutexing */ - mutex_lock(&spec->mute_mutex); + guard(mutex)(&spec->mute_mutex); /* we have to remember current mute status for each DAC */ for (idx = 0; idx < 7 ; ++idx) changed[idx] = stac9460_dac_mute(ice, @@ -330,7 +328,6 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) if (changed[idx]) stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); } - mutex_unlock(&spec->mute_mutex); } diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 9aa12a67d37051..eac23309386556 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -268,7 +268,7 @@ static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem int i; int change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { if (ucontrol->value.integer.value[i] != spec->vol[i]) { spec->vol[i] = ucontrol->value.integer.value[i]; @@ -277,7 +277,6 @@ static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem change = 1; } } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -376,7 +375,7 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val struct prodigy_hifi_spec *spec = ice->spec; int i, idx, change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) { idx = WM_DAC_ATTEN_L + i; @@ -386,7 +385,6 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val change = 1; } } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -428,7 +426,7 @@ static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val voices = kcontrol->private_value >> 8; ofs = kcontrol->private_value & 0xff; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < voices; i++) { if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) { idx = WM8766_LDA1 + ofs + i; @@ -439,7 +437,6 @@ static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val change = 1; } } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -474,7 +471,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct prodigy_hifi_spec *spec = ice->spec; int ch, change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (ch = 0; ch < 2; ch++) { if (ucontrol->value.integer.value[ch] != spec->master[ch]) { spec->master[ch] = ucontrol->value.integer.value[ch]; @@ -494,7 +491,6 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, change = 1; } } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -535,9 +531,8 @@ static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.enumerated.item[0] = wm_get(ice, WM_ADC_MUX) & 0x1f; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -548,14 +543,13 @@ static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol, unsigned short oval, nval; int change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); oval = wm_get(ice, WM_ADC_MUX); nval = (oval & 0xe0) | ucontrol->value.enumerated.item[0]; if (nval != oval) { wm_put(ice, WM_ADC_MUX, nval); change = 1; } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -586,13 +580,12 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, unsigned short val; int i; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; val = val > ADC_MIN ? (val - ADC_MIN) : 0; ucontrol->value.integer.value[i] = val; } - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -603,7 +596,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, unsigned short ovol, nvol; int i, idx, change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (i = 0; i < 2; i++) { nvol = ucontrol->value.integer.value[i]; nvol = nvol ? (nvol + ADC_MIN) : 0; @@ -614,7 +607,6 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, change = 1; } } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -629,10 +621,9 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int bit = kcontrol->private_value; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -644,7 +635,7 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, unsigned short oval, nval; int change; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); nval = oval = wm_get(ice, WM_ADC_MUX); if (ucontrol->value.integer.value[0]) nval |= (1 << bit); @@ -654,7 +645,6 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, if (change) { wm_put(ice, WM_ADC_MUX, nval); } - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -668,10 +658,9 @@ static int wm_bypass_get(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -682,7 +671,7 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, unsigned short val, oval; int change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); val = oval = wm_get(ice, WM_OUT_MUX); if (ucontrol->value.integer.value[0]) val |= 0x04; @@ -692,7 +681,6 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, wm_put(ice, WM_OUT_MUX, val); change = 1; } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -706,10 +694,9 @@ static int wm_chswap_get(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; - mutex_unlock(&ice->gpio_mutex); return 0; } @@ -720,7 +707,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, unsigned short val, oval; int change = 0; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); oval = wm_get(ice, WM_DAC_CTRL1); val = oval & 0x0f; if (ucontrol->value.integer.value[0]) @@ -732,7 +719,6 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, wm_put_nocache(ice, WM_DAC_CTRL1, val); change = 1; } - mutex_unlock(&ice->gpio_mutex); return change; } @@ -864,14 +850,14 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_ice1712 *ice = entry->private_data; char line[64]; unsigned int reg, val; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; if (reg <= 0x17 && val <= 0xffff) wm_put(ice, reg, val); } - mutex_unlock(&ice->gpio_mutex); } static void wm_proc_regs_read(struct snd_info_entry *entry, @@ -880,12 +866,11 @@ static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_ice1712 *ice = entry->private_data; int reg, val; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); for (reg = 0; reg <= 0x17; reg++) { val = wm_get(ice, reg); snd_iprintf(buffer, "%02x = %04x\n", reg, val); } - mutex_unlock(&ice->gpio_mutex); } static void wm_proc_init(struct snd_ice1712 *ice) @@ -994,7 +979,7 @@ static int prodigy_hifi_resume(struct snd_ice1712 *ice) struct prodigy_hifi_spec *spec = ice->spec; int i, ch; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); /* reinitialize WM8776 and re-apply old register values */ wm8776_init(ice); @@ -1023,7 +1008,6 @@ static int prodigy_hifi_resume(struct snd_ice1712 *ice) wm_put(ice, WM_DAC_MUTE, 0x00); wm_put(ice, WM_DAC_CTRL1, 0x90); - mutex_unlock(&ice->gpio_mutex); return 0; } #endif @@ -1134,11 +1118,11 @@ static int prodigy_hd2_resume(struct snd_ice1712 *ice) /* initialize ak4396 codec and restore previous mixer volumes */ struct prodigy_hifi_spec *spec = ice->spec; int i; - mutex_lock(&ice->gpio_mutex); + + guard(mutex)(&ice->gpio_mutex); ak4396_init(ice); for (i = 0; i < 2; i++) ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff); - mutex_unlock(&ice->gpio_mutex); return 0; } #endif diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index f61ee9f5c754e0..099601edf1d05a 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -396,7 +396,7 @@ static void reg_write(struct snd_ice1712 *ice, unsigned int reg, { unsigned int tmp; - mutex_lock(&ice->gpio_mutex); + guard(mutex)(&ice->gpio_mutex); /* set direction of used GPIOs*/ /* all outputs */ tmp = 0x00ffff; @@ -429,7 +429,6 @@ static void reg_write(struct snd_ice1712 *ice, unsigned int reg, ice->gpio.set_mask(ice, 0xffffff); /* outputs only 8-15 */ ice->gpio.set_dir(ice, 0x00ff00); - mutex_unlock(&ice->gpio_mutex); } static unsigned int get_scr(struct snd_ice1712 *ice) diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index f613f0067d8ccf..57a79536e7ba7f 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -118,7 +118,7 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, unsigned char val; int idx, id; - mutex_lock(&spec->mute_mutex); + guard(mutex)(&spec->mute_mutex); if (kcontrol->private_value) { idx = STAC946X_MASTER_VOLUME; @@ -133,7 +133,6 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, val = stac9460_2_get(ice, idx - 6); ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; - mutex_unlock(&spec->mute_mutex); return 0; } @@ -455,7 +454,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) return; /* change detected, setting master clock, muting first */ /* due to possible conflicts with mute controls - mutexing */ - mutex_lock(&spec->mute_mutex); + guard(mutex)(&spec->mute_mutex); /* we have to remember current mute status for each DAC */ changed = 0xFFFF; stac9460_dac_mute_all(ice, 0, &changed); @@ -466,7 +465,6 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) /* unmuting - only originally unmuted dacs - * i.e. those changed when muting */ stac9460_dac_mute_all(ice, 1, &changed); - mutex_unlock(&spec->mute_mutex); } From d0b8e4190407f90db6fbd0b847e485278c5a71f5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:10 +0200 Subject: [PATCH 0945/1292] ALSA: ice1712: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-36-tiwai@suse.de --- sound/pci/ice1712/delta.c | 53 ++++---- sound/pci/ice1712/ews.c | 53 ++++---- sound/pci/ice1712/ice1712.c | 184 ++++++++++++--------------- sound/pci/ice1712/ice1724.c | 240 +++++++++++++++++------------------- 4 files changed, 238 insertions(+), 292 deletions(-) diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index fa484e2a9a7854..e5a9585cba4ccb 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -202,15 +202,13 @@ static int delta_spdif_default_put(struct snd_ice1712 *ice, struct snd_ctl_elem_ int change; val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958); - spin_lock_irq(&ice->reg_lock); - change = ice->spdif.cs8403_bits != val; - ice->spdif.cs8403_bits = val; - if (change && ice->playback_pro_substream == NULL) { - spin_unlock_irq(&ice->reg_lock); - snd_ice1712_delta_cs8403_spdif_write(ice, val); - } else { - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + change = ice->spdif.cs8403_bits != val; + ice->spdif.cs8403_bits = val; + if (!change || ice->playback_pro_substream) + return change; } + snd_ice1712_delta_cs8403_spdif_write(ice, val); return change; } @@ -225,15 +223,13 @@ static int delta_spdif_stream_put(struct snd_ice1712 *ice, struct snd_ctl_elem_v int change; val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958); - spin_lock_irq(&ice->reg_lock); - change = ice->spdif.cs8403_stream_bits != val; - ice->spdif.cs8403_stream_bits = val; - if (change && ice->playback_pro_substream != NULL) { - spin_unlock_irq(&ice->reg_lock); - snd_ice1712_delta_cs8403_spdif_write(ice, val); - } else { - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + change = ice->spdif.cs8403_stream_bits != val; + ice->spdif.cs8403_stream_bits = val; + if (!change || ice->playback_pro_substream) + return change; } + snd_ice1712_delta_cs8403_spdif_write(ice, val); return change; } @@ -375,23 +371,22 @@ static void delta_open_spdif(struct snd_ice1712 *ice, struct snd_pcm_substream * /* set up */ static void delta_setup_spdif(struct snd_ice1712 *ice, int rate) { - unsigned long flags; unsigned int tmp; int change; - spin_lock_irqsave(&ice->reg_lock, flags); - tmp = ice->spdif.cs8403_stream_bits; - if (tmp & 0x01) /* consumer */ - tmp &= (tmp & 0x01) ? ~0x06 : ~0x18; - switch (rate) { - case 32000: tmp |= (tmp & 0x01) ? 0x04 : 0x00; break; - case 44100: tmp |= (tmp & 0x01) ? 0x00 : 0x10; break; - case 48000: tmp |= (tmp & 0x01) ? 0x02 : 0x08; break; - default: tmp |= (tmp & 0x01) ? 0x00 : 0x18; break; + scoped_guard(spinlock_irqsave, &ice->reg_lock) { + tmp = ice->spdif.cs8403_stream_bits; + if (tmp & 0x01) /* consumer */ + tmp &= (tmp & 0x01) ? ~0x06 : ~0x18; + switch (rate) { + case 32000: tmp |= (tmp & 0x01) ? 0x04 : 0x00; break; + case 44100: tmp |= (tmp & 0x01) ? 0x00 : 0x10; break; + case 48000: tmp |= (tmp & 0x01) ? 0x02 : 0x08; break; + default: tmp |= (tmp & 0x01) ? 0x00 : 0x18; break; + } + change = ice->spdif.cs8403_stream_bits != tmp; + ice->spdif.cs8403_stream_bits = tmp; } - change = ice->spdif.cs8403_stream_bits != tmp; - ice->spdif.cs8403_stream_bits = tmp; - spin_unlock_irqrestore(&ice->reg_lock, flags); if (change) snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id); snd_ice1712_delta_cs8403_spdif_write(ice, tmp); diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 8bb86b3c894e2b..1dffcb011deb14 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -260,15 +260,13 @@ static int ews88_spdif_default_put(struct snd_ice1712 *ice, struct snd_ctl_elem_ int change; val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958); - spin_lock_irq(&ice->reg_lock); - change = ice->spdif.cs8403_bits != val; - ice->spdif.cs8403_bits = val; - if (change && ice->playback_pro_substream == NULL) { - spin_unlock_irq(&ice->reg_lock); - snd_ice1712_ews_cs8404_spdif_write(ice, val); - } else { - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + change = ice->spdif.cs8403_bits != val; + ice->spdif.cs8403_bits = val; + if (!change || ice->playback_pro_substream) + return change; } + snd_ice1712_ews_cs8404_spdif_write(ice, val); return change; } @@ -283,15 +281,13 @@ static int ews88_spdif_stream_put(struct snd_ice1712 *ice, struct snd_ctl_elem_v int change; val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958); - spin_lock_irq(&ice->reg_lock); - change = ice->spdif.cs8403_stream_bits != val; - ice->spdif.cs8403_stream_bits = val; - if (change && ice->playback_pro_substream != NULL) { - spin_unlock_irq(&ice->reg_lock); - snd_ice1712_ews_cs8404_spdif_write(ice, val); - } else { - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + change = ice->spdif.cs8403_stream_bits != val; + ice->spdif.cs8403_stream_bits = val; + if (!change || ice->playback_pro_substream) + return change; } + snd_ice1712_ews_cs8404_spdif_write(ice, val); return change; } @@ -305,23 +301,22 @@ static void ews88_open_spdif(struct snd_ice1712 *ice, struct snd_pcm_substream * /* set up SPDIF for EWS88MT / EWS88D */ static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate) { - unsigned long flags; unsigned char tmp; int change; - spin_lock_irqsave(&ice->reg_lock, flags); - tmp = ice->spdif.cs8403_stream_bits; - if (tmp & 0x10) /* consumer */ - tmp &= (tmp & 0x01) ? ~0x06 : ~0x60; - switch (rate) { - case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break; - case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break; - case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break; - default: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break; + scoped_guard(spinlock_irqsave, &ice->reg_lock) { + tmp = ice->spdif.cs8403_stream_bits; + if (tmp & 0x10) /* consumer */ + tmp &= (tmp & 0x01) ? ~0x06 : ~0x60; + switch (rate) { + case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break; + case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break; + case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break; + default: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break; + } + change = ice->spdif.cs8403_stream_bits != tmp; + ice->spdif.cs8403_stream_bits = tmp; } - change = ice->spdif.cs8403_stream_bits != tmp; - ice->spdif.cs8403_stream_bits = tmp; - spin_unlock_irqrestore(&ice->reg_lock, flags); if (change) snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id); snd_ice1712_ews_cs8404_spdif_write(ice, tmp); diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 1aefd46ebf6b54..1e39b985bef263 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -249,13 +249,12 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned char val, nval; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); val = inb(ICEMT(ice, MONITOR_ROUTECTRL)); nval = val & ~ICE1712_ROUTE_AC97; if (ucontrol->value.integer.value[0]) nval |= ICE1712_ROUTE_AC97; outb(nval, ICEMT(ice, MONITOR_ROUTECTRL)); - spin_unlock_irq(&ice->reg_lock); return val != nval; } @@ -484,7 +483,7 @@ static int snd_ice1712_playback_trigger(struct snd_pcm_substream *substream, int result = 0; u32 tmp; - spin_lock(&ice->reg_lock); + guard(spinlock)(&ice->reg_lock); tmp = snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL); if (cmd == SNDRV_PCM_TRIGGER_START) { tmp |= 1; @@ -498,7 +497,6 @@ static int snd_ice1712_playback_trigger(struct snd_pcm_substream *substream, result = -EINVAL; } snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp); - spin_unlock(&ice->reg_lock); return result; } @@ -509,7 +507,7 @@ static int snd_ice1712_playback_ds_trigger(struct snd_pcm_substream *substream, int result = 0; u32 tmp; - spin_lock(&ice->reg_lock); + guard(spinlock)(&ice->reg_lock); tmp = snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL); if (cmd == SNDRV_PCM_TRIGGER_START) { tmp |= 1; @@ -523,7 +521,6 @@ static int snd_ice1712_playback_ds_trigger(struct snd_pcm_substream *substream, result = -EINVAL; } snd_ice1712_ds_write(ice, substream->number * 2, ICE1712_DSC_CONTROL, tmp); - spin_unlock(&ice->reg_lock); return result; } @@ -534,7 +531,7 @@ static int snd_ice1712_capture_trigger(struct snd_pcm_substream *substream, int result = 0; u8 tmp; - spin_lock(&ice->reg_lock); + guard(spinlock)(&ice->reg_lock); tmp = snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL); if (cmd == SNDRV_PCM_TRIGGER_START) { tmp |= 1; @@ -544,7 +541,6 @@ static int snd_ice1712_capture_trigger(struct snd_pcm_substream *substream, result = -EINVAL; } snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp); - spin_unlock(&ice->reg_lock); return result; } @@ -564,7 +560,7 @@ static int snd_ice1712_playback_prepare(struct snd_pcm_substream *substream) rate = (runtime->rate * 8192) / 375; if (rate > 0x000fffff) rate = 0x000fffff; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); outb(0, ice->ddma_port + 15); outb(ICE1712_DMA_MODE_WRITE | ICE1712_DMA_AUTOINIT, ice->ddma_port + 0x0b); outl(runtime->dma_addr, ice->ddma_port + 0); @@ -577,7 +573,6 @@ static int snd_ice1712_playback_prepare(struct snd_pcm_substream *substream) snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_HI, period_size >> 8); snd_ice1712_write(ice, ICE1712_IREG_PBK_LEFT, 0); snd_ice1712_write(ice, ICE1712_IREG_PBK_RIGHT, 0); - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -599,7 +594,7 @@ static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream) ice->playback_con_active_buf[substream->number] = 0; ice->playback_con_virt_addr[substream->number] = runtime->dma_addr; chn = substream->number * 2; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR0, runtime->dma_addr); snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT0, period_size); snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR1, runtime->dma_addr + (runtime->periods > 1 ? period_size + 1 : 0)); @@ -611,7 +606,6 @@ static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream) snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_RATE, rate); snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_VOLUME, 0); } - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -629,13 +623,13 @@ static int snd_ice1712_capture_prepare(struct snd_pcm_substream *substream) tmp &= ~0x04; if (runtime->channels == 2) tmp &= ~0x02; - spin_lock_irq(&ice->reg_lock); - outl(ice->capture_con_virt_addr = runtime->dma_addr, ICEREG(ice, CONCAP_ADDR)); - outw(buf_size, ICEREG(ice, CONCAP_COUNT)); - snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_HI, period_size >> 8); - snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_LO, period_size & 0xff); - snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp); - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + outl(ice->capture_con_virt_addr = runtime->dma_addr, ICEREG(ice, CONCAP_ADDR)); + outw(buf_size, ICEREG(ice, CONCAP_COUNT)); + snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_HI, period_size >> 8); + snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_LO, period_size & 0xff); + snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp); + } snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); return 0; } @@ -763,10 +757,9 @@ static int snd_ice1712_playback_ds_open(struct snd_pcm_substream *substream) ice->playback_con_substream_ds[substream->number] = substream; runtime->hw = snd_ice1712_playback_ds; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); tmp = inw(ICEDS(ice, INTMASK)) & ~(1 << (substream->number * 2)); outw(tmp, ICEDS(ice, INTMASK)); - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -796,10 +789,9 @@ static int snd_ice1712_playback_ds_close(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); u32 tmp; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); tmp = inw(ICEDS(ice, INTMASK)) | (3 << (substream->number * 2)); outw(tmp, ICEDS(ice, INTMASK)); - spin_unlock_irq(&ice->reg_lock); ice->playback_con_substream_ds[substream->number] = NULL; return 0; } @@ -911,14 +903,13 @@ static int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream, return -EINVAL; what = ICE1712_PLAYBACK_PAUSE; snd_pcm_trigger_done(substream, substream); - spin_lock(&ice->reg_lock); + guard(spinlock)(&ice->reg_lock); old = inl(ICEMT(ice, PLAYBACK_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) old |= what; else old &= ~what; outl(old, ICEMT(ice, PLAYBACK_CONTROL)); - spin_unlock(&ice->reg_lock); break; } case SNDRV_PCM_TRIGGER_START: @@ -937,14 +928,13 @@ static int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream, snd_pcm_trigger_done(s, substream); } } - spin_lock(&ice->reg_lock); + guard(spinlock)(&ice->reg_lock); old = inl(ICEMT(ice, PLAYBACK_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_START) old |= what; else old &= ~what; outl(old, ICEMT(ice, PLAYBACK_CONTROL)); - spin_unlock(&ice->reg_lock); break; } default: @@ -957,7 +947,6 @@ static int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream, */ static void snd_ice1712_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, int force) { - unsigned long flags; unsigned char val, old; unsigned int i; @@ -982,24 +971,21 @@ static void snd_ice1712_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, break; } - spin_lock_irqsave(&ice->reg_lock, flags); - if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW| - ICE1712_PLAYBACK_PAUSE| - ICE1712_PLAYBACK_START)) { -__out: - spin_unlock_irqrestore(&ice->reg_lock, flags); - return; - } - if (!force && is_pro_rate_locked(ice)) - goto __out; + scoped_guard(spinlock_irqsave, &ice->reg_lock) { + if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW| + ICE1712_PLAYBACK_PAUSE| + ICE1712_PLAYBACK_START)) + return; + if (!force && is_pro_rate_locked(ice)) + return; - old = inb(ICEMT(ice, RATE)); - if (!force && old == val) - goto __out; + old = inb(ICEMT(ice, RATE)); + if (!force && old == val) + return; - ice->cur_rate = rate; - outb(val, ICEMT(ice, RATE)); - spin_unlock_irqrestore(&ice->reg_lock, flags); + ice->cur_rate = rate; + outb(val, ICEMT(ice, RATE)); + } if (ice->gpio.set_pro_rate) ice->gpio.set_pro_rate(ice, rate); @@ -1016,11 +1002,10 @@ static int snd_ice1712_playback_pro_prepare(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream); - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR)); outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE)); outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT)); - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -1039,11 +1024,10 @@ static int snd_ice1712_capture_pro_prepare(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream); - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR)); outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE)); outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, CAPTURE_COUNT)); - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -1258,12 +1242,11 @@ static int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struc int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); ucontrol->value.integer.value[0] = !((ice->pro_volumes[priv_idx] >> 15) & 1); ucontrol->value.integer.value[1] = !((ice->pro_volumes[priv_idx] >> 31) & 1); - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -1276,12 +1259,11 @@ static int snd_ice1712_pro_mixer_switch_put(struct snd_kcontrol *kcontrol, struc nval = (ucontrol->value.integer.value[0] ? 0 : 0x00008000) | (ucontrol->value.integer.value[1] ? 0 : 0x80000000); - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); nval |= ice->pro_volumes[priv_idx] & ~0x80008000; change = nval != ice->pro_volumes[priv_idx]; ice->pro_volumes[priv_idx] = nval; snd_ice1712_update_volume(ice, priv_idx); - spin_unlock_irq(&ice->reg_lock); return change; } @@ -1300,12 +1282,11 @@ static int snd_ice1712_pro_mixer_volume_get(struct snd_kcontrol *kcontrol, struc int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); ucontrol->value.integer.value[0] = (ice->pro_volumes[priv_idx] >> 0) & 127; ucontrol->value.integer.value[1] = (ice->pro_volumes[priv_idx] >> 16) & 127; - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -1318,12 +1299,11 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc nval = (ucontrol->value.integer.value[0] & 127) | ((ucontrol->value.integer.value[1] & 127) << 16); - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); nval |= ice->pro_volumes[priv_idx] & ~0x007f007f; change = nval != ice->pro_volumes[priv_idx]; ice->pro_volumes[priv_idx] = nval; snd_ice1712_update_volume(ice, priv_idx); - spin_unlock_irq(&ice->reg_lock); return change; } @@ -1781,7 +1761,7 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol, }; unsigned char val; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); if (is_spdif_master(ice)) { ucontrol->value.enumerated.item[0] = 13; } else { @@ -1792,7 +1772,6 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol, } ucontrol->value.enumerated.item[0] = val; } - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -1916,10 +1895,9 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol, int change = 0, nval; nval = ucontrol->value.integer.value[0] ? 1 : 0; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); change = PRO_RATE_LOCKED != nval; PRO_RATE_LOCKED = nval; - spin_unlock_irq(&ice->reg_lock); return change; } @@ -1947,10 +1925,9 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol, int change = 0, nval; nval = ucontrol->value.integer.value[0] ? 1 : 0; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); change = PRO_RATE_RESET != nval; PRO_RATE_RESET = nval; - spin_unlock_irq(&ice->reg_lock); return change; } @@ -1986,10 +1963,10 @@ static int snd_ice1712_pro_route_analog_get(struct snd_kcontrol *kcontrol, int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned int val, cval; - spin_lock_irq(&ice->reg_lock); - val = inw(ICEMT(ice, ROUTE_PSDOUT03)); - cval = inl(ICEMT(ice, ROUTE_CAPTURE)); - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + val = inw(ICEMT(ice, ROUTE_PSDOUT03)); + cval = inl(ICEMT(ice, ROUTE_CAPTURE)); + } val >>= ((idx % 2) * 8) + ((idx / 2) * 2); val &= 3; @@ -2023,35 +2000,35 @@ static int snd_ice1712_pro_route_analog_put(struct snd_kcontrol *kcontrol, else nval = 0; /* pcm */ shift = ((idx % 2) * 8) + ((idx / 2) * 2); - spin_lock_irq(&ice->reg_lock); - val = old_val = inw(ICEMT(ice, ROUTE_PSDOUT03)); - val &= ~(0x03 << shift); - val |= nval << shift; - change = val != old_val; - if (change) - outw(val, ICEMT(ice, ROUTE_PSDOUT03)); - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + val = old_val = inw(ICEMT(ice, ROUTE_PSDOUT03)); + val &= ~(0x03 << shift); + val |= nval << shift; + change = val != old_val; + if (change) + outw(val, ICEMT(ice, ROUTE_PSDOUT03)); + } if (nval < 2) /* dig mixer of pcm */ return change; /* update CAPTURE */ - spin_lock_irq(&ice->reg_lock); - val = old_val = inl(ICEMT(ice, ROUTE_CAPTURE)); - shift = ((idx / 2) * 8) + ((idx % 2) * 4); - if (nval == 2) { /* analog in */ - nval = ucontrol->value.enumerated.item[0] - 1; - val &= ~(0x07 << shift); - val |= nval << shift; - } else { /* spdif in */ - nval = (ucontrol->value.enumerated.item[0] - 9) << 3; - val &= ~(0x08 << shift); - val |= nval << shift; - } - if (val != old_val) { - change = 1; - outl(val, ICEMT(ice, ROUTE_CAPTURE)); + scoped_guard(spinlock_irq, &ice->reg_lock) { + val = old_val = inl(ICEMT(ice, ROUTE_CAPTURE)); + shift = ((idx / 2) * 8) + ((idx % 2) * 4); + if (nval == 2) { /* analog in */ + nval = ucontrol->value.enumerated.item[0] - 1; + val &= ~(0x07 << shift); + val |= nval << shift; + } else { /* spdif in */ + nval = (ucontrol->value.enumerated.item[0] - 9) << 3; + val &= ~(0x08 << shift); + val |= nval << shift; + } + if (val != old_val) { + change = 1; + outl(val, ICEMT(ice, ROUTE_CAPTURE)); + } } - spin_unlock_irq(&ice->reg_lock); return change; } @@ -2084,7 +2061,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, unsigned int val, old_val, nval; /* update SPDOUT */ - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); val = old_val = inw(ICEMT(ice, ROUTE_SPDOUT)); if (ucontrol->value.enumerated.item[0] >= 11) nval = 1; @@ -2110,7 +2087,6 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, change = val != old_val; if (change) outw(val, ICEMT(ice, ROUTE_SPDOUT)); - spin_unlock_irq(&ice->reg_lock); return change; } @@ -2157,10 +2133,9 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int change; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); change = inb(ICEMT(ice, MONITOR_RATE)) != ucontrol->value.integer.value[0]; outb(ucontrol->value.integer.value[0], ICEMT(ice, MONITOR_RATE)); - spin_unlock_irq(&ice->reg_lock); return change; } @@ -2188,12 +2163,11 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); for (idx = 0; idx < 22; idx++) { outb(idx, ICEMT(ice, MONITOR_PEAKINDEX)); ucontrol->value.integer.value[idx] = inb(ICEMT(ice, MONITOR_PEAKDATA)); } - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -2675,11 +2649,11 @@ static int snd_ice1712_suspend(struct device *dev) snd_ac97_suspend(ice->ac97); - spin_lock_irq(&ice->reg_lock); - ice->pm_saved_is_spdif_master = is_spdif_master(ice); - ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT)); - ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03)); - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + ice->pm_saved_is_spdif_master = is_spdif_master(ice); + ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT)); + ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03)); + } if (ice->pm_suspend) ice->pm_suspend(ice); @@ -2712,10 +2686,10 @@ static int snd_ice1712_resume(struct device *dev) if (ice->pm_saved_is_spdif_master) { /* switching to external clock via SPDIF */ - spin_lock_irq(&ice->reg_lock); - outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER, - ICEMT(ice, RATE)); - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER, + ICEMT(ice, RATE)); + } snd_ice1712_set_input_clock_source(ice, 1); } else { /* internal on-card clock */ diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 5bf90e2fd19105..e2dbbbfbca9fa1 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -288,9 +288,8 @@ static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, { struct snd_ice1712 *ice = substream->rmidi->private_data; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); enable_midi_irq(ice, flag, enable); - spin_unlock_irq(&ice->reg_lock); } static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) @@ -306,9 +305,8 @@ static int vt1724_midi_output_close(struct snd_rawmidi_substream *s) static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) { struct snd_ice1712 *ice = s->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&ice->reg_lock, flags); + guard(spinlock_irqsave)(&ice->reg_lock); if (up) { ice->midi_output = 1; vt1724_midi_write(ice); @@ -316,7 +314,6 @@ static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) ice->midi_output = 0; enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); } - spin_unlock_irqrestore(&ice->reg_lock, flags); } static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) @@ -357,16 +354,14 @@ static int vt1724_midi_input_close(struct snd_rawmidi_substream *s) static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) { struct snd_ice1712 *ice = s->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&ice->reg_lock, flags); + guard(spinlock_irqsave)(&ice->reg_lock); if (up) { ice->midi_input = 1; vt1724_midi_read(ice); } else { ice->midi_input = 0; } - spin_unlock_irqrestore(&ice->reg_lock, flags); } static const struct snd_rawmidi_ops vt1724_midi_input_ops = { @@ -394,40 +389,39 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) status &= status_mask; if (status == 0) break; - spin_lock(&ice->reg_lock); - if (++timeout > 10) { - status = inb(ICEREG1724(ice, IRQSTAT)); - dev_err(ice->card->dev, - "Too long irq loop, status = 0x%x\n", status); + scoped_guard(spinlock, &ice->reg_lock) { + if (++timeout > 10) { + status = inb(ICEREG1724(ice, IRQSTAT)); + dev_err(ice->card->dev, + "Too long irq loop, status = 0x%x\n", status); + if (status & VT1724_IRQ_MPU_TX) { + dev_err(ice->card->dev, "Disabling MPU_TX\n"); + enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); + } + goto out; + } + handled = 1; if (status & VT1724_IRQ_MPU_TX) { - dev_err(ice->card->dev, "Disabling MPU_TX\n"); - enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); + if (ice->midi_output) + vt1724_midi_write(ice); + else + enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); + /* Due to mysterical reasons, MPU_TX is always + * generated (and can't be cleared) when a PCM + * playback is going. So let's ignore at the + * next loop. + */ + status_mask &= ~VT1724_IRQ_MPU_TX; } - spin_unlock(&ice->reg_lock); - break; - } - handled = 1; - if (status & VT1724_IRQ_MPU_TX) { - if (ice->midi_output) - vt1724_midi_write(ice); - else - enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); - /* Due to mysterical reasons, MPU_TX is always - * generated (and can't be cleared) when a PCM - * playback is going. So let's ignore at the - * next loop. - */ - status_mask &= ~VT1724_IRQ_MPU_TX; - } - if (status & VT1724_IRQ_MPU_RX) { - if (ice->midi_input) - vt1724_midi_read(ice); - else - vt1724_midi_clear_rx(ice); + if (status & VT1724_IRQ_MPU_RX) { + if (ice->midi_input) + vt1724_midi_read(ice); + else + vt1724_midi_clear_rx(ice); + } + /* ack MPU irq */ + outb(status, ICEREG1724(ice, IRQSTAT)); } - /* ack MPU irq */ - outb(status, ICEREG1724(ice, IRQSTAT)); - spin_unlock(&ice->reg_lock); if (status & VT1724_IRQ_MTPCM) { /* * Multi-track PCM @@ -481,6 +475,7 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) } } + out: return IRQ_RETVAL(handled); } @@ -539,27 +534,27 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - spin_lock(&ice->reg_lock); - old = inb(ICEMT1724(ice, DMA_PAUSE)); - if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) - old |= what; - else - old &= ~what; - outb(old, ICEMT1724(ice, DMA_PAUSE)); - spin_unlock(&ice->reg_lock); + scoped_guard(spinlock, &ice->reg_lock) { + old = inb(ICEMT1724(ice, DMA_PAUSE)); + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) + old |= what; + else + old &= ~what; + outb(old, ICEMT1724(ice, DMA_PAUSE)); + } break; case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - spin_lock(&ice->reg_lock); - old = inb(ICEMT1724(ice, DMA_CONTROL)); - if (cmd == SNDRV_PCM_TRIGGER_START) - old |= what; - else - old &= ~what; - outb(old, ICEMT1724(ice, DMA_CONTROL)); - spin_unlock(&ice->reg_lock); + scoped_guard(spinlock, &ice->reg_lock) { + old = inb(ICEMT1724(ice, DMA_CONTROL)); + if (cmd == SNDRV_PCM_TRIGGER_START) + old |= what; + else + old &= ~what; + outb(old, ICEMT1724(ice, DMA_CONTROL)); + } break; case SNDRV_PCM_TRIGGER_RESUME: @@ -625,7 +620,6 @@ static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice, static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, int force) { - unsigned long flags; unsigned char mclk_change; unsigned int i, old_rate; bool call_set_rate = false; @@ -633,34 +627,31 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, if (rate > ice->hw_rates->list[ice->hw_rates->count - 1]) return -EINVAL; - spin_lock_irqsave(&ice->reg_lock, flags); - if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || - (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { - /* running? we cannot change the rate now... */ - spin_unlock_irqrestore(&ice->reg_lock, flags); - return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY; - } - if (!force && is_pro_rate_locked(ice)) { - /* comparing required and current rate - makes sense for - * internal clock only */ - spin_unlock_irqrestore(&ice->reg_lock, flags); - return (rate == ice->cur_rate) ? 0 : -EBUSY; - } + scoped_guard(spinlock_irqsave, &ice->reg_lock) { + if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || + (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { + /* running? we cannot change the rate now... */ + return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY; + } + if (!force && is_pro_rate_locked(ice)) { + /* comparing required and current rate - makes sense for + * internal clock only */ + return (rate == ice->cur_rate) ? 0 : -EBUSY; + } - if (force || !ice->is_spdif_master(ice)) { - /* force means the rate was switched by ucontrol, otherwise - * setting clock rate for internal clock mode */ - old_rate = ice->get_rate(ice); - if (force || (old_rate != rate)) - call_set_rate = true; - else if (rate == ice->cur_rate) { - spin_unlock_irqrestore(&ice->reg_lock, flags); - return 0; + if (force || !ice->is_spdif_master(ice)) { + /* force means the rate was switched by ucontrol, otherwise + * setting clock rate for internal clock mode */ + old_rate = ice->get_rate(ice); + if (force || (old_rate != rate)) + call_set_rate = true; + else if (rate == ice->cur_rate) { + return 0; + } } - } - ice->cur_rate = rate; - spin_unlock_irqrestore(&ice->reg_lock, flags); + ice->cur_rate = rate; + } if (call_set_rate) ice->set_rate(ice, rate); @@ -755,7 +746,7 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream) unsigned char val; unsigned int size; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); val = (8 - substream->runtime->channels) >> 1; outb(val, ICEMT1724(ice, BURST)); @@ -770,8 +761,6 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream) outw(size, ICEMT1724(ice, PLAYBACK_COUNT)); outb(size >> 16, ICEMT1724(ice, PLAYBACK_COUNT) + 2); - spin_unlock_irq(&ice->reg_lock); - /* dev_dbg(ice->card->dev, "pro prepare: ch = %d, addr = 0x%x, " "buffer = 0x%x, period = 0x%x\n", @@ -825,13 +814,12 @@ static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); const struct vt1724_pcm_reg *reg = substream->runtime->private_data; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); outl(substream->runtime->dma_addr, ice->profi_port + reg->addr); outw((snd_pcm_lib_buffer_bytes(substream) >> 2) - 1, ice->profi_port + reg->size); outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ice->profi_port + reg->count); - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -1160,9 +1148,8 @@ static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val) static void update_spdif_rate(struct snd_ice1712 *ice, unsigned int rate) { unsigned int val, nval; - unsigned long flags; - spin_lock_irqsave(&ice->reg_lock, flags); + guard(spinlock_irqsave)(&ice->reg_lock); nval = val = inw(ICEMT1724(ice, SPDIF_CTRL)); nval &= ~(7 << 12); switch (rate) { @@ -1176,7 +1163,6 @@ static void update_spdif_rate(struct snd_ice1712 *ice, unsigned int rate) } if (val != nval) update_spdif_bits(ice, nval); - spin_unlock_irqrestore(&ice->reg_lock, flags); } static int snd_vt1724_playback_spdif_prepare(struct snd_pcm_substream *substream) @@ -1362,11 +1348,11 @@ static int snd_vt1724_playback_indep_prepare(struct snd_pcm_substream *substream struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); unsigned char val; - spin_lock_irq(&ice->reg_lock); - val = 3 - substream->number; - if (inb(ICEMT1724(ice, BURST)) < val) - outb(val, ICEMT1724(ice, BURST)); - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + val = 3 - substream->number; + if (inb(ICEMT1724(ice, BURST)) < val) + outb(val, ICEMT1724(ice, BURST)); + } return snd_vt1724_pcm_prepare(substream); } @@ -1664,11 +1650,10 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol, unsigned int val, old; val = encode_spdif_bits(&ucontrol->value.iec958); - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); old = inw(ICEMT1724(ice, SPDIF_CTRL)); if (val != old) update_spdif_bits(ice, val); - spin_unlock_irq(&ice->reg_lock); return val != old; } @@ -1739,14 +1724,13 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned char old, val; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); old = val = inb(ICEREG1724(ice, SPDIF_CFG)); val &= ~VT1724_CFG_SPDIF_OUT_EN; if (ucontrol->value.integer.value[0]) val |= VT1724_CFG_SPDIF_OUT_EN; if (old != val) outb(val, ICEREG1724(ice, SPDIF_CFG)); - spin_unlock_irq(&ice->reg_lock); return old != val; } @@ -1842,7 +1826,7 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int i, rate; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); if (ice->is_spdif_master(ice)) { ucontrol->value.enumerated.item[0] = ice->hw_rates->count + ice->get_spdif_master_type(ice); @@ -1856,7 +1840,6 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol, } } } - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -1887,29 +1870,31 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, unsigned int old_rate, new_rate; unsigned int item = ucontrol->value.enumerated.item[0]; unsigned int first_ext_clock = ice->hw_rates->count; + bool set_pro_rate = false; if (item > first_ext_clock + ice->ext_clock_count - 1) return -EINVAL; /* if rate = 0 => external clock */ - spin_lock_irq(&ice->reg_lock); - if (ice->is_spdif_master(ice)) - old_rate = 0; - else - old_rate = ice->get_rate(ice); - if (item >= first_ext_clock) { - /* switching to external clock */ - ice->set_spdif_clock(ice, item - first_ext_clock); - new_rate = 0; - } else { - /* internal on-card clock */ - new_rate = ice->hw_rates->list[item]; - ice->pro_rate_default = new_rate; - spin_unlock_irq(&ice->reg_lock); - snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); - spin_lock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + if (ice->is_spdif_master(ice)) + old_rate = 0; + else + old_rate = ice->get_rate(ice); + if (item >= first_ext_clock) { + /* switching to external clock */ + ice->set_spdif_clock(ice, item - first_ext_clock); + new_rate = 0; + } else { + /* internal on-card clock */ + new_rate = ice->hw_rates->list[item]; + ice->pro_rate_default = new_rate; + set_pro_rate = true; + } } - spin_unlock_irq(&ice->reg_lock); + + if (set_pro_rate) + snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); /* the first switch to the ext. clock mode? */ if (old_rate != new_rate && !new_rate) { @@ -1949,10 +1934,9 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol, int change = 0, nval; nval = ucontrol->value.integer.value[0] ? 1 : 0; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); change = PRO_RATE_LOCKED != nval; PRO_RATE_LOCKED = nval; - spin_unlock_irq(&ice->reg_lock); return change; } @@ -1980,10 +1964,9 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol, int change = 0, nval; nval = ucontrol->value.integer.value[0] ? 1 : 0; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); change = PRO_RATE_RESET != nval; PRO_RATE_RESET = nval; - spin_unlock_irq(&ice->reg_lock); return change; } @@ -2138,13 +2121,12 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx; - spin_lock_irq(&ice->reg_lock); + guard(spinlock_irq)(&ice->reg_lock); for (idx = 0; idx < 22; idx++) { outb(idx, ICEMT1724(ice, MONITOR_PEAKINDEX)); ucontrol->value.integer.value[idx] = inb(ICEMT1724(ice, MONITOR_PEAKDATA)); } - spin_unlock_irq(&ice->reg_lock); return 0; } @@ -2689,12 +2671,12 @@ static int snd_vt1724_suspend(struct device *dev) snd_ac97_suspend(ice->ac97); - spin_lock_irq(&ice->reg_lock); - ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice); - ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL)); - ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG)); - ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK)); - spin_unlock_irq(&ice->reg_lock); + scoped_guard(spinlock_irq, &ice->reg_lock) { + ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice); + ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL)); + ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG)); + ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK)); + } if (ice->pm_suspend) ice->pm_suspend(ice); From 220a76bbf750db588c260d3a6b9ae1f9e342ee55 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:11 +0200 Subject: [PATCH 0946/1292] ALSA: intel8x0: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-37-tiwai@suse.de --- sound/pci/intel8x0.c | 178 +++++++++++++++++++++--------------------- sound/pci/intel8x0m.c | 8 +- 2 files changed, 89 insertions(+), 97 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 9e6a5065ffbf56..3b53c5e63c298e 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -690,52 +690,51 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ichdev) { unsigned long port = ichdev->reg_offset; - unsigned long flags; int status, civ, i, step; int ack = 0; if (!(ichdev->prepared || chip->in_measurement) || ichdev->suspended) return; - spin_lock_irqsave(&chip->reg_lock, flags); - status = igetbyte(chip, port + ichdev->roff_sr); - civ = igetbyte(chip, port + ICH_REG_OFF_CIV); - if (!(status & ICH_BCIS)) { - step = 0; - } else if (civ == ichdev->civ) { - step = 1; - ichdev->civ++; - ichdev->civ &= ICH_REG_LVI_MASK; - } else { - step = civ - ichdev->civ; - if (step < 0) - step += ICH_REG_LVI_MASK + 1; - ichdev->civ = civ; - } - - ichdev->position += step * ichdev->fragsize1; - if (! chip->in_measurement) - ichdev->position %= ichdev->size; - ichdev->lvi += step; - ichdev->lvi &= ICH_REG_LVI_MASK; - iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); - for (i = 0; i < step; i++) { - ichdev->lvi_frag++; - ichdev->lvi_frag %= ichdev->frags; - ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + status = igetbyte(chip, port + ichdev->roff_sr); + civ = igetbyte(chip, port + ICH_REG_OFF_CIV); + if (!(status & ICH_BCIS)) { + step = 0; + } else if (civ == ichdev->civ) { + step = 1; + ichdev->civ++; + ichdev->civ &= ICH_REG_LVI_MASK; + } else { + step = civ - ichdev->civ; + if (step < 0) + step += ICH_REG_LVI_MASK + 1; + ichdev->civ = civ; + } + + ichdev->position += step * ichdev->fragsize1; + if (! chip->in_measurement) + ichdev->position %= ichdev->size; + ichdev->lvi += step; + ichdev->lvi &= ICH_REG_LVI_MASK; + iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); + for (i = 0; i < step; i++) { + ichdev->lvi_frag++; + ichdev->lvi_frag %= ichdev->frags; + ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); #if 0 - dev_dbg(chip->card->dev, - "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", - ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], - ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), - inl(port + 4), inb(port + ICH_REG_OFF_CR)); + dev_dbg(chip->card->dev, + "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", + ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], + ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), + inl(port + 4), inb(port + ICH_REG_OFF_CR)); #endif - if (--ichdev->ack == 0) { - ichdev->ack = ichdev->ack_reload; - ack = 1; + if (--ichdev->ack == 0) { + ichdev->ack = ichdev->ack_reload; + ack = 1; + } } } - spin_unlock_irqrestore(&chip->reg_lock, flags); if (ack && ichdev->substream) { snd_pcm_period_elapsed(ichdev->substream); } @@ -917,7 +916,7 @@ static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, unsigned int cnt; int dbl = runtime->rate > 48000; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); switch (chip->device_type) { case DEVICE_ALI: cnt = igetdword(chip, ICHREG(ALI_SCR)); @@ -963,7 +962,6 @@ static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, iputdword(chip, ICHREG(GLOB_CNT), cnt); break; } - spin_unlock_irq(&chip->reg_lock); } static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) @@ -993,7 +991,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs int civ, timeout = 10; unsigned int position; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); do { civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); @@ -1033,7 +1031,6 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs } } ichdev->last_pos = ptr; - spin_unlock(&chip->reg_lock); if (ptr >= ichdev->size) return 0; return bytes_to_frames(substream->runtime, ptr); @@ -1235,12 +1232,12 @@ static int snd_intel8x0_ali_ac97spdifout_open(struct snd_pcm_substream *substrea struct intel8x0 *chip = snd_pcm_substream_chip(substream); unsigned int val; - spin_lock_irq(&chip->reg_lock); - val = igetdword(chip, ICHREG(ALI_INTERFACECR)); - val |= ICH_ALI_IF_AC97SP; - iputdword(chip, ICHREG(ALI_INTERFACECR), val); - /* also needs to set ALI_SC_CODEC_SPDF correctly */ - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + val = igetdword(chip, ICHREG(ALI_INTERFACECR)); + val |= ICH_ALI_IF_AC97SP; + iputdword(chip, ICHREG(ALI_INTERFACECR), val); + /* also needs to set ALI_SC_CODEC_SPDF correctly */ + } return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_AC97SPDIFOUT]); } @@ -1251,11 +1248,10 @@ static int snd_intel8x0_ali_ac97spdifout_close(struct snd_pcm_substream *substre unsigned int val; chip->ichd[ALID_AC97SPDIFOUT].substream = NULL; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); val = igetdword(chip, ICHREG(ALI_INTERFACECR)); val &= ~ICH_ALI_IF_AC97SP; iputdword(chip, ICHREG(ALI_INTERFACECR), val); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -2662,53 +2658,53 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) } snd_intel8x0_setup_periods(chip, ichdev); port = ichdev->reg_offset; - spin_lock_irq(&chip->reg_lock); - chip->in_measurement = 1; - /* trigger */ - if (chip->device_type != DEVICE_ALI) - iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM); - else { - iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); - iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); + scoped_guard(spinlock_irq, &chip->reg_lock) { + chip->in_measurement = 1; + /* trigger */ + if (chip->device_type != DEVICE_ALI) + iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM); + else { + iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); + iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); + } + start_time = ktime_get(); } - start_time = ktime_get(); - spin_unlock_irq(&chip->reg_lock); msleep(50); - spin_lock_irq(&chip->reg_lock); - /* check the position */ - do { - civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); - pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); - if (pos1 == 0) { - udelay(10); - continue; + scoped_guard(spinlock_irq, &chip->reg_lock) { + /* check the position */ + do { + civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); + pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); + if (pos1 == 0) { + udelay(10); + continue; + } + if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && + pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) + break; + } while (timeout--); + if (pos1 == 0) { /* oops, this value is not reliable */ + pos = 0; + } else { + pos = ichdev->fragsize1; + pos -= pos1 << ichdev->pos_shift; + pos += ichdev->position; } - if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && - pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) - break; - } while (timeout--); - if (pos1 == 0) { /* oops, this value is not reliable */ - pos = 0; - } else { - pos = ichdev->fragsize1; - pos -= pos1 << ichdev->pos_shift; - pos += ichdev->position; - } - chip->in_measurement = 0; - stop_time = ktime_get(); - /* stop */ - if (chip->device_type == DEVICE_ALI) { - iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); - iputbyte(chip, port + ICH_REG_OFF_CR, 0); - while (igetbyte(chip, port + ICH_REG_OFF_CR)) - ; - } else { - iputbyte(chip, port + ICH_REG_OFF_CR, 0); - while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) - ; + chip->in_measurement = 0; + stop_time = ktime_get(); + /* stop */ + if (chip->device_type == DEVICE_ALI) { + iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); + iputbyte(chip, port + ICH_REG_OFF_CR, 0); + while (igetbyte(chip, port + ICH_REG_OFF_CR)) + ; + } else { + iputbyte(chip, port + ICH_REG_OFF_CR, 0); + while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) + ; + } + iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); } - iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); - spin_unlock_irq(&chip->reg_lock); if (pos == 0) { dev_err(chip->card->dev, diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 9e5988583abe91..84e1b7ea34e2a6 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -471,16 +471,13 @@ static irqreturn_t snd_intel8x0m_interrupt(int irq, void *dev_id) unsigned int status; unsigned int i; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); status = igetdword(chip, chip->int_sta_reg); - if (status == 0xffffffff) { /* we are not yet resumed */ - spin_unlock(&chip->reg_lock); + if (status == 0xffffffff) /* we are not yet resumed */ return IRQ_NONE; - } if ((status & chip->int_sta_mask) == 0) { if (status) iputdword(chip, chip->int_sta_reg, status); - spin_unlock(&chip->reg_lock); return IRQ_NONE; } @@ -492,7 +489,6 @@ static irqreturn_t snd_intel8x0m_interrupt(int irq, void *dev_id) /* ack them */ iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask); - spin_unlock(&chip->reg_lock); return IRQ_HANDLED; } From 940653fff03a647357efe3ce6e0d89dc2bcbee2e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:12 +0200 Subject: [PATCH 0947/1292] ALSA: korg1212: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-38-tiwai@suse.de --- sound/pci/korg1212/korg1212.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 0a66d5cfc090ea..26c515ec76e9b2 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -606,13 +606,12 @@ static int snd_korg1212_OpenCard(struct snd_korg1212 * korg1212) { K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt); - mutex_lock(&korg1212->open_mutex); + guard(mutex)(&korg1212->open_mutex); if (korg1212->opencnt++ == 0) { snd_korg1212_TurnOffIdleMonitor(korg1212); snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN); } - mutex_unlock(&korg1212->open_mutex); return 1; } @@ -621,11 +620,9 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212) K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt); - mutex_lock(&korg1212->open_mutex); - if (--(korg1212->opencnt)) { - mutex_unlock(&korg1212->open_mutex); + guard(mutex)(&korg1212->open_mutex); + if (--(korg1212->opencnt)) return 0; - } if (korg1212->cardState == K1212_STATE_SETUP) { int rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, @@ -633,10 +630,8 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212) if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard - RC = %d [%s]\n", rc, stateName[korg1212->cardState]); - if (rc != K1212_CMDRET_Success) { - mutex_unlock(&korg1212->open_mutex); + if (rc != K1212_CMDRET_Success) return 0; - } } else if (korg1212->cardState > K1212_STATE_SETUP) { snd_korg1212_SendStopAndWait(korg1212); } @@ -646,7 +641,6 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212) snd_korg1212_setCardState(korg1212, K1212_STATE_READY); } - mutex_unlock(&korg1212->open_mutex); return 0; } From aff742c156bb070ac05833f0a8565fa307fa4d13 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:13 +0200 Subject: [PATCH 0948/1292] ALSA: korg1212: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-39-tiwai@suse.de --- sound/pci/korg1212/korg1212.c | 168 ++++++++++++---------------------- 1 file changed, 58 insertions(+), 110 deletions(-) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 26c515ec76e9b2..d16acf83668a10 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -568,25 +568,19 @@ static void snd_korg1212_SendStop(struct snd_korg1212 *korg1212) static void snd_korg1212_SendStopAndWait(struct snd_korg1212 *korg1212) { - unsigned long flags; - spin_lock_irqsave(&korg1212->lock, flags); - snd_korg1212_SendStop(korg1212); - spin_unlock_irqrestore(&korg1212->lock, flags); + scoped_guard(spinlock_irqsave, &korg1212->lock) { + snd_korg1212_SendStop(korg1212); + } wait_event_timeout(korg1212->wait, !korg1212->dsp_stop_processing, HZ); } static int snd_korg1212_TurnOnIdleMonitor(struct snd_korg1212 *korg1212) { - unsigned long flags; - int rc; - udelay(INTERCOMMAND_DELAY); - spin_lock_irqsave(&korg1212->lock, flags); + guard(spinlock_irqsave)(&korg1212->lock); korg1212->idleMonitorOn = 1; - rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, - K1212_MODE_MonitorOn, 0, 0, 0); - spin_unlock_irqrestore(&korg1212->lock, flags); - return rc; + return snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, + K1212_MODE_MonitorOn, 0, 0, 0); } static void snd_korg1212_TurnOffIdleMonitor(struct snd_korg1212 *korg1212) @@ -838,7 +832,6 @@ static int snd_korg1212_WriteADCSensitivity(struct snd_korg1212 *korg1212) u16 controlValue; // this keeps the current value to be written to // the card's eeprom control register. u16 count; - unsigned long flags; K1212_DEBUG_PRINTK("K1212_DEBUG: WriteADCSensivity [%s]\n", stateName[korg1212->cardState]); @@ -859,7 +852,7 @@ static int snd_korg1212_WriteADCSensitivity(struct snd_korg1212 *korg1212) } else monModeSet = 0; - spin_lock_irqsave(&korg1212->lock, flags); + guard(spinlock_irqsave)(&korg1212->lock); // ---------------------------------------------------------------------------- // we are about to send new values to the card, so clear the new values queued @@ -968,8 +961,6 @@ static int snd_korg1212_WriteADCSensitivity(struct snd_korg1212 *korg1212) rc, stateName[korg1212->cardState]); } - spin_unlock_irqrestore(&korg1212->lock, flags); - return 1; } @@ -1061,7 +1052,7 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) if (!doorbellValue) return IRQ_NONE; - spin_lock(&korg1212->lock); + guard(spinlock)(&korg1212->lock); writel(doorbellValue, korg1212->inDoorbellPtr); @@ -1139,8 +1130,6 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) korg1212->inIRQ--; - spin_unlock(&korg1212->lock); - return IRQ_HANDLED; } @@ -1326,7 +1315,6 @@ static void snd_korg1212_free_pcm(struct snd_pcm *pcm) static int snd_korg1212_playback_open(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; @@ -1338,15 +1326,13 @@ static int snd_korg1212_playback_open(struct snd_pcm_substream *substream) runtime->hw = snd_korg1212_playback_info; snd_pcm_set_runtime_buffer(substream, korg1212->dma_play); - spin_lock_irqsave(&korg1212->lock, flags); - - korg1212->playback_substream = substream; - korg1212->playback_pid = current->pid; - korg1212->periodsize = K1212_PERIODS; - korg1212->channels = K1212_CHANNELS; - korg1212->errorcnt = 0; - - spin_unlock_irqrestore(&korg1212->lock, flags); + scoped_guard(spinlock_irqsave, &korg1212->lock) { + korg1212->playback_substream = substream; + korg1212->playback_pid = current->pid; + korg1212->periodsize = K1212_PERIODS; + korg1212->channels = K1212_CHANNELS; + korg1212->errorcnt = 0; + } snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames); @@ -1357,7 +1343,6 @@ static int snd_korg1212_playback_open(struct snd_pcm_substream *substream) static int snd_korg1212_capture_open(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; @@ -1369,14 +1354,12 @@ static int snd_korg1212_capture_open(struct snd_pcm_substream *substream) runtime->hw = snd_korg1212_capture_info; snd_pcm_set_runtime_buffer(substream, korg1212->dma_rec); - spin_lock_irqsave(&korg1212->lock, flags); - - korg1212->capture_substream = substream; - korg1212->capture_pid = current->pid; - korg1212->periodsize = K1212_PERIODS; - korg1212->channels = K1212_CHANNELS; - - spin_unlock_irqrestore(&korg1212->lock, flags); + scoped_guard(spinlock_irqsave, &korg1212->lock) { + korg1212->capture_substream = substream; + korg1212->capture_pid = current->pid; + korg1212->periodsize = K1212_PERIODS; + korg1212->channels = K1212_CHANNELS; + } snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames); @@ -1385,7 +1368,6 @@ static int snd_korg1212_capture_open(struct snd_pcm_substream *substream) static int snd_korg1212_playback_close(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_close [%s]\n", @@ -1393,13 +1375,11 @@ static int snd_korg1212_playback_close(struct snd_pcm_substream *substream) snd_korg1212_silence(korg1212, 0, K1212_MAX_SAMPLES, 0, korg1212->channels * 2); - spin_lock_irqsave(&korg1212->lock, flags); - - korg1212->playback_pid = -1; - korg1212->playback_substream = NULL; - korg1212->periodsize = 0; - - spin_unlock_irqrestore(&korg1212->lock, flags); + scoped_guard(spinlock_irqsave, &korg1212->lock) { + korg1212->playback_pid = -1; + korg1212->playback_substream = NULL; + korg1212->periodsize = 0; + } snd_korg1212_CloseCard(korg1212); return 0; @@ -1407,19 +1387,16 @@ static int snd_korg1212_playback_close(struct snd_pcm_substream *substream) static int snd_korg1212_capture_close(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_close [%s]\n", stateName[korg1212->cardState]); - spin_lock_irqsave(&korg1212->lock, flags); - - korg1212->capture_pid = -1; - korg1212->capture_substream = NULL; - korg1212->periodsize = 0; - - spin_unlock_irqrestore(&korg1212->lock, flags); + scoped_guard(spinlock_irqsave, &korg1212->lock) { + korg1212->capture_pid = -1; + korg1212->capture_substream = NULL; + korg1212->periodsize = 0; + } snd_korg1212_CloseCard(korg1212); return 0; @@ -1445,7 +1422,6 @@ static int snd_korg1212_ioctl(struct snd_pcm_substream *substream, static int snd_korg1212_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - unsigned long flags; struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); int err; pid_t this_pid; @@ -1454,7 +1430,7 @@ static int snd_korg1212_hw_params(struct snd_pcm_substream *substream, K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_hw_params [%s]\n", stateName[korg1212->cardState]); - spin_lock_irqsave(&korg1212->lock, flags); + guard(spinlock_irqsave)(&korg1212->lock); if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { this_pid = korg1212->playback_pid; @@ -1472,26 +1448,20 @@ static int snd_korg1212_hw_params(struct snd_pcm_substream *substream, */ if ((int)params_rate(params) != korg1212->clkRate) { - spin_unlock_irqrestore(&korg1212->lock, flags); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); return -EBUSY; } - spin_unlock_irqrestore(&korg1212->lock, flags); return 0; } err = snd_korg1212_SetRate(korg1212, params_rate(params)); - if (err < 0) { - spin_unlock_irqrestore(&korg1212->lock, flags); + if (err < 0) return err; - } korg1212->channels = params_channels(params); korg1212->periodsize = K1212_PERIOD_BYTES; - spin_unlock_irqrestore(&korg1212->lock, flags); - return 0; } @@ -1511,15 +1481,13 @@ static int snd_korg1212_prepare(struct snd_pcm_substream *substream) K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_prepare [%s]\n", stateName[korg1212->cardState]); - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); korg1212->dsp_stop_processing = 0; rc = snd_korg1212_SetupForPlay(korg1212); korg1212->currentBuffer = 0; - spin_unlock_irq(&korg1212->lock); - return rc ? -EINVAL : 0; } @@ -1532,7 +1500,7 @@ static int snd_korg1212_trigger(struct snd_pcm_substream *substream, K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger [%s] cmd=%d\n", stateName[korg1212->cardState], cmd); - spin_lock(&korg1212->lock); + guard(spinlock)(&korg1212->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* @@ -1560,7 +1528,6 @@ static int snd_korg1212_trigger(struct snd_pcm_substream *substream, rc = 1; break; } - spin_unlock(&korg1212->lock); return rc ? -EINVAL : 0; } @@ -1660,15 +1627,13 @@ static int snd_korg1212_control_phase_get(struct snd_kcontrol *kcontrol, struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol); int i = kcontrol->private_value; - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); u->value.integer.value[0] = korg1212->volumePhase[i]; if (i >= 8) u->value.integer.value[1] = korg1212->volumePhase[i+1]; - spin_unlock_irq(&korg1212->lock); - return 0; } @@ -1679,7 +1644,7 @@ static int snd_korg1212_control_phase_put(struct snd_kcontrol *kcontrol, int change = 0; int i, val; - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); i = kcontrol->private_value; @@ -1705,8 +1670,6 @@ static int snd_korg1212_control_phase_put(struct snd_kcontrol *kcontrol, } } - spin_unlock_irq(&korg1212->lock); - return change; } @@ -1726,7 +1689,7 @@ static int snd_korg1212_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol); int i; - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); i = kcontrol->private_value; u->value.integer.value[0] = abs(korg1212->sharedBufferPtr->volumeData[i]); @@ -1734,8 +1697,6 @@ static int snd_korg1212_control_volume_get(struct snd_kcontrol *kcontrol, if (i >= 8) u->value.integer.value[1] = abs(korg1212->sharedBufferPtr->volumeData[i+1]); - spin_unlock_irq(&korg1212->lock); - return 0; } @@ -1747,7 +1708,7 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol, int i; int val; - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); i = kcontrol->private_value; @@ -1773,8 +1734,6 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol, } } - spin_unlock_irq(&korg1212->lock); - return change; } @@ -1792,7 +1751,7 @@ static int snd_korg1212_control_route_get(struct snd_kcontrol *kcontrol, struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol); int i; - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); i = kcontrol->private_value; u->value.enumerated.item[0] = korg1212->sharedBufferPtr->routeData[i]; @@ -1800,8 +1759,6 @@ static int snd_korg1212_control_route_get(struct snd_kcontrol *kcontrol, if (i >= 8) u->value.enumerated.item[1] = korg1212->sharedBufferPtr->routeData[i+1]; - spin_unlock_irq(&korg1212->lock); - return 0; } @@ -1811,7 +1768,7 @@ static int snd_korg1212_control_route_put(struct snd_kcontrol *kcontrol, struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol); int change = 0, i; - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); i = kcontrol->private_value; @@ -1831,8 +1788,6 @@ static int snd_korg1212_control_route_put(struct snd_kcontrol *kcontrol, } } - spin_unlock_irq(&korg1212->lock); - return change; } @@ -1851,13 +1806,11 @@ static int snd_korg1212_control_get(struct snd_kcontrol *kcontrol, { struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); u->value.integer.value[0] = korg1212->leftADCInSens; u->value.integer.value[1] = korg1212->rightADCInSens; - spin_unlock_irq(&korg1212->lock); - return 0; } @@ -1867,22 +1820,20 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol, struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol); int change = 0; - spin_lock_irq(&korg1212->lock); - - if (u->value.integer.value[0] >= k1212MinADCSens && - u->value.integer.value[0] <= k1212MaxADCSens && - u->value.integer.value[0] != korg1212->leftADCInSens) { - korg1212->leftADCInSens = u->value.integer.value[0]; - change = 1; - } - if (u->value.integer.value[1] >= k1212MinADCSens && - u->value.integer.value[1] <= k1212MaxADCSens && - u->value.integer.value[1] != korg1212->rightADCInSens) { - korg1212->rightADCInSens = u->value.integer.value[1]; - change = 1; - } - - spin_unlock_irq(&korg1212->lock); + scoped_guard(spinlock_irq, &korg1212->lock) { + if (u->value.integer.value[0] >= k1212MinADCSens && + u->value.integer.value[0] <= k1212MaxADCSens && + u->value.integer.value[0] != korg1212->leftADCInSens) { + korg1212->leftADCInSens = u->value.integer.value[0]; + change = 1; + } + if (u->value.integer.value[1] >= k1212MinADCSens && + u->value.integer.value[1] <= k1212MaxADCSens && + u->value.integer.value[1] != korg1212->rightADCInSens) { + korg1212->rightADCInSens = u->value.integer.value[1]; + change = 1; + } + } if (change) snd_korg1212_WriteADCSensitivity(korg1212); @@ -1901,11 +1852,9 @@ static int snd_korg1212_control_sync_get(struct snd_kcontrol *kcontrol, { struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); ucontrol->value.enumerated.item[0] = korg1212->clkSource; - - spin_unlock_irq(&korg1212->lock); return 0; } @@ -1917,10 +1866,9 @@ static int snd_korg1212_control_sync_put(struct snd_kcontrol *kcontrol, int change; val = ucontrol->value.enumerated.item[0] % 3; - spin_lock_irq(&korg1212->lock); + guard(spinlock_irq)(&korg1212->lock); change = val != korg1212->clkSource; snd_korg1212_SetClockSource(korg1212, val); - spin_unlock_irq(&korg1212->lock); return change; } From 18aec9ea320ffc3c66058c1da8f86c413c17ff43 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:14 +0200 Subject: [PATCH 0949/1292] ALSA: lola: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-40-tiwai@suse.de --- sound/pci/lola/lola_pcm.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index 32193fae978d12..35e919d240bfb7 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c @@ -214,11 +214,9 @@ static int lola_pcm_open(struct snd_pcm_substream *substream) struct lola_stream *str = lola_get_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; - mutex_lock(&chip->open_mutex); - if (str->opened) { - mutex_unlock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); + if (str->opened) return -EBUSY; - } str->substream = substream; str->master = NULL; str->opened = 1; @@ -239,7 +237,6 @@ static int lola_pcm_open(struct snd_pcm_substream *substream) chip->granularity); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, chip->granularity); - mutex_unlock(&chip->open_mutex); return 0; } @@ -261,7 +258,7 @@ static int lola_pcm_close(struct snd_pcm_substream *substream) struct lola *chip = snd_pcm_substream_chip(substream); struct lola_stream *str = lola_get_stream(substream); - mutex_lock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); if (str->substream == substream) { str->substream = NULL; str->opened = 0; @@ -270,7 +267,6 @@ static int lola_pcm_close(struct snd_pcm_substream *substream) /* release sample rate */ chip->sample_rate = 0; } - mutex_unlock(&chip->open_mutex); return 0; } @@ -291,10 +287,9 @@ static int lola_pcm_hw_free(struct snd_pcm_substream *substream) struct lola_pcm *pcm = lola_get_pcm(substream); struct lola_stream *str = lola_get_stream(substream); - mutex_lock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); lola_stream_reset(chip, str); lola_cleanup_slave_streams(pcm, str); - mutex_unlock(&chip->open_mutex); return 0; } @@ -457,18 +452,16 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream) unsigned int bufsize, period_bytes, format_verb; int i, err; - mutex_lock(&chip->open_mutex); - lola_stream_reset(chip, str); - lola_cleanup_slave_streams(pcm, str); - if (str->index + runtime->channels > pcm->num_streams) { - mutex_unlock(&chip->open_mutex); - return -EINVAL; - } - for (i = 1; i < runtime->channels; i++) { - str[i].master = str; - str[i].opened = 1; + scoped_guard(mutex, &chip->open_mutex) { + lola_stream_reset(chip, str); + lola_cleanup_slave_streams(pcm, str); + if (str->index + runtime->channels > pcm->num_streams) + return -EINVAL; + for (i = 1; i < runtime->channels; i++) { + str[i].master = str; + str[i].opened = 1; + } } - mutex_unlock(&chip->open_mutex); bufsize = snd_pcm_lib_buffer_bytes(substream); period_bytes = snd_pcm_lib_period_bytes(substream); From e25667d3f311f7b56d4c4b7294a8c2a6f1cb69d7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:15 +0200 Subject: [PATCH 0950/1292] ALSA: lola: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-41-tiwai@suse.de --- sound/pci/lola/lola.c | 4 +--- sound/pci/lola/lola_pcm.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 8d927ecba165b2..34a3ba17deb4b7 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -74,7 +74,6 @@ static int corb_send_verb(struct lola *chip, unsigned int nid, unsigned int verb, unsigned int data, unsigned int extdata) { - unsigned long flags; int ret = -EIO; chip->last_cmd_nid = nid; @@ -83,7 +82,7 @@ static int corb_send_verb(struct lola *chip, unsigned int nid, chip->last_extdata = extdata; data |= (nid << 20) | (verb << 8); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) { unsigned int wp = chip->corb.wp + 1; wp %= LOLA_CORB_ENTRIES; @@ -95,7 +94,6 @@ static int corb_send_verb(struct lola *chip, unsigned int nid, smp_wmb(); ret = 0; } - spin_unlock_irqrestore(&chip->reg_lock, flags); return ret; } diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index 35e919d240bfb7..6c046ecd6e08df 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c @@ -523,7 +523,7 @@ static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) */ sync_streams = (start && snd_pcm_stream_linked(substream)); tstamp = lola_get_tstamp(chip, !sync_streams); - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); snd_pcm_group_for_each_entry(s, substream) { if (s->pcm->card != substream->pcm->card) continue; @@ -536,7 +536,6 @@ static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) str->paused = !start; snd_pcm_trigger_done(s, substream); } - spin_unlock(&chip->reg_lock); return 0; } From 3023cc514a2f3b43e96e8360c8b0be3b1c8f7501 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:16 +0200 Subject: [PATCH 0951/1292] ALSA: lx6464es: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-42-tiwai@suse.de --- sound/pci/lx6464es/lx6464es.c | 49 ++++++---------- sound/pci/lx6464es/lx_core.c | 107 ++++++++++------------------------ 2 files changed, 48 insertions(+), 108 deletions(-) diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 9f12c936bb1f7a..96df00db51d537 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -207,7 +207,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) int board_rate; dev_dbg(chip->card->dev, "->lx_pcm_open\n"); - mutex_lock(&chip->setup_mutex); + guard(mutex)(&chip->setup_mutex); /* copy the struct snd_pcm_hardware struct */ runtime->hw = lx_caps; @@ -218,7 +218,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) { dev_warn(chip->card->dev, "could not constrain periods\n"); - goto exit; + return err; } #endif @@ -229,7 +229,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) if (err < 0) { dev_warn(chip->card->dev, "could not constrain periods\n"); - goto exit; + return err; } /* constrain period size */ @@ -240,7 +240,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) if (err < 0) { dev_warn(chip->card->dev, "could not constrain period size\n"); - goto exit; + return err; } snd_pcm_hw_constraint_step(runtime, 0, @@ -249,10 +249,8 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); err = 0; -exit: runtime->private_data = chip; - mutex_unlock(&chip->setup_mutex); dev_dbg(chip->card->dev, "<-lx_pcm_open, %d\n", err); return err; } @@ -275,9 +273,8 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n"); - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); pos = lx_stream->frame_pos * substream->runtime->period_size; - mutex_unlock(&chip->lock); dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos); return pos; @@ -291,21 +288,21 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(chip->card->dev, "->lx_pcm_prepare\n"); - mutex_lock(&chip->setup_mutex); + guard(mutex)(&chip->setup_mutex); if (chip->hardware_running[is_capture]) { err = lx_hardware_stop(chip, substream); if (err < 0) { dev_err(chip->card->dev, "failed to stop hardware. " "Error code %d\n", err); - goto exit; + return err; } err = lx_hardware_close(chip, substream); if (err < 0) { dev_err(chip->card->dev, "failed to close hardware. " "Error code %d\n", err); - goto exit; + return err; } } @@ -314,14 +311,14 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream) if (err < 0) { dev_err(chip->card->dev, "failed to open hardware. " "Error code %d\n", err); - goto exit; + return err; } err = lx_hardware_start(chip, substream); if (err < 0) { dev_err(chip->card->dev, "failed to start hardware. " "Error code %d\n", err); - goto exit; + return err; } chip->hardware_running[is_capture] = 1; @@ -331,8 +328,6 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream) chip->board_sample_rate = substream->runtime->rate; } -exit: - mutex_unlock(&chip->setup_mutex); return err; } @@ -343,14 +338,13 @@ static int lx_pcm_hw_params(struct snd_pcm_substream *substream, dev_dbg(chip->card->dev, "->lx_pcm_hw_params\n"); - mutex_lock(&chip->setup_mutex); + guard(mutex)(&chip->setup_mutex); if (is_capture) chip->capture_stream.stream = substream; else chip->playback_stream.stream = substream; - mutex_unlock(&chip->setup_mutex); return 0; } @@ -373,21 +367,21 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream) int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); dev_dbg(chip->card->dev, "->lx_pcm_hw_free\n"); - mutex_lock(&chip->setup_mutex); + guard(mutex)(&chip->setup_mutex); if (chip->hardware_running[is_capture]) { err = lx_hardware_stop(chip, substream); if (err < 0) { dev_err(chip->card->dev, "failed to stop hardware. " "Error code %d\n", err); - goto exit; + return err; } err = lx_hardware_close(chip, substream); if (err < 0) { dev_err(chip->card->dev, "failed to close hardware. " "Error code %d\n", err); - goto exit; + return err; } chip->hardware_running[is_capture] = 0; @@ -398,9 +392,7 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream) else chip->playback_stream.stream = NULL; -exit: - mutex_unlock(&chip->setup_mutex); - return err; + return 0; } static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) @@ -486,9 +478,7 @@ static void lx_trigger_dispatch_stream(struct lx6464es *chip, static int lx_pcm_trigger_dispatch(struct lx6464es *chip, struct lx_stream *lx_stream, int cmd) { - int err = 0; - - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; @@ -499,16 +489,13 @@ static int lx_pcm_trigger_dispatch(struct lx6464es *chip, break; default: - err = -EINVAL; - goto exit; + return -EINVAL; } lx_trigger_dispatch_stream(chip, &chip->capture_stream); lx_trigger_dispatch_stream(chip, &chip->playback_stream); -exit: - mutex_unlock(&chip->lock); - return err; + return 0; } diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index a99acd1125e74f..6f0843cfb3be43 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -318,13 +318,12 @@ int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) { int ret; - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); ret = lx_message_send_atomic(chip, &chip->rmh); *rdsp_version = chip->rmh.stat[1]; - mutex_unlock(&chip->msg_lock); return ret; } @@ -335,7 +334,7 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) u32 frequency = 0; int ret; - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); ret = lx_message_send_atomic(chip, &chip->rmh); @@ -353,8 +352,6 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) frequency = 48000; } - mutex_unlock(&chip->msg_lock); - *rfreq = frequency * chip->freq_ratio; return ret; @@ -381,23 +378,19 @@ int lx_dsp_get_mac(struct lx6464es *chip) int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran) { - int ret; - - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY); chip->rmh.cmd[0] |= gran; - ret = lx_message_send_atomic(chip, &chip->rmh); - mutex_unlock(&chip->msg_lock); - return ret; + return lx_message_send_atomic(chip, &chip->rmh); } int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) { int ret; - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_04_GET_EVENT); chip->rmh.stat_len = 9; /* we don't necessarily need the full length */ @@ -407,7 +400,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) if (!ret) memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32)); - mutex_unlock(&chip->msg_lock); return ret; } @@ -423,14 +415,13 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE); chip->rmh.cmd[0] |= pipe_cmd; chip->rmh.cmd[0] |= channels; err = lx_message_send_atomic(chip, &chip->rmh); - mutex_unlock(&chip->msg_lock); if (err != 0) dev_err(chip->card->dev, "could not allocate pipe\n"); @@ -440,18 +431,14 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) { - int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE); chip->rmh.cmd[0] |= pipe_cmd; - err = lx_message_send_atomic(chip, &chip->rmh); - mutex_unlock(&chip->msg_lock); - - return err; + return lx_message_send_atomic(chip, &chip->rmh); } int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, @@ -468,7 +455,7 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, *r_needed = 0; *r_freed = 0; - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS); chip->rmh.cmd[0] |= pipe_cmd; @@ -501,41 +488,32 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, } } - mutex_unlock(&chip->msg_lock); return err; } int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture) { - int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_09_STOP_PIPE); chip->rmh.cmd[0] |= pipe_cmd; - err = lx_message_send_atomic(chip, &chip->rmh); - - mutex_unlock(&chip->msg_lock); - return err; + return lx_message_send_atomic(chip, &chip->rmh); } static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture) { - int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE); chip->rmh.cmd[0] |= pipe_cmd; - err = lx_message_send_atomic(chip, &chip->rmh); - - mutex_unlock(&chip->msg_lock); - return err; + return lx_message_send_atomic(chip, &chip->rmh); } @@ -572,7 +550,7 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -589,7 +567,6 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, + chip->rmh.stat[1]; /* lo part */ } - mutex_unlock(&chip->msg_lock); return err; } @@ -598,7 +575,7 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -610,7 +587,6 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) else *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; - mutex_unlock(&chip->msg_lock); return err; } @@ -651,29 +627,24 @@ int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture) int lx_stream_set_state(struct lx6464es *chip, u32 pipe, int is_capture, enum stream_state_t state) { - int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE); chip->rmh.cmd[0] |= pipe_cmd; chip->rmh.cmd[0] |= state; - err = lx_message_send_atomic(chip, &chip->rmh); - mutex_unlock(&chip->msg_lock); - - return err; + return lx_message_send_atomic(chip, &chip->rmh); } int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, u32 pipe, int is_capture) { - int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); u32 channels = runtime->channels; - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); chip->rmh.cmd[0] |= pipe_cmd; @@ -688,10 +659,7 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, chip->rmh.cmd[0] |= channels-1; - err = lx_message_send_atomic(chip, &chip->rmh); - mutex_unlock(&chip->msg_lock); - - return err; + return lx_message_send_atomic(chip, &chip->rmh); } int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, @@ -700,7 +668,7 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -709,7 +677,6 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE; - mutex_unlock(&chip->msg_lock); return err; } @@ -719,7 +686,7 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -730,7 +697,6 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, << 32) /* hi part */ + chip->rmh.stat[1]; /* lo part */ - mutex_unlock(&chip->msg_lock); return err; } @@ -742,7 +708,7 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER); chip->rmh.cmd[0] |= pipe_cmd; @@ -763,7 +729,7 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, if (err == 0) { *r_buffer_index = chip->rmh.stat[0]; - goto done; + return err; } if (err == EB_RBUFFERS_TABLE_OVERFLOW) @@ -778,8 +744,6 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, dev_err(chip->card->dev, "lx_buffer_give EB_CMD_REFUSED\n"); - done: - mutex_unlock(&chip->msg_lock); return err; } @@ -789,7 +753,7 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); chip->rmh.cmd[0] |= pipe_cmd; @@ -801,26 +765,21 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, if (err == 0) *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE; - mutex_unlock(&chip->msg_lock); return err; } int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, u32 buffer_index) { - int err; u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); chip->rmh.cmd[0] |= pipe_cmd; chip->rmh.cmd[0] |= buffer_index; - err = lx_message_send_atomic(chip, &chip->rmh); - - mutex_unlock(&chip->msg_lock); - return err; + return lx_message_send_atomic(chip, &chip->rmh); } @@ -831,11 +790,10 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, * */ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) { - int err; /* bit set to 1: channel muted */ u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU; - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0D_SET_MUTE); chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0); @@ -847,10 +805,7 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) "mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], chip->rmh.cmd[2]); - err = lx_message_send_atomic(chip, &chip->rmh); - - mutex_unlock(&chip->msg_lock); - return err; + return lx_message_send_atomic(chip, &chip->rmh); } static const u32 peak_map[] = { @@ -878,7 +833,7 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, int err = 0; int i; - mutex_lock(&chip->msg_lock); + guard(mutex)(&chip->msg_lock); for (i = 0; i < channels; i += 4) { u32 s0, s1, s2, s3; @@ -903,7 +858,6 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, r_levels += 4; } - mutex_unlock(&chip->msg_lock); return err; } @@ -1033,7 +987,7 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip, dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n"); - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); dev_dbg(chip->card->dev, @@ -1047,7 +1001,6 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip, buffer_index, (unsigned long)buf, period_bytes); lx_stream->frame_pos = next_pos; - mutex_unlock(&chip->lock); return err; } From 35dea82a4396ec0b974aae3e8e836a2336873561 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:17 +0200 Subject: [PATCH 0952/1292] ALSA: maestro3: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-43-tiwai@suse.de --- sound/pci/maestro3.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index e092097599ff9c..bddf47a1f263c4 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1096,7 +1096,7 @@ snd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd) if (snd_BUG_ON(!s)) return -ENXIO; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -1117,7 +1117,6 @@ snd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd) } break; } - spin_unlock(&chip->reg_lock); return err; } @@ -1412,7 +1411,7 @@ snd_m3_pcm_prepare(struct snd_pcm_substream *subs) runtime->rate < 8000) return -EINVAL; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); snd_m3_pcm_setup1(chip, s, subs); @@ -1423,8 +1422,6 @@ snd_m3_pcm_prepare(struct snd_pcm_substream *subs) snd_m3_pcm_setup2(chip, s, runtime); - spin_unlock_irq(&chip->reg_lock); - return 0; } @@ -1466,9 +1463,8 @@ snd_m3_pcm_pointer(struct snd_pcm_substream *subs) if (snd_BUG_ON(!s)) return 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); ptr = snd_m3_get_pointer(chip, s, subs); - spin_unlock(&chip->reg_lock); return bytes_to_frames(subs->runtime, ptr); } @@ -1629,13 +1625,12 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) if (ctl & DSP2HOST_REQ_TIMER) { outb(DSP2HOST_REQ_TIMER, chip->iobase + ASSP_HOST_INT_STATUS); /* update adc/dac info if it was a timer int */ - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); for (i = 0; i < chip->num_substreams; i++) { struct m3_dma *s = &chip->substreams[i]; if (s->running) snd_m3_update_ptr(chip, s); } - spin_unlock(&chip->reg_lock); } } } @@ -1707,18 +1702,16 @@ snd_m3_substream_open(struct snd_m3 *chip, struct snd_pcm_substream *subs) int i; struct m3_dma *s; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); for (i = 0; i < chip->num_substreams; i++) { s = &chip->substreams[i]; if (! s->opened) goto __found; } - spin_unlock_irq(&chip->reg_lock); return -ENOMEM; __found: s->opened = 1; s->running = 0; - spin_unlock_irq(&chip->reg_lock); subs->runtime->private_data = s; s->substream = subs; @@ -1742,7 +1735,7 @@ snd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs) if (s == NULL) return; /* not opened properly */ - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); if (s->substream && s->running) snd_m3_pcm_stop(chip, s, s->substream); /* does this happen? */ if (s->in_lists) { @@ -1753,7 +1746,6 @@ snd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs) } s->running = 0; s->opened = 0; - spin_unlock_irq(&chip->reg_lock); } static int @@ -2339,14 +2331,13 @@ static void snd_m3_free(struct snd_card *card) cancel_work_sync(&chip->hwvol_work); if (chip->substreams) { - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); for (i = 0; i < chip->num_substreams; i++) { s = &chip->substreams[i]; /* check surviving pcms; this should not happen though.. */ if (s->substream && s->running) snd_m3_pcm_stop(chip, s, s->substream); } - spin_unlock_irq(&chip->reg_lock); } if (chip->iobase) { outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */ From 23ab90a965bae0da773893037de1ab4c8df03fde Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:18 +0200 Subject: [PATCH 0953/1292] ALSA: mixart: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-44-tiwai@suse.de --- sound/pci/mixart/mixart.c | 48 +++++++--------------- sound/pci/mixart/mixart_core.c | 71 +++++++++++++++------------------ sound/pci/mixart/mixart_mixer.c | 46 ++++++++++----------- 3 files changed, 70 insertions(+), 95 deletions(-) diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index cdc0ba5dd1adb5..c6319e75beabb9 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -603,7 +603,7 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, /* set up format for the stream */ format = params_format(hw); - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); /* update the stream levels */ if( stream->pcm_number <= MIXART_PCM_DIGITAL ) { @@ -618,10 +618,8 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, /* set the format to the board */ err = mixart_set_format(stream, format); - if(err < 0) { - mutex_unlock(&mgr->setup_mutex); + if (err < 0) return err; - } if (subs->runtime->buffer_changed) { struct mixart_bufferinfo *bufferinfo; @@ -641,7 +639,6 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, bufferinfo[i].available_length, subs->number); } - mutex_unlock(&mgr->setup_mutex); return 0; } @@ -712,7 +709,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs) int err = 0; int pcm_number; - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; @@ -734,25 +731,21 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs) dev_err(chip->card->dev, "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); - err = -EBUSY; - goto _exit_open; + return -EBUSY; } /* get pipe pointer (out pipe) */ pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0); - if (pipe == NULL) { - err = -EINVAL; - goto _exit_open; - } + if (pipe == NULL) + return -EINVAL; /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { dev_err(chip->card->dev, "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); - err = -EINVAL; - goto _exit_open; + return -EINVAL; } stream->pipe = pipe; @@ -773,10 +766,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs) } } - _exit_open: - mutex_unlock(&mgr->setup_mutex); - - return err; + return 0; } @@ -791,7 +781,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs) int err = 0; int pcm_number; - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; @@ -815,25 +805,21 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs) dev_err(chip->card->dev, "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); - err = -EBUSY; - goto _exit_open; + return -EBUSY; } /* get pipe pointer (in pipe) */ pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0); - if (pipe == NULL) { - err = -EINVAL; - goto _exit_open; - } + if (pipe == NULL) + return -EINVAL; /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { dev_err(chip->card->dev, "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); - err = -EINVAL; - goto _exit_open; + return -EINVAL; } stream->pipe = pipe; @@ -854,10 +840,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs) } } - _exit_open: - mutex_unlock(&mgr->setup_mutex); - - return err; + return 0; } @@ -868,7 +851,7 @@ static int snd_mixart_close(struct snd_pcm_substream *subs) struct mixart_mgr *mgr = chip->mgr; struct mixart_stream *stream = subs->runtime->private_data; - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); dev_dbg(chip->card->dev, "snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number); @@ -890,7 +873,6 @@ static int snd_mixart_close(struct snd_pcm_substream *subs) stream->status = MIXART_STREAM_STATUS_FREE; stream->substream = NULL; - mutex_unlock(&mgr->setup_mutex); return 0; } diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index a047ed0f84e909..f7396ee4f6d7c0 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -226,17 +226,16 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int init_waitqueue_entry(&wait, current); - mutex_lock(&mgr->msg_lock); - /* send the message */ - err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ - if (err) { - mutex_unlock(&mgr->msg_lock); - return err; + scoped_guard(mutex, &mgr->msg_lock) { + /* send the message */ + err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ + if (err) + return err; + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&mgr->msg_sleep, &wait); } - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&mgr->msg_sleep, &wait); - mutex_unlock(&mgr->msg_lock); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); remove_wait_queue(&mgr->msg_sleep, &wait); @@ -253,9 +252,9 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int resp.data = resp_data; resp.size = max_resp_size; - mutex_lock(&mgr->msg_lock); - err = get_msg(mgr, &resp, msg_frame); - mutex_unlock(&mgr->msg_lock); + scoped_guard(mutex, &mgr->msg_lock) { + err = get_msg(mgr, &resp, msg_frame); + } if( request->message_id != resp.message_id ) dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n"); @@ -280,17 +279,16 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, init_waitqueue_entry(&wait, current); - mutex_lock(&mgr->msg_lock); - /* send the message */ - err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ - if(err) { - mutex_unlock(&mgr->msg_lock); - return err; + scoped_guard(mutex, &mgr->msg_lock) { + /* send the message */ + err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ + if (err) + return err; + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&mgr->msg_sleep, &wait); } - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&mgr->msg_sleep, &wait); - mutex_unlock(&mgr->msg_lock); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); remove_wait_queue(&mgr->msg_sleep, &wait); @@ -311,9 +309,8 @@ int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *requ int err; /* just send the message (do not mark it as a pending one) */ - mutex_lock(&mgr->msg_lock); + guard(mutex)(&mgr->msg_lock); err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); - mutex_unlock(&mgr->msg_lock); /* the answer will be handled by snd_struct mixart_msgasklet() */ atomic_inc(&mgr->msg_processed); @@ -420,7 +417,7 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id) struct mixart_msg resp; u32 msg; - mutex_lock(&mgr->lock); + guard(mutex)(&mgr->lock); /* process interrupt */ while (retrieve_msg_frame(mgr, &msg)) { @@ -530,19 +527,19 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id) fallthrough; case MSG_TYPE_ANSWER: /* answer or notification to a message we are waiting for*/ - mutex_lock(&mgr->msg_lock); - if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) { - wake_up(&mgr->msg_sleep); - mgr->pending_event = 0; - } - /* answer to a message we did't want to wait for */ - else { - mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; - mgr->msg_fifo_writeptr++; - mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; - snd_mixart_process_msg(mgr); + scoped_guard(mutex, &mgr->msg_lock) { + if ((msg & ~MSG_TYPE_MASK) == mgr->pending_event) { + wake_up(&mgr->msg_sleep); + mgr->pending_event = 0; + } + /* answer to a message we did't want to wait for */ + else { + mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; + mgr->msg_fifo_writeptr++; + mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; + snd_mixart_process_msg(mgr); + } } - mutex_unlock(&mgr->msg_lock); break; case MSG_TYPE_REQUEST: default: @@ -556,8 +553,6 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id) /* allow interrupt again */ writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); - mutex_unlock(&mgr->lock); - return IRQ_HANDLED; } diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 2727f334579571..f4081d3233404d 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -344,7 +344,8 @@ static int mixart_analog_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); if(kcontrol->private_value == 0) { /* playback */ ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; @@ -352,7 +353,6 @@ static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; } - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -362,7 +362,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e int changed = 0; int is_capture, i; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); is_capture = (kcontrol->private_value != 0); for (i = 0; i < 2; i++) { int new_volume = ucontrol->value.integer.value[i]; @@ -385,7 +385,6 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e } if (changed) mixart_update_analog_audio_level(chip, is_capture); - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -409,10 +408,9 @@ static int mixart_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -420,7 +418,8 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int i, changed = 0; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); for (i = 0; i < 2; i++) { if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { @@ -431,7 +430,6 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele } if (changed) /* update playback levels */ mixart_update_analog_audio_level(chip, 0); - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -825,7 +823,8 @@ static int mixart_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem int *stored_volume; int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK; int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); if(is_capture) { if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */ else stored_volume = chip->digital_capture_volume[0]; /* analog capture */ @@ -836,7 +835,6 @@ static int mixart_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem } ucontrol->value.integer.value[0] = stored_volume[0]; ucontrol->value.integer.value[1] = stored_volume[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -849,7 +847,8 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK; int* stored_volume; int i; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); if (is_capture) { if (is_aes) /* AES capture */ stored_volume = chip->digital_capture_volume[1]; @@ -878,7 +877,6 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem else mixart_update_playback_stream_level(chip, is_aes, idx); } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -903,12 +901,12 @@ static int mixart_pcm_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); if(kcontrol->private_value & MIXART_VOL_AES_MASK) /* AES playback */ idx += MIXART_PLAYBACK_STREAMS; ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -920,7 +918,8 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int i, j; snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); j = idx; if (is_aes) j += MIXART_PLAYBACK_STREAMS; @@ -934,7 +933,6 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ } if (changed) mixart_update_playback_stream_level(chip, is_aes, idx); - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -985,10 +983,10 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel) static int mixart_monitor_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -997,7 +995,8 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int changed = 0; int i; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); for (i = 0; i < 2; i++) { if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { @@ -1007,7 +1006,6 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ changed = 1; } } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -1029,10 +1027,10 @@ static const struct snd_kcontrol_new mixart_control_monitor_vol = { static int mixart_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_active[0]; ucontrol->value.integer.value[1] = chip->monitoring_active[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -1041,7 +1039,8 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); int changed = 0; int i; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); for (i = 0; i < 2; i++) { if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { @@ -1074,7 +1073,6 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e } } - mutex_unlock(&chip->mgr->mixer_mutex); return (changed != 0); } From 6c56792a053435b9eee67c07bc4fb0768487a55c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:19 +0200 Subject: [PATCH 0954/1292] ALSA: nm256: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-45-tiwai@suse.de --- sound/pci/nm256/nm256.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 39464d171f6bf7..7b2c986bb5ef5d 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -446,27 +446,25 @@ snd_nm256_set_format(struct nm256 *chip, struct nm256_stream *s, /* acquire interrupt */ static int snd_nm256_acquire_irq(struct nm256 *chip) { - mutex_lock(&chip->irq_mutex); + guard(mutex)(&chip->irq_mutex); if (chip->irq < 0) { if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(chip->card->dev, "unable to grab IRQ %d\n", chip->pci->irq); - mutex_unlock(&chip->irq_mutex); return -EBUSY; } chip->irq = chip->pci->irq; chip->card->sync_irq = chip->irq; } chip->irq_acks++; - mutex_unlock(&chip->irq_mutex); return 0; } /* release interrupt */ static void snd_nm256_release_irq(struct nm256 *chip) { - mutex_lock(&chip->irq_mutex); + guard(mutex)(&chip->irq_mutex); if (chip->irq_acks > 0) chip->irq_acks--; if (chip->irq_acks == 0 && chip->irq >= 0) { @@ -474,7 +472,6 @@ static void snd_nm256_release_irq(struct nm256 *chip) chip->irq = -1; chip->card->sync_irq = -1; } - mutex_unlock(&chip->irq_mutex); } /* From d1d88d2850a9504fc180b4abce4a03cb9191f3b9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:20 +0200 Subject: [PATCH 0955/1292] ALSA: nm256: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-46-tiwai@suse.de --- sound/pci/nm256/nm256.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 7b2c986bb5ef5d..da74b923bc88fd 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -544,12 +544,11 @@ snd_nm256_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct nm256 *chip = snd_pcm_substream_chip(substream); struct nm256_stream *s = substream->runtime->private_data; - int err = 0; if (snd_BUG_ON(!s)) return -ENXIO; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: s->suspended = 0; @@ -570,11 +569,9 @@ snd_nm256_playback_trigger(struct snd_pcm_substream *substream, int cmd) } break; default: - err = -EINVAL; - break; + return -EINVAL; } - spin_unlock(&chip->reg_lock); - return err; + return 0; } static int @@ -582,12 +579,11 @@ snd_nm256_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct nm256 *chip = snd_pcm_substream_chip(substream); struct nm256_stream *s = substream->runtime->private_data; - int err = 0; if (snd_BUG_ON(!s)) return -ENXIO; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -604,11 +600,9 @@ snd_nm256_capture_trigger(struct snd_pcm_substream *substream, int cmd) } break; default: - err = -EINVAL; - break; + return -EINVAL; } - spin_unlock(&chip->reg_lock); - return err; + return 0; } @@ -628,10 +622,9 @@ static int snd_nm256_pcm_prepare(struct snd_pcm_substream *substream) s->periods = substream->runtime->periods; s->cur_period = 0; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); s->running = 0; snd_nm256_set_format(chip, s, substream); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -996,7 +989,7 @@ snd_nm256_interrupt(int irq, void *dev_id) /* Rather boring; check for individual interrupts and process them. */ - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); if (status & NM_PLAYBACK_INT) { status &= ~NM_PLAYBACK_INT; NM_ACK_INT(chip, NM_PLAYBACK_INT); @@ -1035,7 +1028,6 @@ snd_nm256_interrupt(int irq, void *dev_id) NM_ACK_INT(chip, status); } - spin_unlock(&chip->reg_lock); return IRQ_HANDLED; } @@ -1062,7 +1054,7 @@ snd_nm256_interrupt_zx(int irq, void *dev_id) /* Rather boring; check for individual interrupts and process them. */ - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); if (status & NM2_PLAYBACK_INT) { status &= ~NM2_PLAYBACK_INT; NM2_ACK_INT(chip, NM2_PLAYBACK_INT); @@ -1100,7 +1092,6 @@ snd_nm256_interrupt_zx(int irq, void *dev_id) NM2_ACK_INT(chip, status); } - spin_unlock(&chip->reg_lock); return IRQ_HANDLED; } @@ -1389,9 +1380,8 @@ static int nm256_resume(struct device *dev) for (i = 0; i < 2; i++) { struct nm256_stream *s = &chip->streams[i]; if (s->substream && s->suspended) { - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); snd_nm256_set_format(chip, s, s->substream); - spin_unlock_irq(&chip->reg_lock); } } From 8ecafe5dacc2d98312315b83902ce7b7dbcdfa86 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:21 +0200 Subject: [PATCH 0956/1292] ALSA: oxygen: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-47-tiwai@suse.de --- sound/pci/oxygen/oxygen.c | 12 +++---- sound/pci/oxygen/oxygen_mixer.c | 60 +++++++++++-------------------- sound/pci/oxygen/oxygen_pcm.c | 21 ++++------- sound/pci/oxygen/xonar_cs43xx.c | 3 +- sound/pci/oxygen/xonar_dg_mixer.c | 33 ++++++----------- sound/pci/oxygen/xonar_pcm179x.c | 18 ++++------ sound/pci/oxygen/xonar_wm87x6.c | 31 ++++++---------- 7 files changed, 59 insertions(+), 119 deletions(-) diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index ff7439634d7693..e6f869cf8ca26f 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -450,7 +450,7 @@ static int rolloff_put(struct snd_kcontrol *ctl, int changed; u8 reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->ak4396_regs[0][AK4396_CONTROL_2]; if (value->value.enumerated.item[0]) reg |= AK4396_SLOW; @@ -461,7 +461,6 @@ static int rolloff_put(struct snd_kcontrol *ctl, for (i = 0; i < data->dacs; ++i) ak4396_write(chip, i, AK4396_CONTROL_2, reg); } - mutex_unlock(&chip->mutex); return changed; } @@ -499,14 +498,13 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) unsigned int reg; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->wm8785_regs[WM8785_R2] & ~(WM8785_HPFR | WM8785_HPFL); if (value->value.enumerated.item[0]) reg |= WM8785_HPFR | WM8785_HPFL; changed = reg != data->wm8785_regs[WM8785_R2]; if (changed) wm8785_write(chip, WM8785_R2, reg); - mutex_unlock(&chip->mutex); return changed; } @@ -563,7 +561,7 @@ static int meridian_dig_source_put(struct snd_kcontrol *ctl, u16 old_reg, new_reg; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK; if (value->value.enumerated.item[0] == 0) @@ -573,7 +571,6 @@ static int meridian_dig_source_put(struct snd_kcontrol *ctl, changed = new_reg != old_reg; if (changed) oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); - mutex_unlock(&chip->mutex); return changed; } @@ -584,7 +581,7 @@ static int claro_dig_source_put(struct snd_kcontrol *ctl, u16 old_reg, new_reg; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA); new_reg = old_reg & ~GPIO_CLARO_DIG_COAX; if (value->value.enumerated.item[0]) @@ -592,7 +589,6 @@ static int claro_dig_source_put(struct snd_kcontrol *ctl, changed = new_reg != old_reg; if (changed) oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg); - mutex_unlock(&chip->mutex); return changed; } diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index eb3aca16359c58..be35f5582485c1 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -31,10 +31,9 @@ static int dac_volume_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; unsigned int i; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); for (i = 0; i < chip->model.dac_channels_mixer; ++i) value->value.integer.value[i] = chip->dac_volume[i]; - mutex_unlock(&chip->mutex); return 0; } @@ -46,7 +45,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl, int changed; changed = 0; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); for (i = 0; i < chip->model.dac_channels_mixer; ++i) if (value->value.integer.value[i] != chip->dac_volume[i]) { chip->dac_volume[i] = value->value.integer.value[i]; @@ -54,7 +53,6 @@ static int dac_volume_put(struct snd_kcontrol *ctl, } if (changed) chip->model.update_dac_volume(chip); - mutex_unlock(&chip->mutex); return changed; } @@ -63,9 +61,8 @@ static int dac_mute_get(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.integer.value[0] = !chip->dac_mute; - mutex_unlock(&chip->mutex); return 0; } @@ -75,13 +72,12 @@ static int dac_mute_put(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = (!value->value.integer.value[0]) != chip->dac_mute; if (changed) { chip->dac_mute = !value->value.integer.value[0]; chip->model.update_dac_mute(chip); } - mutex_unlock(&chip->mutex); return changed; } @@ -114,9 +110,8 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.enumerated.item[0] = chip->dac_routing; - mutex_unlock(&chip->mutex); return 0; } @@ -188,13 +183,12 @@ static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) if (value->value.enumerated.item[0] >= count) return -EINVAL; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = value->value.enumerated.item[0] != chip->dac_routing; if (changed) { chip->dac_routing = value->value.enumerated.item[0]; oxygen_update_dac_routing(chip); } - mutex_unlock(&chip->mutex); return changed; } @@ -203,9 +197,8 @@ static int spdif_switch_get(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.integer.value[0] = chip->spdif_playback_enable; - mutex_unlock(&chip->mutex); return 0; } @@ -279,7 +272,7 @@ static int spdif_switch_put(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = value->value.integer.value[0] != chip->spdif_playback_enable; if (changed) { chip->spdif_playback_enable = !!value->value.integer.value[0]; @@ -287,7 +280,6 @@ static int spdif_switch_put(struct snd_kcontrol *ctl, oxygen_update_spdif_source(chip); spin_unlock_irq(&chip->reg_lock); } - mutex_unlock(&chip->mutex); return changed; } @@ -336,9 +328,8 @@ static int spdif_default_get(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); oxygen_to_iec958(chip->spdif_bits, value); - mutex_unlock(&chip->mutex); return 0; } @@ -350,14 +341,13 @@ static int spdif_default_put(struct snd_kcontrol *ctl, int changed; new_bits = iec958_to_oxygen(value); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = new_bits != chip->spdif_bits; if (changed) { chip->spdif_bits = new_bits; if (!(chip->pcm_active & (1 << PCM_SPDIF))) write_spdif_bits(chip, new_bits); } - mutex_unlock(&chip->mutex); return changed; } @@ -376,9 +366,8 @@ static int spdif_pcm_get(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); oxygen_to_iec958(chip->spdif_pcm_bits, value); - mutex_unlock(&chip->mutex); return 0; } @@ -390,14 +379,13 @@ static int spdif_pcm_put(struct snd_kcontrol *ctl, int changed; new_bits = iec958_to_oxygen(value); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = new_bits != chip->spdif_pcm_bits; if (changed) { chip->spdif_pcm_bits = new_bits; if (chip->pcm_active & (1 << PCM_SPDIF)) write_spdif_bits(chip, new_bits); } - mutex_unlock(&chip->mutex); return changed; } @@ -511,9 +499,8 @@ static int ac97_switch_get(struct snd_kcontrol *ctl, int invert = ctl->private_value & (1 << 16); u16 reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = oxygen_read_ac97(chip, codec, index); - mutex_unlock(&chip->mutex); if (!(reg & (1 << bitnr)) ^ !invert) value->value.integer.value[0] = 1; else @@ -550,7 +537,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, u16 oldreg, newreg; int change; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); oldreg = oxygen_read_ac97(chip, codec, index); newreg = oldreg; if (!value->value.integer.value[0] ^ !invert) @@ -579,7 +566,6 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, CM9780_GPO0, CM9780_GPO0); } } - mutex_unlock(&chip->mutex); return change; } @@ -604,9 +590,8 @@ static int ac97_volume_get(struct snd_kcontrol *ctl, unsigned int index = ctl->private_value & 0xff; u16 reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = oxygen_read_ac97(chip, codec, index); - mutex_unlock(&chip->mutex); if (!stereo) { value->value.integer.value[0] = 31 - (reg & 0x1f); } else { @@ -626,7 +611,7 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, u16 oldreg, newreg; int change; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); oldreg = oxygen_read_ac97(chip, codec, index); if (!stereo) { newreg = oldreg & ~0x1f; @@ -639,7 +624,6 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, change = newreg != oldreg; if (change) oxygen_write_ac97(chip, codec, index, newreg); - mutex_unlock(&chip->mutex); return change; } @@ -656,10 +640,9 @@ static int mic_fmic_source_get(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.enumerated.item[0] = !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC); - mutex_unlock(&chip->mutex); return 0; } @@ -670,7 +653,7 @@ static int mic_fmic_source_put(struct snd_kcontrol *ctl, u16 oldreg, newreg; int change; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK); if (value->value.enumerated.item[0]) newreg = oldreg | CM9780_FMIC2MIC; @@ -679,7 +662,6 @@ static int mic_fmic_source_put(struct snd_kcontrol *ctl, change = newreg != oldreg; if (change) oxygen_write_ac97(chip, 0, CM9780_JACK, newreg); - mutex_unlock(&chip->mutex); return change; } @@ -699,9 +681,8 @@ static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; u16 reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); - mutex_unlock(&chip->mutex); value->value.integer.value[0] = reg & 7; value->value.integer.value[1] = (reg >> 8) & 7; return 0; @@ -714,7 +695,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, u16 oldreg, newreg; int change; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); newreg = oldreg & ~0x0707; newreg = newreg | (value->value.integer.value[0] & 7); @@ -722,7 +703,6 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, change = newreg != oldreg; if (change) oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg); - mutex_unlock(&chip->mutex); return change; } diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 643141f345bba7..1fcd0b1d439c79 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -171,7 +171,7 @@ static int oxygen_open(struct snd_pcm_substream *substream, snd_pcm_set_sync(substream); chip->streams[channel] = substream; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); chip->pcm_active |= 1 << channel; if (channel == PCM_SPDIF) { chip->spdif_pcm_bits = chip->spdif_bits; @@ -181,7 +181,6 @@ static int oxygen_open(struct snd_pcm_substream *substream, SNDRV_CTL_EVENT_MASK_INFO, &chip->controls[CONTROL_SPDIF_PCM]->id); } - mutex_unlock(&chip->mutex); return 0; } @@ -221,7 +220,7 @@ static int oxygen_close(struct snd_pcm_substream *substream) struct oxygen *chip = snd_pcm_substream_chip(substream); unsigned int channel = oxygen_substream_channel(substream); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); chip->pcm_active &= ~(1 << channel); if (channel == PCM_SPDIF) { chip->controls[CONTROL_SPDIF_PCM]->vd[0].access |= @@ -232,7 +231,6 @@ static int oxygen_close(struct snd_pcm_substream *substream) } if (channel == PCM_SPDIF || channel == PCM_MULTICH) oxygen_update_spdif_source(chip); - mutex_unlock(&chip->mutex); chip->streams[channel] = NULL; return 0; @@ -366,9 +364,8 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, OXYGEN_I2S_BITS_MASK); spin_unlock_irq(&chip->reg_lock); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); chip->model.set_adc_params(chip, hw_params); - mutex_unlock(&chip->mutex); return 0; } @@ -403,9 +400,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, spin_unlock_irq(&chip->reg_lock); if (!is_ac97) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); chip->model.set_adc_params(chip, hw_params); - mutex_unlock(&chip->mutex); } return 0; } @@ -440,9 +436,8 @@ static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream, spin_unlock_irq(&chip->reg_lock); if (!is_spdif) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); chip->model.set_adc_params(chip, hw_params); - mutex_unlock(&chip->mutex); } return 0; } @@ -457,7 +452,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); spin_lock_irq(&chip->reg_lock); oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_OUT_ENABLE); @@ -469,7 +464,6 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, OXYGEN_SPDIF_OUT_RATE_MASK); oxygen_update_spdif_source(chip); spin_unlock_irq(&chip->reg_lock); - mutex_unlock(&chip->mutex); return 0; } @@ -483,7 +477,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); spin_lock_irq(&chip->reg_lock); oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, oxygen_play_channels(hw_params), @@ -505,7 +499,6 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, chip->model.set_dac_params(chip, hw_params); oxygen_update_dac_routing(chip); - mutex_unlock(&chip->mutex); return 0; } diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 664b7759dd628c..d608803fd87477 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -309,7 +309,7 @@ static int rolloff_put(struct snd_kcontrol *ctl, int changed; u8 reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->cs4398_regs[7]; if (value->value.enumerated.item[0]) reg |= CS4398_FILT_SEL; @@ -324,7 +324,6 @@ static int rolloff_put(struct snd_kcontrol *ctl, reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL; cs4362a_write(chip, 0x04, reg); } - mutex_unlock(&chip->mutex); return changed; } diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c index 198588562880b5..2179ff8e4d864f 100644 --- a/sound/pci/oxygen/xonar_dg_mixer.c +++ b/sound/pci/oxygen/xonar_dg_mixer.c @@ -62,9 +62,8 @@ static int output_select_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; struct dg *data = chip->model_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.enumerated.item[0] = data->output_sel; - mutex_unlock(&chip->mutex); return 0; } @@ -77,14 +76,13 @@ static int output_select_put(struct snd_kcontrol *ctl, int changed = 0; int ret; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (data->output_sel != new) { data->output_sel = new; ret = output_select_apply(chip); changed = ret >= 0 ? 1 : ret; oxygen_update_dac_routing(chip); } - mutex_unlock(&chip->mutex); return changed; } @@ -108,12 +106,11 @@ static int hp_stereo_volume_get(struct snd_kcontrol *ctl, struct dg *data = chip->model_data; unsigned int tmp; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255; val->value.integer.value[0] = tmp; tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255; val->value.integer.value[1] = tmp; - mutex_unlock(&chip->mutex); return 0; } @@ -130,7 +127,7 @@ static int hp_stereo_volume_put(struct snd_kcontrol *ctl, if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0)) return -EINVAL; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) || (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) { data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1; @@ -140,7 +137,6 @@ static int hp_stereo_volume_put(struct snd_kcontrol *ctl, ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL); changed = ret >= 0 ? 1 : ret; } - mutex_unlock(&chip->mutex); return changed; } @@ -153,10 +149,9 @@ static int hp_mute_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; struct dg *data = chip->model_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); val->value.integer.value[0] = !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC); - mutex_unlock(&chip->mutex); return 0; } @@ -170,13 +165,12 @@ static int hp_mute_put(struct snd_kcontrol *ctl, if (val->value.integer.value[0] > 1) return -EINVAL; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC; data->cs4245_shadow[CS4245_DAC_CTRL_1] |= (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC; ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1); changed = ret >= 0 ? 1 : ret; - mutex_unlock(&chip->mutex); return changed; } @@ -212,10 +206,9 @@ static int input_vol_get(struct snd_kcontrol *ctl, struct dg *data = chip->model_data; unsigned int idx = ctl->private_value; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.integer.value[0] = data->input_vol[idx][0]; value->value.integer.value[1] = data->input_vol[idx][1]; - mutex_unlock(&chip->mutex); return 0; } @@ -233,7 +226,7 @@ static int input_vol_put(struct snd_kcontrol *ctl, value->value.integer.value[1] < 2 * -12 || value->value.integer.value[1] > 2 * 12) return -EINVAL; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = data->input_vol[idx][0] != value->value.integer.value[0] || data->input_vol[idx][1] != value->value.integer.value[1]; if (changed) { @@ -246,7 +239,6 @@ static int input_vol_put(struct snd_kcontrol *ctl, } changed = ret >= 0 ? 1 : ret; } - mutex_unlock(&chip->mutex); return changed; } @@ -282,9 +274,8 @@ static int input_sel_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; struct dg *data = chip->model_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.enumerated.item[0] = data->input_sel; - mutex_unlock(&chip->mutex); return 0; } @@ -299,7 +290,7 @@ static int input_sel_put(struct snd_kcontrol *ctl, if (value->value.enumerated.item[0] > 3) return -EINVAL; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = value->value.enumerated.item[0] != data->input_sel; if (changed) { data->input_sel = value->value.enumerated.item[0]; @@ -311,7 +302,6 @@ static int input_sel_put(struct snd_kcontrol *ctl, data->input_vol[data->input_sel][1]); changed = ret >= 0 ? 1 : ret; } - mutex_unlock(&chip->mutex); return changed; } @@ -341,7 +331,7 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) u8 reg; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; if (value->value.enumerated.item[0]) reg |= CS4245_HPF_FREEZE; @@ -350,7 +340,6 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) data->cs4245_shadow[CS4245_ADC_CTRL] = reg; cs4245_write_spi(chip, CS4245_ADC_CTRL); } - mutex_unlock(&chip->mutex); return changed; } diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index cf801a235df92c..a491c9c92989e5 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -762,7 +762,7 @@ static int rolloff_put(struct snd_kcontrol *ctl, int changed; u8 reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; reg &= ~PCM1796_FLT_MASK; if (!value->value.enumerated.item[0]) @@ -774,7 +774,6 @@ static int rolloff_put(struct snd_kcontrol *ctl, for (i = 0; i < data->dacs; ++i) pcm1796_write(chip, i, 19, reg); } - mutex_unlock(&chip->mutex); return changed; } @@ -806,7 +805,7 @@ static int deemph_put(struct snd_kcontrol *ctl, int changed; u8 reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->pcm1796_regs[0][18 - PCM1796_REG_BASE]; if (!value->value.integer.value[0]) reg &= ~PCM1796_DME; @@ -817,7 +816,6 @@ static int deemph_put(struct snd_kcontrol *ctl, for (i = 0; i < data->dacs; ++i) pcm1796_write(chip, i, 18, reg); } - mutex_unlock(&chip->mutex); return changed; } @@ -872,7 +870,7 @@ static int st_output_switch_put(struct snd_kcontrol *ctl, struct xonar_pcm179x *data = chip->model_data; u16 gpio_old, gpio; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); gpio = gpio_old; switch (value->value.enumerated.item[0]) { @@ -889,7 +887,6 @@ static int st_output_switch_put(struct snd_kcontrol *ctl, oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); data->hp_active = gpio & GPIO_ST_HP; update_pcm1796_volume(chip); - mutex_unlock(&chip->mutex); return gpio != gpio_old; } @@ -909,7 +906,7 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; struct xonar_pcm179x *data = chip->model_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (data->hp_gain_offset < 2*-12) value->value.enumerated.item[0] = 0; else if (data->hp_gain_offset < 2*-6) @@ -918,7 +915,6 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, value->value.enumerated.item[0] = 2; else value->value.enumerated.item[0] = 3; - mutex_unlock(&chip->mutex); return 0; } @@ -935,13 +931,12 @@ static int st_hp_volume_offset_put(struct snd_kcontrol *ctl, if (value->value.enumerated.item[0] > 3) return -EINVAL; offset = offsets[value->value.enumerated.item[0]]; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = offset != data->hp_gain_offset; if (changed) { data->hp_gain_offset = offset; update_pcm1796_volume(chip); } - mutex_unlock(&chip->mutex); return changed; } @@ -985,7 +980,7 @@ static int xense_output_switch_put(struct snd_kcontrol *ctl, struct xonar_pcm179x *data = chip->model_data; u16 gpio_old, gpio; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); gpio = gpio_old; switch (value->value.enumerated.item[0]) { @@ -1002,7 +997,6 @@ static int xense_output_switch_put(struct snd_kcontrol *ctl, oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS); update_pcm1796_volume(chip); - mutex_unlock(&chip->mutex); return gpio != gpio_old; } diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 8aa92f3e5ee888..7d92e6e20c3958 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -237,7 +237,7 @@ static void xonar_ds_handle_hp_jack(struct oxygen *chip) bool hp_plugged; unsigned int reg; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DS_HP_DETECT); @@ -252,8 +252,6 @@ static void xonar_ds_handle_hp_jack(struct oxygen *chip) wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0); - - mutex_unlock(&chip->mutex); } static void xonar_ds_init(struct oxygen *chip) @@ -521,14 +519,13 @@ static int wm8776_bit_switch_put(struct snd_kcontrol *ctl, bool invert = (ctl->private_value >> 24) & 1; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg_value = data->wm8776_regs[reg_index] & ~bit; if (value->value.integer.value[0] ^ invert) reg_value |= bit; changed = reg_value != data->wm8776_regs[reg_index]; if (changed) wm8776_write(chip, reg_index, reg_value); - mutex_unlock(&chip->mutex); return changed; } @@ -648,13 +645,12 @@ static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value) max = (ctl->private_value >> 12) & 0xf; if (value < min || value > max) return -EINVAL; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = value != (ctl->private_value & 0xf); if (changed) { ctl->private_value = (ctl->private_value & ~0xf) | value; wm8776_field_set_from_ctl(ctl); } - mutex_unlock(&chip->mutex); return changed; } @@ -700,12 +696,11 @@ static int wm8776_hp_vol_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; struct xonar_wm87x6 *data = chip->model_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.integer.value[0] = data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK; value->value.integer.value[1] = data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK; - mutex_unlock(&chip->mutex); return 0; } @@ -716,7 +711,7 @@ static int wm8776_hp_vol_put(struct snd_kcontrol *ctl, struct xonar_wm87x6 *data = chip->model_data; u8 to_update; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); to_update = (value->value.integer.value[0] != (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK)) << 0; @@ -744,7 +739,6 @@ static int wm8776_hp_vol_put(struct snd_kcontrol *ctl, value->value.integer.value[1] | WM8776_HPZCEN | WM8776_UPDATE); } - mutex_unlock(&chip->mutex); return to_update != 0; } @@ -770,7 +764,7 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl, u16 reg; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->wm8776_regs[WM8776_ADCMUX]; if (value->value.integer.value[0]) { reg |= mux_bit; @@ -794,7 +788,6 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl, GPIO_DS_INPUT_ROUTE); wm8776_write(chip, WM8776_ADCMUX, reg); } - mutex_unlock(&chip->mutex); return changed; } @@ -814,12 +807,11 @@ static int wm8776_input_vol_get(struct snd_kcontrol *ctl, struct oxygen *chip = ctl->private_data; struct xonar_wm87x6 *data = chip->model_data; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); value->value.integer.value[0] = data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK; value->value.integer.value[1] = data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK; - mutex_unlock(&chip->mutex); return 0; } @@ -830,7 +822,7 @@ static int wm8776_input_vol_put(struct snd_kcontrol *ctl, struct xonar_wm87x6 *data = chip->model_data; int changed = 0; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = (value->value.integer.value[0] != (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) || (value->value.integer.value[1] != @@ -839,7 +831,6 @@ static int wm8776_input_vol_put(struct snd_kcontrol *ctl, value->value.integer.value[0] | WM8776_ZCA); wm8776_write_cached(chip, WM8776_ADCRVOL, value->value.integer.value[1] | WM8776_ZCA); - mutex_unlock(&chip->mutex); return changed; } @@ -895,7 +886,7 @@ static int wm8776_level_control_put(struct snd_kcontrol *ctl, if (value->value.enumerated.item[0] >= 3) return -EINVAL; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); changed = value->value.enumerated.item[0] != ctl->private_value; if (changed) { ctl->private_value = value->value.enumerated.item[0]; @@ -926,7 +917,6 @@ static int wm8776_level_control_put(struct snd_kcontrol *ctl, for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i) activate_control(chip, data->lc_controls[i], mode); } - mutex_unlock(&chip->mutex); return changed; } @@ -956,14 +946,13 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) unsigned int reg; int changed; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD; if (!value->value.enumerated.item[0]) reg |= WM8776_ADCHPD; changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL]; if (changed) wm8776_write(chip, WM8776_ADCIFCTRL, reg); - mutex_unlock(&chip->mutex); return changed; } From 4751026c7923a3bfb95a204a6d3116c759e28691 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:22 +0200 Subject: [PATCH 0957/1292] ALSA: oxygen: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-48-tiwai@suse.de --- sound/pci/oxygen/oxygen_lib.c | 134 ++++++++++++++-------------- sound/pci/oxygen/oxygen_mixer.c | 6 +- sound/pci/oxygen/oxygen_pcm.c | 144 +++++++++++++++---------------- sound/pci/oxygen/xonar_cs43xx.c | 3 +- sound/pci/oxygen/xonar_lib.c | 3 +- sound/pci/oxygen/xonar_pcm179x.c | 3 +- 6 files changed, 140 insertions(+), 153 deletions(-) diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 9c7270e4c35e4f..6b096d654f9f87 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -59,36 +59,34 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) if (!status) return IRQ_NONE; - spin_lock(&chip->reg_lock); - - clear = status & (OXYGEN_CHANNEL_A | - OXYGEN_CHANNEL_B | - OXYGEN_CHANNEL_C | - OXYGEN_CHANNEL_SPDIF | - OXYGEN_CHANNEL_MULTICH | - OXYGEN_CHANNEL_AC97 | - OXYGEN_INT_SPDIF_IN_DETECT | - OXYGEN_INT_GPIO | - OXYGEN_INT_AC97); - if (clear) { - if (clear & OXYGEN_INT_SPDIF_IN_DETECT) - chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT; - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, - chip->interrupt_mask & ~clear); - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, - chip->interrupt_mask); - } - - elapsed_streams = status & chip->pcm_running; + scoped_guard(spinlock, &chip->reg_lock) { + clear = status & (OXYGEN_CHANNEL_A | + OXYGEN_CHANNEL_B | + OXYGEN_CHANNEL_C | + OXYGEN_CHANNEL_SPDIF | + OXYGEN_CHANNEL_MULTICH | + OXYGEN_CHANNEL_AC97 | + OXYGEN_INT_SPDIF_IN_DETECT | + OXYGEN_INT_GPIO | + OXYGEN_INT_AC97); + if (clear) { + if (clear & OXYGEN_INT_SPDIF_IN_DETECT) + chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT; + oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, + chip->interrupt_mask & ~clear); + oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, + chip->interrupt_mask); + } - spin_unlock(&chip->reg_lock); + elapsed_streams = status & chip->pcm_running; + } for (i = 0; i < PCM_COUNT; ++i) if ((elapsed_streams & (1 << i)) && chip->streams[i]) snd_pcm_period_elapsed(chip->streams[i]); if (status & OXYGEN_INT_SPDIF_IN_DETECT) { - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT | OXYGEN_SPDIF_RATE_INT)) { @@ -96,7 +94,6 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i); schedule_work(&chip->spdif_input_bits_work); } - spin_unlock(&chip->reg_lock); } if (status & OXYGEN_INT_GPIO) @@ -127,45 +124,45 @@ static void oxygen_spdif_input_bits_changed(struct work_struct *work) * changes. */ msleep(1); - spin_lock_irq(&chip->reg_lock); - reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); - if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | - OXYGEN_SPDIF_LOCK_STATUS)) - == OXYGEN_SPDIF_SENSE_STATUS) { - /* - * If we detect activity on the SPDIF input but cannot lock to - * a signal, the clock bit is likely to be wrong. - */ - reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK; - oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); - spin_unlock_irq(&chip->reg_lock); - msleep(1); - spin_lock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | OXYGEN_SPDIF_LOCK_STATUS)) == OXYGEN_SPDIF_SENSE_STATUS) { - /* nothing detected with either clock; give up */ - if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK) - == OXYGEN_SPDIF_IN_CLOCK_192) { - /* - * Reset clock to <= 96 kHz because this is - * more likely to be received next time. - */ - reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK; - reg |= OXYGEN_SPDIF_IN_CLOCK_96; - oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); + /* + * If we detect activity on the SPDIF input but cannot lock to + * a signal, the clock bit is likely to be wrong. + */ + reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK; + oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); + spin_unlock_irq(&chip->reg_lock); + msleep(1); + spin_lock_irq(&chip->reg_lock); + reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); + if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | + OXYGEN_SPDIF_LOCK_STATUS)) + == OXYGEN_SPDIF_SENSE_STATUS) { + /* nothing detected with either clock; give up */ + if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK) + == OXYGEN_SPDIF_IN_CLOCK_192) { + /* + * Reset clock to <= 96 kHz because this is + * more likely to be received next time. + */ + reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK; + reg |= OXYGEN_SPDIF_IN_CLOCK_96; + oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); + } } } } - spin_unlock_irq(&chip->reg_lock); if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) { - spin_lock_irq(&chip->reg_lock); - chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, - chip->interrupt_mask); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; + oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, + chip->interrupt_mask); + } /* * We don't actually know that any channel status bits have @@ -557,12 +554,11 @@ static void oxygen_init(struct oxygen *chip) static void oxygen_shutdown(struct oxygen *chip) { - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->interrupt_mask = 0; chip->pcm_running = 0; oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); - spin_unlock_irq(&chip->reg_lock); } static void oxygen_card_free(struct snd_card *card) @@ -686,13 +682,13 @@ static int __oxygen_pci_probe(struct pci_dev *pci, int index, char *id, oxygen_proc_init(chip); - spin_lock_irq(&chip->reg_lock); - if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) - chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; - if (chip->has_ac97_0 | chip->has_ac97_1) - chip->interrupt_mask |= OXYGEN_INT_AC97; - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) + chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; + if (chip->has_ac97_0 | chip->has_ac97_1) + chip->interrupt_mask |= OXYGEN_INT_AC97; + oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); + } err = snd_card_register(card); if (err < 0) @@ -724,12 +720,12 @@ static int oxygen_pci_suspend(struct device *dev) if (chip->model.suspend) chip->model.suspend(chip); - spin_lock_irq(&chip->reg_lock); - saved_interrupt_mask = chip->interrupt_mask; - chip->interrupt_mask = 0; - oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + saved_interrupt_mask = chip->interrupt_mask; + chip->interrupt_mask = 0; + oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); + oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); + } flush_work(&chip->spdif_input_bits_work); flush_work(&chip->gpio_work); diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index be35f5582485c1..256a601d78113b 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -432,7 +432,7 @@ static int spdif_bit_switch_put(struct snd_kcontrol *ctl, u32 oldreg, newreg; int changed; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); if (value->value.integer.value[0]) newreg = oldreg | bit; @@ -441,7 +441,6 @@ static int spdif_bit_switch_put(struct snd_kcontrol *ctl, changed = newreg != oldreg; if (changed) oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); - spin_unlock_irq(&chip->reg_lock); return changed; } @@ -476,7 +475,7 @@ static int monitor_put(struct snd_kcontrol *ctl, u8 oldreg, newreg; int changed; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oldreg = oxygen_read8(chip, OXYGEN_ADC_MONITOR); if ((!!value->value.integer.value[0] ^ !!invert) != 0) newreg = oldreg | bit; @@ -485,7 +484,6 @@ static int monitor_put(struct snd_kcontrol *ctl, changed = newreg != oldreg; if (changed) oxygen_write8(chip, OXYGEN_ADC_MONITOR, newreg); - spin_unlock_irq(&chip->reg_lock); return changed; } diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 1fcd0b1d439c79..b716356010b898 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -349,20 +349,20 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - spin_lock_irq(&chip->reg_lock); - oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, - oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT, - OXYGEN_REC_FORMAT_A_MASK); - oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, - oxygen_rate(hw_params) | - chip->model.adc_i2s_format | - get_mclk(chip, PCM_A, hw_params) | - oxygen_i2s_bits(hw_params), - OXYGEN_I2S_RATE_MASK | - OXYGEN_I2S_FORMAT_MASK | - OXYGEN_I2S_MCLK_MASK | - OXYGEN_I2S_BITS_MASK); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, + oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT, + OXYGEN_REC_FORMAT_A_MASK); + oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, + oxygen_rate(hw_params) | + chip->model.adc_i2s_format | + get_mclk(chip, PCM_A, hw_params) | + oxygen_i2s_bits(hw_params), + OXYGEN_I2S_RATE_MASK | + OXYGEN_I2S_FORMAT_MASK | + OXYGEN_I2S_MCLK_MASK | + OXYGEN_I2S_BITS_MASK); + } guard(mutex)(&chip->mutex); chip->model.set_adc_params(chip, hw_params); @@ -383,21 +383,21 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, is_ac97 = chip->has_ac97_1 && (chip->model.device_config & CAPTURE_2_FROM_AC97_1); - spin_lock_irq(&chip->reg_lock); - oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, - oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT, - OXYGEN_REC_FORMAT_B_MASK); - if (!is_ac97) - oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, - oxygen_rate(hw_params) | - chip->model.adc_i2s_format | - get_mclk(chip, PCM_B, hw_params) | - oxygen_i2s_bits(hw_params), - OXYGEN_I2S_RATE_MASK | - OXYGEN_I2S_FORMAT_MASK | - OXYGEN_I2S_MCLK_MASK | - OXYGEN_I2S_BITS_MASK); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, + oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT, + OXYGEN_REC_FORMAT_B_MASK); + if (!is_ac97) + oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, + oxygen_rate(hw_params) | + chip->model.adc_i2s_format | + get_mclk(chip, PCM_B, hw_params) | + oxygen_i2s_bits(hw_params), + OXYGEN_I2S_RATE_MASK | + OXYGEN_I2S_FORMAT_MASK | + OXYGEN_I2S_MCLK_MASK | + OXYGEN_I2S_BITS_MASK); + } if (!is_ac97) { guard(mutex)(&chip->mutex); @@ -419,21 +419,21 @@ static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream, is_spdif = chip->model.device_config & CAPTURE_1_FROM_SPDIF; - spin_lock_irq(&chip->reg_lock); - oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, - oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT, - OXYGEN_REC_FORMAT_C_MASK); - if (!is_spdif) - oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT, - oxygen_rate(hw_params) | - chip->model.adc_i2s_format | - get_mclk(chip, PCM_B, hw_params) | - oxygen_i2s_bits(hw_params), - OXYGEN_I2S_RATE_MASK | - OXYGEN_I2S_FORMAT_MASK | - OXYGEN_I2S_MCLK_MASK | - OXYGEN_I2S_BITS_MASK); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, + oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT, + OXYGEN_REC_FORMAT_C_MASK); + if (!is_spdif) + oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT, + oxygen_rate(hw_params) | + chip->model.adc_i2s_format | + get_mclk(chip, PCM_B, hw_params) | + oxygen_i2s_bits(hw_params), + OXYGEN_I2S_RATE_MASK | + OXYGEN_I2S_FORMAT_MASK | + OXYGEN_I2S_MCLK_MASK | + OXYGEN_I2S_BITS_MASK); + } if (!is_spdif) { guard(mutex)(&chip->mutex); @@ -453,7 +453,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, return err; guard(mutex)(&chip->mutex); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_OUT_ENABLE); oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, @@ -463,7 +463,6 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, oxygen_rate(hw_params) << OXYGEN_SPDIF_OUT_RATE_SHIFT, OXYGEN_SPDIF_OUT_RATE_MASK); oxygen_update_spdif_source(chip); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -478,24 +477,24 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, return err; guard(mutex)(&chip->mutex); - spin_lock_irq(&chip->reg_lock); - oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, - oxygen_play_channels(hw_params), - OXYGEN_PLAY_CHANNELS_MASK); - oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, - oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT, - OXYGEN_MULTICH_FORMAT_MASK); - oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, - oxygen_rate(hw_params) | - chip->model.dac_i2s_format | - get_mclk(chip, PCM_MULTICH, hw_params) | - oxygen_i2s_bits(hw_params), - OXYGEN_I2S_RATE_MASK | - OXYGEN_I2S_FORMAT_MASK | - OXYGEN_I2S_MCLK_MASK | - OXYGEN_I2S_BITS_MASK); - oxygen_update_spdif_source(chip); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, + oxygen_play_channels(hw_params), + OXYGEN_PLAY_CHANNELS_MASK); + oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, + oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT, + OXYGEN_MULTICH_FORMAT_MASK); + oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, + oxygen_rate(hw_params) | + chip->model.dac_i2s_format | + get_mclk(chip, PCM_MULTICH, hw_params) | + oxygen_i2s_bits(hw_params), + OXYGEN_I2S_RATE_MASK | + OXYGEN_I2S_FORMAT_MASK | + OXYGEN_I2S_MCLK_MASK | + OXYGEN_I2S_BITS_MASK); + oxygen_update_spdif_source(chip); + } chip->model.set_dac_params(chip, hw_params); oxygen_update_dac_routing(chip); @@ -508,13 +507,12 @@ static int oxygen_hw_free(struct snd_pcm_substream *substream) unsigned int channel = oxygen_substream_channel(substream); unsigned int channel_mask = 1 << channel; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); chip->interrupt_mask &= ~channel_mask; oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -523,10 +521,10 @@ static int oxygen_spdif_hw_free(struct snd_pcm_substream *substream) { struct oxygen *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); - oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, - OXYGEN_SPDIF_OUT_ENABLE); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, + OXYGEN_SPDIF_OUT_ENABLE); + } return oxygen_hw_free(substream); } @@ -536,7 +534,7 @@ static int oxygen_prepare(struct snd_pcm_substream *substream) unsigned int channel = oxygen_substream_channel(substream); unsigned int channel_mask = 1 << channel; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); @@ -545,7 +543,6 @@ static int oxygen_prepare(struct snd_pcm_substream *substream) else chip->interrupt_mask |= channel_mask; oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -577,7 +574,7 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) } } - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); if (!pausing) { if (cmd == SNDRV_PCM_TRIGGER_START) chip->pcm_running |= mask; @@ -590,7 +587,6 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) else oxygen_clear_bits8(chip, OXYGEN_DMA_PAUSE, mask); } - spin_unlock(&chip->reg_lock); return 0; } diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index d608803fd87477..47b2758653e42b 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -339,11 +339,10 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, unsigned int reg, unsigned int mute) { if (reg == AC97_LINE) { - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, mute ? GPIO_D1_INPUT_ROUTE : 0, GPIO_D1_INPUT_ROUTE); - spin_unlock_irq(&chip->reg_lock); } } diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c index e951f54780756f..0edf67ce37d1a5 100644 --- a/sound/pci/oxygen/xonar_lib.c +++ b/sound/pci/oxygen/xonar_lib.c @@ -109,7 +109,7 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, u16 old_bits, new_bits; int changed; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); if (!!value->value.integer.value[0] ^ invert) new_bits = old_bits | bit; @@ -118,6 +118,5 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, changed = new_bits != old_bits; if (changed) oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); - spin_unlock_irq(&chip->reg_lock); return changed; } diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index a491c9c92989e5..837a9505382a2f 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -1021,11 +1021,10 @@ static void xonar_line_mic_ac97_switch(struct oxygen *chip, unsigned int reg, unsigned int mute) { if (reg == AC97_LINE) { - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, mute ? GPIO_INPUT_ROUTE : 0, GPIO_INPUT_ROUTE); - spin_unlock_irq(&chip->reg_lock); } } From 26e4346cff3a33fed726c074df4719eddd930175 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:23 +0200 Subject: [PATCH 0958/1292] ALSA: pcxhr: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-49-tiwai@suse.de --- sound/pci/pcxhr/pcxhr.c | 35 +++++---------------- sound/pci/pcxhr/pcxhr_core.c | 15 +++------ sound/pci/pcxhr/pcxhr_mix22.c | 23 +++++++------- sound/pci/pcxhr/pcxhr_mixer.c | 58 +++++++++++++---------------------- 4 files changed, 45 insertions(+), 86 deletions(-) diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index bfd84c50e98148..83066d08367e61 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -701,7 +701,7 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) start_time = ktime_get(); #endif - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); /* check the pipes concerned and build pipe_array */ for (i = 0; i < mgr->num_cards; i++) { @@ -720,7 +720,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) } } if (capture_mask == 0 && playback_mask == 0) { - mutex_unlock(&mgr->setup_mutex); dev_err(&mgr->pci->dev, "%s : no pipes\n", __func__); return; } @@ -731,7 +730,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) /* synchronous stop of all the pipes concerned */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err) { - mutex_unlock(&mgr->setup_mutex); dev_err(&mgr->pci->dev, "%s : " "error stop pipes (P%x C%x)\n", __func__, playback_mask, capture_mask); @@ -776,7 +774,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) /* synchronous start of all the pipes concerned */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); if (err) { - mutex_unlock(&mgr->setup_mutex); dev_err(&mgr->pci->dev, "%s : " "error start pipes (P%x C%x)\n", __func__, playback_mask, capture_mask); @@ -786,7 +783,7 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) /* put the streams into the running state now * (increment pointer by interrupt) */ - mutex_lock(&mgr->lock); + guard(mutex)(&mgr->lock); for ( i =0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; chip = mgr->chip[i]; @@ -804,9 +801,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) } } } - mutex_unlock(&mgr->lock); - - mutex_unlock(&mgr->setup_mutex); #ifdef CONFIG_SND_DEBUG_VERBOSE stop_time = ktime_get(); @@ -907,7 +901,7 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) subs->runtime->period_size, subs->runtime->periods, subs->runtime->buffer_size); - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); do { /* only the first stream can choose the sample rate */ @@ -923,8 +917,6 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) } } while(0); /* do only once (so we can use break instead of goto) */ - mutex_unlock(&mgr->setup_mutex); - return err; } @@ -939,15 +931,13 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs, struct pcxhr_mgr *mgr = chip->mgr; struct pcxhr_stream *stream = subs->runtime->private_data; - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); /* set up channels */ stream->channels = params_channels(hw); /* set up format for the stream */ stream->format = params_format(hw); - mutex_unlock(&mgr->setup_mutex); - return 0; } @@ -990,7 +980,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) struct pcxhr_stream *stream; int err; - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); /* copy the struct snd_pcm_hardware struct */ runtime->hw = pcxhr_caps; @@ -1012,7 +1002,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs) /* streams in use */ dev_err(chip->card->dev, "%s chip%d subs%d in use\n", __func__, chip->chip_idx, subs->number); - mutex_unlock(&mgr->setup_mutex); return -EBUSY; } @@ -1023,10 +1012,8 @@ static int pcxhr_open(struct snd_pcm_substream *subs) /* buffer-size should better be multiple of period-size */ err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - mutex_unlock(&mgr->setup_mutex); + if (err < 0) return err; - } /* if a sample rate is already used or fixed by external clock, * the stream cannot change @@ -1040,7 +1027,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs) &external_rate) || external_rate == 0) { /* cannot detect the external clock rate */ - mutex_unlock(&mgr->setup_mutex); return -EBUSY; } runtime->hw.rate_min = external_rate; @@ -1063,7 +1049,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs) mgr->ref_count_rate++; - mutex_unlock(&mgr->setup_mutex); return 0; } @@ -1074,7 +1059,7 @@ static int pcxhr_close(struct snd_pcm_substream *subs) struct pcxhr_mgr *mgr = chip->mgr; struct pcxhr_stream *stream = subs->runtime->private_data; - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); dev_dbg(chip->card->dev, "%s chip%d subs%d\n", __func__, chip->chip_idx, subs->number); @@ -1088,8 +1073,6 @@ static int pcxhr_close(struct snd_pcm_substream *subs) stream->status = PCXHR_STREAM_STATUS_FREE; stream->substream = NULL; - mutex_unlock(&mgr->setup_mutex); - return 0; } @@ -1102,14 +1085,12 @@ static snd_pcm_uframes_t pcxhr_stream_pointer(struct snd_pcm_substream *subs) struct snd_pcm_runtime *runtime = subs->runtime; struct pcxhr_stream *stream = runtime->private_data; - mutex_lock(&chip->mgr->lock); + guard(mutex)(&chip->mgr->lock); /* get the period fragment and the nb of periods in the buffer */ timer_period_frag = stream->timer_period_frag; timer_buf_periods = stream->timer_buf_periods; - mutex_unlock(&chip->mgr->lock); - return (snd_pcm_uframes_t)((timer_buf_periods * runtime->period_size) + timer_period_frag); } diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 23f253effb4faa..b3b9ab4f303ee5 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -754,12 +754,8 @@ void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture, */ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) { - int err; - - mutex_lock(&mgr->msg_lock); - err = pcxhr_send_msg_nolock(mgr, rmh); - mutex_unlock(&mgr->msg_lock); - return err; + guard(mutex)(&mgr->msg_lock); + return pcxhr_send_msg_nolock(mgr, rmh); } static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) @@ -962,14 +958,13 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, struct pcxhr_rmh rmh; int err; - mutex_lock(&mgr->msg_lock); + guard(mutex)(&mgr->msg_lock); if ((mgr->io_num_reg_cont & mask) == value) { dev_dbg(&mgr->pci->dev, "IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value); if (changed) *changed = 0; - mutex_unlock(&mgr->msg_lock); return 0; /* already programmed */ } pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); @@ -984,7 +979,6 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, if (changed) *changed = 1; } - mutex_unlock(&mgr->msg_lock); return err; } @@ -1269,7 +1263,7 @@ irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id) int i, j; struct snd_pcxhr *chip; - mutex_lock(&mgr->lock); + guard(mutex)(&mgr->lock); if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) { /* is a 24 bit counter */ int dsp_time_new = @@ -1328,6 +1322,5 @@ irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id) } pcxhr_msg_thread(mgr); - mutex_unlock(&mgr->lock); return IRQ_HANDLED; } diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c index e1435afc49074f..80d22e22ea30d8 100644 --- a/sound/pci/pcxhr/pcxhr_mix22.c +++ b/sound/pci/pcxhr/pcxhr_mix22.c @@ -710,9 +710,9 @@ static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->mic_volume; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -721,13 +721,13 @@ static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int changed = 0; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); if (chip->mic_volume != ucontrol->value.integer.value[0]) { changed = 1; chip->mic_volume = ucontrol->value.integer.value[0]; hr222_update_analog_audio_level(chip, 1, 0); } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -760,9 +760,9 @@ static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->mic_boost; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -771,13 +771,13 @@ static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int changed = 0; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); if (chip->mic_boost != ucontrol->value.integer.value[0]) { changed = 1; chip->mic_boost = ucontrol->value.integer.value[0]; hr222_micro_boost(chip->mgr, chip->mic_boost); } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -800,9 +800,9 @@ static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->phantom_power; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -812,14 +812,13 @@ static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int power, changed = 0; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); power = !!ucontrol->value.integer.value[0]; if (chip->phantom_power != power) { hr222_phantom_power(chip->mgr, power); chip->phantom_power = power; changed = 1; } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index aec509461dd631..03daa2832b1b18 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -110,7 +110,8 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); if (kcontrol->private_value == 0) { /* playback */ ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; @@ -118,7 +119,6 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; } - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -129,7 +129,7 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, int changed = 0; int is_capture, i; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); is_capture = (kcontrol->private_value != 0); for (i = 0; i < 2; i++) { int new_volume = ucontrol->value.integer.value[i]; @@ -168,7 +168,6 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, is_capture, i); } } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -192,10 +191,9 @@ static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -204,7 +202,8 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int i, changed = 0; - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); for(i = 0; i < 2; i++) { if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { @@ -218,7 +217,6 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, pcxhr_update_analog_audio_level(chip, 0, i); } } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -352,14 +350,13 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, int *stored_volume; int is_capture = kcontrol->private_value; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); if (is_capture) /* digital capture */ stored_volume = chip->digital_capture_volume; else /* digital playback */ stored_volume = chip->digital_playback_volume[idx]; ucontrol->value.integer.value[0] = stored_volume[0]; ucontrol->value.integer.value[1] = stored_volume[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -373,7 +370,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, int *stored_volume; int i; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); if (is_capture) /* digital capture */ stored_volume = chip->digital_capture_volume; else /* digital playback */ @@ -392,7 +389,6 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, } if (!is_capture && changed) /* update playback volume */ pcxhr_update_playback_stream_level(chip, idx); - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -416,10 +412,9 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -431,7 +426,7 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int i, j; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); j = idx; for (i = 0; i < 2; i++) { if (chip->digital_playback_active[j][i] != @@ -443,7 +438,6 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, } if (changed) pcxhr_update_playback_stream_level(chip, idx); - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -465,10 +459,10 @@ static int pcxhr_monitor_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -479,7 +473,7 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, int changed = 0; int i; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); for (i = 0; i < 2; i++) { if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { @@ -492,7 +486,6 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, changed = 1; } } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } @@ -515,10 +508,10 @@ static int pcxhr_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); + + guard(mutex)(&chip->mgr->mixer_mutex); ucontrol->value.integer.value[0] = chip->monitoring_active[0]; ucontrol->value.integer.value[1] = chip->monitoring_active[1]; - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -529,7 +522,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, int changed = 0; int i; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); for (i = 0; i < 2; i++) { if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { @@ -545,7 +538,6 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, /* update right monitoring volume and mute */ pcxhr_update_audio_pipe_level(chip, 0, 1); - mutex_unlock(&chip->mgr->mixer_mutex); return (changed != 0); } @@ -671,7 +663,7 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, } if (ucontrol->value.enumerated.item[0] >= i) return -EINVAL; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { chip->audio_capture_source = ucontrol->value.enumerated.item[0]; if (chip->mgr->is_hr_stereo) @@ -680,7 +672,6 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, pcxhr_set_audio_source(chip); ret = 1; } - mutex_unlock(&chip->mgr->mixer_mutex); return ret; } @@ -760,9 +751,9 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, } if (ucontrol->value.enumerated.item[0] >= clock_items) return -EINVAL; - mutex_lock(&mgr->mixer_mutex); + guard(mutex)(&mgr->mixer_mutex); if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { - mutex_lock(&mgr->setup_mutex); + guard(mutex)(&mgr->setup_mutex); mgr->use_clock_type = ucontrol->value.enumerated.item[0]; rate = 0; if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) { @@ -778,10 +769,8 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, if (mgr->sample_rate) mgr->sample_rate = rate; } - mutex_unlock(&mgr->setup_mutex); ret = 1; /* return 1 even if the set was not done. ok ? */ } - mutex_unlock(&mgr->mixer_mutex); return ret; } @@ -814,7 +803,7 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); int i, err, rate; - mutex_lock(&mgr->mixer_mutex); + guard(mutex)(&mgr->mixer_mutex); for(i = 0; i < 3 + mgr->capture_chips; i++) { if (i == PCXHR_CLOCK_TYPE_INTERNAL) rate = mgr->sample_rate_real; @@ -825,7 +814,6 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, } ucontrol->value.integer.value[i] = rate; } - mutex_unlock(&mgr->mixer_mutex); return 0; } @@ -918,7 +906,7 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, unsigned char aes_bits; int i, err; - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); for(i = 0; i < 5; i++) { if (kcontrol->private_value == 0) /* playback */ aes_bits = chip->aes_bits[i]; @@ -934,7 +922,6 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, } ucontrol->value.iec958.status[i] = aes_bits; } - mutex_unlock(&chip->mgr->mixer_mutex); return 0; } @@ -988,7 +975,7 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, int i, changed = 0; /* playback */ - mutex_lock(&chip->mgr->mixer_mutex); + guard(mutex)(&chip->mgr->mixer_mutex); for (i = 0; i < 5; i++) { if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { if (chip->mgr->is_hr_stereo) @@ -1000,7 +987,6 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, changed = 1; } } - mutex_unlock(&chip->mgr->mixer_mutex); return changed; } From 8bb75ae244c5894ae08e090a52faaca8330fef62 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:24 +0200 Subject: [PATCH 0959/1292] ALSA: rme32: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-50-tiwai@suse.de --- sound/pci/rme32.c | 152 +++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 96 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f07b6023473a06..123dddcb697211 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -646,35 +646,27 @@ snd_rme32_playback_hw_params(struct snd_pcm_substream *substream, runtime->dma_bytes = RME32_BUFFER_SIZE; } - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); rate = 0; if (rme32->rcreg & RME32_RCR_KMODE) rate = snd_rme32_capture_getrate(rme32, &dummy); if (rate > 0) { /* AutoSync */ - if ((int)params_rate(params) != rate) { - spin_unlock_irq(&rme32->lock); + if ((int)params_rate(params) != rate) return -EIO; - } } else { err = snd_rme32_playback_setrate(rme32, params_rate(params)); - if (err < 0) { - spin_unlock_irq(&rme32->lock); + if (err < 0) return err; - } } err = snd_rme32_setformat(rme32, params_format(params)); - if (err < 0) { - spin_unlock_irq(&rme32->lock); + if (err < 0) return err; - } snd_rme32_setframelog(rme32, params_channels(params), 1); if (rme32->capture_periodsize != 0) { - if (params_period_size(params) << rme32->playback_frlog != rme32->capture_periodsize) { - spin_unlock_irq(&rme32->lock); + if (params_period_size(params) << rme32->playback_frlog != rme32->capture_periodsize) return -EBUSY; - } } rme32->playback_periodsize = params_period_size(params) << rme32->playback_frlog; /* S/PDIF setup */ @@ -683,7 +675,6 @@ snd_rme32_playback_hw_params(struct snd_pcm_substream *substream, rme32->wcreg |= rme32->wcreg_spdif_stream; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); } - spin_unlock_irq(&rme32->lock); return 0; } @@ -703,32 +694,24 @@ snd_rme32_capture_hw_params(struct snd_pcm_substream *substream, runtime->dma_bytes = RME32_BUFFER_SIZE; } - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); /* enable AutoSync for record-preparing */ rme32->wcreg |= RME32_WCR_AUTOSYNC; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); err = snd_rme32_setformat(rme32, params_format(params)); - if (err < 0) { - spin_unlock_irq(&rme32->lock); + if (err < 0) return err; - } err = snd_rme32_playback_setrate(rme32, params_rate(params)); - if (err < 0) { - spin_unlock_irq(&rme32->lock); + if (err < 0) return err; - } rate = snd_rme32_capture_getrate(rme32, &isadat); if (rate > 0) { - if ((int)params_rate(params) != rate) { - spin_unlock_irq(&rme32->lock); + if ((int)params_rate(params) != rate) return -EIO; - } if ((isadat && runtime->hw.channels_min == 2) || - (!isadat && runtime->hw.channels_min == 8)) { - spin_unlock_irq(&rme32->lock); + (!isadat && runtime->hw.channels_min == 8)) return -EIO; - } } /* AutoSync off for recording */ rme32->wcreg &= ~RME32_WCR_AUTOSYNC; @@ -737,14 +720,11 @@ snd_rme32_capture_hw_params(struct snd_pcm_substream *substream, snd_rme32_setframelog(rme32, params_channels(params), 0); if (rme32->playback_periodsize != 0) { if (params_period_size(params) << rme32->capture_frlog != - rme32->playback_periodsize) { - spin_unlock_irq(&rme32->lock); + rme32->playback_periodsize) return -EBUSY; - } } rme32->capture_periodsize = params_period_size(params) << rme32->capture_frlog; - spin_unlock_irq(&rme32->lock); return 0; } @@ -824,15 +804,13 @@ static int snd_rme32_playback_spdif_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); - spin_lock_irq(&rme32->lock); - if (rme32->playback_substream != NULL) { - spin_unlock_irq(&rme32->lock); - return -EBUSY; + scoped_guard(spinlock_irq, &rme32->lock) { + if (rme32->playback_substream != NULL) + return -EBUSY; + rme32->wcreg &= ~RME32_WCR_ADAT; + writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); + rme32->playback_substream = substream; } - rme32->wcreg &= ~RME32_WCR_ADAT; - writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); - rme32->playback_substream = substream; - spin_unlock_irq(&rme32->lock); if (rme32->fullduplex_mode) runtime->hw = snd_rme32_spdif_fd_info; @@ -869,13 +847,11 @@ static int snd_rme32_capture_spdif_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); - spin_lock_irq(&rme32->lock); - if (rme32->capture_substream != NULL) { - spin_unlock_irq(&rme32->lock); - return -EBUSY; - } - rme32->capture_substream = substream; - spin_unlock_irq(&rme32->lock); + scoped_guard(spinlock_irq, &rme32->lock) { + if (rme32->capture_substream != NULL) + return -EBUSY; + rme32->capture_substream = substream; + } if (rme32->fullduplex_mode) runtime->hw = snd_rme32_spdif_fd_info; @@ -909,15 +885,13 @@ snd_rme32_playback_adat_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); - spin_lock_irq(&rme32->lock); - if (rme32->playback_substream != NULL) { - spin_unlock_irq(&rme32->lock); - return -EBUSY; - } - rme32->wcreg |= RME32_WCR_ADAT; - writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); - rme32->playback_substream = substream; - spin_unlock_irq(&rme32->lock); + scoped_guard(spinlock_irq, &rme32->lock) { + if (rme32->playback_substream != NULL) + return -EBUSY; + rme32->wcreg |= RME32_WCR_ADAT; + writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); + rme32->playback_substream = substream; + } if (rme32->fullduplex_mode) runtime->hw = snd_rme32_adat_fd_info; @@ -960,13 +934,11 @@ snd_rme32_capture_adat_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); - spin_lock_irq(&rme32->lock); - if (rme32->capture_substream != NULL) { - spin_unlock_irq(&rme32->lock); - return -EBUSY; - } - rme32->capture_substream = substream; - spin_unlock_irq(&rme32->lock); + scoped_guard(spinlock_irq, &rme32->lock) { + if (rme32->capture_substream != NULL) + spin_unlock_irq(&rme32->lock); + rme32->capture_substream = substream; + } snd_rme32_set_buffer_constraint(rme32, runtime); return 0; @@ -977,11 +949,11 @@ static int snd_rme32_playback_close(struct snd_pcm_substream *substream) struct rme32 *rme32 = snd_pcm_substream_chip(substream); int spdif = 0; - spin_lock_irq(&rme32->lock); - rme32->playback_substream = NULL; - rme32->playback_periodsize = 0; - spdif = (rme32->wcreg & RME32_WCR_ADAT) == 0; - spin_unlock_irq(&rme32->lock); + scoped_guard(spinlock_irq, &rme32->lock) { + rme32->playback_substream = NULL; + rme32->playback_periodsize = 0; + spdif = (rme32->wcreg & RME32_WCR_ADAT) == 0; + } if (spdif) { rme32->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(rme32->card, SNDRV_CTL_EVENT_MASK_VALUE | @@ -995,10 +967,9 @@ static int snd_rme32_capture_close(struct snd_pcm_substream *substream) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); rme32->capture_substream = NULL; rme32->capture_periodsize = 0; - spin_unlock_irq(&rme32->lock); return 0; } @@ -1006,7 +977,7 @@ static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); if (rme32->fullduplex_mode) { memset(&rme32->playback_pcm, 0, sizeof(rme32->playback_pcm)); rme32->playback_pcm.hw_buffer_size = RME32_BUFFER_SIZE; @@ -1017,7 +988,6 @@ static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream) if (rme32->wcreg & RME32_WCR_SEL) rme32->wcreg &= ~RME32_WCR_MUTE; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); - spin_unlock_irq(&rme32->lock); return 0; } @@ -1025,7 +995,7 @@ static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream) { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); if (rme32->fullduplex_mode) { memset(&rme32->capture_pcm, 0, sizeof(rme32->capture_pcm)); rme32->capture_pcm.hw_buffer_size = RME32_BUFFER_SIZE; @@ -1034,7 +1004,6 @@ static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream) } else { writel(0, rme32->iobase + RME32_IO_RESET_POS); } - spin_unlock_irq(&rme32->lock); return 0; } @@ -1044,7 +1013,7 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_substream *s; - spin_lock(&rme32->lock); + guard(spinlock)(&rme32->lock); snd_pcm_group_for_each_entry(s, substream) { if (s != rme32->playback_substream && s != rme32->capture_substream) @@ -1088,7 +1057,6 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_rme32_pcm_start(rme32, 1); break; } - spin_unlock(&rme32->lock); return 0; } @@ -1124,11 +1092,11 @@ static int snd_rme32_playback_fd_ack(struct snd_pcm_substream *substream) rec = &rme32->playback_pcm; cprec = &rme32->capture_pcm; - spin_lock(&rme32->lock); - rec->hw_queue_size = RME32_BUFFER_SIZE; - if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) - rec->hw_queue_size -= cprec->hw_ready; - spin_unlock(&rme32->lock); + scoped_guard(spinlock, &rme32->lock) { + rec->hw_queue_size = RME32_BUFFER_SIZE; + if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) + rec->hw_queue_size -= cprec->hw_ready; + } return snd_pcm_indirect_playback_transfer(substream, rec, snd_rme32_pb_trans_copy); } @@ -1513,10 +1481,9 @@ snd_rme32_get_loopback_control(struct snd_kcontrol *kcontrol, { struct rme32 *rme32 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); ucontrol->value.integer.value[0] = rme32->wcreg & RME32_WCR_SEL ? 0 : 1; - spin_unlock_irq(&rme32->lock); return 0; } static int @@ -1528,7 +1495,7 @@ snd_rme32_put_loopback_control(struct snd_kcontrol *kcontrol, int change; val = ucontrol->value.integer.value[0] ? 0 : RME32_WCR_SEL; - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); val = (rme32->wcreg & ~RME32_WCR_SEL) | val; change = val != rme32->wcreg; if (ucontrol->value.integer.value[0]) @@ -1537,7 +1504,6 @@ snd_rme32_put_loopback_control(struct snd_kcontrol *kcontrol, val |= RME32_WCR_MUTE; rme32->wcreg = val; writel(val, rme32->iobase + RME32_IO_CONTROL_REGISTER); - spin_unlock_irq(&rme32->lock); return change; } @@ -1572,7 +1538,7 @@ snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol, struct rme32 *rme32 = snd_kcontrol_chip(kcontrol); unsigned int items = 3; - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); ucontrol->value.enumerated.item[0] = snd_rme32_getinputtype(rme32); switch (rme32->pci->device) { @@ -1591,7 +1557,6 @@ snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol, ucontrol->value.enumerated.item[0] = items - 1; } - spin_unlock_irq(&rme32->lock); return 0; } static int @@ -1616,10 +1581,9 @@ snd_rme32_put_inputtype_control(struct snd_kcontrol *kcontrol, } val = ucontrol->value.enumerated.item[0] % items; - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); change = val != (unsigned int)snd_rme32_getinputtype(rme32); snd_rme32_setinputtype(rme32, val); - spin_unlock_irq(&rme32->lock); return change; } @@ -1640,9 +1604,8 @@ snd_rme32_get_clockmode_control(struct snd_kcontrol *kcontrol, { struct rme32 *rme32 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); ucontrol->value.enumerated.item[0] = snd_rme32_getclockmode(rme32); - spin_unlock_irq(&rme32->lock); return 0; } static int @@ -1654,10 +1617,9 @@ snd_rme32_put_clockmode_control(struct snd_kcontrol *kcontrol, int change; val = ucontrol->value.enumerated.item[0] % 3; - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); change = val != (unsigned int)snd_rme32_getclockmode(rme32); snd_rme32_setclockmode(rme32, val); - spin_unlock_irq(&rme32->lock); return change; } @@ -1707,10 +1669,9 @@ static int snd_rme32_control_spdif_put(struct snd_kcontrol *kcontrol, u32 val; val = snd_rme32_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); change = val != rme32->wcreg_spdif; rme32->wcreg_spdif = val; - spin_unlock_irq(&rme32->lock); return change; } @@ -1742,13 +1703,12 @@ static int snd_rme32_control_spdif_stream_put(struct snd_kcontrol *kcontrol, u32 val; val = snd_rme32_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&rme32->lock); + guard(spinlock_irq)(&rme32->lock); change = val != rme32->wcreg_spdif_stream; rme32->wcreg_spdif_stream = val; rme32->wcreg &= ~(RME32_WCR_PRO | RME32_WCR_EMP); rme32->wcreg |= val; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); - spin_unlock_irq(&rme32->lock); return change; } From d3424b8bf78593e1751cfa19628aa0008d2e08ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:25 +0200 Subject: [PATCH 0960/1292] ALSA: rme96: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-51-tiwai@suse.de --- sound/pci/rme96.c | 211 +++++++++++++++++++--------------------------- 1 file changed, 85 insertions(+), 126 deletions(-) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 5cdbbe9cf99419..58b8ebf1a24e7d 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -964,48 +964,45 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, runtime->dma_addr = rme96->port + RME96_IO_PLAY_BUFFER; runtime->dma_bytes = RME96_BUFFER_SIZE; - spin_lock_irq(&rme96->lock); - rate = 0; - if (!(rme96->wcreg & RME96_WCR_MASTER) && - snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) - rate = snd_rme96_capture_getrate(rme96, &dummy); - if (rate > 0) { - /* slave clock */ - if ((int)params_rate(params) != rate) { - err = -EIO; - goto error; + scoped_guard(spinlock_irq, &rme96->lock) { + rate = 0; + if (!(rme96->wcreg & RME96_WCR_MASTER) && + snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) + rate = snd_rme96_capture_getrate(rme96, &dummy); + if (rate > 0) { + /* slave clock */ + if ((int)params_rate(params) != rate) + return -EIO; + } else { + err = snd_rme96_playback_setrate(rme96, params_rate(params)); + if (err < 0) + return err; + apply_dac_volume = err > 0; /* need to restore volume later? */ } - } else { - err = snd_rme96_playback_setrate(rme96, params_rate(params)); - if (err < 0) - goto error; - apply_dac_volume = err > 0; /* need to restore volume later? */ - } - err = snd_rme96_playback_setformat(rme96, params_format(params)); - if (err < 0) - goto error; - snd_rme96_setframelog(rme96, params_channels(params), 1); - if (rme96->capture_periodsize != 0) { - if (params_period_size(params) << rme96->playback_frlog != - rme96->capture_periodsize) - { - err = -EBUSY; + err = snd_rme96_playback_setformat(rme96, params_format(params)); + if (err < 0) goto error; + snd_rme96_setframelog(rme96, params_channels(params), 1); + if (rme96->capture_periodsize != 0) { + if (params_period_size(params) << rme96->playback_frlog != + rme96->capture_periodsize) { + err = -EBUSY; + goto error; + } + } + rme96->playback_periodsize = + params_period_size(params) << rme96->playback_frlog; + snd_rme96_set_period_properties(rme96, rme96->playback_periodsize); + /* S/PDIF setup */ + if ((rme96->wcreg & RME96_WCR_ADAT) == 0) { + rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP); + writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER); } - } - rme96->playback_periodsize = - params_period_size(params) << rme96->playback_frlog; - snd_rme96_set_period_properties(rme96, rme96->playback_periodsize); - /* S/PDIF setup */ - if ((rme96->wcreg & RME96_WCR_ADAT) == 0) { - rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP); - writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER); - } - err = 0; + err = 0; + } error: - spin_unlock_irq(&rme96->lock); if (apply_dac_volume) { usleep_range(3000, 10000); snd_rme96_apply_dac_volume(rme96); @@ -1027,45 +1024,33 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream, runtime->dma_addr = rme96->port + RME96_IO_REC_BUFFER; runtime->dma_bytes = RME96_BUFFER_SIZE; - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); err = snd_rme96_capture_setformat(rme96, params_format(params)); - if (err < 0) { - spin_unlock_irq(&rme96->lock); + if (err < 0) return err; - } if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { err = snd_rme96_capture_analog_setrate(rme96, params_rate(params)); - if (err < 0) { - spin_unlock_irq(&rme96->lock); + if (err < 0) return err; - } } else { rate = snd_rme96_capture_getrate(rme96, &isadat); if (rate > 0) { - if ((int)params_rate(params) != rate) { - spin_unlock_irq(&rme96->lock); + if ((int)params_rate(params) != rate) return -EIO; - } if ((isadat && runtime->hw.channels_min == 2) || - (!isadat && runtime->hw.channels_min == 8)) { - spin_unlock_irq(&rme96->lock); + (!isadat && runtime->hw.channels_min == 8)) return -EIO; - } } } snd_rme96_setframelog(rme96, params_channels(params), 0); if (rme96->playback_periodsize != 0) { if (params_period_size(params) << rme96->capture_frlog != rme96->playback_periodsize) - { - spin_unlock_irq(&rme96->lock); return -EBUSY; - } } rme96->capture_periodsize = params_period_size(params) << rme96->capture_frlog; snd_rme96_set_period_properties(rme96, rme96->capture_periodsize); - spin_unlock_irq(&rme96->lock); return 0; } @@ -1165,15 +1150,13 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_set_sync(substream); - spin_lock_irq(&rme96->lock); - if (rme96->playback_substream) { - spin_unlock_irq(&rme96->lock); - return -EBUSY; - } - rme96->wcreg &= ~RME96_WCR_ADAT; - writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); - rme96->playback_substream = substream; - spin_unlock_irq(&rme96->lock); + scoped_guard(spinlock_irq, &rme96->lock) { + if (rme96->playback_substream) + return -EBUSY; + rme96->wcreg &= ~RME96_WCR_ADAT; + writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); + rme96->playback_substream = substream; + } runtime->hw = snd_rme96_playback_spdif_info; if (!(rme96->wcreg & RME96_WCR_MASTER) && @@ -1215,13 +1198,11 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) } } - spin_lock_irq(&rme96->lock); - if (rme96->capture_substream) { - spin_unlock_irq(&rme96->lock); - return -EBUSY; - } - rme96->capture_substream = substream; - spin_unlock_irq(&rme96->lock); + scoped_guard(spinlock_irq, &rme96->lock) { + if (rme96->capture_substream) + return -EBUSY; + rme96->capture_substream = substream; + } rme96_set_buffer_size_constraint(rme96, runtime); return 0; @@ -1235,15 +1216,13 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_set_sync(substream); - spin_lock_irq(&rme96->lock); - if (rme96->playback_substream) { - spin_unlock_irq(&rme96->lock); - return -EBUSY; - } - rme96->wcreg |= RME96_WCR_ADAT; - writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); - rme96->playback_substream = substream; - spin_unlock_irq(&rme96->lock); + scoped_guard(spinlock_irq, &rme96->lock) { + if (rme96->playback_substream) + return -EBUSY; + rme96->wcreg |= RME96_WCR_ADAT; + writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); + rme96->playback_substream = substream; + } runtime->hw = snd_rme96_playback_adat_info; if (!(rme96->wcreg & RME96_WCR_MASTER) && @@ -1285,13 +1264,11 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) runtime->hw.rate_max = rate; } - spin_lock_irq(&rme96->lock); - if (rme96->capture_substream) { - spin_unlock_irq(&rme96->lock); - return -EBUSY; - } - rme96->capture_substream = substream; - spin_unlock_irq(&rme96->lock); + scoped_guard(spinlock_irq, &rme96->lock) { + if (rme96->capture_substream) + return -EBUSY; + rme96->capture_substream = substream; + } rme96_set_buffer_size_constraint(rme96, runtime); return 0; @@ -1303,14 +1280,13 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); int spdif = 0; - spin_lock_irq(&rme96->lock); - if (RME96_ISPLAYING(rme96)) { - snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); + scoped_guard(spinlock_irq, &rme96->lock) { + if (RME96_ISPLAYING(rme96)) + snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); + rme96->playback_substream = NULL; + rme96->playback_periodsize = 0; + spdif = (rme96->wcreg & RME96_WCR_ADAT) == 0; } - rme96->playback_substream = NULL; - rme96->playback_periodsize = 0; - spdif = (rme96->wcreg & RME96_WCR_ADAT) == 0; - spin_unlock_irq(&rme96->lock); if (spdif) { rme96->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(rme96->card, SNDRV_CTL_EVENT_MASK_VALUE | @@ -1324,13 +1300,12 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); if (RME96_ISRECORDING(rme96)) { snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); } rme96->capture_substream = NULL; rme96->capture_periodsize = 0; - spin_unlock_irq(&rme96->lock); return 0; } @@ -1339,12 +1314,11 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); if (RME96_ISPLAYING(rme96)) { snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); } writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); - spin_unlock_irq(&rme96->lock); return 0; } @@ -1353,12 +1327,11 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); if (RME96_ISRECORDING(rme96)) { snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); } writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); - spin_unlock_irq(&rme96->lock); return 0; } @@ -1829,9 +1802,8 @@ snd_rme96_get_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ele { struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); ucontrol->value.integer.value[0] = rme96->wcreg & RME96_WCR_SEL ? 0 : 1; - spin_unlock_irq(&rme96->lock); return 0; } static int @@ -1842,12 +1814,11 @@ snd_rme96_put_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ele int change; val = ucontrol->value.integer.value[0] ? 0 : RME96_WCR_SEL; - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); val = (rme96->wcreg & ~RME96_WCR_SEL) | val; change = val != rme96->wcreg; rme96->wcreg = val; writel(val, rme96->iobase + RME96_IO_CONTROL_REGISTER); - spin_unlock_irq(&rme96->lock); return change; } @@ -1893,7 +1864,7 @@ snd_rme96_get_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); unsigned int items = 3; - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); ucontrol->value.enumerated.item[0] = snd_rme96_getinputtype(rme96); switch (rme96->pci->device) { @@ -1923,7 +1894,6 @@ snd_rme96_get_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el ucontrol->value.enumerated.item[0] = items - 1; } - spin_unlock_irq(&rme96->lock); return 0; } static int @@ -1961,10 +1931,9 @@ snd_rme96_put_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el } } - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); change = (int)val != snd_rme96_getinputtype(rme96); snd_rme96_setinputtype(rme96, val); - spin_unlock_irq(&rme96->lock); return change; } @@ -1980,9 +1949,8 @@ snd_rme96_get_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el { struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); ucontrol->value.enumerated.item[0] = snd_rme96_getclockmode(rme96); - spin_unlock_irq(&rme96->lock); return 0; } static int @@ -1993,10 +1961,9 @@ snd_rme96_put_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el int change; val = ucontrol->value.enumerated.item[0] % 3; - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); change = (int)val != snd_rme96_getclockmode(rme96); snd_rme96_setclockmode(rme96, val); - spin_unlock_irq(&rme96->lock); return change; } @@ -2014,9 +1981,8 @@ snd_rme96_get_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ { struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); ucontrol->value.enumerated.item[0] = snd_rme96_getattenuation(rme96); - spin_unlock_irq(&rme96->lock); return 0; } static int @@ -2027,11 +1993,10 @@ snd_rme96_put_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ int change; val = ucontrol->value.enumerated.item[0] % 4; - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); change = (int)val != snd_rme96_getattenuation(rme96); snd_rme96_setattenuation(rme96, val); - spin_unlock_irq(&rme96->lock); return change; } @@ -2047,9 +2012,8 @@ snd_rme96_get_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el { struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); ucontrol->value.enumerated.item[0] = snd_rme96_getmontracks(rme96); - spin_unlock_irq(&rme96->lock); return 0; } static int @@ -2060,10 +2024,9 @@ snd_rme96_put_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el int change; val = ucontrol->value.enumerated.item[0] % 4; - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); change = (int)val != snd_rme96_getmontracks(rme96); snd_rme96_setmontracks(rme96, val); - spin_unlock_irq(&rme96->lock); return change; } @@ -2111,10 +2074,9 @@ static int snd_rme96_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd u32 val; val = snd_rme96_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); change = val != rme96->wcreg_spdif; rme96->wcreg_spdif = val; - spin_unlock_irq(&rme96->lock); return change; } @@ -2140,13 +2102,12 @@ static int snd_rme96_control_spdif_stream_put(struct snd_kcontrol *kcontrol, str u32 val; val = snd_rme96_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); change = val != rme96->wcreg_spdif_stream; rme96->wcreg_spdif_stream = val; rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP); rme96->wcreg |= val; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); - spin_unlock_irq(&rme96->lock); return change; } @@ -2180,10 +2141,9 @@ snd_rme96_dac_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); u->value.integer.value[0] = rme96->vol[0]; u->value.integer.value[1] = rme96->vol[1]; - spin_unlock_irq(&rme96->lock); return 0; } @@ -2199,7 +2159,7 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu if (!RME96_HAS_ANALOG_OUT(rme96)) return -EINVAL; maxvol = RME96_185X_MAX_OUT(rme96); - spin_lock_irq(&rme96->lock); + guard(spinlock_irq)(&rme96->lock); vol = u->value.integer.value[0]; if (vol != rme96->vol[0] && vol <= maxvol) { rme96->vol[0] = vol; @@ -2212,7 +2172,6 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu } if (change) snd_rme96_apply_dac_volume(rme96); - spin_unlock_irq(&rme96->lock); return change; } From d422878cae31fcde30818ea082c23c6bf03fd0e3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:26 +0200 Subject: [PATCH 0961/1292] ALSA: hdsp: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-52-tiwai@suse.de --- sound/pci/rme9652/hdsp.c | 311 ++++++++++++++++----------------------- 1 file changed, 125 insertions(+), 186 deletions(-) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 7ce73746168a1c..31cc2d91c8d2f8 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -691,7 +691,6 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops, static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) { int i; - unsigned long flags; const u32 *cache; if (hdsp->fw_uploaded) @@ -746,9 +745,8 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) { if (hdsp->state & HDSP_InitializationComplete) { dev_info(hdsp->card->dev, "firmware loaded from cache, restoring defaults\n"); - spin_lock_irqsave(&hdsp->lock, flags); + guard(spinlock_irqsave)(&hdsp->lock); snd_hdsp_set_defaults(hdsp); - spin_unlock_irqrestore(&hdsp->lock, flags); } hdsp->state |= HDSP_FirmwareLoaded; @@ -939,14 +937,12 @@ static int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short static int snd_hdsp_use_is_exclusive(struct hdsp *hdsp) { - unsigned long flags; int ret = 1; - spin_lock_irqsave(&hdsp->lock, flags); + guard(spinlock_irqsave)(&hdsp->lock); if ((hdsp->playback_pid != hdsp->capture_pid) && (hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0)) ret = 0; - spin_unlock_irqrestore(&hdsp->lock, flags); return ret; } @@ -1063,8 +1059,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) { int n; - spin_lock_irq(&s->lock); - frames >>= 7; n = 0; while (frames) { @@ -1079,8 +1073,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) hdsp_compute_period_size(s); - spin_unlock_irq(&s->lock); - return 0; } @@ -1306,7 +1298,6 @@ static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id) static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi) { - unsigned long flags; int n_pending; int to_write; int i; @@ -1314,7 +1305,7 @@ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi) /* Output is not interrupt driven */ - spin_lock_irqsave (&hmidi->lock, flags); + guard(spinlock_irqsave)(&hmidi->lock); if (hmidi->output) { if (!snd_rawmidi_transmit_empty (hmidi->output)) { n_pending = snd_hdsp_midi_output_possible(hmidi->hdsp, hmidi->id); @@ -1330,40 +1321,38 @@ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi) } } } - spin_unlock_irqrestore (&hmidi->lock, flags); return 0; } static int snd_hdsp_midi_input_read (struct hdsp_midi *hmidi) { unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */ - unsigned long flags; int n_pending; int i; - spin_lock_irqsave (&hmidi->lock, flags); - n_pending = snd_hdsp_midi_input_available(hmidi->hdsp, hmidi->id); - if (n_pending > 0) { - if (hmidi->input) { - if (n_pending > (int)sizeof (buf)) - n_pending = sizeof (buf); - for (i = 0; i < n_pending; ++i) - buf[i] = snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id); - if (n_pending) - snd_rawmidi_receive (hmidi->input, buf, n_pending); - } else { - /* flush the MIDI input FIFO */ - while (--n_pending) - snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id); + scoped_guard(spinlock_irqsave, &hmidi->lock) { + n_pending = snd_hdsp_midi_input_available(hmidi->hdsp, hmidi->id); + if (n_pending > 0) { + if (hmidi->input) { + if (n_pending > (int)sizeof(buf)) + n_pending = sizeof(buf); + for (i = 0; i < n_pending; ++i) + buf[i] = snd_hdsp_midi_read_byte(hmidi->hdsp, hmidi->id); + if (n_pending) + snd_rawmidi_receive(hmidi->input, buf, n_pending); + } else { + /* flush the MIDI input FIFO */ + while (--n_pending) + snd_hdsp_midi_read_byte(hmidi->hdsp, hmidi->id); + } } + hmidi->pending = 0; + if (hmidi->id) + hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable; + else + hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable; + hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register); } - hmidi->pending = 0; - if (hmidi->id) - hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable; - else - hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable; - hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register); - spin_unlock_irqrestore (&hmidi->lock, flags); return snd_hdsp_midi_output_write (hmidi); } @@ -1371,13 +1360,12 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, { struct hdsp *hdsp; struct hdsp_midi *hmidi; - unsigned long flags; u32 ie; hmidi = (struct hdsp_midi *) substream->rmidi->private_data; hdsp = hmidi->hdsp; ie = hmidi->id ? HDSP_Midi1InterruptEnable : HDSP_Midi0InterruptEnable; - spin_lock_irqsave (&hdsp->lock, flags); + guard(spinlock_irqsave)(&hdsp->lock); if (up) { if (!(hdsp->control_register & ie)) { snd_hdsp_flush_midi_input (hdsp, hmidi->id); @@ -1388,16 +1376,14 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - spin_unlock_irqrestore (&hdsp->lock, flags); } static void snd_hdsp_midi_output_timer(struct timer_list *t) { struct hdsp_midi *hmidi = timer_container_of(hmidi, t, timer); - unsigned long flags; snd_hdsp_midi_output_write(hmidi); - spin_lock_irqsave (&hmidi->lock, flags); + guard(spinlock_irqsave)(&hmidi->lock); /* this does not bump hmidi->istimer, because the kernel automatically removed the timer when it @@ -1407,29 +1393,26 @@ static void snd_hdsp_midi_output_timer(struct timer_list *t) if (hmidi->istimer) mod_timer(&hmidi->timer, 1 + jiffies); - - spin_unlock_irqrestore (&hmidi->lock, flags); } static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct hdsp_midi *hmidi; - unsigned long flags; hmidi = (struct hdsp_midi *) substream->rmidi->private_data; - spin_lock_irqsave (&hmidi->lock, flags); - if (up) { - if (!hmidi->istimer) { - timer_setup(&hmidi->timer, snd_hdsp_midi_output_timer, - 0); - mod_timer(&hmidi->timer, 1 + jiffies); - hmidi->istimer++; + scoped_guard(spinlock_irqsave, &hmidi->lock) { + if (up) { + if (!hmidi->istimer) { + timer_setup(&hmidi->timer, snd_hdsp_midi_output_timer, + 0); + mod_timer(&hmidi->timer, 1 + jiffies); + hmidi->istimer++; + } + } else { + if (hmidi->istimer && --hmidi->istimer <= 0) + timer_delete(&hmidi->timer); } - } else { - if (hmidi->istimer && --hmidi->istimer <= 0) - timer_delete(&hmidi->timer); } - spin_unlock_irqrestore (&hmidi->lock, flags); if (up) snd_hdsp_midi_output_write(hmidi); } @@ -1439,10 +1422,9 @@ static int snd_hdsp_midi_input_open(struct snd_rawmidi_substream *substream) struct hdsp_midi *hmidi; hmidi = (struct hdsp_midi *) substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); snd_hdsp_flush_midi_input (hmidi->hdsp, hmidi->id); hmidi->input = substream; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -1452,9 +1434,8 @@ static int snd_hdsp_midi_output_open(struct snd_rawmidi_substream *substream) struct hdsp_midi *hmidi; hmidi = (struct hdsp_midi *) substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); hmidi->output = substream; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -1466,9 +1447,8 @@ static int snd_hdsp_midi_input_close(struct snd_rawmidi_substream *substream) snd_hdsp_midi_input_trigger (substream, 0); hmidi = (struct hdsp_midi *) substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); hmidi->input = NULL; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -1480,9 +1460,8 @@ static int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream) snd_hdsp_midi_output_trigger (substream, 0); hmidi = (struct hdsp_midi *) substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); hmidi->output = NULL; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -1579,10 +1558,9 @@ static int snd_hdsp_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ u32 val; val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = val != hdsp->creg_spdif; hdsp->creg_spdif = val; - spin_unlock_irq(&hdsp->lock); return change; } @@ -1608,12 +1586,11 @@ static int snd_hdsp_control_spdif_stream_put(struct snd_kcontrol *kcontrol, stru u32 val; val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = val != hdsp->creg_spdif_stream; hdsp->creg_spdif_stream = val; hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis); hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -1679,11 +1656,10 @@ static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3); - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = val != hdsp_spdif_in(hdsp); if (change) hdsp_set_spdif_input(hdsp, val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -1720,9 +1696,8 @@ static int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol, struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); u32 regmask = kcontrol->private_value; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask); - spin_unlock_irq(&hdsp->lock); return 0; } @@ -1737,11 +1712,10 @@ static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol, if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = (int) val != hdsp_toggle_setting(hdsp, regmask); if (change) hdsp_set_toggle_setting(hdsp, regmask, val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -2047,12 +2021,11 @@ static int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_c if (val > 6) val = 6; } - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (val != hdsp_clock_source(hdsp)) change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdsp->lock); return change; } @@ -2147,12 +2120,11 @@ static int snd_hdsp_put_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_el val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; if (val > 2) val = 2; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (val != hdsp_da_gain(hdsp)) change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdsp->lock); return change; } @@ -2226,12 +2198,11 @@ static int snd_hdsp_put_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_el val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; if (val > 2) val = 2; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (val != hdsp_ad_gain(hdsp)) change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdsp->lock); return change; } @@ -2305,12 +2276,11 @@ static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; if (val > 2) val = 2; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (val != hdsp_phone_gain(hdsp)) change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdsp->lock); return change; } @@ -2436,10 +2406,9 @@ static int snd_hdsp_put_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ } val = ucontrol->value.enumerated.item[0] % max; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = (int)val != hdsp_pref_sync_ref(hdsp); hdsp_set_pref_sync_ref(hdsp, val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -2519,9 +2488,8 @@ static int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct sn { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); ucontrol->value.integer.value[0] = hdsp->precise_ptr; - spin_unlock_irq(&hdsp->lock); return 0; } @@ -2534,10 +2502,9 @@ static int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct sn if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = (int)val != hdsp->precise_ptr; hdsp_set_precise_pointer(hdsp, val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -2565,9 +2532,8 @@ static int snd_hdsp_get_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); ucontrol->value.integer.value[0] = hdsp->use_midi_work; - spin_unlock_irq(&hdsp->lock); return 0; } @@ -2580,10 +2546,9 @@ static int snd_hdsp_put_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = (int)val != hdsp->use_midi_work; hdsp_set_use_midi_work(hdsp, val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -2624,9 +2589,8 @@ static int snd_hdsp_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem else addr = hdsp_input_to_output_key(hdsp,source, destination); - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr); - spin_unlock_irq(&hdsp->lock); return 0; } @@ -2652,11 +2616,10 @@ static int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem gain = ucontrol->value.integer.value[2]; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = gain != hdsp_read_gain(hdsp, addr); if (change) hdsp_write_gain(hdsp, addr, gain); - spin_unlock_irq(&hdsp->lock); return change; } @@ -2869,12 +2832,11 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.integer.value[0]; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (val != hdsp_dds_offset(hdsp)) change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdsp->lock); return change; } @@ -3018,12 +2980,11 @@ static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ct val = 0; if (val > 4) val = 4; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (val != hdsp_rpm_input12(hdsp)) change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdsp->lock); return change; } @@ -3103,12 +3064,11 @@ static int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ct val = 0; if (val > 4) val = 4; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (val != hdsp_rpm_input34(hdsp)) change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdsp->lock); return change; } @@ -3149,10 +3109,9 @@ static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = (int)val != hdsp_rpm_bypass(hdsp); hdsp_set_rpm_bypass(hdsp, val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -3201,10 +3160,9 @@ static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); change = (int)val != hdsp_rpm_disconnect(hdsp); hdsp_set_rpm_disconnect(hdsp, val); - spin_unlock_irq(&hdsp->lock); return change; } @@ -4051,7 +4009,7 @@ static int snd_hdsp_hw_params(struct snd_pcm_substream *substream, if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis); @@ -4071,39 +4029,31 @@ static int snd_hdsp_hw_params(struct snd_pcm_substream *substream, */ if (params_rate(params) != hdsp->system_sample_rate) { - spin_unlock_irq(&hdsp->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); return -EBUSY; } if (params_period_size(params) != hdsp->period_bytes / 4) { - spin_unlock_irq(&hdsp->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return -EBUSY; } /* We're fine. */ - spin_unlock_irq(&hdsp->lock); return 0; - } else { - spin_unlock_irq(&hdsp->lock); } /* how to make sure that the rate matches an externally-set one ? */ - spin_lock_irq(&hdsp->lock); if (! hdsp->clock_source_locked) { err = hdsp_set_rate(hdsp, params_rate(params), 0); if (err < 0) { - spin_unlock_irq(&hdsp->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); return err; } } - spin_unlock_irq(&hdsp->lock); err = hdsp_set_interrupt_interval(hdsp, params_period_size(params)); if (err < 0) { @@ -4160,7 +4110,7 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd) if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */ return -EIO; - spin_lock(&hdsp->lock); + guard(spinlock)(&hdsp->lock); running = hdsp->running; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -4171,7 +4121,6 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd) break; default: snd_BUG(); - spin_unlock(&hdsp->lock); return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -4211,7 +4160,6 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd) else if (hdsp->running && !running) hdsp_stop_audio(hdsp); hdsp->running = running; - spin_unlock(&hdsp->lock); return 0; } @@ -4227,10 +4175,9 @@ static int snd_hdsp_prepare(struct snd_pcm_substream *substream) if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); if (!hdsp->running) hdsp_reset_hw_pointer(hdsp); - spin_unlock_irq(&hdsp->lock); return result; } @@ -4473,17 +4420,15 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream) if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - spin_lock_irq(&hdsp->lock); + scoped_guard(spinlock_irq, &hdsp->lock) { + snd_pcm_set_sync(substream); - snd_pcm_set_sync(substream); + runtime->hw = snd_hdsp_playback_subinfo; + snd_pcm_set_runtime_buffer(substream, &hdsp->playback_dma_buf); - runtime->hw = snd_hdsp_playback_subinfo; - snd_pcm_set_runtime_buffer(substream, &hdsp->playback_dma_buf); - - hdsp->playback_pid = current->pid; - hdsp->playback_substream = substream; - - spin_unlock_irq(&hdsp->lock); + hdsp->playback_pid = current->pid; + hdsp->playback_substream = substream; + } snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes); @@ -4523,12 +4468,10 @@ static int snd_hdsp_playback_release(struct snd_pcm_substream *substream) { struct hdsp *hdsp = snd_pcm_substream_chip(substream); - spin_lock_irq(&hdsp->lock); - - hdsp->playback_pid = -1; - hdsp->playback_substream = NULL; - - spin_unlock_irq(&hdsp->lock); + scoped_guard(spinlock_irq, &hdsp->lock) { + hdsp->playback_pid = -1; + hdsp->playback_substream = NULL; + } if (RPM != hdsp->io_type) { hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; @@ -4550,17 +4493,15 @@ static int snd_hdsp_capture_open(struct snd_pcm_substream *substream) if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - spin_lock_irq(&hdsp->lock); - - snd_pcm_set_sync(substream); + scoped_guard(spinlock_irq, &hdsp->lock) { + snd_pcm_set_sync(substream); - runtime->hw = snd_hdsp_capture_subinfo; - snd_pcm_set_runtime_buffer(substream, &hdsp->capture_dma_buf); + runtime->hw = snd_hdsp_capture_subinfo; + snd_pcm_set_runtime_buffer(substream, &hdsp->capture_dma_buf); - hdsp->capture_pid = current->pid; - hdsp->capture_substream = substream; - - spin_unlock_irq(&hdsp->lock); + hdsp->capture_pid = current->pid; + hdsp->capture_substream = substream; + } snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes); @@ -4588,12 +4529,11 @@ static int snd_hdsp_capture_release(struct snd_pcm_substream *substream) { struct hdsp *hdsp = snd_pcm_substream_chip(substream); - spin_lock_irq(&hdsp->lock); + guard(spinlock_irq)(&hdsp->lock); hdsp->capture_pid = -1; hdsp->capture_substream = NULL; - spin_unlock_irq(&hdsp->lock); return 0; } @@ -4756,7 +4696,6 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne } case SNDRV_HDSP_IOCTL_GET_CONFIG_INFO: { struct hdsp_config_info info; - unsigned long flags; int i; err = hdsp_check_for_iobox(hdsp); @@ -4768,48 +4707,48 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne return err; memset(&info, 0, sizeof(info)); - spin_lock_irqsave(&hdsp->lock, flags); - info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp); - info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp); - if (hdsp->io_type != H9632) - info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); - info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp); - for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i) - info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); - info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); - info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp, - HDSP_SPDIFOpticalOut); - info.spdif_professional = (unsigned char) - hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional); - info.spdif_emphasis = (unsigned char) - hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis); - info.spdif_nonaudio = (unsigned char) - hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio); - info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp); - info.system_sample_rate = hdsp->system_sample_rate; - info.autosync_sample_rate = hdsp_external_sample_rate(hdsp); - info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp); - info.clock_source = (unsigned char)hdsp_clock_source(hdsp); - info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp); - info.line_out = (unsigned char) - hdsp_toggle_setting(hdsp, HDSP_LineOut); - if (hdsp->io_type == H9632) { - info.da_gain = (unsigned char)hdsp_da_gain(hdsp); - info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp); - info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); - info.xlr_breakout_cable = - (unsigned char)hdsp_toggle_setting(hdsp, - HDSP_XLRBreakoutCable); - - } else if (hdsp->io_type == RPM) { - info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp); - info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp); + scoped_guard(spinlock_irqsave, &hdsp->lock) { + info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp); + info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp); + if (hdsp->io_type != H9632) + info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); + info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp); + for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i) + info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); + info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); + info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_SPDIFOpticalOut); + info.spdif_professional = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional); + info.spdif_emphasis = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis); + info.spdif_nonaudio = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio); + info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp); + info.system_sample_rate = hdsp->system_sample_rate; + info.autosync_sample_rate = hdsp_external_sample_rate(hdsp); + info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp); + info.clock_source = (unsigned char)hdsp_clock_source(hdsp); + info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp); + info.line_out = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_LineOut); + if (hdsp->io_type == H9632) { + info.da_gain = (unsigned char)hdsp_da_gain(hdsp); + info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp); + info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); + info.xlr_breakout_cable = + (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_XLRBreakoutCable); + + } else if (hdsp->io_type == RPM) { + info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp); + info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp); + } + if (hdsp->io_type == H9632 || hdsp->io_type == H9652) + info.analog_extension_board = + (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_AnalogExtensionBoard); } - if (hdsp->io_type == H9632 || hdsp->io_type == H9652) - info.analog_extension_board = - (unsigned char)hdsp_toggle_setting(hdsp, - HDSP_AnalogExtensionBoard); - spin_unlock_irqrestore(&hdsp->lock, flags); if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; break; From 02699abfbd33ce6cf69fbe2771a7c20f84325481 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:27 +0200 Subject: [PATCH 0962/1292] ALSA: hdspm: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-53-tiwai@suse.de --- sound/pci/rme9652/hdspm.c | 301 ++++++++++++++++---------------------- 1 file changed, 127 insertions(+), 174 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a0976824bedaae..3ba5bdc96d9d3a 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1204,16 +1204,11 @@ static inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v) /* check if same process is writing and reading */ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) { - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&hdspm->lock, flags); + guard(spinlock_irqsave)(&hdspm->lock); if ((hdspm->playback_pid != hdspm->capture_pid) && - (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { - ret = 0; - } - spin_unlock_irqrestore(&hdspm->lock, flags); - return ret; + (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) + return 0; + return 1; } /* round arbitrary sample rates to commonly known rates */ @@ -1527,7 +1522,7 @@ static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) { int n; - spin_lock_irq(&s->lock); + guard(spinlock_irq)(&s->lock); if (32 == frames) { /* Special case for new RME cards like RayDAT/AIO which @@ -1557,8 +1552,6 @@ static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames) hdspm_compute_period_size(s); - spin_unlock_irq(&s->lock); - return 0; } @@ -1846,7 +1839,6 @@ static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) { - unsigned long flags; int n_pending; int to_write; int i; @@ -1854,7 +1846,7 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) /* Output is not interrupt driven */ - spin_lock_irqsave (&hmidi->lock, flags); + guard(spinlock_irqsave)(&hmidi->lock); if (hmidi->output && !snd_rawmidi_transmit_empty (hmidi->output)) { n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, @@ -1873,7 +1865,6 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) } } } - spin_unlock_irqrestore (&hmidi->lock, flags); return 0; } @@ -1882,37 +1873,36 @@ static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi) unsigned char buf[128]; /* this buffer is designed to match the MIDI * input FIFO size */ - unsigned long flags; int n_pending; int i; - spin_lock_irqsave (&hmidi->lock, flags); - n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); - if (n_pending > 0) { - if (hmidi->input) { - if (n_pending > (int)sizeof (buf)) - n_pending = sizeof (buf); - for (i = 0; i < n_pending; ++i) - buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, - hmidi->id); - if (n_pending) - snd_rawmidi_receive (hmidi->input, buf, - n_pending); - } else { - /* flush the MIDI input FIFO */ - while (n_pending--) - snd_hdspm_midi_read_byte (hmidi->hdspm, - hmidi->id); + scoped_guard(spinlock_irqsave, &hmidi->lock) { + n_pending = snd_hdspm_midi_input_available(hmidi->hdspm, hmidi->id); + if (n_pending > 0) { + if (hmidi->input) { + if (n_pending > (int)sizeof(buf)) + n_pending = sizeof(buf); + for (i = 0; i < n_pending; ++i) + buf[i] = snd_hdspm_midi_read_byte(hmidi->hdspm, + hmidi->id); + if (n_pending) + snd_rawmidi_receive(hmidi->input, buf, + n_pending); + } else { + /* flush the MIDI input FIFO */ + while (n_pending--) + snd_hdspm_midi_read_byte(hmidi->hdspm, + hmidi->id); + } } + hmidi->pending = 0; } - hmidi->pending = 0; - spin_unlock_irqrestore(&hmidi->lock, flags); - spin_lock_irqsave(&hmidi->hdspm->lock, flags); - hmidi->hdspm->control_register |= hmidi->ie; - hdspm_write(hmidi->hdspm, HDSPM_controlRegister, - hmidi->hdspm->control_register); - spin_unlock_irqrestore(&hmidi->hdspm->lock, flags); + scoped_guard(spinlock_irqsave, &hmidi->hdspm->lock) { + hmidi->hdspm->control_register |= hmidi->ie; + hdspm_write(hmidi->hdspm, HDSPM_controlRegister, + hmidi->hdspm->control_register); + } return snd_hdspm_midi_output_write (hmidi); } @@ -1922,12 +1912,11 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { struct hdspm *hdspm; struct hdspm_midi *hmidi; - unsigned long flags; hmidi = substream->rmidi->private_data; hdspm = hmidi->hdspm; - spin_lock_irqsave (&hdspm->lock, flags); + guard(spinlock_irqsave)(&hdspm->lock); if (up) { if (!(hdspm->control_register & hmidi->ie)) { snd_hdspm_flush_midi_input (hdspm, hmidi->id); @@ -1938,16 +1927,14 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) } hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - spin_unlock_irqrestore (&hdspm->lock, flags); } static void snd_hdspm_midi_output_timer(struct timer_list *t) { struct hdspm_midi *hmidi = timer_container_of(hmidi, t, timer); - unsigned long flags; snd_hdspm_midi_output_write(hmidi); - spin_lock_irqsave (&hmidi->lock, flags); + guard(spinlock_irqsave)(&hmidi->lock); /* this does not bump hmidi->istimer, because the kernel automatically removed the timer when it @@ -1957,30 +1944,27 @@ static void snd_hdspm_midi_output_timer(struct timer_list *t) if (hmidi->istimer) mod_timer(&hmidi->timer, 1 + jiffies); - - spin_unlock_irqrestore (&hmidi->lock, flags); } static void snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct hdspm_midi *hmidi; - unsigned long flags; hmidi = substream->rmidi->private_data; - spin_lock_irqsave (&hmidi->lock, flags); - if (up) { - if (!hmidi->istimer) { - timer_setup(&hmidi->timer, - snd_hdspm_midi_output_timer, 0); - mod_timer(&hmidi->timer, 1 + jiffies); - hmidi->istimer++; + scoped_guard(spinlock_irqsave, &hmidi->lock) { + if (up) { + if (!hmidi->istimer) { + timer_setup(&hmidi->timer, + snd_hdspm_midi_output_timer, 0); + mod_timer(&hmidi->timer, 1 + jiffies); + hmidi->istimer++; + } + } else { + if (hmidi->istimer && --hmidi->istimer <= 0) + timer_delete(&hmidi->timer); } - } else { - if (hmidi->istimer && --hmidi->istimer <= 0) - timer_delete(&hmidi->timer); } - spin_unlock_irqrestore (&hmidi->lock, flags); if (up) snd_hdspm_midi_output_write(hmidi); } @@ -1990,10 +1974,9 @@ static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream) struct hdspm_midi *hmidi; hmidi = substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); hmidi->input = substream; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -2003,9 +1986,8 @@ static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream) struct hdspm_midi *hmidi; hmidi = substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); hmidi->output = substream; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -2017,9 +1999,8 @@ static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream) snd_hdspm_midi_input_trigger (substream, 0); hmidi = substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); hmidi->input = NULL; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -2031,9 +2012,8 @@ static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream) snd_hdspm_midi_output_trigger (substream, 0); hmidi = substream->rmidi->private_data; - spin_lock_irq (&hmidi->lock); + guard(spinlock_irq)(&hmidi->lock); hmidi->output = NULL; - spin_unlock_irq (&hmidi->lock); return 0; } @@ -2671,12 +2651,11 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, val = 0; if (val > 9) val = 9; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); if (val != hdspm_clock_source(hdspm)) change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; else change = 0; - spin_unlock_irq(&hdspm->lock); return change; } @@ -2999,11 +2978,10 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, else if (val >= hdspm->texts_autosync_items) val = hdspm->texts_autosync_items-1; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); if (val != hdspm_pref_sync_ref(hdspm)) change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0; - spin_unlock_irq(&hdspm->lock); return change; } @@ -3239,9 +3217,8 @@ static int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol, struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); u32 regmask = kcontrol->private_value; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask); - spin_unlock_irq(&hdspm->lock); return 0; } @@ -3256,10 +3233,9 @@ static int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol, if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); change = (int) val != hdspm_toggle_setting(hdspm, regmask); hdspm_set_toggle_setting(hdspm, regmask, val); - spin_unlock_irq(&hdspm->lock); return change; } @@ -3301,9 +3277,8 @@ static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); - spin_unlock_irq(&hdspm->lock); return 0; } @@ -3317,10 +3292,9 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); change = (int) val != hdspm_input_select(hdspm); hdspm_set_input_select(hdspm, val); - spin_unlock_irq(&hdspm->lock); return change; } @@ -3363,9 +3337,8 @@ static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm); - spin_unlock_irq(&hdspm->lock); return 0; } @@ -3379,10 +3352,9 @@ static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); change = (int) val != hdspm_ds_wire(hdspm); hdspm_set_ds_wire(hdspm, val); - spin_unlock_irq(&hdspm->lock); return change; } @@ -3436,9 +3408,8 @@ static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm); - spin_unlock_irq(&hdspm->lock); return 0; } @@ -3456,10 +3427,9 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, val = 0; if (val > 2) val = 2; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); change = val != hdspm_qs_wire(hdspm); hdspm_set_qs_wire(hdspm, val); - spin_unlock_irq(&hdspm->lock); return change; } @@ -3512,9 +3482,8 @@ static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); u32 regmask = kcontrol->private_value; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); - spin_unlock_irq(&hdspm->lock); return 0; } @@ -3534,10 +3503,9 @@ static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, if (val > 2) val = 2; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); change = val != hdspm_tristate(hdspm, regmask); hdspm_set_tristate(hdspm, val, regmask); - spin_unlock_irq(&hdspm->lock); return change; } @@ -3590,9 +3558,8 @@ static int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm); - spin_unlock_irq(&hdspm->lock); return 0; } @@ -3610,10 +3577,9 @@ static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol, val = 0; if (val > 2) val = 2; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); change = val != hdspm_madi_speedmode(hdspm); hdspm_set_madi_speedmode(hdspm, val); - spin_unlock_irq(&hdspm->lock); return change; } @@ -3659,7 +3625,7 @@ static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol, else if (destination >= HDSPM_MAX_CHANNELS) destination = HDSPM_MAX_CHANNELS - 1; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); if (source >= HDSPM_MAX_CHANNELS) ucontrol->value.integer.value[2] = hdspm_read_pb_gain(hdspm, destination, @@ -3668,8 +3634,6 @@ static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[2] = hdspm_read_in_gain(hdspm, destination, source); - spin_unlock_irq(&hdspm->lock); - return 0; } @@ -3695,7 +3659,7 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, gain = ucontrol->value.integer.value[2]; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); if (source >= HDSPM_MAX_CHANNELS) change = gain != hdspm_read_pb_gain(hdspm, destination, @@ -3714,7 +3678,6 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, hdspm_write_in_gain(hdspm, destination, source, gain); } - spin_unlock_irq(&hdspm->lock); return change; } @@ -3755,10 +3718,9 @@ static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS)) return -EINVAL; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); ucontrol->value.integer.value[0] = (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN; - spin_unlock_irq(&hdspm->lock); return 0; } @@ -3781,14 +3743,13 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64; - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); change = gain != hdspm_read_pb_gain(hdspm, channel, channel); if (change) hdspm_write_pb_gain(hdspm, channel, channel, gain); - spin_unlock_irq(&hdspm->lock); return change; } @@ -5496,53 +5457,50 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, pid_t this_pid; pid_t other_pid; - spin_lock_irq(&hdspm->lock); + scoped_guard(spinlock_irq, &hdspm->lock) { - if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { - this_pid = hdspm->playback_pid; - other_pid = hdspm->capture_pid; - } else { - this_pid = hdspm->capture_pid; - other_pid = hdspm->playback_pid; - } + if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { + this_pid = hdspm->playback_pid; + other_pid = hdspm->capture_pid; + } else { + this_pid = hdspm->capture_pid; + other_pid = hdspm->playback_pid; + } - if (other_pid > 0 && this_pid != other_pid) { + if (other_pid > 0 && this_pid != other_pid) { - /* The other stream is open, and not by the same - task as this one. Make sure that the parameters - that matter are the same. - */ + /* The other stream is open, and not by the same + task as this one. Make sure that the parameters + that matter are the same. + */ - if (params_rate(params) != hdspm->system_sample_rate) { - spin_unlock_irq(&hdspm->lock); - _snd_pcm_hw_param_setempty(params, - SNDRV_PCM_HW_PARAM_RATE); - return -EBUSY; - } + if (params_rate(params) != hdspm->system_sample_rate) { + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_RATE); + return -EBUSY; + } - if (params_period_size(params) != hdspm->period_bytes / 4) { - spin_unlock_irq(&hdspm->lock); - _snd_pcm_hw_param_setempty(params, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE); - return -EBUSY; - } + if (params_period_size(params) != hdspm->period_bytes / 4) { + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + return -EBUSY; + } + } } /* We're fine. */ - spin_unlock_irq(&hdspm->lock); /* how to make sure that the rate matches an externally-set one ? */ - spin_lock_irq(&hdspm->lock); - err = hdspm_set_rate(hdspm, params_rate(params), 0); - if (err < 0) { - dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err); - spin_unlock_irq(&hdspm->lock); - _snd_pcm_hw_param_setempty(params, - SNDRV_PCM_HW_PARAM_RATE); - return err; + scoped_guard(spinlock_irq, &hdspm->lock) { + err = hdspm_set_rate(hdspm, params_rate(params), 0); + if (err < 0) { + dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err); + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_RATE); + return err; + } } - spin_unlock_irq(&hdspm->lock); err = hdspm_set_interrupt_interval(hdspm, params_period_size(params)); @@ -5750,7 +5708,7 @@ static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_pcm_substream *other; int running; - spin_lock(&hdspm->lock); + guard(spinlock)(&hdspm->lock); running = hdspm->running; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -5761,7 +5719,6 @@ static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd) break; default: snd_BUG(); - spin_unlock(&hdspm->lock); return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -5802,7 +5759,6 @@ static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd) else if (hdspm->running && !running) hdspm_stop_audio(hdspm); hdspm->running = running; - spin_unlock(&hdspm->lock); return 0; } @@ -6035,27 +5991,26 @@ static int snd_hdspm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - spin_lock_irq(&hdspm->lock); - snd_pcm_set_sync(substream); - runtime->hw = (playback) ? snd_hdspm_playback_subinfo : - snd_hdspm_capture_subinfo; + scoped_guard(spinlock_irq, &hdspm->lock) { + snd_pcm_set_sync(substream); + runtime->hw = (playback) ? snd_hdspm_playback_subinfo : + snd_hdspm_capture_subinfo; - if (playback) { - if (!hdspm->capture_substream) - hdspm_stop_audio(hdspm); + if (playback) { + if (!hdspm->capture_substream) + hdspm_stop_audio(hdspm); - hdspm->playback_pid = current->pid; - hdspm->playback_substream = substream; - } else { - if (!hdspm->playback_substream) - hdspm_stop_audio(hdspm); + hdspm->playback_pid = current->pid; + hdspm->playback_substream = substream; + } else { + if (!hdspm->playback_substream) + hdspm_stop_audio(hdspm); - hdspm->capture_pid = current->pid; - hdspm->capture_substream = substream; + hdspm->capture_pid = current->pid; + hdspm->capture_substream = substream; + } } - spin_unlock_irq(&hdspm->lock); - snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); @@ -6108,7 +6063,7 @@ static int snd_hdspm_release(struct snd_pcm_substream *substream) struct hdspm *hdspm = snd_pcm_substream_chip(substream); bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - spin_lock_irq(&hdspm->lock); + guard(spinlock_irq)(&hdspm->lock); if (playback) { hdspm->playback_pid = -1; @@ -6118,8 +6073,6 @@ static int snd_hdspm_release(struct snd_pcm_substream *substream) hdspm->capture_substream = NULL; } - spin_unlock_irq(&hdspm->lock); - return 0; } @@ -6242,19 +6195,19 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, case SNDRV_HDSPM_IOCTL_GET_CONFIG: memset(&info, 0, sizeof(info)); - spin_lock_irq(&hdspm->lock); - info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); - info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); - - info.system_sample_rate = hdspm->system_sample_rate; - info.autosync_sample_rate = - hdspm_external_sample_rate(hdspm); - info.system_clock_mode = hdspm_system_clock_mode(hdspm); - info.clock_source = hdspm_clock_source(hdspm); - info.autosync_ref = hdspm_autosync_ref(hdspm); - info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut); - info.passthru = 0; - spin_unlock_irq(&hdspm->lock); + scoped_guard(spinlock_irq, &hdspm->lock) { + info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); + info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); + + info.system_sample_rate = hdspm->system_sample_rate; + info.autosync_sample_rate = + hdspm_external_sample_rate(hdspm); + info.system_clock_mode = hdspm_system_clock_mode(hdspm); + info.clock_source = hdspm_clock_source(hdspm); + info.autosync_ref = hdspm_autosync_ref(hdspm); + info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut); + info.passthru = 0; + } if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; break; From bd6aa020ec491b3389b2141a5e8ba81248a777a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:28 +0200 Subject: [PATCH 0963/1292] ALSA: rme9652: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-54-tiwai@suse.de --- sound/pci/rme9652/rme9652.c | 199 ++++++++++++++---------------------- 1 file changed, 78 insertions(+), 121 deletions(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 7dc8e3777c37d2..3be30cb57a2e0d 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -308,16 +308,11 @@ static inline unsigned int rme9652_read(struct snd_rme9652 *rme9652, int reg) static inline int snd_rme9652_use_is_exclusive(struct snd_rme9652 *rme9652) { - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&rme9652->lock, flags); + guard(spinlock_irqsave)(&rme9652->lock); if ((rme9652->playback_pid != rme9652->capture_pid) && - (rme9652->playback_pid >= 0) && (rme9652->capture_pid >= 0)) { - ret = 0; - } - spin_unlock_irqrestore(&rme9652->lock, flags); - return ret; + (rme9652->playback_pid >= 0) && (rme9652->capture_pid >= 0)) + return 0; + return 1; } static inline int rme9652_adat_sample_rate(struct snd_rme9652 *rme9652) @@ -428,7 +423,7 @@ static int rme9652_set_interrupt_interval(struct snd_rme9652 *s, int restart = 0; int n; - spin_lock_irq(&s->lock); + guard(spinlock_irq)(&s->lock); restart = s->running; if (restart) @@ -451,8 +446,6 @@ static int rme9652_set_interrupt_interval(struct snd_rme9652 *s, if (restart) rme9652_start(s); - spin_unlock_irq(&s->lock); - return 0; } @@ -477,7 +470,7 @@ static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate) is to flag rate changes in the read/write routines. */ - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); xrate = rme9652_adat_sample_rate(rme9652); switch (rate) { @@ -506,14 +499,11 @@ static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate) rate = RME9652_DS | RME9652_freq; break; default: - spin_unlock_irq(&rme9652->lock); return -EINVAL; } - if (reject_if_open && (rme9652->capture_pid >= 0 || rme9652->playback_pid >= 0)) { - spin_unlock_irq(&rme9652->lock); + if (reject_if_open && (rme9652->capture_pid >= 0 || rme9652->playback_pid >= 0)) return -EBUSY; - } restart = rme9652->running; if (restart) @@ -539,7 +529,6 @@ static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate) } } - spin_unlock_irq(&rme9652->lock); return 0; } @@ -798,10 +787,9 @@ static int snd_rme9652_control_spdif_put(struct snd_kcontrol *kcontrol, struct s u32 val; val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = val != rme9652->creg_spdif; rme9652->creg_spdif = val; - spin_unlock_irq(&rme9652->lock); return change; } @@ -827,12 +815,11 @@ static int snd_rme9652_control_spdif_stream_put(struct snd_kcontrol *kcontrol, s u32 val; val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = val != rme9652->creg_spdif_stream; rme9652->creg_spdif_stream = val; rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP); rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= val); - spin_unlock_irq(&rme9652->lock); return change; } @@ -897,9 +884,8 @@ static int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ct { struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); ucontrol->value.enumerated.item[0] = rme9652_adat1_in(rme9652); - spin_unlock_irq(&rme9652->lock); return 0; } @@ -912,11 +898,10 @@ static int snd_rme9652_put_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ct if (!snd_rme9652_use_is_exclusive(rme9652)) return -EBUSY; val = ucontrol->value.enumerated.item[0] % 2; - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = val != rme9652_adat1_in(rme9652); if (change) rme9652_set_adat1_input(rme9652, val); - spin_unlock_irq(&rme9652->lock); return change; } @@ -961,9 +946,8 @@ static int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ct { struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); ucontrol->value.enumerated.item[0] = rme9652_spdif_in(rme9652); - spin_unlock_irq(&rme9652->lock); return 0; } @@ -976,11 +960,10 @@ static int snd_rme9652_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ct if (!snd_rme9652_use_is_exclusive(rme9652)) return -EBUSY; val = ucontrol->value.enumerated.item[0] % 3; - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = val != rme9652_spdif_in(rme9652); if (change) rme9652_set_spdif_input(rme9652, val); - spin_unlock_irq(&rme9652->lock); return change; } @@ -1022,9 +1005,8 @@ static int snd_rme9652_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_c { struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); ucontrol->value.integer.value[0] = rme9652_spdif_out(rme9652); - spin_unlock_irq(&rme9652->lock); return 0; } @@ -1037,10 +1019,9 @@ static int snd_rme9652_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_c if (!snd_rme9652_use_is_exclusive(rme9652)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = (int)val != rme9652_spdif_out(rme9652); rme9652_set_spdif_output(rme9652, val); - spin_unlock_irq(&rme9652->lock); return change; } @@ -1104,9 +1085,8 @@ static int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_c { struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); ucontrol->value.enumerated.item[0] = rme9652_sync_mode(rme9652); - spin_unlock_irq(&rme9652->lock); return 0; } @@ -1117,10 +1097,9 @@ static int snd_rme9652_put_sync_mode(struct snd_kcontrol *kcontrol, struct snd_c unsigned int val; val = ucontrol->value.enumerated.item[0] % 3; - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = (int)val != rme9652_sync_mode(rme9652); rme9652_set_sync_mode(rme9652, val); - spin_unlock_irq(&rme9652->lock); return change; } @@ -1193,9 +1172,8 @@ static int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_c { struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); ucontrol->value.enumerated.item[0] = rme9652_sync_pref(rme9652); - spin_unlock_irq(&rme9652->lock); return 0; } @@ -1209,10 +1187,9 @@ static int snd_rme9652_put_sync_pref(struct snd_kcontrol *kcontrol, struct snd_c return -EBUSY; max = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3; val = ucontrol->value.enumerated.item[0] % max; - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = (int)val != rme9652_sync_pref(rme9652); rme9652_set_sync_pref(rme9652, val); - spin_unlock_irq(&rme9652->lock); return change; } @@ -1253,7 +1230,7 @@ static int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_el thru_bits |= 1 << chn; } - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = thru_bits ^ rme9652->thru_bits; if (change) { for (chn = 0; chn < rme9652->ss_channels; ++chn) { @@ -1262,7 +1239,6 @@ static int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_el rme9652_set_thru(rme9652,chn,thru_bits&(1<lock); return !!change; } @@ -1278,9 +1254,8 @@ static int snd_rme9652_get_passthru(struct snd_kcontrol *kcontrol, struct snd_ct { struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); ucontrol->value.integer.value[0] = rme9652->passthru; - spin_unlock_irq(&rme9652->lock); return 0; } @@ -1295,11 +1270,10 @@ static int snd_rme9652_put_passthru(struct snd_kcontrol *kcontrol, struct snd_ct return -EBUSY; val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); change = (ucontrol->value.integer.value[0] != rme9652->passthru); if (change) err = rme9652_set_passthru(rme9652, val); - spin_unlock_irq(&rme9652->lock); return err ? err : change; } @@ -1324,9 +1298,8 @@ static int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ { struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); ucontrol->value.integer.value[0] = rme9652_spdif_sample_rate(rme9652); - spin_unlock_irq(&rme9652->lock); return 0; } @@ -1931,45 +1904,39 @@ static int snd_rme9652_hw_params(struct snd_pcm_substream *substream, pid_t this_pid; pid_t other_pid; - spin_lock_irq(&rme9652->lock); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { - rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP); - rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream); - this_pid = rme9652->playback_pid; - other_pid = rme9652->capture_pid; - } else { - this_pid = rme9652->capture_pid; - other_pid = rme9652->playback_pid; - } - - if ((other_pid > 0) && (this_pid != other_pid)) { - - /* The other stream is open, and not by the same - task as this one. Make sure that the parameters - that matter are the same. - */ + scoped_guard(spinlock_irq, &rme9652->lock) { - if ((int)params_rate(params) != - rme9652_adat_sample_rate(rme9652)) { - spin_unlock_irq(&rme9652->lock); - _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); - return -EBUSY; + if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP); + rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream); + this_pid = rme9652->playback_pid; + other_pid = rme9652->capture_pid; + } else { + this_pid = rme9652->capture_pid; + other_pid = rme9652->playback_pid; } - if (params_period_size(params) != rme9652->period_bytes / 4) { - spin_unlock_irq(&rme9652->lock); - _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); - return -EBUSY; - } + if ((other_pid > 0) && (this_pid != other_pid)) { - /* We're fine. */ + /* The other stream is open, and not by the same + task as this one. Make sure that the parameters + that matter are the same. + */ - spin_unlock_irq(&rme9652->lock); - return 0; + if ((int)params_rate(params) != + rme9652_adat_sample_rate(rme9652)) { + _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); + return -EBUSY; + } - } else { - spin_unlock_irq(&rme9652->lock); + if (params_period_size(params) != rme9652->period_bytes / 4) { + _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + return -EBUSY; + } + + /* We're fine. */ + return 0; + } } /* how to make sure that the rate matches an externally-set one ? @@ -2041,7 +2008,8 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream, struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); struct snd_pcm_substream *other; int running; - spin_lock(&rme9652->lock); + + guard(spinlock)(&rme9652->lock); running = rme9652->running; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -2052,7 +2020,6 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream, break; default: snd_BUG(); - spin_unlock(&rme9652->lock); return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -2092,7 +2059,6 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream, else if (rme9652->running && !running) rme9652_stop(rme9652); rme9652->running = running; - spin_unlock(&rme9652->lock); return 0; } @@ -2100,12 +2066,10 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream, static int snd_rme9652_prepare(struct snd_pcm_substream *substream) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); - unsigned long flags; - spin_lock_irqsave(&rme9652->lock, flags); + guard(spinlock_irqsave)(&rme9652->lock); if (!rme9652->running) rme9652_reset_hw_pointer(rme9652); - spin_unlock_irqrestore(&rme9652->lock, flags); return 0; } @@ -2226,23 +2190,21 @@ static int snd_rme9652_playback_open(struct snd_pcm_substream *substream) struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - spin_lock_irq(&rme9652->lock); + scoped_guard(spinlock_irq, &rme9652->lock) { + snd_pcm_set_sync(substream); - snd_pcm_set_sync(substream); + runtime->hw = snd_rme9652_playback_subinfo; + snd_pcm_set_runtime_buffer(substream, &rme9652->playback_dma_buf); - runtime->hw = snd_rme9652_playback_subinfo; - snd_pcm_set_runtime_buffer(substream, &rme9652->playback_dma_buf); + if (rme9652->capture_substream == NULL) { + rme9652_stop(rme9652); + rme9652_set_thru(rme9652, -1, 0); + } - if (rme9652->capture_substream == NULL) { - rme9652_stop(rme9652); - rme9652_set_thru(rme9652, -1, 0); + rme9652->playback_pid = current->pid; + rme9652->playback_substream = substream; } - rme9652->playback_pid = current->pid; - rme9652->playback_substream = substream; - - spin_unlock_irq(&rme9652->lock); - snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -2266,12 +2228,10 @@ static int snd_rme9652_playback_release(struct snd_pcm_substream *substream) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme9652->lock); - - rme9652->playback_pid = -1; - rme9652->playback_substream = NULL; - - spin_unlock_irq(&rme9652->lock); + scoped_guard(spinlock_irq, &rme9652->lock) { + rme9652->playback_pid = -1; + rme9652->playback_substream = NULL; + } rme9652->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE | @@ -2285,23 +2245,21 @@ static int snd_rme9652_capture_open(struct snd_pcm_substream *substream) struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - spin_lock_irq(&rme9652->lock); + scoped_guard(spinlock_irq, &rme9652->lock) { + snd_pcm_set_sync(substream); - snd_pcm_set_sync(substream); + runtime->hw = snd_rme9652_capture_subinfo; + snd_pcm_set_runtime_buffer(substream, &rme9652->capture_dma_buf); - runtime->hw = snd_rme9652_capture_subinfo; - snd_pcm_set_runtime_buffer(substream, &rme9652->capture_dma_buf); + if (rme9652->playback_substream == NULL) { + rme9652_stop(rme9652); + rme9652_set_thru(rme9652, -1, 0); + } - if (rme9652->playback_substream == NULL) { - rme9652_stop(rme9652); - rme9652_set_thru(rme9652, -1, 0); + rme9652->capture_pid = current->pid; + rme9652->capture_substream = substream; } - rme9652->capture_pid = current->pid; - rme9652->capture_substream = substream; - - spin_unlock_irq(&rme9652->lock); - snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -2320,12 +2278,11 @@ static int snd_rme9652_capture_release(struct snd_pcm_substream *substream) { struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream); - spin_lock_irq(&rme9652->lock); + guard(spinlock_irq)(&rme9652->lock); rme9652->capture_pid = -1; rme9652->capture_substream = NULL; - spin_unlock_irq(&rme9652->lock); return 0; } From e7b99fdddfe873b49f72b27676eeab6ec77f2633 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:29 +0200 Subject: [PATCH 0964/1292] ALSA: sis7019: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-55-tiwai@suse.de --- sound/pci/sis7019.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 3d7abcb3167902..a1341af8c41feb 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -902,7 +902,7 @@ static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd) /* Get the AC97 semaphore -- software first, so we don't spin * pounding out IO reads on the hardware semaphore... */ - mutex_lock(&sis->ac97_mutex); + guard(mutex)(&sis->ac97_mutex); count = 0xffff; while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) @@ -941,8 +941,6 @@ static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd) timeout_sema: outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); timeout: - mutex_unlock(&sis->ac97_mutex); - if (!count) { dev_err(&sis->pci->dev, "ac97 codec %d timeout cmd 0x%08x\n", codec, cmd); From 8e11f94ea15ddebfcb040e89ff3093746b7e2c79 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:30 +0200 Subject: [PATCH 0965/1292] ALSA: sis7019: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-56-tiwai@suse.de --- sound/pci/sis7019.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index a1341af8c41feb..4be085d27712ec 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -383,9 +383,7 @@ static void __sis_unmap_silence(struct sis7019 *sis) static void sis_free_voice(struct sis7019 *sis, struct voice *voice) { - unsigned long flags; - - spin_lock_irqsave(&sis->voice_lock, flags); + guard(spinlock_irqsave)(&sis->voice_lock); if (voice->timing) { __sis_unmap_silence(sis); voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | @@ -393,7 +391,6 @@ static void sis_free_voice(struct sis7019 *sis, struct voice *voice) voice->timing = NULL; } voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING); - spin_unlock_irqrestore(&sis->voice_lock, flags); } static struct voice *__sis_alloc_playback_voice(struct sis7019 *sis) @@ -417,14 +414,8 @@ static struct voice *__sis_alloc_playback_voice(struct sis7019 *sis) static struct voice *sis_alloc_playback_voice(struct sis7019 *sis) { - struct voice *voice; - unsigned long flags; - - spin_lock_irqsave(&sis->voice_lock, flags); - voice = __sis_alloc_playback_voice(sis); - spin_unlock_irqrestore(&sis->voice_lock, flags); - - return voice; + guard(spinlock_irqsave)(&sis->voice_lock); + return __sis_alloc_playback_voice(sis); } static int sis_alloc_timing_voice(struct snd_pcm_substream *substream, @@ -434,7 +425,6 @@ static int sis_alloc_timing_voice(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct voice *voice = runtime->private_data; unsigned int period_size, buffer_size; - unsigned long flags; int needed; /* If there are one or two periods per buffer, we don't need a @@ -447,11 +437,11 @@ static int sis_alloc_timing_voice(struct snd_pcm_substream *substream, period_size != (buffer_size / 2)); if (needed && !voice->timing) { - spin_lock_irqsave(&sis->voice_lock, flags); - voice->timing = __sis_alloc_playback_voice(sis); - if (voice->timing) - __sis_map_silence(sis); - spin_unlock_irqrestore(&sis->voice_lock, flags); + scoped_guard(spinlock_irqsave, &sis->voice_lock) { + voice->timing = __sis_alloc_playback_voice(sis); + if (voice->timing) + __sis_map_silence(sis); + } if (!voice->timing) return -ENOMEM; voice->timing->substream = substream; @@ -645,17 +635,16 @@ static int sis_capture_open(struct snd_pcm_substream *substream) struct sis7019 *sis = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct voice *voice = &sis->capture_voice; - unsigned long flags; /* FIXME: The driver only supports recording from one channel * at the moment, but it could support more. */ - spin_lock_irqsave(&sis->voice_lock, flags); - if (voice->flags & VOICE_IN_USE) - voice = NULL; - else - voice->flags |= VOICE_IN_USE; - spin_unlock_irqrestore(&sis->voice_lock, flags); + scoped_guard(spinlock_irqsave, &sis->voice_lock) { + if (voice->flags & VOICE_IN_USE) + voice = NULL; + else + voice->flags |= VOICE_IN_USE; + } if (!voice) return -EAGAIN; From fa670cbaee466c997232d3ddea4bf05b5efa4d78 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:31 +0200 Subject: [PATCH 0966/1292] ALSA: sonicvibes: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-57-tiwai@suse.de --- sound/pci/sonicvibes.c | 113 ++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 69 deletions(-) diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index f85a9556dacbad..a4c72799d0348d 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -303,14 +303,11 @@ static void snd_sonicvibes_out(struct sonicvibes * sonic, unsigned char reg, unsigned char value) { - unsigned long flags; - - spin_lock_irqsave(&sonic->reg_lock, flags); + guard(spinlock_irqsave)(&sonic->reg_lock); outb(reg, SV_REG(sonic, INDEX)); udelay(10); outb(value, SV_REG(sonic, DATA)); udelay(10); - spin_unlock_irqrestore(&sonic->reg_lock, flags); } static unsigned char snd_sonicvibes_in1(struct sonicvibes * sonic, unsigned char reg) @@ -326,15 +323,13 @@ static unsigned char snd_sonicvibes_in1(struct sonicvibes * sonic, unsigned char static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char reg) { - unsigned long flags; unsigned char value; - spin_lock_irqsave(&sonic->reg_lock, flags); + guard(spinlock_irqsave)(&sonic->reg_lock); outb(reg, SV_REG(sonic, INDEX)); udelay(10); value = inb(SV_REG(sonic, DATA)); udelay(10); - spin_unlock_irqrestore(&sonic->reg_lock, flags); return value; } @@ -448,9 +443,7 @@ static void snd_sonicvibes_setfmt(struct sonicvibes * sonic, unsigned char mask, unsigned char value) { - unsigned long flags; - - spin_lock_irqsave(&sonic->reg_lock, flags); + guard(spinlock_irqsave)(&sonic->reg_lock); outb(SV_MCE | SV_IREG_DMA_DATA_FMT, SV_REG(sonic, INDEX)); if (mask) { sonic->format = inb(SV_REG(sonic, DATA)); @@ -461,7 +454,6 @@ static void snd_sonicvibes_setfmt(struct sonicvibes * sonic, udelay(10); outb(0, SV_REG(sonic, INDEX)); udelay(10); - spin_unlock_irqrestore(&sonic->reg_lock, flags); } static void snd_sonicvibes_pll(unsigned int rate, @@ -506,21 +498,18 @@ static void snd_sonicvibes_setpll(struct sonicvibes * sonic, unsigned char reg, unsigned int rate) { - unsigned long flags; unsigned int r, m, n; snd_sonicvibes_pll(rate, &r, &m, &n); if (sonic != NULL) { - spin_lock_irqsave(&sonic->reg_lock, flags); + guard(spinlock_irqsave)(&sonic->reg_lock); snd_sonicvibes_out1(sonic, reg, m); snd_sonicvibes_out1(sonic, reg + 1, r | n); - spin_unlock_irqrestore(&sonic->reg_lock, flags); } } static void snd_sonicvibes_set_adc_rate(struct sonicvibes * sonic, unsigned int rate) { - unsigned long flags; unsigned int div; unsigned char clock; @@ -533,10 +522,9 @@ static void snd_sonicvibes_set_adc_rate(struct sonicvibes * sonic, unsigned int clock = 0x00; snd_sonicvibes_setpll(sonic, SV_IREG_ADC_PLL, rate); } - spin_lock_irqsave(&sonic->reg_lock, flags); + guard(spinlock_irqsave)(&sonic->reg_lock); snd_sonicvibes_out1(sonic, SV_IREG_ADC_ALT_RATE, (div - 1) << 4); snd_sonicvibes_out1(sonic, SV_IREG_ADC_CLOCK, clock); - spin_unlock_irqrestore(&sonic->reg_lock, flags); } static int snd_sonicvibes_hw_constraint_dac_rate(struct snd_pcm_hw_params *params, @@ -567,22 +555,18 @@ static int snd_sonicvibes_hw_constraint_dac_rate(struct snd_pcm_hw_params *param static void snd_sonicvibes_set_dac_rate(struct sonicvibes * sonic, unsigned int rate) { unsigned int div; - unsigned long flags; div = DIV_ROUND_CLOSEST(rate * 65536, SV_FULLRATE); if (div > 65535) div = 65535; - spin_lock_irqsave(&sonic->reg_lock, flags); + guard(spinlock_irqsave)(&sonic->reg_lock); snd_sonicvibes_out1(sonic, SV_IREG_PCM_RATE_HIGH, div >> 8); snd_sonicvibes_out1(sonic, SV_IREG_PCM_RATE_LOW, div); - spin_unlock_irqrestore(&sonic->reg_lock, flags); } static int snd_sonicvibes_trigger(struct sonicvibes * sonic, int what, int cmd) { - int result = 0; - - spin_lock(&sonic->reg_lock); + guard(spinlock)(&sonic->reg_lock); if (cmd == SNDRV_PCM_TRIGGER_START) { if (!(sonic->enable & what)) { sonic->enable |= what; @@ -594,10 +578,9 @@ static int snd_sonicvibes_trigger(struct sonicvibes * sonic, int what, int cmd) snd_sonicvibes_out1(sonic, SV_IREG_PC_ENABLE, sonic->enable); } } else { - result = -EINVAL; + return -EINVAL; } - spin_unlock(&sonic->reg_lock); - return result; + return 0; } static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id) @@ -628,34 +611,34 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id) unsigned char udreg; int vol, oleft, oright, mleft, mright; - spin_lock(&sonic->reg_lock); - udreg = snd_sonicvibes_in1(sonic, SV_IREG_UD_BUTTON); - vol = udreg & 0x3f; - if (!(udreg & 0x40)) - vol = -vol; - oleft = mleft = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ANALOG); - oright = mright = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ANALOG); - oleft &= 0x1f; - oright &= 0x1f; - oleft += vol; - if (oleft < 0) - oleft = 0; - if (oleft > 0x1f) - oleft = 0x1f; - oright += vol; - if (oright < 0) - oright = 0; - if (oright > 0x1f) - oright = 0x1f; - if (udreg & 0x80) { - mleft ^= 0x80; - mright ^= 0x80; + scoped_guard(spinlock, &sonic->reg_lock) { + udreg = snd_sonicvibes_in1(sonic, SV_IREG_UD_BUTTON); + vol = udreg & 0x3f; + if (!(udreg & 0x40)) + vol = -vol; + oleft = mleft = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ANALOG); + oright = mright = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ANALOG); + oleft &= 0x1f; + oright &= 0x1f; + oleft += vol; + if (oleft < 0) + oleft = 0; + if (oleft > 0x1f) + oleft = 0x1f; + oright += vol; + if (oright < 0) + oright = 0; + if (oright > 0x1f) + oright = 0x1f; + if (udreg & 0x80) { + mleft ^= 0x80; + mright ^= 0x80; + } + oleft |= mleft & 0x80; + oright |= mright & 0x80; + snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ANALOG, oleft); + snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ANALOG, oright); } - oleft |= mleft & 0x80; - oright |= mright & 0x80; - snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ANALOG, oleft); - snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ANALOG, oright); - spin_unlock(&sonic->reg_lock); snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_mute->id); snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_volume->id); } @@ -696,11 +679,10 @@ static int snd_sonicvibes_playback_prepare(struct snd_pcm_substream *substream) fmt |= 2; snd_sonicvibes_setfmt(sonic, ~3, fmt); snd_sonicvibes_set_dac_rate(sonic, runtime->rate); - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); snd_sonicvibes_setdmaa(sonic, runtime->dma_addr, size); snd_sonicvibes_out1(sonic, SV_IREG_DMA_A_UPPER, count >> 8); snd_sonicvibes_out1(sonic, SV_IREG_DMA_A_LOWER, count); - spin_unlock_irq(&sonic->reg_lock); return 0; } @@ -721,11 +703,10 @@ static int snd_sonicvibes_capture_prepare(struct snd_pcm_substream *substream) fmt |= 0x20; snd_sonicvibes_setfmt(sonic, ~0x30, fmt); snd_sonicvibes_set_adc_rate(sonic, runtime->rate); - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); snd_sonicvibes_setdmac(sonic, runtime->dma_addr, size); snd_sonicvibes_out1(sonic, SV_IREG_DMA_C_UPPER, count >> 8); snd_sonicvibes_out1(sonic, SV_IREG_DMA_C_LOWER, count); - spin_unlock_irq(&sonic->reg_lock); return 0; } @@ -894,10 +875,9 @@ static int snd_sonicvibes_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ { struct sonicvibes *sonic = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); ucontrol->value.enumerated.item[0] = ((snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC) & SV_RECSRC_OUT) >> 5) - 1; ucontrol->value.enumerated.item[1] = ((snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC) & SV_RECSRC_OUT) >> 5) - 1; - spin_unlock_irq(&sonic->reg_lock); return 0; } @@ -912,7 +892,7 @@ static int snd_sonicvibes_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ return -EINVAL; left = (ucontrol->value.enumerated.item[0] + 1) << 5; right = (ucontrol->value.enumerated.item[1] + 1) << 5; - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); oval1 = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC); oval2 = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC); left = (oval1 & ~SV_RECSRC_OUT) | left; @@ -920,7 +900,6 @@ static int snd_sonicvibes_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ change = left != oval1 || right != oval2; snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ADC, left); snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ADC, right); - spin_unlock_irq(&sonic->reg_lock); return change; } @@ -949,9 +928,8 @@ static int snd_sonicvibes_get_single(struct snd_kcontrol *kcontrol, struct snd_c int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, reg)>> shift) & mask; - spin_unlock_irq(&sonic->reg_lock); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; @@ -971,12 +949,11 @@ static int snd_sonicvibes_put_single(struct snd_kcontrol *kcontrol, struct snd_c if (invert) val = mask - val; val <<= shift; - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); oval = snd_sonicvibes_in1(sonic, reg); val = (oval & ~(mask << shift)) | val; change = val != oval; snd_sonicvibes_out1(sonic, reg, val); - spin_unlock_irq(&sonic->reg_lock); return change; } @@ -1007,10 +984,9 @@ static int snd_sonicvibes_get_double(struct snd_kcontrol *kcontrol, struct snd_c int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, left_reg) >> shift_left) & mask; ucontrol->value.integer.value[1] = (snd_sonicvibes_in1(sonic, right_reg) >> shift_right) & mask; - spin_unlock_irq(&sonic->reg_lock); if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; @@ -1038,7 +1014,7 @@ static int snd_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_c } val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irq(&sonic->reg_lock); + guard(spinlock_irq)(&sonic->reg_lock); oval1 = snd_sonicvibes_in1(sonic, left_reg); oval2 = snd_sonicvibes_in1(sonic, right_reg); val1 = (oval1 & ~(mask << shift_left)) | val1; @@ -1046,7 +1022,6 @@ static int snd_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_c change = val1 != oval1 || val2 != oval2; snd_sonicvibes_out1(sonic, left_reg, val1); snd_sonicvibes_out1(sonic, right_reg, val2); - spin_unlock_irq(&sonic->reg_lock); return change; } From 4f83e1da6e057c13d6e930558d11cb1095b19d3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:32 +0200 Subject: [PATCH 0967/1292] ALSA: trident: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-58-tiwai@suse.de --- sound/pci/trident/trident_memory.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 4a36f194c7f8d9..81f6348191dc44 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -172,12 +172,10 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident, - mutex_lock(&hdr->block_mutex); + guard(mutex)(&hdr->block_mutex); blk = search_empty(hdr, runtime->dma_bytes); - if (blk == NULL) { - mutex_unlock(&hdr->block_mutex); + if (blk == NULL) return NULL; - } /* set TLB entries */ idx = 0; @@ -186,12 +184,10 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident, dma_addr_t addr = snd_pcm_sgbuf_get_addr(substream, ofs); if (!is_valid_page(trident, addr)) { __snd_util_mem_free(hdr, blk); - mutex_unlock(&hdr->block_mutex); return NULL; } set_tlb_bus(trident, page, addr); } - mutex_unlock(&hdr->block_mutex); return blk; } @@ -216,12 +212,10 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident, if (snd_BUG_ON(!hdr)) return NULL; - mutex_lock(&hdr->block_mutex); + guard(mutex)(&hdr->block_mutex); blk = search_empty(hdr, runtime->dma_bytes); - if (blk == NULL) { - mutex_unlock(&hdr->block_mutex); + if (blk == NULL) return NULL; - } /* set TLB entries */ addr = runtime->dma_addr; @@ -229,12 +223,10 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident, addr += SNDRV_TRIDENT_PAGE_SIZE) { if (!is_valid_page(trident, addr)) { __snd_util_mem_free(hdr, blk); - mutex_unlock(&hdr->block_mutex); return NULL; } set_tlb_bus(trident, page, addr); } - mutex_unlock(&hdr->block_mutex); return blk; } @@ -267,12 +259,11 @@ int snd_trident_free_pages(struct snd_trident *trident, return -EINVAL; hdr = trident->tlb.memhdr; - mutex_lock(&hdr->block_mutex); + guard(mutex)(&hdr->block_mutex); /* reset TLB entries */ for (page = firstpg(blk); page <= lastpg(blk); page++) set_silent_tlb(trident, page); /* free memory block */ __snd_util_mem_free(hdr, blk); - mutex_unlock(&hdr->block_mutex); return 0; } From 62d8070db648c17e10602704e9813d209d9ad994 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:33 +0200 Subject: [PATCH 0968/1292] ALSA: trident: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-59-tiwai@suse.de --- sound/pci/trident/trident_main.c | 324 +++++++++++++------------------ 1 file changed, 140 insertions(+), 184 deletions(-) diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 39ed52bf8631ca..55515c58b8aa27 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -107,10 +107,9 @@ static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned sho { unsigned int data = 0, treg; unsigned short count = 0xffff; - unsigned long flags; struct snd_trident *trident = ac97->private_data; - spin_lock_irqsave(&trident->reg_lock, flags); + guard(spinlock_irqsave)(&trident->reg_lock); if (trident->device == TRIDENT_DEVICE_ID_DX) { data = (DX_AC97_BUSY_READ | (reg & 0x000000ff)); outl(data, TRID_REG(trident, DX_ACR1_AC97_R)); @@ -147,7 +146,6 @@ static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned sho data = 0; } - spin_unlock_irqrestore(&trident->reg_lock, flags); return ((unsigned short) (data >> 16)); } @@ -170,12 +168,11 @@ static void snd_trident_codec_write(struct snd_ac97 *ac97, unsigned short reg, { unsigned int address, data; unsigned short count = 0xffff; - unsigned long flags; struct snd_trident *trident = ac97->private_data; data = ((unsigned long) wdata) << 16; - spin_lock_irqsave(&trident->reg_lock, flags); + guard(spinlock_irqsave)(&trident->reg_lock); if (trident->device == TRIDENT_DEVICE_ID_DX) { address = DX_ACR0_AC97_W; @@ -213,12 +210,9 @@ static void snd_trident_codec_write(struct snd_ac97 *ac97, unsigned short reg, count = 0; /* return */ } - if (count == 0) { - spin_unlock_irqrestore(&trident->reg_lock, flags); + if (count == 0) return; - } outl(data, TRID_REG(trident, address)); - spin_unlock_irqrestore(&trident->reg_lock, flags); } /*--------------------------------------------------------------------------- @@ -911,7 +905,7 @@ static int snd_trident_playback_prepare(struct snd_pcm_substream *substream) struct snd_trident_voice *evoice = voice->extra; struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[substream->number]; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); /* set delta (rate) value */ voice->Delta = snd_trident_convert_rate(runtime->rate); @@ -972,8 +966,6 @@ static int snd_trident_playback_prepare(struct snd_pcm_substream *substream) evoice->ESO = (runtime->period_size * 2) - 1; } - spin_unlock_irq(&trident->reg_lock); - return 0; } @@ -1013,7 +1005,7 @@ static int snd_trident_capture_prepare(struct snd_pcm_substream *substream) struct snd_trident_voice *voice = runtime->private_data; unsigned int val, ESO_bytes; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); // Initialize the channel and set channel Mode outb(0, TRID_REG(trident, LEGACY_DMAR15)); @@ -1082,7 +1074,6 @@ static int snd_trident_capture_prepare(struct snd_pcm_substream *substream) snd_trident_write_voice_regs(trident, voice); - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -1147,7 +1138,7 @@ static int snd_trident_si7018_capture_prepare(struct snd_pcm_substream *substrea struct snd_trident_voice *voice = runtime->private_data; struct snd_trident_voice *evoice = voice->extra; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); voice->LBA = runtime->dma_addr; voice->Delta = snd_trident_convert_adc_rate(runtime->rate); @@ -1196,7 +1187,6 @@ static int snd_trident_si7018_capture_prepare(struct snd_pcm_substream *substrea evoice->ESO = (runtime->period_size * 2) - 1; } - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -1218,7 +1208,7 @@ static int snd_trident_foldback_prepare(struct snd_pcm_substream *substream) struct snd_trident_voice *voice = runtime->private_data; struct snd_trident_voice *evoice = voice->extra; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); /* Set channel buffer Address */ if (voice->memblk) @@ -1273,7 +1263,6 @@ static int snd_trident_foldback_prepare(struct snd_pcm_substream *substream) evoice->ESO = (runtime->period_size * 2) - 1; } - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -1307,35 +1296,33 @@ static int snd_trident_spdif_hw_params(struct snd_pcm_substream *substream, } /* prepare SPDIF channel */ - spin_lock_irq(&trident->reg_lock); - old_bits = trident->spdif_pcm_bits; - if (old_bits & IEC958_AES0_PROFESSIONAL) - trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS; - else - trident->spdif_pcm_bits &= ~(IEC958_AES3_CON_FS << 24); - if (params_rate(hw_params) >= 48000) { - trident->spdif_pcm_ctrl = 0x3c; // 48000 Hz - trident->spdif_pcm_bits |= - trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? + scoped_guard(spinlock_irq, &trident->reg_lock) { + old_bits = trident->spdif_pcm_bits; + if (old_bits & IEC958_AES0_PROFESSIONAL) + trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS; + else + trident->spdif_pcm_bits &= ~(IEC958_AES3_CON_FS << 24); + if (params_rate(hw_params) >= 48000) { + trident->spdif_pcm_ctrl = 0x3c; // 48000 Hz + trident->spdif_pcm_bits |= + trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? IEC958_AES0_PRO_FS_48000 : (IEC958_AES3_CON_FS_48000 << 24); - } - else if (params_rate(hw_params) >= 44100) { - trident->spdif_pcm_ctrl = 0x3e; // 44100 Hz - trident->spdif_pcm_bits |= - trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? + } else if (params_rate(hw_params) >= 44100) { + trident->spdif_pcm_ctrl = 0x3e; // 44100 Hz + trident->spdif_pcm_bits |= + trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? IEC958_AES0_PRO_FS_44100 : (IEC958_AES3_CON_FS_44100 << 24); - } - else { - trident->spdif_pcm_ctrl = 0x3d; // 32000 Hz - trident->spdif_pcm_bits |= - trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? + } else { + trident->spdif_pcm_ctrl = 0x3d; // 32000 Hz + trident->spdif_pcm_bits |= + trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? IEC958_AES0_PRO_FS_32000 : (IEC958_AES3_CON_FS_32000 << 24); + } + change = old_bits != trident->spdif_pcm_bits; } - change = old_bits != trident->spdif_pcm_bits; - spin_unlock_irq(&trident->reg_lock); if (change) snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE, &trident->spdif_pcm_ctl->id); @@ -1364,7 +1351,7 @@ static int snd_trident_spdif_prepare(struct snd_pcm_substream *substream) unsigned int RESO, LBAO; unsigned int temp; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); if (trident->device != TRIDENT_DEVICE_ID_SI7018) { @@ -1476,8 +1463,6 @@ static int snd_trident_spdif_prepare(struct snd_pcm_substream *substream) outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); } - spin_unlock_irq(&trident->reg_lock); - return 0; } @@ -1518,7 +1503,7 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream, return -EINVAL; } what = whati = capture_flag = spdif_flag = 0; - spin_lock(&trident->reg_lock); + guard(spinlock)(&trident->reg_lock); val = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff; snd_pcm_group_for_each_entry(s, substream) { if ((struct snd_trident *) snd_pcm_substream_chip(s) == trident) { @@ -1577,7 +1562,6 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream, if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018) outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD)); } - spin_unlock(&trident->reg_lock); return 0; } @@ -1602,7 +1586,7 @@ static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream * if (!voice->running) return 0; - spin_lock(&trident->reg_lock); + guard(spinlock)(&trident->reg_lock); outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); @@ -1612,8 +1596,6 @@ static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream * cso = (unsigned int) inl(TRID_REG(trident, CH_NX_DELTA_CSO)) & 0x00ffffff; } - spin_unlock(&trident->reg_lock); - if (cso >= runtime->buffer_size) cso = 0; @@ -1866,9 +1848,9 @@ static int snd_trident_spdif_open(struct snd_pcm_substream *substream) return -EAGAIN; voice->spdif = 1; voice->substream = substream; - spin_lock_irq(&trident->reg_lock); - trident->spdif_pcm_bits = trident->spdif_bits; - spin_unlock_irq(&trident->reg_lock); + scoped_guard(spinlock_irq, &trident->reg_lock) { + trident->spdif_pcm_bits = trident->spdif_bits; + } runtime->private_data = voice; runtime->private_free = snd_trident_pcm_free_substream; @@ -1901,22 +1883,22 @@ static int snd_trident_spdif_close(struct snd_pcm_substream *substream) struct snd_trident *trident = snd_pcm_substream_chip(substream); unsigned int temp; - spin_lock_irq(&trident->reg_lock); - // restore default SPDIF setting - if (trident->device != TRIDENT_DEVICE_ID_SI7018) { - outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); - outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS)); - } else { - outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS)); - temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)); - if (trident->spdif_ctrl) { - temp |= SPDIF_EN; + scoped_guard(spinlock_irq, &trident->reg_lock) { + // restore default SPDIF setting + if (trident->device != TRIDENT_DEVICE_ID_SI7018) { + outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); + outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS)); } else { - temp &= ~SPDIF_EN; + outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS)); + temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)); + if (trident->spdif_ctrl) { + temp |= SPDIF_EN; + } else { + temp &= ~SPDIF_EN; + } + outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); } - outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); } - spin_unlock_irq(&trident->reg_lock); trident->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &trident->spdif_pcm_ctl->id); @@ -2013,9 +1995,8 @@ static int snd_trident_foldback_close(struct snd_pcm_substream *substream) voice = runtime->private_data; /* stop capture channel */ - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); outb(0x00, TRID_REG(trident, T4D_RCI + voice->foldback_chan)); - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -2269,10 +2250,9 @@ static int snd_trident_spdif_control_get(struct snd_kcontrol *kcontrol, struct snd_trident *trident = snd_kcontrol_chip(kcontrol); unsigned char val; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); val = trident->spdif_ctrl; ucontrol->value.integer.value[0] = val == kcontrol->private_value; - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -2284,7 +2264,7 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol, int change; val = ucontrol->value.integer.value[0] ? (unsigned char) kcontrol->private_value : 0x00; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); /* S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled */ change = trident->spdif_ctrl != val; trident->spdif_ctrl = val; @@ -2303,7 +2283,6 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol, outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); } } - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2336,12 +2315,11 @@ static int snd_trident_spdif_default_get(struct snd_kcontrol *kcontrol, { struct snd_trident *trident = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); ucontrol->value.iec958.status[0] = (trident->spdif_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (trident->spdif_bits >> 8) & 0xff; ucontrol->value.iec958.status[2] = (trident->spdif_bits >> 16) & 0xff; ucontrol->value.iec958.status[3] = (trident->spdif_bits >> 24) & 0xff; - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -2356,7 +2334,7 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol, (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); change = trident->spdif_bits != val; trident->spdif_bits = val; if (trident->device != TRIDENT_DEVICE_ID_SI7018) { @@ -2366,7 +2344,6 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol, if (trident->spdif == NULL) outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS)); } - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2431,12 +2408,11 @@ static int snd_trident_spdif_stream_get(struct snd_kcontrol *kcontrol, { struct snd_trident *trident = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); ucontrol->value.iec958.status[0] = (trident->spdif_pcm_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (trident->spdif_pcm_bits >> 8) & 0xff; ucontrol->value.iec958.status[2] = (trident->spdif_pcm_bits >> 16) & 0xff; ucontrol->value.iec958.status[3] = (trident->spdif_pcm_bits >> 24) & 0xff; - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -2451,7 +2427,7 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol, (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); change = trident->spdif_pcm_bits != val; trident->spdif_pcm_bits = val; if (trident->spdif != NULL) { @@ -2461,7 +2437,6 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol, outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS)); } } - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2489,10 +2464,9 @@ static int snd_trident_ac97_control_get(struct snd_kcontrol *kcontrol, struct snd_trident *trident = snd_kcontrol_chip(kcontrol); unsigned char val; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); val = trident->ac97_ctrl = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)); ucontrol->value.integer.value[0] = (val & (1 << kcontrol->private_value)) ? 1 : 0; - spin_unlock_irq(&trident->reg_lock); return 0; } @@ -2503,7 +2477,7 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol, unsigned char val; int change = 0; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); val = trident->ac97_ctrl = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)); val &= ~(1 << kcontrol->private_value); if (ucontrol->value.integer.value[0]) @@ -2511,7 +2485,6 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol, change = val != trident->ac97_ctrl; trident->ac97_ctrl = val; outl(trident->ac97_ctrl = val, TRID_REG(trident, NX_ACR0_AC97_COM_STAT)); - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2562,14 +2535,13 @@ static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, unsigned int val; int change = 0; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); val = trident->musicvol_wavevol; val &= ~(0xffff << kcontrol->private_value); val |= ((255 - (ucontrol->value.integer.value[0] & 0xff)) | ((255 - (ucontrol->value.integer.value[1] & 0xff)) << 8)) << kcontrol->private_value; change = val != trident->musicvol_wavevol; outl(trident->musicvol_wavevol = val, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL)); - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2642,12 +2614,11 @@ static int snd_trident_pcm_vol_control_put(struct snd_kcontrol *kcontrol, } else { val = (255 - (ucontrol->value.integer.value[0] & 255)) << 2; } - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); change = val != mix->vol; mix->vol = val; if (mix->voice != NULL) snd_trident_write_vol_reg(trident, mix->voice, val); - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2706,12 +2677,11 @@ static int snd_trident_pcm_pan_control_put(struct snd_kcontrol *kcontrol, val = ucontrol->value.integer.value[0] & 0x3f; else val = (0x3f - (ucontrol->value.integer.value[0] & 0x3f)) | 0x40; - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); change = val != mix->pan; mix->pan = val; if (mix->voice != NULL) snd_trident_write_pan_reg(trident, mix->voice, val); - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2761,12 +2731,11 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, int change = 0; val = 0x7f - (ucontrol->value.integer.value[0] & 0x7f); - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); change = val != mix->rvol; mix->rvol = val; if (mix->voice != NULL) snd_trident_write_rvol_reg(trident, mix->voice, val); - spin_unlock_irq(&trident->reg_lock); return change; } @@ -2819,12 +2788,11 @@ static int snd_trident_pcm_cvol_control_put(struct snd_kcontrol *kcontrol, int change = 0; val = 0x7f - (ucontrol->value.integer.value[0] & 0x7f); - spin_lock_irq(&trident->reg_lock); + guard(spinlock_irq)(&trident->reg_lock); change = val != mix->cvol; mix->cvol = val; if (mix->voice != NULL) snd_trident_write_cvol_reg(trident, mix->voice, val); - spin_unlock_irq(&trident->reg_lock); return change; } @@ -3659,79 +3627,76 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id) return IRQ_NONE; if (audio_int & ADDRESS_IRQ) { // get interrupt status for all channels - spin_lock(&trident->reg_lock); - stimer = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff; - chn_int = inl(TRID_REG(trident, T4D_AINT_A)); - if (chn_int == 0) - goto __skip1; - outl(chn_int, TRID_REG(trident, T4D_AINT_A)); /* ack */ - __skip1: - chn_int = inl(TRID_REG(trident, T4D_AINT_B)); - if (chn_int == 0) - goto __skip2; - for (channel = 63; channel >= 32; channel--) { - mask = 1 << (channel&0x1f); - if ((chn_int & mask) == 0) - continue; - voice = &trident->synth.voices[channel]; - if (!voice->pcm || voice->substream == NULL) { - outl(mask, TRID_REG(trident, T4D_STOP_B)); - continue; - } - delta = (int)stimer - (int)voice->stimer; - if (delta < 0) - delta = -delta; - if ((unsigned int)delta < voice->spurious_threshold) { - /* do some statistics here */ - trident->spurious_irq_count++; - if (trident->spurious_irq_max_delta < (unsigned int)delta) - trident->spurious_irq_max_delta = delta; - continue; - } - voice->stimer = stimer; - if (voice->isync) { - if (!voice->isync3) { - tmp = inw(TRID_REG(trident, T4D_SBBL_SBCL)); - if (trident->bDMAStart & 0x40) - tmp >>= 1; - if (tmp > 0) - tmp = voice->isync_max - tmp; - } else { - tmp = inl(TRID_REG(trident, NX_SPCTRL_SPCSO)) & 0x00ffffff; + scoped_guard(spinlock, &trident->reg_lock) { + stimer = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff; + chn_int = inl(TRID_REG(trident, T4D_AINT_A)); + if (chn_int) + outl(chn_int, TRID_REG(trident, T4D_AINT_A)); /* ack */ + chn_int = inl(TRID_REG(trident, T4D_AINT_B)); + if (chn_int == 0) + break; + for (channel = 63; channel >= 32; channel--) { + mask = 1 << (channel&0x1f); + if ((chn_int & mask) == 0) + continue; + voice = &trident->synth.voices[channel]; + if (!voice->pcm || voice->substream == NULL) { + outl(mask, TRID_REG(trident, T4D_STOP_B)); + continue; + } + delta = (int)stimer - (int)voice->stimer; + if (delta < 0) + delta = -delta; + if ((unsigned int)delta < voice->spurious_threshold) { + /* do some statistics here */ + trident->spurious_irq_count++; + if (trident->spurious_irq_max_delta < (unsigned int)delta) + trident->spurious_irq_max_delta = delta; + continue; } - if (tmp < voice->isync_mark) { - if (tmp > 0x10) - tmp = voice->isync_ESO - 7; - else - tmp = voice->isync_ESO + 2; - /* update ESO for IRQ voice to preserve sync */ + voice->stimer = stimer; + if (voice->isync) { + if (!voice->isync3) { + tmp = inw(TRID_REG(trident, T4D_SBBL_SBCL)); + if (trident->bDMAStart & 0x40) + tmp >>= 1; + if (tmp > 0) + tmp = voice->isync_max - tmp; + } else { + tmp = inl(TRID_REG(trident, NX_SPCTRL_SPCSO)) & 0x00ffffff; + } + if (tmp < voice->isync_mark) { + if (tmp > 0x10) + tmp = voice->isync_ESO - 7; + else + tmp = voice->isync_ESO + 2; + /* update ESO for IRQ voice to preserve sync */ + snd_trident_stop_voice(trident, voice->number); + snd_trident_write_eso_reg(trident, voice, tmp); + snd_trident_start_voice(trident, voice->number); + } + } else if (voice->isync2) { + voice->isync2 = 0; + /* write original ESO and update CSO for IRQ voice to preserve sync */ snd_trident_stop_voice(trident, voice->number); - snd_trident_write_eso_reg(trident, voice, tmp); + snd_trident_write_cso_reg(trident, voice, voice->isync_mark); + snd_trident_write_eso_reg(trident, voice, voice->ESO); snd_trident_start_voice(trident, voice->number); } - } else if (voice->isync2) { - voice->isync2 = 0; - /* write original ESO and update CSO for IRQ voice to preserve sync */ - snd_trident_stop_voice(trident, voice->number); - snd_trident_write_cso_reg(trident, voice, voice->isync_mark); - snd_trident_write_eso_reg(trident, voice, voice->ESO); - snd_trident_start_voice(trident, voice->number); - } #if 0 - if (voice->extra) { - /* update CSO for extra voice to preserve sync */ - snd_trident_stop_voice(trident, voice->extra->number); - snd_trident_write_cso_reg(trident, voice->extra, 0); - snd_trident_start_voice(trident, voice->extra->number); - } + if (voice->extra) { + /* update CSO for extra voice to preserve sync */ + snd_trident_stop_voice(trident, voice->extra->number); + snd_trident_write_cso_reg(trident, voice->extra, 0); + snd_trident_start_voice(trident, voice->extra->number); + } #endif - spin_unlock(&trident->reg_lock); - snd_pcm_period_elapsed(voice->substream); - spin_lock(&trident->reg_lock); + spin_unlock(&trident->reg_lock); + snd_pcm_period_elapsed(voice->substream); + spin_lock(&trident->reg_lock); + } + outl(chn_int, TRID_REG(trident, T4D_AINT_B)); /* ack */ } - outl(chn_int, TRID_REG(trident, T4D_AINT_B)); /* ack */ - __skip2: - spin_unlock(&trident->reg_lock); } if (audio_int & MPU401_IRQ) { if (trident->rmidi) { @@ -3747,16 +3712,13 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id) struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port) { struct snd_trident_voice *pvoice; - unsigned long flags; int idx; - spin_lock_irqsave(&trident->voice_alloc, flags); + guard(spinlock_irqsave)(&trident->voice_alloc); if (type == SNDRV_TRIDENT_VOICE_TYPE_PCM) { idx = snd_trident_allocate_pcm_channel(trident); - if(idx < 0) { - spin_unlock_irqrestore(&trident->voice_alloc, flags); + if (idx < 0) return NULL; - } pvoice = &trident->synth.voices[idx]; pvoice->use = 1; pvoice->pcm = 1; @@ -3764,27 +3726,22 @@ struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, pvoice->spdif = 0; pvoice->memblk = NULL; pvoice->substream = NULL; - spin_unlock_irqrestore(&trident->voice_alloc, flags); return pvoice; } if (type == SNDRV_TRIDENT_VOICE_TYPE_SYNTH) { idx = snd_trident_allocate_synth_channel(trident); - if(idx < 0) { - spin_unlock_irqrestore(&trident->voice_alloc, flags); + if (idx < 0) return NULL; - } pvoice = &trident->synth.voices[idx]; pvoice->use = 1; pvoice->synth = 1; pvoice->client = client; pvoice->port = port; pvoice->memblk = NULL; - spin_unlock_irqrestore(&trident->voice_alloc, flags); return pvoice; } if (type == SNDRV_TRIDENT_VOICE_TYPE_MIDI) { } - spin_unlock_irqrestore(&trident->voice_alloc, flags); return NULL; } @@ -3792,26 +3749,25 @@ EXPORT_SYMBOL(snd_trident_alloc_voice); void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice) { - unsigned long flags; void (*private_free)(struct snd_trident_voice *); if (voice == NULL || !voice->use) return; snd_trident_clear_voices(trident, voice->number, voice->number); - spin_lock_irqsave(&trident->voice_alloc, flags); - private_free = voice->private_free; - voice->private_free = NULL; - voice->private_data = NULL; - if (voice->pcm) - snd_trident_free_pcm_channel(trident, voice->number); - if (voice->synth) - snd_trident_free_synth_channel(trident, voice->number); - voice->use = voice->pcm = voice->synth = voice->midi = 0; - voice->capture = voice->spdif = 0; - voice->sample_ops = NULL; - voice->substream = NULL; - voice->extra = NULL; - spin_unlock_irqrestore(&trident->voice_alloc, flags); + scoped_guard(spinlock_irqsave, &trident->voice_alloc) { + private_free = voice->private_free; + voice->private_free = NULL; + voice->private_data = NULL; + if (voice->pcm) + snd_trident_free_pcm_channel(trident, voice->number); + if (voice->synth) + snd_trident_free_synth_channel(trident, voice->number); + voice->use = voice->pcm = voice->synth = voice->midi = 0; + voice->capture = voice->spdif = 0; + voice->sample_ops = NULL; + voice->substream = NULL; + voice->extra = NULL; + } if (private_free) private_free(voice); } From 9d60b94f13d3d1e7251b86e838920d0b0ad4947f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:34 +0200 Subject: [PATCH 0969/1292] ALSA: via82xx: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-60-tiwai@suse.de --- sound/pci/via82xx.c | 80 ++++++++++++++++++--------------------- sound/pci/via82xx_modem.c | 6 +-- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 0753c0c73f5143..2b0f9e38863edd 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -628,7 +628,7 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id) } /* check status for each stream */ - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); for (i = 0; i < chip->num_devs; i++) { struct viadev *viadev = &chip->devs[i]; unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS)); @@ -652,7 +652,6 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id) } outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */ } - spin_unlock(&chip->reg_lock); return IRQ_HANDLED; } @@ -667,7 +666,7 @@ static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id) int irqreturn = 0; /* check status for each stream */ - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); status = inl(VIAREG(chip, SGD_SHADOW)); for (i = 0; i < chip->num_devs; i++) { @@ -706,7 +705,6 @@ static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id) outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */ irqreturn = 1; } - spin_unlock(&chip->reg_lock); return IRQ_RETVAL(irqreturn); } @@ -833,7 +831,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE)) return 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff; /* The via686a does not have the current index register, * so we need to calculate the index from CURR_PTR. @@ -845,7 +843,6 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries; res = calc_linear_pos(chip, viadev, idx, count); viadev->lastpos = res; /* remember the last position */ - spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); } @@ -863,7 +860,7 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst if (snd_BUG_ON(!viadev->tbl_entries)) return 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)); status = viadev->in_interrupt; if (!status) @@ -904,7 +901,6 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst } unlock: viadev->lastpos = res; - spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); } @@ -997,7 +993,7 @@ static int via_lock_rate(struct via_rate_lock *rec, int rate) { int changed = 0; - spin_lock_irq(&rec->lock); + guard(spinlock_irq)(&rec->lock); if (rec->rate != rate) { if (rec->rate && rec->used > 1) /* already set */ changed = -EINVAL; @@ -1006,7 +1002,6 @@ static int via_lock_rate(struct via_rate_lock *rec, int rate) changed = 1; } } - spin_unlock_irq(&rec->lock); return changed; } @@ -1167,33 +1162,33 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev, /* set the hw rate condition */ ratep = &chip->rates[viadev->direction]; - spin_lock_irq(&ratep->lock); - ratep->used++; - if (chip->spdif_on && viadev->reg_offset == 0x30) { - /* DXS#3 and spdif is on */ - runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF]; - snd_pcm_limit_hw_rates(runtime); - } else if (chip->dxs_fixed && viadev->reg_offset < 0x40) { - /* fixed DXS playback rate */ - runtime->hw.rates = SNDRV_PCM_RATE_48000; - runtime->hw.rate_min = runtime->hw.rate_max = 48000; - } else if (chip->dxs_src && viadev->reg_offset < 0x40) { - /* use full SRC capabilities of DXS */ - runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS | - SNDRV_PCM_RATE_8000_48000); - runtime->hw.rate_min = 8000; - runtime->hw.rate_max = 48000; - use_src = true; - } else if (! ratep->rate) { - int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; - runtime->hw.rates = chip->ac97->rates[idx]; - snd_pcm_limit_hw_rates(runtime); - } else { - /* a fixed rate */ - runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate; + scoped_guard(spinlock_irq, &ratep->lock) { + ratep->used++; + if (chip->spdif_on && viadev->reg_offset == 0x30) { + /* DXS#3 and spdif is on */ + runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF]; + snd_pcm_limit_hw_rates(runtime); + } else if (chip->dxs_fixed && viadev->reg_offset < 0x40) { + /* fixed DXS playback rate */ + runtime->hw.rates = SNDRV_PCM_RATE_48000; + runtime->hw.rate_min = runtime->hw.rate_max = 48000; + } else if (chip->dxs_src && viadev->reg_offset < 0x40) { + /* use full SRC capabilities of DXS */ + runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_48000); + runtime->hw.rate_min = 8000; + runtime->hw.rate_max = 48000; + use_src = true; + } else if (!ratep->rate) { + int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; + runtime->hw.rates = chip->ac97->rates[idx]; + snd_pcm_limit_hw_rates(runtime); + } else { + /* a fixed rate */ + runtime->hw.rates = SNDRV_PCM_RATE_KNOT; + runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate; + } } - spin_unlock_irq(&ratep->lock); /* we may remove following constaint when we modify table entries in interrupt */ @@ -1311,11 +1306,11 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream) /* release the rate lock */ ratep = &chip->rates[viadev->direction]; - spin_lock_irq(&ratep->lock); - ratep->used--; - if (! ratep->used) - ratep->rate = 0; - spin_unlock_irq(&ratep->lock); + scoped_guard(spinlock_irq, &ratep->lock) { + ratep->used--; + if (!ratep->used) + ratep->rate = 0; + } if (! ratep->rate) { if (! viadev->direction) { snd_ac97_update_power(chip->ac97, @@ -1606,14 +1601,13 @@ static int snd_via8233_capture_source_put(struct snd_kcontrol *kcontrol, unsigned long port = chip->port + (kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL); u8 val, oval; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oval = inb(port); val = oval & ~VIA_REG_CAPTURE_CHANNEL_MIC; if (ucontrol->value.enumerated.item[0]) val |= VIA_REG_CAPTURE_CHANNEL_MIC; if (val != oval) outb(val, port); - spin_unlock_irq(&chip->reg_lock); return val != oval; } diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 12a8c620724d2a..6ce2cd88cda6c2 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -483,7 +483,7 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id) // _skip_sgd: /* check status for each stream */ - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); for (i = 0; i < chip->num_devs; i++) { struct viadev *viadev = &chip->devs[i]; unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS)); @@ -497,7 +497,6 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id) } outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */ } - spin_unlock(&chip->reg_lock); return IRQ_HANDLED; } @@ -616,7 +615,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE)) return 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff; /* The via686a does not have the current index register, * so we need to calculate the index from CURR_PTR. @@ -628,7 +627,6 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries; res = calc_linear_pos(chip, viadev, idx, count); - spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); } From dde5decc43de96ff508815e359aef6edcef68634 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:35 +0200 Subject: [PATCH 0970/1292] ALSA: vx222: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-61-tiwai@suse.de --- sound/pci/vx222/vx222_ops.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 3e7e928b24f8b6..b6459dbdb1b050 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -868,10 +868,10 @@ static int vx_input_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem { struct vx_core *_chip = snd_kcontrol_chip(kcontrol); struct snd_vx222 *chip = to_vx222(_chip); - mutex_lock(&_chip->mixer_mutex); + + guard(mutex)(&_chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->input_level[0]; ucontrol->value.integer.value[1] = chip->input_level[1]; - mutex_unlock(&_chip->mixer_mutex); return 0; } @@ -885,16 +885,14 @@ static int vx_input_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem if (ucontrol->value.integer.value[1] < 0 || ucontrol->value.integer.value[1] > MIC_LEVEL_MAX) return -EINVAL; - mutex_lock(&_chip->mixer_mutex); + guard(mutex)(&_chip->mixer_mutex); if (chip->input_level[0] != ucontrol->value.integer.value[0] || chip->input_level[1] != ucontrol->value.integer.value[1]) { chip->input_level[0] = ucontrol->value.integer.value[0]; chip->input_level[1] = ucontrol->value.integer.value[1]; vx2_set_input_level(chip); - mutex_unlock(&_chip->mixer_mutex); return 1; } - mutex_unlock(&_chip->mixer_mutex); return 0; } @@ -923,14 +921,12 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v if (ucontrol->value.integer.value[0] < 0 || ucontrol->value.integer.value[0] > MIC_LEVEL_MAX) return -EINVAL; - mutex_lock(&_chip->mixer_mutex); + guard(mutex)(&_chip->mixer_mutex); if (chip->mic_level != ucontrol->value.integer.value[0]) { chip->mic_level = ucontrol->value.integer.value[0]; vx2_set_input_level(chip); - mutex_unlock(&_chip->mixer_mutex); return 1; } - mutex_unlock(&_chip->mixer_mutex); return 0; } From 8c0cb47e2692d7a1c2b56e6b0b9912868a598461 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:43:36 +0200 Subject: [PATCH 0971/1292] ALSA: ymfpci: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829144342.4290-62-tiwai@suse.de --- sound/pci/ymfpci/ymfpci_main.c | 248 ++++++++++++++------------------- 1 file changed, 101 insertions(+), 147 deletions(-) diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 75e013b66c5b3d..eb373d9395e35f 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -159,26 +159,21 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate) static void snd_ymfpci_hw_start(struct snd_ymfpci *chip) { - unsigned long flags; - - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (chip->start_count++ > 0) - goto __end; + return; snd_ymfpci_writel(chip, YDSXGR_MODE, snd_ymfpci_readl(chip, YDSXGR_MODE) | 3); chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1; - __end: - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_ymfpci_hw_stop(struct snd_ymfpci *chip) { - unsigned long flags; long timeout = 1000; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (--chip->start_count > 0) - goto __end; + return; snd_ymfpci_writel(chip, YDSXGR_MODE, snd_ymfpci_readl(chip, YDSXGR_MODE) & ~3); while (timeout-- > 0) { @@ -189,8 +184,6 @@ static void snd_ymfpci_hw_stop(struct snd_ymfpci *chip) atomic_set(&chip->interrupt_sleep_count, 0); wake_up(&chip->interrupt_sleep); } - __end: - spin_unlock_irqrestore(&chip->reg_lock, flags); } /* @@ -239,7 +232,6 @@ static int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip, enum snd_ymfpci_voice_type type, int pair, struct snd_ymfpci_voice **rvoice) { - unsigned long flags; int result; if (snd_BUG_ON(!rvoice)) @@ -247,7 +239,7 @@ static int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip, if (snd_BUG_ON(pair && type != YMFPCI_PCM)) return -EINVAL; - spin_lock_irqsave(&chip->voice_lock, flags); + guard(spinlock_irqsave)(&chip->voice_lock); for (;;) { result = voice_alloc(chip, type, pair, rvoice); if (result == 0 || type != YMFPCI_PCM) @@ -255,18 +247,15 @@ static int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip, /* TODO: synth/midi voice deallocation */ break; } - spin_unlock_irqrestore(&chip->voice_lock, flags); return result; } static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voice *pvoice) { - unsigned long flags; - if (snd_BUG_ON(!pvoice)) return -EINVAL; snd_ymfpci_hw_stop(chip); - spin_lock_irqsave(&chip->voice_lock, flags); + guard(spinlock_irqsave)(&chip->voice_lock); if (pvoice->number == chip->src441_used) { chip->src441_used = -1; pvoice->ypcm->use_441_slot = 0; @@ -274,7 +263,6 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0; pvoice->ypcm = NULL; pvoice->interrupt = NULL; - spin_unlock_irqrestore(&chip->voice_lock, flags); return 0; } @@ -292,7 +280,7 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_ return; if (ypcm->substream == NULL) return; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); if (ypcm->running) { pos = le32_to_cpu(voice->bank[chip->active_bank].start); if (pos < ypcm->last_pos) @@ -334,7 +322,6 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_ ypcm->update_pcm_vol--; } } - spin_unlock(&chip->reg_lock); } static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream) @@ -344,7 +331,7 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream struct snd_ymfpci *chip = ypcm->chip; u32 pos, delta; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); if (ypcm->running) { pos = le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift; if (pos < ypcm->last_pos) @@ -366,7 +353,6 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream spin_lock(&chip->reg_lock); } } - spin_unlock(&chip->reg_lock); } static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, @@ -377,11 +363,9 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, struct snd_kcontrol *kctl = NULL; int result = 0; - spin_lock(&chip->reg_lock); - if (ypcm->voices[0] == NULL) { - result = -EINVAL; - goto __unlock; - } + guard(spinlock)(&chip->reg_lock); + if (ypcm->voices[0] == NULL) + return -EINVAL; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -405,11 +389,8 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, ypcm->running = 0; break; default: - result = -EINVAL; - break; + return -EINVAL; } - __unlock: - spin_unlock(&chip->reg_lock); if (kctl) snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return result; @@ -422,7 +403,7 @@ static int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream, int result = 0; u32 tmp; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -442,7 +423,6 @@ static int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream, result = -EINVAL; break; } - spin_unlock(&chip->reg_lock); return result; } @@ -489,7 +469,6 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int unsigned int nbank; __le32 vol_left, vol_right; u8 use_left, use_right; - unsigned long flags; if (snd_BUG_ON(!voice)) return; @@ -509,26 +488,26 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int vol_left = cpu_to_le32(0x40000000); vol_right = cpu_to_le32(0x40000000); } - spin_lock_irqsave(&ypcm->chip->voice_lock, flags); - format = runtime->channels == 2 ? 0x00010000 : 0; - if (snd_pcm_format_width(runtime->format) == 8) - format |= 0x80000000; - else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && - runtime->rate == 44100 && runtime->channels == 2 && - voiceidx == 0 && (ypcm->chip->src441_used == -1 || - ypcm->chip->src441_used == voice->number)) { - ypcm->chip->src441_used = voice->number; - ypcm->use_441_slot = 1; - format |= 0x10000000; - } - if (ypcm->chip->src441_used == voice->number && - (format & 0x10000000) == 0) { - ypcm->chip->src441_used = -1; - ypcm->use_441_slot = 0; + scoped_guard(spinlock_irqsave, &ypcm->chip->voice_lock) { + format = runtime->channels == 2 ? 0x00010000 : 0; + if (snd_pcm_format_width(runtime->format) == 8) + format |= 0x80000000; + else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && + runtime->rate == 44100 && runtime->channels == 2 && + voiceidx == 0 && (ypcm->chip->src441_used == -1 || + ypcm->chip->src441_used == voice->number)) { + ypcm->chip->src441_used = voice->number; + ypcm->use_441_slot = 1; + format |= 0x10000000; + } + if (ypcm->chip->src441_used == voice->number && + (format & 0x10000000) == 0) { + ypcm->chip->src441_used = -1; + ypcm->use_441_slot = 0; + } + if (runtime->channels == 2 && (voiceidx & 1) != 0) + format |= 1; } - if (runtime->channels == 2 && (voiceidx & 1) != 0) - format |= 1; - spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags); for (nbank = 0; nbank < 2; nbank++) { bank = &voice->bank[nbank]; memset(bank, 0, sizeof(*bank)); @@ -596,19 +575,18 @@ static int snd_ymfpci_ac3_init(struct snd_ymfpci *chip) chip->bank_effect[4][0]->loop_end = chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) | 3 << 3); - spin_unlock_irq(&chip->reg_lock); return 0; } static int snd_ymfpci_ac3_done(struct snd_ymfpci *chip) { - spin_lock_irq(&chip->reg_lock); - snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, - snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3)); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, + snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3)); + } // snd_ymfpci_irq_wait(chip); if (chip->ac3_tmp_base.area) { snd_dma_free_pages(&chip->ac3_tmp_base); @@ -778,28 +756,28 @@ static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id) status = snd_ymfpci_readl(chip, YDSXGR_STATUS); if (status & 0x80000000) { chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1; - spin_lock(&chip->voice_lock); - for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) { - voice = &chip->voices[nvoice]; - if (voice->interrupt) - voice->interrupt(chip, voice); - } - for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) { - if (chip->capture_substream[nvoice]) - snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]); - } + scoped_guard(spinlock, &chip->voice_lock) { + for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) { + voice = &chip->voices[nvoice]; + if (voice->interrupt) + voice->interrupt(chip, voice); + } + for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) { + if (chip->capture_substream[nvoice]) + snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]); + } #if 0 - for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) { - if (chip->effect_substream[nvoice]) - snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]); - } + for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) { + if (chip->effect_substream[nvoice]) + snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]); + } #endif - spin_unlock(&chip->voice_lock); - spin_lock(&chip->reg_lock); - snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000); - mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2; - snd_ymfpci_writel(chip, YDSXGR_MODE, mode); - spin_unlock(&chip->reg_lock); + } + scoped_guard(spinlock, &chip->reg_lock) { + snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000); + mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2; + snd_ymfpci_writel(chip, YDSXGR_MODE, mode); + } if (atomic_read(&chip->interrupt_sleep_count)) { atomic_set(&chip->interrupt_sleep_count, 0); @@ -936,12 +914,11 @@ static int snd_ymfpci_playback_open(struct snd_pcm_substream *substream) ypcm->output_front = 1; ypcm->output_rear = chip->mode_dup4ch ? 1 : 0; ypcm->swap_rear = 0; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); if (ypcm->output_rear) { ymfpci_open_extension(chip); chip->rear_opened++; } - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -959,14 +936,14 @@ static int snd_ymfpci_playback_spdif_open(struct snd_pcm_substream *substream) ypcm->output_front = 0; ypcm->output_rear = 1; ypcm->swap_rear = 1; - spin_lock_irq(&chip->reg_lock); - snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, - snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2); - ymfpci_open_extension(chip); - chip->spdif_pcm_bits = chip->spdif_bits; - snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits); - chip->spdif_opened++; - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, + snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2); + ymfpci_open_extension(chip); + chip->spdif_pcm_bits = chip->spdif_bits; + snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits); + chip->spdif_opened++; + } chip->spdif_pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | @@ -988,10 +965,9 @@ static int snd_ymfpci_playback_4ch_open(struct snd_pcm_substream *substream) ypcm->output_front = 0; ypcm->output_rear = 1; ypcm->swap_rear = 0; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); ymfpci_open_extension(chip); chip->rear_opened++; - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1048,12 +1024,12 @@ static int snd_ymfpci_playback_close(struct snd_pcm_substream *substream) struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; - spin_lock_irq(&chip->reg_lock); - if (ypcm->output_rear && chip->rear_opened > 0) { - chip->rear_opened--; - ymfpci_close_extension(chip); + scoped_guard(spinlock_irq, &chip->reg_lock) { + if (ypcm->output_rear && chip->rear_opened > 0) { + chip->rear_opened--; + ymfpci_close_extension(chip); + } } - spin_unlock_irq(&chip->reg_lock); return snd_ymfpci_playback_close_1(substream); } @@ -1061,13 +1037,13 @@ static int snd_ymfpci_playback_spdif_close(struct snd_pcm_substream *substream) { struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); - chip->spdif_opened = 0; - ymfpci_close_extension(chip); - snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, - snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2); - snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); - spin_unlock_irq(&chip->reg_lock); + scoped_guard(spinlock_irq, &chip->reg_lock) { + chip->spdif_opened = 0; + ymfpci_close_extension(chip); + snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, + snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2); + snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); + } chip->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id); @@ -1078,12 +1054,12 @@ static int snd_ymfpci_playback_4ch_close(struct snd_pcm_substream *substream) { struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); - spin_lock_irq(&chip->reg_lock); - if (chip->rear_opened > 0) { - chip->rear_opened--; - ymfpci_close_extension(chip); + scoped_guard(spinlock_irq, &chip->reg_lock) { + if (chip->rear_opened > 0) { + chip->rear_opened--; + ymfpci_close_extension(chip); + } } - spin_unlock_irq(&chip->reg_lock); return snd_ymfpci_playback_close_1(substream); } @@ -1264,11 +1240,10 @@ static int snd_ymfpci_spdif_default_get(struct snd_kcontrol *kcontrol, { struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); ucontrol->value.iec958.status[0] = (chip->spdif_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (chip->spdif_bits >> 8) & 0xff; ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1281,12 +1256,11 @@ static int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol, val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) | (ucontrol->value.iec958.status[1] << 8); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); change = chip->spdif_bits != val; chip->spdif_bits = val; if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 1) && chip->pcm_spdif == NULL) snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); - spin_unlock_irq(&chip->reg_lock); return change; } @@ -1311,10 +1285,9 @@ static int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol, { struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); ucontrol->value.iec958.status[0] = 0x3e; ucontrol->value.iec958.status[1] = 0xff; - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1339,11 +1312,10 @@ static int snd_ymfpci_spdif_stream_get(struct snd_kcontrol *kcontrol, { struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); ucontrol->value.iec958.status[0] = (chip->spdif_pcm_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (chip->spdif_pcm_bits >> 8) & 0xff; ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; - spin_unlock_irq(&chip->reg_lock); return 0; } @@ -1356,12 +1328,11 @@ static int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol, val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) | (ucontrol->value.iec958.status[1] << 8); - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); change = chip->spdif_pcm_bits != val; chip->spdif_pcm_bits = val; if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 2)) snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits); - spin_unlock_irq(&chip->reg_lock); return change; } @@ -1387,9 +1358,8 @@ static int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); u16 reg; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); - spin_unlock_irq(&chip->reg_lock); if (!(reg & 0x100)) value->value.enumerated.item[0] = 0; else @@ -1402,14 +1372,13 @@ static int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_ struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); u16 reg, old_reg; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); if (value->value.enumerated.item[0] == 0) reg = old_reg & ~0x100; else reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9); snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg); - spin_unlock_irq(&chip->reg_lock); return reg != old_reg; } @@ -1469,12 +1438,11 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol, } val = (ucontrol->value.integer.value[0] & mask); val <<= shift; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oval = snd_ymfpci_readl(chip, reg); val = (oval & ~(mask << shift)) | val; change = val != oval; snd_ymfpci_writel(chip, reg, val); - spin_unlock_irq(&chip->reg_lock); return change; } @@ -1510,9 +1478,8 @@ static int snd_ymfpci_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (reg < 0x80 || reg >= 0xc0) return -EINVAL; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); val = snd_ymfpci_readl(chip, reg); - spin_unlock_irq(&chip->reg_lock); ucontrol->value.integer.value[0] = (val >> shift_left) & mask; ucontrol->value.integer.value[1] = (val >> shift_right) & mask; return 0; @@ -1532,12 +1499,11 @@ static int snd_ymfpci_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e val2 = ucontrol->value.integer.value[1] & mask; val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oval = snd_ymfpci_readl(chip, reg); val1 = (oval & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; change = val1 != oval; snd_ymfpci_writel(chip, reg, val1); - spin_unlock_irq(&chip->reg_lock); return change; } @@ -1552,12 +1518,11 @@ static int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0] & 0x3fff; value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16; - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); oval = snd_ymfpci_readl(chip, reg); change = value != oval; snd_ymfpci_writel(chip, reg, value); snd_ymfpci_writel(chip, reg2, value); - spin_unlock_irq(&chip->reg_lock); return change; } @@ -1629,9 +1594,8 @@ YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4) static int snd_ymfpci_get_gpio_out(struct snd_ymfpci *chip, int pin) { u16 reg, mode; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE); reg &= ~(1 << (pin + 8)); reg |= (1 << pin); @@ -1642,23 +1606,20 @@ static int snd_ymfpci_get_gpio_out(struct snd_ymfpci *chip, int pin) snd_ymfpci_writew(chip, YDSXGR_GPIOTYPECONFIG, mode); snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8))); mode = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS); - spin_unlock_irqrestore(&chip->reg_lock, flags); return (mode >> pin) & 1; } static int snd_ymfpci_set_gpio_out(struct snd_ymfpci *chip, int pin, int enable) { u16 reg; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE); reg &= ~(1 << pin); reg &= ~(1 << (pin + 8)); snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg); snd_ymfpci_writew(chip, YDSXGR_GPIOOUTCTRL, enable << pin); snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8))); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -1726,7 +1687,6 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); unsigned int subs = kcontrol->id.subdevice; struct snd_pcm_substream *substream; - unsigned long flags; if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left || ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { @@ -1738,13 +1698,12 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, chip->pcm_mixer[subs].right = 0x8000; substream = (struct snd_pcm_substream *)kcontrol->private_value; - spin_lock_irqsave(&chip->voice_lock, flags); + guard(spinlock_irqsave)(&chip->voice_lock); if (substream->runtime && substream->runtime->private_data) { struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; if (!ypcm->use_441_slot) ypcm->update_pcm_vol = 2; } - spin_unlock_irqrestore(&chip->voice_lock, flags); return 1; } return 0; @@ -1884,11 +1843,10 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) static int snd_ymfpci_timer_start(struct snd_timer *timer) { struct snd_ymfpci *chip; - unsigned long flags; unsigned int count; chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (timer->sticks > 1) { chip->timer_ticks = timer->sticks; count = timer->sticks - 1; @@ -1902,19 +1860,16 @@ static int snd_ymfpci_timer_start(struct snd_timer *timer) } snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count); snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static int snd_ymfpci_timer_stop(struct snd_timer *timer) { struct snd_ymfpci *chip; - unsigned long flags; chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -2273,10 +2228,9 @@ static int snd_ymfpci_resume(struct device *dev) /* start hw again */ if (chip->start_count > 0) { - spin_lock_irq(&chip->reg_lock); + guard(spinlock_irq)(&chip->reg_lock); snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode); chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT); - spin_unlock_irq(&chip->reg_lock); } snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; From 8c6a0bc917b4ba7db9945dacda7cc582af7a335f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:41 +0200 Subject: [PATCH 0972/1292] ALSA: ad1816a: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-2-tiwai@suse.de --- sound/isa/ad1816a/ad1816a_lib.c | 117 ++++++++++---------------------- 1 file changed, 37 insertions(+), 80 deletions(-) diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 400ae547bcbab0..50f62304de6129 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -96,14 +96,10 @@ static unsigned char snd_ad1816a_get_format(struct snd_ad1816a *chip, static int snd_ad1816a_open(struct snd_ad1816a *chip, unsigned int mode) { - unsigned long flags; + guard(spinlock_irqsave)(&chip->lock); - spin_lock_irqsave(&chip->lock, flags); - - if (chip->mode & mode) { - spin_unlock_irqrestore(&chip->lock, flags); + if (chip->mode & mode) return -EAGAIN; - } switch ((mode &= AD1816A_MODE_OPEN)) { case AD1816A_MODE_PLAYBACK: @@ -126,15 +122,12 @@ static int snd_ad1816a_open(struct snd_ad1816a *chip, unsigned int mode) } chip->mode |= mode; - spin_unlock_irqrestore(&chip->lock, flags); return 0; } static void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode) { - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); switch ((mode &= AD1816A_MODE_OPEN)) { case AD1816A_MODE_PLAYBACK: @@ -158,8 +151,6 @@ static void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode) chip->mode &= ~mode; if (!(chip->mode & AD1816A_MODE_OPEN)) chip->mode = 0; - - spin_unlock_irqrestore(&chip->lock, flags); } @@ -171,19 +162,19 @@ static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: - spin_lock(&chip->lock); - cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00; - /* if (what & AD1816A_PLAYBACK_ENABLE) */ - /* That is not valid, because playback and capture enable - * are the same bit pattern, just to different addresses - */ - if (! iscapture) - snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG, - AD1816A_PLAYBACK_ENABLE, cmd); - else - snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG, - AD1816A_CAPTURE_ENABLE, cmd); - spin_unlock(&chip->lock); + scoped_guard(spinlock, &chip->lock) { + cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00; + /* if (what & AD1816A_PLAYBACK_ENABLE) */ + /* That is not valid, because playback and capture enable + * are the same bit pattern, just to different addresses + */ + if (!iscapture) + snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG, + AD1816A_PLAYBACK_ENABLE, cmd); + else + snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG, + AD1816A_CAPTURE_ENABLE, cmd); + } break; default: dev_warn(chip->card->dev, "invalid trigger mode 0x%x.\n", what); @@ -210,11 +201,10 @@ static int snd_ad1816a_capture_trigger(struct snd_pcm_substream *substream, int static int snd_ad1816a_playback_prepare(struct snd_pcm_substream *substream) { struct snd_ad1816a *chip = snd_pcm_substream_chip(substream); - unsigned long flags; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size, rate; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); chip->p_dma_size = size = snd_pcm_lib_buffer_bytes(substream); snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG, @@ -234,19 +224,16 @@ static int snd_ad1816a_playback_prepare(struct snd_pcm_substream *substream) snd_ad1816a_write(chip, AD1816A_PLAYBACK_BASE_COUNT, snd_pcm_lib_period_bytes(substream) / 4 - 1); - - spin_unlock_irqrestore(&chip->lock, flags); return 0; } static int snd_ad1816a_capture_prepare(struct snd_pcm_substream *substream) { struct snd_ad1816a *chip = snd_pcm_substream_chip(substream); - unsigned long flags; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size, rate; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); chip->c_dma_size = size = snd_pcm_lib_buffer_bytes(substream); snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG, @@ -266,8 +253,6 @@ static int snd_ad1816a_capture_prepare(struct snd_pcm_substream *substream) snd_ad1816a_write(chip, AD1816A_CAPTURE_BASE_COUNT, snd_pcm_lib_period_bytes(substream) / 4 - 1); - - spin_unlock_irqrestore(&chip->lock, flags); return 0; } @@ -298,9 +283,9 @@ static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id) struct snd_ad1816a *chip = dev_id; unsigned char status; - spin_lock(&chip->lock); - status = snd_ad1816a_in(chip, AD1816A_INTERRUPT_STATUS); - spin_unlock(&chip->lock); + scoped_guard(spinlock, &chip->lock) { + status = snd_ad1816a_in(chip, AD1816A_INTERRUPT_STATUS); + } if ((status & AD1816A_PLAYBACK_IRQ_PENDING) && chip->playback_substream) snd_pcm_period_elapsed(chip->playback_substream); @@ -311,9 +296,9 @@ static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id) if ((status & AD1816A_TIMER_IRQ_PENDING) && chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); - spin_lock(&chip->lock); - snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00); - spin_unlock(&chip->lock); + scoped_guard(spinlock, &chip->lock) { + snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00); + } return IRQ_HANDLED; } @@ -381,9 +366,9 @@ static unsigned long snd_ad1816a_timer_resolution(struct snd_timer *timer) static int snd_ad1816a_timer_start(struct snd_timer *timer) { unsigned short bits; - unsigned long flags; struct snd_ad1816a *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->lock, flags); + + guard(spinlock_irqsave)(&chip->lock); bits = snd_ad1816a_read(chip, AD1816A_INTERRUPT_ENABLE); if (!(bits & AD1816A_TIMER_ENABLE)) { @@ -393,20 +378,16 @@ static int snd_ad1816a_timer_start(struct snd_timer *timer) snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE, AD1816A_TIMER_ENABLE, 0xffff); } - spin_unlock_irqrestore(&chip->lock, flags); return 0; } static int snd_ad1816a_timer_stop(struct snd_timer *timer) { - unsigned long flags; struct snd_ad1816a *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE, AD1816A_TIMER_ENABLE, 0x0000); - - spin_unlock_irqrestore(&chip->lock, flags); return 0; } @@ -474,9 +455,7 @@ static int snd_ad1816a_capture_close(struct snd_pcm_substream *substream) static void snd_ad1816a_init(struct snd_ad1816a *chip) { - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00); snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG, @@ -488,40 +467,32 @@ static void snd_ad1816a_init(struct snd_ad1816a *chip) AD1816A_CAPTURE_NOT_EQUAL | AD1816A_WSS_ENABLE, 0xffff); snd_ad1816a_write(chip, AD1816A_DSP_CONFIG, 0x0000); snd_ad1816a_write(chip, AD1816A_POWERDOWN_CTRL, 0x0000); - - spin_unlock_irqrestore(&chip->lock, flags); } #ifdef CONFIG_PM void snd_ad1816a_suspend(struct snd_ad1816a *chip) { int reg; - unsigned long flags; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); for (reg = 0; reg < 48; reg++) chip->image[reg] = snd_ad1816a_read(chip, reg); - spin_unlock_irqrestore(&chip->lock, flags); } void snd_ad1816a_resume(struct snd_ad1816a *chip) { int reg; - unsigned long flags; snd_ad1816a_init(chip); - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); for (reg = 0; reg < 48; reg++) snd_ad1816a_write(chip, reg, chip->image[reg]); - spin_unlock_irqrestore(&chip->lock, flags); } #endif static int snd_ad1816a_probe(struct snd_ad1816a *chip) { - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); switch (chip->version = snd_ad1816a_read(chip, AD1816A_VERSION_ID)) { case 0: @@ -536,8 +507,6 @@ static int snd_ad1816a_probe(struct snd_ad1816a *chip) default: chip->hardware = AD1816A_HW_AUTO; } - - spin_unlock_irqrestore(&chip->lock, flags); return 0; } @@ -679,12 +648,10 @@ static int snd_ad1816a_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned short val; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); val = snd_ad1816a_read(chip, AD1816A_ADC_SOURCE_SEL); - spin_unlock_irqrestore(&chip->lock, flags); ucontrol->value.enumerated.item[0] = (val >> 12) & 7; ucontrol->value.enumerated.item[1] = (val >> 4) & 7; return 0; @@ -693,7 +660,6 @@ static int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned short val; int change; @@ -702,10 +668,9 @@ static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele return -EINVAL; val = (ucontrol->value.enumerated.item[0] << 12) | (ucontrol->value.enumerated.item[1] << 4); - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); change = snd_ad1816a_read(chip, AD1816A_ADC_SOURCE_SEL) != val; snd_ad1816a_write(chip, AD1816A_ADC_SOURCE_SEL, val); - spin_unlock_irqrestore(&chip->lock, flags); return change; } @@ -735,15 +700,13 @@ static int snd_ad1816a_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_ad1816a_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); ucontrol->value.integer.value[0] = (snd_ad1816a_read(chip, reg) >> shift) & mask; - spin_unlock_irqrestore(&chip->lock, flags); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; @@ -752,7 +715,6 @@ static int snd_ad1816a_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -764,12 +726,11 @@ static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ if (invert) val = mask - val; val <<= shift; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); old_val = snd_ad1816a_read(chip, reg); val = (old_val & ~(mask << shift)) | val; change = val != old_val; snd_ad1816a_write(chip, reg, val); - spin_unlock_irqrestore(&chip->lock, flags); return change; } @@ -800,7 +761,6 @@ static int snd_ad1816a_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_ad1816a_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift_left = (kcontrol->private_value >> 8) & 0x0f; int shift_right = (kcontrol->private_value >> 12) & 0x0f; @@ -808,11 +768,10 @@ static int snd_ad1816a_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ int invert = (kcontrol->private_value >> 24) & 0xff; unsigned short val; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); val = snd_ad1816a_read(chip, reg); ucontrol->value.integer.value[0] = (val >> shift_left) & mask; ucontrol->value.integer.value[1] = (val >> shift_right) & mask; - spin_unlock_irqrestore(&chip->lock, flags); if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; @@ -823,7 +782,6 @@ static int snd_ad1816a_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift_left = (kcontrol->private_value >> 8) & 0x0f; int shift_right = (kcontrol->private_value >> 12) & 0x0f; @@ -840,12 +798,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ } val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); old_val = snd_ad1816a_read(chip, reg); val1 = (old_val & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; change = val1 != old_val; snd_ad1816a_write(chip, reg, val1); - spin_unlock_irqrestore(&chip->lock, flags); return change; } From ca1d5ca2e5022f989e3ef48eb2d678a551fb814f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:42 +0200 Subject: [PATCH 0973/1292] ALSA: cmi8330: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-3-tiwai@suse.de --- sound/isa/cmi8330.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index e681c2c8247446..3d1f19321b9e97 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -269,18 +269,17 @@ static const unsigned char cmi8330_sb_init_values[][2] = { static int cmi8330_add_sb_mixers(struct snd_sb *chip) { int idx, err; - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); - snd_sbmixer_write(chip, 0x00, 0x00); /* mixer reset */ - spin_unlock_irqrestore(&chip->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &chip->mixer_lock) { + snd_sbmixer_write(chip, 0x00, 0x00); /* mixer reset */ + } /* mute and zero volume channels */ for (idx = 0; idx < ARRAY_SIZE(cmi8330_sb_init_values); idx++) { - spin_lock_irqsave(&chip->mixer_lock, flags); - snd_sbmixer_write(chip, cmi8330_sb_init_values[idx][0], - cmi8330_sb_init_values[idx][1]); - spin_unlock_irqrestore(&chip->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &chip->mixer_lock) { + snd_sbmixer_write(chip, cmi8330_sb_init_values[idx][0], + cmi8330_sb_init_values[idx][1]); + } } for (idx = 0; idx < ARRAY_SIZE(cmi8330_sb_mixers); idx++) { From 14ba220697f8603795e82db63f81c5f880102a1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:43 +0200 Subject: [PATCH 0974/1292] ALSA: cs423x: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-4-tiwai@suse.de --- sound/isa/cs423x/cs4236_lib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index eaaf39aae5263f..bf5b0ffb92737c 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -956,7 +956,7 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn enable = ucontrol->value.integer.value[0] & 1; - mutex_lock(&chip->mce_mutex); + guard(mutex)(&chip->mce_mutex); snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1); @@ -969,7 +969,6 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn snd_cs4236_ctrl_out(chip, 4, val); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); - mutex_unlock(&chip->mce_mutex); #if 0 dev_dbg(chip->card->dev, From 6f5d556a80a9c719b1c1c2b866a283c6133a0f28 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:44 +0200 Subject: [PATCH 0975/1292] ALSA: cs423x: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-5-tiwai@suse.de --- sound/isa/cs423x/cs4236_lib.c | 128 +++++++++++++--------------------- 1 file changed, 47 insertions(+), 81 deletions(-) diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index bf5b0ffb92737c..e2c29e83102024 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -169,10 +169,9 @@ static void snd_cs4236_playback_format(struct snd_wss *chip, struct snd_pcm_hw_params *params, unsigned char pdfr) { - unsigned long flags; unsigned char rate = divisor_to_rate_register(params->rate_den); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); /* set fast playback format change and clean playback FIFO */ snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10); @@ -180,17 +179,15 @@ static void snd_cs4236_playback_format(struct snd_wss *chip, snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x10); snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_cs4236_capture_format(struct snd_wss *chip, struct snd_pcm_hw_params *params, unsigned char cdfr) { - unsigned long flags; unsigned char rate = divisor_to_rate_register(params->rate_den); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); /* set fast capture format change and clean capture FIFO */ snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20); @@ -198,7 +195,6 @@ static void snd_cs4236_capture_format(struct snd_wss *chip, snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x20); snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate); - spin_unlock_irqrestore(&chip->reg_lock, flags); } #ifdef CONFIG_PM @@ -206,48 +202,45 @@ static void snd_cs4236_capture_format(struct snd_wss *chip, static void snd_cs4236_suspend(struct snd_wss *chip) { int reg; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); for (reg = 0; reg < 32; reg++) chip->image[reg] = snd_wss_in(chip, reg); for (reg = 0; reg < 18; reg++) chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg)); for (reg = 2; reg < 9; reg++) chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_cs4236_resume(struct snd_wss *chip) { int reg; - unsigned long flags; snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - for (reg = 0; reg < 32; reg++) { - switch (reg) { - case CS4236_EXT_REG: - case CS4231_VERSION: - case 27: /* why? CS4235 - master left */ - case 29: /* why? CS4235 - master right */ - break; - default: - snd_wss_out(chip, reg, chip->image[reg]); - break; + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + for (reg = 0; reg < 32; reg++) { + switch (reg) { + case CS4236_EXT_REG: + case CS4231_VERSION: + case 27: /* why? CS4235 - master left */ + case 29: /* why? CS4235 - master right */ + break; + default: + snd_wss_out(chip, reg, chip->image[reg]); + break; + } } - } - for (reg = 0; reg < 18; reg++) - snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]); - for (reg = 2; reg < 9; reg++) { - switch (reg) { - case 7: - break; - default: - snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]); + for (reg = 0; reg < 18; reg++) + snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]); + for (reg = 2; reg < 9; reg++) { + switch (reg) { + case 7: + break; + default: + snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]); + } } } - spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); } @@ -403,15 +396,13 @@ static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; @@ -420,7 +411,6 @@ static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -432,11 +422,10 @@ static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (invert) val = mask - val; val <<= shift; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val; change = val != chip->eimage[CS4236_REG(reg)]; snd_cs4236_ext_out(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -449,15 +438,13 @@ static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; @@ -466,7 +453,6 @@ static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -478,11 +464,10 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_ if (invert) val = mask - val; val <<= shift; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val = (chip->cimage[reg] & ~(mask << shift)) | val; change = val != chip->cimage[reg]; snd_cs4236_ctrl_out(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -516,7 +501,6 @@ static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -524,10 +508,9 @@ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask; ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; @@ -538,7 +521,6 @@ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -556,7 +538,7 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e } val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (left_reg != right_reg) { val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1; val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; @@ -568,7 +550,6 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e change = val1 != chip->eimage[CS4236_REG(left_reg)]; snd_cs4236_ext_out(chip, left_reg, val1); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -592,7 +573,6 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -600,10 +580,9 @@ static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; @@ -614,7 +593,6 @@ static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -632,13 +610,12 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ } val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)]; snd_wss_out(chip, left_reg, val1); snd_cs4236_ext_out(chip, right_reg, val2); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -658,31 +635,27 @@ static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f); ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned short val1, val2; val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f); val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1; val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2; change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)]; snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1); snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -719,31 +692,27 @@ static inline int snd_cs4235_mixer_output_accu_set_volume(int vol) static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]); ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned short val1, val2; val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]); val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1; val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2; change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER]; snd_wss_out(chip, CS4235_LEFT_MASTER, val1); snd_wss_out(chip, CS4235_RIGHT_MASTER, val2); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -929,9 +898,8 @@ WSS_DOUBLE("Analog Loopback Switch", 0, static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0; #if 0 dev_dbg(chip->card->dev, @@ -943,14 +911,12 @@ static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct sn snd_cs4236_ctrl_in(chip, 6), snd_cs4236_ctrl_in(chip, 8)); #endif - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned short enable, val; @@ -958,16 +924,16 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn guard(mutex)(&chip->mce_mutex); snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1); - change = val != chip->image[CS4231_ALT_FEATURE_1]; - snd_wss_out(chip, CS4231_ALT_FEATURE_1, val); - val = snd_cs4236_ctrl_in(chip, 4) | 0xc0; - snd_cs4236_ctrl_out(chip, 4, val); - udelay(100); - val &= ~0x40; - snd_cs4236_ctrl_out(chip, 4, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1); + change = val != chip->image[CS4231_ALT_FEATURE_1]; + snd_wss_out(chip, CS4231_ALT_FEATURE_1, val); + val = snd_cs4236_ctrl_in(chip, 4) | 0xc0; + snd_cs4236_ctrl_out(chip, 4, val); + udelay(100); + val &= ~0x40; + snd_cs4236_ctrl_out(chip, 4, val); + } snd_wss_mce_down(chip); #if 0 From e5a5ad81c825f36a46eb56f3cc41a4c4e3714538 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:45 +0200 Subject: [PATCH 0976/1292] ALSA: es1688: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-6-tiwai@suse.de --- sound/isa/es1688/es1688_lib.c | 280 ++++++++++++++++------------------ 1 file changed, 130 insertions(+), 150 deletions(-) diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 2ef183f197adc7..59987dbc9ae92b 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -105,7 +105,6 @@ EXPORT_SYMBOL(snd_es1688_reset); static int snd_es1688_probe(struct snd_es1688 *chip) { - unsigned long flags; unsigned short major, minor; int i; @@ -113,39 +112,36 @@ static int snd_es1688_probe(struct snd_es1688 *chip) * initialization sequence */ - spin_lock_irqsave(&chip->reg_lock, flags); /* Some ESS1688 cards need this */ - inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ - inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ - inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ - inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */ - inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ - inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */ - inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ - inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ - inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */ - inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ - inb(ES1688P(chip, ENABLE0)); /* ENABLE0 */ - - if (snd_es1688_reset(chip) < 0) { - dev_dbg(chip->card->dev, "ESS: [0x%lx] reset failed... 0x%x\n", - chip->port, inb(ES1688P(chip, READ))); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return -ENODEV; - } - snd_es1688_dsp_command(chip, 0xe7); /* return identification */ - - for (i = 1000, major = minor = 0; i; i--) { - if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80) { - if (major == 0) { - major = inb(ES1688P(chip, READ)); - } else { - minor = inb(ES1688P(chip, READ)); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { /* Some ESS1688 cards need this */ + inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ + inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ + inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ + inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */ + inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ + inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */ + inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ + inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ + inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */ + inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */ + inb(ES1688P(chip, ENABLE0)); /* ENABLE0 */ + + if (snd_es1688_reset(chip) < 0) { + dev_dbg(chip->card->dev, "ESS: [0x%lx] reset failed... 0x%x\n", + chip->port, inb(ES1688P(chip, READ))); + return -ENODEV; + } + snd_es1688_dsp_command(chip, 0xe7); /* return identification */ + + for (i = 1000, major = minor = 0; i; i--) { + if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80) { + if (major == 0) + major = inb(ES1688P(chip, READ)); + else + minor = inb(ES1688P(chip, READ)); } } } - spin_unlock_irqrestore(&chip->reg_lock, flags); - dev_dbg(chip->card->dev, "ESS: [0x%lx] found.. major = 0x%x, minor = 0x%x\n", chip->port, major, minor); @@ -169,15 +165,15 @@ static int snd_es1688_probe(struct snd_es1688 *chip) return -ENODEV; } - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */ - snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */ - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */ + snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */ + } /* enable joystick, but disable OPL3 */ - spin_lock_irqsave(&chip->mixer_lock, flags); - snd_es1688_mixer_write(chip, 0x40, 0x01); - spin_unlock_irqrestore(&chip->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &chip->mixer_lock) { + snd_es1688_mixer_write(chip, 0x40, 0x01); + } return 0; } @@ -185,7 +181,6 @@ static int snd_es1688_probe(struct snd_es1688 *chip) static int snd_es1688_init(struct snd_es1688 * chip, int enable) { static const int irqs[16] = {-1, -1, 0, -1, -1, 1, -1, 2, -1, 0, 3, -1, -1, -1, -1, -1}; - unsigned long flags; int cfg, irq_bits, dma, dma_bits, tmp, tmp1; /* ok.. setup MPU-401 port and joystick and OPL3 */ @@ -214,14 +209,14 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable) } } } - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_mixer_write(chip, 0x40, cfg); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_mixer_write(chip, 0x40, cfg); + } /* --- */ - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_read(chip, 0xb1); - snd_es1688_read(chip, 0xb2); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_read(chip, 0xb1); + snd_es1688_read(chip, 0xb2); + } if (enable) { cfg = 0xf0; /* enable only DMA counter interrupt */ irq_bits = irqs[chip->irq & 0x0f]; @@ -235,9 +230,9 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable) #endif return -EINVAL; } - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_write(chip, 0xb1, cfg | (irq_bits << 2)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_write(chip, 0xb1, cfg | (irq_bits << 2)); + } cfg = 0xf0; /* extended mode DMA enable */ dma = chip->dma8; if (dma > 3 || dma == 2) { @@ -254,20 +249,20 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable) if (dma != 3) dma_bits++; } - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_write(chip, 0xb2, cfg | (dma_bits << 2)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_write(chip, 0xb2, cfg | (dma_bits << 2)); + } } else { - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */ - snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */ - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */ + snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */ + } + } + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_read(chip, 0xb1); + snd_es1688_read(chip, 0xb2); + snd_es1688_reset(chip); } - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_read(chip, 0xb1); - snd_es1688_read(chip, 0xb2); - snd_es1688_reset(chip); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -320,74 +315,70 @@ static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char va } else if (cmd != SNDRV_PCM_TRIGGER_START) { return -EINVAL; } - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); chip->trigger_value = value; val = snd_es1688_read(chip, 0xb8); - if ((val < 0) || (val & 0x0f) == value) { - spin_unlock(&chip->reg_lock); + if ((val < 0) || (val & 0x0f) == value) return -EINVAL; /* something is wrong */ - } #if 0 dev_dbg(chip->card->dev, "trigger: val = 0x%x, value = 0x%x\n", val, value); dev_dbg(chip->card->dev, "trigger: pointer = 0x%x\n", snd_dma_pointer(chip->dma8, chip->dma_size)); #endif snd_es1688_write(chip, 0xb8, (val & 0xf0) | value); - spin_unlock(&chip->reg_lock); return 0; } static int snd_es1688_playback_prepare(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_es1688 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma_size = size; - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_reset(chip); - snd_es1688_set_rate(chip, substream); - snd_es1688_write(chip, 0xb8, 4); /* auto init DMA mode */ - snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels)); - snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */ - if (runtime->channels == 1) { - if (snd_pcm_format_width(runtime->format) == 8) { - /* 8. bit mono */ - snd_es1688_write(chip, 0xb6, 0x80); - snd_es1688_write(chip, 0xb7, 0x51); - snd_es1688_write(chip, 0xb7, 0xd0); - } else { - /* 16. bit mono */ - snd_es1688_write(chip, 0xb6, 0x00); - snd_es1688_write(chip, 0xb7, 0x71); - snd_es1688_write(chip, 0xb7, 0xf4); - } - } else { - if (snd_pcm_format_width(runtime->format) == 8) { - /* 8. bit stereo */ - snd_es1688_write(chip, 0xb6, 0x80); - snd_es1688_write(chip, 0xb7, 0x51); - snd_es1688_write(chip, 0xb7, 0x98); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_reset(chip); + snd_es1688_set_rate(chip, substream); + snd_es1688_write(chip, 0xb8, 4); /* auto init DMA mode */ + snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels)); + snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */ + if (runtime->channels == 1) { + if (snd_pcm_format_width(runtime->format) == 8) { + /* 8. bit mono */ + snd_es1688_write(chip, 0xb6, 0x80); + snd_es1688_write(chip, 0xb7, 0x51); + snd_es1688_write(chip, 0xb7, 0xd0); + } else { + /* 16. bit mono */ + snd_es1688_write(chip, 0xb6, 0x00); + snd_es1688_write(chip, 0xb7, 0x71); + snd_es1688_write(chip, 0xb7, 0xf4); + } } else { - /* 16. bit stereo */ - snd_es1688_write(chip, 0xb6, 0x00); - snd_es1688_write(chip, 0xb7, 0x71); - snd_es1688_write(chip, 0xb7, 0xbc); + if (snd_pcm_format_width(runtime->format) == 8) { + /* 8. bit stereo */ + snd_es1688_write(chip, 0xb6, 0x80); + snd_es1688_write(chip, 0xb7, 0x51); + snd_es1688_write(chip, 0xb7, 0x98); + } else { + /* 16. bit stereo */ + snd_es1688_write(chip, 0xb6, 0x00); + snd_es1688_write(chip, 0xb7, 0x71); + snd_es1688_write(chip, 0xb7, 0xbc); + } } + snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50); + snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50); + snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKON); } - snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50); - snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50); - snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKON); - spin_unlock_irqrestore(&chip->reg_lock, flags); /* --- */ count = -count; snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_write(chip, 0xa4, (unsigned char) count); - snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_write(chip, 0xa4, (unsigned char) count); + snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8)); + } return 0; } @@ -400,51 +391,50 @@ static int snd_es1688_playback_trigger(struct snd_pcm_substream *substream, static int snd_es1688_capture_prepare(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_es1688 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma_size = size; - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_reset(chip); - snd_es1688_set_rate(chip, substream); - snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKOFF); - snd_es1688_write(chip, 0xb8, 0x0e); /* auto init DMA mode */ - snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels)); - snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */ - if (runtime->channels == 1) { - if (snd_pcm_format_width(runtime->format) == 8) { - /* 8. bit mono */ - snd_es1688_write(chip, 0xb7, 0x51); - snd_es1688_write(chip, 0xb7, 0xd0); - } else { - /* 16. bit mono */ - snd_es1688_write(chip, 0xb7, 0x71); - snd_es1688_write(chip, 0xb7, 0xf4); - } - } else { - if (snd_pcm_format_width(runtime->format) == 8) { - /* 8. bit stereo */ - snd_es1688_write(chip, 0xb7, 0x51); - snd_es1688_write(chip, 0xb7, 0x98); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_reset(chip); + snd_es1688_set_rate(chip, substream); + snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKOFF); + snd_es1688_write(chip, 0xb8, 0x0e); /* auto init DMA mode */ + snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels)); + snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */ + if (runtime->channels == 1) { + if (snd_pcm_format_width(runtime->format) == 8) { + /* 8. bit mono */ + snd_es1688_write(chip, 0xb7, 0x51); + snd_es1688_write(chip, 0xb7, 0xd0); + } else { + /* 16. bit mono */ + snd_es1688_write(chip, 0xb7, 0x71); + snd_es1688_write(chip, 0xb7, 0xf4); + } } else { - /* 16. bit stereo */ - snd_es1688_write(chip, 0xb7, 0x71); - snd_es1688_write(chip, 0xb7, 0xbc); + if (snd_pcm_format_width(runtime->format) == 8) { + /* 8. bit stereo */ + snd_es1688_write(chip, 0xb7, 0x51); + snd_es1688_write(chip, 0xb7, 0x98); + } else { + /* 16. bit stereo */ + snd_es1688_write(chip, 0xb7, 0x71); + snd_es1688_write(chip, 0xb7, 0xbc); + } } + snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50); + snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50); } - snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50); - snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50); - spin_unlock_irqrestore(&chip->reg_lock, flags); /* --- */ count = -count; snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_es1688_write(chip, 0xa4, (unsigned char) count); - snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_es1688_write(chip, 0xa4, (unsigned char) count); + snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8)); + } return 0; } @@ -738,19 +728,17 @@ static int snd_es1688_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static int snd_es1688_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned char oval, nval; int change; if (ucontrol->value.enumerated.item[0] > 8) return -EINVAL; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); oval = snd_es1688_mixer_read(chip, ES1688_REC_DEV); nval = (ucontrol->value.enumerated.item[0] & 7) | (oval & ~15); change = nval != oval; if (change) snd_es1688_mixer_write(chip, ES1688_REC_DEV, nval); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -774,15 +762,13 @@ static int snd_es1688_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_es1688_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (snd_es1688_mixer_read(chip, reg) >> shift) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; @@ -791,7 +777,6 @@ static int snd_es1688_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_es1688_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -803,13 +788,12 @@ static int snd_es1688_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (invert) nval = mask - nval; nval <<= shift; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); oval = snd_es1688_mixer_read(chip, reg); nval = (oval & ~(mask << shift)) | nval; change = nval != oval; if (change) snd_es1688_mixer_write(chip, reg, nval); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -833,7 +817,6 @@ static int snd_es1688_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -842,7 +825,7 @@ static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e int invert = (kcontrol->private_value >> 22) & 1; unsigned char left, right; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (left_reg < 0xa0) left = snd_es1688_mixer_read(chip, left_reg); else @@ -854,7 +837,6 @@ static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e right = snd_es1688_read(chip, right_reg); } else right = left; - spin_unlock_irqrestore(&chip->reg_lock, flags); ucontrol->value.integer.value[0] = (left >> shift_left) & mask; ucontrol->value.integer.value[1] = (right >> shift_right) & mask; if (invert) { @@ -867,7 +849,6 @@ static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -885,7 +866,7 @@ static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e } val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (left_reg != right_reg) { if (left_reg < 0xa0) oval1 = snd_es1688_mixer_read(chip, left_reg); @@ -923,7 +904,6 @@ static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e } } - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } From 98ea9c6a06f41ee1d2b158918db9dbf73d6d3493 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:46 +0200 Subject: [PATCH 0977/1292] ALSA: es18xx: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-7-tiwai@suse.de --- sound/isa/es18xx.c | 58 ++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 3e89a84c62447c..1da7b400a17b6a 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -185,16 +185,13 @@ static int snd_es18xx_dsp_get_byte(struct snd_es18xx *chip) static int snd_es18xx_write(struct snd_es18xx *chip, unsigned char reg, unsigned char data) { - unsigned long flags; int ret; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ret = snd_es18xx_dsp_command(chip, reg); if (ret < 0) - goto end; + return ret; ret = snd_es18xx_dsp_command(chip, data); - end: - spin_unlock_irqrestore(&chip->reg_lock, flags); #ifdef REG_DEBUG dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, data); #endif @@ -203,22 +200,20 @@ static int snd_es18xx_write(struct snd_es18xx *chip, static int snd_es18xx_read(struct snd_es18xx *chip, unsigned char reg) { - unsigned long flags; int ret, data; - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); ret = snd_es18xx_dsp_command(chip, 0xC0); if (ret < 0) - goto end; + return ret; ret = snd_es18xx_dsp_command(chip, reg); if (ret < 0) - goto end; + return ret; data = snd_es18xx_dsp_get_byte(chip); ret = data; #ifdef REG_DEBUG dev_dbg(chip->card->dev, "Reg %02x now is %02x (%d)\n", reg, data, ret); #endif - end: - spin_unlock_irqrestore(&chip->reg_lock, flags); return ret; } @@ -228,47 +223,41 @@ static int snd_es18xx_bits(struct snd_es18xx *chip, unsigned char reg, { int ret; unsigned char old, new, oval; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); ret = snd_es18xx_dsp_command(chip, 0xC0); if (ret < 0) - goto end; + return ret; ret = snd_es18xx_dsp_command(chip, reg); if (ret < 0) - goto end; + return ret; ret = snd_es18xx_dsp_get_byte(chip); - if (ret < 0) { - goto end; - } + if (ret < 0) + return ret; old = ret; oval = old & mask; if (val != oval) { ret = snd_es18xx_dsp_command(chip, reg); if (ret < 0) - goto end; + return ret; new = (old & ~mask) | (val & mask); ret = snd_es18xx_dsp_command(chip, new); if (ret < 0) - goto end; + return ret; #ifdef REG_DEBUG dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x (%d)\n", reg, old, new, ret); #endif } - ret = oval; - end: - spin_unlock_irqrestore(&chip->reg_lock, flags); - return ret; + return oval; } static inline void snd_es18xx_mixer_write(struct snd_es18xx *chip, unsigned char reg, unsigned char data) { - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, chip->port + 0x04); outb(data, chip->port + 0x05); - spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, data); #endif @@ -276,12 +265,11 @@ static inline void snd_es18xx_mixer_write(struct snd_es18xx *chip, static inline int snd_es18xx_mixer_read(struct snd_es18xx *chip, unsigned char reg) { - unsigned long flags; int data; - spin_lock_irqsave(&chip->mixer_lock, flags); + + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, chip->port + 0x04); data = inb(chip->port + 0x05); - spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data); #endif @@ -293,8 +281,8 @@ static inline int snd_es18xx_mixer_bits(struct snd_es18xx *chip, unsigned char r unsigned char mask, unsigned char val) { unsigned char old, new, oval; - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); + + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, chip->port + 0x04); old = inb(chip->port + 0x05); oval = old & mask; @@ -306,7 +294,6 @@ static inline int snd_es18xx_mixer_bits(struct snd_es18xx *chip, unsigned char r reg, old, new); #endif } - spin_unlock_irqrestore(&chip->mixer_lock, flags); return oval; } @@ -314,14 +301,13 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch unsigned char mask) { int old, expected, new; - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); + + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, chip->port + 0x04); old = inb(chip->port + 0x05); expected = old ^ mask; outb(expected, chip->port + 0x05); new = inb(chip->port + 0x05); - spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG dev_dbg(chip->card->dev, "Mixer reg %02x was %02x, set to %02x, now is %02x\n", reg, old, expected, new); From 3abb538fffc8af73859f16e6e274962d9b53c907 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:47 +0200 Subject: [PATCH 0978/1292] ALSA: gus: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. As replaced with the guard(mutex), no longer used snd_gf1_mem_lock() is dropped, too. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-8-tiwai@suse.de --- include/sound/gus.h | 1 - sound/isa/gus/gus_dma.c | 10 +++------- sound/isa/gus/gus_main.c | 1 - sound/isa/gus/gus_mem.c | 33 ++++++--------------------------- 4 files changed, 9 insertions(+), 36 deletions(-) diff --git a/include/sound/gus.h b/include/sound/gus.h index 1c8fb6c93e5014..321ae93625ebd9 100644 --- a/include/sound/gus.h +++ b/include/sound/gus.h @@ -515,7 +515,6 @@ struct _SND_IW_LFO_PROGRAM { /* gus_mem.c */ -void snd_gf1_mem_lock(struct snd_gf1_mem * alloc, int xup); int snd_gf1_mem_xfree(struct snd_gf1_mem * alloc, struct snd_gf1_mem_block * block); struct snd_gf1_mem_block *snd_gf1_mem_alloc(struct snd_gf1_mem * alloc, int owner, char *name, int size, int w_16, diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c index bb5a4e2fbfb3c1..7b2e7878adc793 100644 --- a/sound/isa/gus/gus_dma.c +++ b/sound/isa/gus/gus_dma.c @@ -143,18 +143,15 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus) int snd_gf1_dma_init(struct snd_gus_card * gus) { - mutex_lock(&gus->dma_mutex); + guard(mutex)(&gus->dma_mutex); gus->gf1.dma_shared++; - if (gus->gf1.dma_shared > 1) { - mutex_unlock(&gus->dma_mutex); + if (gus->gf1.dma_shared > 1) return 0; - } gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt; gus->gf1.dma_data_pcm = gus->gf1.dma_data_pcm_last = gus->gf1.dma_data_synth = gus->gf1.dma_data_synth_last = NULL; - mutex_unlock(&gus->dma_mutex); return 0; } @@ -162,7 +159,7 @@ int snd_gf1_dma_done(struct snd_gus_card * gus) { struct snd_gf1_dma_block *block; - mutex_lock(&gus->dma_mutex); + guard(mutex)(&gus->dma_mutex); gus->gf1.dma_shared--; if (!gus->gf1.dma_shared) { snd_dma_disable(gus->gf1.dma1); @@ -179,7 +176,6 @@ int snd_gf1_dma_done(struct snd_gus_card * gus) gus->gf1.dma_data_pcm_last = gus->gf1.dma_data_synth_last = NULL; } - mutex_unlock(&gus->dma_mutex); return 0; } diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 873ef4046cd699..a82185c86143e8 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -447,4 +447,3 @@ EXPORT_SYMBOL(snd_gf1_translate_freq); EXPORT_SYMBOL(snd_gf1_mem_alloc); EXPORT_SYMBOL(snd_gf1_mem_xfree); EXPORT_SYMBOL(snd_gf1_mem_free); -EXPORT_SYMBOL(snd_gf1_mem_lock); diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 054058779db608..8d95d8d5abdfd4 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -15,15 +15,6 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer); #endif -void snd_gf1_mem_lock(struct snd_gf1_mem * alloc, int xup) -{ - if (!xup) { - mutex_lock(&alloc->memory_mutex); - } else { - mutex_unlock(&alloc->memory_mutex); - } -} - static struct snd_gf1_mem_block * snd_gf1_mem_xalloc(struct snd_gf1_mem *alloc, struct snd_gf1_mem_block *block, const char *name) @@ -50,7 +41,6 @@ snd_gf1_mem_xalloc(struct snd_gf1_mem *alloc, struct snd_gf1_mem_block *block, alloc->first = nblock; else nblock->prev->next = nblock; - mutex_unlock(&alloc->memory_mutex); return nblock; } pblock = pblock->next; @@ -71,7 +61,6 @@ int snd_gf1_mem_xfree(struct snd_gf1_mem * alloc, struct snd_gf1_mem_block * blo { if (block->share) { /* ok.. shared block */ block->share--; - mutex_unlock(&alloc->memory_mutex); return 0; } if (alloc->first == block) { @@ -183,7 +172,7 @@ struct snd_gf1_mem_block *snd_gf1_mem_alloc(struct snd_gf1_mem * alloc, int owne { struct snd_gf1_mem_block block, *nblock; - snd_gf1_mem_lock(alloc, 0); + guard(mutex)(&alloc->memory_mutex); if (share_id != NULL) { nblock = snd_gf1_mem_share(alloc, share_id); if (nblock != NULL) { @@ -193,36 +182,27 @@ struct snd_gf1_mem_block *snd_gf1_mem_alloc(struct snd_gf1_mem * alloc, int owne goto __std; } nblock->share++; - snd_gf1_mem_lock(alloc, 1); return NULL; } } __std: - if (snd_gf1_mem_find(alloc, &block, size, w_16, align) < 0) { - snd_gf1_mem_lock(alloc, 1); + if (snd_gf1_mem_find(alloc, &block, size, w_16, align) < 0) return NULL; - } if (share_id != NULL) memcpy(&block.share_id, share_id, sizeof(block.share_id)); block.owner = owner; nblock = snd_gf1_mem_xalloc(alloc, &block, name); - snd_gf1_mem_lock(alloc, 1); return nblock; } int snd_gf1_mem_free(struct snd_gf1_mem * alloc, unsigned int address) { - int result; struct snd_gf1_mem_block *block; - snd_gf1_mem_lock(alloc, 0); + guard(mutex)(&alloc->memory_mutex); block = snd_gf1_mem_look(alloc, address); - if (block) { - result = snd_gf1_mem_xfree(alloc, block); - snd_gf1_mem_lock(alloc, 1); - return result; - } - snd_gf1_mem_lock(alloc, 1); + if (block) + return snd_gf1_mem_xfree(alloc, block); return -EINVAL; } @@ -282,7 +262,7 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry, gus = entry->private_data; alloc = &gus->gf1.mem_alloc; - mutex_lock(&alloc->memory_mutex); + guard(mutex)(&alloc->memory_mutex); snd_iprintf(buffer, "8-bit banks : \n "); for (i = 0; i < 4; i++) snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_8[i].address, alloc->banks_8[i].size >> 10, i + 1 < 4 ? "," : ""); @@ -326,7 +306,6 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry, } snd_iprintf(buffer, " Total: memory = %i, used = %i, free = %i\n", total, used, total - used); - mutex_unlock(&alloc->memory_mutex); #if 0 ultra_iprintf(buffer, " Verify: free = %i, max 8-bit block = %i, max 16-bit block = %i\n", ultra_memory_free_size(card, &card->gf1.mem_alloc), From ae2b22b4677767b6f66047b9af320e2f7c9e04d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:48 +0200 Subject: [PATCH 0979/1292] ALSA: gus: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-9-tiwai@suse.de --- sound/isa/gus/gus_dma.c | 78 ++++++++--------- sound/isa/gus/gus_dram.c | 8 +- sound/isa/gus/gus_io.c | 65 +++----------- sound/isa/gus/gus_main.c | 64 +++++++------- sound/isa/gus/gus_mixer.c | 12 +-- sound/isa/gus/gus_pcm.c | 175 +++++++++++++++++-------------------- sound/isa/gus/gus_reset.c | 66 +++++--------- sound/isa/gus/gus_timer.c | 16 +--- sound/isa/gus/gus_uart.c | 24 ++--- sound/isa/gus/gusextreme.c | 23 +++-- sound/isa/gus/interwave.c | 33 ++++--- 11 files changed, 224 insertions(+), 340 deletions(-) diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c index 7b2e7878adc793..ffc69e26227eb7 100644 --- a/sound/isa/gus/gus_dma.c +++ b/sound/isa/gus/gus_dma.c @@ -11,12 +11,9 @@ static void snd_gf1_dma_ack(struct snd_gus_card * gus) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, 0x00); snd_gf1_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL); - spin_unlock_irqrestore(&gus->reg_lock, flags); } static void snd_gf1_dma_program(struct snd_gus_card * gus, @@ -25,7 +22,6 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus, unsigned int count, unsigned int cmd) { - unsigned long flags; unsigned int address; unsigned char dma_cmd; unsigned int address_high; @@ -70,7 +66,7 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus, "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", address << 1, count, dma_cmd); #endif - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); if (gus->gf1.enh_mode) { address_high = ((address >> 16) & 0x000000f0) | (address & 0x0000000f); snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4)); @@ -78,7 +74,6 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus, } else snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4)); snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, dma_cmd); - spin_unlock_irqrestore(&gus->reg_lock, flags); } static struct snd_gf1_dma_block *snd_gf1_dma_next_block(struct snd_gus_card * gus) @@ -120,16 +115,15 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus) snd_gf1_dma_ack(gus); if (gus->gf1.dma_ack) gus->gf1.dma_ack(gus, gus->gf1.dma_private_data); - spin_lock(&gus->dma_lock); - if (gus->gf1.dma_data_pcm == NULL && - gus->gf1.dma_data_synth == NULL) { - gus->gf1.dma_ack = NULL; - gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER; - spin_unlock(&gus->dma_lock); - return; + scoped_guard(spinlock, &gus->dma_lock) { + if (gus->gf1.dma_data_pcm == NULL && + gus->gf1.dma_data_synth == NULL) { + gus->gf1.dma_ack = NULL; + gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER; + return; + } + block = snd_gf1_dma_next_block(gus); } - block = snd_gf1_dma_next_block(gus); - spin_unlock(&gus->dma_lock); if (!block) return; snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd); @@ -184,8 +178,8 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus, int atomic, int synth) { - unsigned long flags; struct snd_gf1_dma_block *block; + struct snd_gf1_dma_block *free_block = NULL; block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL); if (!block) @@ -206,34 +200,36 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus, "gus->gf1.dma_data_pcm = 0x%lx\n", (long)gus->gf1.dma_data_pcm); - spin_lock_irqsave(&gus->dma_lock, flags); - if (synth) { - if (gus->gf1.dma_data_synth_last) { - gus->gf1.dma_data_synth_last->next = block; - gus->gf1.dma_data_synth_last = block; + scoped_guard(spinlock_irqsave, &gus->dma_lock) { + if (synth) { + if (gus->gf1.dma_data_synth_last) { + gus->gf1.dma_data_synth_last->next = block; + gus->gf1.dma_data_synth_last = block; + } else { + gus->gf1.dma_data_synth = + gus->gf1.dma_data_synth_last = block; + } } else { - gus->gf1.dma_data_synth = - gus->gf1.dma_data_synth_last = block; + if (gus->gf1.dma_data_pcm_last) { + gus->gf1.dma_data_pcm_last->next = block; + gus->gf1.dma_data_pcm_last = block; + } else { + gus->gf1.dma_data_pcm = + gus->gf1.dma_data_pcm_last = block; + } } - } else { - if (gus->gf1.dma_data_pcm_last) { - gus->gf1.dma_data_pcm_last->next = block; - gus->gf1.dma_data_pcm_last = block; - } else { - gus->gf1.dma_data_pcm = - gus->gf1.dma_data_pcm_last = block; + if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) { + gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER; + free_block = snd_gf1_dma_next_block(gus); } } - if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) { - gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER; - block = snd_gf1_dma_next_block(gus); - spin_unlock_irqrestore(&gus->dma_lock, flags); - if (block == NULL) - return 0; - snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd); - kfree(block); - return 0; + + if (free_block) { + snd_gf1_dma_program(gus, free_block->addr, free_block->buf_addr, + free_block->count, + (unsigned short)free_block->cmd); + kfree(free_block); } - spin_unlock_irqrestore(&gus->dma_lock, flags); + return 0; } diff --git a/sound/isa/gus/gus_dram.c b/sound/isa/gus/gus_dram.c index 5cebc0119d0aba..50fe738ee3eac7 100644 --- a/sound/isa/gus/gus_dram.c +++ b/sound/isa/gus/gus_dram.c @@ -13,7 +13,6 @@ static int snd_gus_dram_poke(struct snd_gus_card *gus, char __user *_buffer, unsigned int address, unsigned int size) { - unsigned long flags; unsigned int size1, size2; char buffer[256], *pbuffer; @@ -22,11 +21,10 @@ static int snd_gus_dram_poke(struct snd_gus_card *gus, char __user *_buffer, if (copy_from_user(buffer, _buffer, size1)) return -EFAULT; if (gus->interwave) { - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01); snd_gf1_dram_addr(gus, address); outsb(GUSP(gus, DRAM), buffer, size1); - spin_unlock_irqrestore(&gus->reg_lock, flags); address += size1; } else { pbuffer = buffer; @@ -51,19 +49,17 @@ static int snd_gus_dram_peek(struct snd_gus_card *gus, char __user *_buffer, unsigned int address, unsigned int size, int rom) { - unsigned long flags; unsigned int size1, size2; char buffer[256], *pbuffer; while (size > 0) { size1 = size > sizeof(buffer) ? sizeof(buffer) : size; if (gus->interwave) { - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, rom ? 0x03 : 0x01); snd_gf1_dram_addr(gus, address); insb(GUSP(gus, DRAM), buffer, size1); snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01); - spin_unlock_irqrestore(&gus->reg_lock, flags); address += size1; } else { pbuffer = buffer; diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index f167eb8d516b5d..3e6f35084f26c2 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c @@ -177,55 +177,36 @@ unsigned int snd_gf1_read_addr(struct snd_gus_card * gus, void snd_gf1_i_ctrl_stop(struct snd_gus_card * gus, unsigned char reg) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); __snd_gf1_ctrl_stop(gus, reg); - spin_unlock_irqrestore(&gus->reg_lock, flags); } void snd_gf1_i_write8(struct snd_gus_card * gus, unsigned char reg, unsigned char data) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); __snd_gf1_write8(gus, reg, data); - spin_unlock_irqrestore(&gus->reg_lock, flags); } unsigned char snd_gf1_i_look8(struct snd_gus_card * gus, unsigned char reg) { - unsigned long flags; - unsigned char res; - - spin_lock_irqsave(&gus->reg_lock, flags); - res = __snd_gf1_look8(gus, reg); - spin_unlock_irqrestore(&gus->reg_lock, flags); - return res; + guard(spinlock_irqsave)(&gus->reg_lock); + return __snd_gf1_look8(gus, reg); } void snd_gf1_i_write16(struct snd_gus_card * gus, unsigned char reg, unsigned int data) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); __snd_gf1_write16(gus, reg, data); - spin_unlock_irqrestore(&gus->reg_lock, flags); } unsigned short snd_gf1_i_look16(struct snd_gus_card * gus, unsigned char reg) { - unsigned long flags; - unsigned short res; - - spin_lock_irqsave(&gus->reg_lock, flags); - res = __snd_gf1_look16(gus, reg); - spin_unlock_irqrestore(&gus->reg_lock, flags); - return res; + guard(spinlock_irqsave)(&gus->reg_lock); + return __snd_gf1_look16(gus, reg); } void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr) @@ -242,9 +223,7 @@ void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr) void snd_gf1_poke(struct snd_gus_card * gus, unsigned int addr, unsigned char data) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel); mb(); outw((unsigned short) addr, gus->gf1.reg_data16); @@ -254,15 +233,11 @@ void snd_gf1_poke(struct snd_gus_card * gus, unsigned int addr, unsigned char da outb((unsigned char) (addr >> 16), gus->gf1.reg_data8); mb(); outb(data, gus->gf1.reg_dram); - spin_unlock_irqrestore(&gus->reg_lock, flags); } unsigned char snd_gf1_peek(struct snd_gus_card * gus, unsigned int addr) { - unsigned long flags; - unsigned char res; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel); mb(); outw((unsigned short) addr, gus->gf1.reg_data16); @@ -271,20 +246,16 @@ unsigned char snd_gf1_peek(struct snd_gus_card * gus, unsigned int addr) mb(); outb((unsigned char) (addr >> 16), gus->gf1.reg_data8); mb(); - res = inb(gus->gf1.reg_dram); - spin_unlock_irqrestore(&gus->reg_lock, flags); - return res; + return inb(gus->gf1.reg_dram); } #if 0 void snd_gf1_pokew(struct snd_gus_card * gus, unsigned int addr, unsigned short data) { - unsigned long flags; - if (!gus->interwave) dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__); - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel); mb(); outw((unsigned short) addr, gus->gf1.reg_data16); @@ -296,17 +267,13 @@ void snd_gf1_pokew(struct snd_gus_card * gus, unsigned int addr, unsigned short outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel); mb(); outw(data, gus->gf1.reg_data16); - spin_unlock_irqrestore(&gus->reg_lock, flags); } unsigned short snd_gf1_peekw(struct snd_gus_card * gus, unsigned int addr) { - unsigned long flags; - unsigned short res; - if (!gus->interwave) dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__); - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel); mb(); outw((unsigned short) addr, gus->gf1.reg_data16); @@ -317,23 +284,20 @@ unsigned short snd_gf1_peekw(struct snd_gus_card * gus, unsigned int addr) mb(); outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel); mb(); - res = inw(gus->gf1.reg_data16); - spin_unlock_irqrestore(&gus->reg_lock, flags); - return res; + return inw(gus->gf1.reg_data16); } void snd_gf1_dram_setmem(struct snd_gus_card * gus, unsigned int addr, unsigned short value, unsigned int count) { unsigned long port; - unsigned long flags; if (!gus->interwave) dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__); addr &= ~1; count >>= 1; port = GUSP(gus, GF1DATALOW); - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel); mb(); outw((unsigned short) addr, gus->gf1.reg_data16); @@ -345,7 +309,6 @@ void snd_gf1_dram_setmem(struct snd_gus_card * gus, unsigned int addr, outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel); while (count--) outw(value, port); - spin_unlock_irqrestore(&gus->reg_lock, flags); } #endif /* 0 */ diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index a82185c86143e8..5f50a39c6f16d0 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -42,16 +42,14 @@ static int snd_gus_joystick_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int snd_gus_joystick_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned char nval; nval = ucontrol->value.integer.value[0] & 31; - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); change = gus->joystick_dac != nval; gus->joystick_dac = nval; snd_gf1_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac); - spin_unlock_irqrestore(&gus->reg_lock, flags); return change; } @@ -249,7 +247,6 @@ static int snd_gus_detect_memory(struct snd_gus_card * gus) static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) { struct snd_card *card; - unsigned long flags; int irq, dma1, dma2; static const unsigned char irqs[16] = {0, 0, 1, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; @@ -292,34 +289,34 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) card->mixer.mix_ctrl_reg |= 0x10; #endif - spin_lock_irqsave(&gus->reg_lock, flags); - outb(5, GUSP(gus, REGCNTRLS)); - outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); - outb(0x00, GUSP(gus, IRQDMACNTRLREG)); - outb(0, GUSP(gus, REGCNTRLS)); - spin_unlock_irqrestore(&gus->reg_lock, flags); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + outb(5, GUSP(gus, REGCNTRLS)); + outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); + outb(0x00, GUSP(gus, IRQDMACNTRLREG)); + outb(0, GUSP(gus, REGCNTRLS)); + } udelay(100); - spin_lock_irqsave(&gus->reg_lock, flags); - outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); - outb(dma1, GUSP(gus, IRQDMACNTRLREG)); - if (latches) { - outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); - outb(irq, GUSP(gus, IRQDMACNTRLREG)); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); + outb(dma1, GUSP(gus, IRQDMACNTRLREG)); + if (latches) { + outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); + outb(irq, GUSP(gus, IRQDMACNTRLREG)); + } } - spin_unlock_irqrestore(&gus->reg_lock, flags); udelay(100); - spin_lock_irqsave(&gus->reg_lock, flags); - outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); - outb(dma1, GUSP(gus, IRQDMACNTRLREG)); - if (latches) { - outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); - outb(irq, GUSP(gus, IRQDMACNTRLREG)); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); + outb(dma1, GUSP(gus, IRQDMACNTRLREG)); + if (latches) { + outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); + outb(irq, GUSP(gus, IRQDMACNTRLREG)); + } } - spin_unlock_irqrestore(&gus->reg_lock, flags); snd_gf1_delay(gus); @@ -327,26 +324,25 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) gus->mix_cntrl_reg |= 0x08; /* enable latches */ else gus->mix_cntrl_reg &= ~0x08; /* disable latches */ - spin_lock_irqsave(&gus->reg_lock, flags); - outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); - outb(0, GUSP(gus, GF1PAGE)); - spin_unlock_irqrestore(&gus->reg_lock, flags); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); + outb(0, GUSP(gus, GF1PAGE)); + } return 0; } static int snd_gus_check_version(struct snd_gus_card * gus) { - unsigned long flags; unsigned char val, rev; struct snd_card *card; card = gus->card; - spin_lock_irqsave(&gus->reg_lock, flags); - outb(0x20, GUSP(gus, REGCNTRLS)); - val = inb(GUSP(gus, REGCNTRLS)); - rev = inb(GUSP(gus, BOARDVERSION)); - spin_unlock_irqrestore(&gus->reg_lock, flags); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + outb(0x20, GUSP(gus, REGCNTRLS)); + val = inb(GUSP(gus, REGCNTRLS)); + rev = inb(GUSP(gus, BOARDVERSION)); + } dev_dbg(card->dev, "GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev); strscpy(card->driver, "GUS"); strscpy(card->longname, "Gravis UltraSound Classic (2.4)"); diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c index 60c3a8219770d9..9bfdb4e45a5d61 100644 --- a/sound/isa/gus/gus_mixer.c +++ b/sound/isa/gus/gus_mixer.c @@ -37,7 +37,6 @@ static int snd_gf1_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static int snd_gf1_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); - unsigned long flags; int shift = kcontrol->private_value & 0xff; int invert = (kcontrol->private_value >> 8) & 1; int change; @@ -47,13 +46,12 @@ static int snd_gf1_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem if (invert) nval ^= 1; nval <<= shift; - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); oval = gus->mix_cntrl_reg; nval = (oval & ~(1 << shift)) | nval; change = nval != oval; outb(gus->mix_cntrl_reg = nval, GUSP(gus, MIXCNTRLREG)); outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE)); - spin_unlock_irqrestore(&gus->reg_lock, flags); return change; } @@ -75,14 +73,12 @@ static int snd_ics_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ele static int snd_ics_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); - unsigned long flags; int addr = kcontrol->private_value & 0xff; unsigned char left, right; - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); left = gus->gf1.ics_regs[addr][0]; right = gus->gf1.ics_regs[addr][1]; - spin_unlock_irqrestore(&gus->reg_lock, flags); ucontrol->value.integer.value[0] = left & 127; ucontrol->value.integer.value[1] = right & 127; return 0; @@ -91,14 +87,13 @@ static int snd_ics_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static int snd_ics_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); - unsigned long flags; int addr = kcontrol->private_value & 0xff; int change; unsigned char val1, val2, oval1, oval2; val1 = ucontrol->value.integer.value[0] & 127; val2 = ucontrol->value.integer.value[1] & 127; - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); oval1 = gus->gf1.ics_regs[addr][0]; oval2 = gus->gf1.ics_regs[addr][1]; change = val1 != oval1 || val2 != oval2; @@ -116,7 +111,6 @@ static int snd_ics_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem outb(2, GUSP(gus, MIXDATAPORT)); outb(addr | 3, GUSP(gus, MIXCNTRLPORT)); outb((unsigned char) val2, GUSP(gus, MIXDATAPORT)); - spin_unlock_irqrestore(&gus->reg_lock, flags); return change; } diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 8b9b7b8d92b22c..9249cbff30f376 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -89,7 +89,6 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct gus_pcm_private *pcmp = runtime->private_data; struct snd_gus_card * gus = pcmp->gus; - unsigned long flags; unsigned char voice_ctrl, ramp_ctrl; unsigned short rate; unsigned int curr, begin, end; @@ -97,14 +96,12 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream) unsigned char pan; unsigned int voice; - spin_lock_irqsave(&pcmp->lock, flags); - if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) { - spin_unlock_irqrestore(&pcmp->lock, flags); - return; + scoped_guard(spinlock_irqsave, &pcmp->lock) { + if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) + return; + pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE; + pcmp->final_volume = 0; } - pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE; - pcmp->final_volume = 0; - spin_unlock_irqrestore(&pcmp->lock, flags); rate = snd_gf1_translate_freq(gus, runtime->rate << 4); /* enable WAVE IRQ */ voice_ctrl = snd_pcm_format_width(runtime->format) == 16 ? 0x24 : 0x20; @@ -121,7 +118,7 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream) end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1; pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8; vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right; - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number); snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, pan); snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, rate); @@ -137,9 +134,9 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream) snd_gf1_delay(gus); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); } - spin_unlock_irqrestore(&gus->reg_lock, flags); } - spin_lock_irqsave(&gus->reg_lock, flags); + + guard(spinlock_irqsave)(&gus->reg_lock); for (voice = 0; voice < pcmp->voices; voice++) { snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number); if (gus->gf1.enh_mode) @@ -156,7 +153,6 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream) voice_ctrl &= ~0x20; /* disable IRQ for next voice */ } } - spin_unlock_irqrestore(&gus->reg_lock, flags); } static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus, @@ -182,52 +178,52 @@ static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus, gus = pcmp->gus; runtime = pcmp->substream->runtime; - spin_lock(&gus->reg_lock); - snd_gf1_select_voice(gus, pvoice->number); - voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & ~0x8b; - ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03; + scoped_guard(spinlock, &gus->reg_lock) { + snd_gf1_select_voice(gus, pvoice->number); + voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & ~0x8b; + ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03; #if 0 - snd_gf1_select_voice(gus, pvoice->number); - dev_dbg(gus->card->dev, "position = 0x%x\n", - (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4)); - snd_gf1_select_voice(gus, pcmp->pvoices[1]->number); - dev_dbg(gus->card->dev, "position = 0x%x\n", - (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4)); - snd_gf1_select_voice(gus, pvoice->number); + snd_gf1_select_voice(gus, pvoice->number); + dev_dbg(gus->card->dev, "position = 0x%x\n", + (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4)); + snd_gf1_select_voice(gus, pcmp->pvoices[1]->number); + dev_dbg(gus->card->dev, "position = 0x%x\n", + (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4)); + snd_gf1_select_voice(gus, pvoice->number); #endif - pcmp->bpos++; - pcmp->bpos %= pcmp->blocks; - if (pcmp->bpos + 1 >= pcmp->blocks) { /* last block? */ - voice_ctrl |= 0x08; /* enable loop */ - } else { - ramp_ctrl |= 0x04; /* enable rollover */ - } - end = pcmp->memory + (((pcmp->bpos + 1) * pcmp->block_size) / runtime->channels); - end -= voice_ctrl & 4 ? 2 : 1; - step = pcmp->dma_size / runtime->channels; - voice_ctrl |= 0x20; - if (!pcmp->final_volume) { - ramp_ctrl |= 0x20; - ramp_ctrl &= ~0x03; - } - for (idx = 0; idx < pcmp->voices; idx++, end += step) { - snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number); - snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4); - snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl); - snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); - voice_ctrl &= ~0x20; - } - if (!gus->gf1.enh_mode) { - snd_gf1_delay(gus); + pcmp->bpos++; + pcmp->bpos %= pcmp->blocks; + if (pcmp->bpos + 1 >= pcmp->blocks) { /* last block? */ + voice_ctrl |= 0x08; /* enable loop */ + } else { + ramp_ctrl |= 0x04; /* enable rollover */ + } + end = pcmp->memory + (((pcmp->bpos + 1) * pcmp->block_size) / runtime->channels); + end -= voice_ctrl & 4 ? 2 : 1; + step = pcmp->dma_size / runtime->channels; voice_ctrl |= 0x20; - for (idx = 0; idx < pcmp->voices; idx++) { + if (!pcmp->final_volume) { + ramp_ctrl |= 0x20; + ramp_ctrl &= ~0x03; + } + for (idx = 0; idx < pcmp->voices; idx++, end += step) { snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number); + snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4); snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); voice_ctrl &= ~0x20; } + if (!gus->gf1.enh_mode) { + snd_gf1_delay(gus); + voice_ctrl |= 0x20; + for (idx = 0; idx < pcmp->voices; idx++) { + snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number); + snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl); + snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); + voice_ctrl &= ~0x20; + } + } } - spin_unlock(&gus->reg_lock); snd_pcm_period_elapsed(pcmp->substream); #if 0 @@ -252,10 +248,10 @@ static void snd_gf1_pcm_interrupt_volume(struct snd_gus_card * gus, struct gus_pcm_private *pcmp = pvoice->private_data; /* stop ramp, but leave rollover bit untouched */ - spin_lock(&gus->reg_lock); - snd_gf1_select_voice(gus, pvoice->number); - snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); - spin_unlock(&gus->reg_lock); + scoped_guard(spinlock, &gus->reg_lock) { + snd_gf1_select_voice(gus, pvoice->number); + snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); + } if (pcmp == NULL) return; /* are we active? */ @@ -266,11 +262,10 @@ static void snd_gf1_pcm_interrupt_volume(struct snd_gus_card * gus, if (pcmp->substream == NULL) return; vol = !cvoice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right; - spin_lock(&gus->reg_lock); + guard(spinlock)(&gus->reg_lock); snd_gf1_select_voice(gus, pvoice->number); snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol); pcmp->final_volume = 1; - spin_unlock(&gus->reg_lock); } static void snd_gf1_pcm_volume_change(struct snd_gus_card * gus) @@ -282,7 +277,6 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf, int w16, int invert) { unsigned int len; - unsigned long flags; while (count > 0) { len = count; @@ -290,7 +284,7 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf, len = 512; count -= len; if (gus->interwave) { - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01 | (invert ? 0x08 : 0x00)); snd_gf1_dram_addr(gus, pos); if (w16) { @@ -299,7 +293,6 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf, } else { outsb(GUSP(gus, DRAM), buf, len); } - spin_unlock_irqrestore(&gus->reg_lock, flags); buf += 512; pos += 512; } else { @@ -479,9 +472,9 @@ static int snd_gf1_pcm_playback_trigger(struct snd_pcm_substream *substream, if (cmd == SNDRV_PCM_TRIGGER_START) { snd_gf1_pcm_trigger_up(substream); } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { - spin_lock(&pcmp->lock); - pcmp->flags &= ~SNDRV_GF1_PCM_PFLG_ACTIVE; - spin_unlock(&pcmp->lock); + scoped_guard(spinlock, &pcmp->lock) { + pcmp->flags &= ~SNDRV_GF1_PCM_PFLG_ACTIVE; + } voice = pcmp->pvoices[0]->number; snd_gf1_stop_voices(gus, voice, voice); if (pcmp->pvoices[1]) { @@ -503,7 +496,7 @@ static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(struct snd_pcm_substream * unsigned char voice_ctrl; pos = 0; - spin_lock(&gus->reg_lock); + guard(spinlock)(&gus->reg_lock); if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) { snd_gf1_select_voice(gus, pcmp->pvoices[0]->number); voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); @@ -512,7 +505,6 @@ static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(struct snd_pcm_substream * pos <<= 1; pos = bytes_to_frames(runtime, pos); } - spin_unlock(&gus->reg_lock); return pos; } @@ -572,10 +564,9 @@ static int snd_gf1_pcm_capture_trigger(struct snd_pcm_substream *substream, return -EINVAL; } - spin_lock(&gus->reg_lock); + guard(spinlock)(&gus->reg_lock); snd_gf1_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, val); snd_gf1_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL); - spin_unlock(&gus->reg_lock); return 0; } @@ -724,19 +715,16 @@ static int snd_gf1_pcm_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_gf1_pcm_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&gus->pcm_volume_level_lock, flags); + guard(spinlock_irqsave)(&gus->pcm_volume_level_lock); ucontrol->value.integer.value[0] = gus->gf1.pcm_volume_level_left1; ucontrol->value.integer.value[1] = gus->gf1.pcm_volume_level_right1; - spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags); return 0; } static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned int idx; unsigned short val1, val2, vol; @@ -745,33 +733,32 @@ static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ val1 = ucontrol->value.integer.value[0] & 127; val2 = ucontrol->value.integer.value[1] & 127; - spin_lock_irqsave(&gus->pcm_volume_level_lock, flags); - change = val1 != gus->gf1.pcm_volume_level_left1 || - val2 != gus->gf1.pcm_volume_level_right1; - gus->gf1.pcm_volume_level_left1 = val1; - gus->gf1.pcm_volume_level_right1 = val2; - gus->gf1.pcm_volume_level_left = snd_gf1_lvol_to_gvol_raw(val1 << 9) << 4; - gus->gf1.pcm_volume_level_right = snd_gf1_lvol_to_gvol_raw(val2 << 9) << 4; - spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags); + scoped_guard(spinlock_irqsave, &gus->pcm_volume_level_lock) { + change = val1 != gus->gf1.pcm_volume_level_left1 || + val2 != gus->gf1.pcm_volume_level_right1; + gus->gf1.pcm_volume_level_left1 = val1; + gus->gf1.pcm_volume_level_right1 = val2; + gus->gf1.pcm_volume_level_left = snd_gf1_lvol_to_gvol_raw(val1 << 9) << 4; + gus->gf1.pcm_volume_level_right = snd_gf1_lvol_to_gvol_raw(val2 << 9) << 4; + } /* are we active? */ - spin_lock_irqsave(&gus->voice_alloc, flags); - for (idx = 0; idx < 32; idx++) { - pvoice = &gus->gf1.voices[idx]; - if (!pvoice->pcm) - continue; - pcmp = pvoice->private_data; - if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE)) - continue; - /* load real volume - better precision */ - spin_lock(&gus->reg_lock); - snd_gf1_select_voice(gus, pvoice->number); - snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); - vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right; - snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol); - pcmp->final_volume = 1; - spin_unlock(&gus->reg_lock); + scoped_guard(spinlock_irqsave, &gus->voice_alloc) { + for (idx = 0; idx < 32; idx++) { + pvoice = &gus->gf1.voices[idx]; + if (!pvoice->pcm) + continue; + pcmp = pvoice->private_data; + if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE)) + continue; + /* load real volume - better precision */ + guard(spinlock)(&gus->reg_lock); + snd_gf1_select_voice(gus, pvoice->number); + snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); + vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right; + snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol); + pcmp->final_volume = 1; + } } - spin_unlock_irqrestore(&gus->voice_alloc, flags); return change; } diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index 326bc6028885d9..5cbace8369f8e8 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c @@ -83,26 +83,20 @@ void snd_gf1_set_default_handlers(struct snd_gus_card * gus, unsigned int what) static void snd_gf1_clear_regs(struct snd_gus_card * gus) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); inb(GUSP(gus, IRQSTAT)); snd_gf1_write8(gus, 0x41, 0); /* DRAM DMA Control Register */ snd_gf1_write8(gus, 0x45, 0); /* Timer Control */ snd_gf1_write8(gus, 0x49, 0); /* Sampling Control Register */ - spin_unlock_irqrestore(&gus->reg_lock, flags); } static void snd_gf1_look_regs(struct snd_gus_card * gus) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_look8(gus, 0x41); /* DRAM DMA Control Register */ snd_gf1_look8(gus, 0x49); /* Sampling Control Register */ inb(GUSP(gus, IRQSTAT)); snd_gf1_read8(gus, 0x0f); /* IRQ Source Register */ - spin_unlock_irqrestore(&gus->reg_lock, flags); } /* @@ -111,9 +105,7 @@ static void snd_gf1_look_regs(struct snd_gus_card * gus) void snd_gf1_smart_stop_voice(struct snd_gus_card * gus, unsigned short voice) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_select_voice(gus, voice); #if 0 dev_dbg(gus->card->dev, @@ -122,14 +114,11 @@ void snd_gf1_smart_stop_voice(struct snd_gus_card * gus, unsigned short voice) #endif snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); - spin_unlock_irqrestore(&gus->reg_lock, flags); } void snd_gf1_stop_voice(struct snd_gus_card * gus, unsigned short voice) { - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_select_voice(gus, voice); #if 0 dev_dbg(gus->card->dev, @@ -140,13 +129,11 @@ void snd_gf1_stop_voice(struct snd_gus_card * gus, unsigned short voice) snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); if (gus->gf1.enh_mode) snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, 0); - spin_unlock_irqrestore(&gus->reg_lock, flags); } static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min, unsigned short v_max) { - unsigned long flags; unsigned int daddr; unsigned short i, w_16; @@ -156,7 +143,7 @@ static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min if (gus->gf1.syn_voices) gus->gf1.syn_voices[i].flags = ~VFLG_DYNAMIC; #endif - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_select_voice(gus, i); snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); /* Voice Control Register = voice stop */ snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); /* Volume Ramp Control Register = ramp off */ @@ -177,19 +164,17 @@ static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, 0); snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, 0); } - spin_unlock_irqrestore(&gus->reg_lock, flags); } } void snd_gf1_stop_voices(struct snd_gus_card * gus, unsigned short v_min, unsigned short v_max) { - unsigned long flags; short i, ramp_ok; unsigned short ramp_end; if (!in_interrupt()) { /* this can't be done in interrupt */ for (i = v_min, ramp_ok = 0; i <= v_max; i++) { - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); snd_gf1_select_voice(gus, i); ramp_end = snd_gf1_read16(gus, 9) >> 8; if (ramp_end > SNDRV_GF1_MIN_OFFSET) { @@ -203,7 +188,6 @@ void snd_gf1_stop_voices(struct snd_gus_card * gus, unsigned short v_min, unsign snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, 0x40); } } - spin_unlock_irqrestore(&gus->reg_lock, flags); } msleep_interruptible(50); } @@ -236,21 +220,17 @@ static void snd_gf1_alloc_voice_use(struct snd_gus_card * gus, struct snd_gus_voice *snd_gf1_alloc_voice(struct snd_gus_card * gus, int type, int client, int port) { struct snd_gus_voice *pvoice; - unsigned long flags; int idx; - spin_lock_irqsave(&gus->voice_alloc, flags); + guard(spinlock_irqsave)(&gus->voice_alloc); if (type == SNDRV_GF1_VOICE_TYPE_PCM) { - if (gus->gf1.pcm_alloc_voices >= gus->gf1.pcm_channels) { - spin_unlock_irqrestore(&gus->voice_alloc, flags); + if (gus->gf1.pcm_alloc_voices >= gus->gf1.pcm_channels) return NULL; - } } for (idx = 0; idx < 32; idx++) { pvoice = &gus->gf1.voices[idx]; if (!pvoice->use) { snd_gf1_alloc_voice_use(gus, pvoice, type, client, port); - spin_unlock_irqrestore(&gus->voice_alloc, flags); return pvoice; } } @@ -259,32 +239,29 @@ struct snd_gus_voice *snd_gf1_alloc_voice(struct snd_gus_card * gus, int type, i if (pvoice->midi && !pvoice->client) { snd_gf1_clear_voices(gus, pvoice->number, pvoice->number); snd_gf1_alloc_voice_use(gus, pvoice, type, client, port); - spin_unlock_irqrestore(&gus->voice_alloc, flags); return pvoice; } } - spin_unlock_irqrestore(&gus->voice_alloc, flags); return NULL; } void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice) { - unsigned long flags; void (*private_free)(struct snd_gus_voice *voice); if (voice == NULL || !voice->use) return; snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_VOICE | voice->number); snd_gf1_clear_voices(gus, voice->number, voice->number); - spin_lock_irqsave(&gus->voice_alloc, flags); - private_free = voice->private_free; - voice->private_free = NULL; - voice->private_data = NULL; - if (voice->pcm) - gus->gf1.pcm_alloc_voices--; - voice->use = voice->pcm = 0; - voice->sample_ops = NULL; - spin_unlock_irqrestore(&gus->voice_alloc, flags); + scoped_guard(spinlock_irqsave, &gus->voice_alloc) { + private_free = voice->private_free; + voice->private_free = NULL; + voice->private_data = NULL; + if (voice->pcm) + gus->gf1.pcm_alloc_voices--; + voice->use = voice->pcm = 0; + voice->sample_ops = NULL; + } if (private_free) private_free(voice); } @@ -295,7 +272,6 @@ void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice) int snd_gf1_start(struct snd_gus_card * gus) { - unsigned long flags; unsigned int i; snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ @@ -344,10 +320,10 @@ int snd_gf1_start(struct snd_gus_card * gus) } while ((snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ) & 0xc0) != 0xc0); - spin_lock_irqsave(&gus->reg_lock, flags); - outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE)); - outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); - spin_unlock_irqrestore(&gus->reg_lock, flags); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE)); + outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); + } snd_gf1_timers_init(gus); snd_gf1_look_regs(gus); diff --git a/sound/isa/gus/gus_timer.c b/sound/isa/gus/gus_timer.c index 7267fb5bf8e5ec..e3a8847e02cf1a 100644 --- a/sound/isa/gus/gus_timer.c +++ b/sound/isa/gus/gus_timer.c @@ -16,33 +16,29 @@ static int snd_gf1_timer1_start(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; unsigned int ticks; struct snd_gus_card *gus; gus = snd_timer_chip(timer); - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); ticks = timer->sticks; tmp = (gus->gf1.timer_enabled |= 4); snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1, 256 - ticks); /* timer 1 count */ snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 1 IRQ */ snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */ - spin_unlock_irqrestore(&gus->reg_lock, flags); return 0; } static int snd_gf1_timer1_stop(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; struct snd_gus_card *gus; gus = snd_timer_chip(timer); - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); tmp = (gus->gf1.timer_enabled &= ~4); snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */ - spin_unlock_irqrestore(&gus->reg_lock, flags); return 0; } @@ -52,33 +48,29 @@ static int snd_gf1_timer1_stop(struct snd_timer * timer) static int snd_gf1_timer2_start(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; unsigned int ticks; struct snd_gus_card *gus; gus = snd_timer_chip(timer); - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); ticks = timer->sticks; tmp = (gus->gf1.timer_enabled |= 8); snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks); /* timer 2 count */ snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 2 IRQ */ snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */ - spin_unlock_irqrestore(&gus->reg_lock, flags); return 0; } static int snd_gf1_timer2_stop(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; struct snd_gus_card *gus; gus = snd_timer_chip(timer); - spin_lock_irqsave(&gus->reg_lock, flags); + guard(spinlock_irqsave)(&gus->reg_lock); tmp = (gus->gf1.timer_enabled &= ~8); snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */ - spin_unlock_irqrestore(&gus->reg_lock, flags); return 0; } diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index e207f274f240f9..770d8f3e4cfff6 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -49,13 +49,12 @@ static void snd_gf1_interrupt_midi_in(struct snd_gus_card * gus) static void snd_gf1_interrupt_midi_out(struct snd_gus_card * gus) { char byte; - unsigned long flags; /* try unlock output */ if (snd_gf1_uart_stat(gus) & 0x01) snd_gf1_interrupt_midi_in(gus); - spin_lock_irqsave(&gus->uart_cmd_lock, flags); + guard(spinlock_irqsave)(&gus->uart_cmd_lock); if (snd_gf1_uart_stat(gus) & 0x02) { /* Tx FIFO free? */ if (snd_rawmidi_transmit(gus->midi_substream_output, &byte, 1) != 1) { /* no other bytes or error */ snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20); /* disable Tx interrupt */ @@ -63,7 +62,6 @@ static void snd_gf1_interrupt_midi_out(struct snd_gus_card * gus) snd_gf1_uart_put(gus, byte); } } - spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); } static void snd_gf1_uart_reset(struct snd_gus_card * gus, int close) @@ -77,17 +75,15 @@ static void snd_gf1_uart_reset(struct snd_gus_card * gus, int close) static int snd_gf1_uart_output_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_gus_card *gus; gus = substream->rmidi->private_data; - spin_lock_irqsave(&gus->uart_cmd_lock, flags); + guard(spinlock_irqsave)(&gus->uart_cmd_lock); if (!(gus->gf1.uart_cmd & 0x80)) { /* input active? */ snd_gf1_uart_reset(gus, 0); } gus->gf1.interrupt_handler_midi_out = snd_gf1_interrupt_midi_out; gus->midi_substream_output = substream; - spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); #if 0 dev_dbg(gus->card->dev, "write init - cmd = 0x%x, stat = 0x%x\n", @@ -98,12 +94,11 @@ static int snd_gf1_uart_output_open(struct snd_rawmidi_substream *substream) static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_gus_card *gus; int i; gus = substream->rmidi->private_data; - spin_lock_irqsave(&gus->uart_cmd_lock, flags); + guard(spinlock_irqsave)(&gus->uart_cmd_lock); if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) { snd_gf1_uart_reset(gus, 0); } @@ -115,7 +110,6 @@ static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream) if (i >= 1000) dev_err(gus->card->dev, "gus midi uart init read - cleanup error\n"); } - spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); #if 0 dev_dbg(gus->card->dev, "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", @@ -130,42 +124,37 @@ static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream) static int snd_gf1_uart_output_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_gus_card *gus; gus = substream->rmidi->private_data; - spin_lock_irqsave(&gus->uart_cmd_lock, flags); + guard(spinlock_irqsave)(&gus->uart_cmd_lock); if (gus->gf1.interrupt_handler_midi_in != snd_gf1_interrupt_midi_in) snd_gf1_uart_reset(gus, 1); snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_OUT); gus->midi_substream_output = NULL; - spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); return 0; } static int snd_gf1_uart_input_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_gus_card *gus; gus = substream->rmidi->private_data; - spin_lock_irqsave(&gus->uart_cmd_lock, flags); + guard(spinlock_irqsave)(&gus->uart_cmd_lock); if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) snd_gf1_uart_reset(gus, 1); snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_IN); gus->midi_substream_input = NULL; - spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); return 0; } static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_gus_card *gus; - unsigned long flags; gus = substream->rmidi->private_data; - spin_lock_irqsave(&gus->uart_cmd_lock, flags); + guard(spinlock_irqsave)(&gus->uart_cmd_lock); if (up) { if ((gus->gf1.uart_cmd & 0x80) == 0) snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x80); /* enable Rx interrupts */ @@ -173,7 +162,6 @@ static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream *substream, if (gus->gf1.uart_cmd & 0x80) snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x80); /* disable Rx interrupts */ } - spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); } static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 28827a2e6cbdbf..ed921b89b00ab1 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -145,7 +145,6 @@ static int snd_gusextreme_gus_card_create(struct snd_card *card, static int snd_gusextreme_detect(struct snd_gus_card *gus, struct snd_es1688 *es1688) { - unsigned long flags; unsigned char d; /* @@ -162,17 +161,17 @@ static int snd_gusextreme_detect(struct snd_gus_card *gus, * 0x260 = 2,2,1 */ - spin_lock_irqsave(&es1688->mixer_lock, flags); - snd_es1688_mixer_write(es1688, 0x40, 0x0b); /* don't change!!! */ - spin_unlock_irqrestore(&es1688->mixer_lock, flags); - - spin_lock_irqsave(&es1688->reg_lock, flags); - outb(gus->gf1.port & 0x040 ? 2 : 0, ES1688P(es1688, INIT1)); - outb(0, 0x201); - outb(gus->gf1.port & 0x020 ? 2 : 0, ES1688P(es1688, INIT1)); - outb(0, 0x201); - outb(gus->gf1.port & 0x010 ? 3 : 1, ES1688P(es1688, INIT1)); - spin_unlock_irqrestore(&es1688->reg_lock, flags); + scoped_guard(spinlock_irqsave, &es1688->mixer_lock) { + snd_es1688_mixer_write(es1688, 0x40, 0x0b); /* don't change!!! */ + } + + scoped_guard(spinlock_irqsave, &es1688->reg_lock) { + outb(gus->gf1.port & 0x040 ? 2 : 0, ES1688P(es1688, INIT1)); + outb(0, 0x201); + outb(gus->gf1.port & 0x020 ? 2 : 0, ES1688P(es1688, INIT1)); + outb(0, 0x201); + outb(gus->gf1.port & 0x010 ? 3 : 1, ES1688P(es1688, INIT1)); + } udelay(100); diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 0e0bcd85a648df..18adcd35e117ba 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -239,7 +239,6 @@ static int snd_interwave_detect(struct snd_interwave *iwcard, #endif ) { - unsigned long flags; unsigned char rev1, rev2; int d; @@ -257,12 +256,12 @@ static int snd_interwave_detect(struct snd_interwave *iwcard, dev_dbg(gus->card->dev, "[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; } - spin_lock_irqsave(&gus->reg_lock, flags); - rev1 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER); - snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, ~rev1); - rev2 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER); - snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, rev1); - spin_unlock_irqrestore(&gus->reg_lock, flags); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + rev1 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER); + snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, ~rev1); + rev2 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER); + snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, rev1); + } dev_dbg(gus->card->dev, "[0x%lx] InterWave check - rev1=0x%x, rev2=0x%x\n", gus->gf1.port, rev1, rev2); @@ -457,18 +456,16 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus) static void snd_interwave_init(int dev, struct snd_gus_card *gus) { - unsigned long flags; - /* ok.. some InterWave specific initialization */ - spin_lock_irqsave(&gus->reg_lock, flags); - snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00); - snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f); - snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49); - snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11); - snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00); - snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30); - snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00); - spin_unlock_irqrestore(&gus->reg_lock, flags); + scoped_guard(spinlock_irqsave, &gus->reg_lock) { + snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00); + snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f); + snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49); + snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11); + snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00); + snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30); + snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00); + } gus->equal_irq = 1; gus->codec_flag = 1; gus->interwave = 1; From 6aaf6dadd9bf861c1ab1a719d6de02c929a25e0f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:49 +0200 Subject: [PATCH 0980/1292] ALSA: msnd: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-10-tiwai@suse.de --- sound/isa/msnd/msnd.c | 29 ++++++++-------------------- sound/isa/msnd/msnd_pinnacle.c | 11 +++++------ sound/isa/msnd/msnd_pinnacle_mixer.c | 8 ++------ 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c index 8c1d2e27854bc8..5e350234d5726b 100644 --- a/sound/isa/msnd/msnd.c +++ b/sound/isa/msnd/msnd.c @@ -76,15 +76,11 @@ static int snd_msnd_wait_HC0(struct snd_msnd *dev) int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd) { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); + guard(spinlock_irqsave)(&dev->lock); if (snd_msnd_wait_HC0(dev) == 0) { outb(cmd, dev->io + HP_CVR); - spin_unlock_irqrestore(&dev->lock, flags); return 0; } - spin_unlock_irqrestore(&dev->lock, flags); dev_dbg(dev->card->dev, LOGNAME ": Send DSP command timeout\n"); @@ -133,14 +129,12 @@ EXPORT_SYMBOL(snd_msnd_upload_host); int snd_msnd_enable_irq(struct snd_msnd *dev) { - unsigned long flags; - if (dev->irq_ref++) return 0; dev_dbg(dev->card->dev, LOGNAME ": Enabling IRQ\n"); - spin_lock_irqsave(&dev->lock, flags); + guard(spinlock_irqsave)(&dev->lock); if (snd_msnd_wait_TXDE(dev) == 0) { outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR); if (dev->type == msndClassic) @@ -151,10 +145,8 @@ int snd_msnd_enable_irq(struct snd_msnd *dev) enable_irq(dev->irq); snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size); - spin_unlock_irqrestore(&dev->lock, flags); return 0; } - spin_unlock_irqrestore(&dev->lock, flags); dev_dbg(dev->card->dev, LOGNAME ": Enable IRQ failed\n"); @@ -164,8 +156,6 @@ EXPORT_SYMBOL(snd_msnd_enable_irq); int snd_msnd_disable_irq(struct snd_msnd *dev) { - unsigned long flags; - if (--dev->irq_ref > 0) return 0; @@ -175,16 +165,14 @@ int snd_msnd_disable_irq(struct snd_msnd *dev) dev_dbg(dev->card->dev, LOGNAME ": Disabling IRQ\n"); - spin_lock_irqsave(&dev->lock, flags); + guard(spinlock_irqsave)(&dev->lock); if (snd_msnd_wait_TXDE(dev) == 0) { outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); if (dev->type == msndClassic) outb(HPIRQ_NONE, dev->io + HP_IRQM); disable_irq(dev->irq); - spin_unlock_irqrestore(&dev->lock, flags); return 0; } - spin_unlock_irqrestore(&dev->lock, flags); dev_dbg(dev->card->dev, LOGNAME ": Disable IRQ failed\n"); @@ -376,7 +364,6 @@ static void snd_msnd_capture_reset_queue(struct snd_msnd *chip, { int n; void __iomem *pDAQ; - /* unsigned long flags; */ /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */ @@ -388,11 +375,11 @@ static void snd_msnd_capture_reset_queue(struct snd_msnd *chip, chip->DARQ + JQS_wTail); #if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/ - spin_lock_irqsave(&chip->lock, flags); - outb(HPBLKSEL_1, chip->io + HP_BLKS); - memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3); - outb(HPBLKSEL_0, chip->io + HP_BLKS); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + outb(HPBLKSEL_1, chip->io + HP_BLKS); + memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3); + outb(HPBLKSEL_0, chip->io + HP_BLKS); + } #endif chip->capturePeriodBytes = pcm_count; diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 969bbb18657b99..c4eec391cd298c 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -300,7 +300,6 @@ static int snd_msnd_init_sma(struct snd_msnd *chip) { static int initted; u16 mastVolLeft, mastVolRight; - unsigned long flags; #ifdef MSND_CLASSIC outb(chip->memid, chip->io + HP_MEMM); @@ -317,11 +316,11 @@ static int snd_msnd_init_sma(struct snd_msnd *chip) memset_io(chip->mappedbase, 0, 0x8000); /* Critical section: bank 1 access */ - spin_lock_irqsave(&chip->lock, flags); - outb(HPBLKSEL_1, chip->io + HP_BLKS); - memset_io(chip->mappedbase, 0, 0x8000); - outb(HPBLKSEL_0, chip->io + HP_BLKS); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + outb(HPBLKSEL_1, chip->io + HP_BLKS); + memset_io(chip->mappedbase, 0, 0x8000); + outb(HPBLKSEL_0, chip->io + HP_BLKS); + } /* Digital audio play queue */ chip->DAPQ = chip->mappedbase + DAPQ_OFFSET; diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c index 2f1bb5a2b376d5..ec354483b9f825 100644 --- a/sound/isa/msnd/msnd_pinnacle_mixer.c +++ b/sound/isa/msnd/msnd_pinnacle_mixer.c @@ -136,14 +136,12 @@ static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol, { struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol); int addr = kcontrol->private_value; - unsigned long flags; - spin_lock_irqsave(&msnd->mixer_lock, flags); + guard(spinlock_irqsave)(&msnd->mixer_lock); ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100; ucontrol->value.integer.value[0] /= 0xFFFF; ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100; ucontrol->value.integer.value[1] /= 0xFFFF; - spin_unlock_irqrestore(&msnd->mixer_lock, flags); return 0; } @@ -253,15 +251,13 @@ static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol, struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol); int change, addr = kcontrol->private_value; int left, right; - unsigned long flags; left = ucontrol->value.integer.value[0] % 101; right = ucontrol->value.integer.value[1] % 101; - spin_lock_irqsave(&msnd->mixer_lock, flags); + guard(spinlock_irqsave)(&msnd->mixer_lock); change = msnd->left_levels[addr] != left || msnd->right_levels[addr] != right; snd_msndmix_set(msnd, addr, left, right); - spin_unlock_irqrestore(&msnd->mixer_lock, flags); return change; } From 1e012ff2fbe3506b83f4c70ea58071797689fbaa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:50 +0200 Subject: [PATCH 0981/1292] ALSA: opl3sa2: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-11-tiwai@suse.de --- sound/isa/opl3sa2.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 5e8e1326d5c019..8c1767697b6257 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -172,13 +172,8 @@ static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char /* read control port (with spinlock) */ static unsigned char snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char reg) { - unsigned long flags; - unsigned char result; - - spin_lock_irqsave(&chip->reg_lock, flags); - result = __snd_opl3sa2_read(chip, reg); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return result; + guard(spinlock_irqsave)(&chip->reg_lock); + return __snd_opl3sa2_read(chip, reg); } /* write control port (w/o spinlock) */ @@ -195,10 +190,8 @@ static void __snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, uns /* write control port (with spinlock) */ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsigned char value) { - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); __snd_opl3sa2_write(chip, reg, value); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static int snd_opl3sa2_detect(struct snd_card *card) @@ -336,15 +329,13 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id) static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->ctlregs[reg] >> shift) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; @@ -353,7 +344,6 @@ static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -365,12 +355,11 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ if (invert) val = mask - val; val <<= shift; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); oval = chip->ctlregs[reg]; val = (oval & ~(mask << shift)) | val; change = val != oval; __snd_opl3sa2_write(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -391,7 +380,6 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -399,10 +387,9 @@ static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->ctlregs[left_reg] >> shift_left) & mask; ucontrol->value.integer.value[1] = (chip->ctlregs[right_reg] >> shift_right) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; @@ -413,7 +400,6 @@ static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -431,7 +417,7 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ } val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (left_reg != right_reg) { oval1 = chip->ctlregs[left_reg]; oval2 = chip->ctlregs[right_reg]; @@ -446,7 +432,6 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ change = val1 != oval1; __snd_opl3sa2_write(chip, left_reg, val1); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } From 949ffce4af7f33176f271343bff0b72a8b0a64d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:51 +0200 Subject: [PATCH 0982/1292] ALSA: opti9xx: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-12-tiwai@suse.de --- sound/isa/opti9xx/miro.c | 17 +++++------------ sound/isa/opti9xx/opti92x-ad1848.c | 21 ++++++--------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index ad7180d7c0c2b1..c320af3e9a05c5 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -822,10 +822,9 @@ static int snd_miro_init(struct snd_miro *chip, static unsigned char snd_miro_read(struct snd_miro *chip, unsigned char reg) { - unsigned long flags; unsigned char retval = 0xff; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); outb(chip->password, chip->mc_base + chip->pwd_reg); switch (chip->hardware) { @@ -846,16 +845,13 @@ static unsigned char snd_miro_read(struct snd_miro *chip, dev_err(chip->card->dev, "sorry, no support for %d\n", chip->hardware); } - spin_unlock_irqrestore(&chip->lock, flags); return retval; } static void snd_miro_write(struct snd_miro *chip, unsigned char reg, unsigned char value) { - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); outb(chip->password, chip->mc_base + chip->pwd_reg); switch (chip->hardware) { @@ -875,8 +871,6 @@ static void snd_miro_write(struct snd_miro *chip, unsigned char reg, default: dev_err(chip->card->dev, "sorry, no support for %d\n", chip->hardware); } - - spin_unlock_irqrestore(&chip->lock, flags); } static inline void snd_miro_write_mask(struct snd_miro *chip, @@ -1013,7 +1007,6 @@ static int snd_miro_configure(struct snd_miro *chip) unsigned char dma_bits; unsigned char mpu_port_bits = 0; unsigned char mpu_irq_bits; - unsigned long flags; snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ @@ -1109,9 +1102,9 @@ static int snd_miro_configure(struct snd_miro *chip) } dma_bits |= 0x04; - spin_lock_irqsave(&chip->lock, flags); - outb(irq_bits << 3 | dma_bits, chip->wss_base); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + outb(irq_bits << 3 | dma_bits, chip->wss_base); + } __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 328d043a161938..abaa3ed3ab5c2f 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -228,10 +228,9 @@ static int snd_opti9xx_init(struct snd_opti9xx *chip, static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip, unsigned char reg) { - unsigned long flags; unsigned char retval = 0xff; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); outb(chip->password, chip->mc_base + chip->pwd_reg); switch (chip->hardware) { @@ -265,16 +264,13 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip, dev_err(chip->card->dev, "chip %d not supported\n", chip->hardware); } - spin_unlock_irqrestore(&chip->lock, flags); return retval; } static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, unsigned char value) { - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); outb(chip->password, chip->mc_base + chip->pwd_reg); switch (chip->hardware) { @@ -307,8 +303,6 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, default: dev_err(chip->card->dev, "chip %d not supported\n", chip->hardware); } - - spin_unlock_irqrestore(&chip->lock, flags); } @@ -659,9 +653,6 @@ static int snd_opti9xx_read_check(struct snd_card *card, struct snd_opti9xx *chip) { unsigned char value; -#ifdef OPTi93X - unsigned long flags; -#endif chip->res_mc_base = devm_request_region(card->dev, chip->mc_base, @@ -680,10 +671,10 @@ static int snd_opti9xx_read_check(struct snd_card *card, if (!chip->res_mc_indir) return -EBUSY; - spin_lock_irqsave(&chip->lock, flags); - outb(chip->password, chip->mc_base + chip->pwd_reg); - outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + outb(chip->password, chip->mc_base + chip->pwd_reg); + outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base); + } value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)); snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); From d994b2ba8f74e3c62110f781799144d228ef2a31 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:52 +0200 Subject: [PATCH 0983/1292] ALSA: sb: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-13-tiwai@suse.de --- sound/isa/sb/sb16_csp.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 7034072c80d415..7c5072e4a96f79 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -265,14 +265,10 @@ static int snd_sb_csp_release(struct snd_hwdep * hw, struct file *file) */ static int snd_sb_csp_use(struct snd_sb_csp * p) { - mutex_lock(&p->access_mutex); - if (p->used) { - mutex_unlock(&p->access_mutex); + guard(mutex)(&p->access_mutex); + if (p->used) return -EAGAIN; - } p->used++; - mutex_unlock(&p->access_mutex); - return 0; } @@ -282,10 +278,8 @@ static int snd_sb_csp_use(struct snd_sb_csp * p) */ static int snd_sb_csp_unuse(struct snd_sb_csp * p) { - mutex_lock(&p->access_mutex); + guard(mutex)(&p->access_mutex); p->used--; - mutex_unlock(&p->access_mutex); - return 0; } From 5487fb09fa55a043120f6f56d4df3a4e9b6e5bd7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:53 +0200 Subject: [PATCH 0984/1292] ALSA: sb: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-14-tiwai@suse.de --- sound/isa/sb/sb16.c | 11 +-- sound/isa/sb/sb16_csp.c | 207 +++++++++++++++++---------------------- sound/isa/sb/sb16_main.c | 123 +++++++++-------------- sound/isa/sb/sb8_main.c | 170 +++++++++++++++----------------- sound/isa/sb/sb8_midi.c | 121 +++++++++-------------- sound/isa/sb/sb_common.c | 17 ++-- sound/isa/sb/sb_mixer.c | 61 ++++-------- 7 files changed, 292 insertions(+), 418 deletions(-) diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 75276211733833..208d1942a015a7 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -310,7 +310,6 @@ static int snd_sb16_probe(struct snd_card *card, int dev) #ifdef CONFIG_SND_SB16_CSP struct snd_hwdep *xcsp = NULL; #endif - unsigned long flags; int err; xirq = irq[dev]; @@ -421,11 +420,11 @@ static int snd_sb16_probe(struct snd_card *card, int dev) #endif /* setup Mic AGC */ - spin_lock_irqsave(&chip->mixer_lock, flags); - snd_sbmixer_write(chip, SB_DSP4_MIC_AGC, - (snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) | - (mic_agc[dev] ? 0x00 : 0x01)); - spin_unlock_irqrestore(&chip->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &chip->mixer_lock) { + snd_sbmixer_write(chip, SB_DSP4_MIC_AGC, + (snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) | + (mic_agc[dev] ? 0x00 : 0x01)); + } err = snd_card_register(card); if (err < 0) diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 7c5072e4a96f79..9ad71a9fc18daf 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -301,7 +301,6 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p, __le32 item_type; struct desc_header funcdesc_h; - unsigned long flags; int err; if (copy_from_user(&info, mcode, sizeof(info))) @@ -429,10 +428,9 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p, p->acc_rates = le16_to_cpu(funcdesc_h.flags_rates); /* Decouple CSP from IRQ and DMAREQ lines */ - spin_lock_irqsave(&p->chip->reg_lock, flags); + guard(spinlock_irqsave)(&p->chip->reg_lock); set_mode_register(p->chip, 0xfc); set_mode_register(p->chip, 0x00); - spin_unlock_irqrestore(&p->chip->reg_lock, flags); /* finished loading successfully */ p->running = SNDRV_SB_CSP_ST_LOADED; /* set LOADED flag */ @@ -542,10 +540,8 @@ static int set_mode_register(struct snd_sb *chip, unsigned char mode) static int csp_detect(struct snd_sb *chip, int *version) { unsigned char csp_test1, csp_test2; - unsigned long flags; - int result = -ENODEV; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); set_codec_parameter(chip, 0x00, 0x00); set_mode_register(chip, 0xfc); /* 0xfc = ?? */ @@ -554,23 +550,21 @@ static int csp_detect(struct snd_sb *chip, int *version) set_register(chip, 0x83, ~csp_test1); csp_test2 = read_register(chip, 0x83); if (csp_test2 != (csp_test1 ^ 0xff)) - goto __fail; + return -ENODEV; set_register(chip, 0x83, csp_test1); csp_test2 = read_register(chip, 0x83); if (csp_test2 != csp_test1) - goto __fail; + return -ENODEV; set_mode_register(chip, 0x00); /* 0x00 = ? */ *version = get_version(chip); snd_sbdsp_reset(chip); /* reset DSP after getversion! */ if (*version >= 0x10 && *version <= 0x1f) - result = 0; /* valid version id */ + return 0; /* valid version id */ - __fail: - spin_unlock_irqrestore(&chip->reg_lock, flags); - return result; + return -ENODEV; } /* @@ -608,14 +602,12 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int { int status, i; int err; - int result = -EIO; - unsigned long flags; - spin_lock_irqsave(&p->chip->reg_lock, flags); + guard(spinlock_irqsave)(&p->chip->reg_lock); snd_sbdsp_command(p->chip, 0x01); /* CSP download command */ if (snd_sbdsp_get_byte(p->chip)) { dev_dbg(p->chip->card->dev, "%s: Download command failed\n", __func__); - goto __fail; + return -EIO; } /* Send CSP low byte (size - 1) */ snd_sbdsp_command(p->chip, (unsigned char)(size - 1)); @@ -625,10 +617,10 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int /* load from kernel space */ while (size--) { if (!snd_sbdsp_command(p->chip, *buf++)) - goto __fail; + return -EIO; } if (snd_sbdsp_get_byte(p->chip)) - goto __fail; + return -EIO; if (load_flags & SNDRV_SB_CSP_LOAD_INITBLOCK) { i = 0; @@ -644,7 +636,7 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int dev_dbg(p->chip->card->dev, "%s: Microcode initialization failed\n", __func__); - goto __fail; + return -EIO; } } else { /* @@ -652,24 +644,21 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int * Start CSP chip if no 16bit DMA channel is set - some kind * of autorun or perhaps a bugfix? */ - spin_lock(&p->chip->mixer_lock); - status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP); - spin_unlock(&p->chip->mixer_lock); + scoped_guard(spinlock, &p->chip->mixer_lock) { + status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP); + } if (!(status & (SB_DMASETUP_DMA7 | SB_DMASETUP_DMA6 | SB_DMASETUP_DMA5))) { err = (set_codec_parameter(p->chip, 0xaa, 0x00) || set_codec_parameter(p->chip, 0xff, 0x00)); snd_sbdsp_reset(p->chip); /* really! */ if (err) - goto __fail; + return -EIO; set_mode_register(p->chip, 0xc0); /* c0 = STOP */ set_mode_register(p->chip, 0x70); /* 70 = RUN */ } } - result = 0; - __fail: - spin_unlock_irqrestore(&p->chip->reg_lock, flags); - return result; + return 0; } static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags) @@ -716,7 +705,6 @@ static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags) */ static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode) { - unsigned long flags; int err = 0; /* if CSP is running or manually loaded then exit */ @@ -757,10 +745,9 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, default: /* Decouple CSP from IRQ and DMAREQ lines */ if (p->running & SNDRV_SB_CSP_ST_AUTO) { - spin_lock_irqsave(&p->chip->reg_lock, flags); + guard(spinlock_irqsave)(&p->chip->reg_lock); set_mode_register(p->chip, 0xfc); set_mode_register(p->chip, 0x00); - spin_unlock_irqrestore(&p->chip->reg_lock, flags); p->running = 0; /* clear autoloaded flag */ } return -EINVAL; @@ -792,7 +779,6 @@ static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channel unsigned char s_type; /* sample type */ unsigned char mixL, mixR; int result = -EIO; - unsigned long flags; if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) { dev_dbg(dev, "%s: Microcode not loaded\n", __func__); @@ -812,55 +798,54 @@ static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channel } /* Mute PCM volume */ - spin_lock_irqsave(&p->chip->mixer_lock, flags); - mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV); - mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); - spin_unlock_irqrestore(&p->chip->mixer_lock, flags); - - spin_lock(&p->chip->reg_lock); - set_mode_register(p->chip, 0xc0); /* c0 = STOP */ - set_mode_register(p->chip, 0x70); /* 70 = RUN */ - - s_type = 0x00; - if (channels == SNDRV_SB_CSP_MONO) - s_type = 0x11; /* 000n 000n (n = 1 if mono) */ - if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT) - s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */ - - if (set_codec_parameter(p->chip, 0x81, s_type)) { - dev_dbg(dev, "%s: Set sample type command failed\n", __func__); - goto __fail; - } - if (set_codec_parameter(p->chip, 0x80, 0x00)) { - dev_dbg(dev, "%s: Codec start command failed\n", __func__); - goto __fail; + scoped_guard(spinlock_irqsave, &p->chip->mixer_lock) { + mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV); + mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); } - p->run_width = sample_width; - p->run_channels = channels; - p->running |= SNDRV_SB_CSP_ST_RUNNING; + scoped_guard(spinlock, &p->chip->reg_lock) { + set_mode_register(p->chip, 0xc0); /* c0 = STOP */ + set_mode_register(p->chip, 0x70); /* 70 = RUN */ - if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) { - set_codec_parameter(p->chip, 0xe0, 0x01); - /* enable QSound decoder */ - set_codec_parameter(p->chip, 0x00, 0xff); - set_codec_parameter(p->chip, 0x01, 0xff); - p->running |= SNDRV_SB_CSP_ST_QSOUND; - /* set QSound startup value */ - snd_sb_csp_qsound_transfer(p); - } - result = 0; + s_type = 0x00; + if (channels == SNDRV_SB_CSP_MONO) + s_type = 0x11; /* 000n 000n (n = 1 if mono) */ + if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT) + s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */ - __fail: - spin_unlock(&p->chip->reg_lock); + if (set_codec_parameter(p->chip, 0x81, s_type)) { + dev_dbg(dev, "%s: Set sample type command failed\n", __func__); + break; + } + if (set_codec_parameter(p->chip, 0x80, 0x00)) { + dev_dbg(dev, "%s: Codec start command failed\n", __func__); + break; + } + p->run_width = sample_width; + p->run_channels = channels; + + p->running |= SNDRV_SB_CSP_ST_RUNNING; + + if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) { + set_codec_parameter(p->chip, 0xe0, 0x01); + /* enable QSound decoder */ + set_codec_parameter(p->chip, 0x00, 0xff); + set_codec_parameter(p->chip, 0x01, 0xff); + p->running |= SNDRV_SB_CSP_ST_QSOUND; + /* set QSound startup value */ + snd_sb_csp_qsound_transfer(p); + } + result = 0; + } /* restore PCM volume */ - spin_lock_irqsave(&p->chip->mixer_lock, flags); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); - spin_unlock_irqrestore(&p->chip->mixer_lock, flags); + if (result < 0) { + guard(spinlock_irqsave)(&p->chip->mixer_lock); + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); + } return result; } @@ -872,36 +857,35 @@ static int snd_sb_csp_stop(struct snd_sb_csp * p) { int result; unsigned char mixL, mixR; - unsigned long flags; if (!(p->running & SNDRV_SB_CSP_ST_RUNNING)) return 0; /* Mute PCM volume */ - spin_lock_irqsave(&p->chip->mixer_lock, flags); - mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV); - mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); - spin_unlock_irqrestore(&p->chip->mixer_lock, flags); - - spin_lock(&p->chip->reg_lock); - if (p->running & SNDRV_SB_CSP_ST_QSOUND) { - set_codec_parameter(p->chip, 0xe0, 0x01); - /* disable QSound decoder */ - set_codec_parameter(p->chip, 0x00, 0x00); - set_codec_parameter(p->chip, 0x01, 0x00); + scoped_guard(spinlock_irqsave, &p->chip->mixer_lock) { + mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV); + mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); + } - p->running &= ~SNDRV_SB_CSP_ST_QSOUND; + scoped_guard(spinlock, &p->chip->reg_lock) { + if (p->running & SNDRV_SB_CSP_ST_QSOUND) { + set_codec_parameter(p->chip, 0xe0, 0x01); + /* disable QSound decoder */ + set_codec_parameter(p->chip, 0x00, 0x00); + set_codec_parameter(p->chip, 0x01, 0x00); + + p->running &= ~SNDRV_SB_CSP_ST_QSOUND; + } + result = set_mode_register(p->chip, 0xc0); /* c0 = STOP */ } - result = set_mode_register(p->chip, 0xc0); /* c0 = STOP */ - spin_unlock(&p->chip->reg_lock); /* restore PCM volume */ - spin_lock_irqsave(&p->chip->mixer_lock, flags); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); - snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); - spin_unlock_irqrestore(&p->chip->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &p->chip->mixer_lock) { + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); + snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); + } if (!(result)) p->running &= ~(SNDRV_SB_CSP_ST_PAUSED | SNDRV_SB_CSP_ST_RUNNING); @@ -914,14 +898,13 @@ static int snd_sb_csp_stop(struct snd_sb_csp * p) static int snd_sb_csp_pause(struct snd_sb_csp * p) { int result; - unsigned long flags; if (!(p->running & SNDRV_SB_CSP_ST_RUNNING)) return -EBUSY; - spin_lock_irqsave(&p->chip->reg_lock, flags); - result = set_codec_parameter(p->chip, 0x80, 0xff); - spin_unlock_irqrestore(&p->chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &p->chip->reg_lock) { + result = set_codec_parameter(p->chip, 0x80, 0xff); + } if (!(result)) p->running |= SNDRV_SB_CSP_ST_PAUSED; @@ -934,14 +917,13 @@ static int snd_sb_csp_pause(struct snd_sb_csp * p) static int snd_sb_csp_restart(struct snd_sb_csp * p) { int result; - unsigned long flags; if (!(p->running & SNDRV_SB_CSP_ST_PAUSED)) return -EBUSY; - spin_lock_irqsave(&p->chip->reg_lock, flags); - result = set_codec_parameter(p->chip, 0x80, 0x00); - spin_unlock_irqrestore(&p->chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &p->chip->reg_lock) { + result = set_codec_parameter(p->chip, 0x80, 0x00); + } if (!(result)) p->running &= ~SNDRV_SB_CSP_ST_PAUSED; @@ -967,15 +949,13 @@ static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ct static int snd_sb_qsound_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned char nval; nval = ucontrol->value.integer.value[0] & 0x01; - spin_lock_irqsave(&p->q_lock, flags); + guard(spinlock_irqsave)(&p->q_lock); change = p->q_enabled != nval; p->q_enabled = nval; - spin_unlock_irqrestore(&p->q_lock, flags); return change; } @@ -991,19 +971,16 @@ static int snd_sb_qsound_space_info(struct snd_kcontrol *kcontrol, struct snd_ct static int snd_sb_qsound_space_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&p->q_lock, flags); + guard(spinlock_irqsave)(&p->q_lock); ucontrol->value.integer.value[0] = p->qpos_left; ucontrol->value.integer.value[1] = p->qpos_right; - spin_unlock_irqrestore(&p->q_lock, flags); return 0; } static int snd_sb_qsound_space_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned char nval1, nval2; @@ -1013,12 +990,11 @@ static int snd_sb_qsound_space_put(struct snd_kcontrol *kcontrol, struct snd_ctl nval2 = ucontrol->value.integer.value[1]; if (nval2 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT) nval2 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT; - spin_lock_irqsave(&p->q_lock, flags); + guard(spinlock_irqsave)(&p->q_lock); change = p->qpos_left != nval1 || p->qpos_right != nval2; p->qpos_left = nval1; p->qpos_right = nval2; p->qpos_changed = change; - spin_unlock_irqrestore(&p->q_lock, flags); return change; } @@ -1074,7 +1050,6 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p) static void snd_sb_qsound_destroy(struct snd_sb_csp * p) { struct snd_card *card; - unsigned long flags; if (snd_BUG_ON(!p)) return; @@ -1087,9 +1062,8 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p) p->qsound_space = NULL; /* cancel pending transfer of QSound parameters */ - spin_lock_irqsave (&p->q_lock, flags); + guard(spinlock_irqsave)(&p->q_lock); p->qpos_changed = 0; - spin_unlock_irqrestore (&p->q_lock, flags); } /* @@ -1100,7 +1074,7 @@ static int snd_sb_csp_qsound_transfer(struct snd_sb_csp * p) { int err = -ENXIO; - spin_lock(&p->q_lock); + guard(spinlock)(&p->q_lock); if (p->running & SNDRV_SB_CSP_ST_QSOUND) { set_codec_parameter(p->chip, 0xe0, 0x01); /* left channel */ @@ -1112,7 +1086,6 @@ static int snd_sb_csp_qsound_transfer(struct snd_sb_csp * p) err = 0; } p->qpos_changed = 0; - spin_unlock(&p->q_lock); return err; } diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 5a083eecaa6b99..4d64db4f58523d 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -130,9 +130,8 @@ static void snd_sb16_csp_update(struct snd_sb *chip) struct snd_sb_csp *csp = chip->csp; if (csp->qpos_changed) { - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); csp->ops.csp_qsound_transfer (csp); - spin_unlock(&chip->reg_lock); } } } @@ -213,9 +212,7 @@ static void snd_sb16_setup_rate(struct snd_sb *chip, unsigned short rate, int channel) { - unsigned long flags; - - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (chip->mode & (channel == SNDRV_PCM_STREAM_PLAYBACK ? SB_MODE_PLAYBACK_16 : SB_MODE_CAPTURE_16)) snd_sb_ack_16bit(chip); else @@ -229,12 +226,10 @@ static void snd_sb16_setup_rate(struct snd_sb *chip, snd_sbdsp_command(chip, rate >> 8); snd_sbdsp_command(chip, rate & 0xff); } - spin_unlock_irqrestore(&chip->reg_lock, flags); } static int snd_sb16_playback_prepare(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned char format; @@ -253,7 +248,7 @@ static int snd_sb16_playback_prepare(struct snd_pcm_substream *substream) snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); count = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (chip->mode & SB_MODE_PLAYBACK_16) { count >>= 1; count--; @@ -270,7 +265,6 @@ static int snd_sb16_playback_prepare(struct snd_pcm_substream *substream) snd_sbdsp_command(chip, count >> 8); snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -278,9 +272,8 @@ static int snd_sb16_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_sb *chip = snd_pcm_substream_chip(substream); - int result = 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -296,15 +289,13 @@ static int snd_sb16_playback_trigger(struct snd_pcm_substream *substream, chip->mode &= ~SB_RATE_LOCK_PLAYBACK; break; default: - result = -EINVAL; + return -EINVAL; } - spin_unlock(&chip->reg_lock); - return result; + return 0; } static int snd_sb16_capture_prepare(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned char format; @@ -322,7 +313,7 @@ static int snd_sb16_capture_prepare(struct snd_pcm_substream *substream) snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); count = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (chip->mode & SB_MODE_CAPTURE_16) { count >>= 1; count--; @@ -339,7 +330,6 @@ static int snd_sb16_capture_prepare(struct snd_pcm_substream *substream) snd_sbdsp_command(chip, count >> 8); snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -347,9 +337,8 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_sb *chip = snd_pcm_substream_chip(substream); - int result = 0; - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -365,10 +354,9 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream, chip->mode &= ~SB_RATE_LOCK_CAPTURE; break; default: - result = -EINVAL; + return -EINVAL; } - spin_unlock(&chip->reg_lock); - return result; + return 0; } irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id) @@ -377,9 +365,9 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id) unsigned char status; int ok; - spin_lock(&chip->mixer_lock); - status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); - spin_unlock(&chip->mixer_lock); + scoped_guard(spinlock, &chip->mixer_lock) { + status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); + } if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback) chip->rmidi_callback(irq, chip->rmidi->private_data); if (status & SB_IRQTYPE_8BIT) { @@ -393,11 +381,11 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id) snd_pcm_period_elapsed(chip->capture_substream); ok++; } - spin_lock(&chip->reg_lock); - if (!ok) - snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); - snd_sb_ack_8bit(chip); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + if (!ok) + snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); + snd_sb_ack_8bit(chip); + } } if (status & SB_IRQTYPE_16BIT) { ok = 0; @@ -410,11 +398,11 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id) snd_pcm_period_elapsed(chip->capture_substream); ok++; } - spin_lock(&chip->reg_lock); - if (!ok) - snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); - snd_sb_ack_16bit(chip); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + if (!ok) + snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); + snd_sb_ack_16bit(chip); + } } return IRQ_HANDLED; } @@ -491,15 +479,12 @@ static const struct snd_pcm_hardware snd_sb16_capture = static int snd_sb16_playback_open(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - spin_lock_irqsave(&chip->open_lock, flags); - if (chip->mode & SB_MODE_PLAYBACK) { - spin_unlock_irqrestore(&chip->open_lock, flags); + guard(spinlock_irqsave)(&chip->open_lock); + if (chip->mode & SB_MODE_PLAYBACK) return -EAGAIN; - } runtime->hw = snd_sb16_playback; /* skip if 16 bit DMA was reserved for capture */ @@ -533,7 +518,6 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream) runtime->hw.period_bytes_max = 64 * 1024; goto __open_ok; } - spin_unlock_irqrestore(&chip->open_lock, flags); return -EAGAIN; __open_ok: @@ -547,34 +531,28 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream) if (chip->mode & SB_RATE_LOCK) runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate; chip->playback_substream = substream; - spin_unlock_irqrestore(&chip->open_lock, flags); return 0; } static int snd_sb16_playback_close(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); snd_sb16_csp_playback_close(chip); - spin_lock_irqsave(&chip->open_lock, flags); + guard(spinlock_irqsave)(&chip->open_lock); chip->playback_substream = NULL; chip->mode &= ~SB_MODE_PLAYBACK; - spin_unlock_irqrestore(&chip->open_lock, flags); return 0; } static int snd_sb16_capture_open(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - spin_lock_irqsave(&chip->open_lock, flags); - if (chip->mode & SB_MODE_CAPTURE) { - spin_unlock_irqrestore(&chip->open_lock, flags); + guard(spinlock_irqsave)(&chip->open_lock); + if (chip->mode & SB_MODE_CAPTURE) return -EAGAIN; - } runtime->hw = snd_sb16_capture; /* skip if 16 bit DMA was reserved for playback */ @@ -608,7 +586,6 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream) runtime->hw.period_bytes_max = 64 * 1024; goto __open_ok; } - spin_unlock_irqrestore(&chip->open_lock, flags); return -EAGAIN; __open_ok: @@ -622,20 +599,17 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream) if (chip->mode & SB_RATE_LOCK) runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate; chip->capture_substream = substream; - spin_unlock_irqrestore(&chip->open_lock, flags); return 0; } static int snd_sb16_capture_close(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); snd_sb16_csp_capture_close(chip); - spin_lock_irqsave(&chip->open_lock, flags); + guard(spinlock_irqsave)(&chip->open_lock); chip->capture_substream = NULL; chip->mode &= ~SB_MODE_CAPTURE; - spin_unlock_irqrestore(&chip->open_lock, flags); return 0; } @@ -688,18 +662,15 @@ static int snd_sb16_dma_control_info(struct snd_kcontrol *kcontrol, struct snd_c static int snd_sb16_dma_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.enumerated.item[0] = snd_sb16_get_dma_mode(chip); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static int snd_sb16_dma_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned char nval, oval; int change; @@ -709,11 +680,11 @@ static int snd_sb16_dma_control_put(struct snd_kcontrol *kcontrol, struct snd_ct nval = ucontrol->value.enumerated.item[0]; if (nval > 2) return -EINVAL; - spin_lock_irqsave(&chip->reg_lock, flags); - oval = snd_sb16_get_dma_mode(chip); - change = nval != oval; - snd_sb16_set_dma_mode(chip, nval); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + oval = snd_sb16_get_dma_mode(chip); + change = nval != oval; + snd_sb16_set_dma_mode(chip, nval); + } if (change) { snd_dma_disable(chip->dma8); snd_dma_disable(chip->dma16); @@ -735,14 +706,13 @@ static const struct snd_kcontrol_new snd_sb16_dma_control = { int snd_sb16dsp_configure(struct snd_sb * chip) { - unsigned long flags; unsigned char irqreg = 0, dmareg = 0, mpureg; unsigned char realirq, realdma, realmpureg; /* note: mpu register should be present only on SB16 Vibra soundcards */ - spin_lock_irqsave(&chip->mixer_lock, flags); - mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06; - spin_unlock_irqrestore(&chip->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &chip->mixer_lock) { + mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06; + } switch (chip->irq) { case 2: case 9: @@ -800,18 +770,17 @@ int snd_sb16dsp_configure(struct snd_sb * chip) default: mpureg |= 0x02; /* disable MPU */ } - spin_lock_irqsave(&chip->mixer_lock, flags); - snd_sbmixer_write(chip, SB_DSP4_IRQSETUP, irqreg); - realirq = snd_sbmixer_read(chip, SB_DSP4_IRQSETUP); + scoped_guard(spinlock_irqsave, &chip->mixer_lock) { + snd_sbmixer_write(chip, SB_DSP4_IRQSETUP, irqreg); + realirq = snd_sbmixer_read(chip, SB_DSP4_IRQSETUP); - snd_sbmixer_write(chip, SB_DSP4_DMASETUP, dmareg); - realdma = snd_sbmixer_read(chip, SB_DSP4_DMASETUP); + snd_sbmixer_write(chip, SB_DSP4_DMASETUP, dmareg); + realdma = snd_sbmixer_read(chip, SB_DSP4_DMASETUP); - snd_sbmixer_write(chip, SB_DSP4_MPUSETUP, mpureg); - realmpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP); - - spin_unlock_irqrestore(&chip->mixer_lock, flags); + snd_sbmixer_write(chip, SB_DSP4_MPUSETUP, mpureg); + realmpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP); + } if ((~realirq) & irqreg || (~realdma) & dmareg) { dev_err(chip->card->dev, "SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n", diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 2ed176a5a57436..a4b5725255cfe4 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -89,7 +89,6 @@ static int snd_sb8_hw_constraint_channels_rate(struct snd_pcm_hw_params *params, static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int mixreg, rate, size, count; @@ -142,48 +141,48 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) } size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); - if (chip->hardware == SB_HW_JAZZ16) - snd_sbdsp_command(chip, format); - else if (stereo) { - /* set playback stereo mode */ - spin_lock(&chip->mixer_lock); - mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); - snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02); - spin_unlock(&chip->mixer_lock); - - /* Soundblaster hardware programming reference guide, 3-23 */ - snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); - runtime->dma_area[0] = 0x80; - snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); - /* force interrupt */ - snd_sbdsp_command(chip, SB_DSP_OUTPUT); - snd_sbdsp_command(chip, 0); - snd_sbdsp_command(chip, 0); - } - snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); - if (stereo) { - snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); - spin_lock(&chip->mixer_lock); - /* save output filter status and turn it off */ - mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT); - snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20); - spin_unlock(&chip->mixer_lock); - /* just use force_mode16 for temporary storate... */ - chip->force_mode16 = mixreg; - } else { - snd_sbdsp_command(chip, 256 - runtime->rate_den); - } - if (chip->playback_format != SB_DSP_OUTPUT) { - if (chip->mode & SB_MODE_PLAYBACK_16) - count /= 2; - count--; - snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); - snd_sbdsp_command(chip, count & 0xff); - snd_sbdsp_command(chip, count >> 8); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); + if (chip->hardware == SB_HW_JAZZ16) + snd_sbdsp_command(chip, format); + else if (stereo) { + /* set playback stereo mode */ + scoped_guard(spinlock, &chip->mixer_lock) { + mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); + snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02); + } + + /* Soundblaster hardware programming reference guide, 3-23 */ + snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); + runtime->dma_area[0] = 0x80; + snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); + /* force interrupt */ + snd_sbdsp_command(chip, SB_DSP_OUTPUT); + snd_sbdsp_command(chip, 0); + snd_sbdsp_command(chip, 0); + } + snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); + if (stereo) { + snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); + scoped_guard(spinlock, &chip->mixer_lock) { + /* save output filter status and turn it off */ + mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT); + snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20); + } + /* just use force_mode16 for temporary storate... */ + chip->force_mode16 = mixreg; + } else { + snd_sbdsp_command(chip, 256 - runtime->rate_den); + } + if (chip->playback_format != SB_DSP_OUTPUT) { + if (chip->mode & SB_MODE_PLAYBACK_16) + count /= 2; + count--; + snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); + snd_sbdsp_command(chip, count & 0xff); + snd_sbdsp_command(chip, count >> 8); + } } - spin_unlock_irqrestore(&chip->reg_lock, flags); snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); return 0; @@ -192,11 +191,10 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, int cmd) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); unsigned int count; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_sbdsp_command(chip, chip->playback_format); @@ -211,23 +209,20 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_sbdsp_reset(chip); if (runtime->channels > 1) { - spin_lock(&chip->mixer_lock); + guard(spinlock)(&chip->mixer_lock); /* restore output filter and set hardware to mono mode */ snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02); - spin_unlock(&chip->mixer_lock); } } else { snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); } snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int mixreg, rate, size, count; @@ -281,34 +276,34 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) } size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); - if (chip->hardware == SB_HW_JAZZ16) - snd_sbdsp_command(chip, format); - else if (stereo) - snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); - snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); - if (stereo) { - snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); - spin_lock(&chip->mixer_lock); - /* save input filter status and turn it off */ - mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT); - snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20); - spin_unlock(&chip->mixer_lock); - /* just use force_mode16 for temporary storate... */ - chip->force_mode16 = mixreg; - } else { - snd_sbdsp_command(chip, 256 - runtime->rate_den); - } - if (chip->capture_format != SB_DSP_INPUT) { - if (chip->mode & SB_MODE_PLAYBACK_16) - count /= 2; - count--; - snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); - snd_sbdsp_command(chip, count & 0xff); - snd_sbdsp_command(chip, count >> 8); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); + if (chip->hardware == SB_HW_JAZZ16) + snd_sbdsp_command(chip, format); + else if (stereo) + snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); + snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); + if (stereo) { + snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); + scoped_guard(spinlock, &chip->mixer_lock) { + /* save input filter status and turn it off */ + mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT); + snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20); + } + /* just use force_mode16 for temporary storate... */ + chip->force_mode16 = mixreg; + } else { + snd_sbdsp_command(chip, 256 - runtime->rate_den); + } + if (chip->capture_format != SB_DSP_INPUT) { + if (chip->mode & SB_MODE_PLAYBACK_16) + count /= 2; + count--; + snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); + snd_sbdsp_command(chip, count & 0xff); + snd_sbdsp_command(chip, count >> 8); + } } - spin_unlock_irqrestore(&chip->reg_lock, flags); snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); return 0; @@ -317,11 +312,10 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, int cmd) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); unsigned int count; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_sbdsp_command(chip, chip->capture_format); @@ -337,9 +331,9 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, snd_sbdsp_reset(chip); if (runtime->channels > 1) { /* restore input filter status */ - spin_lock(&chip->mixer_lock); - snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16); - spin_unlock(&chip->mixer_lock); + scoped_guard(spinlock, &chip->mixer_lock) { + snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16); + } /* set hardware to mono mode */ snd_sbdsp_command(chip, SB_DSP_MONO_8BIT); } @@ -348,7 +342,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, } snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -464,15 +457,12 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) { struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - spin_lock_irqsave(&chip->open_lock, flags); - if (chip->open) { - spin_unlock_irqrestore(&chip->open_lock, flags); - return -EAGAIN; + scoped_guard(spinlock_irqsave, &chip->open_lock) { + if (chip->open) + return -EAGAIN; + chip->open |= SB_OPEN_PCM; } - chip->open |= SB_OPEN_PCM; - spin_unlock_irqrestore(&chip->open_lock, flags); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { chip->playback_substream = substream; runtime->hw = snd_sb8_playback; @@ -525,18 +515,16 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) static int snd_sb8_close(struct snd_pcm_substream *substream) { - unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); chip->playback_substream = NULL; chip->capture_substream = NULL; - spin_lock_irqsave(&chip->open_lock, flags); + guard(spinlock_irqsave)(&chip->open_lock); chip->open &= ~SB_OPEN_PCM; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) chip->mode &= ~SB_MODE_PLAYBACK; else chip->mode &= ~SB_MODE_CAPTURE; - spin_unlock_irqrestore(&chip->open_lock, flags); return 0; } diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index 637079a2f02a4d..1d41f2470697b2 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -35,7 +35,7 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip) return IRQ_NONE; } - spin_lock(&chip->midi_input_lock); + guard(spinlock)(&chip->midi_input_lock); while (max-- > 0) { if (inb(SBP(chip, DATA_AVAIL)) & 0x80) { byte = inb(SBP(chip, READ)); @@ -44,108 +44,90 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip) } } } - spin_unlock(&chip->midi_input_lock); return IRQ_HANDLED; } static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_sb *chip; unsigned int valid_open_flags; chip = substream->rmidi->private_data; valid_open_flags = chip->hardware >= SB_HW_20 ? SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER : 0; - spin_lock_irqsave(&chip->open_lock, flags); - if (chip->open & ~valid_open_flags) { - spin_unlock_irqrestore(&chip->open_lock, flags); - return -EAGAIN; - } - chip->open |= SB_OPEN_MIDI_INPUT; - chip->midi_substream_input = substream; - if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) { - spin_unlock_irqrestore(&chip->open_lock, flags); - snd_sbdsp_reset(chip); /* reset DSP */ - if (chip->hardware >= SB_HW_20) - snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ); - } else { - spin_unlock_irqrestore(&chip->open_lock, flags); + scoped_guard(spinlock_irqsave, &chip->open_lock) { + if (chip->open & ~valid_open_flags) + return -EAGAIN; + chip->open |= SB_OPEN_MIDI_INPUT; + chip->midi_substream_input = substream; + if (chip->open & SB_OPEN_MIDI_OUTPUT) + return 0; } + snd_sbdsp_reset(chip); /* reset DSP */ + if (chip->hardware >= SB_HW_20) + snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ); return 0; } static int snd_sb8dsp_midi_output_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_sb *chip; unsigned int valid_open_flags; chip = substream->rmidi->private_data; valid_open_flags = chip->hardware >= SB_HW_20 ? SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER : 0; - spin_lock_irqsave(&chip->open_lock, flags); - if (chip->open & ~valid_open_flags) { - spin_unlock_irqrestore(&chip->open_lock, flags); - return -EAGAIN; - } - chip->open |= SB_OPEN_MIDI_OUTPUT; - chip->midi_substream_output = substream; - if (!(chip->open & SB_OPEN_MIDI_INPUT)) { - spin_unlock_irqrestore(&chip->open_lock, flags); - snd_sbdsp_reset(chip); /* reset DSP */ - if (chip->hardware >= SB_HW_20) - snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ); - } else { - spin_unlock_irqrestore(&chip->open_lock, flags); + scoped_guard(spinlock_irqsave, &chip->open_lock) { + if (chip->open & ~valid_open_flags) + return -EAGAIN; + chip->open |= SB_OPEN_MIDI_OUTPUT; + chip->midi_substream_output = substream; + if (chip->open & SB_OPEN_MIDI_INPUT) + return 0; } + snd_sbdsp_reset(chip); /* reset DSP */ + if (chip->hardware >= SB_HW_20) + snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ); return 0; } static int snd_sb8dsp_midi_input_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_sb *chip; chip = substream->rmidi->private_data; - spin_lock_irqsave(&chip->open_lock, flags); - chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER); - chip->midi_substream_input = NULL; - if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) { - spin_unlock_irqrestore(&chip->open_lock, flags); - snd_sbdsp_reset(chip); /* reset DSP */ - } else { - spin_unlock_irqrestore(&chip->open_lock, flags); + scoped_guard(spinlock_irqsave, &chip->open_lock) { + chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER); + chip->midi_substream_input = NULL; + if (chip->open & SB_OPEN_MIDI_OUTPUT) + return 0; } + snd_sbdsp_reset(chip); /* reset DSP */ return 0; } static int snd_sb8dsp_midi_output_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_sb *chip; chip = substream->rmidi->private_data; timer_delete_sync(&chip->midi_timer); - spin_lock_irqsave(&chip->open_lock, flags); - chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER); - chip->midi_substream_output = NULL; - if (!(chip->open & SB_OPEN_MIDI_INPUT)) { - spin_unlock_irqrestore(&chip->open_lock, flags); - snd_sbdsp_reset(chip); /* reset DSP */ - } else { - spin_unlock_irqrestore(&chip->open_lock, flags); + scoped_guard(spinlock_irqsave, &chip->open_lock) { + chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER); + chip->midi_substream_output = NULL; + if (chip->open & SB_OPEN_MIDI_INPUT) + return 0; } + snd_sbdsp_reset(chip); /* reset DSP */ return 0; } static void snd_sb8dsp_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_sb *chip; chip = substream->rmidi->private_data; - spin_lock_irqsave(&chip->open_lock, flags); + guard(spinlock_irqsave)(&chip->open_lock); if (up) { if (!(chip->open & SB_OPEN_MIDI_INPUT_TRIGGER)) { if (chip->hardware < SB_HW_20) @@ -159,12 +141,10 @@ static void snd_sb8dsp_midi_input_trigger(struct snd_rawmidi_substream *substrea chip->open &= ~SB_OPEN_MIDI_INPUT_TRIGGER; } } - spin_unlock_irqrestore(&chip->open_lock, flags); } static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_sb *chip; char byte; int max = 32; @@ -172,11 +152,10 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream /* how big is Tx FIFO? */ chip = substream->rmidi->private_data; while (max-- > 0) { - spin_lock_irqsave(&chip->open_lock, flags); + guard(spinlock_irqsave)(&chip->open_lock); if (snd_rawmidi_transmit_peek(substream, &byte, 1) != 1) { chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER; timer_delete(&chip->midi_timer); - spin_unlock_irqrestore(&chip->open_lock, flags); break; } if (chip->hardware >= SB_HW_20) { @@ -185,7 +164,6 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream ; if (timeout == 0) { /* Tx FIFO full - try again later */ - spin_unlock_irqrestore(&chip->open_lock, flags); break; } outb(byte, SBP(chip, WRITE)); @@ -194,7 +172,6 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream snd_sbdsp_command(chip, byte); } snd_rawmidi_transmit_ack(substream, 1); - spin_unlock_irqrestore(&chip->open_lock, flags); } } @@ -202,32 +179,30 @@ static void snd_sb8dsp_midi_output_timer(struct timer_list *t) { struct snd_sb *chip = timer_container_of(chip, t, midi_timer); struct snd_rawmidi_substream *substream = chip->midi_substream_output; - unsigned long flags; - spin_lock_irqsave(&chip->open_lock, flags); - mod_timer(&chip->midi_timer, 1 + jiffies); - spin_unlock_irqrestore(&chip->open_lock, flags); + scoped_guard(spinlock_irqsave, &chip->open_lock) { + mod_timer(&chip->midi_timer, 1 + jiffies); + } snd_sb8dsp_midi_output_write(substream); } static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_sb *chip; chip = substream->rmidi->private_data; - spin_lock_irqsave(&chip->open_lock, flags); - if (up) { - if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) { - mod_timer(&chip->midi_timer, 1 + jiffies); - chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER; - } - } else { - if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) { - chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER; + scoped_guard(spinlock_irqsave, &chip->open_lock) { + if (up) { + if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) { + mod_timer(&chip->midi_timer, 1 + jiffies); + chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER; + } + } else { + if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) { + chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER; + } } } - spin_unlock_irqrestore(&chip->open_lock, flags); if (up) snd_sb8dsp_midi_output_write(substream); diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index a4d5bf3d145f48..f2848559e6da23 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -94,23 +94,18 @@ static int snd_sbdsp_probe(struct snd_sb * chip) int version; int major, minor; char *str; - unsigned long flags; /* * initialization sequence */ - spin_lock_irqsave(&chip->reg_lock, flags); - if (snd_sbdsp_reset(chip) < 0) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - return -ENODEV; - } - version = snd_sbdsp_version(chip); - if (version < 0) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - return -ENODEV; + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + if (snd_sbdsp_reset(chip) < 0) + return -ENODEV; + version = snd_sbdsp_version(chip); + if (version < 0) + return -ENODEV; } - spin_unlock_irqrestore(&chip->reg_lock, flags); major = version >> 8; minor = version & 0xff; dev_dbg(chip->card->dev, "SB [0x%lx]: DSP chip found, version = %i.%i\n", diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index b2709ed134b4a4..95173b18cee3e2 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -57,15 +57,13 @@ static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 16) & 0xff; int mask = (kcontrol->private_value >> 24) & 0xff; unsigned char val; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); val = (snd_sbmixer_read(sb, reg) >> shift) & mask; - spin_unlock_irqrestore(&sb->mixer_lock, flags); ucontrol->value.integer.value[0] = val; return 0; } @@ -73,7 +71,6 @@ static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 16) & 0x07; int mask = (kcontrol->private_value >> 24) & 0xff; @@ -81,13 +78,12 @@ static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ unsigned char val, oval; val = (ucontrol->value.integer.value[0] & mask) << shift; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); oval = snd_sbmixer_read(sb, reg); val = (oval & ~(mask << shift)) | val; change = val != oval; if (change) snd_sbmixer_write(sb, reg, val); - spin_unlock_irqrestore(&sb->mixer_lock, flags); return change; } @@ -109,7 +105,6 @@ static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int left_shift = (kcontrol->private_value >> 16) & 0x07; @@ -117,10 +112,9 @@ static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ int mask = (kcontrol->private_value >> 24) & 0xff; unsigned char left, right; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask; right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask; - spin_unlock_irqrestore(&sb->mixer_lock, flags); ucontrol->value.integer.value[0] = left; ucontrol->value.integer.value[1] = right; return 0; @@ -129,7 +123,6 @@ static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int left_shift = (kcontrol->private_value >> 16) & 0x07; @@ -140,7 +133,7 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ left = (ucontrol->value.integer.value[0] & mask) << left_shift; right = (ucontrol->value.integer.value[1] & mask) << right_shift; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); if (left_reg == right_reg) { oleft = snd_sbmixer_read(sb, left_reg); left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right; @@ -158,7 +151,6 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ snd_sbmixer_write(sb, right_reg, right); } } - spin_unlock_irqrestore(&sb->mixer_lock, flags); return change; } @@ -178,12 +170,11 @@ static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ct static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned char oval; - spin_lock_irqsave(&sb->mixer_lock, flags); - oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); - spin_unlock_irqrestore(&sb->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &sb->mixer_lock) { + oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); + } switch (oval & 0x07) { case SB_DT019X_CAP_CD: ucontrol->value.enumerated.item[0] = 0; @@ -214,7 +205,6 @@ static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned char nval, oval; @@ -239,12 +229,11 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl default: nval = SB_DT019X_CAP_MAIN; } - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); change = nval != oval; if (change) snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval); - spin_unlock_irqrestore(&sb->mixer_lock, flags); return change; } @@ -266,12 +255,10 @@ static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned char oval; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); - spin_unlock_irqrestore(&sb->mixer_lock, flags); oval >>= 6; if (oval > 2) oval = 2; @@ -284,13 +271,12 @@ static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned char nval, oval; if (ucontrol->value.enumerated.item[0] > 2) return -EINVAL; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); nval = (oval & ~(3 << 6)) @@ -298,7 +284,6 @@ static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol, change = nval != oval; if (change) snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval); - spin_unlock_irqrestore(&sb->mixer_lock, flags); return change; } @@ -319,12 +304,10 @@ static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned char oval; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); - spin_unlock_irqrestore(&sb->mixer_lock, flags); switch ((oval >> 0x01) & 0x03) { case SB_DSP_MIXS_CD: ucontrol->value.enumerated.item[0] = 1; @@ -342,7 +325,6 @@ static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned char nval, oval; @@ -359,13 +341,12 @@ static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_el nval = SB_DSP_MIXS_MIC; } nval <<= 1; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); nval |= oval & ~0x06; change = nval != oval; if (change) snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval); - spin_unlock_irqrestore(&sb->mixer_lock, flags); return change; } @@ -385,17 +366,15 @@ static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg1 = kcontrol->private_value & 0xff; int reg2 = (kcontrol->private_value >> 8) & 0xff; int left_shift = (kcontrol->private_value >> 16) & 0x0f; int right_shift = (kcontrol->private_value >> 24) & 0x0f; unsigned char val1, val2; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); val1 = snd_sbmixer_read(sb, reg1); val2 = snd_sbmixer_read(sb, reg2); - spin_unlock_irqrestore(&sb->mixer_lock, flags); ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01; ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01; ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01; @@ -406,7 +385,6 @@ static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_sb *sb = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg1 = kcontrol->private_value & 0xff; int reg2 = (kcontrol->private_value >> 8) & 0xff; int left_shift = (kcontrol->private_value >> 16) & 0x0f; @@ -414,7 +392,7 @@ static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ int change; unsigned char val1, val2, oval1, oval2; - spin_lock_irqsave(&sb->mixer_lock, flags); + guard(spinlock_irqsave)(&sb->mixer_lock); oval1 = snd_sbmixer_read(sb, reg1); oval2 = snd_sbmixer_read(sb, reg2); val1 = oval1 & ~((1 << left_shift) | (1 << right_shift)); @@ -428,7 +406,6 @@ static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ snd_sbmixer_write(sb, reg1, val1); snd_sbmixer_write(sb, reg2, val2); } - spin_unlock_irqrestore(&sb->mixer_lock, flags); return change; } @@ -697,20 +674,18 @@ static int snd_sbmixer_init(struct snd_sb *chip, int map_count, char *name) { - unsigned long flags; struct snd_card *card = chip->card; int idx, err; /* mixer reset */ - spin_lock_irqsave(&chip->mixer_lock, flags); - snd_sbmixer_write(chip, 0x00, 0x00); - spin_unlock_irqrestore(&chip->mixer_lock, flags); + scoped_guard(spinlock_irqsave, &chip->mixer_lock) { + snd_sbmixer_write(chip, 0x00, 0x00); + } /* mute and zero volume channels */ for (idx = 0; idx < map_count; idx++) { - spin_lock_irqsave(&chip->mixer_lock, flags); + guard(spinlock_irqsave)(&chip->mixer_lock); snd_sbmixer_write(chip, map[idx][0], map[idx][1]); - spin_unlock_irqrestore(&chip->mixer_lock, flags); } for (idx = 0; idx < controls_count; idx++) { From 7b4ac266898ad716c03456d9cc368c2d8592922a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:54 +0200 Subject: [PATCH 0985/1292] ALSA: emu8000: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-15-tiwai@suse.de --- sound/isa/sb/emu8000.c | 94 ++++++++++++++++---------------------- sound/isa/sb/emu8000_pcm.c | 48 ++++++++++--------- 2 files changed, 62 insertions(+), 80 deletions(-) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 312b217491d4ec..12c296ee34ecf7 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -35,60 +35,49 @@ /* Write a word */ void snd_emu8000_poke(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val) { - unsigned long flags; - spin_lock_irqsave(&emu->reg_lock, flags); + guard(spinlock_irqsave)(&emu->reg_lock); if (reg != emu->last_reg) { outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */ emu->last_reg = reg; } outw((unsigned short)val, port); /* Send data */ - spin_unlock_irqrestore(&emu->reg_lock, flags); } /* Read a word */ unsigned short snd_emu8000_peek(struct snd_emu8000 *emu, unsigned int port, unsigned int reg) { - unsigned short res; - unsigned long flags; - spin_lock_irqsave(&emu->reg_lock, flags); + guard(spinlock_irqsave)(&emu->reg_lock); if (reg != emu->last_reg) { outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */ emu->last_reg = reg; } - res = inw(port); /* Read data */ - spin_unlock_irqrestore(&emu->reg_lock, flags); - return res; + return inw(port); /* Read data */ } /* Write a double word */ void snd_emu8000_poke_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val) { - unsigned long flags; - spin_lock_irqsave(&emu->reg_lock, flags); + guard(spinlock_irqsave)(&emu->reg_lock); if (reg != emu->last_reg) { outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */ emu->last_reg = reg; } outw((unsigned short)val, port); /* Send low word of data */ outw((unsigned short)(val>>16), port+2); /* Send high word of data */ - spin_unlock_irqrestore(&emu->reg_lock, flags); } /* Read a double word */ unsigned int snd_emu8000_peek_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg) { unsigned short low; - unsigned int res; - unsigned long flags; - spin_lock_irqsave(&emu->reg_lock, flags); + + guard(spinlock_irqsave)(&emu->reg_lock); if (reg != emu->last_reg) { outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */ emu->last_reg = reg; } low = inw(port); /* Read low word of data */ - res = low + (inw(port+2) << 16); - spin_unlock_irqrestore(&emu->reg_lock, flags); - return res; + return low + (inw(port+2) << 16); } /* @@ -456,8 +445,6 @@ size_dram(struct snd_emu8000 *emu) /*exported*/ void snd_emu8000_init_fm(struct snd_emu8000 *emu) { - unsigned long flags; - /* Initialize the last two channels for DRAM refresh and producing the reverb and chorus effects for Yamaha OPL-3 synthesizer */ @@ -479,12 +466,12 @@ snd_emu8000_init_fm(struct snd_emu8000 *emu) snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0); - spin_lock_irqsave(&emu->reg_lock, flags); - while (!(inw(EMU8000_PTR(emu)) & 0x1000)) - ; - while ((inw(EMU8000_PTR(emu)) & 0x1000)) - ; - spin_unlock_irqrestore(&emu->reg_lock, flags); + scoped_guard(spinlock_irqsave, &emu->reg_lock) { + while (!(inw(EMU8000_PTR(emu)) & 0x1000)) + ; + while ((inw(EMU8000_PTR(emu)) & 0x1000)) + ; + } snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828); /* this is really odd part.. */ outb(0x3C, EMU8000_PTR(emu)); @@ -838,20 +825,19 @@ static int mixer_bass_treble_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int mixer_bass_treble_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned short val1; val1 = ucontrol->value.integer.value[0] % 12; - spin_lock_irqsave(&emu->control_lock, flags); - if (kcontrol->private_value) { - change = val1 != emu->treble_level; - emu->treble_level = val1; - } else { - change = val1 != emu->bass_level; - emu->bass_level = val1; + scoped_guard(spinlock_irqsave, &emu->control_lock) { + if (kcontrol->private_value) { + change = val1 != emu->treble_level; + emu->treble_level = val1; + } else { + change = val1 != emu->bass_level; + emu->bass_level = val1; + } } - spin_unlock_irqrestore(&emu->control_lock, flags); snd_emu8000_update_equalizer(emu); return change; } @@ -899,21 +885,20 @@ static int mixer_chorus_reverb_get(struct snd_kcontrol *kcontrol, struct snd_ctl static int mixer_chorus_reverb_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned short val1; - spin_lock_irqsave(&emu->control_lock, flags); - if (kcontrol->private_value) { - val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS; - change = val1 != emu->chorus_mode; - emu->chorus_mode = val1; - } else { - val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS; - change = val1 != emu->reverb_mode; - emu->reverb_mode = val1; + scoped_guard(spinlock_irqsave, &emu->control_lock) { + if (kcontrol->private_value) { + val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS; + change = val1 != emu->chorus_mode; + emu->chorus_mode = val1; + } else { + val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS; + change = val1 != emu->reverb_mode; + emu->reverb_mode = val1; + } } - spin_unlock_irqrestore(&emu->control_lock, flags); if (change) { if (kcontrol->private_value) snd_emu8000_update_chorus_mode(emu); @@ -966,20 +951,19 @@ static int mixer_fm_depth_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static int mixer_fm_depth_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol); - unsigned long flags; int change; unsigned short val1; val1 = ucontrol->value.integer.value[0] % 256; - spin_lock_irqsave(&emu->control_lock, flags); - if (kcontrol->private_value) { - change = val1 != emu->fm_chorus_depth; - emu->fm_chorus_depth = val1; - } else { - change = val1 != emu->fm_reverb_depth; - emu->fm_reverb_depth = val1; + scoped_guard(spinlock_irqsave, &emu->control_lock) { + if (kcontrol->private_value) { + change = val1 != emu->fm_chorus_depth; + emu->fm_chorus_depth = val1; + } else { + change = val1 != emu->fm_reverb_depth; + emu->fm_reverb_depth = val1; + } } - spin_unlock_irqrestore(&emu->control_lock, flags); if (change) snd_emu8000_init_fm(emu); return change; diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 215bbcd0360e6b..656a655d618d54 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -184,28 +184,30 @@ static void emu8k_pcm_timer_func(struct timer_list *t) { struct snd_emu8k_pcm *rec = timer_container_of(rec, t, timer); int ptr, delta; + bool period_elapsed = false; + + scoped_guard(spinlock, &rec->timer_lock) { + /* update the current pointer */ + ptr = emu8k_get_curpos(rec, 0); + if (ptr < rec->last_ptr) + delta = ptr + rec->buf_size - rec->last_ptr; + else + delta = ptr - rec->last_ptr; + rec->period_pos += delta; + rec->last_ptr = ptr; + + /* reprogram timer */ + mod_timer(&rec->timer, jiffies + 1); - spin_lock(&rec->timer_lock); - /* update the current pointer */ - ptr = emu8k_get_curpos(rec, 0); - if (ptr < rec->last_ptr) - delta = ptr + rec->buf_size - rec->last_ptr; - else - delta = ptr - rec->last_ptr; - rec->period_pos += delta; - rec->last_ptr = ptr; - - /* reprogram timer */ - mod_timer(&rec->timer, jiffies + 1); + /* update period */ + if (rec->period_pos >= (int)rec->period_size) { + rec->period_pos %= rec->period_size; + period_elapsed = true; + } + } - /* update period */ - if (rec->period_pos >= (int)rec->period_size) { - rec->period_pos %= rec->period_size; - spin_unlock(&rec->timer_lock); + if (period_elapsed) snd_pcm_period_elapsed(rec->substream); - return; - } - spin_unlock(&rec->timer_lock); } @@ -321,7 +323,6 @@ static void setup_voice(struct snd_emu8k_pcm *rec, int ch) */ static void start_voice(struct snd_emu8k_pcm *rec, int ch) { - unsigned long flags; struct snd_emu8000 *hw = rec->emu; unsigned int temp, aux; int pt = calc_pitch_target(rec->pitch); @@ -343,12 +344,11 @@ static void start_voice(struct snd_emu8k_pcm *rec, int ch) EMU8000_CPF_WRITE(hw, ch, pt << 16); /* start timer */ - spin_lock_irqsave(&rec->timer_lock, flags); + guard(spinlock_irqsave)(&rec->timer_lock); if (! rec->timer_running) { mod_timer(&rec->timer, jiffies + 1); rec->timer_running = 1; } - spin_unlock_irqrestore(&rec->timer_lock, flags); } /* @@ -356,18 +356,16 @@ static void start_voice(struct snd_emu8k_pcm *rec, int ch) */ static void stop_voice(struct snd_emu8k_pcm *rec, int ch) { - unsigned long flags; struct snd_emu8000 *hw = rec->emu; EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F); /* stop timer */ - spin_lock_irqsave(&rec->timer_lock, flags); + guard(spinlock_irqsave)(&rec->timer_lock); if (rec->timer_running) { timer_delete(&rec->timer); rec->timer_running = 0; } - spin_unlock_irqrestore(&rec->timer_lock, flags); } static int emu8k_pcm_trigger(struct snd_pcm_substream *subs, int cmd) From 79112d65276f889a3c5c30ed4595c12e910a9f1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:55 +0200 Subject: [PATCH 0986/1292] ALSA: sscape: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-16-tiwai@suse.de --- sound/isa/sscape.c | 190 ++++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 106 deletions(-) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 709a1659d66f5b..a31ca75774a6ae 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -200,11 +200,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val) { - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); + guard(spinlock_irqsave)(&s->lock); sscape_write_unsafe(s->io_base, reg, val); - spin_unlock_irqrestore(&s->lock, flags); } /* @@ -367,12 +364,11 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout) unsigned long end_time = jiffies + msecs_to_jiffies(timeout); do { - unsigned long flags; int x; - spin_lock_irqsave(&s->lock, flags); - x = host_read_unsafe(s->io_base); - spin_unlock_irqrestore(&s->lock, flags); + scoped_guard(spinlock_irqsave, &s->lock) { + x = host_read_unsafe(s->io_base); + } if (x == 0xfe || x == 0xff) return 1; @@ -394,12 +390,11 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) unsigned long end_time = jiffies + msecs_to_jiffies(timeout); do { - unsigned long flags; int x; - spin_lock_irqsave(&s->lock, flags); - x = host_read_unsafe(s->io_base); - spin_unlock_irqrestore(&s->lock, flags); + scoped_guard(spinlock_irqsave, &s->lock) { + x = host_read_unsafe(s->io_base); + } if (x == 0xfe) return 1; @@ -415,7 +410,6 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) static int upload_dma_data(struct soundscape *s, const unsigned char *data, size_t size) { - unsigned long flags; struct snd_dma_buffer dma; int ret; unsigned char val; @@ -423,62 +417,57 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data, if (!get_dmabuf(s, &dma, PAGE_ALIGN(32 * 1024))) return -ENOMEM; - spin_lock_irqsave(&s->lock, flags); - - /* - * Reset the board ... - */ - val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f); - - /* - * Enable the DMA channels and configure them ... - */ - val = (s->chip->dma1 << 4) | DMA_8BIT; - sscape_write_unsafe(s->io_base, GA_DMAA_REG, val); - sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); - - /* - * Take the board out of reset ... - */ - val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80); + scoped_guard(spinlock_irqsave, &s->lock) { - /* - * Upload the firmware to the SoundScape - * board through the DMA channel ... - */ - while (size != 0) { - unsigned long len; + /* + * Reset the board ... + */ + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f); - len = min(size, dma.bytes); - memcpy(dma.area, data, len); - data += len; - size -= len; + /* + * Enable the DMA channels and configure them ... + */ + val = (s->chip->dma1 << 4) | DMA_8BIT; + sscape_write_unsafe(s->io_base, GA_DMAA_REG, val); + sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); - snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE); - sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); - if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { - /* - * Don't forget to release this spinlock we're holding - */ - spin_unlock_irqrestore(&s->lock, flags); + /* + * Take the board out of reset ... + */ + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80); - dev_err(s->dev, "sscape: DMA upload has timed out\n"); - ret = -EAGAIN; - goto _release_dma; - } - } /* while */ + /* + * Upload the firmware to the SoundScape + * board through the DMA channel ... + */ + while (size != 0) { + unsigned long len; + + len = min(size, dma.bytes); + memcpy(dma.area, data, len); + data += len; + size -= len; + + snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE); + sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); + if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { + dev_err(s->dev, "sscape: DMA upload has timed out\n"); + ret = -EAGAIN; + goto _release_dma; + } + } /* while */ - set_host_mode_unsafe(s->io_base); - outb(0x0, s->io_base); + set_host_mode_unsafe(s->io_base); + outb(0x0, s->io_base); - /* - * Boot the board ... (I think) - */ - val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40); - spin_unlock_irqrestore(&s->lock, flags); + /* + * Boot the board ... (I think) + */ + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40); + } /* * If all has gone well, then the board should acknowledge @@ -513,7 +502,6 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data, static int sscape_upload_bootblock(struct snd_card *card) { struct soundscape *sscape = get_card_soundscape(card); - unsigned long flags; const struct firmware *init_fw = NULL; int data = 0; int ret; @@ -527,15 +515,13 @@ static int sscape_upload_bootblock(struct snd_card *card) release_firmware(init_fw); - spin_lock_irqsave(&sscape->lock, flags); + guard(spinlock_irqsave)(&sscape->lock); if (ret == 0) data = host_read_ctrl_unsafe(sscape->io_base, 100); if (data & 0x10) sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f); - spin_unlock_irqrestore(&sscape->lock, flags); - data &= 0xf; if (ret == 0 && data > 7) { dev_err(card->dev, @@ -593,11 +579,9 @@ static int sscape_midi_get(struct snd_kcontrol *kctl, struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; register struct soundscape *s = get_card_soundscape(card); - unsigned long flags; - spin_lock_irqsave(&s->lock, flags); + guard(spinlock_irqsave)(&s->lock); uctl->value.integer.value[0] = s->midi_vol; - spin_unlock_irqrestore(&s->lock, flags); return 0; } @@ -607,11 +591,10 @@ static int sscape_midi_put(struct snd_kcontrol *kctl, struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; struct soundscape *s = get_card_soundscape(card); - unsigned long flags; int change; unsigned char new_val; - spin_lock_irqsave(&s->lock, flags); + guard(spinlock_irqsave)(&s->lock); new_val = uctl->value.integer.value[0] & 127; /* @@ -642,7 +625,6 @@ static int sscape_midi_put(struct snd_kcontrol *kctl, */ set_midi_mode_unsafe(s->io_base); - spin_unlock_irqrestore(&s->lock, flags); return change; } @@ -852,8 +834,6 @@ static int create_ad1845(struct snd_card *card, unsigned port, err = snd_wss_create(card, port, -1, irq, dma1, dma2, codec_type, WSS_HWSHARE_DMA1, &chip); if (!err) { - unsigned long flags; - if (sscape->type != SSCAPE_VIVO) { /* * The input clock frequency on the SoundScape must @@ -861,9 +841,9 @@ static int create_ad1845(struct snd_card *card, unsigned port, * to get the playback to sound correct ... */ snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_wss_out(chip, AD1845_CLOCK, 0x20); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_wss_out(chip, AD1845_CLOCK, 0x20); + } snd_wss_mce_down(chip); } @@ -920,7 +900,6 @@ static int create_sscape(int dev, struct snd_card *card) unsigned mpu_irq_cfg; struct resource *io_res; struct resource *wss_res; - unsigned long flags; int err; int val; const char *name; @@ -1006,34 +985,34 @@ static int create_sscape(int dev, struct snd_card *card) * Tell the on-board devices where their resources are (I think - * I can't be sure without a datasheet ... So many magic values!) */ - spin_lock_irqsave(&sscape->lock, flags); + scoped_guard(spinlock_irqsave, &sscape->lock) { - sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); - sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); + sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); + sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); - /* - * Enable and configure the DMA channels ... - */ - sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); - dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70); - sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); - sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); - - mpu_irq_cfg |= mpu_irq_cfg << 2; - val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7; - if (joystick[dev]) - val |= 8; - sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10); - sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); - sscape_write_unsafe(sscape->io_base, - GA_CDCFG_REG, 0x09 | DMA_8BIT - | (dma[dev] << 4) | (irq_cfg << 1)); - /* - * Enable the master IRQ ... - */ - sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); + /* + * Enable and configure the DMA channels ... + */ + sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); + dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70); + sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); + sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); + + mpu_irq_cfg |= mpu_irq_cfg << 2; + val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7; + if (joystick[dev]) + val |= 8; + sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10); + sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); + sscape_write_unsafe(sscape->io_base, + GA_CDCFG_REG, 0x09 | DMA_8BIT + | (dma[dev] << 4) | (irq_cfg << 1)); + /* + * Enable the master IRQ ... + */ + sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); - spin_unlock_irqrestore(&sscape->lock, flags); + } /* * We have now enabled the codec chip, and so we should @@ -1073,7 +1052,7 @@ static int create_sscape(int dev, struct snd_card *card) /* * Initialize mixer */ - spin_lock_irqsave(&sscape->lock, flags); + guard(spinlock_irqsave)(&sscape->lock); sscape->midi_vol = 0; host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); @@ -1090,7 +1069,6 @@ static int create_sscape(int dev, struct snd_card *card) host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100); set_midi_mode_unsafe(sscape->io_base); - spin_unlock_irqrestore(&sscape->lock, flags); } } From 372b43467aecd97b7c9435b51987a5e958b7d7e2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:56 +0200 Subject: [PATCH 0987/1292] ALSA: wss: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-17-tiwai@suse.de --- sound/isa/wss/wss_lib.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 1b6a80021d1829..0a2c040af5f0ff 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -618,7 +618,7 @@ static void snd_wss_playback_format(struct snd_wss *chip, unsigned long flags; int full_calib = 1; - mutex_lock(&chip->mce_mutex); + guard(mutex)(&chip->mce_mutex); if (chip->hardware == WSS_HW_CS4231A || (chip->hardware & WSS_HW_CS4232_MASK)) { spin_lock_irqsave(&chip->reg_lock, flags); @@ -669,7 +669,6 @@ static void snd_wss_playback_format(struct snd_wss *chip, udelay(100); /* this seems to help */ snd_wss_mce_down(chip); } - mutex_unlock(&chip->mce_mutex); } static void snd_wss_capture_format(struct snd_wss *chip, @@ -679,7 +678,7 @@ static void snd_wss_capture_format(struct snd_wss *chip, unsigned long flags; int full_calib = 1; - mutex_lock(&chip->mce_mutex); + guard(mutex)(&chip->mce_mutex); if (chip->hardware == WSS_HW_CS4231A || (chip->hardware & WSS_HW_CS4232_MASK)) { spin_lock_irqsave(&chip->reg_lock, flags); @@ -736,7 +735,6 @@ static void snd_wss_capture_format(struct snd_wss *chip, spin_unlock_irqrestore(&chip->reg_lock, flags); snd_wss_mce_down(chip); } - mutex_unlock(&chip->mce_mutex); } /* @@ -862,15 +860,12 @@ static int snd_wss_open(struct snd_wss *chip, unsigned int mode) { unsigned long flags; - mutex_lock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); if ((chip->mode & mode) || - ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) { - mutex_unlock(&chip->open_mutex); + ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) return -EAGAIN; - } if (chip->mode & WSS_MODE_OPEN) { chip->mode |= mode; - mutex_unlock(&chip->open_mutex); return 0; } /* ok. now enable and ack CODEC IRQ */ @@ -896,7 +891,6 @@ static int snd_wss_open(struct snd_wss *chip, unsigned int mode) spin_unlock_irqrestore(&chip->reg_lock, flags); chip->mode = mode; - mutex_unlock(&chip->open_mutex); return 0; } @@ -904,12 +898,10 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode) { unsigned long flags; - mutex_lock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); chip->mode &= ~mode; - if (chip->mode & WSS_MODE_OPEN) { - mutex_unlock(&chip->open_mutex); + if (chip->mode & WSS_MODE_OPEN) return; - } /* disable IRQ */ spin_lock_irqsave(&chip->reg_lock, flags); if (!(chip->hardware & WSS_HW_AD1848_MASK)) @@ -943,7 +935,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode) spin_unlock_irqrestore(&chip->reg_lock, flags); chip->mode = 0; - mutex_unlock(&chip->open_mutex); } /* From ec4c3dcf155916e53283f7593a44759d86837726 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:57 +0200 Subject: [PATCH 0988/1292] ALSA: wss: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-18-tiwai@suse.de --- sound/isa/wss/wss_lib.c | 264 ++++++++++++++++------------------------ 1 file changed, 107 insertions(+), 157 deletions(-) diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 0a2c040af5f0ff..6cf88625bbc341 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -360,7 +360,6 @@ static void snd_wss_busy_wait(struct snd_wss *chip) void snd_wss_mce_up(struct snd_wss *chip) { - unsigned long flags; int timeout; snd_wss_wait(chip); @@ -369,7 +368,7 @@ void snd_wss_mce_up(struct snd_wss *chip) dev_dbg(chip->card->dev, "mce_up - auto calibration time out (0)\n"); #endif - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); chip->mce_bit |= CS4231_MCE; timeout = wss_inb(chip, CS4231P(REGSEL)); if (timeout == 0x80) @@ -379,13 +378,11 @@ void snd_wss_mce_up(struct snd_wss *chip) if (!(timeout & CS4231_MCE)) wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); - spin_unlock_irqrestore(&chip->reg_lock, flags); } EXPORT_SYMBOL(snd_wss_mce_up); void snd_wss_mce_down(struct snd_wss *chip) { - unsigned long flags; unsigned long end_time; int timeout; int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848; @@ -398,11 +395,11 @@ void snd_wss_mce_down(struct snd_wss *chip) "mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL)); #endif - spin_lock_irqsave(&chip->reg_lock, flags); - chip->mce_bit &= ~CS4231_MCE; - timeout = wss_inb(chip, CS4231P(REGSEL)); - wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + chip->mce_bit &= ~CS4231_MCE; + timeout = wss_inb(chip, CS4231P(REGSEL)); + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); + } if (timeout == 0x80) dev_dbg(chip->card->dev, "mce_down [0x%lx]: serious init problem - codec still busy\n", @@ -496,7 +493,7 @@ static int snd_wss_trigger(struct snd_pcm_substream *substream, snd_pcm_trigger_done(s, substream); } } - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); if (do_start) { chip->image[CS4231_IFACE_CTRL] |= what; if (chip->trigger) @@ -507,7 +504,6 @@ static int snd_wss_trigger(struct snd_pcm_substream *substream, chip->trigger(chip, what, 0); } snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - spin_unlock(&chip->reg_lock); #if 0 snd_wss_debug(chip); #endif @@ -553,14 +549,11 @@ static unsigned char snd_wss_get_format(struct snd_wss *chip, static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute) { - unsigned long flags; mute = mute ? 0x80 : 0; - spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->calibrate_mute == mute) { - spin_unlock_irqrestore(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); + if (chip->calibrate_mute == mute) return; - } if (!mute) { snd_wss_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]); @@ -608,20 +601,18 @@ static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute) mute | chip->image[CS4231_LINE_RIGHT_OUTPUT]); } chip->calibrate_mute = mute; - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_wss_playback_format(struct snd_wss *chip, struct snd_pcm_hw_params *params, unsigned char pdfr) { - unsigned long flags; int full_calib = 1; guard(mutex)(&chip->mce_mutex); if (chip->hardware == WSS_HW_CS4231A || (chip->hardware & WSS_HW_CS4232_MASK)) { - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) { /* rate is same? */ snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10); @@ -633,7 +624,6 @@ static void snd_wss_playback_format(struct snd_wss *chip, udelay(100); /* Fixes audible clicks at least on GUS MAX */ full_calib = 0; } - spin_unlock_irqrestore(&chip->reg_lock, flags); } else if (chip->hardware == WSS_HW_AD1845) { unsigned rate = params_rate(params); @@ -646,25 +636,24 @@ static void snd_wss_playback_format(struct snd_wss *chip, * NOTE: We seem to need to write to the MSB before the LSB * to get the correct sample frequency. */ - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (pdfr & 0xf0)); snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff); snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff); full_calib = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); } if (full_calib) { snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) { - if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) - pdfr = (pdfr & 0xf0) | - (chip->image[CS4231_REC_FORMAT] & 0x0f); - } else { - chip->image[CS4231_PLAYBK_FORMAT] = pdfr; + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) { + if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) + pdfr = (pdfr & 0xf0) | + (chip->image[CS4231_REC_FORMAT] & 0x0f); + } else { + chip->image[CS4231_PLAYBK_FORMAT] = pdfr; + } + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr); } - snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr); - spin_unlock_irqrestore(&chip->reg_lock, flags); if (chip->hardware == WSS_HW_OPL3SA2) udelay(100); /* this seems to help */ snd_wss_mce_down(chip); @@ -681,7 +670,7 @@ static void snd_wss_capture_format(struct snd_wss *chip, guard(mutex)(&chip->mce_mutex); if (chip->hardware == WSS_HW_CS4231A || (chip->hardware & WSS_HW_CS4232_MASK)) { - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) || /* rate is same? */ (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) { snd_wss_out(chip, CS4231_ALT_FEATURE_1, @@ -692,7 +681,6 @@ static void snd_wss_capture_format(struct snd_wss *chip, chip->image[CS4231_ALT_FEATURE_1] &= ~0x20); full_calib = 0; } - spin_unlock_irqrestore(&chip->reg_lock, flags); } else if (chip->hardware == WSS_HW_AD1845) { unsigned rate = params_rate(params); @@ -705,12 +693,11 @@ static void snd_wss_capture_format(struct snd_wss *chip, * NOTE: We seem to need to write to the MSB before the LSB * to get the correct sample frequency. */ - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_wss_out(chip, CS4231_REC_FORMAT, (cdfr & 0xf0)); snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff); snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff); full_calib = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); } if (full_calib) { snd_wss_mce_up(chip); @@ -752,10 +739,10 @@ static unsigned long snd_wss_timer_resolution(struct snd_timer *timer) static int snd_wss_timer_start(struct snd_timer *timer) { - unsigned long flags; unsigned int ticks; struct snd_wss *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); ticks = timer->sticks; if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 || (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] || @@ -770,26 +757,22 @@ static int snd_wss_timer_start(struct snd_timer *timer) chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static int snd_wss_timer_stop(struct snd_timer *timer) { - unsigned long flags; struct snd_wss *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE; snd_wss_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } static void snd_wss_init(struct snd_wss *chip) { - unsigned long flags; - snd_wss_calibrate_mute(chip, 1); snd_wss_mce_down(chip); @@ -797,15 +780,15 @@ static void snd_wss_init(struct snd_wss *chip) dev_dbg(chip->card->dev, "init: (1)\n"); #endif snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | - CS4231_PLAYBACK_PIO | - CS4231_RECORD_ENABLE | - CS4231_RECORD_PIO | - CS4231_CALIB_MODE); - chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; - snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | + CS4231_PLAYBACK_PIO | + CS4231_RECORD_ENABLE | + CS4231_RECORD_PIO | + CS4231_CALIB_MODE); + chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; + snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); + } snd_wss_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -813,12 +796,12 @@ static void snd_wss_init(struct snd_wss *chip) #endif snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB; - snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - snd_wss_out(chip, - CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB; + snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); + snd_wss_out(chip, + CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); + } snd_wss_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -826,16 +809,16 @@ static void snd_wss_init(struct snd_wss *chip) chip->image[CS4231_ALT_FEATURE_1]); #endif - spin_lock_irqsave(&chip->reg_lock, flags); - snd_wss_out(chip, CS4231_ALT_FEATURE_2, - chip->image[CS4231_ALT_FEATURE_2]); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_wss_out(chip, CS4231_ALT_FEATURE_2, + chip->image[CS4231_ALT_FEATURE_2]); + } snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_wss_out(chip, CS4231_PLAYBK_FORMAT, - chip->image[CS4231_PLAYBK_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, + chip->image[CS4231_PLAYBK_FORMAT]); + } snd_wss_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -843,11 +826,11 @@ static void snd_wss_init(struct snd_wss *chip) #endif snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - if (!(chip->hardware & WSS_HW_AD1848_MASK)) - snd_wss_out(chip, CS4231_REC_FORMAT, - chip->image[CS4231_REC_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + if (!(chip->hardware & WSS_HW_AD1848_MASK)) + snd_wss_out(chip, CS4231_REC_FORMAT, + chip->image[CS4231_REC_FORMAT]); + } snd_wss_mce_down(chip); snd_wss_calibrate_mute(chip, 0); @@ -858,8 +841,6 @@ static void snd_wss_init(struct snd_wss *chip) static int snd_wss_open(struct snd_wss *chip, unsigned int mode) { - unsigned long flags; - guard(mutex)(&chip->open_mutex); if ((chip->mode & mode) || ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) @@ -869,7 +850,7 @@ static int snd_wss_open(struct snd_wss *chip, unsigned int mode) return 0; } /* ok. now enable and ack CODEC IRQ */ - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (!(chip->hardware & WSS_HW_AD1848_MASK)) { snd_wss_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | @@ -888,7 +869,6 @@ static int snd_wss_open(struct snd_wss *chip, unsigned int mode) CS4231_TIMER_IRQ); snd_wss_out(chip, CS4231_IRQ_STATUS, 0); } - spin_unlock_irqrestore(&chip->reg_lock, flags); chip->mode = mode; return 0; @@ -988,18 +968,16 @@ static int snd_wss_playback_prepare(struct snd_pcm_substream *substream) { struct snd_wss *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); chip->p_dma_size = size; chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO); snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1; snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count); snd_wss_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8)); - spin_unlock_irqrestore(&chip->reg_lock, flags); #if 0 snd_wss_debug(chip); #endif @@ -1023,11 +1001,10 @@ static int snd_wss_capture_prepare(struct snd_pcm_substream *substream) { struct snd_wss *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); chip->c_dma_size = size; chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); @@ -1047,18 +1024,16 @@ static int snd_wss_capture_prepare(struct snd_pcm_substream *substream) snd_wss_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8)); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } void snd_wss_overrange(struct snd_wss *chip) { - unsigned long flags; unsigned char res; - spin_lock_irqsave(&chip->reg_lock, flags); - res = snd_wss_in(chip, CS4231_TEST_INIT); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + res = snd_wss_in(chip, CS4231_TEST_INIT); + } if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */ chip->capture_substream->runtime->overrange++; } @@ -1104,13 +1079,12 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id) } } - spin_lock(&chip->reg_lock); + guard(spinlock)(&chip->reg_lock); status = ~CS4231_ALL_IRQS | ~status; if (chip->hardware & WSS_HW_AD1848_MASK) wss_outb(chip, CS4231P(STATUS), 0); else snd_wss_out(chip, CS4231_IRQ_STATUS, status); - spin_unlock(&chip->reg_lock); return IRQ_HANDLED; } EXPORT_SYMBOL(snd_wss_interrupt); @@ -1144,10 +1118,8 @@ static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *subst static int snd_ad1848_probe(struct snd_wss *chip) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); - unsigned long flags; unsigned char r; unsigned short hardware = 0; - int err = 0; int i; while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { @@ -1155,7 +1127,7 @@ static int snd_ad1848_probe(struct snd_wss *chip) return -ENODEV; cond_resched(); } - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); /* set CS423x MODE 1 */ snd_wss_dout(chip, CS4231_MISC_INFO, 0); @@ -1164,19 +1136,15 @@ static int snd_ad1848_probe(struct snd_wss *chip) r = snd_wss_in(chip, CS4231_RIGHT_INPUT); if (r != 0x45) { /* RMGE always high on AD1847 */ - if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) { - err = -ENODEV; - goto out; - } + if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) + return -ENODEV; hardware = WSS_HW_AD1847; } else { snd_wss_dout(chip, CS4231_LEFT_INPUT, 0xaa); r = snd_wss_in(chip, CS4231_LEFT_INPUT); /* L/RMGE always low on AT2320 */ - if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) { - err = -ENODEV; - goto out; - } + if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) + return -ENODEV; } /* clear pending IRQ */ @@ -1185,11 +1153,11 @@ static int snd_ad1848_probe(struct snd_wss *chip) mb(); if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT) - goto out; + return 0; if (hardware) { chip->hardware = hardware; - goto out; + return 0; } r = snd_wss_in(chip, CS4231_MISC_INFO); @@ -1218,14 +1186,11 @@ static int snd_ad1848_probe(struct snd_wss *chip) chip->hardware = WSS_HW_AD1848; out_mode: snd_wss_dout(chip, CS4231_MISC_INFO, 0); -out: - spin_unlock_irqrestore(&chip->reg_lock, flags); - return err; + return 0; } static int snd_wss_probe(struct snd_wss *chip) { - unsigned long flags; int i, id, rev, regnum; unsigned char *ptr; unsigned int hw; @@ -1241,11 +1206,10 @@ static int snd_wss_probe(struct snd_wss *chip) if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) msleep(2); else { - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2); id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (id == 0x0a) break; /* this is valid value */ } @@ -1280,11 +1244,11 @@ static int snd_wss_probe(struct snd_wss *chip) return -ENODEV; /* unknown CS4231 chip? */ } } - spin_lock_irqsave(&chip->reg_lock, flags); - wss_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */ - wss_outb(chip, CS4231P(STATUS), 0); - mb(); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + wss_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */ + wss_outb(chip, CS4231P(STATUS), 0); + mb(); + } if (!(chip->hardware & WSS_HW_AD1848_MASK)) chip->image[CS4231_MISC_INFO] = CS4231_MODE2; @@ -1319,10 +1283,10 @@ static int snd_wss_probe(struct snd_wss *chip) ptr = (unsigned char *) &chip->image; regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32; snd_wss_mce_down(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - for (i = 0; i < regnum; i++) /* ok.. fill all registers */ - snd_wss_out(chip, i, *ptr++); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + for (i = 0; i < regnum; i++) /* ok.. fill all registers */ + snd_wss_out(chip, i, *ptr++); + } snd_wss_mce_up(chip); snd_wss_mce_down(chip); @@ -1587,12 +1551,11 @@ static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on) static void snd_wss_suspend(struct snd_wss *chip) { int reg; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); - for (reg = 0; reg < 32; reg++) - chip->image[reg] = snd_wss_in(chip, reg); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + for (reg = 0; reg < 32; reg++) + chip->image[reg] = snd_wss_in(chip, reg); + } if (chip->thinkpad_flag) snd_wss_thinkpad_twiddle(chip, 0); } @@ -1601,27 +1564,26 @@ static void snd_wss_suspend(struct snd_wss *chip) static void snd_wss_resume(struct snd_wss *chip) { int reg; - unsigned long flags; /* int timeout; */ if (chip->thinkpad_flag) snd_wss_thinkpad_twiddle(chip, 1); snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - for (reg = 0; reg < 32; reg++) { - switch (reg) { - case CS4231_VERSION: - break; - default: - snd_wss_out(chip, reg, chip->image[reg]); - break; + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + for (reg = 0; reg < 32; reg++) { + switch (reg) { + case CS4231_VERSION: + break; + default: + snd_wss_out(chip, reg, chip->image[reg]); + break; + } } + /* Yamaha needs this to resume properly */ + if (chip->hardware == WSS_HW_OPL3SA2) + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, + chip->image[CS4231_PLAYBK_FORMAT]); } - /* Yamaha needs this to resume properly */ - if (chip->hardware == WSS_HW_OPL3SA2) - snd_wss_out(chip, CS4231_PLAYBK_FORMAT, - chip->image[CS4231_PLAYBK_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); #if 1 snd_wss_mce_down(chip); #else @@ -1630,11 +1592,11 @@ static void snd_wss_resume(struct snd_wss *chip) include rescheduling. -- iwai */ snd_wss_busy_wait(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->mce_bit &= ~CS4231_MCE; - timeout = wss_inb(chip, CS4231P(REGSEL)); - wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + chip->mce_bit &= ~CS4231_MCE; + timeout = wss_inb(chip, CS4231P(REGSEL)); + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); + } if (timeout == 0x80) dev_err(chip->card->dev "down [0x%lx]: serious init problem - codec still busy\n", @@ -1935,12 +1897,10 @@ static int snd_wss_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6; ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6; - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -1948,7 +1908,6 @@ static int snd_wss_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned short left, right; int change; @@ -1957,14 +1916,13 @@ static int snd_wss_put_mux(struct snd_kcontrol *kcontrol, return -EINVAL; left = ucontrol->value.enumerated.item[0] << 6; right = ucontrol->value.enumerated.item[1] << 6; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left; right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right; change = left != chip->image[CS4231_LEFT_INPUT] || right != chip->image[CS4231_RIGHT_INPUT]; snd_wss_out(chip, CS4231_LEFT_INPUT, left); snd_wss_out(chip, CS4231_RIGHT_INPUT, right); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -1985,15 +1943,13 @@ int snd_wss_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; @@ -2004,7 +1960,6 @@ int snd_wss_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -2016,11 +1971,10 @@ int snd_wss_put_single(struct snd_kcontrol *kcontrol, if (invert) val = mask - val; val <<= shift; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val = (chip->image[reg] & ~(mask << shift)) | val; change = val != chip->image[reg]; snd_wss_out(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } EXPORT_SYMBOL(snd_wss_put_single); @@ -2042,7 +1996,6 @@ int snd_wss_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -2050,10 +2003,9 @@ int snd_wss_get_double(struct snd_kcontrol *kcontrol, int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; @@ -2066,7 +2018,6 @@ int snd_wss_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -2084,7 +2035,7 @@ int snd_wss_put_double(struct snd_kcontrol *kcontrol, } val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (left_reg != right_reg) { val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; @@ -2098,7 +2049,6 @@ int snd_wss_put_double(struct snd_kcontrol *kcontrol, change = val1 != chip->image[left_reg]; snd_wss_out(chip, left_reg, val1); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } EXPORT_SYMBOL(snd_wss_put_double); From 4b97f8e614ba46a50bd181d40b5a1424411a211a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 16:52:58 +0200 Subject: [PATCH 0989/1292] ALSA: wavefront: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829145300.5460-19-tiwai@suse.de --- sound/isa/wavefront/wavefront_midi.c | 131 ++++++++++---------------- sound/isa/wavefront/wavefront_synth.c | 18 ++-- 2 files changed, 61 insertions(+), 88 deletions(-) diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index 494b21be665c8a..1250ecba659a05 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -113,7 +113,6 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) { snd_wavefront_midi_t *midi = &card->wavefront.midi; snd_wavefront_mpu_id mpu; - unsigned long flags; unsigned char midi_byte; int max = 256, mask = 1; int timeout; @@ -142,11 +141,9 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) break; } - spin_lock_irqsave (&midi->virtual, flags); - if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) { - spin_unlock_irqrestore (&midi->virtual, flags); + guard(spinlock_irqsave)(&midi->virtual); + if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) goto __second; - } if (output_ready (midi)) { if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) { if (!midi->isvirtual || @@ -160,14 +157,11 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) timer_delete(&midi->timer); } midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; - spin_unlock_irqrestore (&midi->virtual, flags); goto __second; } } else { - spin_unlock_irqrestore (&midi->virtual, flags); return; } - spin_unlock_irqrestore (&midi->virtual, flags); } __second: @@ -185,15 +179,13 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) break; } - spin_lock_irqsave (&midi->virtual, flags); + guard(spinlock_irqsave)(&midi->virtual); if (!midi->isvirtual) mask = 0; mpu = midi->output_mpu ^ mask; mask = 0; /* don't invert the value from now */ - if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) { - spin_unlock_irqrestore (&midi->virtual, flags); + if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) return; - } if (snd_rawmidi_transmit_empty(midi->substream_output[mpu])) goto __timer; if (output_ready (midi)) { @@ -215,20 +207,16 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) timer_delete(&midi->timer); } midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; - spin_unlock_irqrestore (&midi->virtual, flags); return; } } else { - spin_unlock_irqrestore (&midi->virtual, flags); return; } - spin_unlock_irqrestore (&midi->virtual, flags); } } static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; @@ -243,17 +231,15 @@ static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream if (!midi) return -EIO; - spin_lock_irqsave (&midi->open, flags); + guard(spinlock_irqsave)(&midi->open); midi->mode[mpu] |= MPU401_MODE_INPUT; midi->substream_input[mpu] = substream; - spin_unlock_irqrestore (&midi->open, flags); return 0; } static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; @@ -268,17 +254,15 @@ static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substrea if (!midi) return -EIO; - spin_lock_irqsave (&midi->open, flags); + guard(spinlock_irqsave)(&midi->open); midi->mode[mpu] |= MPU401_MODE_OUTPUT; midi->substream_output[mpu] = substream; - spin_unlock_irqrestore (&midi->open, flags); return 0; } static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; @@ -293,16 +277,14 @@ static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substrea if (!midi) return -EIO; - spin_lock_irqsave (&midi->open, flags); + guard(spinlock_irqsave)(&midi->open); midi->mode[mpu] &= ~MPU401_MODE_INPUT; - spin_unlock_irqrestore (&midi->open, flags); return 0; } static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; @@ -317,15 +299,13 @@ static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substre if (!midi) return -EIO; - spin_lock_irqsave (&midi->open, flags); + guard(spinlock_irqsave)(&midi->open); midi->mode[mpu] &= ~MPU401_MODE_OUTPUT; - spin_unlock_irqrestore (&midi->open, flags); return 0; } static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; @@ -341,30 +321,27 @@ static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *subst if (!midi) return; - spin_lock_irqsave (&midi->virtual, flags); + guard(spinlock_irqsave)(&midi->virtual); if (up) { midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER; } else { midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER; } - spin_unlock_irqrestore (&midi->virtual, flags); } static void snd_wavefront_midi_output_timer(struct timer_list *t) { snd_wavefront_midi_t *midi = timer_container_of(midi, t, timer); snd_wavefront_card_t *card = midi->timer_card; - unsigned long flags; - spin_lock_irqsave (&midi->virtual, flags); - mod_timer(&midi->timer, 1 + jiffies); - spin_unlock_irqrestore (&midi->virtual, flags); + scoped_guard(spinlock_irqsave, &midi->virtual) { + mod_timer(&midi->timer, 1 + jiffies); + } snd_wavefront_midi_output_write(card); } static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; @@ -380,22 +357,22 @@ static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *subs if (!midi) return; - spin_lock_irqsave (&midi->virtual, flags); - if (up) { - if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { - if (!midi->istimer) { - timer_setup(&midi->timer, - snd_wavefront_midi_output_timer, - 0); - mod_timer(&midi->timer, 1 + jiffies); + scoped_guard(spinlock_irqsave, &midi->virtual) { + if (up) { + if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { + if (!midi->istimer) { + timer_setup(&midi->timer, + snd_wavefront_midi_output_timer, + 0); + mod_timer(&midi->timer, 1 + jiffies); + } + midi->istimer++; + midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; } - midi->istimer++; - midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; + } else { + midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; } - } else { - midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; } - spin_unlock_irqrestore (&midi->virtual, flags); if (up) snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data); @@ -405,7 +382,6 @@ void snd_wavefront_midi_interrupt (snd_wavefront_card_t *card) { - unsigned long flags; snd_wavefront_midi_t *midi; static struct snd_rawmidi_substream *substream = NULL; static int mpu = external_mpu; @@ -419,37 +395,37 @@ snd_wavefront_midi_interrupt (snd_wavefront_card_t *card) return; } - spin_lock_irqsave (&midi->virtual, flags); - while (--max) { - - if (input_avail (midi)) { - byte = read_data (midi); - - if (midi->isvirtual) { - if (byte == WF_EXTERNAL_SWITCH) { - substream = midi->substream_input[external_mpu]; - mpu = external_mpu; - } else if (byte == WF_INTERNAL_SWITCH) { - substream = midi->substream_output[internal_mpu]; + scoped_guard(spinlock_irqsave, &midi->virtual) { + while (--max) { + + if (input_avail(midi)) { + byte = read_data(midi); + + if (midi->isvirtual) { + if (byte == WF_EXTERNAL_SWITCH) { + substream = midi->substream_input[external_mpu]; + mpu = external_mpu; + } else if (byte == WF_INTERNAL_SWITCH) { + substream = midi->substream_output[internal_mpu]; + mpu = internal_mpu; + } /* else just leave it as it is */ + } else { + substream = midi->substream_input[internal_mpu]; mpu = internal_mpu; - } /* else just leave it as it is */ - } else { - substream = midi->substream_input[internal_mpu]; - mpu = internal_mpu; - } + } - if (substream == NULL) { - continue; - } + if (substream == NULL) { + continue; + } - if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { - snd_rawmidi_receive(substream, &byte, 1); + if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { + snd_rawmidi_receive(substream, &byte, 1); + } + } else { + break; } - } else { - break; } - } - spin_unlock_irqrestore (&midi->virtual, flags); + } snd_wavefront_midi_output_write(card); } @@ -471,13 +447,10 @@ void snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card) { - unsigned long flags; - - spin_lock_irqsave (&card->wavefront.midi.virtual, flags); + guard(spinlock_irqsave)(&card->wavefront.midi.virtual); // snd_wavefront_midi_input_close (card->ics2115_external_rmidi); // snd_wavefront_midi_output_close (card->ics2115_external_rmidi); card->wavefront.midi.isvirtual = 0; - spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); } int diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index bd679e2da154e2..cd5c177943aa0d 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -1741,10 +1741,10 @@ snd_wavefront_internal_interrupt (snd_wavefront_card_t *card) return; } - spin_lock(&dev->irq_lock); - dev->irq_ok = 1; - dev->irq_cnt++; - spin_unlock(&dev->irq_lock); + scoped_guard(spinlock, &dev->irq_lock) { + dev->irq_ok = 1; + dev->irq_cnt++; + } wake_up(&dev->interrupt_sleeper); } @@ -1796,11 +1796,11 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev, wait_queue_entry_t wait; init_waitqueue_entry(&wait, current); - spin_lock_irq(&dev->irq_lock); - add_wait_queue(&dev->interrupt_sleeper, &wait); - dev->irq_ok = 0; - outb (val,port); - spin_unlock_irq(&dev->irq_lock); + scoped_guard(spinlock_irq, &dev->irq_lock) { + add_wait_queue(&dev->interrupt_sleeper, &wait); + dev->irq_ok = 0; + outb(val, port); + } while (!dev->irq_ok && time_before(jiffies, timeout)) { schedule_timeout_uninterruptible(1); barrier(); From ebd9b6c91d4e345b7ded4b56567c46267a45d961 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:12 +0200 Subject: [PATCH 0990/1292] ALSA: aloop: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-2-tiwai@suse.de --- sound/drivers/aloop.c | 83 +++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index a8902dc45dc117..79e7f03e51e9cc 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -511,13 +511,12 @@ static int loopback_prepare(struct snd_pcm_substream *substream) dpcm->pcm_salign = salign; dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); - mutex_lock(&dpcm->loopback->cable_lock); + guard(mutex)(&dpcm->loopback->cable_lock); if (!(cable->valid & ~(1 << substream->stream)) || (get_setup(dpcm)->notify && substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) params_change(substream); cable->valid |= 1 << substream->stream; - mutex_unlock(&dpcm->loopback->cable_lock); return 0; } @@ -958,9 +957,8 @@ static int loopback_hw_free(struct snd_pcm_substream *substream) struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; - mutex_lock(&dpcm->loopback->cable_lock); + guard(mutex)(&dpcm->loopback->cable_lock); cable->valid &= ~(1 << substream->stream); - mutex_unlock(&dpcm->loopback->cable_lock); return 0; } @@ -980,10 +978,10 @@ static int rule_format(struct snd_pcm_hw_params *params, struct snd_mask m; snd_mask_none(&m); - mutex_lock(&dpcm->loopback->cable_lock); - m.bits[0] = (u_int32_t)cable->hw.formats; - m.bits[1] = (u_int32_t)(cable->hw.formats >> 32); - mutex_unlock(&dpcm->loopback->cable_lock); + scoped_guard(mutex, &dpcm->loopback->cable_lock) { + m.bits[0] = (u_int32_t)cable->hw.formats; + m.bits[1] = (u_int32_t)(cable->hw.formats >> 32); + } return snd_mask_refine(hw_param_mask(params, rule->var), &m); } @@ -994,10 +992,10 @@ static int rule_rate(struct snd_pcm_hw_params *params, struct loopback_cable *cable = dpcm->cable; struct snd_interval t; - mutex_lock(&dpcm->loopback->cable_lock); - t.min = cable->hw.rate_min; - t.max = cable->hw.rate_max; - mutex_unlock(&dpcm->loopback->cable_lock); + scoped_guard(mutex, &dpcm->loopback->cable_lock) { + t.min = cable->hw.rate_min; + t.max = cable->hw.rate_max; + } t.openmin = t.openmax = 0; t.integer = 0; return snd_interval_refine(hw_param_interval(params, rule->var), &t); @@ -1010,10 +1008,10 @@ static int rule_channels(struct snd_pcm_hw_params *params, struct loopback_cable *cable = dpcm->cable; struct snd_interval t; - mutex_lock(&dpcm->loopback->cable_lock); - t.min = cable->hw.channels_min; - t.max = cable->hw.channels_max; - mutex_unlock(&dpcm->loopback->cable_lock); + scoped_guard(mutex, &dpcm->loopback->cable_lock) { + t.min = cable->hw.channels_min; + t.max = cable->hw.channels_max; + } t.openmin = t.openmax = 0; t.integer = 0; return snd_interval_refine(hw_param_interval(params, rule->var), &t); @@ -1026,10 +1024,10 @@ static int rule_period_bytes(struct snd_pcm_hw_params *params, struct loopback_cable *cable = dpcm->cable; struct snd_interval t; - mutex_lock(&dpcm->loopback->cable_lock); - t.min = cable->hw.period_bytes_min; - t.max = cable->hw.period_bytes_max; - mutex_unlock(&dpcm->loopback->cable_lock); + scoped_guard(mutex, &dpcm->loopback->cable_lock) { + t.min = cable->hw.period_bytes_min; + t.max = cable->hw.period_bytes_max; + } t.openmin = 0; t.openmax = 0; t.integer = 0; @@ -1238,12 +1236,10 @@ static int loopback_open(struct snd_pcm_substream *substream) int err = 0; int dev = get_cable_index(substream); - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); - if (!dpcm) { - err = -ENOMEM; - goto unlock; - } + if (!dpcm) + return -ENOMEM; dpcm->loopback = loopback; dpcm->substream = substream; @@ -1326,7 +1322,6 @@ static int loopback_open(struct snd_pcm_substream *substream) free_cable(substream); kfree(dpcm); } - mutex_unlock(&loopback->cable_lock); return err; } @@ -1338,9 +1333,8 @@ static int loopback_close(struct snd_pcm_substream *substream) if (dpcm->cable->ops->close_substream) err = dpcm->cable->ops->close_substream(dpcm); - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); free_cable(substream); - mutex_unlock(&loopback->cable_lock); return err; } @@ -1391,11 +1385,10 @@ static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate_shift; - mutex_unlock(&loopback->cable_lock); return 0; } @@ -1411,14 +1404,13 @@ static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol, val = 80000; if (val > 120000) val = 120000; - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); if (val != loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate_shift) { loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate_shift = val; change = 1; } - mutex_unlock(&loopback->cable_lock); return change; } @@ -1427,11 +1419,10 @@ static int loopback_notify_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify; - mutex_unlock(&loopback->cable_lock); return 0; } @@ -1443,14 +1434,13 @@ static int loopback_notify_put(struct snd_kcontrol *kcontrol, int change = 0; val = ucontrol->value.integer.value[0] ? 1 : 0; - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); if (val != loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify) { loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify = val; change = 1; } - mutex_unlock(&loopback->cable_lock); return change; } @@ -1462,14 +1452,13 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol, unsigned int val = 0; - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1]; if (cable != NULL) { unsigned int running = cable->running ^ cable->pause; val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0; } - mutex_unlock(&loopback->cable_lock); ucontrol->value.integer.value[0] = val; return 0; } @@ -1512,11 +1501,10 @@ static int loopback_rate_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate; - mutex_unlock(&loopback->cable_lock); return 0; } @@ -1536,11 +1524,10 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].channels; - mutex_unlock(&loopback->cable_lock); return 0; } @@ -1558,12 +1545,11 @@ static int loopback_access_get(struct snd_kcontrol *kcontrol, struct loopback *loopback = snd_kcontrol_chip(kcontrol); snd_pcm_access_t access; - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); access = loopback->setup[kcontrol->id.subdevice][kcontrol->id.device].access; ucontrol->value.enumerated.item[0] = !is_access_interleaved(access); - mutex_unlock(&loopback->cable_lock); return 0; } @@ -1731,12 +1717,11 @@ static void print_cable_info(struct snd_info_entry *entry, struct loopback *loopback = entry->private_data; int sub, num; - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); num = entry->name[strlen(entry->name)-1]; num = num == '0' ? 0 : 1; for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++) print_substream_info(buffer, loopback, sub, num); - mutex_unlock(&loopback->cable_lock); } static int loopback_cable_proc_new(struct loopback *loopback, int cidx) @@ -1765,10 +1750,9 @@ static void print_timer_source_info(struct snd_info_entry *entry, { struct loopback *loopback = entry->private_data; - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); snd_iprintf(buffer, "%s\n", loopback->timer_source ? loopback->timer_source : ""); - mutex_unlock(&loopback->cable_lock); } static void change_timer_source_info(struct snd_info_entry *entry, @@ -1777,10 +1761,9 @@ static void change_timer_source_info(struct snd_info_entry *entry, struct loopback *loopback = entry->private_data; char line[64]; - mutex_lock(&loopback->cable_lock); + guard(mutex)(&loopback->cable_lock); if (!snd_info_get_line(buffer, line, sizeof(line))) loopback_set_timer_source(loopback, strim(line)); - mutex_unlock(&loopback->cable_lock); } static int loopback_timer_source_proc_new(struct loopback *loopback) From 1ef2cb6b29c2c9c26b490ab5a1e8161923fb7798 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:13 +0200 Subject: [PATCH 0991/1292] ALSA: aloop: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-3-tiwai@suse.de --- sound/drivers/aloop.c | 179 +++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 90 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 79e7f03e51e9cc..64ef03b2d579c9 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -414,39 +414,39 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) dpcm->last_jiffies = jiffies; dpcm->pcm_rate_shift = 0; dpcm->last_drift = 0; - spin_lock(&cable->lock); - cable->running |= stream; - cable->pause &= ~stream; - err = cable->ops->start(dpcm); - spin_unlock(&cable->lock); + scoped_guard(spinlock, &cable->lock) { + cable->running |= stream; + cable->pause &= ~stream; + err = cable->ops->start(dpcm); + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_STOP: - spin_lock(&cable->lock); - cable->running &= ~stream; - cable->pause &= ~stream; - err = cable->ops->stop(dpcm); - spin_unlock(&cable->lock); + scoped_guard(spinlock, &cable->lock) { + cable->running &= ~stream; + cable->pause &= ~stream; + err = cable->ops->stop(dpcm); + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - spin_lock(&cable->lock); - cable->pause |= stream; - err = cable->ops->stop(dpcm); - spin_unlock(&cable->lock); + scoped_guard(spinlock, &cable->lock) { + cable->pause |= stream; + err = cable->ops->stop(dpcm); + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: - spin_lock(&cable->lock); - dpcm->last_jiffies = jiffies; - cable->pause &= ~stream; - err = cable->ops->start(dpcm); - spin_unlock(&cable->lock); + scoped_guard(spinlock, &cable->lock) { + dpcm->last_jiffies = jiffies; + cable->pause &= ~stream; + err = cable->ops->start(dpcm); + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; @@ -700,21 +700,22 @@ static unsigned int loopback_jiffies_timer_pos_update static void loopback_jiffies_timer_function(struct timer_list *t) { struct loopback_pcm *dpcm = timer_container_of(dpcm, t, timer); - unsigned long flags; - - spin_lock_irqsave(&dpcm->cable->lock, flags); - if (loopback_jiffies_timer_pos_update(dpcm->cable) & - (1 << dpcm->substream->stream)) { - loopback_jiffies_timer_start(dpcm); - if (dpcm->period_update_pending) { - dpcm->period_update_pending = 0; - spin_unlock_irqrestore(&dpcm->cable->lock, flags); - /* need to unlock before calling below */ - snd_pcm_period_elapsed(dpcm->substream); - return; + bool period_elapsed = false; + + scoped_guard(spinlock_irqsave, &dpcm->cable->lock) { + if (loopback_jiffies_timer_pos_update(dpcm->cable) & + (1 << dpcm->substream->stream)) { + loopback_jiffies_timer_start(dpcm); + if (dpcm->period_update_pending) { + dpcm->period_update_pending = 0; + period_elapsed = true; + break; + } } } - spin_unlock_irqrestore(&dpcm->cable->lock, flags); + + if (period_elapsed) + snd_pcm_period_elapsed(dpcm->substream); } /* call in cable->lock */ @@ -759,68 +760,68 @@ static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable, struct snd_pcm_substream *substream_play, *substream_capt; struct snd_pcm_runtime *valid_runtime; unsigned int running, elapsed_bytes; - unsigned long flags; + bool xrun = false; - spin_lock_irqsave(&cable->lock, flags); - running = cable->running ^ cable->pause; - /* no need to do anything if no stream is running */ - if (!running) { - spin_unlock_irqrestore(&cable->lock, flags); - return; - } + scoped_guard(spinlock_irqsave, &cable->lock) { + running = cable->running ^ cable->pause; + /* no need to do anything if no stream is running */ + if (!running) + return; - dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; - dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; + dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; + dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; - if (event == SNDRV_TIMER_EVENT_MSTOP) { - if (!dpcm_play || - dpcm_play->substream->runtime->state != - SNDRV_PCM_STATE_DRAINING) { - spin_unlock_irqrestore(&cable->lock, flags); - return; + if (event == SNDRV_TIMER_EVENT_MSTOP) { + if (!dpcm_play || + dpcm_play->substream->runtime->state != + SNDRV_PCM_STATE_DRAINING) + return; } - } - substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? + substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? dpcm_play->substream : NULL; - substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ? + substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ? dpcm_capt->substream : NULL; - valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? - dpcm_play->substream->runtime : - dpcm_capt->substream->runtime; - - /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */ - if (event == SNDRV_TIMER_EVENT_TICK) { - /* The hardware rules guarantee that playback and capture period - * are the same. Therefore only one device has to be checked - * here. - */ - if (loopback_snd_timer_check_resolution(valid_runtime, - resolution) < 0) { - spin_unlock_irqrestore(&cable->lock, flags); - if (substream_play) - snd_pcm_stop_xrun(substream_play); - if (substream_capt) - snd_pcm_stop_xrun(substream_capt); - return; + valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? + dpcm_play->substream->runtime : + dpcm_capt->substream->runtime; + + /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */ + if (event == SNDRV_TIMER_EVENT_TICK) { + /* The hardware rules guarantee that playback and capture period + * are the same. Therefore only one device has to be checked + * here. + */ + if (loopback_snd_timer_check_resolution(valid_runtime, + resolution) < 0) { + xrun = true; + break; + } + } + + elapsed_bytes = frames_to_bytes(valid_runtime, + valid_runtime->period_size); + /* The same timer interrupt is used for playback and capture device */ + if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && + (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) { + copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes); + bytepos_finish(dpcm_play, elapsed_bytes); + bytepos_finish(dpcm_capt, elapsed_bytes); + } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { + bytepos_finish(dpcm_play, elapsed_bytes); + } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { + clear_capture_buf(dpcm_capt, elapsed_bytes); + bytepos_finish(dpcm_capt, elapsed_bytes); } } - elapsed_bytes = frames_to_bytes(valid_runtime, - valid_runtime->period_size); - /* The same timer interrupt is used for playback and capture device */ - if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && - (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) { - copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes); - bytepos_finish(dpcm_play, elapsed_bytes); - bytepos_finish(dpcm_capt, elapsed_bytes); - } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { - bytepos_finish(dpcm_play, elapsed_bytes); - } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { - clear_capture_buf(dpcm_capt, elapsed_bytes); - bytepos_finish(dpcm_capt, elapsed_bytes); + if (xrun) { + if (substream_play) + snd_pcm_stop_xrun(substream_play); + if (substream_capt) + snd_pcm_stop_xrun(substream_capt); + return; } - spin_unlock_irqrestore(&cable->lock, flags); if (substream_play) snd_pcm_period_elapsed(substream_play); @@ -909,11 +910,10 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) struct loopback_pcm *dpcm = runtime->private_data; snd_pcm_uframes_t pos; - spin_lock(&dpcm->cable->lock); + guard(spinlock)(&dpcm->cable->lock); if (dpcm->cable->ops->pos_update) dpcm->cable->ops->pos_update(dpcm->cable); pos = dpcm->buf_pos; - spin_unlock(&dpcm->cable->lock); return bytes_to_frames(runtime, pos); } @@ -1045,9 +1045,8 @@ static void free_cable(struct snd_pcm_substream *substream) return; if (cable->streams[!substream->stream]) { /* other stream is still alive */ - spin_lock_irq(&cable->lock); + guard(spinlock_irq)(&cable->lock); cable->streams[substream->stream] = NULL; - spin_unlock_irq(&cable->lock); } else { struct loopback_pcm *dpcm = substream->runtime->private_data; @@ -1313,9 +1312,9 @@ static int loopback_open(struct snd_pcm_substream *substream) else runtime->hw = cable->hw; - spin_lock_irq(&cable->lock); - cable->streams[substream->stream] = dpcm; - spin_unlock_irq(&cable->lock); + scoped_guard(spinlock_irq, &cable->lock) { + cable->streams[substream->stream] = dpcm; + } unlock: if (err < 0) { From 6a6da5ca9795d59f2e8b851f2b8d2ce8bc536c6e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:14 +0200 Subject: [PATCH 0992/1292] ALSA: opl3: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-4-tiwai@suse.de --- sound/drivers/opl3/opl3_seq.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index 9fc78b7fb78083..8db77a81476c00 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -40,13 +40,11 @@ int snd_opl3_synth_setup(struct snd_opl3 * opl3) int idx; struct snd_hwdep *hwdep = opl3->hwdep; - mutex_lock(&hwdep->open_mutex); - if (hwdep->used) { - mutex_unlock(&hwdep->open_mutex); - return -EBUSY; + scoped_guard(mutex, &hwdep->open_mutex) { + if (hwdep->used) + return -EBUSY; + hwdep->used++; } - hwdep->used++; - mutex_unlock(&hwdep->open_mutex); snd_opl3_reset(opl3); @@ -81,9 +79,9 @@ void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) snd_opl3_reset(opl3); hwdep = opl3->hwdep; - mutex_lock(&hwdep->open_mutex); - hwdep->used--; - mutex_unlock(&hwdep->open_mutex); + scoped_guard(mutex, &hwdep->open_mutex) { + hwdep->used--; + } wake_up(&hwdep->open_wait); } From ec6ac1d5e15a14e403630c5fbf8e41daf184ec83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:15 +0200 Subject: [PATCH 0993/1292] ALSA: opl3: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-5-tiwai@suse.de --- sound/drivers/opl3/opl3_lib.c | 26 ++++------------- sound/drivers/opl3/opl3_midi.c | 51 ++++++++++++---------------------- sound/drivers/opl3/opl3_seq.c | 11 ++++---- 3 files changed, 28 insertions(+), 60 deletions(-) diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index cd9642a6689b03..fa8a2ccbbd51ac 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -25,7 +25,6 @@ MODULE_LICENSE("GPL"); static void snd_opl2_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val) { - unsigned long flags; unsigned long port; /* @@ -35,20 +34,17 @@ static void snd_opl2_command(struct snd_opl3 * opl3, unsigned short cmd, unsigne port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port; - spin_lock_irqsave(&opl3->reg_lock, flags); + guard(spinlock_irqsave)(&opl3->reg_lock); outb((unsigned char) cmd, port); udelay(10); outb((unsigned char) val, port + 1); udelay(30); - - spin_unlock_irqrestore(&opl3->reg_lock, flags); } static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val) { - unsigned long flags; unsigned long port; /* @@ -58,7 +54,7 @@ static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigne port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port; - spin_lock_irqsave(&opl3->reg_lock, flags); + guard(spinlock_irqsave)(&opl3->reg_lock); outb((unsigned char) cmd, port); inb(opl3->l_port); @@ -67,8 +63,6 @@ static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigne outb((unsigned char) val, port + 1); inb(opl3->l_port); inb(opl3->l_port); - - spin_unlock_irqrestore(&opl3->reg_lock, flags); } static int snd_opl3_detect(struct snd_opl3 * opl3) @@ -142,34 +136,30 @@ static int snd_opl3_detect(struct snd_opl3 * opl3) static int snd_opl3_timer1_start(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; unsigned int ticks; struct snd_opl3 *opl3; opl3 = snd_timer_chip(timer); - spin_lock_irqsave(&opl3->timer_lock, flags); + guard(spinlock_irqsave)(&opl3->timer_lock); ticks = timer->sticks; tmp = (opl3->timer_enable | OPL3_TIMER1_START) & ~OPL3_TIMER1_MASK; opl3->timer_enable = tmp; opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 256 - ticks); /* timer 1 count */ opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* enable timer 1 IRQ */ - spin_unlock_irqrestore(&opl3->timer_lock, flags); return 0; } static int snd_opl3_timer1_stop(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; struct snd_opl3 *opl3; opl3 = snd_timer_chip(timer); - spin_lock_irqsave(&opl3->timer_lock, flags); + guard(spinlock_irqsave)(&opl3->timer_lock); tmp = (opl3->timer_enable | OPL3_TIMER1_MASK) & ~OPL3_TIMER1_START; opl3->timer_enable = tmp; opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* disable timer #1 */ - spin_unlock_irqrestore(&opl3->timer_lock, flags); return 0; } @@ -179,34 +169,30 @@ static int snd_opl3_timer1_stop(struct snd_timer * timer) static int snd_opl3_timer2_start(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; unsigned int ticks; struct snd_opl3 *opl3; opl3 = snd_timer_chip(timer); - spin_lock_irqsave(&opl3->timer_lock, flags); + guard(spinlock_irqsave)(&opl3->timer_lock); ticks = timer->sticks; tmp = (opl3->timer_enable | OPL3_TIMER2_START) & ~OPL3_TIMER2_MASK; opl3->timer_enable = tmp; opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER2, 256 - ticks); /* timer 1 count */ opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* enable timer 1 IRQ */ - spin_unlock_irqrestore(&opl3->timer_lock, flags); return 0; } static int snd_opl3_timer2_stop(struct snd_timer * timer) { - unsigned long flags; unsigned char tmp; struct snd_opl3 *opl3; opl3 = snd_timer_chip(timer); - spin_lock_irqsave(&opl3->timer_lock, flags); + guard(spinlock_irqsave)(&opl3->timer_lock); tmp = (opl3->timer_enable | OPL3_TIMER2_MASK) & ~OPL3_TIMER2_START; opl3->timer_enable = tmp; opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* disable timer #1 */ - spin_unlock_irqrestore(&opl3->timer_lock, flags); return 0; } diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index de7449cb6515f1..6d3c5b5a35ffc6 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c @@ -234,29 +234,27 @@ void snd_opl3_timer_func(struct timer_list *t) { struct snd_opl3 *opl3 = timer_container_of(opl3, t, tlist); - unsigned long flags; int again = 0; int i; - spin_lock_irqsave(&opl3->voice_lock, flags); - for (i = 0; i < opl3->max_voices; i++) { - struct snd_opl3_voice *vp = &opl3->voices[i]; - if (vp->state > 0 && vp->note_off_check) { - if (vp->note_off == jiffies) - snd_opl3_note_off_unsafe(opl3, vp->note, 0, - vp->chan); - else - again++; + scoped_guard(spinlock_irqsave, &opl3->voice_lock) { + for (i = 0; i < opl3->max_voices; i++) { + struct snd_opl3_voice *vp = &opl3->voices[i]; + if (vp->state > 0 && vp->note_off_check) { + if (vp->note_off == jiffies) + snd_opl3_note_off_unsafe(opl3, vp->note, 0, + vp->chan); + else + again++; + } } } - spin_unlock_irqrestore(&opl3->voice_lock, flags); - spin_lock_irqsave(&opl3->sys_timer_lock, flags); + guard(spinlock_irqsave)(&opl3->sys_timer_lock); if (again) mod_timer(&opl3->tlist, jiffies + 1); /* invoke again */ else opl3->sys_timer_status = 0; - spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); } /* @@ -264,13 +262,11 @@ void snd_opl3_timer_func(struct timer_list *t) */ static void snd_opl3_start_timer(struct snd_opl3 *opl3) { - unsigned long flags; - spin_lock_irqsave(&opl3->sys_timer_lock, flags); + guard(spinlock_irqsave)(&opl3->sys_timer_lock); if (! opl3->sys_timer_status) { mod_timer(&opl3->tlist, jiffies + 1); opl3->sys_timer_status = 1; } - spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); } /* ------------------------------ */ @@ -309,7 +305,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) struct fm_patch *patch; struct fm_instrument *fm; - unsigned long flags; opl3 = p; @@ -337,20 +332,17 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) prg = chan->midi_program; } - spin_lock_irqsave(&opl3->voice_lock, flags); + guard(spinlock_irqsave)(&opl3->voice_lock); if (use_internal_drums) { snd_opl3_drum_switch(opl3, note, vel, 1, chan); - spin_unlock_irqrestore(&opl3->voice_lock, flags); return; } __extra_prg: patch = snd_opl3_find_patch(opl3, prg, bank, 0); - if (!patch) { - spin_unlock_irqrestore(&opl3->voice_lock, flags); + if (!patch) return; - } fm = &patch->inst; switch (patch->type) { @@ -364,7 +356,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) } fallthrough; default: - spin_unlock_irqrestore(&opl3->voice_lock, flags); return; } opl3_dbg(opl3, " --> OPL%i instrument: %s\n", @@ -378,10 +369,8 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) voice = snd_opl3_oss_map[chan->number]; } - if (voice < 0) { - spin_unlock_irqrestore(&opl3->voice_lock, flags); + if (voice < 0) return; - } if (voice < MAX_OPL2_VOICES) { /* Left register block for voices 0 .. 8 */ @@ -597,7 +586,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) opl3_dbg(opl3, " *** allocating extra program\n"); goto __extra_prg; } - spin_unlock_irqrestore(&opl3->voice_lock, flags); } static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice) @@ -686,11 +674,9 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan) { struct snd_opl3 *opl3 = p; - unsigned long flags; - spin_lock_irqsave(&opl3->voice_lock, flags); + guard(spinlock_irqsave)(&opl3->voice_lock); snd_opl3_note_off_unsafe(p, note, vel, chan); - spin_unlock_irqrestore(&opl3->voice_lock, flags); } /* @@ -764,9 +750,7 @@ static void snd_opl3_pitch_ctrl(struct snd_opl3 *opl3, struct snd_midi_channel * int voice; struct snd_opl3_voice *vp; - unsigned long flags; - - spin_lock_irqsave(&opl3->voice_lock, flags); + guard(spinlock_irqsave)(&opl3->voice_lock); if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { for (voice = 0; voice < opl3->max_voices; voice++) { @@ -782,7 +766,6 @@ static void snd_opl3_pitch_ctrl(struct snd_opl3 *opl3, struct snd_midi_channel * snd_opl3_update_pitch(opl3, voice); } } - spin_unlock_irqrestore(&opl3->voice_lock, flags); } /* diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index 8db77a81476c00..d3278428d3604e 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -66,16 +66,15 @@ int snd_opl3_synth_setup(struct snd_opl3 * opl3) void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) { - unsigned long flags; struct snd_hwdep *hwdep; /* Stop system timer */ - spin_lock_irqsave(&opl3->sys_timer_lock, flags); - if (opl3->sys_timer_status) { - timer_delete(&opl3->tlist); - opl3->sys_timer_status = 0; + scoped_guard(spinlock_irq, &opl3->sys_timer_lock) { + if (opl3->sys_timer_status) { + timer_delete(&opl3->tlist); + opl3->sys_timer_status = 0; + } } - spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); snd_opl3_reset(opl3); hwdep = opl3->hwdep; From 45451eb5d16d817ab4acf65c137c34f6dd608842 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:16 +0200 Subject: [PATCH 0994/1292] ALSA: opl4: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-6-tiwai@suse.de --- sound/drivers/opl4/opl4_proc.c | 10 +++------- sound/drivers/opl4/opl4_seq.c | 30 ++++++++++++------------------ 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index f2149091e10aca..fd0ba4704d9fc2 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c @@ -14,13 +14,10 @@ static int snd_opl4_mem_proc_open(struct snd_info_entry *entry, { struct snd_opl4 *opl4 = entry->private_data; - mutex_lock(&opl4->access_mutex); - if (opl4->memory_access) { - mutex_unlock(&opl4->access_mutex); + guard(mutex)(&opl4->access_mutex); + if (opl4->memory_access) return -EBUSY; - } opl4->memory_access++; - mutex_unlock(&opl4->access_mutex); return 0; } @@ -29,9 +26,8 @@ static int snd_opl4_mem_proc_release(struct snd_info_entry *entry, { struct snd_opl4 *opl4 = entry->private_data; - mutex_lock(&opl4->access_mutex); + guard(mutex)(&opl4->access_mutex); opl4->memory_access--; - mutex_unlock(&opl4->access_mutex); return 0; } diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c index f59ca660c6164e..7bb22089a0934d 100644 --- a/sound/drivers/opl4/opl4_seq.c +++ b/sound/drivers/opl4/opl4_seq.c @@ -63,24 +63,18 @@ static int snd_opl4_seq_use(void *private_data, struct snd_seq_port_subscribe *i struct snd_opl4 *opl4 = private_data; int err; - mutex_lock(&opl4->access_mutex); - - if (opl4->used) { - mutex_unlock(&opl4->access_mutex); - return -EBUSY; - } - opl4->used++; - - if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) { - err = snd_opl4_seq_use_inc(opl4); - if (err < 0) { - mutex_unlock(&opl4->access_mutex); - return err; + scoped_guard(mutex, &opl4->access_mutex) { + if (opl4->used) + return -EBUSY; + opl4->used++; + + if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) { + err = snd_opl4_seq_use_inc(opl4); + if (err < 0) + return err; } } - mutex_unlock(&opl4->access_mutex); - snd_opl4_synth_reset(opl4); return 0; } @@ -91,9 +85,9 @@ static int snd_opl4_seq_unuse(void *private_data, struct snd_seq_port_subscribe snd_opl4_synth_shutdown(opl4); - mutex_lock(&opl4->access_mutex); - opl4->used--; - mutex_unlock(&opl4->access_mutex); + scoped_guard(mutex, &opl4->access_mutex) { + opl4->used--; + } if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) snd_opl4_seq_use_dec(opl4); From 72a3017077495a7dfacf1ef9ef83e92bbbd18244 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:17 +0200 Subject: [PATCH 0995/1292] ALSA: opl4: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-7-tiwai@suse.de --- sound/drivers/opl4/opl4_lib.c | 10 +--- sound/drivers/opl4/opl4_mixer.c | 8 +--- sound/drivers/opl4/opl4_synth.c | 81 ++++++++++++++------------------- 3 files changed, 39 insertions(+), 60 deletions(-) diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index ef6b2d533958a2..44fbc6bf0654f6 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -47,10 +47,9 @@ EXPORT_SYMBOL(snd_opl4_read); void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size) { - unsigned long flags; u8 memcfg; - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); memcfg = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION); snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg | OPL4_MODE_BIT); @@ -65,18 +64,15 @@ void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size insb(opl4->pcm_port + 1, buf, size); snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg); - - spin_unlock_irqrestore(&opl4->reg_lock, flags); } EXPORT_SYMBOL(snd_opl4_read_memory); void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, int size) { - unsigned long flags; u8 memcfg; - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); memcfg = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION); snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg | OPL4_MODE_BIT); @@ -91,8 +87,6 @@ void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, i outsb(opl4->pcm_port + 1, buf, size); snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg); - - spin_unlock_irqrestore(&opl4->reg_lock, flags); } EXPORT_SYMBOL(snd_opl4_write_memory); diff --git a/sound/drivers/opl4/opl4_mixer.c b/sound/drivers/opl4/opl4_mixer.c index fa1e6eff43ab5a..deebb8636437bf 100644 --- a/sound/drivers/opl4/opl4_mixer.c +++ b/sound/drivers/opl4/opl4_mixer.c @@ -19,13 +19,11 @@ static int snd_opl4_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ static int snd_opl4_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol); - unsigned long flags; u8 reg = kcontrol->private_value; u8 value; - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); value = snd_opl4_read(opl4, reg); - spin_unlock_irqrestore(&opl4->reg_lock, flags); ucontrol->value.integer.value[0] = 7 - (value & 7); ucontrol->value.integer.value[1] = 7 - ((value >> 3) & 7); return 0; @@ -34,16 +32,14 @@ static int snd_opl4_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v static int snd_opl4_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol); - unsigned long flags; u8 reg = kcontrol->private_value; u8 value, old_value; value = (7 - (ucontrol->value.integer.value[0] & 7)) | ((7 - (ucontrol->value.integer.value[1] & 7)) << 3); - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); old_value = snd_opl4_read(opl4, reg); snd_opl4_write(opl4, reg, value); - spin_unlock_irqrestore(&opl4->reg_lock, flags); return value != old_value; } diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c index 34e2bd52bba1b4..82dbb8519ab170 100644 --- a/sound/drivers/opl4/opl4_synth.c +++ b/sound/drivers/opl4/opl4_synth.c @@ -272,13 +272,12 @@ static const unsigned char snd_opl4_volume_table[128] = { */ void snd_opl4_synth_reset(struct snd_opl4 *opl4) { - unsigned long flags; int i; - spin_lock_irqsave(&opl4->reg_lock, flags); - for (i = 0; i < OPL4_MAX_VOICES; i++) - snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT); - spin_unlock_irqrestore(&opl4->reg_lock, flags); + scoped_guard(spinlock_irqsave, &opl4->reg_lock) { + for (i = 0; i < OPL4_MAX_VOICES; i++) + snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT); + } INIT_LIST_HEAD(&opl4->off_voices); INIT_LIST_HEAD(&opl4->on_voices); @@ -296,14 +295,12 @@ void snd_opl4_synth_reset(struct snd_opl4 *opl4) */ void snd_opl4_synth_shutdown(struct snd_opl4 *opl4) { - unsigned long flags; int i; - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); for (i = 0; i < OPL4_MAX_VOICES; i++) snd_opl4_write(opl4, OPL4_REG_MISC + i, opl4->voices[i].reg_misc & ~OPL4_KEY_ON_BIT); - spin_unlock_irqrestore(&opl4->reg_lock, flags); } /* @@ -313,17 +310,15 @@ static void snd_opl4_do_for_note(struct snd_opl4 *opl4, int note, struct snd_mid void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice)) { int i; - unsigned long flags; struct opl4_voice *voice; - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); for (i = 0; i < OPL4_MAX_VOICES; i++) { voice = &opl4->voices[i]; if (voice->chan == chan && voice->note == note) { func(opl4, voice); } } - spin_unlock_irqrestore(&opl4->reg_lock, flags); } /* @@ -334,17 +329,15 @@ static void snd_opl4_do_for_channel(struct snd_opl4 *opl4, void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice)) { int i; - unsigned long flags; struct opl4_voice *voice; - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); for (i = 0; i < OPL4_MAX_VOICES; i++) { voice = &opl4->voices[i]; if (voice->chan == chan) { func(opl4, voice); } } - spin_unlock_irqrestore(&opl4->reg_lock, flags); } /* @@ -354,16 +347,14 @@ static void snd_opl4_do_for_all(struct snd_opl4 *opl4, void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice)) { int i; - unsigned long flags; struct opl4_voice *voice; - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); for (i = 0; i < OPL4_MAX_VOICES; i++) { voice = &opl4->voices[i]; if (voice->chan) func(opl4, voice); } - spin_unlock_irqrestore(&opl4->reg_lock, flags); } static void snd_opl4_update_volume(struct snd_opl4 *opl4, struct opl4_voice *voice) @@ -486,7 +477,6 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha struct opl4_voice *voice[2]; const struct opl4_sound *sound[2]; int voices = 0, i; - unsigned long flags; /* determine the number of voices and voice parameters */ i = chan->drum_channel ? 0x80 : (chan->midi_program & 0x7f); @@ -501,41 +491,41 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha } /* allocate and initialize the needed voices */ - spin_lock_irqsave(&opl4->reg_lock, flags); - for (i = 0; i < voices; i++) { - voice[i] = snd_opl4_get_voice(opl4); - list_move_tail(&voice[i]->list, &opl4->on_voices); - voice[i]->chan = chan; - voice[i]->note = note; - voice[i]->velocity = vel & 0x7f; - voice[i]->sound = sound[i]; - } + scoped_guard(spinlock_irqsave, &opl4->reg_lock) { + for (i = 0; i < voices; i++) { + voice[i] = snd_opl4_get_voice(opl4); + list_move_tail(&voice[i]->list, &opl4->on_voices); + voice[i]->chan = chan; + voice[i]->note = note; + voice[i]->velocity = vel & 0x7f; + voice[i]->sound = sound[i]; + } - /* set tone number (triggers header loading) */ - for (i = 0; i < voices; i++) { - voice[i]->reg_f_number = - (sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8; - snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number, - voice[i]->reg_f_number); - snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number, - sound[i]->tone & 0xff); - } + /* set tone number (triggers header loading) */ + for (i = 0; i < voices; i++) { + voice[i]->reg_f_number = + (sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8; + snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number, + voice[i]->reg_f_number); + snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number, + sound[i]->tone & 0xff); + } - /* set parameters which can be set while loading */ - for (i = 0; i < voices; i++) { - voice[i]->reg_misc = OPL4_LFO_RESET_BIT; - snd_opl4_update_pan(opl4, voice[i]); - snd_opl4_update_pitch(opl4, voice[i]); - voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT; - snd_opl4_update_volume(opl4, voice[i]); + /* set parameters which can be set while loading */ + for (i = 0; i < voices; i++) { + voice[i]->reg_misc = OPL4_LFO_RESET_BIT; + snd_opl4_update_pan(opl4, voice[i]); + snd_opl4_update_pitch(opl4, voice[i]); + voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT; + snd_opl4_update_volume(opl4, voice[i]); + } } - spin_unlock_irqrestore(&opl4->reg_lock, flags); /* wait for completion of loading */ snd_opl4_wait_for_wave_headers(opl4); /* set remaining parameters */ - spin_lock_irqsave(&opl4->reg_lock, flags); + guard(spinlock_irqsave)(&opl4->reg_lock); for (i = 0; i < voices; i++) { snd_opl4_update_tone_parameters(opl4, voice[i]); voice[i]->reg_lfo_vibrato = voice[i]->sound->reg_lfo_vibrato; @@ -549,7 +539,6 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha snd_opl4_write(opl4, OPL4_REG_MISC + voice[i]->number, voice[i]->reg_misc); } - spin_unlock_irqrestore(&opl4->reg_lock, flags); } static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice) From 353fc3e3811aa577956940b04a4c540eb65a9992 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:18 +0200 Subject: [PATCH 0996/1292] ALSA: vx: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-8-tiwai@suse.de --- sound/drivers/vx/vx_core.c | 19 ++++--------- sound/drivers/vx/vx_mixer.c | 57 +++++++++++-------------------------- sound/drivers/vx/vx_pcm.c | 3 +- sound/drivers/vx/vx_uer.c | 17 +++++------ 4 files changed, 30 insertions(+), 66 deletions(-) diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 7f25fa7c04043c..52b93407bfe3b8 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -344,12 +344,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) */ int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh) { - int err; - - mutex_lock(&chip->lock); - err = vx_send_msg_nolock(chip, rmh); - mutex_unlock(&chip->lock); - return err; + guard(mutex)(&chip->lock); + return vx_send_msg_nolock(chip, rmh); } @@ -404,12 +400,8 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd) */ int vx_send_rih(struct vx_core *chip, int cmd) { - int err; - - mutex_lock(&chip->lock); - err = vx_send_rih_nolock(chip, cmd); - mutex_unlock(&chip->lock); - return err; + guard(mutex)(&chip->lock); + return vx_send_rih_nolock(chip, cmd); } #define END_OF_RESET_WAIT_TIME 500 /* us */ @@ -481,13 +473,12 @@ static int vx_test_irq_src(struct vx_core *chip, unsigned int *ret) int err; vx_init_rmh(&chip->irq_rmh, CMD_TEST_IT); - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); err = vx_send_msg_nolock(chip, &chip->irq_rmh); if (err < 0) *ret = 0; else *ret = chip->irq_rmh.Stat[0]; - mutex_unlock(&chip->lock); return err; } diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 0a51ecdc084a98..9dc5cecaa86a56 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -25,9 +25,8 @@ static void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int dat if (chip->chip_status & VX_STAT_IS_STALE) return; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); chip->ops->write_codec(chip, codec, data); - mutex_unlock(&chip->lock); } /* @@ -166,9 +165,8 @@ static void vx_change_audio_source(struct vx_core *chip, int src) if (chip->chip_status & VX_STAT_IS_STALE) return; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); chip->ops->change_audio_source(chip, src); - mutex_unlock(&chip->lock); } @@ -411,10 +409,10 @@ static int vx_output_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele { struct vx_core *chip = snd_kcontrol_chip(kcontrol); int codec = kcontrol->id.index; - mutex_lock(&chip->mixer_mutex); + + guard(mutex)(&chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->output_level[codec][0]; ucontrol->value.integer.value[1] = chip->output_level[codec][1]; - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -429,16 +427,14 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele val[1] = ucontrol->value.integer.value[1]; if (val[0] > vmax || val[1] > vmax) return -EINVAL; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (val[0] != chip->output_level[codec][0] || val[1] != chip->output_level[codec][1]) { vx_set_analog_output_level(chip, codec, val[0], val[1]); chip->output_level[codec][0] = val[0]; chip->output_level[codec][1] = val[1]; - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -490,14 +486,12 @@ static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v if (ucontrol->value.enumerated.item[0] > 1) return -EINVAL; } - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) { chip->audio_source_target = ucontrol->value.enumerated.item[0]; vx_sync_audio_source(chip); - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -534,14 +528,12 @@ static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ if (ucontrol->value.enumerated.item[0] > 2) return -EINVAL; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (chip->clock_mode != ucontrol->value.enumerated.item[0]) { chip->clock_mode = ucontrol->value.enumerated.item[0]; vx_set_clock(chip, chip->freq); - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -571,10 +563,9 @@ static int vx_audio_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ int audio = kcontrol->private_value & 0xff; int capture = (kcontrol->private_value >> 8) & 1; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->audio_gain[capture][audio]; ucontrol->value.integer.value[1] = chip->audio_gain[capture][audio+1]; - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -589,15 +580,13 @@ static int vx_audio_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ val[1] = ucontrol->value.integer.value[1]; if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) return -EINVAL; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (val[0] != chip->audio_gain[capture][audio] || val[1] != chip->audio_gain[capture][audio+1]) { vx_set_audio_gain(chip, audio, capture, val[0]); vx_set_audio_gain(chip, audio+1, capture, val[1]); - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -606,10 +595,9 @@ static int vx_audio_monitor_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el struct vx_core *chip = snd_kcontrol_chip(kcontrol); int audio = kcontrol->private_value & 0xff; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->audio_monitor[audio]; ucontrol->value.integer.value[1] = chip->audio_monitor[audio+1]; - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -624,17 +612,15 @@ static int vx_audio_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) return -EINVAL; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (val[0] != chip->audio_monitor[audio] || val[1] != chip->audio_monitor[audio+1]) { vx_set_monitor_level(chip, audio, val[0], chip->audio_monitor_active[audio]); vx_set_monitor_level(chip, audio+1, val[1], chip->audio_monitor_active[audio+1]); - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -645,10 +631,9 @@ static int vx_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va struct vx_core *chip = snd_kcontrol_chip(kcontrol); int audio = kcontrol->private_value & 0xff; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->audio_active[audio]; ucontrol->value.integer.value[1] = chip->audio_active[audio+1]; - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -657,17 +642,15 @@ static int vx_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va struct vx_core *chip = snd_kcontrol_chip(kcontrol); int audio = kcontrol->private_value & 0xff; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (ucontrol->value.integer.value[0] != chip->audio_active[audio] || ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) { vx_set_audio_switch(chip, audio, !!ucontrol->value.integer.value[0]); vx_set_audio_switch(chip, audio+1, !!ucontrol->value.integer.value[1]); - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -676,10 +659,9 @@ static int vx_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ struct vx_core *chip = snd_kcontrol_chip(kcontrol); int audio = kcontrol->private_value & 0xff; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); ucontrol->value.integer.value[0] = chip->audio_monitor_active[audio]; ucontrol->value.integer.value[1] = chip->audio_monitor_active[audio+1]; - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -688,17 +670,15 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ struct vx_core *chip = snd_kcontrol_chip(kcontrol); int audio = kcontrol->private_value & 0xff; - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] || ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) { vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], !!ucontrol->value.integer.value[0]); vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], !!ucontrol->value.integer.value[1]); - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -754,12 +734,11 @@ static int vx_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu { struct vx_core *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); ucontrol->value.iec958.status[0] = (chip->uer_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (chip->uer_bits >> 8) & 0xff; ucontrol->value.iec958.status[2] = (chip->uer_bits >> 16) & 0xff; ucontrol->value.iec958.status[3] = (chip->uer_bits >> 24) & 0xff; - mutex_unlock(&chip->mixer_mutex); return 0; } @@ -781,14 +760,12 @@ static int vx_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); - mutex_lock(&chip->mixer_mutex); + guard(mutex)(&chip->mixer_mutex); if (chip->uer_bits != val) { chip->uer_bits = val; vx_set_iec958_status(chip, val); - mutex_unlock(&chip->mixer_mutex); return 1; } - mutex_unlock(&chip->mixer_mutex); return 0; } diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index defc489494af75..7fd8f413d6cfcc 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -630,12 +630,11 @@ static int vx_pcm_playback_transfer_chunk(struct vx_core *chip, /* we don't need irqsave here, because this function * is called from either trigger callback or irq handler */ - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); vx_pseudo_dma_write(chip, runtime, pipe, size); err = vx_notify_end_of_buffer(chip, pipe); /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); - mutex_unlock(&chip->lock); return err; } diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c index 3eca22151225b5..1d90db3b0abd03 100644 --- a/sound/drivers/vx/vx_uer.c +++ b/sound/drivers/vx/vx_uer.c @@ -49,7 +49,7 @@ static int vx_read_one_cbit(struct vx_core *chip, int index) { int val; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); if (chip->type >= VX_TYPE_VXPOCKET) { vx_outb(chip, CSUER, 1); /* read */ vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); @@ -59,7 +59,6 @@ static int vx_read_one_cbit(struct vx_core *chip, int index) vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); val = (vx_inl(chip, RUER) >> 7) & 0x01; } - mutex_unlock(&chip->lock); return val; } @@ -71,7 +70,7 @@ static int vx_read_one_cbit(struct vx_core *chip, int index) static void vx_write_one_cbit(struct vx_core *chip, int index, int val) { val = !!val; /* 0 or 1 */ - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); if (vx_is_pcmcia(chip)) { vx_outb(chip, CSUER, 0); /* write */ vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); @@ -79,7 +78,6 @@ static void vx_write_one_cbit(struct vx_core *chip, int index, int val) vx_outl(chip, CSUER, 0); /* write */ vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); } - mutex_unlock(&chip->lock); } /* @@ -178,10 +176,10 @@ static void vx_change_clock_source(struct vx_core *chip, int source) { /* we mute DAC to prevent clicks */ vx_toggle_dac_mute(chip, 1); - mutex_lock(&chip->lock); - chip->ops->set_clock_source(chip, source); - chip->clock_source = source; - mutex_unlock(&chip->lock); + scoped_guard(mutex, &chip->lock) { + chip->ops->set_clock_source(chip, source); + chip->clock_source = source; + } /* unmute */ vx_toggle_dac_mute(chip, 0); } @@ -198,7 +196,7 @@ void vx_set_internal_clock(struct vx_core *chip, unsigned int freq) clock = vx_calc_clock_from_freq(chip, freq); dev_dbg(chip->card->dev, "set internal clock to 0x%x from freq %d\n", clock, freq); - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); if (vx_is_pcmcia(chip)) { vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f); vx_outb(chip, LOFREQ, clock & 0xff); @@ -206,7 +204,6 @@ void vx_set_internal_clock(struct vx_core *chip, unsigned int freq) vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f); vx_outl(chip, LOFREQ, clock & 0xff); } - mutex_unlock(&chip->lock); } From 638c33ef7923a0907ff907e18e2c87f0e7fcbd63 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:19 +0200 Subject: [PATCH 0997/1292] ALSA: dummy: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-9-tiwai@suse.de --- sound/drivers/dummy.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 6dac0b2523c11d..1860ff75fe159b 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -269,19 +269,19 @@ static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm) static int dummy_systimer_start(struct snd_pcm_substream *substream) { struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; - spin_lock(&dpcm->lock); + + guard(spinlock)(&dpcm->lock); dpcm->base_time = jiffies; dummy_systimer_rearm(dpcm); - spin_unlock(&dpcm->lock); return 0; } static int dummy_systimer_stop(struct snd_pcm_substream *substream) { struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; - spin_lock(&dpcm->lock); + + guard(spinlock)(&dpcm->lock); timer_delete(&dpcm->timer); - spin_unlock(&dpcm->lock); return 0; } @@ -303,15 +303,14 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) static void dummy_systimer_callback(struct timer_list *t) { struct dummy_systimer_pcm *dpcm = timer_container_of(dpcm, t, timer); - unsigned long flags; int elapsed = 0; - spin_lock_irqsave(&dpcm->lock, flags); - dummy_systimer_update(dpcm); - dummy_systimer_rearm(dpcm); - elapsed = dpcm->elapsed; - dpcm->elapsed = 0; - spin_unlock_irqrestore(&dpcm->lock, flags); + scoped_guard(spinlock_irqsave, &dpcm->lock) { + dummy_systimer_update(dpcm); + dummy_systimer_rearm(dpcm); + elapsed = dpcm->elapsed; + dpcm->elapsed = 0; + } if (elapsed) snd_pcm_period_elapsed(dpcm->substream); } @@ -320,13 +319,10 @@ static snd_pcm_uframes_t dummy_systimer_pointer(struct snd_pcm_substream *substream) { struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; - snd_pcm_uframes_t pos; - spin_lock(&dpcm->lock); + guard(spinlock)(&dpcm->lock); dummy_systimer_update(dpcm); - pos = dpcm->frac_pos / HZ; - spin_unlock(&dpcm->lock); - return pos; + return dpcm->frac_pos / HZ; } static int dummy_systimer_create(struct snd_pcm_substream *substream) @@ -724,10 +720,9 @@ static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol, struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); int addr = kcontrol->private_value; - spin_lock_irq(&dummy->mixer_lock); + guard(spinlock_irq)(&dummy->mixer_lock); ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0]; ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1]; - spin_unlock_irq(&dummy->mixer_lock); return 0; } @@ -748,12 +743,11 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, right = mixer_volume_level_min; if (right > mixer_volume_level_max) right = mixer_volume_level_max; - spin_lock_irq(&dummy->mixer_lock); + guard(spinlock_irq)(&dummy->mixer_lock); change = dummy->mixer_volume[addr][0] != left || dummy->mixer_volume[addr][1] != right; dummy->mixer_volume[addr][0] = left; dummy->mixer_volume[addr][1] = right; - spin_unlock_irq(&dummy->mixer_lock); return change; } @@ -773,10 +767,9 @@ static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol, struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); int addr = kcontrol->private_value; - spin_lock_irq(&dummy->mixer_lock); + guard(spinlock_irq)(&dummy->mixer_lock); ucontrol->value.integer.value[0] = dummy->capture_source[addr][0]; ucontrol->value.integer.value[1] = dummy->capture_source[addr][1]; - spin_unlock_irq(&dummy->mixer_lock); return 0; } @@ -788,12 +781,11 @@ static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el left = ucontrol->value.integer.value[0] & 1; right = ucontrol->value.integer.value[1] & 1; - spin_lock_irq(&dummy->mixer_lock); + guard(spinlock_irq)(&dummy->mixer_lock); change = dummy->capture_source[addr][0] != left && dummy->capture_source[addr][1] != right; dummy->capture_source[addr][0] = left; dummy->capture_source[addr][1] = right; - spin_unlock_irq(&dummy->mixer_lock); return change; } From 55c52cd3118bc400d7364945475f02e905ccca56 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:20 +0200 Subject: [PATCH 0998/1292] ALSA: mpu401: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-10-tiwai@suse.de --- sound/drivers/mpu401/mpu401_uart.c | 41 ++++++++---------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 670f8ba92c0843..4af89822bf32b8 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -81,27 +81,21 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu) static void uart_interrupt_tx(struct snd_mpu401 *mpu) { - unsigned long flags; - if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { - spin_lock_irqsave(&mpu->output_lock, flags); + guard(spinlock_irqsave)(&mpu->output_lock); snd_mpu401_uart_output_write(mpu); - spin_unlock_irqrestore(&mpu->output_lock, flags); } } static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) { - unsigned long flags; - if (mpu->info_flags & MPU401_INFO_INPUT) { - spin_lock_irqsave(&mpu->input_lock, flags); + guard(spinlock_irqsave)(&mpu->input_lock); if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) snd_mpu401_uart_input_read(mpu); else snd_mpu401_uart_clear_rx(mpu); - spin_unlock_irqrestore(&mpu->input_lock, flags); } if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) /* ok. for better Tx performance try do some output @@ -158,12 +152,11 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx); static void snd_mpu401_uart_timer(struct timer_list *t) { struct snd_mpu401 *mpu = timer_container_of(mpu, t, timer); - unsigned long flags; - spin_lock_irqsave(&mpu->timer_lock, flags); - /*mpu->mode |= MPU401_MODE_TIMER;*/ - mod_timer(&mpu->timer, 1 + jiffies); - spin_unlock_irqrestore(&mpu->timer_lock, flags); + scoped_guard(spinlock_irqsave, &mpu->timer_lock) { + /*mpu->mode |= MPU401_MODE_TIMER;*/ + mod_timer(&mpu->timer, 1 + jiffies); + } if (mpu->rmidi) _snd_mpu401_uart_interrupt(mpu); } @@ -173,16 +166,13 @@ static void snd_mpu401_uart_timer(struct timer_list *t) */ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) { - unsigned long flags; - - spin_lock_irqsave (&mpu->timer_lock, flags); + guard(spinlock_irqsave)(&mpu->timer_lock); if (mpu->timer_invoked == 0) { timer_setup(&mpu->timer, snd_mpu401_uart_timer, 0); mod_timer(&mpu->timer, 1 + jiffies); } mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : MPU401_MODE_OUTPUT_TIMER; - spin_unlock_irqrestore (&mpu->timer_lock, flags); } /* @@ -190,16 +180,13 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) */ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) { - unsigned long flags; - - spin_lock_irqsave (&mpu->timer_lock, flags); + guard(spinlock_irqsave)(&mpu->timer_lock); if (mpu->timer_invoked) { mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : ~MPU401_MODE_OUTPUT_TIMER; if (! mpu->timer_invoked) timer_delete(&mpu->timer); } - spin_unlock_irqrestore (&mpu->timer_lock, flags); } /* @@ -210,10 +197,9 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, int ack) { - unsigned long flags; int timeout, ok; - spin_lock_irqsave(&mpu->input_lock, flags); + guard(spinlock_irqsave)(&mpu->input_lock); if (mpu->hardware != MPU401_HW_TRID4DWAVE) { mpu->write(mpu, 0x00, MPU401D(mpu)); /*snd_mpu401_uart_clear_rx(mpu);*/ @@ -244,7 +230,6 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, ok = 1; } else ok = 1; - spin_unlock_irqrestore(&mpu->input_lock, flags); if (!ok) { dev_err(mpu->rmidi->dev, "cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", @@ -358,7 +343,6 @@ static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream) static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_mpu401 *mpu; int max = 64; @@ -374,9 +358,8 @@ snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) } /* read data in advance */ - spin_lock_irqsave(&mpu->input_lock, flags); + guard(spinlock_irqsave)(&mpu->input_lock); snd_mpu401_uart_input_read(mpu); - spin_unlock_irqrestore(&mpu->input_lock, flags); } else { if (mpu->info_flags & MPU401_INFO_USE_TIMER) snd_mpu401_uart_remove_timer(mpu, 1); @@ -445,7 +428,6 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_mpu401 *mpu; mpu = substream->rmidi->private_data; @@ -460,9 +442,8 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) snd_mpu401_uart_add_timer(mpu, 0); /* output pending data */ - spin_lock_irqsave(&mpu->output_lock, flags); + guard(spinlock_irqsave)(&mpu->output_lock); snd_mpu401_uart_output_write(mpu); - spin_unlock_irqrestore(&mpu->output_lock, flags); } else { if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) snd_mpu401_uart_remove_timer(mpu, 0); From 316e0074ecdc1f5723f69c12004bec31ca4cd276 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:21 +0200 Subject: [PATCH 0999/1292] ALSA: mtpav: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-11-tiwai@suse.de --- sound/drivers/mtpav.c | 61 +++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 91828f496738f6..d31eadf4be5f83 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -304,11 +304,9 @@ static void snd_mtpav_output_write(struct snd_rawmidi_substream *substream) { struct mtpav *mtp_card = substream->rmidi->private_data; struct mtpav_port *portp = &mtp_card->ports[substream->number]; - unsigned long flags; - spin_lock_irqsave(&mtp_card->spinlock, flags); + guard(spinlock_irqsave)(&mtp_card->spinlock); snd_mtpav_output_port_write(mtp_card, portp, substream); - spin_unlock_irqrestore(&mtp_card->spinlock, flags); } @@ -334,14 +332,12 @@ static int snd_mtpav_input_open(struct snd_rawmidi_substream *substream) { struct mtpav *mtp_card = substream->rmidi->private_data; struct mtpav_port *portp = &mtp_card->ports[substream->number]; - unsigned long flags; - spin_lock_irqsave(&mtp_card->spinlock, flags); + guard(spinlock_irqsave)(&mtp_card->spinlock); portp->mode |= MTPAV_MODE_INPUT_OPENED; portp->input = substream; if (mtp_card->share_irq++ == 0) snd_mtpav_mputreg(mtp_card, CREG, (SIGC_INTEN | SIGC_WRITE)); // enable pport interrupts - spin_unlock_irqrestore(&mtp_card->spinlock, flags); return 0; } @@ -352,14 +348,12 @@ static int snd_mtpav_input_close(struct snd_rawmidi_substream *substream) { struct mtpav *mtp_card = substream->rmidi->private_data; struct mtpav_port *portp = &mtp_card->ports[substream->number]; - unsigned long flags; - spin_lock_irqsave(&mtp_card->spinlock, flags); + guard(spinlock_irqsave)(&mtp_card->spinlock); portp->mode &= ~MTPAV_MODE_INPUT_OPENED; portp->input = NULL; if (--mtp_card->share_irq == 0) snd_mtpav_mputreg(mtp_card, CREG, 0); // disable pport interrupts - spin_unlock_irqrestore(&mtp_card->spinlock, flags); return 0; } @@ -370,15 +364,12 @@ static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int { struct mtpav *mtp_card = substream->rmidi->private_data; struct mtpav_port *portp = &mtp_card->ports[substream->number]; - unsigned long flags; - spin_lock_irqsave(&mtp_card->spinlock, flags); + guard(spinlock_irqsave)(&mtp_card->spinlock); if (up) portp->mode |= MTPAV_MODE_INPUT_TRIGGERED; else portp->mode &= ~MTPAV_MODE_INPUT_TRIGGERED; - spin_unlock_irqrestore(&mtp_card->spinlock, flags); - } @@ -388,11 +379,10 @@ static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int static void snd_mtpav_output_timer(struct timer_list *t) { - unsigned long flags; struct mtpav *chip = timer_container_of(chip, t, timer); int p; - spin_lock_irqsave(&chip->spinlock, flags); + guard(spinlock_irqsave)(&chip->spinlock); /* reprogram timer */ mod_timer(&chip->timer, 1 + jiffies); /* process each port */ @@ -401,7 +391,6 @@ static void snd_mtpav_output_timer(struct timer_list *t) if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED) && portp->output) snd_mtpav_output_port_write(chip, portp, portp->output); } - spin_unlock_irqrestore(&chip->spinlock, flags); } /* spinlock held! */ @@ -423,12 +412,10 @@ static int snd_mtpav_output_open(struct snd_rawmidi_substream *substream) { struct mtpav *mtp_card = substream->rmidi->private_data; struct mtpav_port *portp = &mtp_card->ports[substream->number]; - unsigned long flags; - spin_lock_irqsave(&mtp_card->spinlock, flags); + guard(spinlock_irqsave)(&mtp_card->spinlock); portp->mode |= MTPAV_MODE_OUTPUT_OPENED; portp->output = substream; - spin_unlock_irqrestore(&mtp_card->spinlock, flags); return 0; }; @@ -439,12 +426,10 @@ static int snd_mtpav_output_close(struct snd_rawmidi_substream *substream) { struct mtpav *mtp_card = substream->rmidi->private_data; struct mtpav_port *portp = &mtp_card->ports[substream->number]; - unsigned long flags; - spin_lock_irqsave(&mtp_card->spinlock, flags); + guard(spinlock_irqsave)(&mtp_card->spinlock); portp->mode &= ~MTPAV_MODE_OUTPUT_OPENED; portp->output = NULL; - spin_unlock_irqrestore(&mtp_card->spinlock, flags); return 0; }; @@ -455,21 +440,20 @@ static void snd_mtpav_output_trigger(struct snd_rawmidi_substream *substream, in { struct mtpav *mtp_card = substream->rmidi->private_data; struct mtpav_port *portp = &mtp_card->ports[substream->number]; - unsigned long flags; - - spin_lock_irqsave(&mtp_card->spinlock, flags); - if (up) { - if (! (portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED)) { - if (mtp_card->istimer++ == 0) - snd_mtpav_add_output_timer(mtp_card); - portp->mode |= MTPAV_MODE_OUTPUT_TRIGGERED; + + scoped_guard(spinlock_irqsave, &mtp_card->spinlock) { + if (up) { + if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED)) { + if (mtp_card->istimer++ == 0) + snd_mtpav_add_output_timer(mtp_card); + portp->mode |= MTPAV_MODE_OUTPUT_TRIGGERED; + } + } else { + portp->mode &= ~MTPAV_MODE_OUTPUT_TRIGGERED; + if (--mtp_card->istimer == 0) + snd_mtpav_remove_output_timer(mtp_card); } - } else { - portp->mode &= ~MTPAV_MODE_OUTPUT_TRIGGERED; - if (--mtp_card->istimer == 0) - snd_mtpav_remove_output_timer(mtp_card); } - spin_unlock_irqrestore(&mtp_card->spinlock, flags); if (up) snd_mtpav_output_write(substream); @@ -550,9 +534,8 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id) { struct mtpav *mcard = dev_id; - spin_lock(&mcard->spinlock); + guard(spinlock)(&mcard->spinlock); snd_mtpav_read_bytes(mcard); - spin_unlock(&mcard->spinlock); return IRQ_HANDLED; } @@ -658,12 +641,10 @@ static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard) static void snd_mtpav_free(struct snd_card *card) { struct mtpav *crd = card->private_data; - unsigned long flags; - spin_lock_irqsave(&crd->spinlock, flags); + guard(spinlock_irqsave)(&crd->spinlock); if (crd->istimer > 0) snd_mtpav_remove_output_timer(crd); - spin_unlock_irqrestore(&crd->spinlock, flags); } /* From a28d65886b9b80d93d939dd9f02e6e995b4febda Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:22 +0200 Subject: [PATCH 1000/1292] ALSA: mts64: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-12-tiwai@suse.de --- sound/drivers/mts64.c | 57 +++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index bbeebbe467eace..fe50b48c10e77a 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -432,9 +432,8 @@ static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl, { struct mts64 *mts = snd_kcontrol_chip(kctl); - spin_lock_irq(&mts->lock); + guard(spinlock_irq)(&mts->lock); uctl->value.integer.value[0] = mts->smpte_switch; - spin_unlock_irq(&mts->lock); return 0; } @@ -445,14 +444,12 @@ static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl, struct snd_ctl_elem_value *uctl) { struct mts64 *mts = snd_kcontrol_chip(kctl); - int changed = 0; int val = !!uctl->value.integer.value[0]; - spin_lock_irq(&mts->lock); + guard(spinlock_irq)(&mts->lock); if (mts->smpte_switch == val) - goto __out; + return 0; - changed = 1; mts->smpte_switch = val; if (mts->smpte_switch) { mts64_smpte_start(mts->pardev->port, @@ -462,9 +459,7 @@ static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl, } else { mts64_smpte_stop(mts->pardev->port); } -__out: - spin_unlock_irq(&mts->lock); - return changed; + return 1; } static const struct snd_kcontrol_new mts64_ctl_smpte_switch = { @@ -515,9 +510,8 @@ static int snd_mts64_ctl_smpte_time_get(struct snd_kcontrol *kctl, struct mts64 *mts = snd_kcontrol_chip(kctl); int idx = kctl->private_value; - spin_lock_irq(&mts->lock); + guard(spinlock_irq)(&mts->lock); uctl->value.integer.value[0] = mts->time[idx]; - spin_unlock_irq(&mts->lock); return 0; } @@ -528,16 +522,14 @@ static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl, struct mts64 *mts = snd_kcontrol_chip(kctl); int idx = kctl->private_value; unsigned int time = uctl->value.integer.value[0] % 60; - int changed = 0; - spin_lock_irq(&mts->lock); + guard(spinlock_irq)(&mts->lock); if (mts->time[idx] != time) { - changed = 1; mts->time[idx] = time; + return 1; } - spin_unlock_irq(&mts->lock); - return changed; + return 0; } static const struct snd_kcontrol_new mts64_ctl_smpte_time_hours = { @@ -600,9 +592,8 @@ static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl, { struct mts64 *mts = snd_kcontrol_chip(kctl); - spin_lock_irq(&mts->lock); + guard(spinlock_irq)(&mts->lock); uctl->value.enumerated.item[0] = mts->fps; - spin_unlock_irq(&mts->lock); return 0; } @@ -611,18 +602,16 @@ static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { struct mts64 *mts = snd_kcontrol_chip(kctl); - int changed = 0; if (uctl->value.enumerated.item[0] >= 5) return -EINVAL; - spin_lock_irq(&mts->lock); + guard(spinlock_irq)(&mts->lock); if (mts->fps != uctl->value.enumerated.item[0]) { - changed = 1; mts->fps = uctl->value.enumerated.item[0]; + return 1; } - spin_unlock_irq(&mts->lock); - return changed; + return 0; } static const struct snd_kcontrol_new mts64_ctl_smpte_fps = { @@ -687,15 +676,14 @@ static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) { struct mts64 *mts = substream->rmidi->private_data; - unsigned long flags; --(mts->open_count); if (mts->open_count == 0) { /* We need the spinlock_irqsave here because we can still have IRQs at this point */ - spin_lock_irqsave(&mts->lock, flags); - mts64_device_close(mts); - spin_unlock_irqrestore(&mts->lock, flags); + scoped_guard(spinlock_irqsave, &mts->lock) { + mts64_device_close(mts); + } msleep(500); @@ -710,29 +698,24 @@ static void snd_mts64_rawmidi_output_trigger(struct snd_rawmidi_substream *subst { struct mts64 *mts = substream->rmidi->private_data; u8 data; - unsigned long flags; - spin_lock_irqsave(&mts->lock, flags); + guard(spinlock_irqsave)(&mts->lock); while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) { mts64_write_midi(mts, data, substream->number+1); snd_rawmidi_transmit_ack(substream, 1); } - spin_unlock_irqrestore(&mts->lock, flags); } static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) { struct mts64 *mts = substream->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&mts->lock, flags); + guard(spinlock_irqsave)(&mts->lock); if (up) mts->mode[substream->number] |= MTS64_MODE_INPUT_TRIGGERED; else mts->mode[substream->number] &= ~MTS64_MODE_INPUT_TRIGGERED; - - spin_unlock_irqrestore(&mts->lock, flags); } static const struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = { @@ -819,7 +802,7 @@ static void snd_mts64_interrupt(void *private) if (!mts) return; - spin_lock(&mts->lock); + guard(spinlock)(&mts->lock); ret = mts64_read(mts->pardev->port); data = ret & 0x00ff; status = ret >> 8; @@ -828,13 +811,11 @@ static void snd_mts64_interrupt(void *private) mts->current_midi_input_port = mts64_map_midi_input(data); } else { if (mts->current_midi_input_port == -1) - goto __out; + return; substream = mts->midi_input_substream[mts->current_midi_input_port]; if (mts->mode[substream->number] & MTS64_MODE_INPUT_TRIGGERED) snd_rawmidi_receive(substream, &data, 1); } -__out: - spin_unlock(&mts->lock); } static void snd_mts64_attach(struct parport *p) From ec339e149e93779ef7ea4cd2fe6f61ea9e823cb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:23 +0200 Subject: [PATCH 1001/1292] ALSA: portman2x4: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-13-tiwai@suse.de --- sound/drivers/portman2x4.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index b4fa6625a3d674..b903a138fc2a42 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -496,29 +496,25 @@ static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substre int up) { struct portman *pm = substream->rmidi->private_data; - unsigned long flags; - spin_lock_irqsave(&pm->reg_lock, flags); + guard(spinlock_irqsave)(&pm->reg_lock); if (up) pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED; else pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED; - spin_unlock_irqrestore(&pm->reg_lock, flags); } static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct portman *pm = substream->rmidi->private_data; - unsigned long flags; unsigned char byte; - spin_lock_irqsave(&pm->reg_lock, flags); + guard(spinlock_irqsave)(&pm->reg_lock); if (up) { while ((snd_rawmidi_transmit(substream, &byte, 1) == 1)) portman_write_midi(pm, substream->number, byte); } - spin_unlock_irqrestore(&pm->reg_lock, flags); } static const struct snd_rawmidi_ops snd_portman_midi_output = { @@ -590,7 +586,7 @@ static void snd_portman_interrupt(void *userdata) unsigned char midivalue = 0; struct portman *pm = ((struct snd_card*)userdata)->private_data; - spin_lock(&pm->reg_lock); + guard(spinlock)(&pm->reg_lock); /* While any input data is waiting */ while ((portman_read_status(pm) & INT_REQ) == INT_REQ) { @@ -617,8 +613,6 @@ static void snd_portman_interrupt(void *userdata) } } - - spin_unlock(&pm->reg_lock); } static void snd_portman_attach(struct parport *p) From b9526bff42197cc83cdfb64e51822734180258d1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:00:24 +0200 Subject: [PATCH 1002/1292] ALSA: serial-u16550: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150026.6379-14-tiwai@suse.de --- sound/drivers/serial-u16550.c | 48 +++++++++++------------------------ 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 52772ccfc377b9..3c28961091b12e 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -281,29 +281,24 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) struct snd_uart16550 *uart; uart = dev_id; - spin_lock(&uart->open_lock); - if (uart->filemode == SERIAL_MODE_NOT_OPENED) { - spin_unlock(&uart->open_lock); + guard(spinlock)(&uart->open_lock); + if (uart->filemode == SERIAL_MODE_NOT_OPENED) return IRQ_NONE; - } /* indicate to the UART that the interrupt has been serviced */ inb(uart->base + UART_IIR); snd_uart16550_io_loop(uart); - spin_unlock(&uart->open_lock); return IRQ_HANDLED; } /* When the polling mode, this function calls snd_uart16550_io_loop. */ static void snd_uart16550_buffer_timer(struct timer_list *t) { - unsigned long flags; struct snd_uart16550 *uart; uart = timer_container_of(uart, t, buffer_timer); - spin_lock_irqsave(&uart->open_lock, flags); + guard(spinlock_irqsave)(&uart->open_lock); snd_uart16550_del_timer(uart); snd_uart16550_io_loop(uart); - spin_unlock_irqrestore(&uart->open_lock, flags); } /* @@ -499,71 +494,61 @@ static void snd_uart16550_do_close(struct snd_uart16550 * uart) static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_uart16550 *uart = substream->rmidi->private_data; - spin_lock_irqsave(&uart->open_lock, flags); + guard(spinlock_irqsave)(&uart->open_lock); if (uart->filemode == SERIAL_MODE_NOT_OPENED) snd_uart16550_do_open(uart); uart->filemode |= SERIAL_MODE_INPUT_OPEN; uart->midi_input[substream->number] = substream; - spin_unlock_irqrestore(&uart->open_lock, flags); return 0; } static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_uart16550 *uart = substream->rmidi->private_data; - spin_lock_irqsave(&uart->open_lock, flags); + guard(spinlock_irqsave)(&uart->open_lock); uart->filemode &= ~SERIAL_MODE_INPUT_OPEN; uart->midi_input[substream->number] = NULL; if (uart->filemode == SERIAL_MODE_NOT_OPENED) snd_uart16550_do_close(uart); - spin_unlock_irqrestore(&uart->open_lock, flags); return 0; } static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_uart16550 *uart = substream->rmidi->private_data; - spin_lock_irqsave(&uart->open_lock, flags); + guard(spinlock_irqsave)(&uart->open_lock); if (up) uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED; else uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED; - spin_unlock_irqrestore(&uart->open_lock, flags); } static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_uart16550 *uart = substream->rmidi->private_data; - spin_lock_irqsave(&uart->open_lock, flags); + guard(spinlock_irqsave)(&uart->open_lock); if (uart->filemode == SERIAL_MODE_NOT_OPENED) snd_uart16550_do_open(uart); uart->filemode |= SERIAL_MODE_OUTPUT_OPEN; uart->midi_output[substream->number] = substream; - spin_unlock_irqrestore(&uart->open_lock, flags); return 0; }; static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) { - unsigned long flags; struct snd_uart16550 *uart = substream->rmidi->private_data; - spin_lock_irqsave(&uart->open_lock, flags); + guard(spinlock_irqsave)(&uart->open_lock); uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN; uart->midi_output[substream->number] = NULL; if (uart->filemode == SERIAL_MODE_NOT_OPENED) snd_uart16550_do_close(uart); - spin_unlock_irqrestore(&uart->open_lock, flags); return 0; }; @@ -632,7 +617,6 @@ static int snd_uart16550_output_byte(struct snd_uart16550 *uart, static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) { - unsigned long flags; unsigned char midi_byte, addr_byte; struct snd_uart16550 *uart = substream->rmidi->private_data; char first; @@ -643,7 +627,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) * variables (ie buff_in & buff_out) */ - spin_lock_irqsave(&uart->open_lock, flags); + guard(spinlock_irqsave)(&uart->open_lock); if (uart->irq < 0) /* polling */ snd_uart16550_io_loop(uart); @@ -718,21 +702,19 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) } lasttime = jiffies; } - spin_unlock_irqrestore(&uart->open_lock, flags); } static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct snd_uart16550 *uart = substream->rmidi->private_data; - spin_lock_irqsave(&uart->open_lock, flags); - if (up) - uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED; - else - uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED; - spin_unlock_irqrestore(&uart->open_lock, flags); + scoped_guard(spinlock_irqsave, &uart->open_lock) { + if (up) + uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED; + else + uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED; + } if (up) snd_uart16550_output_write(substream); } From 9b99749f2a892e5d92cf985d6a12121e58aa4c50 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:09 +0200 Subject: [PATCH 1003/1292] ALSA: ua101: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-2-tiwai@suse.de --- sound/usb/misc/ua101.c | 85 +++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 51 deletions(-) diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index e200e4af799c2f..1c4a266018bb0a 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -658,11 +658,10 @@ static int capture_pcm_open(struct snd_pcm_substream *substream) DIV_ROUND_CLOSEST(ua->rate, ua->packets_per_second); substream->runtime->delay = substream->runtime->hw.fifo_size; - mutex_lock(&ua->mutex); + guard(mutex)(&ua->mutex); err = start_usb_capture(ua); if (err >= 0) set_bit(ALSA_CAPTURE_OPEN, &ua->states); - mutex_unlock(&ua->mutex); return err; } @@ -679,31 +678,28 @@ static int playback_pcm_open(struct snd_pcm_substream *substream) DIV_ROUND_CLOSEST(ua->rate * ua->playback.queue_length, ua->packets_per_second); - mutex_lock(&ua->mutex); + guard(mutex)(&ua->mutex); err = start_usb_capture(ua); if (err < 0) - goto error; + return err; err = start_usb_playback(ua); if (err < 0) { if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) stop_usb_capture(ua); - goto error; + return err; } set_bit(ALSA_PLAYBACK_OPEN, &ua->states); -error: - mutex_unlock(&ua->mutex); - return err; + return 0; } static int capture_pcm_close(struct snd_pcm_substream *substream) { struct ua101 *ua = substream->private_data; - mutex_lock(&ua->mutex); + guard(mutex)(&ua->mutex); clear_bit(ALSA_CAPTURE_OPEN, &ua->states); if (!test_bit(ALSA_PLAYBACK_OPEN, &ua->states)) stop_usb_capture(ua); - mutex_unlock(&ua->mutex); return 0; } @@ -711,12 +707,11 @@ static int playback_pcm_close(struct snd_pcm_substream *substream) { struct ua101 *ua = substream->private_data; - mutex_lock(&ua->mutex); + guard(mutex)(&ua->mutex); stop_usb_playback(ua); clear_bit(ALSA_PLAYBACK_OPEN, &ua->states); if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) stop_usb_capture(ua); - mutex_unlock(&ua->mutex); return 0; } @@ -724,12 +719,9 @@ static int capture_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct ua101 *ua = substream->private_data; - int err; - mutex_lock(&ua->mutex); - err = start_usb_capture(ua); - mutex_unlock(&ua->mutex); - return err; + guard(mutex)(&ua->mutex); + return start_usb_capture(ua); } static int playback_pcm_hw_params(struct snd_pcm_substream *substream, @@ -738,11 +730,10 @@ static int playback_pcm_hw_params(struct snd_pcm_substream *substream, struct ua101 *ua = substream->private_data; int err; - mutex_lock(&ua->mutex); + guard(mutex)(&ua->mutex); err = start_usb_capture(ua); if (err >= 0) err = start_usb_playback(ua); - mutex_unlock(&ua->mutex); return err; } @@ -751,9 +742,9 @@ static int capture_pcm_prepare(struct snd_pcm_substream *substream) struct ua101 *ua = substream->private_data; int err; - mutex_lock(&ua->mutex); - err = start_usb_capture(ua); - mutex_unlock(&ua->mutex); + scoped_guard(mutex, &ua->mutex) { + err = start_usb_capture(ua); + } if (err < 0) return err; @@ -781,11 +772,11 @@ static int playback_pcm_prepare(struct snd_pcm_substream *substream) struct ua101 *ua = substream->private_data; int err; - mutex_lock(&ua->mutex); - err = start_usb_capture(ua); - if (err >= 0) - err = start_usb_playback(ua); - mutex_unlock(&ua->mutex); + scoped_guard(mutex, &ua->mutex) { + err = start_usb_capture(ua); + if (err >= 0) + err = start_usb_playback(ua); + } if (err < 0) return err; @@ -1127,18 +1118,18 @@ static void free_usb_related_resources(struct ua101 *ua, unsigned int i; struct usb_interface *intf; - mutex_lock(&ua->mutex); - free_stream_urbs(&ua->capture); - free_stream_urbs(&ua->playback); - mutex_unlock(&ua->mutex); + scoped_guard(mutex, &ua->mutex) { + free_stream_urbs(&ua->capture); + free_stream_urbs(&ua->playback); + } free_stream_buffers(ua, &ua->capture); free_stream_buffers(ua, &ua->playback); for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) { - mutex_lock(&ua->mutex); - intf = ua->intf[i]; - ua->intf[i] = NULL; - mutex_unlock(&ua->mutex); + scoped_guard(mutex, &ua->mutex) { + intf = ua->intf[i]; + ua->intf[i] = NULL; + } if (intf) { usb_set_intfdata(intf, NULL); if (intf != interface) @@ -1192,22 +1183,18 @@ static int ua101_probe(struct usb_interface *interface, intf_numbers[is_ua1000][0]) return -ENODEV; - mutex_lock(&devices_mutex); + guard(mutex)(&devices_mutex); for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) if (enable[card_index] && !(devices_used & (1 << card_index))) break; - if (card_index >= SNDRV_CARDS) { - mutex_unlock(&devices_mutex); + if (card_index >= SNDRV_CARDS) return -ENOENT; - } err = snd_card_new(&interface->dev, index[card_index], id[card_index], THIS_MODULE, sizeof(*ua), &card); - if (err < 0) { - mutex_unlock(&devices_mutex); + if (err < 0) return err; - } card->private_free = ua101_card_free; ua = card->private_data; ua->dev = interface_to_usbdev(interface); @@ -1290,13 +1277,11 @@ static int ua101_probe(struct usb_interface *interface, usb_set_intfdata(interface, ua); devices_used |= 1 << card_index; - mutex_unlock(&devices_mutex); return 0; probe_error: free_usb_related_resources(ua, interface); snd_card_free(card); - mutex_unlock(&devices_mutex); return err; } @@ -1308,7 +1293,7 @@ static void ua101_disconnect(struct usb_interface *interface) if (!ua) return; - mutex_lock(&devices_mutex); + guard(mutex)(&devices_mutex); set_bit(DISCONNECTED, &ua->states); wake_up(&ua->rate_feedback_wait); @@ -1321,18 +1306,16 @@ static void ua101_disconnect(struct usb_interface *interface) snd_usbmidi_disconnect(midi); abort_alsa_playback(ua); abort_alsa_capture(ua); - mutex_lock(&ua->mutex); - stop_usb_playback(ua); - stop_usb_capture(ua); - mutex_unlock(&ua->mutex); + scoped_guard(mutex, &ua->mutex) { + stop_usb_playback(ua); + stop_usb_capture(ua); + } free_usb_related_resources(ua, interface); devices_used &= ~(1 << ua->card_index); snd_card_free_when_closed(ua->card); - - mutex_unlock(&devices_mutex); } static const struct usb_device_id ua101_ids[] = { From f9435abeb3eee14854d8a7769a626bc983e70d68 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:10 +0200 Subject: [PATCH 1004/1292] ALSA: ua101: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-3-tiwai@suse.de --- sound/usb/misc/ua101.c | 171 +++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 91 deletions(-) diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 1c4a266018bb0a..76b6eb55dcc221 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -171,7 +171,6 @@ static void playback_urb_complete(struct urb *usb_urb) { struct ua101_urb *urb = (struct ua101_urb *)usb_urb; struct ua101 *ua = urb->urb.context; - unsigned long flags; if (unlikely(urb->urb.status == -ENOENT || /* unlinked */ urb->urb.status == -ENODEV || /* device removed */ @@ -184,14 +183,13 @@ static void playback_urb_complete(struct urb *usb_urb) if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) { /* append URB to FIFO */ - spin_lock_irqsave(&ua->lock, flags); + guard(spinlock_irqsave)(&ua->lock); list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); if (ua->rate_feedback_count > 0) queue_work(system_highpri_wq, &ua->playback_work); ua->playback.substream->runtime->delay -= urb->urb.iso_frame_desc[0].length / ua->playback.frame_bytes; - spin_unlock_irqrestore(&ua->lock, flags); } } @@ -249,7 +247,6 @@ static inline void add_with_wraparound(struct ua101 *ua, static void playback_work(struct work_struct *work) { struct ua101 *ua = container_of(work, struct ua101, playback_work); - unsigned long flags; unsigned int frames; struct ua101_urb *urb; bool do_period_elapsed = false; @@ -269,43 +266,43 @@ static void playback_work(struct work_struct *work) * submitting playback URBs is possible as long as both FIFOs are * nonempty. */ - spin_lock_irqsave(&ua->lock, flags); - while (ua->rate_feedback_count > 0 && - !list_empty(&ua->ready_playback_urbs)) { - /* take packet size out of FIFO */ - frames = ua->rate_feedback[ua->rate_feedback_start]; - add_with_wraparound(ua, &ua->rate_feedback_start, 1); - ua->rate_feedback_count--; - - /* take URB out of FIFO */ - urb = list_first_entry(&ua->ready_playback_urbs, - struct ua101_urb, ready_list); - list_del(&urb->ready_list); - - /* fill packet with data or silence */ - urb->urb.iso_frame_desc[0].length = - frames * ua->playback.frame_bytes; - if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) - do_period_elapsed |= copy_playback_data(&ua->playback, - &urb->urb, - frames); - else - memset(urb->urb.transfer_buffer, 0, - urb->urb.iso_frame_desc[0].length); - - /* and off you go ... */ - err = usb_submit_urb(&urb->urb, GFP_ATOMIC); - if (unlikely(err < 0)) { - spin_unlock_irqrestore(&ua->lock, flags); - abort_usb_playback(ua); - abort_alsa_playback(ua); - dev_err(&ua->dev->dev, "USB request error %d: %s\n", - err, usb_error_string(err)); - return; + scoped_guard(spinlock_irqsave, &ua->lock) { + while (ua->rate_feedback_count > 0 && + !list_empty(&ua->ready_playback_urbs)) { + /* take packet size out of FIFO */ + frames = ua->rate_feedback[ua->rate_feedback_start]; + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + ua->rate_feedback_count--; + + /* take URB out of FIFO */ + urb = list_first_entry(&ua->ready_playback_urbs, + struct ua101_urb, ready_list); + list_del(&urb->ready_list); + + /* fill packet with data or silence */ + urb->urb.iso_frame_desc[0].length = + frames * ua->playback.frame_bytes; + if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) + do_period_elapsed |= copy_playback_data(&ua->playback, + &urb->urb, + frames); + else + memset(urb->urb.transfer_buffer, 0, + urb->urb.iso_frame_desc[0].length); + + /* and off you go ... */ + err = usb_submit_urb(&urb->urb, GFP_ATOMIC); + if (unlikely(err < 0)) { + abort_usb_playback(ua); + abort_alsa_playback(ua); + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + return; + } + ua->playback.substream->runtime->delay += frames; } - ua->playback.substream->runtime->delay += frames; } - spin_unlock_irqrestore(&ua->lock, flags); + if (do_period_elapsed) snd_pcm_period_elapsed(ua->playback.substream); } @@ -347,7 +344,6 @@ static void capture_urb_complete(struct urb *urb) { struct ua101 *ua = urb->context; struct ua101_stream *stream = &ua->capture; - unsigned long flags; unsigned int frames, write_ptr; bool do_period_elapsed; int err; @@ -364,47 +360,45 @@ static void capture_urb_complete(struct urb *urb) else frames = 0; - spin_lock_irqsave(&ua->lock, flags); - - if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) - do_period_elapsed = copy_capture_data(stream, urb, frames); - else - do_period_elapsed = false; + scoped_guard(spinlock_irqsave, &ua->lock) { - if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err < 0)) { - spin_unlock_irqrestore(&ua->lock, flags); - dev_err(&ua->dev->dev, "USB request error %d: %s\n", - err, usb_error_string(err)); - goto stream_stopped; - } + if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) + do_period_elapsed = copy_capture_data(stream, urb, frames); + else + do_period_elapsed = false; + + if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err < 0)) { + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + goto stream_stopped; + } - /* append packet size to FIFO */ - write_ptr = ua->rate_feedback_start; - add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count); - ua->rate_feedback[write_ptr] = frames; - if (ua->rate_feedback_count < ua->playback.queue_length) { - ua->rate_feedback_count++; - if (ua->rate_feedback_count == - ua->playback.queue_length) - wake_up(&ua->rate_feedback_wait); - } else { - /* - * Ring buffer overflow; this happens when the playback - * stream is not running. Throw away the oldest entry, - * so that the playback stream, when it starts, sees - * the most recent packet sizes. - */ - add_with_wraparound(ua, &ua->rate_feedback_start, 1); + /* append packet size to FIFO */ + write_ptr = ua->rate_feedback_start; + add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count); + ua->rate_feedback[write_ptr] = frames; + if (ua->rate_feedback_count < ua->playback.queue_length) { + ua->rate_feedback_count++; + if (ua->rate_feedback_count == + ua->playback.queue_length) + wake_up(&ua->rate_feedback_wait); + } else { + /* + * Ring buffer overflow; this happens when the playback + * stream is not running. Throw away the oldest entry, + * so that the playback stream, when it starts, sees + * the most recent packet sizes. + */ + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + } + if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) && + !list_empty(&ua->ready_playback_urbs)) + queue_work(system_highpri_wq, &ua->playback_work); } - if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) && - !list_empty(&ua->ready_playback_urbs)) - queue_work(system_highpri_wq, &ua->playback_work); } - spin_unlock_irqrestore(&ua->lock, flags); - if (do_period_elapsed) snd_pcm_period_elapsed(stream->substream); @@ -558,9 +552,9 @@ static int start_usb_playback(struct ua101 *ua) clear_bit(PLAYBACK_URB_COMPLETED, &ua->states); ua->playback.urbs[0]->urb.complete = first_playback_urb_complete; - spin_lock_irq(&ua->lock); - INIT_LIST_HEAD(&ua->ready_playback_urbs); - spin_unlock_irq(&ua->lock); + scoped_guard(spinlock_irq, &ua->lock) { + INIT_LIST_HEAD(&ua->ready_playback_urbs); + } /* * We submit the initial URBs all at once, so we have to wait for the @@ -581,11 +575,11 @@ static int start_usb_playback(struct ua101 *ua) for (i = 0; i < ua->playback.queue_length; ++i) { /* all initial URBs contain silence */ - spin_lock_irq(&ua->lock); - frames = ua->rate_feedback[ua->rate_feedback_start]; - add_with_wraparound(ua, &ua->rate_feedback_start, 1); - ua->rate_feedback_count--; - spin_unlock_irq(&ua->lock); + scoped_guard(spinlock_irq, &ua->lock) { + frames = ua->rate_feedback[ua->rate_feedback_start]; + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + ua->rate_feedback_count--; + } urb = &ua->playback.urbs[i]->urb; urb->iso_frame_desc[0].length = frames * ua->playback.frame_bytes; @@ -834,13 +828,8 @@ static int playback_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static inline snd_pcm_uframes_t ua101_pcm_pointer(struct ua101 *ua, struct ua101_stream *stream) { - unsigned long flags; - unsigned int pos; - - spin_lock_irqsave(&ua->lock, flags); - pos = stream->buffer_pos; - spin_unlock_irqrestore(&ua->lock, flags); - return pos; + guard(spinlock_irqsave)(&ua->lock); + return stream->buffer_pos; } static snd_pcm_uframes_t capture_pcm_pointer(struct snd_pcm_substream *subs) From 9e38c362a6d8b69e8760ff5e5614362b09a1b30e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:11 +0200 Subject: [PATCH 1005/1292] ALSA: usx2y: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-4-tiwai@suse.de --- sound/usb/usx2y/us122l.c | 44 +++++++++++---------------------- sound/usb/usx2y/usbusx2yaudio.c | 23 ++++++----------- sound/usb/usx2y/usx2yhwdeppcm.c | 33 +++++++++---------------- 3 files changed, 35 insertions(+), 65 deletions(-) diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 8dbbefe3e7306b..011ea96e977998 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -97,10 +97,10 @@ static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf) struct us122l *us122l = vmf->vma->vm_private_data; struct usb_stream *s; - mutex_lock(&us122l->mutex); + guard(mutex)(&us122l->mutex); s = us122l->sk.s; if (!s) - goto unlock; + return VM_FAULT_SIGBUS; offset = vmf->pgoff << PAGE_SHIFT; if (offset < PAGE_ALIGN(s->read_size)) { @@ -108,21 +108,17 @@ static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf) } else { offset -= PAGE_ALIGN(s->read_size); if (offset >= PAGE_ALIGN(s->write_size)) - goto unlock; + return VM_FAULT_SIGBUS; vaddr = us122l->sk.write_page + offset; } page = virt_to_page(vaddr); get_page(page); - mutex_unlock(&us122l->mutex); vmf->page = page; return 0; -unlock: - mutex_unlock(&us122l->mutex); - return VM_FAULT_SIGBUS; } @@ -163,12 +159,11 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) usb_autopm_put_interface(iface); if (us122l->first == file) us122l->first = NULL; - mutex_lock(&us122l->mutex); + guard(mutex)(&us122l->mutex); if (us122l->master == file) us122l->master = us122l->slave; us122l->slave = NULL; - mutex_unlock(&us122l->mutex); return 0; } @@ -179,23 +174,19 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw, struct us122l *us122l = hw->private_data; unsigned long offset; struct usb_stream *s; - int err = 0; bool read; offset = area->vm_pgoff << PAGE_SHIFT; - mutex_lock(&us122l->mutex); + guard(mutex)(&us122l->mutex); s = us122l->sk.s; read = offset < s->read_size; - if (read && area->vm_flags & VM_WRITE) { - err = -EPERM; - goto out; - } + if (read && area->vm_flags & VM_WRITE) + return -EPERM; /* if userspace tries to mmap beyond end of our buffer, fail */ if (size > PAGE_ALIGN(read ? s->read_size : s->write_size)) { dev_warn(hw->card->dev, "%s: size %lu > %u\n", __func__, size, read ? s->read_size : s->write_size); - err = -EINVAL; - goto out; + return -EINVAL; } area->vm_ops = &usb_stream_hwdep_vm_ops; @@ -203,9 +194,7 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw, if (!read) vm_flags_set(area, VM_DONTEXPAND); area->vm_private_data = us122l; -out: - mutex_unlock(&us122l->mutex); - return err; + return 0; } static __poll_t usb_stream_hwdep_poll(struct snd_hwdep *hw, @@ -361,7 +350,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, snd_power_wait(hw->card); - mutex_lock(&us122l->mutex); + guard(mutex)(&us122l->mutex); s = us122l->sk.s; if (!us122l->master) { us122l->master = file; @@ -381,7 +370,6 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, err = 1; } unlock: - mutex_unlock(&us122l->mutex); wake_up_all(&us122l->sk.sleep); return err; } @@ -577,9 +565,9 @@ static void snd_us122l_disconnect(struct usb_interface *intf) snd_card_disconnect(card); us122l = US122L(card); - mutex_lock(&us122l->mutex); - us122l_stop(us122l); - mutex_unlock(&us122l->mutex); + scoped_guard(mutex, &us122l->mutex) { + us122l_stop(us122l); + } /* release the midi resources */ list_for_each(p, &us122l->midi_list) { @@ -611,9 +599,8 @@ static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); - mutex_lock(&us122l->mutex); + guard(mutex)(&us122l->mutex); usb_stream_stop(&us122l->sk); - mutex_unlock(&us122l->mutex); return 0; } @@ -633,7 +620,7 @@ static int snd_us122l_resume(struct usb_interface *intf) if (!us122l) return 0; - mutex_lock(&us122l->mutex); + guard(mutex)(&us122l->mutex); /* needed, doesn't restart without: */ if (us122l->is_us144) { err = usb_set_interface(us122l->dev, 0, 1); @@ -664,7 +651,6 @@ static int snd_us122l_resume(struct usb_interface *intf) list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); unlock: - mutex_unlock(&us122l->mutex); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return err; } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index acca8bead82e5b..c7c7ec9c228b4f 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -751,7 +751,6 @@ static int usx2y_format_set(struct usx2ydev *usx2y, snd_pcm_format_t format) static int snd_usx2y_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - int err = 0; unsigned int rate = params_rate(hw_params); snd_pcm_format_t format = params_format(hw_params); struct snd_card *card = substream->pstr->pcm->card; @@ -760,7 +759,7 @@ static int snd_usx2y_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_substream *test_substream; int i; - mutex_lock(&usx2y(card)->pcm_mutex); + guard(mutex)(&usx2y(card)->pcm_mutex); dev_dbg(&dev->dev->dev, "%s(%p, %p)\n", __func__, substream, hw_params); /* all pcm substreams off one usx2y have to operate at the same * rate & format @@ -777,14 +776,11 @@ static int snd_usx2y_pcm_hw_params(struct snd_pcm_substream *substream, test_substream->runtime->format != format) || (test_substream->runtime->rate && test_substream->runtime->rate != rate)) { - err = -EINVAL; - goto error; + return -EINVAL; } } - error: - mutex_unlock(&usx2y(card)->pcm_mutex); - return err; + return 0; } /* @@ -796,7 +792,7 @@ static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_usx2y_substream *subs = runtime->private_data; struct snd_usx2y_substream *cap_subs, *playback_subs; - mutex_lock(&subs->usx2y->pcm_mutex); + guard(mutex)(&subs->usx2y->pcm_mutex); dev_dbg(&subs->usx2y->dev->dev, "%s(%p)\n", __func__, substream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -816,7 +812,6 @@ static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream) usx2y_urbs_release(subs); } } - mutex_unlock(&subs->usx2y->pcm_mutex); return 0; } @@ -835,7 +830,7 @@ static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(&usx2y->dev->dev, "%s(%p)\n", __func__, substream); - mutex_lock(&usx2y->pcm_mutex); + guard(mutex)(&usx2y->pcm_mutex); usx2y_subs_prepare(subs); // Start hardware streams // SyncStream first.... @@ -843,25 +838,23 @@ static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream) if (usx2y->format != runtime->format) { err = usx2y_format_set(usx2y, runtime->format); if (err < 0) - goto up_prepare_mutex; + return err; } if (usx2y->rate != runtime->rate) { err = usx2y_rate_set(usx2y, runtime->rate); if (err < 0) - goto up_prepare_mutex; + return err; } dev_dbg(&usx2y->dev->dev, "%s: starting capture pipe for %s\n", __func__, subs == capsubs ? "self" : "playpipe"); err = usx2y_urbs_start(capsubs); if (err < 0) - goto up_prepare_mutex; + return err; } if (subs != capsubs && atomic_read(&subs->state) < STATE_PREPARED) err = usx2y_urbs_start(subs); - up_prepare_mutex: - mutex_unlock(&usx2y->pcm_mutex); return err; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 1b1496adb47eb2..7c90214485d970 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -365,7 +365,7 @@ static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream) struct snd_usx2y_substream *playback_subs; struct snd_usx2y_substream *cap_subs2; - mutex_lock(&subs->usx2y->pcm_mutex); + guard(mutex)(&subs->usx2y->pcm_mutex); dev_dbg(&subs->usx2y->dev->dev, "%s(%p)\n", __func__, substream); cap_subs2 = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; @@ -394,7 +394,6 @@ static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream) usx2y_usbpcm_urbs_release(cap_subs2); } } - mutex_unlock(&subs->usx2y->pcm_mutex); return 0; } @@ -504,15 +503,13 @@ static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream) dev_dbg(&usx2y->dev->dev, "snd_usx2y_pcm_prepare(%p)\n", substream); - mutex_lock(&usx2y->pcm_mutex); + guard(mutex)(&usx2y->pcm_mutex); if (!usx2y->hwdep_pcm_shm) { usx2y->hwdep_pcm_shm = alloc_pages_exact(USX2Y_HWDEP_PCM_PAGES, GFP_KERNEL); - if (!usx2y->hwdep_pcm_shm) { - err = -ENOMEM; - goto up_prepare_mutex; - } + if (!usx2y->hwdep_pcm_shm) + return -ENOMEM; memset(usx2y->hwdep_pcm_shm, 0, USX2Y_HWDEP_PCM_PAGES); } @@ -523,19 +520,19 @@ static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream) if (usx2y->format != runtime->format) { err = usx2y_format_set(usx2y, runtime->format); if (err < 0) - goto up_prepare_mutex; + return err; } if (usx2y->rate != runtime->rate) { err = usx2y_rate_set(usx2y, runtime->rate); if (err < 0) - goto up_prepare_mutex; + return err; } dev_dbg(&usx2y->dev->dev, "starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe"); err = usx2y_usbpcm_urbs_start(capsubs); if (err < 0) - goto up_prepare_mutex; + return err; } if (subs != capsubs) { @@ -547,14 +544,12 @@ static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream) "Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usx2y_iso_frames_per_buffer(runtime, usx2y), usx2y->hwdep_pcm_shm->captured_iso_frames); - if (msleep_interruptible(10)) { - err = -ERESTARTSYS; - goto up_prepare_mutex; - } + if (msleep_interruptible(10)) + return -ERESTARTSYS; } err = usx2y_usbpcm_urbs_start(subs); if (err < 0) - goto up_prepare_mutex; + return err; } dev_dbg(&usx2y->dev->dev, "Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", @@ -564,8 +559,6 @@ static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream) usx2y->hwdep_pcm_shm->capture_iso_start = -1; } - up_prepare_mutex: - mutex_unlock(&usx2y->pcm_mutex); return err; } @@ -646,11 +639,10 @@ static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file) struct snd_card *card = hw->card; int err; - mutex_lock(&usx2y(card)->pcm_mutex); + guard(mutex)(&usx2y(card)->pcm_mutex); err = usx2y_pcms_busy_check(card); if (!err) usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS; - mutex_unlock(&usx2y(card)->pcm_mutex); return err; } @@ -659,11 +651,10 @@ static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file) struct snd_card *card = hw->card; int err; - mutex_lock(&usx2y(card)->pcm_mutex); + guard(mutex)(&usx2y(card)->pcm_mutex); err = usx2y_pcms_busy_check(card); if (!err) usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS; - mutex_unlock(&usx2y(card)->pcm_mutex); return err; } From 07f55c77b922b21009e12b3bb70c8ef0e07b0eb0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:12 +0200 Subject: [PATCH 1006/1292] ALSA: hiface: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-5-tiwai@suse.de --- sound/usb/hiface/chip.c | 11 +++-------- sound/usb/hiface/pcm.c | 25 +++++++------------------ 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c index 95385e90882c74..bce28f6836661d 100644 --- a/sound/usb/hiface/chip.c +++ b/sound/usb/hiface/chip.c @@ -101,7 +101,7 @@ static int hiface_chip_probe(struct usb_interface *intf, /* check whether the card is already registered */ chip = NULL; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); for (i = 0; i < SNDRV_CARDS; i++) if (enable[i]) @@ -109,13 +109,12 @@ static int hiface_chip_probe(struct usb_interface *intf, if (i >= SNDRV_CARDS) { dev_err(&device->dev, "no available " CARD_NAME " audio device\n"); - ret = -ENODEV; - goto err; + return -ENODEV; } ret = hiface_chip_create(intf, device, i, quirk, &chip); if (ret < 0) - goto err; + return ret; ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0); if (ret < 0) @@ -127,15 +126,11 @@ static int hiface_chip_probe(struct usb_interface *intf, goto err_chip_destroy; } - mutex_unlock(®ister_mutex); - usb_set_intfdata(intf, chip); return 0; err_chip_destroy: snd_card_free(chip->card); -err: - mutex_unlock(®ister_mutex); return ret; } diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index cf650fab54d7e2..f992e94feb64cd 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -356,7 +356,7 @@ static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) if (rt->panic) return -EPIPE; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); alsa_rt->hw = pcm_hw; if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -364,7 +364,6 @@ static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) if (!sub) { struct device *device = &rt->chip->dev->dev; - mutex_unlock(&rt->stream_mutex); dev_err(device, "Invalid stream type\n"); return -EINVAL; } @@ -377,15 +376,12 @@ static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) ret = snd_pcm_hw_constraint_list(alsa_sub->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_extra_rates); - if (ret < 0) { - mutex_unlock(&rt->stream_mutex); + if (ret < 0) return ret; - } } sub->instance = alsa_sub; sub->active = false; - mutex_unlock(&rt->stream_mutex); return 0; } @@ -398,7 +394,7 @@ static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) if (rt->panic) return 0; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); if (sub) { hiface_pcm_stream_stop(rt); @@ -409,7 +405,6 @@ static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) spin_unlock_irqrestore(&sub->lock, flags); } - mutex_unlock(&rt->stream_mutex); return 0; } @@ -425,7 +420,7 @@ static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) if (!sub) return -ENODEV; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); hiface_pcm_stream_stop(rt); @@ -435,17 +430,12 @@ static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) if (rt->stream_state == STREAM_DISABLED) { ret = hiface_pcm_set_rate(rt, alsa_rt->rate); - if (ret) { - mutex_unlock(&rt->stream_mutex); + if (ret) return ret; - } ret = hiface_pcm_stream_start(rt); - if (ret) { - mutex_unlock(&rt->stream_mutex); + if (ret) return ret; - } } - mutex_unlock(&rt->stream_mutex); return 0; } @@ -532,9 +522,8 @@ void hiface_pcm_abort(struct hiface_chip *chip) if (rt) { rt->panic = true; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); hiface_pcm_stream_stop(rt); - mutex_unlock(&rt->stream_mutex); } } From ea3bfbbc9a28c6ede618a97af31d99f36d4050e6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:13 +0200 Subject: [PATCH 1007/1292] ALSA: hiface: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-6-tiwai@suse.de --- sound/usb/hiface/pcm.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index f992e94feb64cd..27cd427fbaa566 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -305,7 +305,6 @@ static void hiface_pcm_out_urb_handler(struct urb *usb_urb) struct pcm_runtime *rt = out_urb->chip->pcm; struct pcm_substream *sub; bool do_period_elapsed = false; - unsigned long flags; int ret; if (rt->panic || rt->stream_state == STREAM_STOPPING) @@ -325,13 +324,12 @@ static void hiface_pcm_out_urb_handler(struct urb *usb_urb) /* now send our playback data (if a free out urb was found) */ sub = &rt->playback; - spin_lock_irqsave(&sub->lock, flags); - if (sub->active) - do_period_elapsed = hiface_pcm_playback(sub, out_urb); - else - memset(out_urb->buffer, 0, PCM_PACKET_SIZE); - - spin_unlock_irqrestore(&sub->lock, flags); + scoped_guard(spinlock_irqsave, &sub->lock) { + if (sub->active) + do_period_elapsed = hiface_pcm_playback(sub, out_urb); + else + memset(out_urb->buffer, 0, PCM_PACKET_SIZE); + } if (do_period_elapsed) snd_pcm_period_elapsed(sub->instance); @@ -389,7 +387,6 @@ static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) { struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); - unsigned long flags; if (rt->panic) return 0; @@ -399,11 +396,9 @@ static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) hiface_pcm_stream_stop(rt); /* deactivate substream */ - spin_lock_irqsave(&sub->lock, flags); + guard(spinlock_irqsave)(&sub->lock); sub->instance = NULL; sub->active = false; - spin_unlock_irqrestore(&sub->lock, flags); - } return 0; } @@ -452,16 +447,16 @@ static int hiface_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - spin_lock_irq(&sub->lock); - sub->active = true; - spin_unlock_irq(&sub->lock); + scoped_guard(spinlock_irq, &sub->lock) { + sub->active = true; + } return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irq(&sub->lock); - sub->active = false; - spin_unlock_irq(&sub->lock); + scoped_guard(spinlock_irq, &sub->lock) { + sub->active = false; + } return 0; default: @@ -473,15 +468,13 @@ static snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub) { struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); - unsigned long flags; snd_pcm_uframes_t dma_offset; if (rt->panic || !sub) return SNDRV_PCM_POS_XRUN; - spin_lock_irqsave(&sub->lock, flags); + guard(spinlock_irqsave)(&sub->lock); dma_offset = sub->dma_off; - spin_unlock_irqrestore(&sub->lock, flags); return bytes_to_frames(alsa_sub->runtime, dma_offset); } From 6dcbb0a9a6b50f5cb1c9cbb88914be98777b26a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:14 +0200 Subject: [PATCH 1008/1292] ALSA: line6: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. The core code of line6_pcm_release() is factored out, so that it can be covered by guard() nicely, too. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-7-tiwai@suse.de --- sound/usb/line6/driver.c | 8 ++---- sound/usb/line6/pcm.c | 58 ++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index f2f9261489a214..c505c1cba16233 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -628,16 +628,12 @@ line6_hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count, static __poll_t line6_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { - __poll_t rv; struct usb_line6 *line6 = hwdep->private_data; poll_wait(file, &line6->messages.wait_queue, wait); - mutex_lock(&line6->messages.read_lock); - rv = kfifo_len(&line6->messages.fifo) == 0 ? 0 : EPOLLIN | EPOLLRDNORM; - mutex_unlock(&line6->messages.read_lock); - - return rv; + guard(mutex)(&line6->messages.read_lock); + return kfifo_len(&line6->messages.fifo) == 0 ? 0 : EPOLLIN | EPOLLRDNORM; } static const struct snd_hwdep_ops hwdep_ops = { diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index c1e2a8ab66fac5..81e6d5e05135ad 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -295,6 +295,28 @@ snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream) return pstr->pos_done; } +/* Stop and release duplex streams */ +static void __line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) +{ + struct line6_pcm_stream *pstr; + int dir; + + for (dir = 0; dir < 2; dir++) + line6_stream_stop(line6pcm, dir, type); + for (dir = 0; dir < 2; dir++) { + pstr = get_stream(line6pcm, dir); + line6_buffer_release(line6pcm, pstr, type); + } +} + +/* Stop and release duplex streams */ +void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) +{ + guard(mutex)(&line6pcm->state_mutex); + __line6_pcm_release(line6pcm, type); +} +EXPORT_SYMBOL_GPL(line6_pcm_release); + /* Acquire and optionally start duplex streams: * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR */ @@ -304,7 +326,7 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start) int ret = 0, dir; /* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */ - mutex_lock(&line6pcm->state_mutex); + guard(mutex)(&line6pcm->state_mutex); for (dir = 0; dir < 2; dir++) { pstr = get_stream(line6pcm, dir); ret = line6_buffer_acquire(line6pcm, pstr, dir, type); @@ -321,30 +343,12 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start) } } error: - mutex_unlock(&line6pcm->state_mutex); if (ret < 0) - line6_pcm_release(line6pcm, type); + __line6_pcm_release(line6pcm, type); return ret; } EXPORT_SYMBOL_GPL(line6_pcm_acquire); -/* Stop and release duplex streams */ -void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) -{ - struct line6_pcm_stream *pstr; - int dir; - - mutex_lock(&line6pcm->state_mutex); - for (dir = 0; dir < 2; dir++) - line6_stream_stop(line6pcm, dir, type); - for (dir = 0; dir < 2; dir++) { - pstr = get_stream(line6pcm, dir); - line6_buffer_release(line6pcm, pstr, type); - } - mutex_unlock(&line6pcm->state_mutex); -} -EXPORT_SYMBOL_GPL(line6_pcm_release); - /* common PCM hw_params callback */ int snd_line6_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) @@ -353,16 +357,14 @@ int snd_line6_hw_params(struct snd_pcm_substream *substream, struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); - mutex_lock(&line6pcm->state_mutex); + guard(mutex)(&line6pcm->state_mutex); ret = line6_buffer_acquire(line6pcm, pstr, substream->stream, LINE6_STREAM_PCM); if (ret < 0) - goto error; + return ret; pstr->period = params_period_bytes(hw_params); - error: - mutex_unlock(&line6pcm->state_mutex); - return ret; + return 0; } /* common PCM hw_free callback */ @@ -371,9 +373,8 @@ int snd_line6_hw_free(struct snd_pcm_substream *substream) struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); - mutex_lock(&line6pcm->state_mutex); + guard(mutex)(&line6pcm->state_mutex); line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); - mutex_unlock(&line6pcm->state_mutex); return 0; } @@ -588,7 +589,7 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); - mutex_lock(&line6pcm->state_mutex); + guard(mutex)(&line6pcm->state_mutex); if (!pstr->running) line6_wait_clear_audio_urbs(line6pcm, pstr); @@ -602,6 +603,5 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) line6pcm->in.bytes = 0; } - mutex_unlock(&line6pcm->state_mutex); return 0; } From e5d3eeb4261a3a288b427201b9a97e4aa8159a3e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:15 +0200 Subject: [PATCH 1009/1292] ALSA: usb: qcom: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. The manual mutex lock/unlock are still left in handle_uaudio_stream_req() and its callee as they have a bit complex locking patterns. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-8-tiwai@suse.de --- sound/usb/qcom/qc_audio_offload.c | 69 ++++++++++--------------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c index 965ddc792acc3f..a17fb63f605e6b 100644 --- a/sound/usb/qcom/qc_audio_offload.c +++ b/sound/usb/qcom/qc_audio_offload.c @@ -744,7 +744,7 @@ static void qmi_stop_session(void) int if_idx; int idx; - mutex_lock(&qdev_mutex); + guard(mutex)(&qdev_mutex); /* find all active intf for set alt 0 and cleanup usb audio dev */ for (idx = 0; idx < SNDRV_CARDS; idx++) { if (!atomic_read(&uadev[idx].in_use)) @@ -780,11 +780,9 @@ static void qmi_stop_session(void) disable_audio_stream(subs); } atomic_set(&uadev[idx].in_use, 0); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); uaudio_dev_cleanup(&uadev[idx]); - mutex_unlock(&chip->mutex); } - mutex_unlock(&qdev_mutex); } /** @@ -810,8 +808,8 @@ static int uaudio_sideband_notifier(struct usb_interface *intf, chip = usb_get_intfdata(intf); - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); dev = &uadev[chip->card->number]; @@ -825,9 +823,6 @@ static int uaudio_sideband_notifier(struct usb_interface *intf, } } - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); - return 0; } @@ -1577,17 +1572,15 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, goto response; } - mutex_lock(&chip->mutex); - if (req_msg->enable) { - if (info_idx < 0 || chip->system_suspend || subs->opened) { - ret = -EBUSY; - mutex_unlock(&chip->mutex); - - goto response; + scoped_guard(mutex, &chip->mutex) { + if (req_msg->enable) { + if (info_idx < 0 || chip->system_suspend || subs->opened) { + ret = -EBUSY; + goto response; + } + subs->opened = 1; } - subs->opened = 1; } - mutex_unlock(&chip->mutex); if (req_msg->service_interval_valid) { ret = get_data_interval_from_si(subs, @@ -1610,9 +1603,8 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, ret = prepare_qmi_response(subs, req_msg, &resp, info_idx); if (ret < 0) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); subs->opened = 0; - mutex_unlock(&chip->mutex); } } else { info = &uadev[pcm_card_num].info[info_idx]; @@ -1643,14 +1635,13 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, } disable_audio_stream(subs); - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); subs->opened = 0; - mutex_unlock(&chip->mutex); } response: if (!req_msg->enable && ret != -EINVAL && ret != -ENODEV) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (info_idx >= 0) { info = &uadev[pcm_card_num].info[info_idx]; uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, @@ -1659,7 +1650,6 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, if (atomic_read(&uadev[pcm_card_num].in_use)) kref_put(&uadev[pcm_card_num].kref, uaudio_dev_release); - mutex_unlock(&chip->mutex); } mutex_unlock(&qdev_mutex); @@ -1762,12 +1752,12 @@ static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) !usb_qmi_get_pcm_num(chip, 0)) return; - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); if (!uadev[chip->card->number].chip) { sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); if (!sdev) - goto exit; + return; sb = xhci_sideband_register(intf, XHCI_SIDEBAND_VENDOR, uaudio_sideband_notifier); @@ -1806,9 +1796,6 @@ static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) snd_soc_usb_connect(uaudio_qdev->auxdev->dev.parent, sdev); } - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); - return; unreg_xhci: @@ -1818,9 +1805,6 @@ static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) kfree(sdev); uadev[chip->card->number].sdev = NULL; uadev[chip->card->number].chip = NULL; -exit: - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); } /** @@ -1856,16 +1840,13 @@ static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip) if (card_num >= SNDRV_CARDS) return; - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); dev = &uadev[card_num]; /* Device has already been cleaned up, or never populated */ - if (!dev->chip) { - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); + if (!dev->chip) return; - } /* cleaned up already */ if (!dev->udev) @@ -1886,9 +1867,6 @@ static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip) kfree(dev->sdev); dev->sdev = NULL; } - mutex_unlock(&chip->mutex); - - mutex_unlock(&qdev_mutex); } /** @@ -1913,13 +1891,10 @@ static void qc_usb_audio_offload_suspend(struct usb_interface *intf, if (card_num >= SNDRV_CARDS) return; - mutex_lock(&qdev_mutex); - mutex_lock(&chip->mutex); + guard(mutex)(&qdev_mutex); + guard(mutex)(&chip->mutex); uaudio_send_disconnect_ind(chip); - - mutex_unlock(&chip->mutex); - mutex_unlock(&qdev_mutex); } static struct snd_usb_platform_ops offload_ops = { From cff7acfe0b8f80653726d31741ca111d56cdbc38 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:16 +0200 Subject: [PATCH 1010/1292] ALSA: bcd2000: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-9-tiwai@suse.de --- sound/usb/bcd2000/bcd2000.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index 392b4d8e9e7696..bebb48cb9abc8c 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -369,23 +369,19 @@ static int bcd2000_probe(struct usb_interface *interface, char usb_path[32]; int err; - mutex_lock(&devices_mutex); + guard(mutex)(&devices_mutex); for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) if (!test_bit(card_index, devices_used)) break; - if (card_index >= SNDRV_CARDS) { - mutex_unlock(&devices_mutex); + if (card_index >= SNDRV_CARDS) return -ENOENT; - } err = snd_card_new(&interface->dev, index[card_index], id[card_index], THIS_MODULE, sizeof(*bcd2k), &card); - if (err < 0) { - mutex_unlock(&devices_mutex); + if (err < 0) return err; - } bcd2k = card->private_data; bcd2k->dev = interface_to_usbdev(interface); @@ -413,14 +409,12 @@ static int bcd2000_probe(struct usb_interface *interface, usb_set_intfdata(interface, bcd2k); set_bit(card_index, devices_used); - mutex_unlock(&devices_mutex); return 0; probe_error: dev_info(&bcd2k->dev->dev, PREFIX "error during probing"); bcd2000_free_usb_related_resources(bcd2k, interface); snd_card_free(card); - mutex_unlock(&devices_mutex); return err; } @@ -431,7 +425,7 @@ static void bcd2000_disconnect(struct usb_interface *interface) if (!bcd2k) return; - mutex_lock(&devices_mutex); + guard(mutex)(&devices_mutex); /* make sure that userspace cannot create new requests */ snd_card_disconnect(bcd2k->card); @@ -441,8 +435,6 @@ static void bcd2000_disconnect(struct usb_interface *interface) clear_bit(bcd2k->card_index, devices_used); snd_card_free_when_closed(bcd2k->card); - - mutex_unlock(&devices_mutex); } static struct usb_driver bcd2000_driver = { From 95692e3c9fceecb821ba14b41773442d720fceaa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:07:17 +0200 Subject: [PATCH 1011/1292] ALSA: caiaq: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829150724.6886-10-tiwai@suse.de --- sound/usb/caiaq/audio.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 05f964347ed6c2..95d425dd9d7034 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -51,29 +51,24 @@ static void activate_substream(struct snd_usb_caiaqdev *cdev, struct snd_pcm_substream *sub) { - spin_lock(&cdev->spinlock); + guard(spinlock)(&cdev->spinlock); if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) cdev->sub_playback[sub->number] = sub; else cdev->sub_capture[sub->number] = sub; - - spin_unlock(&cdev->spinlock); } static void deactivate_substream(struct snd_usb_caiaqdev *cdev, struct snd_pcm_substream *sub) { - unsigned long flags; - spin_lock_irqsave(&cdev->spinlock, flags); + guard(spinlock_irqsave)(&cdev->spinlock); if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) cdev->sub_playback[sub->number] = NULL; else cdev->sub_capture[sub->number] = NULL; - - spin_unlock_irqrestore(&cdev->spinlock, flags); } static int @@ -285,25 +280,18 @@ snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) { int index = sub->number; struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub); - snd_pcm_uframes_t ptr; - spin_lock(&cdev->spinlock); + guard(spinlock)(&cdev->spinlock); - if (cdev->input_panic || cdev->output_panic) { - ptr = SNDRV_PCM_POS_XRUN; - goto unlock; - } + if (cdev->input_panic || cdev->output_panic) + return SNDRV_PCM_POS_XRUN; if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) - ptr = bytes_to_frames(sub->runtime, - cdev->audio_out_buf_pos[index]); + return bytes_to_frames(sub->runtime, + cdev->audio_out_buf_pos[index]); else - ptr = bytes_to_frames(sub->runtime, - cdev->audio_in_buf_pos[index]); - -unlock: - spin_unlock(&cdev->spinlock); - return ptr; + return bytes_to_frames(sub->runtime, + cdev->audio_in_buf_pos[index]); } /* operators for both playback and capture */ @@ -601,7 +589,6 @@ static void read_completed(struct urb *urb) struct device *dev; struct urb *out = NULL; int i, frame, len, send_it = 0, outframe = 0; - unsigned long flags; size_t offset = 0; if (urb->status || !info) @@ -638,10 +625,10 @@ static void read_completed(struct urb *urb) offset += len; if (len > 0) { - spin_lock_irqsave(&cdev->spinlock, flags); - fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]); - read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]); - spin_unlock_irqrestore(&cdev->spinlock, flags); + scoped_guard(spinlock_irqsave, &cdev->spinlock) { + fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]); + read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]); + } check_for_elapsed_periods(cdev, cdev->sub_playback); check_for_elapsed_periods(cdev, cdev->sub_capture); send_it = 1; From 7a3dc0da931ea7c8a1f2e585a0465131f3c9e556 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:15 +0200 Subject: [PATCH 1012/1292] ALSA: i2c: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-2-tiwai@suse.de --- sound/i2c/other/ak4113.c | 6 +++--- sound/i2c/other/ak4114.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index c1f7447a4d11de..fd54e44fe7d650 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c @@ -127,9 +127,9 @@ void snd_ak4113_reinit(struct ak4113 *chip) { if (atomic_inc_return(&chip->wq_processing) == 1) cancel_delayed_work_sync(&chip->work); - mutex_lock(&chip->reinit_mutex); - ak4113_init_regs(chip); - mutex_unlock(&chip->reinit_mutex); + scoped_guard(mutex, &chip->reinit_mutex) { + ak4113_init_regs(chip); + } /* bring up statistics / event queing */ if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 7c493681f3cb6e..f4ded69bb0e428 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -132,9 +132,9 @@ void snd_ak4114_reinit(struct ak4114 *chip) { if (atomic_inc_return(&chip->wq_processing) == 1) cancel_delayed_work_sync(&chip->work); - mutex_lock(&chip->reinit_mutex); - ak4114_init_regs(chip); - mutex_unlock(&chip->reinit_mutex); + scoped_guard(mutex, &chip->reinit_mutex) { + ak4114_init_regs(chip); + } /* bring up statistics / event queing */ if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); From cc8c535320913c6476fb068309f2e78c98dc8caf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:16 +0200 Subject: [PATCH 1013/1292] ALSA: i2c: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-3-tiwai@suse.de --- sound/i2c/other/ak4113.c | 48 +++++++++++++++++++--------------------- sound/i2c/other/ak4114.c | 33 ++++++++++++++------------- sound/i2c/other/ak4117.c | 40 ++++++++++++++++----------------- 3 files changed, 58 insertions(+), 63 deletions(-) diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index fd54e44fe7d650..70b3f7e17f9e63 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c @@ -185,11 +185,10 @@ static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol, { struct ak4113 *chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); ucontrol->value.integer.value[0] = chip->errors[kcontrol->private_value]; chip->errors[kcontrol->private_value] = 0; - spin_unlock_irq(&chip->lock); return 0; } @@ -235,14 +234,13 @@ static int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol, int change; u8 old_val; - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); old_val = chip->regmap[AK4113_REG_IO1]; change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val); if (change) reg_write(chip, AK4113_REG_IO1, (old_val & (~AK4113_IPS(0xff))) | (AK4113_IPS(ucontrol->value.integer.value[0]))); - spin_unlock_irq(&chip->lock); return change; } @@ -532,27 +530,27 @@ int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags) goto __rate; rcs0 = reg_read(ak4113, AK4113_REG_RCS0); rcs2 = reg_read(ak4113, AK4113_REG_RCS2); - spin_lock_irqsave(&ak4113->lock, _flags); - if (rcs0 & AK4113_PAR) - ak4113->errors[AK4113_PARITY_ERRORS]++; - if (rcs0 & AK4113_V) - ak4113->errors[AK4113_V_BIT_ERRORS]++; - if (rcs2 & AK4113_CCRC) - ak4113->errors[AK4113_CCRC_ERRORS]++; - if (rcs2 & AK4113_QCRC) - ak4113->errors[AK4113_QCRC_ERRORS]++; - c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | - AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^ - (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | - AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)); - c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | - AK4113_DAT | 0xf0)) ^ - (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | - AK4113_DAT | 0xf0)); - ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC); - ak4113->rcs1 = rcs1; - ak4113->rcs2 = rcs2; - spin_unlock_irqrestore(&ak4113->lock, _flags); + scoped_guard(spinlock_irqsave, &ak4113->lock) { + if (rcs0 & AK4113_PAR) + ak4113->errors[AK4113_PARITY_ERRORS]++; + if (rcs0 & AK4113_V) + ak4113->errors[AK4113_V_BIT_ERRORS]++; + if (rcs2 & AK4113_CCRC) + ak4113->errors[AK4113_CCRC_ERRORS]++; + if (rcs2 & AK4113_QCRC) + ak4113->errors[AK4113_QCRC_ERRORS]++; + c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | + AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^ + (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | + AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)); + c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | + AK4113_DAT | 0xf0)) ^ + (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | + AK4113_DAT | 0xf0)); + ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC); + ak4113->rcs1 = rcs1; + ak4113->rcs2 = rcs2; + } if (rcs0 & AK4113_PAR) snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index f4ded69bb0e428..0e3a272c149076 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -170,11 +170,10 @@ static int snd_ak4114_in_error_get(struct snd_kcontrol *kcontrol, { struct ak4114 *chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); ucontrol->value.integer.value[0] = chip->errors[kcontrol->private_value]; chip->errors[kcontrol->private_value] = 0; - spin_unlock_irq(&chip->lock); return 0; } @@ -552,21 +551,21 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) if (flags & AK4114_CHECK_NO_STAT) goto __rate; rcs0 = reg_read(ak4114, AK4114_REG_RCS0); - spin_lock_irqsave(&ak4114->lock, _flags); - if (rcs0 & AK4114_PAR) - ak4114->errors[AK4114_PARITY_ERRORS]++; - if (rcs1 & AK4114_V) - ak4114->errors[AK4114_V_BIT_ERRORS]++; - if (rcs1 & AK4114_CCRC) - ak4114->errors[AK4114_CCRC_ERRORS]++; - if (rcs1 & AK4114_QCRC) - ak4114->errors[AK4114_QCRC_ERRORS]++; - c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^ - (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)); - c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0); - ak4114->rcs0 = rcs0 & ~(AK4114_QINT | AK4114_CINT); - ak4114->rcs1 = rcs1; - spin_unlock_irqrestore(&ak4114->lock, _flags); + scoped_guard(spinlock_irqsave, &ak4114->lock) { + if (rcs0 & AK4114_PAR) + ak4114->errors[AK4114_PARITY_ERRORS]++; + if (rcs1 & AK4114_V) + ak4114->errors[AK4114_V_BIT_ERRORS]++; + if (rcs1 & AK4114_CCRC) + ak4114->errors[AK4114_CCRC_ERRORS]++; + if (rcs1 & AK4114_QCRC) + ak4114->errors[AK4114_QCRC_ERRORS]++; + c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^ + (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)); + c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0); + ak4114->rcs0 = rcs0 & ~(AK4114_QINT | AK4114_CINT); + ak4114->rcs1 = rcs1; + } ak4114_notify(ak4114, rcs0, rcs1, c0, c1); if (ak4114->change_callback && (c0 | c1) != 0) diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index cd380db195ef5e..d2ec20f885f0cb 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -144,11 +144,10 @@ static int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol, { struct ak4117 *chip = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); ucontrol->value.integer.value[0] = chip->errors[kcontrol->private_value]; chip->errors[kcontrol->private_value] = 0; - spin_unlock_irq(&chip->lock); return 0; } @@ -192,12 +191,11 @@ static int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol, int change; u8 old_val; - spin_lock_irq(&chip->lock); + guard(spinlock_irq)(&chip->lock); old_val = chip->regmap[AK4117_REG_IO]; change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0); if (change) reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0)); - spin_unlock_irq(&chip->lock); return change; } @@ -441,23 +439,23 @@ int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags) goto __rate; rcs0 = reg_read(ak4117, AK4117_REG_RCS0); rcs2 = reg_read(ak4117, AK4117_REG_RCS2); - spin_lock_irqsave(&ak4117->lock, _flags); - if (rcs0 & AK4117_PAR) - ak4117->errors[AK4117_PARITY_ERRORS]++; - if (rcs0 & AK4117_V) - ak4117->errors[AK4117_V_BIT_ERRORS]++; - if (rcs2 & AK4117_CCRC) - ak4117->errors[AK4117_CCRC_ERRORS]++; - if (rcs2 & AK4117_QCRC) - ak4117->errors[AK4117_QCRC_ERRORS]++; - c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^ - (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)); - c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^ - (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)); - ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); - ak4117->rcs1 = rcs1; - ak4117->rcs2 = rcs2; - spin_unlock_irqrestore(&ak4117->lock, _flags); + scoped_guard(spinlock_irqsave, &ak4117->lock) { + if (rcs0 & AK4117_PAR) + ak4117->errors[AK4117_PARITY_ERRORS]++; + if (rcs0 & AK4117_V) + ak4117->errors[AK4117_V_BIT_ERRORS]++; + if (rcs2 & AK4117_CCRC) + ak4117->errors[AK4117_CCRC_ERRORS]++; + if (rcs2 & AK4117_QCRC) + ak4117->errors[AK4117_QCRC_ERRORS]++; + c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^ + (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)); + c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^ + (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)); + ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); + ak4117->rcs1 = rcs1; + ak4117->rcs2 = rcs2; + } if (rcs0 & AK4117_PAR) snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id); From eff259d5b90508fe09edb172d2d4ec5487edf992 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:17 +0200 Subject: [PATCH 1014/1292] ALSA: synth: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-4-tiwai@suse.de --- sound/synth/emux/emux_proc.c | 6 ++---- sound/synth/emux/emux_seq.c | 17 +++++------------ sound/synth/util_mem.c | 17 +++++------------ 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 820351f52551ec..16d6c9a1e24fb0 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c @@ -19,7 +19,7 @@ snd_emux_proc_info_read(struct snd_info_entry *entry, int i; emu = entry->private_data; - mutex_lock(&emu->register_mutex); + guard(mutex)(&emu->register_mutex); if (emu->name) snd_iprintf(buf, "Device: %s\n", emu->name); snd_iprintf(buf, "Ports: %d\n", emu->num_ports); @@ -38,13 +38,12 @@ snd_emux_proc_info_read(struct snd_info_entry *entry, snd_iprintf(buf, "Memory Size: 0\n"); } if (emu->sflist) { - mutex_lock(&emu->sflist->presets_mutex); + guard(mutex)(&emu->sflist->presets_mutex); snd_iprintf(buf, "SoundFonts: %d\n", emu->sflist->fonts_size); snd_iprintf(buf, "Instruments: %d\n", emu->sflist->zone_counter); snd_iprintf(buf, "Samples: %d\n", emu->sflist->sample_counter); snd_iprintf(buf, "Locked Instruments: %d\n", emu->sflist->zone_locked); snd_iprintf(buf, "Locked Samples: %d\n", emu->sflist->sample_locked); - mutex_unlock(&emu->sflist->presets_mutex); } #if 0 /* debug */ if (emu->voices[0].state != SNDRV_EMUX_ST_OFF && emu->voices[0].ch >= 0) { @@ -85,7 +84,6 @@ snd_emux_proc_info_read(struct snd_info_entry *entry, snd_iprintf(buf, "sample_mode=%x, rate=%x\n", vp->reg.sample_mode, vp->reg.rate_offset); } #endif - mutex_unlock(&emu->register_mutex); } diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index 9daced0e6c59d9..9d63ac006aa5a8 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c @@ -272,12 +272,8 @@ __snd_emux_inc_count(struct snd_emux *emu) int snd_emux_inc_count(struct snd_emux *emu) { - int ret; - - mutex_lock(&emu->register_mutex); - ret = __snd_emux_inc_count(emu); - mutex_unlock(&emu->register_mutex); - return ret; + guard(mutex)(&emu->register_mutex); + return __snd_emux_inc_count(emu); } /* @@ -295,9 +291,8 @@ __snd_emux_dec_count(struct snd_emux *emu) void snd_emux_dec_count(struct snd_emux *emu) { - mutex_lock(&emu->register_mutex); + guard(mutex)(&emu->register_mutex); __snd_emux_dec_count(emu); - mutex_unlock(&emu->register_mutex); } /* @@ -316,10 +311,9 @@ snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info) if (snd_BUG_ON(!emu)) return -EINVAL; - mutex_lock(&emu->register_mutex); + guard(mutex)(&emu->register_mutex); snd_emux_init_port(p); __snd_emux_inc_count(emu); - mutex_unlock(&emu->register_mutex); return 0; } @@ -339,10 +333,9 @@ snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info) if (snd_BUG_ON(!emu)) return -EINVAL; - mutex_lock(&emu->register_mutex); + guard(mutex)(&emu->register_mutex); snd_emux_sounds_off_all(p); __snd_emux_dec_count(emu); - mutex_unlock(&emu->register_mutex); return 0; } diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c index 304a8f1740c385..2fd577c2a8eb69 100644 --- a/sound/synth/util_mem.c +++ b/sound/synth/util_mem.c @@ -124,11 +124,8 @@ __snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units, struct snd_util_memblk * snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size) { - struct snd_util_memblk *blk; - mutex_lock(&hdr->block_mutex); - blk = __snd_util_mem_alloc(hdr, size); - mutex_unlock(&hdr->block_mutex); - return blk; + guard(mutex)(&hdr->block_mutex); + return __snd_util_mem_alloc(hdr, size); } @@ -153,9 +150,8 @@ int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk) if (snd_BUG_ON(!hdr || !blk)) return -EINVAL; - mutex_lock(&hdr->block_mutex); + guard(mutex)(&hdr->block_mutex); __snd_util_mem_free(hdr, blk); - mutex_unlock(&hdr->block_mutex); return 0; } @@ -164,11 +160,8 @@ int snd_util_mem_free(struct snd_util_memhdr *hdr, struct snd_util_memblk *blk) */ int snd_util_mem_avail(struct snd_util_memhdr *hdr) { - unsigned int size; - mutex_lock(&hdr->block_mutex); - size = hdr->size - hdr->used; - mutex_unlock(&hdr->block_mutex); - return size; + guard(mutex)(&hdr->block_mutex); + return hdr->size - hdr->used; } From 59ede7178d402b3bfa0266cbd9ad348d5612c295 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:18 +0200 Subject: [PATCH 1015/1292] ALSA: synth: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-5-tiwai@suse.de --- sound/synth/emux/emux_effect.c | 29 ++++++++-------- sound/synth/emux/emux_synth.c | 54 +++++++---------------------- sound/synth/emux/soundfont.c | 63 ++++++++++++---------------------- 3 files changed, 49 insertions(+), 97 deletions(-) diff --git a/sound/synth/emux/emux_effect.c b/sound/synth/emux/emux_effect.c index 3c7314f5fb19c0..bfe383fa90ba1b 100644 --- a/sound/synth/emux/emux_effect.c +++ b/sound/synth/emux/emux_effect.c @@ -168,7 +168,6 @@ snd_emux_send_effect(struct snd_emux_port *port, struct snd_midi_channel *chan, unsigned char *srcp, *origp; struct snd_emux *emu; struct snd_emux_effect_table *fx; - unsigned long flags; emu = port->emu; fx = chan->private; @@ -195,22 +194,22 @@ snd_emux_send_effect(struct snd_emux_port *port, struct snd_midi_channel *chan, offset++; #endif /* modify the register values */ - spin_lock_irqsave(&emu->voice_lock, flags); - for (i = 0; i < emu->max_voices; i++) { - struct snd_emux_voice *vp = &emu->voices[i]; - if (!STATE_IS_PLAYING(vp->state) || vp->chan != chan) - continue; - srcp = (unsigned char*)&vp->reg.parm + offset; - origp = (unsigned char*)&vp->zone->v.parm + offset; - if (parm_defs[i].type & PARM_IS_BYTE) { - *srcp = *origp; - effect_set_byte(srcp, chan, type); - } else { - *(unsigned short*)srcp = *(unsigned short*)origp; - effect_set_word((unsigned short*)srcp, chan, type); + scoped_guard(spinlock_irqsave, &emu->voice_lock) { + for (i = 0; i < emu->max_voices; i++) { + struct snd_emux_voice *vp = &emu->voices[i]; + if (!STATE_IS_PLAYING(vp->state) || vp->chan != chan) + continue; + srcp = (unsigned char *)&vp->reg.parm + offset; + origp = (unsigned char *)&vp->zone->v.parm + offset; + if (parm_defs[i].type & PARM_IS_BYTE) { + *srcp = *origp; + effect_set_byte(srcp, chan, type); + } else { + *(unsigned short *)srcp = *(unsigned short *)origp; + effect_set_word((unsigned short *)srcp, chan, type); + } } } - spin_unlock_irqrestore(&emu->voice_lock, flags); /* activate them */ snd_emux_update_channel(port, chan, parm_defs[type].update); diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c index cff6aba9bfc392..6982e1317da5e5 100644 --- a/sound/synth/emux/emux_synth.c +++ b/sound/synth/emux/emux_synth.c @@ -49,7 +49,6 @@ snd_emux_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) int i, key, nvoices; struct snd_emux_voice *vp; struct snd_sf_zone *table[SNDRV_EMUX_MAX_MULTI_VOICES]; - unsigned long flags; struct snd_emux_port *port; port = p; @@ -77,7 +76,7 @@ snd_emux_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) terminate_note1(emu, key, chan, 0); #endif - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < nvoices; i++) { /* set up each voice parameter */ @@ -124,7 +123,6 @@ snd_emux_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) vp->ontime = jiffies; /* remember the trigger timing */ } } - spin_unlock_irqrestore(&emu->voice_lock, flags); #ifdef SNDRV_EMUX_USE_RAW_EFFECT if (port->port_mode == SNDRV_EMUX_PORT_MODE_OSS_SYNTH) { @@ -147,7 +145,6 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan) int ch; struct snd_emux *emu; struct snd_emux_voice *vp; - unsigned long flags; struct snd_emux_port *port; port = p; @@ -158,7 +155,7 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan) if (snd_BUG_ON(!emu || !emu->ops.release)) return; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (ch = 0; ch < emu->max_voices; ch++) { vp = &emu->voices[ch]; if (STATE_IS_PLAYING(vp->state) && @@ -180,7 +177,6 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan) emu->ops.release(vp); } } - spin_unlock_irqrestore(&emu->voice_lock, flags); } /* @@ -192,10 +188,9 @@ void snd_emux_timer_callback(struct timer_list *t) { struct snd_emux *emu = timer_container_of(emu, t, tlist); struct snd_emux_voice *vp; - unsigned long flags; int ch, do_again = 0; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (ch = 0; ch < emu->max_voices; ch++) { vp = &emu->voices[ch]; if (vp->state == SNDRV_EMUX_ST_PENDING) { @@ -212,7 +207,6 @@ void snd_emux_timer_callback(struct timer_list *t) emu->timer_active = 1; } else emu->timer_active = 0; - spin_unlock_irqrestore(&emu->voice_lock, flags); } /* @@ -224,7 +218,6 @@ snd_emux_key_press(void *p, int note, int vel, struct snd_midi_channel *chan) int ch; struct snd_emux *emu; struct snd_emux_voice *vp; - unsigned long flags; struct snd_emux_port *port; port = p; @@ -235,7 +228,7 @@ snd_emux_key_press(void *p, int note, int vel, struct snd_midi_channel *chan) if (snd_BUG_ON(!emu || !emu->ops.update)) return; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (ch = 0; ch < emu->max_voices; ch++) { vp = &emu->voices[ch]; if (vp->state == SNDRV_EMUX_ST_ON && @@ -244,7 +237,6 @@ snd_emux_key_press(void *p, int note, int vel, struct snd_midi_channel *chan) update_voice(emu, vp, SNDRV_EMUX_UPDATE_VOLUME); } } - spin_unlock_irqrestore(&emu->voice_lock, flags); } @@ -257,7 +249,6 @@ snd_emux_update_channel(struct snd_emux_port *port, struct snd_midi_channel *cha struct snd_emux *emu; struct snd_emux_voice *vp; int i; - unsigned long flags; if (! update) return; @@ -266,13 +257,12 @@ snd_emux_update_channel(struct snd_emux_port *port, struct snd_midi_channel *cha if (snd_BUG_ON(!emu || !emu->ops.update)) return; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < emu->max_voices; i++) { vp = &emu->voices[i]; if (vp->chan == chan) update_voice(emu, vp, update); } - spin_unlock_irqrestore(&emu->voice_lock, flags); } /* @@ -284,7 +274,6 @@ snd_emux_update_port(struct snd_emux_port *port, int update) struct snd_emux *emu; struct snd_emux_voice *vp; int i; - unsigned long flags; if (! update) return; @@ -293,13 +282,12 @@ snd_emux_update_port(struct snd_emux_port *port, int update) if (snd_BUG_ON(!emu || !emu->ops.update)) return; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < emu->max_voices; i++) { vp = &emu->voices[i]; if (vp->port == port) update_voice(emu, vp, update); } - spin_unlock_irqrestore(&emu->voice_lock, flags); } @@ -365,16 +353,14 @@ terminate_note1(struct snd_emux *emu, int note, struct snd_midi_channel *chan, i { int i; struct snd_emux_voice *vp; - unsigned long flags; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < emu->max_voices; i++) { vp = &emu->voices[i]; if (STATE_IS_PLAYING(vp->state) && vp->chan == chan && vp->key == note) terminate_voice(emu, vp, free); } - spin_unlock_irqrestore(&emu->voice_lock, flags); } @@ -407,9 +393,8 @@ snd_emux_terminate_all(struct snd_emux *emu) { int i; struct snd_emux_voice *vp; - unsigned long flags; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < emu->max_voices; i++) { vp = &emu->voices[i]; if (STATE_IS_PLAYING(vp->state)) @@ -424,7 +409,6 @@ snd_emux_terminate_all(struct snd_emux *emu) } /* initialize allocation time */ emu->use_time = 0; - spin_unlock_irqrestore(&emu->voice_lock, flags); } EXPORT_SYMBOL(snd_emux_terminate_all); @@ -438,7 +422,6 @@ snd_emux_sounds_off_all(struct snd_emux_port *port) int i; struct snd_emux *emu; struct snd_emux_voice *vp; - unsigned long flags; if (snd_BUG_ON(!port)) return; @@ -446,7 +429,7 @@ snd_emux_sounds_off_all(struct snd_emux_port *port) if (snd_BUG_ON(!emu || !emu->ops.terminate)) return; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < emu->max_voices; i++) { vp = &emu->voices[i]; if (STATE_IS_PLAYING(vp->state) && @@ -459,7 +442,6 @@ snd_emux_sounds_off_all(struct snd_emux_port *port) emu->ops.reset(emu, i); } } - spin_unlock_irqrestore(&emu->voice_lock, flags); } @@ -472,9 +454,8 @@ exclusive_note_off(struct snd_emux *emu, struct snd_emux_port *port, int exclass { struct snd_emux_voice *vp; int i; - unsigned long flags; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < emu->max_voices; i++) { vp = &emu->voices[i]; if (STATE_IS_PLAYING(vp->state) && vp->port == port && @@ -482,7 +463,6 @@ exclusive_note_off(struct snd_emux *emu, struct snd_emux_port *port, int exclass terminate_voice(emu, vp, 0); } } - spin_unlock_irqrestore(&emu->voice_lock, flags); } /* @@ -916,9 +896,8 @@ snd_emux_init_voices(struct snd_emux *emu) { struct snd_emux_voice *vp; int i; - unsigned long flags; - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); for (i = 0; i < emu->max_voices; i++) { vp = &emu->voices[i]; vp->ch = -1; /* not used */ @@ -929,23 +908,19 @@ snd_emux_init_voices(struct snd_emux *emu) vp->emu = emu; vp->hw = emu->hw; } - spin_unlock_irqrestore(&emu->voice_lock, flags); } /* */ void snd_emux_lock_voice(struct snd_emux *emu, int voice) { - unsigned long flags; - - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); if (emu->voices[voice].state == SNDRV_EMUX_ST_OFF) emu->voices[voice].state = SNDRV_EMUX_ST_LOCKED; else dev_warn(emu->card->dev, "invalid voice for lock %d (state = %x)\n", voice, emu->voices[voice].state); - spin_unlock_irqrestore(&emu->voice_lock, flags); } EXPORT_SYMBOL(snd_emux_lock_voice); @@ -954,16 +929,13 @@ EXPORT_SYMBOL(snd_emux_lock_voice); */ void snd_emux_unlock_voice(struct snd_emux *emu, int voice) { - unsigned long flags; - - spin_lock_irqsave(&emu->voice_lock, flags); + guard(spinlock_irqsave)(&emu->voice_lock); if (emu->voices[voice].state == SNDRV_EMUX_ST_LOCKED) emu->voices[voice].state = SNDRV_EMUX_ST_OFF; else dev_warn(emu->card->dev, "invalid voice for unlock %d (state = %x)\n", voice, emu->voices[voice].state); - spin_unlock_irqrestore(&emu->voice_lock, flags); } EXPORT_SYMBOL(snd_emux_unlock_voice); diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index b38a4e231790fe..cbff9f7ad38caa 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -66,11 +66,9 @@ static void snd_sf_clear(struct snd_sf_list *sflist); static void lock_preset(struct snd_sf_list *sflist) { - unsigned long flags; mutex_lock(&sflist->presets_mutex); - spin_lock_irqsave(&sflist->lock, flags); + guard(spinlock_irqsave)(&sflist->lock); sflist->presets_locked = 1; - spin_unlock_irqrestore(&sflist->lock, flags); } @@ -80,10 +78,8 @@ lock_preset(struct snd_sf_list *sflist) static void unlock_preset(struct snd_sf_list *sflist) { - unsigned long flags; - spin_lock_irqsave(&sflist->lock, flags); + guard(spinlock_irqsave)(&sflist->lock); sflist->presets_locked = 0; - spin_unlock_irqrestore(&sflist->lock, flags); mutex_unlock(&sflist->presets_mutex); } @@ -94,14 +90,11 @@ unlock_preset(struct snd_sf_list *sflist) int snd_soundfont_close_check(struct snd_sf_list *sflist, int client) { - unsigned long flags; - spin_lock_irqsave(&sflist->lock, flags); - if (sflist->open_client == client) { - spin_unlock_irqrestore(&sflist->lock, flags); - return close_patch(sflist); + scoped_guard(spinlock_irqsave, &sflist->lock) { + if (sflist->open_client != client) + return 0; } - spin_unlock_irqrestore(&sflist->lock, flags); - return 0; + return close_patch(sflist); } @@ -119,7 +112,6 @@ snd_soundfont_load(struct snd_card *card, long count, int client) { struct soundfont_patch_info patch; - unsigned long flags; int rc; if (count < (long)sizeof(patch)) { @@ -155,12 +147,10 @@ snd_soundfont_load(struct snd_card *card, } /* check if other client already opened patch */ - spin_lock_irqsave(&sflist->lock, flags); - if (sflist->open_client != client) { - spin_unlock_irqrestore(&sflist->lock, flags); - return -EBUSY; + scoped_guard(spinlock_irqsave, &sflist->lock) { + if (sflist->open_client != client) + return -EBUSY; } - spin_unlock_irqrestore(&sflist->lock, flags); lock_preset(sflist); rc = -EINVAL; @@ -223,14 +213,11 @@ open_patch(struct snd_sf_list *sflist, const char __user *data, { struct soundfont_open_parm parm; struct snd_soundfont *sf; - unsigned long flags; - spin_lock_irqsave(&sflist->lock, flags); - if (sflist->open_client >= 0 || sflist->currsf) { - spin_unlock_irqrestore(&sflist->lock, flags); - return -EBUSY; + scoped_guard(spinlock_irqsave, &sflist->lock) { + if (sflist->open_client >= 0 || sflist->currsf) + return -EBUSY; } - spin_unlock_irqrestore(&sflist->lock, flags); if (copy_from_user(&parm, data, sizeof(parm))) return -EFAULT; @@ -244,10 +231,10 @@ open_patch(struct snd_sf_list *sflist, const char __user *data, return -ENOMEM; } - spin_lock_irqsave(&sflist->lock, flags); - sflist->open_client = client; - sflist->currsf = sf; - spin_unlock_irqrestore(&sflist->lock, flags); + scoped_guard(spinlock_irqsave, &sflist->lock) { + sflist->open_client = client; + sflist->currsf = sf; + } return 0; } @@ -305,12 +292,10 @@ is_identical_font(struct snd_soundfont *sf, int type, unsigned char *name) static int close_patch(struct snd_sf_list *sflist) { - unsigned long flags; - - spin_lock_irqsave(&sflist->lock, flags); - sflist->currsf = NULL; - sflist->open_client = -1; - spin_unlock_irqrestore(&sflist->lock, flags); + scoped_guard(spinlock_irqsave, &sflist->lock) { + sflist->currsf = NULL; + sflist->open_client = -1; + } rebuild_presets(sflist); @@ -1278,17 +1263,14 @@ snd_soundfont_search_zone(struct snd_sf_list *sflist, int *notep, int vel, struct snd_sf_zone **table, int max_layers) { int nvoices; - unsigned long flags; /* this function is supposed to be called atomically, * so we check the lock. if it's busy, just returns 0 to * tell the caller the busy state */ - spin_lock_irqsave(&sflist->lock, flags); - if (sflist->presets_locked) { - spin_unlock_irqrestore(&sflist->lock, flags); + guard(spinlock_irqsave)(&sflist->lock); + if (sflist->presets_locked) return 0; - } nvoices = search_zones(sflist, notep, vel, preset, bank, table, max_layers, 0); if (! nvoices) { @@ -1297,7 +1279,6 @@ snd_soundfont_search_zone(struct snd_sf_list *sflist, int *notep, int vel, def_preset, def_bank, table, max_layers, 0); } - spin_unlock_irqrestore(&sflist->lock, flags); return nvoices; } From 826f35b829f43dc62fb847eca6f79e8698b4994d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:19 +0200 Subject: [PATCH 1016/1292] ALSA: synth: Use guard() for preset locks Define a macro for the preset locking/unlocking pairs for soundfont using guard() macro as a further code cleanup. The new macro is put in soundfont.h (and some function renames) along with it for avoiding unnecessary troubles with clang. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-6-tiwai@suse.de --- include/sound/soundfont.h | 18 ++++++++++++ sound/synth/emux/soundfont.c | 56 ++++++++---------------------------- 2 files changed, 30 insertions(+), 44 deletions(-) diff --git a/include/sound/soundfont.h b/include/sound/soundfont.h index 8a40cc15f66db7..48f8cf6de3acf1 100644 --- a/include/sound/soundfont.h +++ b/include/sound/soundfont.h @@ -114,5 +114,23 @@ int snd_sf_calc_parm_decay(int msec); extern int snd_sf_vol_table[128]; int snd_sf_linear_to_log(unsigned int amount, int offset, int ratio); +/* lock access to sflist */ +static inline void snd_soundfont_lock_preset(struct snd_sf_list *sflist) +{ + mutex_lock(&sflist->presets_mutex); + guard(spinlock_irqsave)(&sflist->lock); + sflist->presets_locked = 1; +} + +/* remove lock */ +static inline void snd_soundfont_unlock_preset(struct snd_sf_list *sflist) +{ + guard(spinlock_irqsave)(&sflist->lock); + sflist->presets_locked = 0; + mutex_unlock(&sflist->presets_mutex); +} + +DEFINE_GUARD(snd_soundfont_lock_preset, struct snd_sf_list *, + snd_soundfont_lock_preset(_T), snd_soundfont_unlock_preset(_T)) #endif /* __SOUND_SOUNDFONT_H */ diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index cbff9f7ad38caa..59f3b1b6df4a24 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -60,30 +60,6 @@ static int get_index(int bank, int instr, int key); static void snd_sf_init(struct snd_sf_list *sflist); static void snd_sf_clear(struct snd_sf_list *sflist); -/* - * lock access to sflist - */ -static void -lock_preset(struct snd_sf_list *sflist) -{ - mutex_lock(&sflist->presets_mutex); - guard(spinlock_irqsave)(&sflist->lock); - sflist->presets_locked = 1; -} - - -/* - * remove lock - */ -static void -unlock_preset(struct snd_sf_list *sflist) -{ - guard(spinlock_irqsave)(&sflist->lock); - sflist->presets_locked = 0; - mutex_unlock(&sflist->presets_mutex); -} - - /* * close the patch if the patch was opened by this client. */ @@ -140,10 +116,8 @@ snd_soundfont_load(struct snd_card *card, if (patch.type == SNDRV_SFNT_OPEN_PATCH) { /* grab sflist to open */ - lock_preset(sflist); - rc = open_patch(sflist, data, count, client); - unlock_preset(sflist); - return rc; + guard(snd_soundfont_lock_preset)(sflist); + return open_patch(sflist, data, count, client); } /* check if other client already opened patch */ @@ -152,7 +126,7 @@ snd_soundfont_load(struct snd_card *card, return -EBUSY; } - lock_preset(sflist); + guard(snd_soundfont_lock_preset)(sflist); rc = -EINVAL; switch (patch.type) { case SNDRV_SFNT_LOAD_INFO: @@ -190,7 +164,6 @@ snd_soundfont_load(struct snd_card *card, } break; } - unlock_preset(sflist); return rc; } @@ -1153,11 +1126,8 @@ snd_soundfont_load_guspatch(struct snd_card *card, struct snd_sf_list *sflist, const char __user *data, long count) { - int rc; - lock_preset(sflist); - rc = load_guspatch(card, sflist, data, count); - unlock_preset(sflist); - return rc; + guard(snd_soundfont_lock_preset)(sflist); + return load_guspatch(card, sflist, data, count); } @@ -1446,11 +1416,11 @@ snd_sf_free(struct snd_sf_list *sflist) if (sflist == NULL) return; - lock_preset(sflist); - if (sflist->callback.sample_reset) - sflist->callback.sample_reset(sflist->callback.private_data); - snd_sf_clear(sflist); - unlock_preset(sflist); + scoped_guard(snd_soundfont_lock_preset, sflist) { + if (sflist->callback.sample_reset) + sflist->callback.sample_reset(sflist->callback.private_data); + snd_sf_clear(sflist); + } kfree(sflist); } @@ -1462,11 +1432,10 @@ snd_sf_free(struct snd_sf_list *sflist) int snd_soundfont_remove_samples(struct snd_sf_list *sflist) { - lock_preset(sflist); + guard(snd_soundfont_lock_preset)(sflist); if (sflist->callback.sample_reset) sflist->callback.sample_reset(sflist->callback.private_data); snd_sf_clear(sflist); - unlock_preset(sflist); return 0; } @@ -1482,7 +1451,7 @@ snd_soundfont_remove_unlocked(struct snd_sf_list *sflist) struct snd_sf_zone *zp, *nextzp; struct snd_sf_sample *sp, *nextsp; - lock_preset(sflist); + guard(snd_soundfont_lock_preset)(sflist); if (sflist->callback.sample_reset) sflist->callback.sample_reset(sflist->callback.private_data); @@ -1516,6 +1485,5 @@ snd_soundfont_remove_unlocked(struct snd_sf_list *sflist) rebuild_presets(sflist); - unlock_preset(sflist); return 0; } From 10403f910ad2cd18a1f0d7ba5c7c702bbaec0511 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:20 +0200 Subject: [PATCH 1017/1292] ALSA: x86: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-7-tiwai@suse.de --- sound/x86/intel_hdmi_audio.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 01f49555c5f61d..c1506a9f7e15a9 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -554,16 +554,13 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, memset(ucontrol->value.integer.value, 0, sizeof(long) * HAD_MAX_CHANNEL); - mutex_lock(&intelhaddata->mutex); - if (!intelhaddata->chmap->chmap) { - mutex_unlock(&intelhaddata->mutex); + guard(mutex)(&intelhaddata->mutex); + if (!intelhaddata->chmap->chmap) return 0; - } chmap = intelhaddata->chmap->chmap; for (i = 0; i < chmap->channels; i++) ucontrol->value.integer.value[i] = chmap->map[i]; - mutex_unlock(&intelhaddata->mutex); return 0; } @@ -1394,14 +1391,13 @@ static int had_iec958_get(struct snd_kcontrol *kcontrol, { struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); - mutex_lock(&intelhaddata->mutex); + guard(mutex)(&intelhaddata->mutex); ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff; ucontrol->value.iec958.status[2] = (intelhaddata->aes_bits >> 16) & 0xff; ucontrol->value.iec958.status[3] = (intelhaddata->aes_bits >> 24) & 0xff; - mutex_unlock(&intelhaddata->mutex); return 0; } @@ -1426,12 +1422,11 @@ static int had_iec958_put(struct snd_kcontrol *kcontrol, (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); - mutex_lock(&intelhaddata->mutex); + guard(mutex)(&intelhaddata->mutex); if (intelhaddata->aes_bits != val) { intelhaddata->aes_bits = val; changed = 1; } - mutex_unlock(&intelhaddata->mutex); return changed; } @@ -1448,10 +1443,9 @@ static int had_ctl_eld_get(struct snd_kcontrol *kcontrol, { struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); - mutex_lock(&intelhaddata->mutex); + guard(mutex)(&intelhaddata->mutex); memcpy(ucontrol->value.bytes.data, intelhaddata->eld, HDMI_MAX_ELD_BYTES); - mutex_unlock(&intelhaddata->mutex); return 0; } From ab770b41630d186b9e51c013e2108a6a5df9be3d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:21 +0200 Subject: [PATCH 1018/1292] ALSA: x86: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-8-tiwai@suse.de --- sound/x86/intel_hdmi_audio.c | 93 +++++++++++++++--------------------- 1 file changed, 39 insertions(+), 54 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index c1506a9f7e15a9..8e2a007311d361 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -171,13 +171,11 @@ static struct snd_pcm_substream * had_substream_get(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; - unsigned long flags; - spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + guard(spinlock_irqsave)(&intelhaddata->had_spinlock); substream = intelhaddata->stream_info.substream; if (substream) intelhaddata->stream_info.substream_refcount++; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); return substream; } @@ -186,11 +184,8 @@ had_substream_get(struct snd_intelhad *intelhaddata) */ static void had_substream_put(struct snd_intelhad *intelhaddata) { - unsigned long flags; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + guard(spinlock_irqsave)(&intelhaddata->had_spinlock); intelhaddata->stream_info.substream_refcount--; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); } static u32 had_config_offset(int pipe) @@ -946,10 +941,9 @@ static int had_process_ringbuf(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata) { int len, processed; - unsigned long flags; processed = 0; - spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + guard(spinlock_irqsave)(&intelhaddata->had_spinlock); for (;;) { /* get the remaining bytes on the buffer */ had_read_register(intelhaddata, @@ -958,25 +952,20 @@ static int had_process_ringbuf(struct snd_pcm_substream *substream, if (len < 0 || len > intelhaddata->period_bytes) { dev_dbg(intelhaddata->dev, "Invalid buf length %d\n", len); - len = -EPIPE; - goto out; + return -EPIPE; } if (len > 0) /* OK, this is the current buffer */ break; /* len=0 => already empty, check the next buffer */ - if (++processed >= intelhaddata->num_bds) { - len = -EPIPE; /* all empty? - report underrun */ - goto out; - } + if (++processed >= intelhaddata->num_bds) + return -EPIPE; /* all empty? - report underrun */ had_advance_ringbuf(substream, intelhaddata); } len = intelhaddata->period_bytes - len; len += intelhaddata->period_bytes * intelhaddata->pcmbuf_head; - out: - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); return len; } @@ -1092,10 +1081,10 @@ static int had_pcm_open(struct snd_pcm_substream *substream) goto error; /* expose PCM substream */ - spin_lock_irq(&intelhaddata->had_spinlock); - intelhaddata->stream_info.substream = substream; - intelhaddata->stream_info.substream_refcount++; - spin_unlock_irq(&intelhaddata->had_spinlock); + scoped_guard(spinlock_irq, &intelhaddata->had_spinlock) { + intelhaddata->stream_info.substream = substream; + intelhaddata->stream_info.substream_refcount++; + } return retval; error: @@ -1153,7 +1142,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) intelhaddata = snd_pcm_substream_chip(substream); - spin_lock(&intelhaddata->had_spinlock); + guard(spinlock)(&intelhaddata->had_spinlock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -1172,7 +1161,6 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) default: retval = -EINVAL; } - spin_unlock(&intelhaddata->had_spinlock); return retval; } @@ -1311,21 +1299,20 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; - spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->connected) { - dev_dbg(intelhaddata->dev, "Device already connected\n"); - spin_unlock_irq(&intelhaddata->had_spinlock); - return; - } + scoped_guard(spinlock_irq, &intelhaddata->had_spinlock) { + if (intelhaddata->connected) { + dev_dbg(intelhaddata->dev, "Device already connected\n"); + return; + } - /* Disable Audio */ - had_enable_audio(intelhaddata, false); + /* Disable Audio */ + had_enable_audio(intelhaddata, false); - intelhaddata->connected = true; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + intelhaddata->connected = true; + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); - spin_unlock_irq(&intelhaddata->had_spinlock); + } had_build_channel_allocation_map(intelhaddata); @@ -1344,22 +1331,20 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; - spin_lock_irq(&intelhaddata->had_spinlock); - if (!intelhaddata->connected) { - dev_dbg(intelhaddata->dev, "Device already disconnected\n"); - spin_unlock_irq(&intelhaddata->had_spinlock); - return; - - } + scoped_guard(spinlock_irq, &intelhaddata->had_spinlock) { + if (!intelhaddata->connected) { + dev_dbg(intelhaddata->dev, "Device already disconnected\n"); + return; + } - /* Disable Audio */ - had_enable_audio(intelhaddata, false); + /* Disable Audio */ + had_enable_audio(intelhaddata, false); - intelhaddata->connected = false; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + intelhaddata->connected = false; + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - spin_unlock_irq(&intelhaddata->had_spinlock); + } kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; @@ -1636,9 +1621,9 @@ static void hdmi_lpe_audio_free(struct snd_card *card) struct intel_hdmi_lpe_audio_pdata *pdata = card_ctx->dev->platform_data; int port; - spin_lock_irq(&pdata->lpe_audio_slock); - pdata->notify_audio_lpe = NULL; - spin_unlock_irq(&pdata->lpe_audio_slock); + scoped_guard(spinlock_irq, &pdata->lpe_audio_slock) { + pdata->notify_audio_lpe = NULL; + } for_each_port(card_ctx, port) { struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port]; @@ -1799,9 +1784,9 @@ static int __hdmi_lpe_audio_probe(struct platform_device *pdev) if (ret) return ret; - spin_lock_irq(&pdata->lpe_audio_slock); - pdata->notify_audio_lpe = notify_audio_lpe; - spin_unlock_irq(&pdata->lpe_audio_slock); + scoped_guard(spinlock_irq, &pdata->lpe_audio_slock) { + pdata->notify_audio_lpe = notify_audio_lpe; + } pm_runtime_set_autosuspend_delay(&pdev->dev, INTEL_HDMI_AUDIO_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); From 3ddf4f97166a9cbea5113c1095d8148fd66bbed9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:22 +0200 Subject: [PATCH 1019/1292] ALSA: xen: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-9-tiwai@suse.de --- sound/xen/xen_snd_front.c | 82 ++++++++++++++----------------- sound/xen/xen_snd_front_evtchnl.c | 33 ++++++------- 2 files changed, 53 insertions(+), 62 deletions(-) diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c index b66e037710d0df..c56d17479f05d1 100644 --- a/sound/xen/xen_snd_front.c +++ b/sound/xen/xen_snd_front.c @@ -62,12 +62,12 @@ int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl, struct xensnd_req *req; int ret; - mutex_lock(&evtchnl->u.req.req_io_lock); + guard(mutex)(&evtchnl->u.req.req_io_lock); - mutex_lock(&evtchnl->ring_io_lock); - req = be_stream_prepare_req(evtchnl, XENSND_OP_HW_PARAM_QUERY); - req->op.hw_param = *hw_param_req; - mutex_unlock(&evtchnl->ring_io_lock); + scoped_guard(mutex, &evtchnl->ring_io_lock) { + req = be_stream_prepare_req(evtchnl, XENSND_OP_HW_PARAM_QUERY); + req->op.hw_param = *hw_param_req; + } ret = be_stream_do_io(evtchnl); @@ -77,7 +77,6 @@ int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl, if (ret == 0) *hw_param_resp = evtchnl->u.req.resp.hw_param; - mutex_unlock(&evtchnl->u.req.req_io_lock); return ret; } @@ -90,25 +89,24 @@ int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, struct xensnd_req *req; int ret; - mutex_lock(&evtchnl->u.req.req_io_lock); - - mutex_lock(&evtchnl->ring_io_lock); - req = be_stream_prepare_req(evtchnl, XENSND_OP_OPEN); - req->op.open.pcm_format = format; - req->op.open.pcm_channels = channels; - req->op.open.pcm_rate = rate; - req->op.open.buffer_sz = buffer_sz; - req->op.open.period_sz = period_sz; - req->op.open.gref_directory = - xen_front_pgdir_shbuf_get_dir_start(shbuf); - mutex_unlock(&evtchnl->ring_io_lock); + guard(mutex)(&evtchnl->u.req.req_io_lock); + + scoped_guard(mutex, &evtchnl->ring_io_lock) { + req = be_stream_prepare_req(evtchnl, XENSND_OP_OPEN); + req->op.open.pcm_format = format; + req->op.open.pcm_channels = channels; + req->op.open.pcm_rate = rate; + req->op.open.buffer_sz = buffer_sz; + req->op.open.period_sz = period_sz; + req->op.open.gref_directory = + xen_front_pgdir_shbuf_get_dir_start(shbuf); + } ret = be_stream_do_io(evtchnl); if (ret == 0) ret = be_stream_wait_io(evtchnl); - mutex_unlock(&evtchnl->u.req.req_io_lock); return ret; } @@ -117,18 +115,17 @@ int xen_snd_front_stream_close(struct xen_snd_front_evtchnl *evtchnl) __always_unused struct xensnd_req *req; int ret; - mutex_lock(&evtchnl->u.req.req_io_lock); + guard(mutex)(&evtchnl->u.req.req_io_lock); - mutex_lock(&evtchnl->ring_io_lock); - req = be_stream_prepare_req(evtchnl, XENSND_OP_CLOSE); - mutex_unlock(&evtchnl->ring_io_lock); + scoped_guard(mutex, &evtchnl->ring_io_lock) { + req = be_stream_prepare_req(evtchnl, XENSND_OP_CLOSE); + } ret = be_stream_do_io(evtchnl); if (ret == 0) ret = be_stream_wait_io(evtchnl); - mutex_unlock(&evtchnl->u.req.req_io_lock); return ret; } @@ -138,20 +135,19 @@ int xen_snd_front_stream_write(struct xen_snd_front_evtchnl *evtchnl, struct xensnd_req *req; int ret; - mutex_lock(&evtchnl->u.req.req_io_lock); + guard(mutex)(&evtchnl->u.req.req_io_lock); - mutex_lock(&evtchnl->ring_io_lock); - req = be_stream_prepare_req(evtchnl, XENSND_OP_WRITE); - req->op.rw.length = count; - req->op.rw.offset = pos; - mutex_unlock(&evtchnl->ring_io_lock); + scoped_guard(mutex, &evtchnl->ring_io_lock) { + req = be_stream_prepare_req(evtchnl, XENSND_OP_WRITE); + req->op.rw.length = count; + req->op.rw.offset = pos; + } ret = be_stream_do_io(evtchnl); if (ret == 0) ret = be_stream_wait_io(evtchnl); - mutex_unlock(&evtchnl->u.req.req_io_lock); return ret; } @@ -161,20 +157,19 @@ int xen_snd_front_stream_read(struct xen_snd_front_evtchnl *evtchnl, struct xensnd_req *req; int ret; - mutex_lock(&evtchnl->u.req.req_io_lock); + guard(mutex)(&evtchnl->u.req.req_io_lock); - mutex_lock(&evtchnl->ring_io_lock); - req = be_stream_prepare_req(evtchnl, XENSND_OP_READ); - req->op.rw.length = count; - req->op.rw.offset = pos; - mutex_unlock(&evtchnl->ring_io_lock); + scoped_guard(mutex, &evtchnl->ring_io_lock) { + req = be_stream_prepare_req(evtchnl, XENSND_OP_READ); + req->op.rw.length = count; + req->op.rw.offset = pos; + } ret = be_stream_do_io(evtchnl); if (ret == 0) ret = be_stream_wait_io(evtchnl); - mutex_unlock(&evtchnl->u.req.req_io_lock); return ret; } @@ -184,19 +179,18 @@ int xen_snd_front_stream_trigger(struct xen_snd_front_evtchnl *evtchnl, struct xensnd_req *req; int ret; - mutex_lock(&evtchnl->u.req.req_io_lock); + guard(mutex)(&evtchnl->u.req.req_io_lock); - mutex_lock(&evtchnl->ring_io_lock); - req = be_stream_prepare_req(evtchnl, XENSND_OP_TRIGGER); - req->op.trigger.type = type; - mutex_unlock(&evtchnl->ring_io_lock); + scoped_guard(mutex, &evtchnl->ring_io_lock) { + req = be_stream_prepare_req(evtchnl, XENSND_OP_TRIGGER); + req->op.trigger.type = type; + } ret = be_stream_do_io(evtchnl); if (ret == 0) ret = be_stream_wait_io(evtchnl); - mutex_unlock(&evtchnl->u.req.req_io_lock); return ret; } diff --git a/sound/xen/xen_snd_front_evtchnl.c b/sound/xen/xen_snd_front_evtchnl.c index 26d1b3987887c6..2fbed8e4a490e1 100644 --- a/sound/xen/xen_snd_front_evtchnl.c +++ b/sound/xen/xen_snd_front_evtchnl.c @@ -28,7 +28,7 @@ static irqreturn_t evtchnl_interrupt_req(int irq, void *dev_id) if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED)) return IRQ_HANDLED; - mutex_lock(&channel->ring_io_lock); + guard(mutex)(&channel->ring_io_lock); again: rp = channel->u.req.ring.sring->rsp_prod; @@ -80,7 +80,6 @@ static irqreturn_t evtchnl_interrupt_req(int irq, void *dev_id) channel->u.req.ring.sring->rsp_event = i + 1; } - mutex_unlock(&channel->ring_io_lock); return IRQ_HANDLED; } @@ -93,13 +92,13 @@ static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id) if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED)) return IRQ_HANDLED; - mutex_lock(&channel->ring_io_lock); + guard(mutex)(&channel->ring_io_lock); prod = page->in_prod; /* Ensure we see ring contents up to prod. */ virt_rmb(); if (prod == page->in_cons) - goto out; + return IRQ_HANDLED; /* * Assume that the backend is trusted to always write sane values @@ -125,8 +124,6 @@ static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id) /* Ensure ring contents. */ virt_wmb(); -out: - mutex_unlock(&channel->ring_io_lock); return IRQ_HANDLED; } @@ -444,23 +441,23 @@ void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair else state = EVTCHNL_STATE_DISCONNECTED; - mutex_lock(&evt_pair->req.ring_io_lock); - evt_pair->req.state = state; - mutex_unlock(&evt_pair->req.ring_io_lock); + scoped_guard(mutex, &evt_pair->req.ring_io_lock) { + evt_pair->req.state = state; + } - mutex_lock(&evt_pair->evt.ring_io_lock); - evt_pair->evt.state = state; - mutex_unlock(&evt_pair->evt.ring_io_lock); + scoped_guard(mutex, &evt_pair->evt.ring_io_lock) { + evt_pair->evt.state = state; + } } void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair *evt_pair) { - mutex_lock(&evt_pair->req.ring_io_lock); - evt_pair->req.evt_next_id = 0; - mutex_unlock(&evt_pair->req.ring_io_lock); + scoped_guard(mutex, &evt_pair->req.ring_io_lock) { + evt_pair->req.evt_next_id = 0; + } - mutex_lock(&evt_pair->evt.ring_io_lock); - evt_pair->evt.evt_next_id = 0; - mutex_unlock(&evt_pair->evt.ring_io_lock); + scoped_guard(mutex, &evt_pair->evt.ring_io_lock) { + evt_pair->evt.evt_next_id = 0; + } } From 7b4d15bcdc8bb15d72363f1497e147d570441269 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:23 +0200 Subject: [PATCH 1020/1292] ALSA: at73c213: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-10-tiwai@suse.de --- sound/spi/at73c213.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index a0a7f90b614693..0ece7ccbd55fae 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -401,7 +401,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - mutex_lock(&chip->mixer_lock); + guard(mutex)(&chip->mixer_lock); ucontrol->value.integer.value[0] = (chip->reg_image[reg] >> shift) & mask; @@ -410,8 +410,6 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - mutex_unlock(&chip->mixer_lock); - return 0; } @@ -431,14 +429,12 @@ static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, val = mask - val; val <<= shift; - mutex_lock(&chip->mixer_lock); + guard(mutex)(&chip->mixer_lock); val = (chip->reg_image[reg] & ~(mask << shift)) | val; change = val != chip->reg_image[reg]; retval = snd_at73c213_write_reg(chip, reg, val); - mutex_unlock(&chip->mixer_lock); - if (retval) return retval; @@ -473,7 +469,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - mutex_lock(&chip->mixer_lock); + guard(mutex)(&chip->mixer_lock); ucontrol->value.integer.value[0] = (chip->reg_image[left_reg] >> shift_left) & mask; @@ -487,8 +483,6 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, mask - ucontrol->value.integer.value[1]; } - mutex_unlock(&chip->mixer_lock); - return 0; } @@ -514,29 +508,20 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, val1 <<= shift_left; val2 <<= shift_right; - mutex_lock(&chip->mixer_lock); + guard(mutex)(&chip->mixer_lock); val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; change = val1 != chip->reg_image[left_reg] || val2 != chip->reg_image[right_reg]; retval = snd_at73c213_write_reg(chip, left_reg, val1); - if (retval) { - mutex_unlock(&chip->mixer_lock); - goto out; - } + if (retval) + return retval; retval = snd_at73c213_write_reg(chip, right_reg, val2); - if (retval) { - mutex_unlock(&chip->mixer_lock); - goto out; - } - - mutex_unlock(&chip->mixer_lock); + if (retval) + return retval; return change; - -out: - return retval; } #define snd_at73c213_mono_switch_info snd_ctl_boolean_mono_info @@ -549,7 +534,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, int shift = (kcontrol->private_value >> 8) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - mutex_lock(&chip->mixer_lock); + guard(mutex)(&chip->mixer_lock); ucontrol->value.integer.value[0] = (chip->reg_image[reg] >> shift) & 0x01; @@ -558,8 +543,6 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = 0x01 - ucontrol->value.integer.value[0]; - mutex_unlock(&chip->mixer_lock); - return 0; } @@ -583,15 +566,13 @@ static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, val = mask - val; val <<= shift; - mutex_lock(&chip->mixer_lock); + guard(mutex)(&chip->mixer_lock); val |= (chip->reg_image[reg] & ~(mask << shift)); change = val != chip->reg_image[reg]; retval = snd_at73c213_write_reg(chip, reg, val); - mutex_unlock(&chip->mixer_lock); - if (retval) return retval; From 2c24032607d6d5f2e1ac3cbd46eaf4722880ba83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:24 +0200 Subject: [PATCH 1021/1292] ALSA: pdaudiocf: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-11-tiwai@suse.de --- sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 3 +-- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index 11aacc7e3f0b03..a104baac3a941f 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -161,14 +161,13 @@ static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, uns if (!(c0 & AK4117_UNLCK)) return; - mutex_lock(&chip->reg_lock); + guard(mutex)(&chip->reg_lock); val = chip->regmap[PDAUDIOCF_REG_SCR>>1]; if (ak4117->rcs0 & AK4117_UNLCK) val |= PDAUDIOCF_BLUE_LED_OFF; else val &= ~PDAUDIOCF_BLUE_LED_OFF; pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); - mutex_unlock(&chip->reg_lock); } int snd_pdacf_ak4117_create(struct snd_pdacf *chip) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 20aba745f1dcdf..228822996ef78b 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -64,21 +64,20 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) default: return -EINVAL; } - mutex_lock(&chip->reg_lock); - chip->pcm_running += inc; - tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); - if (chip->pcm_running) { - if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) { - chip->pcm_running -= inc; - ret = -EIO; - goto __end; + scoped_guard(mutex, &chip->reg_lock) { + chip->pcm_running += inc; + tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); + if (chip->pcm_running) { + if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) { + chip->pcm_running -= inc; + ret = -EIO; + break; + } } + tmp &= ~mask; + tmp |= val; + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp); } - tmp &= ~mask; - tmp |= val; - pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp); - __end: - mutex_unlock(&chip->reg_lock); snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE); return ret; } From 89008621bb2dcfcb8905f58a64cadcbdb16c9214 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:25 +0200 Subject: [PATCH 1022/1292] ALSA: vxpocket: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-12-tiwai@suse.de --- sound/pcmcia/vx/vxp_mixer.c | 9 +++------ sound/pcmcia/vx/vxp_ops.c | 6 ++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index bc2114475810c6..998cea2d03180c 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -43,14 +43,12 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v if (val > MIC_LEVEL_MAX) return -EINVAL; - mutex_lock(&_chip->mixer_mutex); + guard(mutex)(&_chip->mixer_mutex); if (chip->mic_level != ucontrol->value.integer.value[0]) { vx_set_mic_level(_chip, ucontrol->value.integer.value[0]); chip->mic_level = ucontrol->value.integer.value[0]; - mutex_unlock(&_chip->mixer_mutex); return 1; } - mutex_unlock(&_chip->mixer_mutex); return 0; } @@ -85,14 +83,13 @@ static int vx_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v struct vx_core *_chip = snd_kcontrol_chip(kcontrol); struct snd_vxpocket *chip = to_vxpocket(_chip); int val = !!ucontrol->value.integer.value[0]; - mutex_lock(&_chip->mixer_mutex); + + guard(mutex)(&_chip->mixer_mutex); if (chip->mic_level != val) { vx_set_mic_boost(_chip, val); chip->mic_level = val; - mutex_unlock(&_chip->mixer_mutex); return 1; } - mutex_unlock(&_chip->mixer_mutex); return 0; } diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 0bc5c5d9d15742..4211e7239138c4 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c @@ -463,7 +463,7 @@ void vx_set_mic_boost(struct vx_core *chip, int boost) if (chip->chip_status & VX_STAT_IS_STALE) return; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) { if (boost) { /* boost: 38 dB */ @@ -476,7 +476,6 @@ void vx_set_mic_boost(struct vx_core *chip, int boost) } vx_outb(chip, CDSP, pchip->regCDSP); } - mutex_unlock(&chip->lock); } /* @@ -505,12 +504,11 @@ void vx_set_mic_level(struct vx_core *chip, int level) if (chip->chip_status & VX_STAT_IS_STALE) return; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) { level = vx_compute_mic_level(level); vx_outb(chip, MICRO, level); } - mutex_unlock(&chip->lock); } From 3d10c26fae4ec629a78b1c3189a6f6a0a8c053ba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:26 +0200 Subject: [PATCH 1023/1292] ALSA: sparc: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-13-tiwai@suse.de --- sound/sparc/cs4231.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 1a1fe3ceb76c9e..8d54617e252689 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -608,7 +608,7 @@ static void snd_cs4231_playback_format(struct snd_cs4231 *chip, { unsigned long flags; - mutex_lock(&chip->mce_mutex); + guard(mutex)(&chip->mce_mutex); snd_cs4231_calibrate_mute(chip, 1); snd_cs4231_mce_up(chip); @@ -623,7 +623,6 @@ static void snd_cs4231_playback_format(struct snd_cs4231 *chip, snd_cs4231_mce_down(chip); snd_cs4231_calibrate_mute(chip, 0); - mutex_unlock(&chip->mce_mutex); } static void snd_cs4231_capture_format(struct snd_cs4231 *chip, @@ -632,7 +631,7 @@ static void snd_cs4231_capture_format(struct snd_cs4231 *chip, { unsigned long flags; - mutex_lock(&chip->mce_mutex); + guard(mutex)(&chip->mce_mutex); snd_cs4231_calibrate_mute(chip, 1); snd_cs4231_mce_up(chip); @@ -653,7 +652,6 @@ static void snd_cs4231_capture_format(struct snd_cs4231 *chip, snd_cs4231_mce_down(chip); snd_cs4231_calibrate_mute(chip, 0); - mutex_unlock(&chip->mce_mutex); } /* @@ -775,14 +773,11 @@ static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode) { unsigned long flags; - mutex_lock(&chip->open_mutex); - if ((chip->mode & mode)) { - mutex_unlock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); + if ((chip->mode & mode)) return -EAGAIN; - } if (chip->mode & CS4231_MODE_OPEN) { chip->mode |= mode; - mutex_unlock(&chip->open_mutex); return 0; } /* ok. now enable and ack CODEC IRQ */ @@ -802,7 +797,6 @@ static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode) spin_unlock_irqrestore(&chip->lock, flags); chip->mode = mode; - mutex_unlock(&chip->open_mutex); return 0; } @@ -810,12 +804,10 @@ static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode) { unsigned long flags; - mutex_lock(&chip->open_mutex); + guard(mutex)(&chip->open_mutex); chip->mode &= ~mode; - if (chip->mode & CS4231_MODE_OPEN) { - mutex_unlock(&chip->open_mutex); + if (chip->mode & CS4231_MODE_OPEN) return; - } snd_cs4231_calibrate_mute(chip, 1); /* disable IRQ */ @@ -851,7 +843,6 @@ static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode) snd_cs4231_calibrate_mute(chip, 0); chip->mode = 0; - mutex_unlock(&chip->open_mutex); } /* From 1cb6ecbb372002ef9e531c5377e5f60122411e40 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:27 +0200 Subject: [PATCH 1024/1292] ALSA: aoa: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-14-tiwai@suse.de --- sound/aoa/codecs/onyx.c | 104 +++++++++-------------------- sound/aoa/codecs/tas.c | 113 +++++++++++--------------------- sound/aoa/core/gpio-feature.c | 20 ++---- sound/aoa/core/gpio-pmf.c | 26 +++----- sound/aoa/soundbus/i2sbus/pcm.c | 76 +++++++-------------- 5 files changed, 112 insertions(+), 227 deletions(-) diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index ac347a14f282cf..7400a5aa47ca64 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -122,10 +122,9 @@ static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol, struct onyx *onyx = snd_kcontrol_chip(kcontrol); s8 l, r; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); - mutex_unlock(&onyx->mutex); ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT; ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT; @@ -146,15 +145,13 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT) return -EINVAL; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] && - r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) { - mutex_unlock(&onyx->mutex); + r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) return 0; - } onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, ucontrol->value.integer.value[0] @@ -162,7 +159,6 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol, onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, ucontrol->value.integer.value[1] - VOLUME_RANGE_SHIFT); - mutex_unlock(&onyx->mutex); return 1; } @@ -198,9 +194,8 @@ static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol, struct onyx *onyx = snd_kcontrol_chip(kcontrol); u8 ig; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig); - mutex_unlock(&onyx->mutex); ucontrol->value.integer.value[0] = (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT; @@ -217,14 +212,13 @@ static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT || ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT) return -EINVAL; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); n = v; n &= ~ONYX_ADC_PGA_GAIN_MASK; n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT) & ONYX_ADC_PGA_GAIN_MASK; onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n); - mutex_unlock(&onyx->mutex); return n != v; } @@ -252,9 +246,8 @@ static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol, struct onyx *onyx = snd_kcontrol_chip(kcontrol); s8 v; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); - mutex_unlock(&onyx->mutex); ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC); @@ -265,13 +258,12 @@ static void onyx_set_capture_source(struct onyx *onyx, int mic) { s8 v; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); v &= ~ONYX_ADC_INPUT_MIC; if (mic) v |= ONYX_ADC_INPUT_MIC; onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v); - mutex_unlock(&onyx->mutex); } static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol, @@ -312,9 +304,8 @@ static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol, struct onyx *onyx = snd_kcontrol_chip(kcontrol); u8 c; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c); - mutex_unlock(&onyx->mutex); ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT); ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT); @@ -329,9 +320,9 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol, u8 v = 0, c = 0; int err = -EBUSY; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); if (onyx->analog_locked) - goto out_unlock; + return -EBUSY; onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); c = v; @@ -342,9 +333,6 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol, c |= ONYX_MUTE_RIGHT; err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c); - out_unlock: - mutex_unlock(&onyx->mutex); - return !err ? (v != c) : err; } @@ -373,9 +361,8 @@ static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol, u8 address = (pv >> 8) & 0xff; u8 mask = pv & 0xff; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, address, &c); - mutex_unlock(&onyx->mutex); ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity; @@ -394,11 +381,10 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol, u8 address = (pv >> 8) & 0xff; u8 mask = pv & 0xff; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); if (spdiflock && onyx->spdif_locked) { /* even if alsamixer doesn't care.. */ - err = -EBUSY; - goto out_unlock; + return -EBUSY; } onyx_read_register(onyx, address, &v); c = v; @@ -407,9 +393,6 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol, c |= mask; err = onyx_write_register(onyx, address, c); - out_unlock: - mutex_unlock(&onyx->mutex); - return !err ? (v != c) : err; } @@ -490,7 +473,7 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol, struct onyx *onyx = snd_kcontrol_chip(kcontrol); u8 v; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v); ucontrol->value.iec958.status[0] = v & 0x3e; @@ -502,7 +485,6 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol, onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); ucontrol->value.iec958.status[4] = v & 0x0f; - mutex_unlock(&onyx->mutex); return 0; } @@ -513,7 +495,7 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol, struct onyx *onyx = snd_kcontrol_chip(kcontrol); u8 v; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v); v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e); onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v); @@ -528,7 +510,6 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol, onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f); onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v); - mutex_unlock(&onyx->mutex); return 1; } @@ -673,14 +654,13 @@ static int onyx_usable(struct codec_info_item *cii, struct onyx *onyx = cii->codec_data; int spdif_enabled, analog_enabled; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); spdif_enabled = !!(v & ONYX_SPDIF_ENABLE); onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); analog_enabled = (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT)) != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT); - mutex_unlock(&onyx->mutex); switch (ti->tag) { case 0: return 1; @@ -696,9 +676,8 @@ static int onyx_prepare(struct codec_info_item *cii, { u8 v; struct onyx *onyx = cii->codec_data; - int err = -EBUSY; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) { @@ -707,10 +686,9 @@ static int onyx_prepare(struct codec_info_item *cii, if (onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT)) - goto out_unlock; + return -EBUSY; onyx->analog_locked = 1; - err = 0; - goto out_unlock; + return 0; } #endif switch (substream->runtime->rate) { @@ -720,8 +698,7 @@ static int onyx_prepare(struct codec_info_item *cii, /* these rates are ok for all outputs */ /* FIXME: program spdif channel control bits here so that * userspace doesn't have to if it only plays pcm! */ - err = 0; - goto out_unlock; + return 0; default: /* got some rate that the digital output can't do, * so disable and lock it */ @@ -729,16 +706,12 @@ static int onyx_prepare(struct codec_info_item *cii, if (onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v & ~ONYX_SPDIF_ENABLE)) - goto out_unlock; + return -EBUSY; onyx->spdif_locked = 1; - err = 0; - goto out_unlock; + return 0; } - out_unlock: - mutex_unlock(&onyx->mutex); - - return err; + return -EBUSY; } static int onyx_open(struct codec_info_item *cii, @@ -746,9 +719,8 @@ static int onyx_open(struct codec_info_item *cii, { struct onyx *onyx = cii->codec_data; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx->open_count++; - mutex_unlock(&onyx->mutex); return 0; } @@ -758,11 +730,10 @@ static int onyx_close(struct codec_info_item *cii, { struct onyx *onyx = cii->codec_data; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); onyx->open_count--; if (!onyx->open_count) onyx->spdif_locked = onyx->analog_locked = 0; - mutex_unlock(&onyx->mutex); return 0; } @@ -772,7 +743,7 @@ static int onyx_switch_clock(struct codec_info_item *cii, { struct onyx *onyx = cii->codec_data; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); /* this *MUST* be more elaborate later... */ switch (what) { case CLOCK_SWITCH_PREPARE_SLAVE: @@ -784,7 +755,6 @@ static int onyx_switch_clock(struct codec_info_item *cii, default: /* silence warning */ break; } - mutex_unlock(&onyx->mutex); return 0; } @@ -795,27 +765,21 @@ static int onyx_suspend(struct codec_info_item *cii, pm_message_t state) { struct onyx *onyx = cii->codec_data; u8 v; - int err = -ENXIO; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) - goto out_unlock; + return -ENXIO; onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV); /* Apple does a sleep here but the datasheet says to do it on resume */ - err = 0; - out_unlock: - mutex_unlock(&onyx->mutex); - - return err; + return 0; } static int onyx_resume(struct codec_info_item *cii) { struct onyx *onyx = cii->codec_data; u8 v; - int err = -ENXIO; - mutex_lock(&onyx->mutex); + guard(mutex)(&onyx->mutex); /* reset codec */ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); @@ -827,17 +791,13 @@ static int onyx_resume(struct codec_info_item *cii) /* take codec out of suspend (if it still is after reset) */ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) - goto out_unlock; + return -ENXIO; onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV)); /* FIXME: should divide by sample rate, but 8k is the lowest we go */ msleep(2205000/8000); /* reset all values */ onyx_register_init(onyx); - err = 0; - out_unlock: - mutex_unlock(&onyx->mutex); - - return err; + return 0; } #endif /* CONFIG_PM */ diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 804b2ebbe28fe8..70216aa059650e 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -235,10 +235,9 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.integer.value[0] = tas->cached_volume_l; ucontrol->value.integer.value[1] = tas->cached_volume_r; - mutex_unlock(&tas->mtx); return 0; } @@ -254,18 +253,15 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[1] > 177) return -EINVAL; - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); if (tas->cached_volume_l == ucontrol->value.integer.value[0] - && tas->cached_volume_r == ucontrol->value.integer.value[1]) { - mutex_unlock(&tas->mtx); + && tas->cached_volume_r == ucontrol->value.integer.value[1]) return 0; - } tas->cached_volume_l = ucontrol->value.integer.value[0]; tas->cached_volume_r = ucontrol->value.integer.value[1]; if (tas->hw_enabled) tas_set_volume(tas); - mutex_unlock(&tas->mtx); return 1; } @@ -285,10 +281,9 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.integer.value[0] = !tas->mute_l; ucontrol->value.integer.value[1] = !tas->mute_r; - mutex_unlock(&tas->mtx); return 0; } @@ -297,18 +292,15 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); if (tas->mute_l == !ucontrol->value.integer.value[0] - && tas->mute_r == !ucontrol->value.integer.value[1]) { - mutex_unlock(&tas->mtx); + && tas->mute_r == !ucontrol->value.integer.value[1]) return 0; - } tas->mute_l = !ucontrol->value.integer.value[0]; tas->mute_r = !ucontrol->value.integer.value[1]; if (tas->hw_enabled) tas_set_volume(tas); - mutex_unlock(&tas->mtx); return 1; } @@ -337,10 +329,9 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol, struct tas *tas = snd_kcontrol_chip(kcontrol); int idx = kcontrol->private_value; - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.integer.value[0] = tas->mixer_l[idx]; ucontrol->value.integer.value[1] = tas->mixer_r[idx]; - mutex_unlock(&tas->mtx); return 0; } @@ -351,19 +342,16 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol, struct tas *tas = snd_kcontrol_chip(kcontrol); int idx = kcontrol->private_value; - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] - && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) { - mutex_unlock(&tas->mtx); + && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) return 0; - } tas->mixer_l[idx] = ucontrol->value.integer.value[0]; tas->mixer_r[idx] = ucontrol->value.integer.value[1]; if (tas->hw_enabled) tas_set_mixer(tas); - mutex_unlock(&tas->mtx); return 1; } @@ -396,9 +384,8 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.integer.value[0] = tas->drc_range; - mutex_unlock(&tas->mtx); return 0; } @@ -411,16 +398,13 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] > TAS3004_DRC_MAX) return -EINVAL; - mutex_lock(&tas->mtx); - if (tas->drc_range == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); + guard(mutex)(&tas->mtx); + if (tas->drc_range == ucontrol->value.integer.value[0]) return 0; - } tas->drc_range = ucontrol->value.integer.value[0]; if (tas->hw_enabled) tas3004_set_drc(tas); - mutex_unlock(&tas->mtx); return 1; } @@ -440,9 +424,8 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.integer.value[0] = tas->drc_enabled; - mutex_unlock(&tas->mtx); return 0; } @@ -451,16 +434,13 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); - if (tas->drc_enabled == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); + guard(mutex)(&tas->mtx); + if (tas->drc_enabled == ucontrol->value.integer.value[0]) return 0; - } tas->drc_enabled = !!ucontrol->value.integer.value[0]; if (tas->hw_enabled) tas3004_set_drc(tas); - mutex_unlock(&tas->mtx); return 1; } @@ -486,9 +466,8 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); - mutex_unlock(&tas->mtx); return 0; } @@ -500,7 +479,7 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.enumerated.item[0] > 1) return -EINVAL; - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); oldacr = tas->acr; /* @@ -512,13 +491,10 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.enumerated.item[0]) tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL | TAS_ACR_B_MON_SEL_RIGHT; - if (oldacr == tas->acr) { - mutex_unlock(&tas->mtx); + if (oldacr == tas->acr) return 0; - } if (tas->hw_enabled) tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); - mutex_unlock(&tas->mtx); return 1; } @@ -557,9 +533,8 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.integer.value[0] = tas->treble; - mutex_unlock(&tas->mtx); return 0; } @@ -571,16 +546,13 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN || ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX) return -EINVAL; - mutex_lock(&tas->mtx); - if (tas->treble == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); + guard(mutex)(&tas->mtx); + if (tas->treble == ucontrol->value.integer.value[0]) return 0; - } tas->treble = ucontrol->value.integer.value[0]; if (tas->hw_enabled) tas_set_treble(tas); - mutex_unlock(&tas->mtx); return 1; } @@ -608,9 +580,8 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); ucontrol->value.integer.value[0] = tas->bass; - mutex_unlock(&tas->mtx); return 0; } @@ -622,16 +593,13 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN || ucontrol->value.integer.value[0] > TAS3004_BASS_MAX) return -EINVAL; - mutex_lock(&tas->mtx); - if (tas->bass == ucontrol->value.integer.value[0]) { - mutex_unlock(&tas->mtx); + guard(mutex)(&tas->mtx); + if (tas->bass == ucontrol->value.integer.value[0]) return 0; - } tas->bass = ucontrol->value.integer.value[0]; if (tas->hw_enabled) tas_set_bass(tas); - mutex_unlock(&tas->mtx); return 1; } @@ -722,13 +690,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock break; case CLOCK_SWITCH_SLAVE: /* Clocks are back, re-init the codec */ - mutex_lock(&tas->mtx); - tas_reset_init(tas); - tas_set_volume(tas); - tas_set_mixer(tas); - tas->hw_enabled = 1; - tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); - mutex_unlock(&tas->mtx); + scoped_guard(mutex, &tas->mtx) { + tas_reset_init(tas); + tas_set_volume(tas); + tas_set_mixer(tas); + tas->hw_enabled = 1; + tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); + } break; default: /* doesn't happen as of now */ @@ -743,23 +711,21 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock * our i2c device is suspended, and then take note of that! */ static int tas_suspend(struct tas *tas) { - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); tas->hw_enabled = 0; tas->acr |= TAS_ACR_ANALOG_PDOWN; tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); - mutex_unlock(&tas->mtx); return 0; } static int tas_resume(struct tas *tas) { /* reset codec */ - mutex_lock(&tas->mtx); + guard(mutex)(&tas->mtx); tas_reset_init(tas); tas_set_volume(tas); tas_set_mixer(tas); tas->hw_enabled = 1; - mutex_unlock(&tas->mtx); return 0; } @@ -802,14 +768,13 @@ static int tas_init_codec(struct aoa_codec *codec) return -EINVAL; } - mutex_lock(&tas->mtx); - if (tas_reset_init(tas)) { - printk(KERN_ERR PFX "tas failed to initialise\n"); - mutex_unlock(&tas->mtx); - return -ENXIO; + scoped_guard(mutex, &tas->mtx) { + if (tas_reset_init(tas)) { + printk(KERN_ERR PFX "tas failed to initialise\n"); + return -ENXIO; + } + tas->hw_enabled = 1; } - tas->hw_enabled = 1; - mutex_unlock(&tas->mtx); if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, aoa_get_card(), diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c index 39bb409b27f6d8..19ed0e6907da3f 100644 --- a/sound/aoa/core/gpio-feature.c +++ b/sound/aoa/core/gpio-feature.c @@ -212,10 +212,9 @@ static void ftr_handle_notify(struct work_struct *work) struct gpio_notification *notif = container_of(work, struct gpio_notification, work.work); - mutex_lock(¬if->mutex); + guard(mutex)(¬if->mutex); if (notif->notify) notif->notify(notif->data); - mutex_unlock(¬if->mutex); } static void gpio_enable_dual_edge(int gpio) @@ -341,19 +340,17 @@ static int ftr_set_notify(struct gpio_runtime *rt, if (!irq) return -ENODEV; - mutex_lock(¬if->mutex); + guard(mutex)(¬if->mutex); old = notif->notify; - if (!old && !notify) { - err = 0; - goto out_unlock; - } + if (!old && !notify) + return 0; if (old && notify) { if (old == notify && notif->data == data) err = 0; - goto out_unlock; + return err; } if (old && !notify) @@ -362,16 +359,13 @@ static int ftr_set_notify(struct gpio_runtime *rt, if (!old && notify) { err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif); if (err) - goto out_unlock; + return err; } notif->notify = notify; notif->data = data; - err = 0; - out_unlock: - mutex_unlock(¬if->mutex); - return err; + return 0; } static int ftr_get_detect(struct gpio_runtime *rt, diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/gpio-pmf.c index 37866039d1ead4..e76bde25e41afa 100644 --- a/sound/aoa/core/gpio-pmf.c +++ b/sound/aoa/core/gpio-pmf.c @@ -74,10 +74,9 @@ static void pmf_handle_notify(struct work_struct *work) struct gpio_notification *notif = container_of(work, struct gpio_notification, work.work); - mutex_lock(¬if->mutex); + guard(mutex)(¬if->mutex); if (notif->notify) notif->notify(notif->data); - mutex_unlock(¬if->mutex); } static void pmf_gpio_init(struct gpio_runtime *rt) @@ -154,19 +153,17 @@ static int pmf_set_notify(struct gpio_runtime *rt, return -EINVAL; } - mutex_lock(¬if->mutex); + guard(mutex)(¬if->mutex); old = notif->notify; - if (!old && !notify) { - err = 0; - goto out_unlock; - } + if (!old && !notify) + return 0; if (old && notify) { if (old == notify && notif->data == data) err = 0; - goto out_unlock; + return err; } if (old && !notify) { @@ -178,10 +175,8 @@ static int pmf_set_notify(struct gpio_runtime *rt, if (!old && notify) { irq_client = kzalloc(sizeof(struct pmf_irq_client), GFP_KERNEL); - if (!irq_client) { - err = -ENOMEM; - goto out_unlock; - } + if (!irq_client) + return -ENOMEM; irq_client->data = notif; irq_client->handler = pmf_handle_notify_irq; irq_client->owner = THIS_MODULE; @@ -192,17 +187,14 @@ static int pmf_set_notify(struct gpio_runtime *rt, printk(KERN_ERR "snd-aoa: gpio layer failed to" " register %s irq (%d)\n", name, err); kfree(irq_client); - goto out_unlock; + return err; } notif->gpio_private = irq_client; } notif->notify = notify; notif->data = data; - err = 0; - out_unlock: - mutex_unlock(¬if->mutex); - return err; + return 0; } static int pmf_get_detect(struct gpio_runtime *rt, diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 98b812ffbde68e..1edda4c9c6ab38 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -79,11 +79,10 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) u64 formats = 0; unsigned int rates = 0; struct transfer_info v; - int result = 0; int bus_factor = 0, sysclock_factor = 0; int found_this; - mutex_lock(&i2sdev->lock); + guard(mutex)(&i2sdev->lock); get_pcm_info(i2sdev, in, &pi, &other); @@ -92,8 +91,7 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) if (pi->active) { /* alsa messed up */ - result = -EBUSY; - goto out_unlock; + return -EBUSY; } /* we now need to assign the hw */ @@ -117,10 +115,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) ti++; } } - if (!masks_inited || !bus_factor || !sysclock_factor) { - result = -ENODEV; - goto out_unlock; - } + if (!masks_inited || !bus_factor || !sysclock_factor) + return -ENODEV; /* bus dependent stuff */ hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | @@ -194,15 +190,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) hw->periods_max = MAX_DBDMA_COMMANDS; err = snd_pcm_hw_constraint_integer(pi->substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - result = err; - goto out_unlock; - } + if (err < 0) + return err; list_for_each_entry(cii, &sdev->codec_list, list) { if (cii->codec->open) { err = cii->codec->open(cii, pi->substream); if (err) { - result = err; /* unwind */ found_this = 0; list_for_each_entry_reverse(rev, @@ -214,14 +207,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) if (rev == cii) found_this = 1; } - goto out_unlock; + return err; } } } - out_unlock: - mutex_unlock(&i2sdev->lock); - return result; + return 0; } #undef CHECK_RATE @@ -232,7 +223,7 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) struct pcm_info *pi; int err = 0, tmp; - mutex_lock(&i2sdev->lock); + guard(mutex)(&i2sdev->lock); get_pcm_info(i2sdev, in, &pi, NULL); @@ -246,7 +237,6 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) pi->substream = NULL; pi->active = 0; - mutex_unlock(&i2sdev->lock); return err; } @@ -330,33 +320,26 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) int input_16bit; struct pcm_info *pi, *other; int cnt; - int result = 0; unsigned int cmd, stopaddr; - mutex_lock(&i2sdev->lock); + guard(mutex)(&i2sdev->lock); get_pcm_info(i2sdev, in, &pi, &other); - if (pi->dbdma_ring.running) { - result = -EBUSY; - goto out_unlock; - } + if (pi->dbdma_ring.running) + return -EBUSY; if (pi->dbdma_ring.stopping) i2sbus_wait_for_stop(i2sdev, pi); - if (!pi->substream || !pi->substream->runtime) { - result = -EINVAL; - goto out_unlock; - } + if (!pi->substream || !pi->substream->runtime) + return -EINVAL; runtime = pi->substream->runtime; pi->active = 1; if (other->active && ((i2sdev->format != runtime->format) - || (i2sdev->rate != runtime->rate))) { - result = -EINVAL; - goto out_unlock; - } + || (i2sdev->rate != runtime->rate))) + return -EINVAL; i2sdev->format = runtime->format; i2sdev->rate = runtime->rate; @@ -412,10 +395,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) bi.bus_factor = cii->codec->bus_factor; break; } - if (!bi.bus_factor) { - result = -ENODEV; - goto out_unlock; - } + if (!bi.bus_factor) + return -ENODEV; input_16bit = 1; break; case SNDRV_PCM_FORMAT_S32_BE: @@ -426,8 +407,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) input_16bit = 0; break; default: - result = -EINVAL; - goto out_unlock; + return -EINVAL; } /* we assume all sysclocks are the same! */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { @@ -438,10 +418,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) if (clock_and_divisors(bi.sysclock_factor, bi.bus_factor, runtime->rate, - &sfr) < 0) { - result = -EINVAL; - goto out_unlock; - } + &sfr) < 0) + return -EINVAL; switch (bi.bus_factor) { case 32: sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X; @@ -457,10 +435,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) int err = 0; if (cii->codec->prepare) err = cii->codec->prepare(cii, &bi, pi->substream); - if (err) { - result = err; - goto out_unlock; - } + if (err) + return err; } /* codecs are fine with it, so set our clocks */ if (input_16bit) @@ -476,7 +452,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) /* not locking these is fine since we touch them only in this function */ if (in_le32(&i2sdev->intfregs->serial_format) == sfr && in_le32(&i2sdev->intfregs->data_word_sizes) == dws) - goto out_unlock; + return 0; /* let's notify the codecs about clocks going away. * For now we only do mastering on the i2s cell... */ @@ -514,9 +490,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) if (cii->codec->switch_clock) cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE); - out_unlock: - mutex_unlock(&i2sdev->lock); - return result; + return 0; } #ifdef CONFIG_PM From bc58470aa2595bb21937d35572989a68e6b5f679 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:28 +0200 Subject: [PATCH 1025/1292] ALSA: aaci: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-15-tiwai@suse.de --- sound/arm/aaci.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 243965615ef2ba..881d5b067c2367 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -73,7 +73,7 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, if (ac97->num >= 4) return; - mutex_lock(&aaci->ac97_sem); + guard(mutex)(&aaci->ac97_sem); aaci_ac97_select_codec(aaci, ac97); @@ -97,8 +97,6 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, if (v & (SLFR_1TXB|SLFR_2TXB)) dev_err(&aaci->dev->dev, "timeout waiting for write to complete\n"); - - mutex_unlock(&aaci->ac97_sem); } /* @@ -113,7 +111,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) if (ac97->num >= 4) return ~0; - mutex_lock(&aaci->ac97_sem); + guard(mutex)(&aaci->ac97_sem); aaci_ac97_select_codec(aaci, ac97); @@ -134,8 +132,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) if (v & SLFR_1TXB) { dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n"); - v = ~0; - goto out; + return ~0; } /* Now wait for the response frame */ @@ -151,8 +148,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) if (v != (SLFR_1RXV|SLFR_2RXV)) { dev_err(&aaci->dev->dev, "timeout on RX valid\n"); - v = ~0; - goto out; + return ~0; } do { @@ -171,8 +167,6 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) v = ~0; } } while (retries); - out: - mutex_unlock(&aaci->ac97_sem); return v; } @@ -437,14 +431,13 @@ static int aaci_pcm_open(struct snd_pcm_substream *substream) */ runtime->hw.fifo_size = aaci->fifo_depth * 2; - mutex_lock(&aaci->irq_lock); + guard(mutex)(&aaci->irq_lock); if (!aaci->users++) { ret = request_irq(aaci->dev->irq[0], aaci_irq, IRQF_SHARED, DRIVER_NAME, aaci); if (ret != 0) aaci->users--; } - mutex_unlock(&aaci->irq_lock); return ret; } @@ -462,10 +455,9 @@ static int aaci_pcm_close(struct snd_pcm_substream *substream) aacirun->substream = NULL; - mutex_lock(&aaci->irq_lock); + guard(mutex)(&aaci->irq_lock); if (!--aaci->users) free_irq(aaci->dev->irq[0], aaci); - mutex_unlock(&aaci->irq_lock); return 0; } From 372020ddaa76ba9d18806de90448562ca12ad53e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:29 +0200 Subject: [PATCH 1026/1292] ALSA: pxa2xx: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-16-tiwai@suse.de --- sound/arm/pxa2xx-ac97-lib.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index a03a3291de8407..64510318091f4a 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -51,7 +51,7 @@ int pxa2xx_ac97_read(int slot, unsigned short reg) if (slot > 0) return -ENODEV; - mutex_lock(&car_mutex); + guard(mutex)(&car_mutex); /* set up primary or secondary codec space */ if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) @@ -67,13 +67,12 @@ int pxa2xx_ac97_read(int slot, unsigned short reg) gsr_bits = 0; val = (readl(reg_addr) & 0xffff); if (reg == AC97_GPIO_STATUS) - goto out; + return val; if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 && !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) { printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", __func__, reg, readl(ac97_reg_base + GSR) | gsr_bits); - val = -ETIMEDOUT; - goto out; + return -ETIMEDOUT; } /* valid data now */ @@ -82,8 +81,6 @@ int pxa2xx_ac97_read(int slot, unsigned short reg) val = (readl(reg_addr) & 0xffff); /* but we've just started another cycle... */ wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1); - -out: mutex_unlock(&car_mutex); return val; } EXPORT_SYMBOL_GPL(pxa2xx_ac97_read); @@ -93,7 +90,7 @@ int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val) u32 __iomem *reg_addr; int ret = 0; - mutex_lock(&car_mutex); + guard(mutex)(&car_mutex); /* set up primary or secondary codec space */ if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) @@ -114,7 +111,6 @@ int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val) ret = -EIO; } - mutex_unlock(&car_mutex); return ret; } EXPORT_SYMBOL_GPL(pxa2xx_ac97_write); From 94f8cb2b358ca2acfa489d6a54f8e614d17c0572 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:30 +0200 Subject: [PATCH 1027/1292] ALSA: atmel: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-17-tiwai@suse.de --- sound/atmel/ac97c.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 693d48f08b88be..df0a049192deeb 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -88,7 +88,7 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream) struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - mutex_lock(&opened_mutex); + guard(mutex)(&opened_mutex); chip->opened++; runtime->hw = atmel_ac97c_hw; if (chip->cur_rate) { @@ -97,7 +97,6 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream) } if (chip->cur_format) runtime->hw.formats = pcm_format_to_bits(chip->cur_format); - mutex_unlock(&opened_mutex); chip->playback_substream = substream; return 0; } @@ -107,7 +106,7 @@ static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream) struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - mutex_lock(&opened_mutex); + guard(mutex)(&opened_mutex); chip->opened++; runtime->hw = atmel_ac97c_hw; if (chip->cur_rate) { @@ -116,7 +115,6 @@ static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream) } if (chip->cur_format) runtime->hw.formats = pcm_format_to_bits(chip->cur_format); - mutex_unlock(&opened_mutex); chip->capture_substream = substream; return 0; } @@ -125,13 +123,12 @@ static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - mutex_lock(&opened_mutex); + guard(mutex)(&opened_mutex); chip->opened--; if (!chip->opened) { chip->cur_rate = 0; chip->cur_format = 0; } - mutex_unlock(&opened_mutex); chip->playback_substream = NULL; @@ -142,13 +139,12 @@ static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - mutex_lock(&opened_mutex); + guard(mutex)(&opened_mutex); chip->opened--; if (!chip->opened) { chip->cur_rate = 0; chip->cur_format = 0; } - mutex_unlock(&opened_mutex); chip->capture_substream = NULL; @@ -161,10 +157,9 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream, struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); /* Set restrictions to params. */ - mutex_lock(&opened_mutex); + guard(mutex)(&opened_mutex); chip->cur_rate = params_rate(hw_params); chip->cur_format = params_format(hw_params); - mutex_unlock(&opened_mutex); return 0; } @@ -175,10 +170,9 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); /* Set restrictions to params. */ - mutex_lock(&opened_mutex); + guard(mutex)(&opened_mutex); chip->cur_rate = params_rate(hw_params); chip->cur_format = params_format(hw_params); - mutex_unlock(&opened_mutex); return 0; } From c07824a14d99c10edd4ec4c389d219af336ecf20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:31 +0200 Subject: [PATCH 1028/1292] ALSA: ac97bus: Use guard() for mutex locks Replace the manual mutex lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-18-tiwai@suse.de --- sound/ac97/bus.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 47c6787158a777..f4254703d29f75 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -241,10 +241,9 @@ static ssize_t cold_reset_store(struct device *dev, { struct ac97_controller *ac97_ctrl; - mutex_lock(&ac97_controllers_mutex); + guard(mutex)(&ac97_controllers_mutex); ac97_ctrl = to_ac97_controller(dev); ac97_ctrl->ops->reset(ac97_ctrl); - mutex_unlock(&ac97_controllers_mutex); return len; } static DEVICE_ATTR_WO(cold_reset); @@ -258,10 +257,9 @@ static ssize_t warm_reset_store(struct device *dev, if (!dev) return -ENODEV; - mutex_lock(&ac97_controllers_mutex); + guard(mutex)(&ac97_controllers_mutex); ac97_ctrl = to_ac97_controller(dev); ac97_ctrl->ops->warm_reset(ac97_ctrl); - mutex_unlock(&ac97_controllers_mutex); return len; } static DEVICE_ATTR_WO(warm_reset); @@ -284,10 +282,10 @@ static const struct attribute_group *ac97_adapter_groups[] = { static void ac97_del_adapter(struct ac97_controller *ac97_ctrl) { - mutex_lock(&ac97_controllers_mutex); - ac97_ctrl_codecs_unregister(ac97_ctrl); - list_del(&ac97_ctrl->controllers); - mutex_unlock(&ac97_controllers_mutex); + scoped_guard(mutex, &ac97_controllers_mutex) { + ac97_ctrl_codecs_unregister(ac97_ctrl); + list_del(&ac97_ctrl->controllers); + } device_unregister(&ac97_ctrl->adap); } @@ -311,7 +309,7 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl) { int ret; - mutex_lock(&ac97_controllers_mutex); + guard(mutex)(&ac97_controllers_mutex); ret = idr_alloc(&ac97_adapter_idr, ac97_ctrl, 0, 0, GFP_KERNEL); ac97_ctrl->nr = ret; if (ret >= 0) { @@ -322,13 +320,11 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl) if (ret) put_device(&ac97_ctrl->adap); } - if (!ret) + if (!ret) { list_add(&ac97_ctrl->controllers, &ac97_controllers); - mutex_unlock(&ac97_controllers_mutex); - - if (!ret) dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n", dev_name(ac97_ctrl->parent)); + } return ret; } From 69f374931fa4714891cad0a0558b415f80aa7225 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:32 +0200 Subject: [PATCH 1029/1292] ALSA: virtio: Use guard() for spin locks Replace the manual spin lock/unlock pairs with guard() for code simplification. Only code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-19-tiwai@suse.de --- sound/virtio/virtio_card.c | 8 ++--- sound/virtio/virtio_ctl_msg.c | 23 ++++++-------- sound/virtio/virtio_pcm.c | 8 ++--- sound/virtio/virtio_pcm_msg.c | 17 +++-------- sound/virtio/virtio_pcm_ops.c | 56 ++++++++++++----------------------- 5 files changed, 38 insertions(+), 74 deletions(-) diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 965209e1d87282..52c5757585c6d3 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -85,9 +85,8 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue) struct virtio_snd_queue *queue = virtsnd_event_queue(snd); struct virtio_snd_event *event; u32 length; - unsigned long flags; - spin_lock_irqsave(&queue->lock, flags); + guard(spinlock_irqsave)(&queue->lock); do { virtqueue_disable_cb(vqueue); while ((event = virtqueue_get_buf(vqueue, &length))) { @@ -95,7 +94,6 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue) virtsnd_event_send(vqueue, event, true, GFP_ATOMIC); } } while (!virtqueue_enable_cb(vqueue)); - spin_unlock_irqrestore(&queue->lock, flags); } /** @@ -176,14 +174,12 @@ static void virtsnd_disable_event_vq(struct virtio_snd *snd) struct virtio_snd_queue *queue = virtsnd_event_queue(snd); struct virtio_snd_event *event; u32 length; - unsigned long flags; if (queue->vqueue) { - spin_lock_irqsave(&queue->lock, flags); + guard(spinlock_irqsave)(&queue->lock); virtqueue_disable_cb(queue->vqueue); while ((event = virtqueue_get_buf(queue->vqueue, &length))) virtsnd_event_dispatch(snd, event); - spin_unlock_irqrestore(&queue->lock, flags); } } diff --git a/sound/virtio/virtio_ctl_msg.c b/sound/virtio/virtio_ctl_msg.c index 9dabea01277f84..6433c870f271a7 100644 --- a/sound/virtio/virtio_ctl_msg.c +++ b/sound/virtio/virtio_ctl_msg.c @@ -131,7 +131,6 @@ int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg, unsigned int nins = 0; struct scatterlist *psgs[4]; bool notify = false; - unsigned long flags; int rc; virtsnd_ctl_msg_ref(msg); @@ -147,15 +146,15 @@ int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg, if (in_sgs) psgs[nouts + nins++] = in_sgs; - spin_lock_irqsave(&queue->lock, flags); - rc = virtqueue_add_sgs(queue->vqueue, psgs, nouts, nins, msg, - GFP_ATOMIC); - if (!rc) { - notify = virtqueue_kick_prepare(queue->vqueue); + scoped_guard(spinlock_irqsave, &queue->lock) { + rc = virtqueue_add_sgs(queue->vqueue, psgs, nouts, nins, msg, + GFP_ATOMIC); + if (!rc) { + notify = virtqueue_kick_prepare(queue->vqueue); - list_add_tail(&msg->list, &snd->ctl_msgs); + list_add_tail(&msg->list, &snd->ctl_msgs); + } } - spin_unlock_irqrestore(&queue->lock, flags); if (rc) { dev_err(&vdev->dev, "failed to send control message (0x%08x)\n", @@ -233,9 +232,8 @@ void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg) void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd) { struct virtio_snd_queue *queue = virtsnd_control_queue(snd); - unsigned long flags; - spin_lock_irqsave(&queue->lock, flags); + guard(spinlock_irqsave)(&queue->lock); while (!list_empty(&snd->ctl_msgs)) { struct virtio_snd_msg *msg = list_first_entry(&snd->ctl_msgs, struct virtio_snd_msg, @@ -243,7 +241,6 @@ void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd) virtsnd_ctl_msg_complete(msg); } - spin_unlock_irqrestore(&queue->lock, flags); } /** @@ -296,13 +293,11 @@ void virtsnd_ctl_notify_cb(struct virtqueue *vqueue) struct virtio_snd_queue *queue = virtsnd_control_queue(snd); struct virtio_snd_msg *msg; u32 length; - unsigned long flags; - spin_lock_irqsave(&queue->lock, flags); + guard(spinlock_irqsave)(&queue->lock); do { virtqueue_disable_cb(vqueue); while ((msg = virtqueue_get_buf(vqueue, &length))) virtsnd_ctl_msg_complete(msg); } while (!virtqueue_enable_cb(vqueue)); - spin_unlock_irqrestore(&queue->lock, flags); } diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c index 2f7c5e709f0755..3602b6690fcd90 100644 --- a/sound/virtio/virtio_pcm.c +++ b/sound/virtio/virtio_pcm.c @@ -515,10 +515,10 @@ void virtsnd_pcm_event(struct virtio_snd *snd, struct virtio_snd_event *event) /* TODO: deal with shmem elapsed period */ break; case VIRTIO_SND_EVT_PCM_XRUN: - spin_lock(&vss->lock); - if (vss->xfer_enabled) - vss->xfer_xrun = true; - spin_unlock(&vss->lock); + scoped_guard(spinlock, &vss->lock) { + if (vss->xfer_enabled) + vss->xfer_xrun = true; + } break; } } diff --git a/sound/virtio/virtio_pcm_msg.c b/sound/virtio/virtio_pcm_msg.c index 8c32efaf4c5294..9778020a7ba899 100644 --- a/sound/virtio/virtio_pcm_msg.c +++ b/sound/virtio/virtio_pcm_msg.c @@ -272,14 +272,8 @@ int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss, unsigned long offset, */ unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss) { - unsigned int num; - unsigned long flags; - - spin_lock_irqsave(&vss->lock, flags); - num = vss->msg_count; - spin_unlock_irqrestore(&vss->lock, flags); - - return num; + guard(spinlock_irqsave)(&vss->lock); + return vss->msg_count; } /** @@ -308,7 +302,7 @@ static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg, * in the virtqueue. Therefore, on each completion of an I/O message, * the hw_ptr value is unconditionally advanced. */ - spin_lock(&vss->lock); + guard(spinlock)(&vss->lock); /* * If the capture substream returned an incorrect status, then just * increase the hw_ptr by the message size. @@ -338,7 +332,6 @@ static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg, } else if (!vss->msg_count) { wake_up_all(&vss->msg_empty); } - spin_unlock(&vss->lock); } /** @@ -351,15 +344,13 @@ static inline void virtsnd_pcm_notify_cb(struct virtio_snd_queue *queue) { struct virtio_pcm_msg *msg; u32 written_bytes; - unsigned long flags; - spin_lock_irqsave(&queue->lock, flags); + guard(spinlock_irqsave)(&queue->lock); do { virtqueue_disable_cb(queue->vqueue); while ((msg = virtqueue_get_buf(queue->vqueue, &written_bytes))) virtsnd_pcm_msg_complete(msg, written_bytes); } while (!virtqueue_enable_cb(queue->vqueue)); - spin_unlock_irqrestore(&queue->lock, flags); } /** diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c index ad12aae52fc32e..6297a9c61e70b0 100644 --- a/sound/virtio/virtio_pcm_ops.c +++ b/sound/virtio/virtio_pcm_ops.c @@ -327,7 +327,6 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command) struct virtio_snd *snd = vss->snd; struct virtio_snd_queue *queue; struct virtio_snd_msg *msg; - unsigned long flags; int rc = 0; switch (command) { @@ -335,23 +334,20 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: queue = virtsnd_pcm_queue(vss); - spin_lock_irqsave(&queue->lock, flags); - spin_lock(&vss->lock); - if (vss->direction == SNDRV_PCM_STREAM_CAPTURE) - rc = virtsnd_pcm_msg_send(vss, 0, vss->buffer_bytes); - if (!rc) + scoped_guard(spinlock_irqsave, &queue->lock) { + guard(spinlock)(&vss->lock); + if (vss->direction == SNDRV_PCM_STREAM_CAPTURE) + rc = virtsnd_pcm_msg_send(vss, 0, vss->buffer_bytes); + if (rc) + return rc; vss->xfer_enabled = true; - spin_unlock(&vss->lock); - spin_unlock_irqrestore(&queue->lock, flags); - if (rc) - return rc; + } msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_START, GFP_KERNEL); if (!msg) { - spin_lock_irqsave(&vss->lock, flags); + guard(spinlock_irqsave)(&vss->lock); vss->xfer_enabled = false; - spin_unlock_irqrestore(&vss->lock, flags); return -ENOMEM; } @@ -364,9 +360,9 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command) vss->stopped = true; fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irqsave(&vss->lock, flags); - vss->xfer_enabled = false; - spin_unlock_irqrestore(&vss->lock, flags); + scoped_guard(spinlock_irqsave, &vss->lock) { + vss->xfer_enabled = false; + } msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_STOP, GFP_KERNEL); @@ -480,38 +476,24 @@ static int virtsnd_pcm_pb_ack(struct snd_pcm_substream *substream) { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); struct virtio_snd_queue *queue = virtsnd_pcm_queue(vss); - unsigned long flags; - int rc; - spin_lock_irqsave(&queue->lock, flags); - spin_lock(&vss->lock); + guard(spinlock_irqsave)(&queue->lock); + guard(spinlock)(&vss->lock); - rc = snd_pcm_indirect_playback_transfer(substream, &vss->pcm_indirect, - virtsnd_pcm_trans_copy); - - spin_unlock(&vss->lock); - spin_unlock_irqrestore(&queue->lock, flags); - - return rc; + return snd_pcm_indirect_playback_transfer(substream, &vss->pcm_indirect, + virtsnd_pcm_trans_copy); } static int virtsnd_pcm_cp_ack(struct snd_pcm_substream *substream) { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); struct virtio_snd_queue *queue = virtsnd_pcm_queue(vss); - unsigned long flags; - int rc; - - spin_lock_irqsave(&queue->lock, flags); - spin_lock(&vss->lock); - - rc = snd_pcm_indirect_capture_transfer(substream, &vss->pcm_indirect, - virtsnd_pcm_trans_copy); - spin_unlock(&vss->lock); - spin_unlock_irqrestore(&queue->lock, flags); + guard(spinlock_irqsave)(&queue->lock); + guard(spinlock)(&vss->lock); - return rc; + return snd_pcm_indirect_capture_transfer(substream, &vss->pcm_indirect, + virtsnd_pcm_trans_copy); } /* PCM substream operators map. */ From b8e1684163ae52db90f428965bd9aaff7205c02e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2025 17:13:33 +0200 Subject: [PATCH 1030/1292] ALSA: misc: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250829151335.7342-20-tiwai@suse.de --- sound/core/misc.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/sound/core/misc.c b/sound/core/misc.c index c2fda3bd90a0d4..88d9e1f9a6e9ff 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -127,35 +127,30 @@ int snd_fasync_helper(int fd, struct file *file, int on, INIT_LIST_HEAD(&fasync->list); } - spin_lock_irq(&snd_fasync_lock); - if (*fasyncp) { - kfree(fasync); - fasync = *fasyncp; - } else { - if (!fasync) { - spin_unlock_irq(&snd_fasync_lock); - return 0; + scoped_guard(spinlock_irq, &snd_fasync_lock) { + if (*fasyncp) { + kfree(fasync); + fasync = *fasyncp; + } else { + if (!fasync) + return 0; + *fasyncp = fasync; } - *fasyncp = fasync; + fasync->on = on; } - fasync->on = on; - spin_unlock_irq(&snd_fasync_lock); return fasync_helper(fd, file, on, &fasync->fasync); } EXPORT_SYMBOL_GPL(snd_fasync_helper); void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll) { - unsigned long flags; - if (!fasync || !fasync->on) return; - spin_lock_irqsave(&snd_fasync_lock, flags); + guard(spinlock_irqsave)(&snd_fasync_lock); fasync->signal = signal; fasync->poll = poll; list_move(&fasync->list, &snd_fasync_list); schedule_work(&snd_fasync_work); - spin_unlock_irqrestore(&snd_fasync_lock, flags); } EXPORT_SYMBOL_GPL(snd_kill_fasync); From f54d87dad7619c8026e95b848d6ef677b9f2b55f Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 1 Sep 2025 16:57:57 +0800 Subject: [PATCH 1031/1292] ASoC: rt712: avoid skipping the blind write Some devices might not use the DMIC function of the RT712VB. Therefore, this patch avoids skipping the blind write with RT712VB. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20250901085757.1287945-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 5b298db5f0f611..0ebaae426e73b5 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -1890,11 +1890,9 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt712_sdca_va_io_init(rt712); } else { - if (!rt712->dmic_function_found) { - dev_err(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n", + if (!rt712->dmic_function_found) + dev_warn(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n", __func__); - goto suspend; - } /* multilanes and DMIC are supported by rt712vb */ prop->lane_control_support = true; From 782a7c73078e1301c0c427f21c06377d77dfa541 Mon Sep 17 00:00:00 2001 From: Larisa Grigore Date: Thu, 28 Aug 2025 11:14:40 +0100 Subject: [PATCH 1032/1292] spi: spi-fsl-lpspi: Fix transmissions when using CONT Commit 6a130448498c ("spi: lpspi: Fix wrong transmission when don't use CONT") breaks transmissions when CONT is used. The TDIE interrupt should not be disabled in all cases. If CONT is used and the TX transfer is not yet completed yet, but the interrupt handler is called because there are characters to be received, TDIE is replaced with FCIE. When the transfer is finally completed, SR_TDF is set but the interrupt handler isn't called again. Fixes: 6a130448498c ("spi: lpspi: Fix wrong transmission when don't use CONT") Signed-off-by: Larisa Grigore Signed-off-by: James Clark Reviewed-by: Frank Li Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-1-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 313e444a34f3e8..eaa6bade61a6ab 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -3,7 +3,7 @@ // Freescale i.MX7ULP LPSPI driver // // Copyright 2016 Freescale Semiconductor, Inc. -// Copyright 2018 NXP Semiconductors +// Copyright 2018, 2023, 2025 NXP #include #include @@ -785,7 +785,7 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id) if (temp_SR & SR_MBF || readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_TXCOUNT) { writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR); - fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE); + fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE | (temp_IER & IER_TDIE)); return IRQ_HANDLED; } From cbe33705864ba2697a2939de715b81538cf32430 Mon Sep 17 00:00:00 2001 From: Larisa Grigore Date: Thu, 28 Aug 2025 11:14:41 +0100 Subject: [PATCH 1033/1292] spi: spi-fsl-lpspi: Set correct chip-select polarity bit The driver currently supports multiple chip-selects, but only sets the polarity for the first one (CS 0). Fix it by setting the PCSPOL bit for the desired chip-select. Fixes: 5314987de5e5 ("spi: imx: add lpspi bus driver") Signed-off-by: Larisa Grigore Signed-off-by: James Clark Reviewed-by: Frank Li Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-2-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index eaa6bade61a6ab..5ea4a306ffa6ab 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -5,6 +5,7 @@ // Copyright 2016 Freescale Semiconductor, Inc. // Copyright 2018, 2023, 2025 NXP +#include #include #include #include @@ -70,7 +71,7 @@ #define DER_TDDE BIT(0) #define CFGR1_PCSCFG BIT(27) #define CFGR1_PINCFG (BIT(24)|BIT(25)) -#define CFGR1_PCSPOL BIT(8) +#define CFGR1_PCSPOL_MASK GENMASK(11, 8) #define CFGR1_NOSTALL BIT(3) #define CFGR1_HOST BIT(0) #define FSR_TXCOUNT (0xFF) @@ -423,7 +424,9 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi) else temp = CFGR1_PINCFG; if (fsl_lpspi->config.mode & SPI_CS_HIGH) - temp |= CFGR1_PCSPOL; + temp |= FIELD_PREP(CFGR1_PCSPOL_MASK, + BIT(fsl_lpspi->config.chip_select)); + writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1); temp = readl(fsl_lpspi->base + IMX7ULP_CR); From e811b088a3641861fc9d2b2b840efc61a0f1907d Mon Sep 17 00:00:00 2001 From: Larisa Grigore Date: Thu, 28 Aug 2025 11:14:42 +0100 Subject: [PATCH 1034/1292] spi: spi-fsl-lpspi: Reset FIFO and disable module on transfer abort In DMA mode fsl_lpspi_reset() is always called at the end, even when the transfer is aborted. In PIO mode aborts skip the reset leaving the FIFO filled and the module enabled. Fix it by always calling fsl_lpspi_reset(). Fixes: a15dc3d657fa ("spi: lpspi: Fix CLK pin becomes low before one transfer") Signed-off-by: Larisa Grigore Reviewed-by: Frank Li Signed-off-by: James Clark Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-3-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 5ea4a306ffa6ab..e50261e9a1fa00 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -733,12 +733,10 @@ static int fsl_lpspi_pio_transfer(struct spi_controller *controller, fsl_lpspi_write_tx_fifo(fsl_lpspi); ret = fsl_lpspi_wait_for_completion(controller); - if (ret) - return ret; fsl_lpspi_reset(fsl_lpspi); - return 0; + return ret; } static int fsl_lpspi_transfer_one(struct spi_controller *controller, From dedf9c93dece441e9a0a4836458bc93677008ddd Mon Sep 17 00:00:00 2001 From: Larisa Grigore Date: Thu, 28 Aug 2025 11:14:43 +0100 Subject: [PATCH 1035/1292] spi: spi-fsl-lpspi: Clear status register after disabling the module Clear the error flags after disabling the module to avoid the case when a flag is set again between flag clear and module disable. And use SR_CLEAR_MASK to replace hardcoded value for improved readability. Although fsl_lpspi_reset() was only introduced in commit a15dc3d657fa ("spi: lpspi: Fix CLK pin becomes low before one transfer"), the original driver only reset SR in the interrupt handler, making it vulnerable to the same issue. Therefore the fixes commit is set at the introduction of the driver. Fixes: 5314987de5e5 ("spi: imx: add lpspi bus driver") Signed-off-by: Larisa Grigore Signed-off-by: Ciprian Marian Costea Reviewed-by: Frank Li Signed-off-by: James Clark Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-4-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index e50261e9a1fa00..fc4d49f0717eae 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -83,6 +83,8 @@ #define TCR_RXMSK BIT(19) #define TCR_TXMSK BIT(18) +#define SR_CLEAR_MASK GENMASK(13, 8) + struct fsl_lpspi_devtype_data { u8 prescale_max; }; @@ -535,14 +537,13 @@ static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi) fsl_lpspi_intctrl(fsl_lpspi, 0); } - /* W1C for all flags in SR */ - temp = 0x3F << 8; - writel(temp, fsl_lpspi->base + IMX7ULP_SR); - /* Clear FIFO and disable module */ temp = CR_RRF | CR_RTF; writel(temp, fsl_lpspi->base + IMX7ULP_CR); + /* W1C for all flags in SR */ + writel(SR_CLEAR_MASK, fsl_lpspi->base + IMX7ULP_SR); + return 0; } From b663fd4532699cc24f5d1094f3859198ee1ed4b6 Mon Sep 17 00:00:00 2001 From: Larisa Grigore Date: Thu, 28 Aug 2025 11:14:44 +0100 Subject: [PATCH 1036/1292] dt-bindings: lpspi: Document support for S32G Add compatible strings 'nxp,s32g2-lpspi' and 'nxp,s32g3-lpspi' for S32G2 and S32G3. Require nxp,s32g3-lpspi to fallback to nxp,s32g2-lpspi since they are currently compatible. Signed-off-by: Larisa Grigore Signed-off-by: James Clark Reviewed-by: Rob Herring (Arm) Reviewed-by: Frank Li Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-5-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml index a65a42ccaafed1..a82360bed1882e 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml +++ b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml @@ -20,6 +20,7 @@ properties: - enum: - fsl,imx7ulp-spi - fsl,imx8qxp-spi + - nxp,s32g2-lpspi - items: - enum: - fsl,imx8ulp-spi @@ -27,6 +28,10 @@ properties: - fsl,imx94-spi - fsl,imx95-spi - const: fsl,imx7ulp-spi + - items: + - const: nxp,s32g3-lpspi + - const: nxp,s32g2-lpspi + reg: maxItems: 1 From fb4273faa4d0eeca8cb7265531d48eb084bcceea Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 28 Aug 2025 11:14:45 +0100 Subject: [PATCH 1037/1292] spi: spi-fsl-lpspi: Constify devtype datas Add const for all devtype_data. Signed-off-by: James Clark Reviewed-by: Frank Li Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-6-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index fc4d49f0717eae..f16449cf42bb9a 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -135,11 +135,11 @@ struct fsl_lpspi_data { * ERR051608 fixed or not: * https://www.nxp.com/docs/en/errata/i.MX93_1P87f.pdf */ -static struct fsl_lpspi_devtype_data imx93_lpspi_devtype_data = { +static const struct fsl_lpspi_devtype_data imx93_lpspi_devtype_data = { .prescale_max = 1, }; -static struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = { +static const struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = { .prescale_max = 7, }; From 9bbfb1ec959ce95f91cfab544f705e5257be3be1 Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 28 Aug 2025 11:14:46 +0100 Subject: [PATCH 1038/1292] spi: spi-fsl-lpspi: Treat prescale_max == 0 as no erratum This erratum only ever results in a max value of 1, otherwise the full 3 bits are available. To avoid repeating the same default prescale value for every new device's devdata, treat 0 as no limit (7) and only set a value when the erratum is present. Change the field to be 3 bits to catch out of range definitions. No functionality change. Signed-off-by: James Clark Reviewed-by: Frank Li Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-7-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index f16449cf42bb9a..ea25e8dab0a40b 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -86,7 +86,7 @@ #define SR_CLEAR_MASK GENMASK(13, 8) struct fsl_lpspi_devtype_data { - u8 prescale_max; + u8 prescale_max : 3; /* 0 == no limit */ }; struct lpspi_config { @@ -132,15 +132,15 @@ struct fsl_lpspi_data { }; /* - * ERR051608 fixed or not: - * https://www.nxp.com/docs/en/errata/i.MX93_1P87f.pdf + * Devices with ERR051608 have a max TCR_PRESCALE value of 1, otherwise there is + * no prescale limit: https://www.nxp.com/docs/en/errata/i.MX93_1P87f.pdf */ static const struct fsl_lpspi_devtype_data imx93_lpspi_devtype_data = { .prescale_max = 1, }; static const struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = { - .prescale_max = 7, + /* All defaults */ }; static const struct of_device_id fsl_lpspi_dt_ids[] = { @@ -324,7 +324,7 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) int scldiv; perclk_rate = clk_get_rate(fsl_lpspi->clk_per); - prescale_max = fsl_lpspi->devtype_data->prescale_max; + prescale_max = fsl_lpspi->devtype_data->prescale_max ?: 7; if (!config.speed_hz) { dev_err(fsl_lpspi->dev, From 41c91c2eed83cb93781078108077b7e34f867fc2 Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 28 Aug 2025 11:14:47 +0100 Subject: [PATCH 1039/1292] spi: spi-fsl-lpspi: Parameterize reading num-cs from hardware Add query_hw_for_num_cs in devtype to avoid directly checking compatible string "fsl,imx93-spi". No functionality change. Signed-off-by: James Clark Reviewed-by: Frank Li Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-8-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index ea25e8dab0a40b..ce347cdbb009c1 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -87,6 +87,7 @@ struct fsl_lpspi_devtype_data { u8 prescale_max : 3; /* 0 == no limit */ + bool query_hw_for_num_cs : 1; }; struct lpspi_config { @@ -137,6 +138,7 @@ struct fsl_lpspi_data { */ static const struct fsl_lpspi_devtype_data imx93_lpspi_devtype_data = { .prescale_max = 1, + .query_hw_for_num_cs = true, }; static const struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = { @@ -932,7 +934,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f); if (of_property_read_u32((&pdev->dev)->of_node, "num-cs", &num_cs)) { - if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx93-spi")) + if (devtype_data->query_hw_for_num_cs) num_cs = ((temp >> 16) & 0xf); else num_cs = 1; From 431f6c88cb5d2d62d579d4d78f5c1a2583465ffb Mon Sep 17 00:00:00 2001 From: Larisa Grigore Date: Thu, 28 Aug 2025 11:14:48 +0100 Subject: [PATCH 1040/1292] spi: spi-fsl-lpspi: Add compatible for S32G S32G doesn't have the max prescale erratum (default) and it can query the max number of CS from hardware, so add those settings. Signed-off-by: Larisa Grigore Signed-off-by: Ciprian Marian Costea Signed-off-by: James Clark Reviewed-by: Frank Li Link: https://patch.msgid.link/20250828-james-nxp-lpspi-v2-9-6262b9aa9be4@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index ce347cdbb009c1..431439d4cdda9c 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -145,9 +145,14 @@ static const struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = { /* All defaults */ }; +static const struct fsl_lpspi_devtype_data s32g_lpspi_devtype_data = { + .query_hw_for_num_cs = true, +}; + static const struct of_device_id fsl_lpspi_dt_ids[] = { { .compatible = "fsl,imx7ulp-spi", .data = &imx7ulp_lpspi_devtype_data,}, { .compatible = "fsl,imx93-spi", .data = &imx93_lpspi_devtype_data,}, + { .compatible = "nxp,s32g2-lpspi", .data = &s32g_lpspi_devtype_data,}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_lpspi_dt_ids); From 7446284023e8ef694fb392348185349c773eefb3 Mon Sep 17 00:00:00 2001 From: Khairul Anuar Romli Date: Tue, 26 Aug 2025 08:33:58 +0800 Subject: [PATCH 1041/1292] spi: cadence-quadspi: Implement refcount to handle unbind during busy driver support indirect read and indirect write operation with assumption no force device removal(unbind) operation. However force device removal(removal) is still available to root superuser. Unbinding driver during operation causes kernel crash. This changes ensure driver able to handle such operation for indirect read and indirect write by implementing refcount to track attached devices to the controller and gracefully wait and until attached devices remove operation completed before proceed with removal operation. Signed-off-by: Khairul Anuar Romli Reviewed-by: Matthew Gerlach Reviewed-by: Niravkumar L Rabara Link: https://patch.msgid.link/8704fd6bd2ff4d37bba4a0eacf5eba3ba001079e.1756168074.git.khairul.anuar.romli@altera.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 177f9a33f3a25e..9bf823348cd30d 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -108,6 +108,8 @@ struct cqspi_st { bool is_jh7110; /* Flag for StarFive JH7110 SoC */ bool disable_stig_mode; + refcount_t refcount; + refcount_t inflight_ops; const struct cqspi_driver_platdata *ddata; }; @@ -735,6 +737,9 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, u8 *rxbuf_end = rxbuf + n_rx; int ret = 0; + if (!refcount_read(&cqspi->refcount)) + return -ENODEV; + writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES); @@ -1071,6 +1076,9 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, unsigned int write_bytes; int ret; + if (!refcount_read(&cqspi->refcount)) + return -ENODEV; + writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR); writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES); @@ -1461,12 +1469,26 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller); struct device *dev = &cqspi->pdev->dev; + if (refcount_read(&cqspi->inflight_ops) == 0) + return -ENODEV; + ret = pm_runtime_resume_and_get(dev); if (ret) { dev_err(&mem->spi->dev, "resume failed with %d\n", ret); return ret; } + if (!refcount_read(&cqspi->refcount)) + return -EBUSY; + + refcount_inc(&cqspi->inflight_ops); + + if (!refcount_read(&cqspi->refcount)) { + if (refcount_read(&cqspi->inflight_ops)) + refcount_dec(&cqspi->inflight_ops); + return -EBUSY; + } + ret = cqspi_mem_process(mem, op); pm_runtime_put_autosuspend(dev); @@ -1474,6 +1496,9 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) if (ret) dev_err(&mem->spi->dev, "operation failed with %d\n", ret); + if (refcount_read(&cqspi->inflight_ops) > 1) + refcount_dec(&cqspi->inflight_ops); + return ret; } @@ -1925,6 +1950,9 @@ static int cqspi_probe(struct platform_device *pdev) } } + refcount_set(&cqspi->refcount, 1); + refcount_set(&cqspi->inflight_ops, 1); + ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0, pdev->name, cqspi); if (ret) { @@ -1987,6 +2015,11 @@ static void cqspi_remove(struct platform_device *pdev) { struct cqspi_st *cqspi = platform_get_drvdata(pdev); + refcount_set(&cqspi->refcount, 0); + + if (!refcount_dec_and_test(&cqspi->inflight_ops)) + cqspi_wait_idle(cqspi); + spi_unregister_controller(cqspi->host); cqspi_controller_enable(cqspi, 0); From bbf7a84787d0dc5910d121b025dd5f4dea060768 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 26 Aug 2025 06:22:05 +0000 Subject: [PATCH 1042/1292] ASoC: soc-dapm: rename snd_soc_dapm_kcontrol_widget() to snd_soc_dapm_kcontrol_to_widget() snd_soc_dapm_kcontrol_widget() is unclear naming, rename it to snd_soc_dapm_kcontrol_to_widget(). This is prepare for dapm cleanup. This patch keeps compatible by using define, but old name will be replaced on each drivers and removed from ASoC in the future. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/875xeay54j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 ++- sound/soc/soc-dapm.c | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 2e9196b6ffba10..220eb6d08534a3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -719,7 +719,7 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list); struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol); -struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol); +struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_to_widget(struct snd_kcontrol *kcontrol); int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); enum snd_soc_bias_level snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context *dapm); @@ -729,6 +729,7 @@ void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_so #define snd_soc_component_force_bias_level(c, l) snd_soc_dapm_force_bias_level(&(c)->dapm, l) #define snd_soc_component_get_bias_level(c) snd_soc_dapm_get_bias_level(&(c)->dapm) #define snd_soc_component_init_bias_level(c, l) snd_soc_dapm_init_bias_level(&(c)->dapm, l) +#define snd_soc_dapm_kcontrol_widget snd_soc_dapm_kcontrol_to_widget #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6782a0d6cd4774..bfb2edc2f91de1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -877,16 +877,15 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, } /** - * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a + * snd_soc_dapm_kcontrol_to_widget() - Returns the widget associated to a * kcontrol * @kcontrol: The kcontrol */ -struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget( - struct snd_kcontrol *kcontrol) +struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_to_widget(struct snd_kcontrol *kcontrol) { return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget); +EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_widget); /** * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a From 2532041865305594e37c4c22bd650d52ea805ec8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 26 Aug 2025 06:22:12 +0000 Subject: [PATCH 1043/1292] ASoC: soc-dapm: rename snd_soc_dapm_kcontrol_dapm() to snd_soc_dapm_kcontrol_to_dapm() snd_soc_dapm_kcontrol_dapm() is unclear naming, rename it to snd_soc_dapm_kcontrol_to_dapm(). This is prepare for dapm cleanup. This patch keeps compatible by using define, but old name will be replaced on each drivers and removed from ASoC in the future. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/874ituy54c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 ++- sound/soc/soc-dapm.c | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 220eb6d08534a3..8add8de7a8c948 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -718,7 +718,7 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, enum snd_soc_dapm_direction)); void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list); -struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol); +struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_to_dapm(struct snd_kcontrol *kcontrol); struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_to_widget(struct snd_kcontrol *kcontrol); int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); @@ -730,6 +730,7 @@ void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_so #define snd_soc_component_get_bias_level(c) snd_soc_dapm_get_bias_level(&(c)->dapm) #define snd_soc_component_init_bias_level(c, l) snd_soc_dapm_init_bias_level(&(c)->dapm, l) #define snd_soc_dapm_kcontrol_widget snd_soc_dapm_kcontrol_to_widget +#define snd_soc_dapm_kcontrol_dapm snd_soc_dapm_kcontrol_to_dapm #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index bfb2edc2f91de1..25b2ea14d6599e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -888,19 +888,17 @@ struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_to_widget(struct snd_kcontrol EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_widget); /** - * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a - * kcontrol + * snd_soc_dapm_kcontrol_to_dapm() - Returns the dapm context associated to a kcontrol * @kcontrol: The kcontrol * * Note: This function must only be used on kcontrols that are known to have * been registered for a CODEC. Otherwise the behaviour is undefined. */ -struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( - struct snd_kcontrol *kcontrol) +struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_to_dapm(struct snd_kcontrol *kcontrol) { return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm); +EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_dapm); static void dapm_reset(struct snd_soc_card *card) { From f6883f0f03575ecc8c4c5d2a04339bac91eb33d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 26 Aug 2025 06:22:19 +0000 Subject: [PATCH 1044/1292] ASoC: soc-dapm: rename dapm_kcontrol_get_value() to snd_soc_dapm_kcontrol_get_value() dapm_kcontrol_get_value() is global function, adds snd_soc_ prefix This patch keeps compatible by using define, but old name will be replaced on each drivers and removed from ASoC in the future. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87349ey546.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 ++- sound/soc/soc-dapm.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 8add8de7a8c948..cd02fedb2624d3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -699,7 +699,6 @@ int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm); int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); -unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); void snd_soc_dapm_mark_endpoints_dirty(struct snd_soc_card *card); /* @@ -720,6 +719,7 @@ void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list); struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_to_dapm(struct snd_kcontrol *kcontrol); struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_to_widget(struct snd_kcontrol *kcontrol); +unsigned int snd_soc_dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); enum snd_soc_bias_level snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context *dapm); @@ -731,6 +731,7 @@ void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_so #define snd_soc_component_init_bias_level(c, l) snd_soc_dapm_init_bias_level(&(c)->dapm, l) #define snd_soc_dapm_kcontrol_widget snd_soc_dapm_kcontrol_to_widget #define snd_soc_dapm_kcontrol_dapm snd_soc_dapm_kcontrol_to_dapm +#define dapm_kcontrol_get_value snd_soc_dapm_kcontrol_get_value #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 25b2ea14d6599e..f8ecf86a3d2b16 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -838,13 +838,13 @@ static struct list_head *dapm_kcontrol_get_path_list( list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ list_kcontrol) -unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) +unsigned int snd_soc_dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) { struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); return data->value; } -EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value); +EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_get_value); static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, unsigned int value) From 8a9772ec08f87c9e45ab1ad2c8d2b8c1763836eb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 26 Aug 2025 06:22:26 +0000 Subject: [PATCH 1045/1292] ASoC: soc-dapm: rename snd_soc_kcontrol_component() to snd_soc_kcontrol_to_component() We have 2 similar functions, both converts date from snd_kcontrol to snd_soc_component. (A) snd_soc_kcontrol_component() (B) snd_soc_dapm_kcontrol_component() (A) is just wrapper for snd_kcontrol_chip(). (B) is for more complex conversion. Having similar functions is confusable. So (A) will be replaced to original snd_kcontrol_chip(). (B) will be stay, but the function name should be xx_to_xx(). And it is defined at soc-component.h. It should be implemented at soc-dapm.c. This patch renames it to snd_soc_dapm_kcontrol_to_component(), and move to soc-dapm.c. This patch keeps compatible by using define, but old name will be replaced on each drivers and removed from ASoC in the future. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/871poyy53x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 14 -------------- include/sound/soc-dapm.h | 2 ++ sound/soc/soc-dapm.c | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 54bfa0cb1085b9..48e45cbe82e53b 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -286,20 +286,6 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( return &component->dapm; } -/** - * snd_soc_dapm_kcontrol_component() - Returns the component associated to a - * kcontrol - * @kcontrol: The kcontrol - * - * This function must only be used on DAPM contexts that are known to be part of - * a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined - */ -static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component( - struct snd_kcontrol *kcontrol) -{ - return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol)); -} - /** * snd_soc_component_cache_sync() - Sync the register cache with the hardware * @component: COMPONENT to sync diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index cd02fedb2624d3..ed39458b94bf9b 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -719,6 +719,7 @@ void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list); struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_to_dapm(struct snd_kcontrol *kcontrol); struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_to_widget(struct snd_kcontrol *kcontrol); +struct snd_soc_component *snd_soc_dapm_kcontrol_to_component(struct snd_kcontrol *kcontrol); unsigned int snd_soc_dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); @@ -732,6 +733,7 @@ void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_so #define snd_soc_dapm_kcontrol_widget snd_soc_dapm_kcontrol_to_widget #define snd_soc_dapm_kcontrol_dapm snd_soc_dapm_kcontrol_to_dapm #define dapm_kcontrol_get_value snd_soc_dapm_kcontrol_get_value +#define snd_soc_dapm_kcontrol_component snd_soc_dapm_kcontrol_to_component #define for_each_dapm_widgets(list, i, widget) \ for ((i) = 0; \ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f8ecf86a3d2b16..d74c096cc20840 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -900,6 +900,20 @@ struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_to_dapm(struct snd_kcontrol * } EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_dapm); +/** + * snd_soc_dapm_kcontrol_to_component() - Returns the component associated to a + * kcontrol + * @kcontrol: The kcontrol + * + * This function must only be used on DAPM contexts that are known to be part of + * a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined + */ +struct snd_soc_component *snd_soc_dapm_kcontrol_to_component(struct snd_kcontrol *kcontrol) +{ + return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_to_dapm(kcontrol)); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_component); + static void dapm_reset(struct snd_soc_card *card) { struct snd_soc_dapm_widget *w; From d05afb53c683ef7ed1228b593c3360f4d3126c58 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Aug 2025 09:26:37 +0100 Subject: [PATCH 1046/1292] ASoC: wm8940: Correct PLL rate rounding Using a single value of 22500000 for both 48000Hz and 44100Hz audio will sometimes result in returning wrong dividers due to rounding. Update the code to use the actual value for both. Fixes: 294833fc9eb4 ("ASoC: wm8940: Rewrite code to set proper clocks") Reported-by: Ankur Tyagi Signed-off-by: Charles Keepax Tested-by: Ankur Tyagi Link: https://patch.msgid.link/20250821082639.1301453-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8940.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 401ee20897b1ba..46c16c9bc17a88 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -693,7 +693,12 @@ static int wm8940_update_clocks(struct snd_soc_dai *dai) f = wm8940_get_mclkdiv(priv->mclk, fs256, &mclkdiv); if (f != priv->mclk) { /* The PLL performs best around 90MHz */ - fpll = wm8940_get_mclkdiv(22500000, fs256, &mclkdiv); + if (fs256 % 8000) + f = 22579200; + else + f = 24576000; + + fpll = wm8940_get_mclkdiv(f, fs256, &mclkdiv); } wm8940_set_dai_pll(dai, 0, 0, priv->mclk, fpll); From b4799520dcd6fe1e14495cecbbe9975d847cd482 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Aug 2025 09:26:38 +0100 Subject: [PATCH 1047/1292] ASoC: wm8940: Correct typo in control name Fixes: 0b5e92c5e020 ("ASoC WM8940 Driver") Reported-by: Ankur Tyagi Signed-off-by: Charles Keepax Tested-by: Ankur Tyagi Link: https://patch.msgid.link/20250821082639.1301453-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8940.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 46c16c9bc17a88..94873ea630146b 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -220,7 +220,7 @@ static const struct snd_kcontrol_new wm8940_snd_controls[] = { SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL, 0, 255, 0, wm8940_adc_tlv), SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum), - SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST, + SOC_SINGLE_TLV("Capture Boost Volume", WM8940_ADCBOOST, 8, 1, 0, wm8940_capture_boost_vol_tlv), SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL, 0, 63, 0, wm8940_spk_vol_tlv), From 9b17d3724df55ecc2bc67978822585f2b023be48 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Aug 2025 09:26:39 +0100 Subject: [PATCH 1048/1292] ASoC: wm8974: Correct PLL rate rounding Using a single value of 22500000 for both 48000Hz and 44100Hz audio will sometimes result in returning wrong dividers due to rounding. Update the code to use the actual value for both. Fixes: 51b2bb3f2568 ("ASoC: wm8974: configure pll and mclk divider automatically") Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20250821082639.1301453-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8974.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index bdf437a5403fe2..db16d893a23514 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -419,10 +419,14 @@ static int wm8974_update_clocks(struct snd_soc_dai *dai) fs256 = 256 * priv->fs; f = wm8974_get_mclkdiv(priv->mclk, fs256, &mclkdiv); - if (f != priv->mclk) { /* The PLL performs best around 90MHz */ - fpll = wm8974_get_mclkdiv(22500000, fs256, &mclkdiv); + if (fs256 % 8000) + f = 22579200; + else + f = 24576000; + + fpll = wm8974_get_mclkdiv(f, fs256, &mclkdiv); } wm8974_set_dai_pll(dai, 0, 0, priv->mclk, fpll); From bd7e7bc2cc2024035dfbc8239c9f4d8675793445 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 29 Aug 2025 06:49:51 -0700 Subject: [PATCH 1049/1292] hwmon: (ina238) Correctly clamp shunt voltage limit When clamping a register value, the result needs to be masked against the register size. This was missing, resulting in errors when trying to write negative limits. Fix by masking the clamping result against the register size. Fixes: eacb52f010a80 ("hwmon: Driver for Texas Instruments INA238") Cc: Nathan Rossi Cc: Chris Packham Signed-off-by: Guenter Roeck --- drivers/hwmon/ina238.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 4d3dc018ead9a4..c6b2734898d011 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -379,7 +379,7 @@ static int ina238_write_in(struct device *dev, u32 attr, int channel, regval = clamp_val(val, -163, 163); regval = (regval * 1000 * 4) / (INA238_SHUNT_VOLTAGE_LSB * data->gain); - regval = clamp_val(regval, S16_MIN, S16_MAX); + regval = clamp_val(regval, S16_MIN, S16_MAX) & 0xffff; switch (attr) { case hwmon_in_max: From c2623573178bab32990695fb729e9b69710ed66d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 29 Aug 2025 11:51:20 -0700 Subject: [PATCH 1050/1292] hwmon: (ina238) Correctly clamp power limits ina238_write_power() was attempting to clamp the user input but was throwing away the result. Ensure that we clamp the value to the appropriate range before it is converted into a register value. Fixes: 0d9f596b1fe34 ("hwmon: (ina238) Modify the calculation formula to adapt to different chips") Cc: Wenliang Yan Cc: Chris Packham Signed-off-by: Guenter Roeck --- drivers/hwmon/ina238.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index c6b2734898d011..59a2c8889fa2b1 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -517,9 +517,10 @@ static int ina238_write_power(struct device *dev, u32 attr, long val) * Unsigned postive values. Compared against the 24-bit power register, * lower 8-bits are truncated. Same conversion to/from uW as POWER * register. + * The first clamp_val() is to establish a baseline to avoid overflows. */ - regval = clamp_val(val, 0, LONG_MAX); - regval = div_u64(val * 4 * 100 * data->rshunt, data->config->power_calculate_factor * + regval = clamp_val(val, 0, LONG_MAX / 2); + regval = div_u64(regval * 4 * 100 * data->rshunt, data->config->power_calculate_factor * 1000ULL * INA238_FIXED_SHUNT * data->gain); regval = clamp_val(regval >> 8, 0, U16_MAX); From 91418337a27d800b33d6d391f565b1fa2c7ff75c Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Mon, 18 Aug 2025 14:21:24 +0530 Subject: [PATCH 1051/1292] intel_idle: Remove unnecessary address-of operators Remove redundant address-of operators (&) when assigning the intel_idle() function pointer to the .enter field in cpuidle_state structures.in C, the & is not needed for function names. This change improves code consistency and readability by using the more conventional form without the & operator. No functional change intended. Signed-off-by: Kaushlendra Kumar Reviewed-by: Artem Bityutskiy Link: https://patch.msgid.link/20250818085124.3897921-1-kaushlendra.kumar@intel.com Signed-off-by: Rafael J. Wysocki --- drivers/idle/intel_idle.c | 256 +++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 91a7b7e7c0c8e3..9ba83954c25558 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -259,7 +259,7 @@ static struct cpuidle_state nehalem_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 3, .target_residency = 6, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -267,7 +267,7 @@ static struct cpuidle_state nehalem_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -275,7 +275,7 @@ static struct cpuidle_state nehalem_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 20, .target_residency = 80, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -283,7 +283,7 @@ static struct cpuidle_state nehalem_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 200, .target_residency = 800, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -296,7 +296,7 @@ static struct cpuidle_state snb_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -304,7 +304,7 @@ static struct cpuidle_state snb_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -312,7 +312,7 @@ static struct cpuidle_state snb_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 80, .target_residency = 211, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -320,7 +320,7 @@ static struct cpuidle_state snb_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 104, .target_residency = 345, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", @@ -328,7 +328,7 @@ static struct cpuidle_state snb_cstates[] __initdata = { .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 109, .target_residency = 345, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -341,7 +341,7 @@ static struct cpuidle_state byt_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6N", @@ -349,7 +349,7 @@ static struct cpuidle_state byt_cstates[] __initdata = { .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 300, .target_residency = 275, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6S", @@ -357,7 +357,7 @@ static struct cpuidle_state byt_cstates[] __initdata = { .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 500, .target_residency = 560, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", @@ -365,7 +365,7 @@ static struct cpuidle_state byt_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 1200, .target_residency = 4000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7S", @@ -373,7 +373,7 @@ static struct cpuidle_state byt_cstates[] __initdata = { .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 10000, .target_residency = 20000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -386,7 +386,7 @@ static struct cpuidle_state cht_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6N", @@ -394,7 +394,7 @@ static struct cpuidle_state cht_cstates[] __initdata = { .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 80, .target_residency = 275, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6S", @@ -402,7 +402,7 @@ static struct cpuidle_state cht_cstates[] __initdata = { .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 200, .target_residency = 560, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", @@ -410,7 +410,7 @@ static struct cpuidle_state cht_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 1200, .target_residency = 4000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7S", @@ -418,7 +418,7 @@ static struct cpuidle_state cht_cstates[] __initdata = { .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 10000, .target_residency = 20000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -431,7 +431,7 @@ static struct cpuidle_state ivb_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -439,7 +439,7 @@ static struct cpuidle_state ivb_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -447,7 +447,7 @@ static struct cpuidle_state ivb_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 59, .target_residency = 156, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -455,7 +455,7 @@ static struct cpuidle_state ivb_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 80, .target_residency = 300, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", @@ -463,7 +463,7 @@ static struct cpuidle_state ivb_cstates[] __initdata = { .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 87, .target_residency = 300, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -476,7 +476,7 @@ static struct cpuidle_state ivt_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -484,7 +484,7 @@ static struct cpuidle_state ivt_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 80, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -492,7 +492,7 @@ static struct cpuidle_state ivt_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 59, .target_residency = 156, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -500,7 +500,7 @@ static struct cpuidle_state ivt_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 82, .target_residency = 300, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -513,7 +513,7 @@ static struct cpuidle_state ivt_cstates_4s[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -521,7 +521,7 @@ static struct cpuidle_state ivt_cstates_4s[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 250, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -529,7 +529,7 @@ static struct cpuidle_state ivt_cstates_4s[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 59, .target_residency = 300, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -537,7 +537,7 @@ static struct cpuidle_state ivt_cstates_4s[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 84, .target_residency = 400, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -550,7 +550,7 @@ static struct cpuidle_state ivt_cstates_8s[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -558,7 +558,7 @@ static struct cpuidle_state ivt_cstates_8s[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -566,7 +566,7 @@ static struct cpuidle_state ivt_cstates_8s[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 59, .target_residency = 600, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -574,7 +574,7 @@ static struct cpuidle_state ivt_cstates_8s[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 88, .target_residency = 700, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -587,7 +587,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -595,7 +595,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -603,7 +603,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 33, .target_residency = 100, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -611,7 +611,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 133, .target_residency = 400, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", @@ -619,7 +619,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 166, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", @@ -627,7 +627,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 300, .target_residency = 900, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", @@ -635,7 +635,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 600, .target_residency = 1800, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -643,7 +643,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 2600, .target_residency = 7700, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -655,7 +655,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -663,7 +663,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -671,7 +671,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 40, .target_residency = 100, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -679,7 +679,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 133, .target_residency = 400, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", @@ -687,7 +687,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 166, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", @@ -695,7 +695,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 300, .target_residency = 900, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", @@ -703,7 +703,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 600, .target_residency = 1800, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -711,7 +711,7 @@ static struct cpuidle_state bdw_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 2600, .target_residency = 7700, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -724,7 +724,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -732,7 +732,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", @@ -740,7 +740,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 70, .target_residency = 100, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -748,7 +748,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 85, .target_residency = 200, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", @@ -756,7 +756,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 124, .target_residency = 800, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", @@ -764,7 +764,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 200, .target_residency = 800, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", @@ -772,7 +772,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 480, .target_residency = 5000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -780,7 +780,7 @@ static struct cpuidle_state skl_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 890, .target_residency = 5000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -793,7 +793,7 @@ static struct cpuidle_state skx_cstates[] __initdata = { .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_IRQ_ENABLE, .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -801,7 +801,7 @@ static struct cpuidle_state skx_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -809,7 +809,7 @@ static struct cpuidle_state skx_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 133, .target_residency = 600, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -822,7 +822,7 @@ static struct cpuidle_state icx_cstates[] __initdata = { .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_IRQ_ENABLE, .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -830,7 +830,7 @@ static struct cpuidle_state icx_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 4, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -838,7 +838,7 @@ static struct cpuidle_state icx_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 170, .target_residency = 600, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -861,7 +861,7 @@ static struct cpuidle_state adl_cstates[] __initdata = { .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_UNUSABLE, .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -869,7 +869,7 @@ static struct cpuidle_state adl_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 2, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -877,7 +877,7 @@ static struct cpuidle_state adl_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 220, .target_residency = 600, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", @@ -885,7 +885,7 @@ static struct cpuidle_state adl_cstates[] __initdata = { .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 280, .target_residency = 800, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -893,7 +893,7 @@ static struct cpuidle_state adl_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 680, .target_residency = 2000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -906,7 +906,7 @@ static struct cpuidle_state adl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_UNUSABLE, .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -914,7 +914,7 @@ static struct cpuidle_state adl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 2, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -922,7 +922,7 @@ static struct cpuidle_state adl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 170, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", @@ -930,7 +930,7 @@ static struct cpuidle_state adl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 200, .target_residency = 600, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -938,7 +938,7 @@ static struct cpuidle_state adl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 230, .target_residency = 700, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -951,7 +951,7 @@ static struct cpuidle_state mtl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -959,7 +959,7 @@ static struct cpuidle_state mtl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 140, .target_residency = 420, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -967,7 +967,7 @@ static struct cpuidle_state mtl_l_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 310, .target_residency = 930, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -980,7 +980,7 @@ static struct cpuidle_state gmt_cstates[] __initdata = { .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_UNUSABLE, .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -988,7 +988,7 @@ static struct cpuidle_state gmt_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 2, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -996,7 +996,7 @@ static struct cpuidle_state gmt_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 195, .target_residency = 585, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", @@ -1004,7 +1004,7 @@ static struct cpuidle_state gmt_cstates[] __initdata = { .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 260, .target_residency = 1040, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -1012,7 +1012,7 @@ static struct cpuidle_state gmt_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 660, .target_residency = 1980, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1025,7 +1025,7 @@ static struct cpuidle_state spr_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1033,7 +1033,7 @@ static struct cpuidle_state spr_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 2, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1042,7 +1042,7 @@ static struct cpuidle_state spr_cstates[] __initdata = { CPUIDLE_FLAG_INIT_XSTATE, .exit_latency = 290, .target_residency = 800, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1055,7 +1055,7 @@ static struct cpuidle_state gnr_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1063,7 +1063,7 @@ static struct cpuidle_state gnr_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 4, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1073,7 +1073,7 @@ static struct cpuidle_state gnr_cstates[] __initdata = { CPUIDLE_FLAG_PARTIAL_HINT_MATCH, .exit_latency = 170, .target_residency = 650, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6P", @@ -1083,7 +1083,7 @@ static struct cpuidle_state gnr_cstates[] __initdata = { CPUIDLE_FLAG_PARTIAL_HINT_MATCH, .exit_latency = 210, .target_residency = 1000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1096,7 +1096,7 @@ static struct cpuidle_state gnrd_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1104,7 +1104,7 @@ static struct cpuidle_state gnrd_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 4, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1114,7 +1114,7 @@ static struct cpuidle_state gnrd_cstates[] __initdata = { CPUIDLE_FLAG_PARTIAL_HINT_MATCH, .exit_latency = 220, .target_residency = 650, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6P", @@ -1124,7 +1124,7 @@ static struct cpuidle_state gnrd_cstates[] __initdata = { CPUIDLE_FLAG_PARTIAL_HINT_MATCH, .exit_latency = 240, .target_residency = 750, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1137,7 +1137,7 @@ static struct cpuidle_state atom_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C2", @@ -1145,7 +1145,7 @@ static struct cpuidle_state atom_cstates[] __initdata = { .flags = MWAIT2flg(0x10), .exit_latency = 20, .target_residency = 80, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C4", @@ -1153,7 +1153,7 @@ static struct cpuidle_state atom_cstates[] __initdata = { .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 100, .target_residency = 400, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1161,7 +1161,7 @@ static struct cpuidle_state atom_cstates[] __initdata = { .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 140, .target_residency = 560, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1173,7 +1173,7 @@ static struct cpuidle_state tangier_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 4, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C4", @@ -1181,7 +1181,7 @@ static struct cpuidle_state tangier_cstates[] __initdata = { .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 100, .target_residency = 400, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1189,7 +1189,7 @@ static struct cpuidle_state tangier_cstates[] __initdata = { .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 140, .target_residency = 560, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", @@ -1197,7 +1197,7 @@ static struct cpuidle_state tangier_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 1200, .target_residency = 4000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", @@ -1205,7 +1205,7 @@ static struct cpuidle_state tangier_cstates[] __initdata = { .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 10000, .target_residency = 20000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1217,7 +1217,7 @@ static struct cpuidle_state avn_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1225,7 +1225,7 @@ static struct cpuidle_state avn_cstates[] __initdata = { .flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 15, .target_residency = 45, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1237,7 +1237,7 @@ static struct cpuidle_state knl_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 1, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle }, { .name = "C6", @@ -1245,7 +1245,7 @@ static struct cpuidle_state knl_cstates[] __initdata = { .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 120, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle }, { .enter = NULL } @@ -1258,7 +1258,7 @@ static struct cpuidle_state bxt_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1266,7 +1266,7 @@ static struct cpuidle_state bxt_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1274,7 +1274,7 @@ static struct cpuidle_state bxt_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 133, .target_residency = 133, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", @@ -1282,7 +1282,7 @@ static struct cpuidle_state bxt_cstates[] __initdata = { .flags = MWAIT2flg(0x31) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 155, .target_residency = 155, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", @@ -1290,7 +1290,7 @@ static struct cpuidle_state bxt_cstates[] __initdata = { .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 1000, .target_residency = 1000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", @@ -1298,7 +1298,7 @@ static struct cpuidle_state bxt_cstates[] __initdata = { .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 2000, .target_residency = 2000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", @@ -1306,7 +1306,7 @@ static struct cpuidle_state bxt_cstates[] __initdata = { .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 10000, .target_residency = 10000, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1319,7 +1319,7 @@ static struct cpuidle_state dnv_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1327,7 +1327,7 @@ static struct cpuidle_state dnv_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 10, .target_residency = 20, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1335,7 +1335,7 @@ static struct cpuidle_state dnv_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 50, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1352,7 +1352,7 @@ static struct cpuidle_state snr_cstates[] __initdata = { .flags = MWAIT2flg(0x00), .exit_latency = 2, .target_residency = 2, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1360,7 +1360,7 @@ static struct cpuidle_state snr_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 15, .target_residency = 25, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", @@ -1368,7 +1368,7 @@ static struct cpuidle_state snr_cstates[] __initdata = { .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 130, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1381,7 +1381,7 @@ static struct cpuidle_state grr_cstates[] __initdata = { .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1389,7 +1389,7 @@ static struct cpuidle_state grr_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 2, .target_residency = 10, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6S", @@ -1397,7 +1397,7 @@ static struct cpuidle_state grr_cstates[] __initdata = { .flags = MWAIT2flg(0x22) | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 140, .target_residency = 500, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } @@ -1410,7 +1410,7 @@ static struct cpuidle_state srf_cstates[] __initdata = { .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 1, .target_residency = 1, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", @@ -1418,7 +1418,7 @@ static struct cpuidle_state srf_cstates[] __initdata = { .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, .exit_latency = 2, .target_residency = 10, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6S", @@ -1427,7 +1427,7 @@ static struct cpuidle_state srf_cstates[] __initdata = { CPUIDLE_FLAG_PARTIAL_HINT_MATCH, .exit_latency = 270, .target_residency = 700, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .name = "C6SP", @@ -1436,7 +1436,7 @@ static struct cpuidle_state srf_cstates[] __initdata = { CPUIDLE_FLAG_PARTIAL_HINT_MATCH, .exit_latency = 310, .target_residency = 900, - .enter = &intel_idle, + .enter = intel_idle, .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } From 969bf687c12cd9f64ed9368f0c7429445de7c10b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 27 Aug 2025 13:15:06 +0300 Subject: [PATCH 1052/1292] soundwire: bus: Drop dev_pm_domain_detach() call Starting with commit f99508074e78 ("PM: domains: Detach on device_unbind_cleanup()"), there is no longer a need to call dev_pm_domain_detach() in the bus remove function. The device_unbind_cleanup() function now handles this to avoid invoking devres cleanup handlers while the PM domain is powered off, which could otherwise lead to failures as described in the above-mentioned commit. Drop the explicit dev_pm_domain_detach() call and rely instead on the flags passed to dev_pm_domain_attach() to power off the domain. Signed-off-by: Claudiu Beznea Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20250827101506.927787-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus_type.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index bc1e653080d909..91e70cb46fb575 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -114,7 +114,6 @@ static int sdw_drv_probe(struct device *dev) ret = drv->probe(slave, id); if (ret) { - dev_pm_domain_detach(dev, false); ida_free(&slave->bus->slave_ida, slave->index); return ret; } @@ -180,8 +179,6 @@ static int sdw_drv_remove(struct device *dev) if (drv->remove) ret = drv->remove(slave); - dev_pm_domain_detach(dev, false); - ida_free(&slave->bus->slave_ida, slave->index); return ret; From 88f5d2a477ec64b12e83b488407490bb4a9298f8 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 14 Aug 2025 22:24:28 +0800 Subject: [PATCH 1053/1292] soundwire: Use min() to improve code Use min() to reduce the code in qcom_swrm_xfer_msg() and improve its readability. Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250814142428.282639-1-rongqianfeng@vivo.com Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index bd2b293b44f257..5b3078220189be 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -924,10 +924,7 @@ static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, if (msg->flags == SDW_MSG_FLAG_READ) { for (i = 0; i < msg->len;) { - if ((msg->len - i) < QCOM_SWRM_MAX_RD_LEN) - len = msg->len - i; - else - len = QCOM_SWRM_MAX_RD_LEN; + len = min(msg->len - i, QCOM_SWRM_MAX_RD_LEN); ret = qcom_swrm_cmd_fifo_rd_cmd(ctrl, msg->dev_num, msg->addr + i, len, From 8318e04ab2526b155773313b66a1542476ce1106 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 25 Aug 2025 11:12:45 +0100 Subject: [PATCH 1054/1292] ASoC: qcom: audioreach: fix potential null pointer dereference It is possible that the topology parsing function audioreach_widget_load_module_common() could return NULL or an error pointer. Add missing NULL check so that we do not dereference it. Reported-by: Dan Carpenter Cc: Stable@vger.kernel.org Fixes: 36ad9bf1d93d ("ASoC: qdsp6: audioreach: add topology support") Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250825101247.152619-2-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index ec51fabd98cb87..c2226ed5164f76 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -607,8 +607,8 @@ static int audioreach_widget_load_module_common(struct snd_soc_component *compon return PTR_ERR(cont); mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w); - if (IS_ERR(mod)) - return PTR_ERR(mod); + if (IS_ERR_OR_NULL(mod)) + return mod ? PTR_ERR(mod) : -ENODEV; mod->data = audioreach_get_module_priv_data(&tplg_w->priv); From 7e67e1c99efa6ecd003d51a42dbe7bd5bad329eb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 25 Aug 2025 11:12:46 +0100 Subject: [PATCH 1055/1292] ASoC: qcom: topology: convert to cpu endainess type before accessing Looks like some of the members of module config are accessed directly without converting their endainess to cpu type. Fix this by using le32_to_cpu() where required. Fixes: c7ed4c2debfd ("ASoC: qcom: audioreach: add support for static calibration") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508230741.heXmHeDC-lkp@intel.com Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250825101247.152619-3-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index c2226ed5164f76..f61285e7dcf209 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -314,7 +314,7 @@ static struct audioreach_module_priv_data *audioreach_get_module_priv_data( struct snd_soc_tplg_vendor_array *mod_array; mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); - if (mod_array->type == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) { + if (le32_to_cpu(mod_array->type) == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) { struct audioreach_module_priv_data *pdata; pdata = kzalloc(struct_size(pdata, data, le32_to_cpu(mod_array->size)), From 8f57dcf39fd0864f5f3e6701fe885e55f45d0d3a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 25 Aug 2025 11:12:47 +0100 Subject: [PATCH 1056/1292] ASoC: qcom: audioreach: convert to cpu endainess type before accessing Looks like some of the members of module config are accessed directly without converting their endainess to cpu type. Fix this by using le32_to_cpu() where required. Fixes: da9881d00153 ("ASoC: qcom: audioreach: add support for SMECNS module") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508230830.Rkp7HHbG-lkp@intel.com Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20250825101247.152619-4-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/audioreach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index f4c53e84b4dc52..bbfd51db879766 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -815,7 +815,7 @@ static int audioreach_set_module_config(struct q6apm_graph *graph, struct audioreach_module *module, struct audioreach_module_config *cfg) { - int payload_size = module->data->size; + int payload_size = le32_to_cpu(module->data->size); struct gpr_pkt *pkt; int rc; void *p; From 49c2502b5946ebf454d7e16fd0189769a82b6117 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 30 Aug 2025 11:38:42 -0700 Subject: [PATCH 1057/1292] selftests: drv-net: csum: fix interface name for remote host Use cfg.remote_ifname for arguments of remote command. Without this UDP tests fail in NIPA where local interface is called enp1s0 and remote enp0s4. Fixes: 1d0dc857b5d8 ("selftests: drv-net: add checksum tests") Reviewed-by: Willem de Bruijn Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20250830183842.688935-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/hw/csum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/drivers/net/hw/csum.py b/tools/testing/selftests/drivers/net/hw/csum.py index cd23af87531708..3e3a89a34afe74 100755 --- a/tools/testing/selftests/drivers/net/hw/csum.py +++ b/tools/testing/selftests/drivers/net/hw/csum.py @@ -17,7 +17,7 @@ def test_receive(cfg, ipver="6", extra_args=None): ip_args = f"-{ipver} -S {cfg.remote_addr_v[ipver]} -D {cfg.addr_v[ipver]}" rx_cmd = f"{cfg.bin_local} -i {cfg.ifname} -n 100 {ip_args} -r 1 -R {extra_args}" - tx_cmd = f"{cfg.bin_remote} -i {cfg.ifname} -n 100 {ip_args} -r 1 -T {extra_args}" + tx_cmd = f"{cfg.bin_remote} -i {cfg.remote_ifname} -n 100 {ip_args} -r 1 -T {extra_args}" with bkg(rx_cmd, exit_wait=True): wait_port_listen(34000, proto="udp") @@ -37,7 +37,7 @@ def test_transmit(cfg, ipver="6", extra_args=None): if extra_args != "-U -Z": extra_args += " -r 1" - rx_cmd = f"{cfg.bin_remote} -i {cfg.ifname} -L 1 -n 100 {ip_args} -R {extra_args}" + rx_cmd = f"{cfg.bin_remote} -i {cfg.remote_ifname} -L 1 -n 100 {ip_args} -R {extra_args}" tx_cmd = f"{cfg.bin_local} -i {cfg.ifname} -L 1 -n 100 {ip_args} -T {extra_args}" with bkg(rx_cmd, host=cfg.remote, exit_wait=True): From a334ec77f2666b3c09e3af095efc3b4b6c5c266f Mon Sep 17 00:00:00 2001 From: Christian Loehle Date: Sun, 31 Aug 2025 22:43:57 +0100 Subject: [PATCH 1058/1292] PM: EM: Fix late boot with holes in CPU topology Commit e3f1164fc9ee ("PM: EM: Support late CPUs booting and capacity adjustment") added a mechanism to handle CPUs that come up late by retrying when any of the `cpufreq_cpu_get()` call fails. However, if there are holes in the CPU topology (offline CPUs, e.g. nosmt), the first missing CPU causes the loop to break, preventing subsequent online CPUs from being updated. Instead of aborting on the first missing CPU policy, loop through all and retry if any were missing. Fixes: e3f1164fc9ee ("PM: EM: Support late CPUs booting and capacity adjustment") Suggested-by: Kenneth Crudup Reported-by: Kenneth Crudup Closes: https://lore.kernel.org/linux-pm/40212796-734c-4140-8a85-854f72b8144d@panix.com/ Cc: 6.9+ # 6.9+ Signed-off-by: Christian Loehle Link: https://patch.msgid.link/20250831214357.2020076-1-christian.loehle@arm.com [ rjw: Drop the new one pr_debug() message which is not very useful ] Signed-off-by: Rafael J. Wysocki --- kernel/power/energy_model.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index ea7995a25780f3..14ccb357e3da5b 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -778,7 +778,7 @@ void em_adjust_cpu_capacity(unsigned int cpu) static void em_check_capacity_update(void) { cpumask_var_t cpu_done_mask; - int cpu; + int cpu, failed_cpus = 0; if (!zalloc_cpumask_var(&cpu_done_mask, GFP_KERNEL)) { pr_warn("no free memory\n"); @@ -796,10 +796,8 @@ static void em_check_capacity_update(void) policy = cpufreq_cpu_get(cpu); if (!policy) { - pr_debug("Accessing cpu%d policy failed\n", cpu); - schedule_delayed_work(&em_update_work, - msecs_to_jiffies(1000)); - break; + failed_cpus++; + continue; } cpufreq_cpu_put(policy); @@ -814,6 +812,9 @@ static void em_check_capacity_update(void) em_adjust_new_capacity(cpu, dev, pd); } + if (failed_cpus) + schedule_delayed_work(&em_update_work, msecs_to_jiffies(1000)); + free_cpumask_var(cpu_done_mask); } From 7000f4fa9b24ae2511b07babd0d49e888db5d265 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Fri, 29 Aug 2025 23:23:27 -0700 Subject: [PATCH 1059/1292] bnxt_en: fix incorrect page count in RX aggr ring log The warning in bnxt_alloc_one_rx_ring_netmem() reports the number of pages allocated for the RX aggregation ring. However, it mistakenly used bp->rx_ring_size instead of bp->rx_agg_ring_size, leading to confusing or misleading log output. Use the correct bp->rx_agg_ring_size value to fix this. Fixes: c0c050c58d84 ("bnxt_en: New Broadcom ethernet driver.") Signed-off-by: Alok Tiwari Reviewed-by: Jacob Keller Reviewed-by: Michael Chan Reviewed-by: Somnath Kotur Link: https://patch.msgid.link/20250830062331.783783-1-alok.a.tiwari@oracle.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 31e3d825b4bc07..0daa08cecaf288 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4397,7 +4397,7 @@ static void bnxt_alloc_one_rx_ring_netmem(struct bnxt *bp, for (i = 0; i < bp->rx_agg_ring_size; i++) { if (bnxt_alloc_rx_netmem(bp, rxr, prod, GFP_KERNEL)) { netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d pages only\n", - ring_nr, i, bp->rx_ring_size); + ring_nr, i, bp->rx_agg_ring_size); break; } prod = NEXT_RX_AGG(prod); From c6dd1aa2cbb72b33e0569f3e71d95792beab5042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Bl=C3=A4se?= Date: Thu, 28 Aug 2025 11:14:35 +0200 Subject: [PATCH 1060/1292] icmp: fix icmp_ndo_send address translation for reply direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The icmp_ndo_send function was originally introduced to ensure proper rate limiting when icmp_send is called by a network device driver, where the packet's source address may have already been transformed by SNAT. However, the original implementation only considers the IP_CT_DIR_ORIGINAL direction for SNAT and always replaced the packet's source address with that of the original-direction tuple. This causes two problems: 1. For SNAT: Reply-direction packets were incorrectly translated using the source address of the CT original direction, even though no translation is required. 2. For DNAT: Reply-direction packets were not handled at all. In DNAT, the original direction's destination is translated. Therefore, in the reply direction the source address must be set to the reply-direction source, so rate limiting works as intended. Fix this by using the connection direction to select the correct tuple for source address translation, and adjust the pre-checks to handle reply-direction packets in case of DNAT. Additionally, wrap the `ct->status` access in READ_ONCE(). This avoids possible KCSAN reports about concurrent updates to `ct->status`. Fixes: 0b41713b6066 ("icmp: introduce helper for nat'd source address in network device context") Signed-off-by: Fabian BlƤse Cc: Jason A. Donenfeld Reviewed-by: Florian Westphal Signed-off-by: Jakub Kicinski --- net/ipv4/icmp.c | 6 ++++-- net/ipv6/ip6_icmp.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 2ffe73ea644ff7..c48c572f024da8 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -799,11 +799,12 @@ void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct sk_buff *cloned_skb = NULL; struct ip_options opts = { 0 }; enum ip_conntrack_info ctinfo; + enum ip_conntrack_dir dir; struct nf_conn *ct; __be32 orig_ip; ct = nf_ct_get(skb_in, &ctinfo); - if (!ct || !(ct->status & IPS_SRC_NAT)) { + if (!ct || !(READ_ONCE(ct->status) & IPS_NAT_MASK)) { __icmp_send(skb_in, type, code, info, &opts); return; } @@ -818,7 +819,8 @@ void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info) goto out; orig_ip = ip_hdr(skb_in)->saddr; - ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip; + dir = CTINFO2DIR(ctinfo); + ip_hdr(skb_in)->saddr = ct->tuplehash[dir].tuple.src.u3.ip; __icmp_send(skb_in, type, code, info, &opts); ip_hdr(skb_in)->saddr = orig_ip; out: diff --git a/net/ipv6/ip6_icmp.c b/net/ipv6/ip6_icmp.c index 9e3574880cb03e..233914b63bdb82 100644 --- a/net/ipv6/ip6_icmp.c +++ b/net/ipv6/ip6_icmp.c @@ -54,11 +54,12 @@ void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info) struct inet6_skb_parm parm = { 0 }; struct sk_buff *cloned_skb = NULL; enum ip_conntrack_info ctinfo; + enum ip_conntrack_dir dir; struct in6_addr orig_ip; struct nf_conn *ct; ct = nf_ct_get(skb_in, &ctinfo); - if (!ct || !(ct->status & IPS_SRC_NAT)) { + if (!ct || !(READ_ONCE(ct->status) & IPS_NAT_MASK)) { __icmpv6_send(skb_in, type, code, info, &parm); return; } @@ -73,7 +74,8 @@ void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info) goto out; orig_ip = ipv6_hdr(skb_in)->saddr; - ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6; + dir = CTINFO2DIR(ctinfo); + ipv6_hdr(skb_in)->saddr = ct->tuplehash[dir].tuple.src.u3.in6; __icmpv6_send(skb_in, type, code, info, &parm); ipv6_hdr(skb_in)->saddr = orig_ip; out: From e580beaf43d563aaf457f1c7f934002355ebfe7b Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 28 Aug 2025 20:18:58 +0800 Subject: [PATCH 1061/1292] eth: mlx4: Fix IS_ERR() vs NULL check bug in mlx4_en_create_rx_ring Replace NULL check with IS_ERR() check after calling page_pool_create() since this function returns error pointers (ERR_PTR). Using NULL check could lead to invalid pointer dereference. Fixes: 8533b14b3d65 ("eth: mlx4: create a page pool for Rx") Signed-off-by: Miaoqian Lin Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20250828121858.67639-1-linmq006@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 92a16ddb7d8653..13666d50b90fec 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -267,8 +267,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, pp.dma_dir = priv->dma_dir; ring->pp = page_pool_create(&pp); - if (!ring->pp) + if (IS_ERR(ring->pp)) { + err = PTR_ERR(ring->pp); goto err_ring; + } if (xdp_rxq_info_reg(&ring->xdp_rxq, priv->dev, queue_index, 0) < 0) goto err_pp; From b434a3772dca1c90a40e8ec69230caa55c18ef84 Mon Sep 17 00:00:00 2001 From: Kohei Enju Date: Fri, 29 Aug 2025 15:48:42 +0900 Subject: [PATCH 1062/1292] docs: remove obsolete description about threaded NAPI Commit 2677010e7793 ("Add support to set NAPI threaded for individual NAPI") introduced threaded NAPI configuration per individual NAPI instance, however obsolete description that threaded NAPI is per device has remained. Remove the old description and clarify that only NAPI instances running in threaded mode spawn kernel threads by changing "Each NAPI instance" to "Each threaded NAPI instance". Signed-off-by: Kohei Enju Reviewed-by: Samiullah Khawaja Link: https://patch.msgid.link/20250829064857.51503-1-enjuk@amazon.com Signed-off-by: Jakub Kicinski --- Documentation/networking/napi.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/napi.rst b/Documentation/networking/napi.rst index a15754adb04173..7dd60366f4ff39 100644 --- a/Documentation/networking/napi.rst +++ b/Documentation/networking/napi.rst @@ -433,9 +433,8 @@ Threaded NAPI Threaded NAPI is an operating mode that uses dedicated kernel threads rather than software IRQ context for NAPI processing. -The configuration is per netdevice and will affect all -NAPI instances of that device. Each NAPI instance will spawn a separate -thread (called ``napi/${ifc-name}-${napi-id}``). +Each threaded NAPI instance will spawn a separate thread +(called ``napi/${ifc-name}-${napi-id}``). It is recommended to pin each kernel thread to a single CPU, the same CPU as the CPU which services the interrupt. Note that the mapping From 6bc8a5098bf4a365c4086a4a4130bfab10a58260 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 29 Aug 2025 10:35:21 -0400 Subject: [PATCH 1063/1292] net: macb: Fix tx_ptr_lock locking macb_start_xmit and macb_tx_poll can be called with bottom-halves disabled (e.g. from softirq) as well as with interrupts disabled (with netpoll). Because of this, all other functions taking tx_ptr_lock must use spin_lock_irqsave. Fixes: 138badbc21a0 ("net: macb: use NAPI for TX completion path") Reported-by: Mike Galbraith Signed-off-by: Sean Anderson Link: https://patch.msgid.link/20250829143521.1686062-1-sean.anderson@linux.dev Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/cadence/macb_main.c | 28 ++++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 16d28a8b3b56cc..c769b7dbd3baf5 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1223,12 +1223,13 @@ static int macb_tx_complete(struct macb_queue *queue, int budget) { struct macb *bp = queue->bp; u16 queue_index = queue - bp->queues; + unsigned long flags; unsigned int tail; unsigned int head; int packets = 0; u32 bytes = 0; - spin_lock(&queue->tx_ptr_lock); + spin_lock_irqsave(&queue->tx_ptr_lock, flags); head = queue->tx_head; for (tail = queue->tx_tail; tail != head && packets < budget; tail++) { struct macb_tx_skb *tx_skb; @@ -1291,7 +1292,7 @@ static int macb_tx_complete(struct macb_queue *queue, int budget) CIRC_CNT(queue->tx_head, queue->tx_tail, bp->tx_ring_size) <= MACB_TX_WAKEUP_THRESH(bp)) netif_wake_subqueue(bp->dev, queue_index); - spin_unlock(&queue->tx_ptr_lock); + spin_unlock_irqrestore(&queue->tx_ptr_lock, flags); return packets; } @@ -1707,8 +1708,9 @@ static void macb_tx_restart(struct macb_queue *queue) { struct macb *bp = queue->bp; unsigned int head_idx, tbqp; + unsigned long flags; - spin_lock(&queue->tx_ptr_lock); + spin_lock_irqsave(&queue->tx_ptr_lock, flags); if (queue->tx_head == queue->tx_tail) goto out_tx_ptr_unlock; @@ -1720,19 +1722,20 @@ static void macb_tx_restart(struct macb_queue *queue) if (tbqp == head_idx) goto out_tx_ptr_unlock; - spin_lock_irq(&bp->lock); + spin_lock(&bp->lock); macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); - spin_unlock_irq(&bp->lock); + spin_unlock(&bp->lock); out_tx_ptr_unlock: - spin_unlock(&queue->tx_ptr_lock); + spin_unlock_irqrestore(&queue->tx_ptr_lock, flags); } static bool macb_tx_complete_pending(struct macb_queue *queue) { bool retval = false; + unsigned long flags; - spin_lock(&queue->tx_ptr_lock); + spin_lock_irqsave(&queue->tx_ptr_lock, flags); if (queue->tx_head != queue->tx_tail) { /* Make hw descriptor updates visible to CPU */ rmb(); @@ -1740,7 +1743,7 @@ static bool macb_tx_complete_pending(struct macb_queue *queue) if (macb_tx_desc(queue, queue->tx_tail)->ctrl & MACB_BIT(TX_USED)) retval = true; } - spin_unlock(&queue->tx_ptr_lock); + spin_unlock_irqrestore(&queue->tx_ptr_lock, flags); return retval; } @@ -2308,6 +2311,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) struct macb_queue *queue = &bp->queues[queue_index]; unsigned int desc_cnt, nr_frags, frag_size, f; unsigned int hdrlen; + unsigned long flags; bool is_lso; netdev_tx_t ret = NETDEV_TX_OK; @@ -2368,7 +2372,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length); } - spin_lock_bh(&queue->tx_ptr_lock); + spin_lock_irqsave(&queue->tx_ptr_lock, flags); /* This is a hard error, log it. */ if (CIRC_SPACE(queue->tx_head, queue->tx_tail, @@ -2392,15 +2396,15 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev) netdev_tx_sent_queue(netdev_get_tx_queue(bp->dev, queue_index), skb->len); - spin_lock_irq(&bp->lock); + spin_lock(&bp->lock); macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); - spin_unlock_irq(&bp->lock); + spin_unlock(&bp->lock); if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1) netif_stop_subqueue(dev, queue_index); unlock: - spin_unlock_bh(&queue->tx_ptr_lock); + spin_unlock_irqrestore(&queue->tx_ptr_lock, flags); return ret; } From 030e1c45666629f72d0fc1d040f9d2915680de8e Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 29 Aug 2025 20:55:40 +0200 Subject: [PATCH 1064/1292] macsec: read MACSEC_SA_ATTR_PN with nla_get_uint The code currently reads both U32 attributes and U64 attributes as U64, so when a U32 attribute is provided by userspace (ie, when not using XPN), on big endian systems, we'll load that value into the upper 32bits of the next_pn field instead of the lower 32bits. This means that the value that userspace provided is ignored (we only care about the lower 32bits for non-XPN), and we'll start using PNs from 0. Switch to nla_get_uint, which will read the value correctly on all arches, whether it's 32b or 64b. Fixes: 48ef50fa866a ("macsec: Netlink support of XPN cipher suites (IEEE 802.1AEbw)") Signed-off-by: Sabrina Dubroca Reviewed-by: Simon Horman Link: https://patch.msgid.link/1c1df1661b89238caf5beefb84a10ebfd56c66ea.1756459839.git.sd@queasysnail.net Signed-off-by: Jakub Kicinski --- drivers/net/macsec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 4c75d1fea55271..01329fe7451a12 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -1844,7 +1844,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info) if (tb_sa[MACSEC_SA_ATTR_PN]) { spin_lock_bh(&rx_sa->lock); - rx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]); + rx_sa->next_pn = nla_get_uint(tb_sa[MACSEC_SA_ATTR_PN]); spin_unlock_bh(&rx_sa->lock); } @@ -2086,7 +2086,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info) } spin_lock_bh(&tx_sa->lock); - tx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]); + tx_sa->next_pn = nla_get_uint(tb_sa[MACSEC_SA_ATTR_PN]); spin_unlock_bh(&tx_sa->lock); if (tb_sa[MACSEC_SA_ATTR_ACTIVE]) @@ -2398,7 +2398,7 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info) spin_lock_bh(&tx_sa->lock); prev_pn = tx_sa->next_pn_halves; - tx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]); + tx_sa->next_pn = nla_get_uint(tb_sa[MACSEC_SA_ATTR_PN]); spin_unlock_bh(&tx_sa->lock); } @@ -2496,7 +2496,7 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info) spin_lock_bh(&rx_sa->lock); prev_pn = rx_sa->next_pn_halves; - rx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]); + rx_sa->next_pn = nla_get_uint(tb_sa[MACSEC_SA_ATTR_PN]); spin_unlock_bh(&rx_sa->lock); } From c873ccbb2f8db46ad9b4a989ea924b6d8f19abf1 Mon Sep 17 00:00:00 2001 From: Gu Bowen Date: Fri, 22 Aug 2025 15:35:41 +0800 Subject: [PATCH 1065/1292] mm: fix possible deadlock in kmemleak There are some AA deadlock issues in kmemleak, similar to the situation reported by Breno [1]. The deadlock path is as follows: mem_pool_alloc() -> raw_spin_lock_irqsave(&kmemleak_lock, flags); -> pr_warn() -> netconsole subsystem -> netpoll -> __alloc_skb -> __create_object -> raw_spin_lock_irqsave(&kmemleak_lock, flags); To solve this problem, switch to printk_safe mode before printing warning message, this will redirect all printk()-s to a special per-CPU buffer, which will be flushed later from a safe context (irq work), and this deadlock problem can be avoided. The proper API to use should be printk_deferred_enter()/printk_deferred_exit() [2]. Another way is to place the warn print after kmemleak is released. Link: https://lkml.kernel.org/r/20250822073541.1886469-1-gubowen5@huawei.com Link: https://lore.kernel.org/all/20250731-kmemleak_lock-v1-1-728fd470198f@debian.org/#t [1] Link: https://lore.kernel.org/all/5ca375cd-4a20-4807-b897-68b289626550@redhat.com/ [2] Signed-off-by: Gu Bowen Reviewed-by: Waiman Long Reviewed-by: Catalin Marinas Reviewed-by: Breno Leitao Cc: Greg Kroah-Hartman Cc: John Ogness Cc: Lu Jialin Cc: Petr Mladek Cc: Signed-off-by: Andrew Morton --- mm/kmemleak.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 84265983f239c1..1ac56ceb29b6b1 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -437,9 +437,15 @@ static struct kmemleak_object *__lookup_object(unsigned long ptr, int alias, else if (untagged_objp == untagged_ptr || alias) return object; else { + /* + * Printk deferring due to the kmemleak_lock held. + * This is done to avoid deadlock. + */ + printk_deferred_enter(); kmemleak_warn("Found object by alias at 0x%08lx\n", ptr); dump_object_info(object); + printk_deferred_exit(); break; } } @@ -736,6 +742,11 @@ static int __link_object(struct kmemleak_object *object, unsigned long ptr, else if (untagged_objp + parent->size <= untagged_ptr) link = &parent->rb_node.rb_right; else { + /* + * Printk deferring due to the kmemleak_lock held. + * This is done to avoid deadlock. + */ + printk_deferred_enter(); kmemleak_stop("Cannot insert 0x%lx into the object search tree (overlaps existing)\n", ptr); /* @@ -743,6 +754,7 @@ static int __link_object(struct kmemleak_object *object, unsigned long ptr, * be freed while the kmemleak_lock is held. */ dump_object_info(parent); + printk_deferred_exit(); return -EEXIST; } } @@ -856,13 +868,8 @@ static void delete_object_part(unsigned long ptr, size_t size, raw_spin_lock_irqsave(&kmemleak_lock, flags); object = __find_and_remove_object(ptr, 1, objflags); - if (!object) { -#ifdef DEBUG - kmemleak_warn("Partially freeing unknown object at 0x%08lx (size %zu)\n", - ptr, size); -#endif + if (!object) goto unlock; - } /* * Create one or two objects that may result from the memory block @@ -882,8 +889,14 @@ static void delete_object_part(unsigned long ptr, size_t size, unlock: raw_spin_unlock_irqrestore(&kmemleak_lock, flags); - if (object) + if (object) { __delete_object(object); + } else { +#ifdef DEBUG + kmemleak_warn("Partially freeing unknown object at 0x%08lx (size %zu)\n", + ptr, size); +#endif + } out: if (object_l) From dcc6785caffad27f2ea601fdd2f9782036e1faed Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Tue, 26 Aug 2025 10:08:36 +0200 Subject: [PATCH 1066/1292] arm64: dts: rockchip: fix second M.2 slot on ROCK 5T The Radxa ROCK 5T has two M.2 slots, much like the Radxa Rock 5B+. As it stands, the board won't be able to use PCIe3 if the second M.2 slot is in use. Fix this by adding the necessary node enablement and data-lanes property to the ROCK 5T device tree, mirroring what's in the ROCK 5B+ device tree. Reported-by: FUKAUMI Naoki Closes: https://libera.catirclogs.org/linux-rockchip/2025-08-25#38610630; Fixes: 0ea651de9b79 ("arm64: dts: rockchip: add ROCK 5T device tree") Signed-off-by: Nicolas Frattaroli Link: https://lore.kernel.org/r/20250826-rock5t-second-m2-fix-v1-1-8252124f9cc8@collabora.com Signed-off-by: Heiko Stuebner --- .../boot/dts/rockchip/rk3588-rock-5t.dts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts index 6acc7a8a5a12ee..f16ff0064309ae 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts @@ -68,6 +68,22 @@ status = "okay"; }; +&pcie30phy { + data-lanes = <1 1 2 2>; +}; + +&pcie3x2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie3x2_rst>; + reset-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_pcie30>; + status = "okay"; +}; + +&pcie3x4 { + num-lanes = <2>; +}; + &pinctrl { hdmirx { hdmirx_hpd: hdmirx-5v-detection { @@ -90,6 +106,12 @@ }; }; + pcie3 { + pcie3x2_rst: pcie3x2-rst { + rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + sound { hp_detect: hp-detect { rockchip,pins = <4 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; From ba1e9421cf1a8369d25c3832439702a015d6b5f9 Mon Sep 17 00:00:00 2001 From: Liu Jian Date: Thu, 28 Aug 2025 20:41:17 +0800 Subject: [PATCH 1067/1292] net/smc: fix one NULL pointer dereference in smc_ib_is_sg_need_sync() BUG: kernel NULL pointer dereference, address: 00000000000002ec PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP PTI CPU: 28 UID: 0 PID: 343 Comm: kworker/28:1 Kdump: loaded Tainted: G OE 6.17.0-rc2+ #9 NONE Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014 Workqueue: smc_hs_wq smc_listen_work [smc] RIP: 0010:smc_ib_is_sg_need_sync+0x9e/0xd0 [smc] ... Call Trace: smcr_buf_map_link+0x211/0x2a0 [smc] __smc_buf_create+0x522/0x970 [smc] smc_buf_create+0x3a/0x110 [smc] smc_find_rdma_v2_device_serv+0x18f/0x240 [smc] ? smc_vlan_by_tcpsk+0x7e/0xe0 [smc] smc_listen_find_device+0x1dd/0x2b0 [smc] smc_listen_work+0x30f/0x580 [smc] process_one_work+0x18c/0x340 worker_thread+0x242/0x360 kthread+0xe7/0x220 ret_from_fork+0x13a/0x160 ret_from_fork_asm+0x1a/0x30 If the software RoCE device is used, ibdev->dma_device is a null pointer. As a result, the problem occurs. Null pointer detection is added to prevent problems. Fixes: 0ef69e788411c ("net/smc: optimize for smc_sndbuf_sync_sg_for_device and smc_rmb_sync_sg_for_cpu") Signed-off-by: Liu Jian Reviewed-by: Guangguan Wang Reviewed-by: Zhu Yanjun Reviewed-by: D. Wythe Link: https://patch.msgid.link/20250828124117.2622624-1-liujian56@huawei.com Signed-off-by: Paolo Abeni --- net/smc/smc_ib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 53828833a3f7f7..a42ef3f77b961a 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -742,6 +742,9 @@ bool smc_ib_is_sg_need_sync(struct smc_link *lnk, unsigned int i; bool ret = false; + if (!lnk->smcibdev->ibdev->dma_device) + return ret; + /* for now there is just one DMA address */ for_each_sg(buf_slot->sgt[lnk->link_idx].sgl, sg, buf_slot->sgt[lnk->link_idx].nents, i) { From ef9f21c3f370bcd45688a3a573b788e39b364e80 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 1 Sep 2025 14:55:13 +0200 Subject: [PATCH 1068/1292] gpio: fix GPIO submenu in Kconfig Commit a86240a37d43 ("gpiolib: enable CONFIG_GPIOLIB_LEGACY even for !GPIOLIB") accidentally pulled all items from within the GPIOLIB submenu into the main driver menu. Put them back under the top-level GPIO entry. Suggested-by: Rob Herring Fixes: a86240a37d43 ("gpiolib: enable CONFIG_GPIOLIB_LEGACY even for !GPIOLIB") Reported-by: Rob Herring Closes: https://lore.kernel.org/all/20250813222649.GA965895-robh@kernel.org/ Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20250901125513.108691-1-brgl@bgdev.pl Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e43abb322fa6e1..d8ac40d0eb6fb6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -3,6 +3,9 @@ # GPIO infrastructure and drivers # +config GPIOLIB_LEGACY + def_bool y + menuconfig GPIOLIB bool "GPIO Support" help @@ -12,9 +15,6 @@ menuconfig GPIOLIB If unsure, say N. -config GPIOLIB_LEGACY - def_bool y - if GPIOLIB config GPIOLIB_FASTPATH_LIMIT From 78338108b5a856dc98223a335f147846a8a18c51 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 29 Aug 2025 15:57:34 +0300 Subject: [PATCH 1069/1292] ASoC: codec: sma1307: Fix memory corruption in sma1307_setting_loaded() The sma1307->set.header_size is how many integers are in the header (there are 8 of them) but instead of allocating space of 8 integers we allocate 8 bytes. This leads to memory corruption when we copy data it on the next line: memcpy(sma1307->set.header, data, sma1307->set.header_size * sizeof(int)); Also since we're immediately copying over the memory in ->set.header, there is no need to zero it in the allocator. Use devm_kmalloc_array() to allocate the memory instead. Fixes: 576c57e6b4c1 ("ASoC: sma1307: Add driver for Iron Device SMA1307") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aLGjvjpueVstekXP@stanley.mountain Signed-off-by: Mark Brown --- sound/soc/codecs/sma1307.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c index 6a601e7134ea2d..b683e676640d89 100644 --- a/sound/soc/codecs/sma1307.c +++ b/sound/soc/codecs/sma1307.c @@ -1737,9 +1737,10 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil sma1307->set.checksum = data[sma1307->set.header_size - 2]; sma1307->set.num_mode = data[sma1307->set.header_size - 1]; num_mode = sma1307->set.num_mode; - sma1307->set.header = devm_kzalloc(sma1307->dev, - sma1307->set.header_size, - GFP_KERNEL); + sma1307->set.header = devm_kmalloc_array(sma1307->dev, + sma1307->set.header_size, + sizeof(int), + GFP_KERNEL); if (!sma1307->set.header) { sma1307->set.status = false; return; From f1d0260362d72f9f454dc1f9db2eeb80cb801f28 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Thu, 21 Aug 2025 11:15:47 +0530 Subject: [PATCH 1070/1292] ASoC: amd: acp: Adjust pdm gain value Set pdm gain value by setting PDM_MISC_CTRL_MASK value. To avoid low pdm gain value. Signed-off-by: Venkata Prasad Potturu Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/20250821054606.1279178-1-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/amd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index cb8d97122f95c7..73a028e672462d 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -130,7 +130,7 @@ #define PDM_DMA_INTR_MASK 0x10000 #define PDM_DEC_64 0x2 #define PDM_CLK_FREQ_MASK 0x07 -#define PDM_MISC_CTRL_MASK 0x10 +#define PDM_MISC_CTRL_MASK 0x18 #define PDM_ENABLE 0x01 #define PDM_DISABLE 0x00 #define DMA_EN_MASK 0x02 From 28edfaa10ca1b370b1a27fde632000d35c43402c Mon Sep 17 00:00:00 2001 From: Maciej Strozek Date: Mon, 1 Sep 2025 16:15:07 +0100 Subject: [PATCH 1071/1292] ASoC: SDCA: Add quirk for incorrect function types for 3 systems Certain systems have CS42L43 DisCo that claims to conform to version 0.6.28 but uses the function types from the 1.0 spec. Add a quirk as a workaround. Closes: https://github.com/thesofproject/linux/issues/5515 Cc: stable@vger.kernel.org Signed-off-by: Maciej Strozek Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250901151518.3197941-1-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca.h | 1 + sound/soc/sdca/sdca_device.c | 20 ++++++++++++++++++++ sound/soc/sdca/sdca_functions.c | 13 ++++++++----- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/include/sound/sdca.h b/include/sound/sdca.h index 5a5d6de78d7283..9c6a351c9d474f 100644 --- a/include/sound/sdca.h +++ b/include/sound/sdca.h @@ -46,6 +46,7 @@ struct sdca_device_data { enum sdca_quirk { SDCA_QUIRKS_RT712_VB, + SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING, }; #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA) diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c index 0244cdcdd109a7..4798ce2c8f0b40 100644 --- a/sound/soc/sdca/sdca_device.c +++ b/sound/soc/sdca/sdca_device.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -55,11 +56,30 @@ static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave) return false; } +static bool sdca_device_quirk_skip_func_type_patching(struct sdw_slave *slave) +{ + const char *vendor, *sku; + + vendor = dmi_get_system_info(DMI_SYS_VENDOR); + sku = dmi_get_system_info(DMI_PRODUCT_SKU); + + if (vendor && sku && + !strcmp(vendor, "Dell Inc.") && + (!strcmp(sku, "0C62") || !strcmp(sku, "0C63") || !strcmp(sku, "0C6B")) && + slave->sdca_data.interface_revision == 0x061c && + slave->id.mfg_id == 0x01fa && slave->id.part_id == 0x4243) + return true; + + return false; +} + bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) { switch (quirk) { case SDCA_QUIRKS_RT712_VB: return sdca_device_quirk_rt712_vb(slave); + case SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING: + return sdca_device_quirk_skip_func_type_patching(slave); default: break; } diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index f26f597dca9e94..13f68f7b6dd6af 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -90,6 +90,7 @@ static int find_sdca_function(struct acpi_device *adev, void *data) { struct fwnode_handle *function_node = acpi_fwnode_handle(adev); struct sdca_device_data *sdca_data = data; + struct sdw_slave *slave = container_of(sdca_data, struct sdw_slave, sdca_data); struct device *dev = &adev->dev; struct fwnode_handle *control5; /* used to identify function type */ const char *function_name; @@ -137,11 +138,13 @@ static int find_sdca_function(struct acpi_device *adev, void *data) return ret; } - ret = patch_sdca_function_type(sdca_data->interface_revision, &function_type); - if (ret < 0) { - dev_err(dev, "SDCA version %#x invalid function type %d\n", - sdca_data->interface_revision, function_type); - return ret; + if (!sdca_device_quirk_match(slave, SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING)) { + ret = patch_sdca_function_type(sdca_data->interface_revision, &function_type); + if (ret < 0) { + dev_err(dev, "SDCA version %#x invalid function type %d\n", + sdca_data->interface_revision, function_type); + return ret; + } } function_name = get_sdca_function_name(function_type); From 649c6e1314d43840cbdca854d37ca30423acdb9f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Sep 2025 11:56:35 +0200 Subject: [PATCH 1072/1292] ALSA: hda/realtek: Use is_s4_resume() macro Use the given macro for determining the resume state instead of referring to the raw value. Only a cleanup for now. The infrastructure might be changed in future, though. Link: https://patch.msgid.link/20250902095636.21462-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 26ccd8d7c6d823..02ed1ac27d4703 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -872,8 +872,7 @@ static void alc294_init(struct hda_codec *codec) struct alc_spec *spec = codec->spec; /* required only at boot or S4 resume time */ - if (!spec->done_hp_init || - codec->core.dev.power.power_state.event == PM_EVENT_RESTORE) { + if (!spec->done_hp_init || is_s4_resume(codec)) { alc294_hp_init(codec); spec->done_hp_init = true; } From 3279052eab235bfb7130b1fabc74029c2260ed8d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Sep 2025 09:32:13 +0100 Subject: [PATCH 1073/1292] ASoC: SOF: ipc4-topology: Fix a less than zero check on a u32 Currently the error check from the call to sof_ipc4_get_sample_type is always false because a u32 variable out_ref_type is being used to perform the less than zero check. Fix this by using the int variable ret to perform the check. Fixes: c04c2e829649 ("ASoC: SOF: ipc4-topology: Add support for 8-bit formats") Signed-off-by: Colin Ian King Acked-by: Peter Ujfalusi Link: https://patch.msgid.link/20250902083213.2620124-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index f5e62cd8fc0cb4..b6a732d0adb4b7 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -2191,9 +2191,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, case snd_soc_dapm_dai_in: out_ref_rate = params_rate(fe_params); out_ref_channels = params_channels(fe_params); - out_ref_type = sof_ipc4_get_sample_type(sdev, fe_params); - if (out_ref_type < 0) - return out_ref_type; + ret = sof_ipc4_get_sample_type(sdev, fe_params); + if (ret < 0) + return ret; + out_ref_type = (u32)ret; if (!single_output_bitdepth) { out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); From 232674e1a6dd2f7a68b0d496a7ed1a57d79533da Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Mon, 1 Sep 2025 14:40:32 +0200 Subject: [PATCH 1074/1292] drm/sched: Fix racy access to drm_sched_entity.dependency The drm_sched_job_unschedulable trace point can access entity->dependency after it was cleared by the callback installed in drm_sched_entity_add_dependency_cb, causing: BUG: kernel NULL pointer dereference, address: 0000000000000020 [...] Workqueue: comp_1.1.0 drm_sched_run_job_work [gpu_sched] RIP: 0010:trace_event_raw_event_drm_sched_job_unschedulable+0x70/0xd0 [gpu_sched] To fix this we either need to keep a reference to the fence before setting up the callbacks, or move the trace_drm_sched_job_unschedulable calls into drm_sched_entity_add_dependency_cb where they can be done earlier. Fixes: 76d97c870f29 ("drm/sched: Trace dependencies for GPU jobs") Signed-off-by: Pierre-Eric Pelloux-Prayer Reviewed-by: Tvrtko Ursulin Signed-off-by: Philipp Stanner Link: https://lore.kernel.org/r/20250901124032.1955-1-pierre-eric.pelloux-prayer@amd.com (cherry picked from commit b2b8af21fec35be417a3199b5a6c354605dd222a) Signed-off-by: Maxime Ripard --- drivers/gpu/drm/scheduler/sched_entity.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 8867b95ab089ce..3d06f72531ba24 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -391,7 +391,8 @@ EXPORT_SYMBOL(drm_sched_entity_set_priority); * Add a callback to the current dependency of the entity to wake up the * scheduler when the entity becomes available. */ -static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) +static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity, + struct drm_sched_job *sched_job) { struct drm_gpu_scheduler *sched = entity->rq->sched; struct dma_fence *fence = entity->dependency; @@ -421,6 +422,10 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) entity->dependency = fence; } + if (trace_drm_sched_job_unschedulable_enabled() && + !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &entity->dependency->flags)) + trace_drm_sched_job_unschedulable(sched_job, entity->dependency); + if (!dma_fence_add_callback(entity->dependency, &entity->cb, drm_sched_entity_wakeup)) return true; @@ -461,10 +466,8 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) while ((entity->dependency = drm_sched_job_dependency(sched_job, entity))) { - if (drm_sched_entity_add_dependency_cb(entity)) { - trace_drm_sched_job_unschedulable(sched_job, entity->dependency); + if (drm_sched_entity_add_dependency_cb(entity, sched_job)) return NULL; - } } /* skip jobs from entity that marked guilty */ From 0c28431f6fe13f3a3be0978f79c1a7ae8a93d028 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 2 Sep 2025 13:21:00 +0300 Subject: [PATCH 1075/1292] ASoC: SOF: imx: Fix devm_ioremap_resource check devm_ioremap_resource does not return NULL on error but an error pointer so we need to use IS_ERR to check the return code. While at it also pass the error code to dev_err_probe to improve logging. Fixes: bc163baef570 ("ASoC: Use of_reserved_mem_region_to_resource() for "memory-region"") Signed-off-by: Daniel Baluta Link: https://patch.msgid.link/20250902102101.378809-1-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index f00b381cec3b4a..d66c198b861ae9 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -316,9 +316,9 @@ static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev) } sdev->bar[blk_type] = devm_ioremap_resource(sdev->dev, res); - if (!sdev->bar[blk_type]) + if (IS_ERR(sdev->bar[blk_type])) return dev_err_probe(sdev->dev, - -ENOMEM, + PTR_ERR(sdev->bar[blk_type]), "failed to ioremap %s region\n", chip_info->memory[i].name); } From 773b27a8a2f00ce3134e92e50ea4794a98ba2b76 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 29 Aug 2025 15:28:26 +0800 Subject: [PATCH 1076/1292] net: mctp: mctp_fraq_queue should take ownership of passed skb As of commit f5d83cf0eeb9 ("net: mctp: unshare packets when reassembling"), we skb_unshare() in mctp_frag_queue(). The unshare may invalidate the original skb pointer, so we need to treat the skb as entirely owned by the fraq queue, even on failure. Fixes: f5d83cf0eeb9 ("net: mctp: unshare packets when reassembling") Signed-off-by: Jeremy Kerr Link: https://patch.msgid.link/20250829-mctp-skb-unshare-v1-1-1c28fe10235a@codeconstruct.com.au Signed-off-by: Paolo Abeni --- net/mctp/route.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/net/mctp/route.c b/net/mctp/route.c index 2b2b958ef6a375..4d314e062ba9c4 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -378,6 +378,7 @@ static void mctp_skb_set_flow(struct sk_buff *skb, struct mctp_sk_key *key) {} static void mctp_flow_prepare_output(struct sk_buff *skb, struct mctp_dev *dev) {} #endif +/* takes ownership of skb, both in success and failure cases */ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb) { struct mctp_hdr *hdr = mctp_hdr(skb); @@ -387,8 +388,10 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb) & MCTP_HDR_SEQ_MASK; if (!key->reasm_head) { - /* Since we're manipulating the shared frag_list, ensure it isn't - * shared with any other SKBs. + /* Since we're manipulating the shared frag_list, ensure it + * isn't shared with any other SKBs. In the cloned case, + * this will free the skb; callers can no longer access it + * safely. */ key->reasm_head = skb_unshare(skb, GFP_ATOMIC); if (!key->reasm_head) @@ -402,10 +405,10 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb) exp_seq = (key->last_seq + 1) & MCTP_HDR_SEQ_MASK; if (this_seq != exp_seq) - return -EINVAL; + goto err_free; if (key->reasm_head->len + skb->len > mctp_message_maxlen) - return -EINVAL; + goto err_free; skb->next = NULL; skb->sk = NULL; @@ -419,6 +422,10 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb) key->reasm_head->truesize += skb->truesize; return 0; + +err_free: + kfree_skb(skb); + return -EINVAL; } static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb) @@ -532,18 +539,16 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb) * key isn't observable yet */ mctp_frag_queue(key, skb); + skb = NULL; /* if the key_add fails, we've raced with another * SOM packet with the same src, dest and tag. There's * no way to distinguish future packets, so all we - * can do is drop; we'll free the skb on exit from - * this function. + * can do is drop. */ rc = mctp_key_add(key, msk); - if (!rc) { + if (!rc) trace_mctp_key_acquire(key); - skb = NULL; - } /* we don't need to release key->lock on exit, so * clean up here and suppress the unlock via @@ -561,8 +566,7 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb) key = NULL; } else { rc = mctp_frag_queue(key, skb); - if (!rc) - skb = NULL; + skb = NULL; } } @@ -572,17 +576,16 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb) */ /* we need to be continuing an existing reassembly... */ - if (!key->reasm_head) + if (!key->reasm_head) { rc = -EINVAL; - else + } else { rc = mctp_frag_queue(key, skb); + skb = NULL; + } if (rc) goto out_unlock; - /* we've queued; the queue owns the skb now */ - skb = NULL; - /* end of message? deliver to socket, and we're done with * the reassembly/response key */ From e27e34bc99413a29cafae02ad572ea3c9beba2ce Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 29 Aug 2025 15:40:23 +0800 Subject: [PATCH 1077/1292] net: mctp: usb: initialise mac header in RX path We're not currently setting skb->mac_header on ingress, and the netdev core rx path expects it. Without it, we'll hit a warning on DEBUG_NETDEV from commit 1e4033b53db4 ("net: skb_reset_mac_len() must check if mac_header was set") Initialise the mac_header to refer to the USB transport header. Fixes: 0791c0327a6e ("net: mctp: Add MCTP USB transport driver") Signed-off-by: Jeremy Kerr Link: https://patch.msgid.link/20250829-mctp-usb-mac-header-v1-1-338ad725e183@codeconstruct.com.au Signed-off-by: Paolo Abeni --- drivers/net/mctp/mctp-usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c index 775a386d0aca12..36ccc53b179759 100644 --- a/drivers/net/mctp/mctp-usb.c +++ b/drivers/net/mctp/mctp-usb.c @@ -183,6 +183,7 @@ static void mctp_usb_in_complete(struct urb *urb) struct mctp_usb_hdr *hdr; u8 pkt_len; /* length of MCTP packet, no USB header */ + skb_reset_mac_header(skb); hdr = skb_pull_data(skb, sizeof(*hdr)); if (!hdr) break; From a6099f263e1f408bcc7913c9df24b0677164fc5d Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 29 Aug 2025 17:40:51 +0530 Subject: [PATCH 1078/1292] net: ethernet: ti: am65-cpsw-nuss: Fix null pointer dereference for ndev In the TX completion packet stage of TI SoCs with CPSW2G instance, which has single external ethernet port, ndev is accessed without being initialized if no TX packets have been processed. It results into null pointer dereference, causing kernel to crash. Fix this by having a check on the number of TX packets which have been processed. Fixes: 9a369ae3d143 ("net: ethernet: ti: am65-cpsw: remove am65_cpsw_nuss_tx_compl_packets_2g()") Signed-off-by: Nishanth Menon Signed-off-by: Chintan Vankar Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250829121051.2031832-1-c-vankar@ti.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index ecd6ecac87bb4d..8b2364f5f73124 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -1522,7 +1522,7 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common, } } - if (single_port) { + if (single_port && num_tx) { netif_txq = netdev_get_tx_queue(ndev, chn); netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); am65_cpsw_nuss_tx_wake(tx_chn, ndev, netif_txq); From 379b3c983fc0257c183052278832ac68e3ccd33b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Thu, 28 Aug 2025 15:48:37 +0200 Subject: [PATCH 1079/1292] drm/xe: Fix incorrect migration of backed-up object to VRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an object is backed up to shmem it is incorrectly identified as not having valid data by the move code. This means moving to VRAM skips the -EMULTIHOP step and the bo is cleared. This causes all sorts of weird behaviour on DGFX if an already evicted object is targeted by the shrinker. Fix this by using ttm_tt_is_swapped() to identify backed-up objects. Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/5996 Fixes: 00c8efc3180f ("drm/xe: Add a shrinker for xe bos") Cc: Matthew Brost Cc: Matthew Auld Cc: # v6.15+ Signed-off-by: Thomas Hellstrƶm Reviewed-by: Matthew Auld Link: https://lore.kernel.org/r/20250828134837.5709-1-thomas.hellstrom@linux.intel.com (cherry picked from commit 1047bd82794a1eab64d643f196d09171ce983f44) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_bo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 1be2415966df2d..9954bb458ce12d 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -819,8 +819,7 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, return ret; } - tt_has_data = ttm && (ttm_tt_is_populated(ttm) || - (ttm->page_flags & TTM_TT_FLAG_SWAPPED)); + tt_has_data = ttm && (ttm_tt_is_populated(ttm) || ttm_tt_is_swapped(ttm)); move_lacks_source = !old_mem || (handle_system_ccs ? (!bo->ccs_cleared) : (!mem_type_is_vram(old_mem_type) && !tt_has_data)); From 35fc531a59694f24a2456569cf7d1a9c6436841c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Sep 2025 13:06:39 +0100 Subject: [PATCH 1080/1292] ASoC: SOF: Intel: hda-stream: Fix incorrect variable used in error message The dev_err message is reporting an error about capture streams however it is using the incorrect variable num_playback instead of num_capture. Fix this by using the correct variable num_capture. Fixes: a1d1e266b445 ("ASoC: SOF: Intel: Add Intel specific HDA stream operations") Signed-off-by: Colin Ian King Acked-by: Peter Ujfalusi Link: https://patch.msgid.link/20250902120639.2626861-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index aa6b0247d5c99e..a34f472ef1751f 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -890,7 +890,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) if (num_capture >= SOF_HDA_CAPTURE_STREAMS) { dev_err(sdev->dev, "error: too many capture streams %d\n", - num_playback); + num_capture); return -EINVAL; } From 304f455b648d68ba47135583b644ee72ac48d544 Mon Sep 17 00:00:00 2001 From: James Jones Date: Tue, 26 Aug 2025 12:57:16 -0700 Subject: [PATCH 1081/1292] MAINTAINERS: Update git entry for nouveau The gitlab repository previously associated with the nouveau module has fallen out of use. The drm-misc tree here: https://gitlab.freedesktop.org/drm/misc/kernel.git Is now where most nouveau-related patches are applied. This change updates the MAINTAINERS file to reflect this. Signed-off-by: James Jones Link: https://lore.kernel.org/r/20250826195716.1897-1-jajones@nvidia.com Signed-off-by: Danilo Krummrich --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3f1c4af3f8e09b..f94e115a8d32b0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7820,7 +7820,7 @@ Q: https://patchwork.freedesktop.org/project/nouveau/ Q: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests B: https://gitlab.freedesktop.org/drm/nouveau/-/issues C: irc://irc.oftc.net/nouveau -T: git https://gitlab.freedesktop.org/drm/nouveau.git +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: drivers/gpu/drm/nouveau/ F: include/uapi/drm/nouveau_drm.h From 7a8c994cbb2db3c5335cee35fd486557f5aaf7e1 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Mon, 28 Jul 2025 15:06:12 +0800 Subject: [PATCH 1082/1292] ACPI: processor: idle: Optimize ACPI idle driver registration Currently, the ACPI idle driver is registered from within a CPU hotplug callback. Although this didn't cause any functional issues, this is questionable and confusing. And it is better to register the cpuidle driver when all of the CPUs have been brought up. So add a new function to initialize acpi_idle_driver based on the power management information of an available CPU and register cpuidle driver in acpi_processor_driver_init(). Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250728070612.1260859-3-lihuisong@huawei.com [ rjw: Added missing inline modifiers ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 3 ++ drivers/acpi/processor_idle.c | 65 +++++++++++++++++++++------------ include/acpi/processor.h | 8 ++++ 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 65e779be64ffcc..bc9f58a02c1db5 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -263,6 +263,8 @@ static int __init acpi_processor_driver_init(void) if (result < 0) return result; + acpi_processor_register_idle_driver(); + result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "acpi/cpu-drv:online", acpi_soft_cpu_online, NULL); @@ -301,6 +303,7 @@ static void __exit acpi_processor_driver_exit(void) cpuhp_remove_state_nocalls(hp_online); cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD); + acpi_processor_unregister_idle_driver(); driver_unregister(&acpi_processor_driver); } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d0fc045a8d310c..d8eb0b51518820 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1360,7 +1360,48 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr) return 0; } -static int acpi_processor_registered; +void acpi_processor_register_idle_driver(void) +{ + struct acpi_processor *pr; + int ret = -ENODEV; + int cpu; + + /* + * Acpi idle driver is used by all possible CPUs. + * Install the idle handler by the processor power info of one in them. + * Note that we use previously set idle handler will be used on + * platforms that only support C1. + */ + for_each_cpu(cpu, (struct cpumask *)cpu_possible_mask) { + pr = per_cpu(processors, cpu); + if (!pr) + continue; + + ret = acpi_processor_get_power_info(pr); + if (!ret) { + pr->flags.power_setup_done = 1; + acpi_processor_setup_cpuidle_states(pr); + break; + } + } + + if (ret) { + pr_debug("No ACPI power information from any CPUs.\n"); + return; + } + + ret = cpuidle_register_driver(&acpi_idle_driver); + if (ret) { + pr_debug("register %s failed.\n", acpi_idle_driver.name); + return; + } + pr_debug("%s registered with cpuidle.\n", acpi_idle_driver.name); +} + +void acpi_processor_unregister_idle_driver(void) +{ + cpuidle_unregister_driver(&acpi_idle_driver); +} int acpi_processor_power_init(struct acpi_processor *pr) { @@ -1375,22 +1416,7 @@ int acpi_processor_power_init(struct acpi_processor *pr) if (!acpi_processor_get_power_info(pr)) pr->flags.power_setup_done = 1; - /* - * Install the idle handler if processor power management is supported. - * Note that we use previously set idle handler will be used on - * platforms that only support C1. - */ if (pr->flags.power) { - /* Register acpi_idle_driver if not already registered */ - if (!acpi_processor_registered) { - acpi_processor_setup_cpuidle_states(pr); - retval = cpuidle_register_driver(&acpi_idle_driver); - if (retval) - return retval; - pr_debug("%s registered with cpuidle\n", - acpi_idle_driver.name); - } - dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1403,14 +1429,11 @@ int acpi_processor_power_init(struct acpi_processor *pr) */ retval = cpuidle_register_device(dev); if (retval) { - if (acpi_processor_registered == 0) - cpuidle_unregister_driver(&acpi_idle_driver); per_cpu(acpi_cpuidle_device, pr->id) = NULL; kfree(dev); return retval; } - acpi_processor_registered++; } return 0; } @@ -1424,10 +1447,6 @@ int acpi_processor_power_exit(struct acpi_processor *pr) if (pr->flags.power) { cpuidle_unregister_device(dev); - acpi_processor_registered--; - if (acpi_processor_registered == 0) - cpuidle_unregister_driver(&acpi_idle_driver); - kfree(dev); } diff --git a/include/acpi/processor.h b/include/acpi/processor.h index d0eccbd920e5ce..360b673f05e575 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -423,6 +423,8 @@ int acpi_processor_power_init(struct acpi_processor *pr); int acpi_processor_power_exit(struct acpi_processor *pr); int acpi_processor_power_state_has_changed(struct acpi_processor *pr); int acpi_processor_hotplug(struct acpi_processor *pr); +void acpi_processor_register_idle_driver(void); +void acpi_processor_unregister_idle_driver(void); #else static inline int acpi_processor_power_init(struct acpi_processor *pr) { @@ -443,6 +445,12 @@ static inline int acpi_processor_hotplug(struct acpi_processor *pr) { return -ENODEV; } +static inline void acpi_processor_register_idle_driver(void) +{ +} +static inline void acpi_processor_unregister_idle_driver(void) +{ +} #endif /* CONFIG_ACPI_PROCESSOR_IDLE */ /* in processor_thermal.c */ From eb58738d1546bababc77392968ece9c595b4f737 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Aug 2025 12:36:04 +0200 Subject: [PATCH 1083/1292] ACPI: processor: idle: Add module import namespace Add a new module import namespace called ACPI_PROCESSOR_IDLE for functions exported from the non-modular part of the ACPI processor driver to the modular part of it. Export acpi_processor_claim_cst_control() and acpi_processor_evaluate_cst() in that namespace to hide them from unrelated modules. They are also used by the intel_idle driver, but it is non-modular, so it can call them regardless of the way the symbols are exported. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3376499.aeNJFYEL58@rafael.j.wysocki --- drivers/acpi/acpi_processor.c | 4 ++-- drivers/acpi/processor_idle.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 2a99f5eb69629a..7ec1dc04fd11b9 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -815,7 +815,7 @@ bool acpi_processor_claim_cst_control(void) cst_control_claimed = true; return true; } -EXPORT_SYMBOL_GPL(acpi_processor_claim_cst_control); +EXPORT_SYMBOL_NS_GPL(acpi_processor_claim_cst_control, "ACPI_PROCESSOR_IDLE"); /** * acpi_processor_evaluate_cst - Evaluate the processor _CST control method. @@ -994,5 +994,5 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, return ret; } -EXPORT_SYMBOL_GPL(acpi_processor_evaluate_cst); +EXPORT_SYMBOL_NS_GPL(acpi_processor_evaluate_cst, "ACPI_PROCESSOR_IDLE"); #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d8eb0b51518820..0c8a88aa055331 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1453,3 +1453,5 @@ int acpi_processor_power_exit(struct acpi_processor *pr) pr->flags.power_setup_done = 0; return 0; } + +MODULE_IMPORT_NS("ACPI_PROCESSOR_IDLE"); From e4c628e91c6ab12f89500a023adfb030f737f3fd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Aug 2025 12:38:58 +0200 Subject: [PATCH 1084/1292] ACPI: processor: idle: Eliminate static variable flat_state_cnt Instead of using static variable flat_state_cnt to pass data between functions involved in the _LPI information processing, pass the current number of "flattened" idle states to flatten_lpi_states() and make it return the updated number of those states. At the same time, use a local variable called state_count to store the number of "flattened" idle states found so far in acpi_processor_get_lpi_info(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Sudeep Holla Tested-by: Sudeep Holla Acked-by: lihuisong@huawei.com Link: https://patch.msgid.link/10715991.nUPlyArG6x@rafael.j.wysocki --- drivers/acpi/processor_idle.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0c8a88aa055331..5dacf41d7cc0a0 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -998,11 +998,6 @@ static int acpi_processor_evaluate_lpi(acpi_handle handle, return ret; } -/* - * flat_state_cnt - the number of composite LPI states after the process of flattening - */ -static int flat_state_cnt; - /** * combine_lpi_states - combine local and parent LPI states to form a composite LPI state * @@ -1045,9 +1040,10 @@ static void stash_composite_state(struct acpi_lpi_states_array *curr_level, curr_level->composite_states[curr_level->composite_states_size++] = t; } -static int flatten_lpi_states(struct acpi_processor *pr, - struct acpi_lpi_states_array *curr_level, - struct acpi_lpi_states_array *prev_level) +static unsigned int flatten_lpi_states(struct acpi_processor *pr, + unsigned int flat_state_cnt, + struct acpi_lpi_states_array *curr_level, + struct acpi_lpi_states_array *prev_level) { int i, j, state_count = curr_level->size; struct acpi_lpi_state *p, *t = curr_level->entries; @@ -1087,7 +1083,7 @@ static int flatten_lpi_states(struct acpi_processor *pr, } kfree(curr_level->entries); - return 0; + return flat_state_cnt; } int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu) @@ -1102,6 +1098,7 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) acpi_handle handle = pr->handle, pr_ahandle; struct acpi_device *d = NULL; struct acpi_lpi_states_array info[2], *tmp, *prev, *curr; + unsigned int state_count; /* make sure our architecture has support */ ret = acpi_processor_ffh_lpi_probe(pr->id); @@ -1114,14 +1111,13 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) if (!acpi_has_method(handle, "_LPI")) return -EINVAL; - flat_state_cnt = 0; prev = &info[0]; curr = &info[1]; handle = pr->handle; ret = acpi_processor_evaluate_lpi(handle, prev); if (ret) return ret; - flatten_lpi_states(pr, prev, NULL); + state_count = flatten_lpi_states(pr, 0, prev, NULL); status = acpi_get_parent(handle, &pr_ahandle); while (ACPI_SUCCESS(status)) { @@ -1143,18 +1139,19 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) break; /* flatten all the LPI states in this level of hierarchy */ - flatten_lpi_states(pr, curr, prev); + state_count = flatten_lpi_states(pr, state_count, curr, prev); tmp = prev, prev = curr, curr = tmp; status = acpi_get_parent(handle, &pr_ahandle); } - pr->power.count = flat_state_cnt; /* reset the index after flattening */ - for (i = 0; i < pr->power.count; i++) + for (i = 0; i < state_count; i++) pr->power.lpi_states[i].index = i; + pr->power.count = state_count; + /* Tell driver that _LPI is supported. */ pr->flags.has_lpi = 1; pr->flags.power = 1; From 664596bd98bb251dd417dfd3f9b615b661e1e44a Mon Sep 17 00:00:00 2001 From: Chiasheng Lee Date: Mon, 1 Sep 2025 20:59:43 +0800 Subject: [PATCH 1085/1292] i2c: i801: Hide Intel Birch Stream SoC TCO WDT Hide the Intel Birch Stream SoC TCO WDT feature since it was removed. On platforms with PCH TCO WDT, this redundant device might be rendering errors like this: [ 28.144542] sysfs: cannot create duplicate filename '/bus/platform/devices/iTCO_wdt' Fixes: 8c56f9ef25a3 ("i2c: i801: Add support for Intel Birch Stream SoC") Link: https://bugzilla.kernel.org/show_bug.cgi?id=220320 Signed-off-by: Chiasheng Lee Cc: # v6.7+ Reviewed-by: Mika Westerberg Reviewed-by: Jarkko Nikula Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250901125943.916522-1-chiasheng.lee@linux.intel.com --- drivers/i2c/busses/i2c-i801.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index a7f89946dad418..e94ac746a741af 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1052,7 +1052,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5) }, { PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, From bdd5a14e660062114bdebaef9ad52adf04970a89 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 21 Aug 2025 14:23:41 +0200 Subject: [PATCH 1086/1292] drm/bridge: ti-sn65dsi86: fix REFCLK setting The bridge has three bootstrap pins which are sampled to determine the frequency of the external reference clock. The driver will also (over)write that setting. But it seems this is racy after the bridge is enabled. It was observed that although the driver write the correct value (by sniffing on the I2C bus), the register has the wrong value. The datasheet states that the GPIO lines have to be stable for at least 5us after asserting the EN signal. Thus, there seems to be some logic which samples the GPIO lines and this logic appears to overwrite the register value which was set by the driver. Waiting 20us after asserting the EN line resolves this issue. Fixes: a095f15c00e2 ("drm/bridge: add support for sn65dsi86 bridge driver") Signed-off-by: Michael Walle Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20250821122341.1257286-1-mwalle@kernel.org --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 464390372b341d..ae0d08e5e96004 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -392,6 +392,17 @@ static int __maybe_unused ti_sn65dsi86_resume(struct device *dev) gpiod_set_value_cansleep(pdata->enable_gpio, 1); + /* + * After EN is deasserted and an external clock is detected, the bridge + * will sample GPIO3:1 to determine its frequency. The driver will + * overwrite this setting in ti_sn_bridge_set_refclk_freq(). But this is + * racy. Thus we have to wait a couple of us. According to the datasheet + * the GPIO lines has to be stable at least 5 us (td5) but it seems that + * is not enough and the refclk frequency value is still lost or + * overwritten by the bridge itself. Waiting for 20us seems to work. + */ + usleep_range(20, 30); + /* * If we have a reference clock we can enable communication w/ the * panel (including the aux channel) w/out any need for an input clock From 403bf043d9340196e06769065169df7444b91f7a Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 7 Aug 2025 10:35:26 -0700 Subject: [PATCH 1087/1292] ice: fix NULL access of tx->in_use in ice_ptp_ts_irq The E810 device has support for a "low latency" firmware interface to access and read the Tx timestamps. This interface does not use the standard Tx timestamp logic, due to the latency overhead of proxying sideband command requests over the firmware AdminQ. The logic still makes use of the Tx timestamp tracking structure, ice_ptp_tx, as it uses the same "ready" bitmap to track which Tx timestamps complete. Unfortunately, the ice_ptp_ts_irq() function does not check if the tracker is initialized before its first access. This results in NULL dereference or use-after-free bugs similar to the following: [245977.278756] BUG: kernel NULL pointer dereference, address: 0000000000000000 [245977.278774] RIP: 0010:_find_first_bit+0x19/0x40 [245977.278796] Call Trace: [245977.278809] ? ice_misc_intr+0x364/0x380 [ice] This can occur if a Tx timestamp interrupt races with the driver reset logic. Fix this by only checking the in_use bitmap (and other fields) if the tracker is marked as initialized. The reset flow will clear the init field under lock before it tears the tracker down, thus preventing any use-after-free or NULL access. Fixes: f9472aaabd1f ("ice: Process TSYN IRQ in a separate function") Signed-off-by: Jacob Keller Reviewed-by: Paul Menzel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_ptp.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index e358eb1d719f75..fb0f6365a6d6f1 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2701,16 +2701,19 @@ irqreturn_t ice_ptp_ts_irq(struct ice_pf *pf) */ if (hw->dev_caps.ts_dev_info.ts_ll_int_read) { struct ice_ptp_tx *tx = &pf->ptp.port.tx; - u8 idx; + u8 idx, last; if (!ice_pf_state_is_nominal(pf)) return IRQ_HANDLED; spin_lock(&tx->lock); - idx = find_next_bit_wrap(tx->in_use, tx->len, - tx->last_ll_ts_idx_read + 1); - if (idx != tx->len) - ice_ptp_req_tx_single_tstamp(tx, idx); + if (tx->init) { + last = tx->last_ll_ts_idx_read + 1; + idx = find_next_bit_wrap(tx->in_use, tx->len, + last); + if (idx != tx->len) + ice_ptp_req_tx_single_tstamp(tx, idx); + } spin_unlock(&tx->lock); return IRQ_HANDLED; From f6486338fde3f04ed0ec59fe67a69a208c32734f Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 7 Aug 2025 10:35:27 -0700 Subject: [PATCH 1088/1292] ice: fix NULL access of tx->in_use in ice_ll_ts_intr Recent versions of the E810 firmware have support for an extra interrupt to handle report of the "low latency" Tx timestamps coming from the specialized low latency firmware interface. Instead of polling the registers, software can wait until the low latency interrupt is fired. This logic makes use of the Tx timestamp tracking structure, ice_ptp_tx, as it uses the same "ready" bitmap to track which Tx timestamps complete. Unfortunately, the ice_ll_ts_intr() function does not check if the tracker is initialized before its first access. This results in NULL dereference or use-after-free bugs similar to the issues fixed in the ice_ptp_ts_irq() function. Fix this by only checking the in_use bitmap (and other fields) if the tracker is marked as initialized. The reset flow will clear the init field under lock before it tears the tracker down, thus preventing any use-after-free or NULL access. Fixes: 82e71b226e0e ("ice: Enable SW interrupt from FW for LL TS") Signed-off-by: Jacob Keller Reviewed-by: Paul Menzel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index cae992d8f03ca5..77781277aa8e4c 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3176,12 +3176,14 @@ static irqreturn_t ice_ll_ts_intr(int __always_unused irq, void *data) hw = &pf->hw; tx = &pf->ptp.port.tx; spin_lock_irqsave(&tx->lock, flags); - ice_ptp_complete_tx_single_tstamp(tx); + if (tx->init) { + ice_ptp_complete_tx_single_tstamp(tx); - idx = find_next_bit_wrap(tx->in_use, tx->len, - tx->last_ll_ts_idx_read + 1); - if (idx != tx->len) - ice_ptp_req_tx_single_tstamp(tx, idx); + idx = find_next_bit_wrap(tx->in_use, tx->len, + tx->last_ll_ts_idx_read + 1); + if (idx != tx->len) + ice_ptp_req_tx_single_tstamp(tx, idx); + } spin_unlock_irqrestore(&tx->lock, flags); val = GLINT_DYN_CTL_INTENA_M | GLINT_DYN_CTL_CLEARPBA_M | From 65637c3a181184ae25bd10d37bc83f8bb97708b5 Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Mon, 11 Aug 2025 17:19:21 -0700 Subject: [PATCH 1089/1292] idpf: fix UAF in RDMA core aux dev deinitialization Free the adev->id before auxiliary_device_uninit. The call to uninit triggers the release callback, which frees the iadev memory containing the adev. The previous flow results in a UAF during rmmod due to the adev->id access. [264939.604077] ================================================================== [264939.604093] BUG: KASAN: slab-use-after-free in idpf_idc_deinit_core_aux_device+0xe4/0x100 [idpf] [264939.604134] Read of size 4 at addr ff1100109eb6eaf8 by task rmmod/17842 ... [264939.604635] Allocated by task 17597: [264939.604643] kasan_save_stack+0x20/0x40 [264939.604654] kasan_save_track+0x14/0x30 [264939.604663] __kasan_kmalloc+0x8f/0xa0 [264939.604672] idpf_idc_init_aux_core_dev+0x4bd/0xb60 [idpf] [264939.604700] idpf_idc_init+0x55/0xd0 [idpf] [264939.604726] process_one_work+0x658/0xfe0 [264939.604742] worker_thread+0x6e1/0xf10 [264939.604750] kthread+0x382/0x740 [264939.604762] ret_from_fork+0x23a/0x310 [264939.604772] ret_from_fork_asm+0x1a/0x30 [264939.604785] Freed by task 17842: [264939.604790] kasan_save_stack+0x20/0x40 [264939.604799] kasan_save_track+0x14/0x30 [264939.604808] kasan_save_free_info+0x3b/0x60 [264939.604820] __kasan_slab_free+0x37/0x50 [264939.604830] kfree+0xf1/0x420 [264939.604840] device_release+0x9c/0x210 [264939.604850] kobject_put+0x17c/0x4b0 [264939.604860] idpf_idc_deinit_core_aux_device+0x4f/0x100 [idpf] [264939.604886] idpf_vc_core_deinit+0xba/0x3a0 [idpf] [264939.604915] idpf_remove+0xb0/0x7c0 [idpf] [264939.604944] pci_device_remove+0xab/0x1e0 [264939.604955] device_release_driver_internal+0x371/0x530 [264939.604969] driver_detach+0xbf/0x180 [264939.604981] bus_remove_driver+0x11b/0x2a0 [264939.604991] pci_unregister_driver+0x2a/0x250 [264939.605005] __do_sys_delete_module.constprop.0+0x2eb/0x540 [264939.605014] do_syscall_64+0x64/0x2c0 [264939.605024] entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: f4312e6bfa2a ("idpf: implement core RDMA auxiliary dev create, init, and destroy") Signed-off-by: Joshua Hay Reviewed-by: Aleksandr Loktionov Reviewed-by: Vadim Fedorenko Tested-by: Samuel Salin Reviewed-by: Jacob Keller Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_idc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c index 4d29051032153f..7e20a07e98e538 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_idc.c +++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c @@ -247,10 +247,10 @@ static void idpf_unplug_aux_dev(struct auxiliary_device *adev) if (!adev) return; + ida_free(&idpf_idc_ida, adev->id); + auxiliary_device_delete(adev); auxiliary_device_uninit(adev); - - ida_free(&idpf_idc_ida, adev->id); } /** From acf3a5c8be80fe238c1a7629db1c21c74a1f9dd4 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 14 Aug 2025 16:43:00 -0700 Subject: [PATCH 1090/1292] idpf: set mac type when adding and removing MAC filters On control planes that allow changing the MAC address of the interface, the driver must provide a MAC type to avoid errors such as: idpf 0000:0a:00.0: Transaction failed (op 535) idpf 0000:0a:00.0: Received invalid MAC filter payload (op 535) (len 0) idpf 0000:0a:00.0: Transaction failed (op 536) These errors occur during driver load or when changing the MAC via: ip link set address Add logic to set the MAC type when sending ADD/DEL (opcodes 535/536) to the control plane. Since only one primary MAC is supported per vport, the driver only needs to send an ADD opcode when setting it. Remove the old address by calling __idpf_del_mac_filter(), which skips the message and just clears the entry from the internal list. This avoids an error on DEL as it attempts to remove an address already cleared by the preceding ADD opcode. Fixes: ce1b75d0635c ("idpf: add ptypes and MAC filter support") Reported-by: Jian Liu Signed-off-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Reviewed-by: Paul Menzel Reviewed-by: Simon Horman Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 9 ++++++--- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 12 ++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 2c2a3e85d69301..513032cb5f0882 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -2344,6 +2344,7 @@ static int idpf_set_mac(struct net_device *netdev, void *p) struct idpf_netdev_priv *np = netdev_priv(netdev); struct idpf_vport_config *vport_config; struct sockaddr *addr = p; + u8 old_mac_addr[ETH_ALEN]; struct idpf_vport *vport; int err = 0; @@ -2367,17 +2368,19 @@ static int idpf_set_mac(struct net_device *netdev, void *p) if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) goto unlock_mutex; + ether_addr_copy(old_mac_addr, vport->default_mac_addr); + ether_addr_copy(vport->default_mac_addr, addr->sa_data); vport_config = vport->adapter->vport_config[vport->idx]; err = idpf_add_mac_filter(vport, np, addr->sa_data, false); if (err) { __idpf_del_mac_filter(vport_config, addr->sa_data); + ether_addr_copy(vport->default_mac_addr, netdev->dev_addr); goto unlock_mutex; } - if (is_valid_ether_addr(vport->default_mac_addr)) - idpf_del_mac_filter(vport, np, vport->default_mac_addr, false); + if (is_valid_ether_addr(old_mac_addr)) + __idpf_del_mac_filter(vport_config, old_mac_addr); - ether_addr_copy(vport->default_mac_addr, addr->sa_data); eth_hw_addr_set(netdev, addr->sa_data); unlock_mutex: diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index a028c69f7fdccd..6330d4a0ae075d 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -3765,6 +3765,16 @@ u32 idpf_get_vport_id(struct idpf_vport *vport) return le32_to_cpu(vport_msg->vport_id); } +static void idpf_set_mac_type(struct idpf_vport *vport, + struct virtchnl2_mac_addr *mac_addr) +{ + bool is_primary; + + is_primary = ether_addr_equal(vport->default_mac_addr, mac_addr->addr); + mac_addr->type = is_primary ? VIRTCHNL2_MAC_ADDR_PRIMARY : + VIRTCHNL2_MAC_ADDR_EXTRA; +} + /** * idpf_mac_filter_async_handler - Async callback for mac filters * @adapter: private data struct @@ -3894,6 +3904,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, list) { if (add && f->add) { ether_addr_copy(mac_addr[i].addr, f->macaddr); + idpf_set_mac_type(vport, &mac_addr[i]); i++; f->add = false; if (i == total_filters) @@ -3901,6 +3912,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport, } if (!add && f->remove) { ether_addr_copy(mac_addr[i].addr, f->macaddr); + idpf_set_mac_type(vport, &mac_addr[i]); i++; f->remove = false; if (i == total_filters) From 9fcdb1c3c4ba134434694c001dbff343f1ffa319 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 22 Jul 2025 17:14:37 -0700 Subject: [PATCH 1091/1292] i40e: remove read access to debugfs files The 'command' and 'netdev_ops' debugfs files are a legacy debugging interface supported by the i40e driver since its early days by commit 02e9c290814c ("i40e: debugfs interface"). Both of these debugfs files provide a read handler which is mostly useless, and which is implemented with questionable logic. They both use a static 256 byte buffer which is initialized to the empty string. In the case of the 'command' file this buffer is literally never used and simply wastes space. In the case of the 'netdev_ops' file, the last command written is saved here. On read, the files contents are presented as the name of the device followed by a colon and then the contents of their respective static buffer. For 'command' this will always be ": ". For 'netdev_ops', this will be ": ". But note the buffer is shared between all devices operated by this module. At best, it is mostly meaningless information, and at worse it could be accessed simultaneously as there doesn't appear to be any locking mechanism. We have also recently received multiple reports for both read functions about their use of snprintf and potential overflow that could result in reading arbitrary kernel memory. For the 'command' file, this is definitely impossible, since the static buffer is always zero and never written to. For the 'netdev_ops' file, it does appear to be possible, if the user carefully crafts the command input, it will be copied into the buffer, which could be large enough to cause snprintf to truncate, which then causes the copy_to_user to read beyond the length of the buffer allocated by kzalloc. A minimal fix would be to replace snprintf() with scnprintf() which would cap the return to the number of bytes written, preventing an overflow. A more involved fix would be to drop the mostly useless static buffers, saving 512 bytes and modifying the read functions to stop needing those as input. Instead, lets just completely drop the read access to these files. These are debug interfaces exposed as part of debugfs, and I don't believe that dropping read access will break any script, as the provided output is pretty useless. You can find the netdev name through other more standard interfaces, and the 'netdev_ops' interface can easily result in garbage if you issue simultaneous writes to multiple devices at once. In order to properly remove the i40e_dbg_netdev_ops_buf, we need to refactor its write function to avoid using the static buffer. Instead, use the same logic as the i40e_dbg_command_write, with an allocated buffer. Update the code to use this instead of the static buffer, and ensure we free the buffer on exit. This fixes simultaneous writes to 'netdev_ops' on multiple devices, and allows us to remove the now unused static buffer along with removing the read access. Fixes: 02e9c290814c ("i40e: debugfs interface") Reported-by: Kunwu Chan Closes: https://lore.kernel.org/intel-wired-lan/20231208031950.47410-1-chentao@kylinos.cn/ Reported-by: Wang Haoran Closes: https://lore.kernel.org/all/CANZ3JQRRiOdtfQJoP9QM=6LS1Jto8PGBGw6y7-TL=BcnzHQn1Q@mail.gmail.com/ Reported-by: Amir Mohammad Jahangirzad Closes: https://lore.kernel.org/all/20250722115017.206969-1-a.jahangirzad@gmail.com/ Signed-off-by: Jacob Keller Reviewed-by: Dawid Osuchowski Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Reviewed-by: Kunwu Chan Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- .../net/ethernet/intel/i40e/i40e_debugfs.c | 123 +++--------------- 1 file changed, 19 insertions(+), 104 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 6cd6f23d42a6e6..c17b5d290f0a20 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -40,48 +40,6 @@ static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid) * setup, adding or removing filters, or other things. Many of * these will be useful for some forms of unit testing. **************************************************************/ -static char i40e_dbg_command_buf[256] = ""; - -/** - * i40e_dbg_command_read - read for command datum - * @filp: the opened file - * @buffer: where to write the data for the user to read - * @count: the size of the user's buffer - * @ppos: file position offset - **/ -static ssize_t i40e_dbg_command_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct i40e_pf *pf = filp->private_data; - struct i40e_vsi *main_vsi; - int bytes_not_copied; - int buf_size = 256; - char *buf; - int len; - - /* don't allow partial reads */ - if (*ppos != 0) - return 0; - if (count < buf_size) - return -ENOSPC; - - buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOSPC; - - main_vsi = i40e_pf_get_main_vsi(pf); - len = snprintf(buf, buf_size, "%s: %s\n", main_vsi->netdev->name, - i40e_dbg_command_buf); - - bytes_not_copied = copy_to_user(buffer, buf, len); - kfree(buf); - - if (bytes_not_copied) - return -EFAULT; - - *ppos = len; - return len; -} static char *i40e_filter_state_string[] = { "INVALID", @@ -1621,7 +1579,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp, static const struct file_operations i40e_dbg_command_fops = { .owner = THIS_MODULE, .open = simple_open, - .read = i40e_dbg_command_read, .write = i40e_dbg_command_write, }; @@ -1630,48 +1587,6 @@ static const struct file_operations i40e_dbg_command_fops = { * The netdev_ops entry in debugfs is for giving the driver commands * to be executed from the netdev operations. **************************************************************/ -static char i40e_dbg_netdev_ops_buf[256] = ""; - -/** - * i40e_dbg_netdev_ops_read - read for netdev_ops datum - * @filp: the opened file - * @buffer: where to write the data for the user to read - * @count: the size of the user's buffer - * @ppos: file position offset - **/ -static ssize_t i40e_dbg_netdev_ops_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct i40e_pf *pf = filp->private_data; - struct i40e_vsi *main_vsi; - int bytes_not_copied; - int buf_size = 256; - char *buf; - int len; - - /* don't allow partal reads */ - if (*ppos != 0) - return 0; - if (count < buf_size) - return -ENOSPC; - - buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOSPC; - - main_vsi = i40e_pf_get_main_vsi(pf); - len = snprintf(buf, buf_size, "%s: %s\n", main_vsi->netdev->name, - i40e_dbg_netdev_ops_buf); - - bytes_not_copied = copy_to_user(buffer, buf, len); - kfree(buf); - - if (bytes_not_copied) - return -EFAULT; - - *ppos = len; - return len; -} /** * i40e_dbg_netdev_ops_write - write into netdev_ops datum @@ -1685,35 +1600,36 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp, size_t count, loff_t *ppos) { struct i40e_pf *pf = filp->private_data; + char *cmd_buf, *buf_tmp; int bytes_not_copied; struct i40e_vsi *vsi; - char *buf_tmp; int vsi_seid; int i, cnt; /* don't allow partial writes */ if (*ppos != 0) return 0; - if (count >= sizeof(i40e_dbg_netdev_ops_buf)) - return -ENOSPC; - memset(i40e_dbg_netdev_ops_buf, 0, sizeof(i40e_dbg_netdev_ops_buf)); - bytes_not_copied = copy_from_user(i40e_dbg_netdev_ops_buf, - buffer, count); - if (bytes_not_copied) + cmd_buf = kzalloc(count + 1, GFP_KERNEL); + if (!cmd_buf) + return count; + bytes_not_copied = copy_from_user(cmd_buf, buffer, count); + if (bytes_not_copied) { + kfree(cmd_buf); return -EFAULT; - i40e_dbg_netdev_ops_buf[count] = '\0'; + } + cmd_buf[count] = '\0'; - buf_tmp = strchr(i40e_dbg_netdev_ops_buf, '\n'); + buf_tmp = strchr(cmd_buf, '\n'); if (buf_tmp) { *buf_tmp = '\0'; - count = buf_tmp - i40e_dbg_netdev_ops_buf + 1; + count = buf_tmp - cmd_buf + 1; } - if (strncmp(i40e_dbg_netdev_ops_buf, "change_mtu", 10) == 0) { + if (strncmp(cmd_buf, "change_mtu", 10) == 0) { int mtu; - cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i %i", + cnt = sscanf(&cmd_buf[11], "%i %i", &vsi_seid, &mtu); if (cnt != 2) { dev_info(&pf->pdev->dev, "change_mtu \n"); @@ -1735,8 +1651,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp, dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n"); } - } else if (strncmp(i40e_dbg_netdev_ops_buf, "set_rx_mode", 11) == 0) { - cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i", &vsi_seid); + } else if (strncmp(cmd_buf, "set_rx_mode", 11) == 0) { + cnt = sscanf(&cmd_buf[11], "%i", &vsi_seid); if (cnt != 1) { dev_info(&pf->pdev->dev, "set_rx_mode \n"); goto netdev_ops_write_done; @@ -1756,8 +1672,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp, dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n"); } - } else if (strncmp(i40e_dbg_netdev_ops_buf, "napi", 4) == 0) { - cnt = sscanf(&i40e_dbg_netdev_ops_buf[4], "%i", &vsi_seid); + } else if (strncmp(cmd_buf, "napi", 4) == 0) { + cnt = sscanf(&cmd_buf[4], "%i", &vsi_seid); if (cnt != 1) { dev_info(&pf->pdev->dev, "napi \n"); goto netdev_ops_write_done; @@ -1775,21 +1691,20 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp, dev_info(&pf->pdev->dev, "napi called\n"); } } else { - dev_info(&pf->pdev->dev, "unknown command '%s'\n", - i40e_dbg_netdev_ops_buf); + dev_info(&pf->pdev->dev, "unknown command '%s'\n", cmd_buf); dev_info(&pf->pdev->dev, "available commands\n"); dev_info(&pf->pdev->dev, " change_mtu \n"); dev_info(&pf->pdev->dev, " set_rx_mode \n"); dev_info(&pf->pdev->dev, " napi \n"); } netdev_ops_write_done: + kfree(cmd_buf); return count; } static const struct file_operations i40e_dbg_netdev_ops_fops = { .owner = THIS_MODULE, .open = simple_open, - .read = i40e_dbg_netdev_ops_read, .write = i40e_dbg_netdev_ops_write, }; From a556f06338e1d5a85af0e32ecb46e365547f92b9 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Wed, 27 Aug 2025 19:56:31 +0800 Subject: [PATCH 1092/1292] i40e: Fix potential invalid access when MAC list is empty list_first_entry() never returns NULL - if the list is empty, it still returns a pointer to an invalid object, leading to potential invalid memory access when dereferenced. Fix this by using list_first_entry_or_null instead of list_first_entry. Fixes: e3219ce6a775 ("i40e: Add support for client interface for IWARP driver") Signed-off-by: Zhen Ni Reviewed-by: Paul Menzel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c index 5f1a405cbbf8a1..518bc738ea3bec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_client.c +++ b/drivers/net/ethernet/intel/i40e/i40e_client.c @@ -359,8 +359,8 @@ static void i40e_client_add_instance(struct i40e_pf *pf) if (i40e_client_get_params(vsi, &cdev->lan_info.params)) goto free_cdev; - mac = list_first_entry(&cdev->lan_info.netdev->dev_addrs.list, - struct netdev_hw_addr, list); + mac = list_first_entry_or_null(&cdev->lan_info.netdev->dev_addrs.list, + struct netdev_hw_addr, list); if (mac) ether_addr_copy(cdev->lan_info.lanmac, mac->addr); else From b7e5c3e3bfa9dc8af75ff6d8633ad7070e1985e4 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Sun, 10 Aug 2025 10:01:14 -0700 Subject: [PATCH 1093/1292] ixgbe: fix incorrect map used in eee linkmode incorrectly used ixgbe_lp_map in loops intended to populate the supported and advertised EEE linkmode bitmaps based on ixgbe_ls_map. This results in incorrect bit setting and potential out-of-bounds access, since ixgbe_lp_map and ixgbe_ls_map have different sizes and purposes. ixgbe_lp_map[i] -> ixgbe_ls_map[i] Use ixgbe_ls_map for supported and advertised linkmodes, and keep ixgbe_lp_map usage only for link partner (lp_advertised) mapping. Fixes: 9356b6db9d05 ("net: ethernet: ixgbe: Convert EEE to use linkmodes") Signed-off-by: Alok Tiwari Reviewed-by: Aleksandr Loktionov Reviewed-by: Paul Menzel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 25c3a09ad7f1c8..1a2f1bdb91aa3a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -3571,13 +3571,13 @@ ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata) for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed) - linkmode_set_bit(ixgbe_lp_map[i].link_mode, + linkmode_set_bit(ixgbe_ls_map[i].link_mode, edata->supported); } for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed) - linkmode_set_bit(ixgbe_lp_map[i].link_mode, + linkmode_set_bit(ixgbe_ls_map[i].link_mode, edata->advertised); } From 90fb7db49c6dbac961c6b8ebfd741141ffbc8545 Mon Sep 17 00:00:00 2001 From: Vitaly Lifshits Date: Sun, 17 Aug 2025 12:25:47 +0300 Subject: [PATCH 1094/1292] e1000e: fix heap overflow in e1000_set_eeprom Fix a possible heap overflow in e1000_set_eeprom function by adding input validation for the requested length of the change in the EEPROM. In addition, change the variable type from int to size_t for better code practices and rearrange declarations to RCT. Cc: stable@vger.kernel.org Fixes: bc7f75fa9788 ("[E1000E]: New pci-express e1000 driver (currently for ICH9 devices only)") Co-developed-by: Mikael Wessel Signed-off-by: Mikael Wessel Signed-off-by: Vitaly Lifshits Tested-by: Mor Bar-Gabay Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/e1000e/ethtool.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index c0bbb12eed2e97..cf01a108a5bb21 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -549,12 +549,12 @@ static int e1000_set_eeprom(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + size_t total_len, max_len; u16 *eeprom_buff; - void *ptr; - int max_len; + int ret_val = 0; int first_word; int last_word; - int ret_val = 0; + void *ptr; u16 i; if (eeprom->len == 0) @@ -569,6 +569,10 @@ static int e1000_set_eeprom(struct net_device *netdev, max_len = hw->nvm.word_size * 2; + if (check_add_overflow(eeprom->offset, eeprom->len, &total_len) || + total_len > max_len) + return -EFBIG; + first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(max_len, GFP_KERNEL); From 7ac3c2889bc060c3f67cf44df0dbb093a835c176 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 25 Aug 2025 15:32:49 +0200 Subject: [PATCH 1095/1292] nvme: fix PI insert on write I recently ran into an issue where the PI generated using the block layer integrity code differs from that from a kernel using the PRACT fallback when the block layer integrity code is disabled, and I tracked this down to us using PRACT incorrectly. The NVM Command Set Specification (section 5.33 in 1.2, similar in older versions) specifies the PRACT insert behavior as: Inserted protection information consists of the computed CRC for the protection information format (refer to section 5.3.1) in the Guard field, the LBAT field value in the Application Tag field, the LBST field value in the Storage Tag field, if defined, and the computed reference tag in the Logical Block Reference Tag. Where the computed reference tag is defined as following for type 1 and type 2 using the text below that is duplicated in the respective bullet points: the value of the computed reference tag for the first logical block of the command is the value contained in the Initial Logical Block Reference Tag (ILBRT) or Expected Initial Logical Block Reference Tag (EILBRT) field in the command, and the computed reference tag is incremented for each subsequent logical block. So we need to set ILBRT field, but we currently don't. Interestingly this works fine on my older type 1 formatted SSD, but Qemu trips up on this. We already set ILBRT for Write Same since commit aeb7bb061be5 ("nvme: set the PRACT bit when using Write Zeroes with T10 PI"). To ease this, move the PI type check into nvme_set_ref_tag. Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig Signed-off-by: Keith Busch --- drivers/nvme/host/core.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 812c1565114fde..6b7493934535a7 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -903,6 +903,15 @@ static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd, u32 upper, lower; u64 ref48; + /* only type1 and type 2 PI formats have a reftag */ + switch (ns->head->pi_type) { + case NVME_NS_DPS_PI_TYPE1: + case NVME_NS_DPS_PI_TYPE2: + break; + default: + return; + } + /* both rw and write zeroes share the same reftag format */ switch (ns->head->guard_type) { case NVME_NVM_NS_16B_GUARD: @@ -942,13 +951,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns, if (nvme_ns_has_pi(ns->head)) { cmnd->write_zeroes.control |= cpu_to_le16(NVME_RW_PRINFO_PRACT); - - switch (ns->head->pi_type) { - case NVME_NS_DPS_PI_TYPE1: - case NVME_NS_DPS_PI_TYPE2: - nvme_set_ref_tag(ns, cmnd, req); - break; - } + nvme_set_ref_tag(ns, cmnd, req); } return BLK_STS_OK; @@ -1039,6 +1042,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, if (WARN_ON_ONCE(!nvme_ns_has_pi(ns->head))) return BLK_STS_NOTSUPP; control |= NVME_RW_PRINFO_PRACT; + nvme_set_ref_tag(ns, cmnd, req); } if (bio_integrity_flagged(req->bio, BIP_CHECK_GUARD)) From ddbf0e78a8b20ec18d314d31336a0230fdc9b394 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Sun, 31 Aug 2025 12:59:07 +0200 Subject: [PATCH 1096/1292] net: sfp: add quirk for FLYPRO copper SFP+ module Add quirk for a copper SFP that identifies itself as "FLYPRO" "SFP-10GT-CS-30M". It uses RollBall protocol to talk to the PHY. Signed-off-by: Aleksander Jan Bajkowski Reviewed-by: Russell King (Oracle) Link: https://patch.msgid.link/20250831105910.3174-1-olek2@wp.pl Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 5347c95d1e772b..4cd1d6c51dc2a0 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -492,6 +492,9 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex, sfp_fixup_nokia), + // FLYPRO SFP-10GT-CS-30M uses Rollball protocol to talk to the PHY. + SFP_QUIRK_F("FLYPRO", "SFP-10GT-CS-30M", sfp_fixup_rollball), + // Fiberstore SFP-10G-T doesn't identify as copper, uses the Rollball // protocol to talk to the PHY and needs 4 sec wait before probing the // PHY. From d7b67dd6f9db7bd2c49b415e901849b182ff0735 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 2 Sep 2025 11:17:11 -0700 Subject: [PATCH 1097/1292] perf bpf-event: Fix use-after-free in synthesis Calls to perf_env__insert_bpf_prog_info may fail as a sideband thread may already have inserted the bpf_prog_info. Such failures may yield info_linear being freed which then causes use-after-free issues with the internal bpf_prog_info info struct. Make it so that perf_env__insert_bpf_prog_info trigger early non-error paths and fix the use-after-free in perf_event__synthesize_one_bpf_prog. Add proper return error handling to perf_env__add_bpf_info (that calls perf_env__insert_bpf_prog_info) and propagate the return value in its callers. Closes: https://lore.kernel.org/lkml/CAP-5=fWJQcmUOP7MuCA2ihKnDAHUCOBLkQFEkQES-1ZZTrgf8Q@mail.gmail.com/ Fixes: 03edb7020bb9 ("perf bpf: Fix two memory leakages when calling perf_env__insert_bpf_prog_info()") Reviewed-by: Namhyung Kim Signed-off-by: Ian Rogers Link: https://lore.kernel.org/r/20250902181713.309797-2-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/util/bpf-event.c | 39 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 5b6d3e899e1159..2298cd396c4235 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -657,9 +657,15 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, info_node->info_linear = info_linear; info_node->metadata = NULL; if (!perf_env__insert_bpf_prog_info(env, info_node)) { - free(info_linear); + /* + * Insert failed, likely because of a duplicate event + * made by the sideband thread. Ignore synthesizing the + * metadata. + */ free(info_node); + goto out; } + /* info_linear is now owned by info_node and shouldn't be freed below. */ info_linear = NULL; /* @@ -827,18 +833,18 @@ int perf_event__synthesize_bpf_events(struct perf_session *session, return err; } -static void perf_env__add_bpf_info(struct perf_env *env, u32 id) +static int perf_env__add_bpf_info(struct perf_env *env, u32 id) { struct bpf_prog_info_node *info_node; struct perf_bpil *info_linear; struct btf *btf = NULL; u64 arrays; u32 btf_id; - int fd; + int fd, err = 0; fd = bpf_prog_get_fd_by_id(id); if (fd < 0) - return; + return -EINVAL; arrays = 1UL << PERF_BPIL_JITED_KSYMS; arrays |= 1UL << PERF_BPIL_JITED_FUNC_LENS; @@ -852,6 +858,7 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id) info_linear = get_bpf_prog_info_linear(fd, arrays); if (IS_ERR_OR_NULL(info_linear)) { pr_debug("%s: failed to get BPF program info. aborting\n", __func__); + err = PTR_ERR(info_linear); goto out; } @@ -862,38 +869,46 @@ static void perf_env__add_bpf_info(struct perf_env *env, u32 id) info_node->info_linear = info_linear; info_node->metadata = bpf_metadata_create(&info_linear->info); if (!perf_env__insert_bpf_prog_info(env, info_node)) { + pr_debug("%s: duplicate add bpf info request for id %u\n", + __func__, btf_id); free(info_linear); free(info_node); + goto out; } - } else + } else { free(info_linear); + err = -ENOMEM; + goto out; + } if (btf_id == 0) goto out; btf = btf__load_from_kernel_by_id(btf_id); - if (libbpf_get_error(btf)) { - pr_debug("%s: failed to get BTF of id %u, aborting\n", - __func__, btf_id); - goto out; + if (!btf) { + err = -errno; + pr_debug("%s: failed to get BTF of id %u %d\n", __func__, btf_id, err); + } else { + perf_env__fetch_btf(env, btf_id, btf); } - perf_env__fetch_btf(env, btf_id, btf); out: btf__free(btf); close(fd); + return err; } static int bpf_event__sb_cb(union perf_event *event, void *data) { struct perf_env *env = data; + int ret = 0; if (event->header.type != PERF_RECORD_BPF_EVENT) return -1; switch (event->bpf.type) { case PERF_BPF_EVENT_PROG_LOAD: - perf_env__add_bpf_info(env, event->bpf.id); + ret = perf_env__add_bpf_info(env, event->bpf.id); case PERF_BPF_EVENT_PROG_UNLOAD: /* @@ -907,7 +922,7 @@ static int bpf_event__sb_cb(union perf_event *event, void *data) break; } - return 0; + return ret; } int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env) From 1654a0e4d576d9e43fbb10ccf6a1b307c5c18566 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 2 Sep 2025 11:17:12 -0700 Subject: [PATCH 1098/1292] perf bpf-utils: Constify bpil_array_desc The array's contents is a compile time constant. Constify to make the code more intention revealing and avoid unintended errors. Reviewed-by: Namhyung Kim Signed-off-by: Ian Rogers Link: https://lore.kernel.org/r/20250902181713.309797-3-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/util/bpf-utils.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/bpf-utils.c b/tools/perf/util/bpf-utils.c index 80b1d2b3729ba4..64a55834469645 100644 --- a/tools/perf/util/bpf-utils.c +++ b/tools/perf/util/bpf-utils.c @@ -20,7 +20,7 @@ struct bpil_array_desc { */ }; -static struct bpil_array_desc bpil_array_desc[] = { +static const struct bpil_array_desc bpil_array_desc[] = { [PERF_BPIL_JITED_INSNS] = { offsetof(struct bpf_prog_info, jited_prog_insns), offsetof(struct bpf_prog_info, jited_prog_len), @@ -129,12 +129,10 @@ get_bpf_prog_info_linear(int fd, __u64 arrays) /* step 2: calculate total size of all arrays */ for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { + const struct bpil_array_desc *desc = &bpil_array_desc[i]; bool include_array = (arrays & (1UL << i)) > 0; - struct bpil_array_desc *desc; __u32 count, size; - desc = bpil_array_desc + i; - /* kernel is too old to support this field */ if (info_len < desc->array_offset + sizeof(__u32) || info_len < desc->count_offset + sizeof(__u32) || @@ -163,13 +161,12 @@ get_bpf_prog_info_linear(int fd, __u64 arrays) ptr = info_linear->data; for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { - struct bpil_array_desc *desc; + const struct bpil_array_desc *desc = &bpil_array_desc[i]; __u32 count, size; if ((arrays & (1UL << i)) == 0) continue; - desc = bpil_array_desc + i; count = bpf_prog_info_read_offset_u32(&info, desc->count_offset); size = bpf_prog_info_read_offset_u32(&info, desc->size_offset); bpf_prog_info_set_offset_u32(&info_linear->info, @@ -192,13 +189,12 @@ get_bpf_prog_info_linear(int fd, __u64 arrays) /* step 6: verify the data */ for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { - struct bpil_array_desc *desc; + const struct bpil_array_desc *desc = &bpil_array_desc[i]; __u32 v1, v2; if ((arrays & (1UL << i)) == 0) continue; - desc = bpil_array_desc + i; v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset); v2 = bpf_prog_info_read_offset_u32(&info_linear->info, desc->count_offset); @@ -224,13 +220,12 @@ void bpil_addr_to_offs(struct perf_bpil *info_linear) int i; for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { - struct bpil_array_desc *desc; + const struct bpil_array_desc *desc = &bpil_array_desc[i]; __u64 addr, offs; if ((info_linear->arrays & (1UL << i)) == 0) continue; - desc = bpil_array_desc + i; addr = bpf_prog_info_read_offset_u64(&info_linear->info, desc->array_offset); offs = addr - ptr_to_u64(info_linear->data); @@ -244,13 +239,12 @@ void bpil_offs_to_addr(struct perf_bpil *info_linear) int i; for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { - struct bpil_array_desc *desc; + const struct bpil_array_desc *desc = &bpil_array_desc[i]; __u64 addr, offs; if ((info_linear->arrays & (1UL << i)) == 0) continue; - desc = bpil_array_desc + i; offs = bpf_prog_info_read_offset_u64(&info_linear->info, desc->array_offset); addr = offs + ptr_to_u64(info_linear->data); From 01be43f2a0eaeed83e94dee054742f37625c86d9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 2 Sep 2025 11:17:13 -0700 Subject: [PATCH 1099/1292] perf bpf-utils: Harden get_bpf_prog_info_linear In get_bpf_prog_info_linear two calls to bpf_obj_get_info_by_fd are made, the first to compute memory requirements for a struct perf_bpil and the second to fill it in. Previously the code would warn when the second call didn't match the first. Such races can be common place in things like perf test, whose perf trace tests will frequently load BPF programs. Rather than a debug message, return actual errors for this case. Out of paranoia also validate the read bpf_prog_info array value. Change the type of ptr to avoid mismatched pointer type compiler warnings. Add some additional debug print outs and sanity asserts. Closes: https://lore.kernel.org/lkml/CAP-5=fWJQcmUOP7MuCA2ihKnDAHUCOBLkQFEkQES-1ZZTrgf8Q@mail.gmail.com/ Fixes: 6ac22d036f86 ("perf bpf: Pull in bpf_program__get_prog_info_linear()") Reviewed-by: Namhyung Kim Signed-off-by: Ian Rogers Link: https://lore.kernel.org/r/20250902181713.309797-4-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/util/bpf-utils.c | 43 ++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/bpf-utils.c b/tools/perf/util/bpf-utils.c index 64a55834469645..5a66dc8594aa88 100644 --- a/tools/perf/util/bpf-utils.c +++ b/tools/perf/util/bpf-utils.c @@ -115,7 +115,7 @@ get_bpf_prog_info_linear(int fd, __u64 arrays) __u32 info_len = sizeof(info); __u32 data_len = 0; int i, err; - void *ptr; + __u8 *ptr; if (arrays >> PERF_BPIL_LAST_ARRAY) return ERR_PTR(-EINVAL); @@ -126,6 +126,8 @@ get_bpf_prog_info_linear(int fd, __u64 arrays) pr_debug("can't get prog info: %s", strerror(errno)); return ERR_PTR(-EFAULT); } + if (info.type >= __MAX_BPF_PROG_TYPE) + pr_debug("%s:%d: unexpected program type %u\n", __func__, __LINE__, info.type); /* step 2: calculate total size of all arrays */ for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { @@ -173,6 +175,8 @@ get_bpf_prog_info_linear(int fd, __u64 arrays) desc->count_offset, count); bpf_prog_info_set_offset_u32(&info_linear->info, desc->size_offset, size); + assert(ptr >= info_linear->data); + assert(ptr < &info_linear->data[data_len]); bpf_prog_info_set_offset_u64(&info_linear->info, desc->array_offset, ptr_to_u64(ptr)); @@ -186,26 +190,45 @@ get_bpf_prog_info_linear(int fd, __u64 arrays) free(info_linear); return ERR_PTR(-EFAULT); } + if (info_linear->info.type >= __MAX_BPF_PROG_TYPE) { + pr_debug("%s:%d: unexpected program type %u\n", + __func__, __LINE__, info_linear->info.type); + } /* step 6: verify the data */ + ptr = info_linear->data; for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) { const struct bpil_array_desc *desc = &bpil_array_desc[i]; - __u32 v1, v2; + __u32 count1, count2, size1, size2; + __u64 ptr2; if ((arrays & (1UL << i)) == 0) continue; - v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset); - v2 = bpf_prog_info_read_offset_u32(&info_linear->info, + count1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset); + count2 = bpf_prog_info_read_offset_u32(&info_linear->info, desc->count_offset); - if (v1 != v2) - pr_warning("%s: mismatch in element count\n", __func__); + if (count1 != count2) { + pr_warning("%s: mismatch in element count %u vs %u\n", __func__, count1, count2); + free(info_linear); + return ERR_PTR(-ERANGE); + } - v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset); - v2 = bpf_prog_info_read_offset_u32(&info_linear->info, + size1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset); + size2 = bpf_prog_info_read_offset_u32(&info_linear->info, desc->size_offset); - if (v1 != v2) - pr_warning("%s: mismatch in rec size\n", __func__); + if (size1 != size2) { + pr_warning("%s: mismatch in rec size %u vs %u\n", __func__, size1, size2); + free(info_linear); + return ERR_PTR(-ERANGE); + } + ptr2 = bpf_prog_info_read_offset_u64(&info_linear->info, desc->array_offset); + if (ptr_to_u64(ptr) != ptr2) { + pr_warning("%s: mismatch in array %p vs %llx\n", __func__, ptr, ptr2); + free(info_linear); + return ERR_PTR(-ERANGE); + } + ptr += roundup(count1 * size1, sizeof(__u64)); } /* step 7: update info_len and data_len */ From 22c55fb9eb92395d999b8404d73e58540d11bdd8 Mon Sep 17 00:00:00 2001 From: Ramya Gnanasekar Date: Fri, 1 Aug 2025 16:19:20 +0530 Subject: [PATCH 1100/1292] wifi: ath12k: Set EMLSR support flag in MLO flags for EML-capable stations Currently, when updating EMLSR capabilities of a multi-link (ML) station, only the EMLSR parameters (e.g., padding delay, transition delay, and timeout) are sent to firmware. However, firmware also requires the EMLSR support flag to be set in the MLO flags of the peer assoc WMI command to properly handle EML operating mode notification frames. Set the ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT flag in the peer assoc WMI command when the ML station is EMLSR-capable, so that the firmware can respond to EHT EML action frames from associated stations. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: 4bcf9525bc49 ("wifi: ath12k: update EMLSR capabilities of ML Station") Signed-off-by: Ramya Gnanasekar Signed-off-by: Rameshkumar Sundaram Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250801104920.3326352-1-rameshkumar.sundaram@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index da85c28ec35568..742ffeb48bce77 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2423,6 +2423,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, eml_cap = arg->ml.eml_cap; if (u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLSR_SUPP)) { + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT); /* Padding delay */ eml_pad_delay = ieee80211_emlsr_pad_delay_in_us(eml_cap); ml_params->emlsr_padding_delay_us = cpu_to_le32(eml_pad_delay); From 97acb0259cc9cbfbd7ab689e25684f3d8ce10e26 Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Sun, 10 Aug 2025 22:30:18 +0530 Subject: [PATCH 1101/1292] wifi: ath11k: fix group data packet drops during rekey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During GTK rekey, mac80211 issues a clear key (if the old key exists) followed by an install key operation in the same context. This causes ath11k to send two WMI commands in quick succession: one to clear the old key and another to install the new key in the same slot. Under certain conditions—especially under high load or time sensitive scenarios, firmware may process these commands asynchronously in a way that firmware assumes the key is cleared whereas hardware has a valid key. This inconsistency between hardware and firmware leads to group addressed packet drops. Only setting the same key again can restore a valid key in firmware and allow packets to be transmitted. This issue remained latent because the host's clear key commands were not effective in firmware until commit 436a4e886598 ("ath11k: clear the keys properly via DISABLE_KEY"). That commit enabled the host to explicitly clear group keys, which inadvertently exposed the race. To mitigate this, restrict group key clearing across all modes (AP, STA, MESH). During rekey, the new key can simply be set on top of the previous one, avoiding the need for a clear followed by a set. However, in AP mode specifically, permit group key clearing when no stations are associated. This exception supports transitions from secure modes (e.g., WPA2/WPA3) to open mode, during which all associated peers are removed and the group key is cleared as part of the transition. Add a per-BSS station counter to track the presence of stations during set key operations. Also add a reset_group_keys flag to track the key re-installation state and avoid repeated installation of the same key when the number of connected stations transitions to non-zero within a rekey period. Additionally, for AP and Mesh modes, when the first station associates, reinstall the same group key that was last set. This ensures that the firmware recovers from any race that may have occurred during a previous key clear when no stations were associated. This change ensures that key clearing is permitted only when no clients are connected, avoiding packet loss while enabling dynamic security mode transitions. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41 Reported-by: Steffen Moser Closes: https://lore.kernel.org/linux-wireless/c6366409-9928-4dd7-bf7b-ba7fcf20eabf@steffen-moser.de Fixes: 436a4e886598 ("ath11k: clear the keys properly via DISABLE_KEY") Signed-off-by: Rameshkumar Sundaram Tested-by: Nicolas Escande Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20250810170018.1124014-1-rameshkumar.sundaram@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath11k/core.h | 2 + drivers/net/wireless/ath/ath11k/mac.c | 111 +++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 220d69a7a429d5..e8780b05ce11e3 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -411,6 +411,8 @@ struct ath11k_vif { bool do_not_send_tmpl; struct ath11k_arp_ns_offload arp_ns_offload; struct ath11k_rekey_data rekey_data; + u32 num_stations; + bool reinstall_group_keys; struct ath11k_reg_tpc_power_info reg_tpc_info; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 1fadf5faafb826..106e2530b64e97 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4317,6 +4317,40 @@ static int ath11k_clear_peer_keys(struct ath11k_vif *arvif, return first_errno; } +static int ath11k_set_group_keys(struct ath11k_vif *arvif) +{ + struct ath11k *ar = arvif->ar; + struct ath11k_base *ab = ar->ab; + const u8 *addr = arvif->bssid; + int i, ret, first_errno = 0; + struct ath11k_peer *peer; + + spin_lock_bh(&ab->base_lock); + peer = ath11k_peer_find(ab, arvif->vdev_id, addr); + spin_unlock_bh(&ab->base_lock); + + if (!peer) + return -ENOENT; + + for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { + struct ieee80211_key_conf *key = peer->keys[i]; + + if (!key || (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + continue; + + ret = ath11k_install_key(arvif, key, SET_KEY, addr, + WMI_KEY_GROUP); + if (ret < 0 && first_errno == 0) + first_errno = ret; + + if (ret < 0) + ath11k_warn(ab, "failed to set group key of idx %d for vdev %d: %d\n", + i, arvif->vdev_id, ret); + } + + return first_errno; +} + static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) @@ -4326,6 +4360,7 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_peer *peer; struct ath11k_sta *arsta; + bool is_ap_with_no_sta; const u8 *peer_addr; int ret = 0; u32 flags = 0; @@ -4386,16 +4421,57 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, else flags |= WMI_KEY_GROUP; - ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags); - if (ret) { - ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret); - goto exit; - } + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "%s for peer %pM on vdev %d flags 0x%X, type = %d, num_sta %d\n", + cmd == SET_KEY ? "SET_KEY" : "DEL_KEY", peer_addr, arvif->vdev_id, + flags, arvif->vdev_type, arvif->num_stations); + + /* Allow group key clearing only in AP mode when no stations are + * associated. There is a known race condition in firmware where + * group addressed packets may be dropped if the key is cleared + * and immediately set again during rekey. + * + * During GTK rekey, mac80211 issues a clear key (if the old key + * exists) followed by an install key operation for same key + * index. This causes ath11k to send two WMI commands in quick + * succession: one to clear the old key and another to install the + * new key in the same slot. + * + * Under certain conditions—especially under high load or time + * sensitive scenarios, firmware may process these commands + * asynchronously in a way that firmware assumes the key is + * cleared whereas hardware has a valid key. This inconsistency + * between hardware and firmware leads to group addressed packet + * drops after rekey. + * Only setting the same key again can restore a valid key in + * firmware and allow packets to be transmitted. + * + * There is a use case where an AP can transition from Secure mode + * to open mode without a vdev restart by just deleting all + * associated peers and clearing key, Hence allow clear key for + * that case alone. Mark arvif->reinstall_group_keys in such cases + * and reinstall the same key when the first peer is added, + * allowing firmware to recover from the race if it had occurred. + */ - ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key); - if (ret) { - ath11k_warn(ab, "failed to offload PN replay detection %d\n", ret); - goto exit; + is_ap_with_no_sta = (vif->type == NL80211_IFTYPE_AP && + !arvif->num_stations); + if ((flags & WMI_KEY_PAIRWISE) || cmd == SET_KEY || is_ap_with_no_sta) { + ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags); + if (ret) { + ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret); + goto exit; + } + + ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key); + if (ret) { + ath11k_warn(ab, "failed to offload PN replay detection %d\n", + ret); + goto exit; + } + + if ((flags & WMI_KEY_GROUP) && cmd == SET_KEY && is_ap_with_no_sta) + arvif->reinstall_group_keys = true; } spin_lock_bh(&ab->base_lock); @@ -4994,6 +5070,7 @@ static int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif, return -ENOBUFS; ar->num_stations++; + arvif->num_stations++; return 0; } @@ -5009,6 +5086,7 @@ static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif, return; ar->num_stations--; + arvif->num_stations--; } static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, @@ -9540,6 +9618,21 @@ static int ath11k_mac_station_add(struct ath11k *ar, goto exit; } + /* Driver allows the DEL KEY followed by SET KEY sequence for + * group keys for only when there is no clients associated, if at + * all firmware has entered the race during that window, + * reinstalling the same key when the first sta connects will allow + * firmware to recover from the race. + */ + if (arvif->num_stations == 1 && arvif->reinstall_group_keys) { + ath11k_dbg(ab, ATH11K_DBG_MAC, "set group keys on 1st station add for vdev %d\n", + arvif->vdev_id); + ret = ath11k_set_group_keys(arvif); + if (ret) + goto dec_num_station; + arvif->reinstall_group_keys = false; + } + arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); if (!arsta->rx_stats) { ret = -ENOMEM; From 8b3332c1331c7c260bdff89bfdfd24ea263be764 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 1 Sep 2025 14:08:17 -0700 Subject: [PATCH 1102/1292] Revert "eth: remove the DLink/Sundance (ST201) driver" This reverts commit 8401a108a63302a5a198c7075d857895ca624851. I got a report from an (anonymous) Sundance user: Ethernet controller: Sundance Technology Inc / IC Plus Corp IC Plus IP100A Integrated 10/100 Ethernet MAC + PHY (rev 31) Revert the driver back in. Make following changes: - update Denis's email address in MAINTAINERS - adjust to timer API renames: - del_timer_sync() -> timer_delete_sync() - from_timer() -> timer_container_of() Fixes: 8401a108a633 ("eth: remove the DLink/Sundance (ST201) driver") Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250901210818.1025316-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- MAINTAINERS | 6 + arch/mips/configs/mtx1_defconfig | 1 + arch/powerpc/configs/ppc6xx_defconfig | 1 + drivers/net/ethernet/dlink/Kconfig | 20 + drivers/net/ethernet/dlink/Makefile | 1 + drivers/net/ethernet/dlink/sundance.c | 1985 +++++++++++++++++++++++++ 6 files changed, 2014 insertions(+) create mode 100644 drivers/net/ethernet/dlink/sundance.c diff --git a/MAINTAINERS b/MAINTAINERS index 09b34bbd0c489c..1819c477eee3b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24252,6 +24252,12 @@ S: Maintained F: Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml F: drivers/input/keyboard/sun4i-lradc-keys.c +SUNDANCE NETWORK DRIVER +M: Denis Kirjanov +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/dlink/sundance.c + SUNPLUS ETHERNET DRIVER M: Wells Lu L: netdev@vger.kernel.org diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index e4bcdb64df6c6c..2707ab1346393e 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -273,6 +273,7 @@ CONFIG_DM9102=m CONFIG_ULI526X=m CONFIG_PCMCIA_XIRCOM=m CONFIG_DL2K=m +CONFIG_SUNDANCE=m CONFIG_PCMCIA_FMVJ18X=m CONFIG_E100=m CONFIG_E1000=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index bb359643ddc118..b082c1fae13c94 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -433,6 +433,7 @@ CONFIG_DM9102=m CONFIG_ULI526X=m CONFIG_PCMCIA_XIRCOM=m CONFIG_DL2K=m +CONFIG_SUNDANCE=m CONFIG_S2IO=m CONFIG_FEC_MPC52xx=m CONFIG_GIANFAR=m diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig index e9e13654812c2d..0d77f84c8e7bbc 100644 --- a/drivers/net/ethernet/dlink/Kconfig +++ b/drivers/net/ethernet/dlink/Kconfig @@ -32,4 +32,24 @@ config DL2K To compile this driver as a module, choose M here: the module will be called dl2k. +config SUNDANCE + tristate "Sundance Alta support" + depends on PCI + select CRC32 + select MII + help + This driver is for the Sundance "Alta" chip. + More specific information and updates are available from + . + +config SUNDANCE_MMIO + bool "Use MMIO instead of PIO" + depends on SUNDANCE + help + Enable memory-mapped I/O for interaction with Sundance NIC registers. + Do NOT enable this by default, PIO (enabled when MMIO is disabled) + is known to solve bugs on certain chips. + + If unsure, say N. + endif # NET_VENDOR_DLINK diff --git a/drivers/net/ethernet/dlink/Makefile b/drivers/net/ethernet/dlink/Makefile index 38c236eb6007a5..3ff503c747db74 100644 --- a/drivers/net/ethernet/dlink/Makefile +++ b/drivers/net/ethernet/dlink/Makefile @@ -4,3 +4,4 @@ # obj-$(CONFIG_DL2K) += dl2k.o +obj-$(CONFIG_SUNDANCE) += sundance.o diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c new file mode 100644 index 00000000000000..29d59c42dfa37e --- /dev/null +++ b/drivers/net/ethernet/dlink/sundance.c @@ -0,0 +1,1985 @@ +/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */ +/* + Written 1999-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support and updates available at + http://www.scyld.com/network/sundance.html + [link no longer provides useful info -jgarzik] + Archives of the mailing list are still available at + https://www.beowulf.org/pipermail/netdrivers/ + +*/ + +#define DRV_NAME "sundance" + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + Typical is a 64 element hash table based on the Ethernet CRC. */ +static const int multicast_filter_limit = 32; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. + This chip can receive into offset buffers, so the Alpha does not + need a copy-align. */ +static int rx_copybreak; +static int flowctrl=1; + +/* media[] specifies the media type the NIC operates at. + autosense Autosensing active media. + 10mbps_hd 10Mbps half duplex. + 10mbps_fd 10Mbps full duplex. + 100mbps_hd 100Mbps half duplex. + 100mbps_fd 100Mbps full duplex. + 0 Autosensing active media. + 1 10Mbps half duplex. + 2 10Mbps full duplex. + 3 100Mbps half duplex. + 4 100Mbps full duplex. +*/ +#define MAX_UNITS 8 +static char *media[MAX_UNITS]; + + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority, and more than 128 requires modifying the + Tx error recovery. + Large receive rings merely waste memory. */ +#define TX_RING_SIZE 32 +#define TX_QUEUE_LEN (TX_RING_SIZE - 1) /* Limit ring entries actually used. */ +#define RX_RING_SIZE 64 +#define RX_BUDGET 32 +#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc) +#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc) + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); +MODULE_LICENSE("GPL"); + +module_param(debug, int, 0); +module_param(rx_copybreak, int, 0); +module_param_array(media, charp, NULL, 0); +module_param(flowctrl, int, 0); +MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)"); +MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is designed for the Sundance Technologies "Alta" ST201 chip. + +II. Board-specific settings + +III. Driver operation + +IIIa. Ring buffers + +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. +Some chips explicitly use only 2^N sized rings, while others use a +'next descriptor' pointer that the driver forms into rings. + +IIIb/c. Transmit/Receive Structure + +This driver uses a zero-copy receive and transmit scheme. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the chip as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack. Buffers consumed this way are replaced by newly allocated +skbuffs in a later phase of receives. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. New boards are typically used in generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. When copying is done, the cost is usually mitigated by using +a combined copy/checksum routine. Copying also preloads the cache, which is +most useful with small frames. + +A subtle aspect of the operation is that the IP header at offset 14 in an +ethernet frame isn't longword aligned for further processing. +Unaligned buffers are permitted by the Sundance hardware, so +frames are received into the skbuff at an offset of "+2", 16-byte aligning +the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +IVb. References + +The Sundance ST201 datasheet, preliminary version. +The Kendin KS8723 datasheet, preliminary version. +The ICplus IP100 datasheet, preliminary version. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html + +IVc. Errata + +*/ + +/* Work-around for Kendin chip bugs. */ +#ifndef CONFIG_SUNDANCE_MMIO +#define USE_IO_OPS 1 +#endif + +static const struct pci_device_id sundance_pci_tbl[] = { + { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 }, + { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 }, + { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 }, + { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 }, + { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + { } +}; +MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); + +enum { + netdev_io_size = 128 +}; + +struct pci_id_info { + const char *name; +}; +static const struct pci_id_info pci_id_tbl[] = { + {"D-Link DFE-550TX FAST Ethernet Adapter"}, + {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"}, + {"D-Link DFE-580TX 4 port Server Adapter"}, + {"D-Link DFE-530TXS FAST Ethernet Adapter"}, + {"D-Link DL10050-based FAST Ethernet Adapter"}, + {"Sundance Technology Alta"}, + {"IC Plus Corporation IP100A FAST Ethernet Adapter"}, + { } /* terminate list. */ +}; + +/* This driver was written to use PCI memory space, however x86-oriented + hardware often uses I/O space accesses. */ + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. The name can only partially document the semantics and make + the driver longer and more difficult to read. + In general, only the important configuration values or bits changed + multiple times should be defined symbolically. +*/ +enum alta_offsets { + DMACtrl = 0x00, + TxListPtr = 0x04, + TxDMABurstThresh = 0x08, + TxDMAUrgentThresh = 0x09, + TxDMAPollPeriod = 0x0a, + RxDMAStatus = 0x0c, + RxListPtr = 0x10, + DebugCtrl0 = 0x1a, + DebugCtrl1 = 0x1c, + RxDMABurstThresh = 0x14, + RxDMAUrgentThresh = 0x15, + RxDMAPollPeriod = 0x16, + LEDCtrl = 0x1a, + ASICCtrl = 0x30, + EEData = 0x34, + EECtrl = 0x36, + FlashAddr = 0x40, + FlashData = 0x44, + WakeEvent = 0x45, + TxStatus = 0x46, + TxFrameId = 0x47, + DownCounter = 0x18, + IntrClear = 0x4a, + IntrEnable = 0x4c, + IntrStatus = 0x4e, + MACCtrl0 = 0x50, + MACCtrl1 = 0x52, + StationAddr = 0x54, + MaxFrameSize = 0x5A, + RxMode = 0x5c, + MIICtrl = 0x5e, + MulticastFilter0 = 0x60, + MulticastFilter1 = 0x64, + RxOctetsLow = 0x68, + RxOctetsHigh = 0x6a, + TxOctetsLow = 0x6c, + TxOctetsHigh = 0x6e, + TxFramesOK = 0x70, + RxFramesOK = 0x72, + StatsCarrierError = 0x74, + StatsLateColl = 0x75, + StatsMultiColl = 0x76, + StatsOneColl = 0x77, + StatsTxDefer = 0x78, + RxMissed = 0x79, + StatsTxXSDefer = 0x7a, + StatsTxAbort = 0x7b, + StatsBcastTx = 0x7c, + StatsBcastRx = 0x7d, + StatsMcastTx = 0x7e, + StatsMcastRx = 0x7f, + /* Aliased and bogus values! */ + RxStatus = 0x0c, +}; + +#define ASIC_HI_WORD(x) ((x) + 2) + +enum ASICCtrl_HiWord_bit { + GlobalReset = 0x0001, + RxReset = 0x0002, + TxReset = 0x0004, + DMAReset = 0x0008, + FIFOReset = 0x0010, + NetworkReset = 0x0020, + HostReset = 0x0040, + ResetBusy = 0x0400, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008, + IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020, + IntrDrvRqst=0x0040, + StatsMax=0x0080, LinkChange=0x0100, + IntrTxDMADone=0x0200, IntrRxDMADone=0x0400, +}; + +/* Bits in the RxMode register. */ +enum rx_mode_bits { + AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08, + AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01, +}; +/* Bits in MACCtrl. */ +enum mac_ctrl0_bits { + EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40, + EnbFlowCtrl=0x100, EnbPassRxCRC=0x200, +}; +enum mac_ctrl1_bits { + StatsEnable=0x0020, StatsDisable=0x0040, StatsEnabled=0x0080, + TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400, + RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000, +}; + +/* Bits in WakeEvent register. */ +enum wake_event_bits { + WakePktEnable = 0x01, + MagicPktEnable = 0x02, + LinkEventEnable = 0x04, + WolEnable = 0x80, +}; + +/* The Rx and Tx buffer descriptors. */ +/* Note that using only 32 bit fields simplifies conversion to big-endian + architectures. */ +struct netdev_desc { + __le32 next_desc; + __le32 status; + struct desc_frag { __le32 addr, length; } frag; +}; + +/* Bits in netdev_desc.status */ +enum desc_status_bits { + DescOwn=0x8000, + DescEndPacket=0x4000, + DescEndRing=0x2000, + LastFrag=0x80000000, + DescIntrOnTx=0x8000, + DescIntrOnDMADone=0x80000000, + DisableAlign = 0x00000001, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment + within the structure. */ +#define MII_CNT 4 +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct netdev_desc *rx_ring; + struct netdev_desc *tx_ring; + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; + struct timer_list timer; /* Media monitoring timer. */ + struct net_device *ndev; /* backpointer */ + /* ethtool extra stats */ + struct { + u64 tx_multiple_collisions; + u64 tx_single_collisions; + u64 tx_late_collisions; + u64 tx_deferred; + u64 tx_deferred_excessive; + u64 tx_aborted; + u64 tx_bcasts; + u64 rx_bcasts; + u64 tx_mcasts; + u64 rx_mcasts; + } xstats; + /* Frequently used values: keep some adjacent for cache effect. */ + spinlock_t lock; + int msg_enable; + int chip_id; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + struct netdev_desc *last_tx; /* Last Tx descriptor used. */ + unsigned int cur_tx, dirty_tx; + /* These values are keep track of the transceiver/media in use. */ + unsigned int flowctrl:1; + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int an_enable:1; + unsigned int speed; + unsigned int wol_enabled:1; /* Wake on LAN enabled */ + struct tasklet_struct rx_tasklet; + struct tasklet_struct tx_tasklet; + int budget; + int cur_task; + /* Multicast and receive mode. */ + spinlock_t mcastlock; /* SMP lock multicast updates. */ + u16 mcast_filter[4]; + /* MII transceiver section. */ + struct mii_if_info mii_if; + int mii_preamble_required; + unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ + struct pci_dev *pci_dev; + void __iomem *base; + spinlock_t statlock; +}; + +/* The station address location in the EEPROM. */ +#define EEPROM_SA_OFFSET 0x10 +#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \ + IntrDrvRqst | IntrTxDone | StatsMax | \ + LinkChange) + +static int change_mtu(struct net_device *dev, int new_mtu); +static int eeprom_read(void __iomem *ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int mdio_wait_link(struct net_device *dev, int wait); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev); +static void netdev_timer(struct timer_list *t); +static void tx_timeout(struct net_device *dev, unsigned int txqueue); +static void init_ring(struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); +static int reset_tx (struct net_device *dev); +static irqreturn_t intr_handler(int irq, void *dev_instance); +static void rx_poll(struct tasklet_struct *t); +static void tx_poll(struct tasklet_struct *t); +static void refill_rx (struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static void netdev_error(struct net_device *dev, int intr_status); +static void set_rx_mode(struct net_device *dev); +static int __set_mac_addr(struct net_device *dev); +static int sundance_set_mac_addr(struct net_device *dev, void *data); +static struct net_device_stats *get_stats(struct net_device *dev); +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); +static const struct ethtool_ops ethtool_ops; + +static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base + ASICCtrl; + int countdown; + + /* ST201 documentation states ASICCtrl is a 32bit register */ + iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr); + /* ST201 documentation states reset can take up to 1 ms */ + countdown = 10 + 1; + while (ioread32 (ioaddr) & (ResetBusy << 16)) { + if (--countdown == 0) { + printk(KERN_WARNING "%s : reset not completed !!\n", dev->name); + break; + } + udelay(100); + } +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void sundance_poll_controller(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + + disable_irq(np->pci_dev->irq); + intr_handler(np->pci_dev->irq, dev); + enable_irq(np->pci_dev->irq); +} +#endif + +static const struct net_device_ops netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_get_stats = get_stats, + .ndo_set_rx_mode = set_rx_mode, + .ndo_eth_ioctl = netdev_ioctl, + .ndo_tx_timeout = tx_timeout, + .ndo_change_mtu = change_mtu, + .ndo_set_mac_address = sundance_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sundance_poll_controller, +#endif +}; + +static int sundance_probe1(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct netdev_private *np; + static int card_idx; + int chip_idx = ent->driver_data; + int irq; + int i; + void __iomem *ioaddr; + u16 mii_ctl; + void *ring_space; + dma_addr_t ring_dma; +#ifdef USE_IO_OPS + int bar = 0; +#else + int bar = 1; +#endif + int phy, phy_end, phy_idx = 0; + __le16 addr[ETH_ALEN / 2]; + + if (pci_enable_device(pdev)) + return -EIO; + pci_set_master(pdev); + + irq = pdev->irq; + + dev = alloc_etherdev(sizeof(*np)); + if (!dev) + return -ENOMEM; + SET_NETDEV_DEV(dev, &pdev->dev); + + if (pci_request_regions(pdev, DRV_NAME)) + goto err_out_netdev; + + ioaddr = pci_iomap(pdev, bar, netdev_io_size); + if (!ioaddr) + goto err_out_res; + + for (i = 0; i < 3; i++) + addr[i] = + cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); + eth_hw_addr_set(dev, (u8 *)addr); + + np = netdev_priv(dev); + np->ndev = dev; + np->base = ioaddr; + np->pci_dev = pdev; + np->chip_id = chip_idx; + np->msg_enable = (1 << debug) - 1; + spin_lock_init(&np->lock); + spin_lock_init(&np->statlock); + tasklet_setup(&np->rx_tasklet, rx_poll); + tasklet_setup(&np->tx_tasklet, tx_poll); + + ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, + &ring_dma, GFP_KERNEL); + if (!ring_space) + goto err_out_cleardev; + np->tx_ring = (struct netdev_desc *)ring_space; + np->tx_ring_dma = ring_dma; + + ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, + &ring_dma, GFP_KERNEL); + if (!ring_space) + goto err_out_unmap_tx; + np->rx_ring = (struct netdev_desc *)ring_space; + np->rx_ring_dma = ring_dma; + + np->mii_if.dev = dev; + np->mii_if.mdio_read = mdio_read; + np->mii_if.mdio_write = mdio_write; + np->mii_if.phy_id_mask = 0x1f; + np->mii_if.reg_num_mask = 0x1f; + + /* The chip-specific entries in the device structure. */ + dev->netdev_ops = &netdev_ops; + dev->ethtool_ops = ðtool_ops; + dev->watchdog_timeo = TX_TIMEOUT; + + /* MTU range: 68 - 8191 */ + dev->min_mtu = ETH_MIN_MTU; + dev->max_mtu = 8191; + + pci_set_drvdata(pdev, dev); + + i = register_netdev(dev); + if (i) + goto err_out_unmap_rx; + + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, + dev->dev_addr, irq); + + np->phys[0] = 1; /* Default setting */ + np->mii_preamble_required++; + + /* + * It seems some phys doesn't deal well with address 0 being accessed + * first + */ + if (sundance_pci_tbl[np->chip_id].device == 0x0200) { + phy = 0; + phy_end = 31; + } else { + phy = 1; + phy_end = 32; /* wraps to zero, due to 'phy & 0x1f' */ + } + for (; phy <= phy_end && phy_idx < MII_CNT; phy++) { + int phyx = phy & 0x1f; + int mii_status = mdio_read(dev, phyx, MII_BMSR); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phyx; + np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); + if ((mii_status & 0x0040) == 0) + np->mii_preamble_required++; + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phyx, mii_status, np->mii_if.advertising); + } + } + np->mii_preamble_required--; + + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", + dev->name, ioread32(ioaddr + ASICCtrl)); + goto err_out_unregister; + } + + np->mii_if.phy_id = np->phys[0]; + + /* Parse override configuration */ + np->an_enable = 1; + if (card_idx < MAX_UNITS) { + if (media[card_idx] != NULL) { + np->an_enable = 0; + if (strcmp (media[card_idx], "100mbps_fd") == 0 || + strcmp (media[card_idx], "4") == 0) { + np->speed = 100; + np->mii_if.full_duplex = 1; + } else if (strcmp (media[card_idx], "100mbps_hd") == 0 || + strcmp (media[card_idx], "3") == 0) { + np->speed = 100; + np->mii_if.full_duplex = 0; + } else if (strcmp (media[card_idx], "10mbps_fd") == 0 || + strcmp (media[card_idx], "2") == 0) { + np->speed = 10; + np->mii_if.full_duplex = 1; + } else if (strcmp (media[card_idx], "10mbps_hd") == 0 || + strcmp (media[card_idx], "1") == 0) { + np->speed = 10; + np->mii_if.full_duplex = 0; + } else { + np->an_enable = 1; + } + } + if (flowctrl == 1) + np->flowctrl = 1; + } + + /* Fibre PHY? */ + if (ioread32 (ioaddr + ASICCtrl) & 0x80) { + /* Default 100Mbps Full */ + if (np->an_enable) { + np->speed = 100; + np->mii_if.full_duplex = 1; + np->an_enable = 0; + } + } + /* Reset PHY */ + mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET); + mdelay (300); + /* If flow control enabled, we need to advertise it.*/ + if (np->flowctrl) + mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400); + mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART); + /* Force media type */ + if (!np->an_enable) { + mii_ctl = 0; + mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0; + mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0; + mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl); + printk (KERN_INFO "Override speed=%d, %s duplex\n", + np->speed, np->mii_if.full_duplex ? "Full" : "Half"); + + } + + /* Perhaps move the reset here? */ + /* Reset the chip to erase previous misconfiguration. */ + if (netif_msg_hw(np)) + printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); + sundance_reset(dev, 0x00ff << 16); + if (netif_msg_hw(np)) + printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); + + card_idx++; + return 0; + +err_out_unregister: + unregister_netdev(dev); +err_out_unmap_rx: + dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, + np->rx_ring, np->rx_ring_dma); +err_out_unmap_tx: + dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, + np->tx_ring, np->tx_ring_dma); +err_out_cleardev: + pci_iounmap(pdev, ioaddr); +err_out_res: + pci_release_regions(pdev); +err_out_netdev: + free_netdev (dev); + return -ENODEV; +} + +static int change_mtu(struct net_device *dev, int new_mtu) +{ + if (netif_running(dev)) + return -EBUSY; + WRITE_ONCE(dev->mtu, new_mtu); + return 0; +} + +#define eeprom_delay(ee_addr) ioread32(ee_addr) +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ +static int eeprom_read(void __iomem *ioaddr, int location) +{ + int boguscnt = 10000; /* Typical 1900 ticks. */ + iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl); + do { + eeprom_delay(ioaddr + EECtrl); + if (! (ioread16(ioaddr + EECtrl) & 0x8000)) { + return ioread16(ioaddr + EEData); + } + } while (--boguscnt > 0); + return 0; +} + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. + + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back 33Mhz PCI cycles. */ +#define mdio_delay() ioread8(mdio_addr) + +enum mii_reg_bits { + MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004, +}; +#define MDIO_EnbIn (0) +#define MDIO_WRITE0 (MDIO_EnbOutput) +#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput) + +/* Generate the preamble required for initial synchronization and + a few older transceivers. */ +static void mdio_sync(void __iomem *mdio_addr) +{ + int bits = 32; + + /* Establish sync by sending at least 32 logic ones. */ + while (--bits >= 0) { + iowrite8(MDIO_WRITE1, mdio_addr); + mdio_delay(); + iowrite8(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } +} + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *mdio_addr = np->base + MIICtrl; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int i, retval = 0; + + if (np->mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + iowrite8(dataval, mdio_addr); + mdio_delay(); + iowrite8(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + iowrite8(MDIO_EnbIn, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((ioread8(mdio_addr) & MDIO_Data) ? 1 : 0); + iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *mdio_addr = np->base + MIICtrl; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int i; + + if (np->mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + iowrite8(dataval, mdio_addr); + mdio_delay(); + iowrite8(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + iowrite8(MDIO_EnbIn, mdio_addr); + mdio_delay(); + iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } +} + +static int mdio_wait_link(struct net_device *dev, int wait) +{ + int bmsr; + int phy_id; + struct netdev_private *np; + + np = netdev_priv(dev); + phy_id = np->phys[0]; + + do { + bmsr = mdio_read(dev, phy_id, MII_BMSR); + if (bmsr & 0x0004) + return 0; + mdelay(1); + } while (--wait > 0); + return -1; +} + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + const int irq = np->pci_dev->irq; + unsigned long flags; + int i; + + sundance_reset(dev, 0x00ff << 16); + + i = request_irq(irq, intr_handler, IRQF_SHARED, dev->name, dev); + if (i) + return i; + + if (netif_msg_ifup(np)) + printk(KERN_DEBUG "%s: netdev_open() irq %d\n", dev->name, irq); + + init_ring(dev); + + iowrite32(np->rx_ring_dma, ioaddr + RxListPtr); + /* The Tx list pointer is written as packets are queued. */ + + /* Initialize other registers. */ + __set_mac_addr(dev); +#if IS_ENABLED(CONFIG_VLAN_8021Q) + iowrite16(dev->mtu + 18, ioaddr + MaxFrameSize); +#else + iowrite16(dev->mtu + 14, ioaddr + MaxFrameSize); +#endif + if (dev->mtu > 2047) + iowrite32(ioread32(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl); + + /* Configure the PCI bus bursts and FIFO thresholds. */ + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + spin_lock_init(&np->mcastlock); + + set_rx_mode(dev); + iowrite16(0, ioaddr + IntrEnable); + iowrite16(0, ioaddr + DownCounter); + /* Set the chip to poll every N*320nsec. */ + iowrite8(100, ioaddr + RxDMAPollPeriod); + iowrite8(127, ioaddr + TxDMAPollPeriod); + /* Fix DFE-580TX packet drop issue */ + if (np->pci_dev->revision >= 0x14) + iowrite8(0x01, ioaddr + DebugCtrl1); + netif_start_queue(dev); + + spin_lock_irqsave(&np->lock, flags); + reset_tx(dev); + spin_unlock_irqrestore(&np->lock, flags); + + iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); + + /* Disable Wol */ + iowrite8(ioread8(ioaddr + WakeEvent) | 0x00, ioaddr + WakeEvent); + np->wol_enabled = 0; + + if (netif_msg_ifup(np)) + printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " + "MAC Control %x, %4.4x %4.4x.\n", + dev->name, ioread32(ioaddr + RxStatus), ioread8(ioaddr + TxStatus), + ioread32(ioaddr + MACCtrl0), + ioread16(ioaddr + MACCtrl1), ioread16(ioaddr + MACCtrl0)); + + /* Set the timer to check for link beat. */ + timer_setup(&np->timer, netdev_timer, 0); + np->timer.expires = jiffies + 3*HZ; + add_timer(&np->timer); + + /* Enable interrupts by setting the interrupt mask. */ + iowrite16(DEFAULT_INTR, ioaddr + IntrEnable); + + return 0; +} + +static void check_duplex(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); + int negotiated = mii_lpa & np->mii_if.advertising; + int duplex; + + /* Force media */ + if (!np->an_enable || mii_lpa == 0xffff) { + if (np->mii_if.full_duplex) + iowrite16 (ioread16 (ioaddr + MACCtrl0) | EnbFullDuplex, + ioaddr + MACCtrl0); + return; + } + + /* Autonegotiation */ + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (np->mii_if.full_duplex != duplex) { + np->mii_if.full_duplex = duplex; + if (netif_msg_link(np)) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " + "negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + iowrite16(ioread16(ioaddr + MACCtrl0) | (duplex ? 0x20 : 0), ioaddr + MACCtrl0); + } +} + +static void netdev_timer(struct timer_list *t) +{ + struct netdev_private *np = timer_container_of(np, t, timer); + struct net_device *dev = np->mii_if.dev; + void __iomem *ioaddr = np->base; + int next_tick = 10*HZ; + + if (netif_msg_timer(np)) { + printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, " + "Tx %x Rx %x.\n", + dev->name, ioread16(ioaddr + IntrEnable), + ioread8(ioaddr + TxStatus), ioread32(ioaddr + RxStatus)); + } + check_duplex(dev); + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev, unsigned int txqueue) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + unsigned long flag; + + netif_stop_queue(dev); + tasklet_disable_in_atomic(&np->tx_tasklet); + iowrite16(0, ioaddr + IntrEnable); + printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x " + "TxFrameId %2.2x," + " resetting...\n", dev->name, ioread8(ioaddr + TxStatus), + ioread8(ioaddr + TxFrameId)); + + { + int i; + for (i=0; itx_ring_dma + i*sizeof(*np->tx_ring)), + le32_to_cpu(np->tx_ring[i].next_desc), + le32_to_cpu(np->tx_ring[i].status), + (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff, + le32_to_cpu(np->tx_ring[i].frag.addr), + le32_to_cpu(np->tx_ring[i].frag.length)); + } + printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", + ioread32(np->base + TxListPtr), + netif_queue_stopped(dev)); + printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", + np->cur_tx, np->cur_tx % TX_RING_SIZE, + np->dirty_tx, np->dirty_tx % TX_RING_SIZE); + printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx); + printk(KERN_DEBUG "cur_task=%d\n", np->cur_task); + } + spin_lock_irqsave(&np->lock, flag); + + /* Stop and restart the chip's Tx processes . */ + reset_tx(dev); + spin_unlock_irqrestore(&np->lock, flag); + + dev->if_port = 0; + + netif_trans_update(dev); /* prevent tx timeout */ + dev->stats.tx_errors++; + if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + netif_wake_queue(dev); + } + iowrite16(DEFAULT_INTR, ioaddr + IntrEnable); + tasklet_enable(&np->tx_tasklet); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + int i; + + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->dirty_tx = 0; + np->cur_task = 0; + + np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16); + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma + + ((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring)); + np->rx_ring[i].status = 0; + np->rx_ring[i].frag.length = 0; + np->rx_skbuff[i] = NULL; + } + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = + netdev_alloc_skb(dev, np->rx_buf_sz + 2); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb_reserve(skb, 2); /* 16 byte align the IP header. */ + np->rx_ring[i].frag.addr = cpu_to_le32( + dma_map_single(&np->pci_dev->dev, skb->data, + np->rx_buf_sz, DMA_FROM_DEVICE)); + if (dma_mapping_error(&np->pci_dev->dev, + np->rx_ring[i].frag.addr)) { + dev_kfree_skb(skb); + np->rx_skbuff[i] = NULL; + break; + } + np->rx_ring[i].frag.length = cpu_to_le32(np->rx_buf_sz | LastFrag); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = NULL; + np->tx_ring[i].status = 0; + } +} + +static void tx_poll(struct tasklet_struct *t) +{ + struct netdev_private *np = from_tasklet(np, t, tx_tasklet); + unsigned head = np->cur_task % TX_RING_SIZE; + struct netdev_desc *txdesc = + &np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE]; + + /* Chain the next pointer */ + for (; np->cur_tx - np->cur_task > 0; np->cur_task++) { + int entry = np->cur_task % TX_RING_SIZE; + txdesc = &np->tx_ring[entry]; + if (np->last_tx) { + np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma + + entry*sizeof(struct netdev_desc)); + } + np->last_tx = txdesc; + } + /* Indicate the latest descriptor of tx ring */ + txdesc->status |= cpu_to_le32(DescIntrOnTx); + + if (ioread32 (np->base + TxListPtr) == 0) + iowrite32 (np->tx_ring_dma + head * sizeof(struct netdev_desc), + np->base + TxListPtr); +} + +static netdev_tx_t +start_tx (struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + struct netdev_desc *txdesc; + unsigned entry; + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + np->tx_skbuff[entry] = skb; + txdesc = &np->tx_ring[entry]; + + txdesc->next_desc = 0; + txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign); + txdesc->frag.addr = cpu_to_le32(dma_map_single(&np->pci_dev->dev, + skb->data, skb->len, DMA_TO_DEVICE)); + if (dma_mapping_error(&np->pci_dev->dev, + txdesc->frag.addr)) + goto drop_frame; + txdesc->frag.length = cpu_to_le32 (skb->len | LastFrag); + + /* Increment cur_tx before tasklet_schedule() */ + np->cur_tx++; + mb(); + /* Schedule a tx_poll() task */ + tasklet_schedule(&np->tx_tasklet); + + /* On some architectures: explicitly flush cache lines here. */ + if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1 && + !netif_queue_stopped(dev)) { + /* do nothing */ + } else { + netif_stop_queue (dev); + } + if (netif_msg_tx_queued(np)) { + printk (KERN_DEBUG + "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return NETDEV_TX_OK; + +drop_frame: + dev_kfree_skb_any(skb); + np->tx_skbuff[entry] = NULL; + dev->stats.tx_dropped++; + return NETDEV_TX_OK; +} + +/* Reset hardware tx and free all of tx buffers */ +static int +reset_tx (struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + struct sk_buff *skb; + int i; + + /* Reset tx logic, TxListPtr will be cleaned */ + iowrite16 (TxDisable, ioaddr + MACCtrl1); + sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16); + + /* free all tx skbuff */ + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].next_desc = 0; + + skb = np->tx_skbuff[i]; + if (skb) { + dma_unmap_single(&np->pci_dev->dev, + le32_to_cpu(np->tx_ring[i].frag.addr), + skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + np->tx_skbuff[i] = NULL; + dev->stats.tx_dropped++; + } + } + np->cur_tx = np->dirty_tx = 0; + np->cur_task = 0; + + np->last_tx = NULL; + iowrite8(127, ioaddr + TxDMAPollPeriod); + + iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); + return 0; +} + +/* The interrupt handler cleans up after the Tx thread, + and schedule a Rx thread work */ +static irqreturn_t intr_handler(int irq, void *dev_instance) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + int hw_frame_id; + int tx_cnt; + int tx_status; + int handled = 0; + int i; + + do { + int intr_status = ioread16(ioaddr + IntrStatus); + iowrite16(intr_status, ioaddr + IntrStatus); + + if (netif_msg_intr(np)) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (!(intr_status & DEFAULT_INTR)) + break; + + handled = 1; + + if (intr_status & (IntrRxDMADone)) { + iowrite16(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone), + ioaddr + IntrEnable); + if (np->budget < 0) + np->budget = RX_BUDGET; + tasklet_schedule(&np->rx_tasklet); + } + if (intr_status & (IntrTxDone | IntrDrvRqst)) { + tx_status = ioread16 (ioaddr + TxStatus); + for (tx_cnt=32; tx_status & 0x80; --tx_cnt) { + if (netif_msg_tx_done(np)) + printk + ("%s: Transmit status is %2.2x.\n", + dev->name, tx_status); + if (tx_status & 0x1e) { + if (netif_msg_tx_err(np)) + printk("%s: Transmit error status %4.4x.\n", + dev->name, tx_status); + dev->stats.tx_errors++; + if (tx_status & 0x10) + dev->stats.tx_fifo_errors++; + if (tx_status & 0x08) + dev->stats.collisions++; + if (tx_status & 0x04) + dev->stats.tx_fifo_errors++; + if (tx_status & 0x02) + dev->stats.tx_window_errors++; + + /* + ** This reset has been verified on + ** DFE-580TX boards ! phdm@macqel.be. + */ + if (tx_status & 0x10) { /* TxUnderrun */ + /* Restart Tx FIFO and transmitter */ + sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); + /* No need to reset the Tx pointer here */ + } + /* Restart the Tx. Need to make sure tx enabled */ + i = 10; + do { + iowrite16(ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1); + if (ioread16(ioaddr + MACCtrl1) & TxEnabled) + break; + mdelay(1); + } while (--i); + } + /* Yup, this is a documentation bug. It cost me *hours*. */ + iowrite16 (0, ioaddr + TxStatus); + if (tx_cnt < 0) { + iowrite32(5000, ioaddr + DownCounter); + break; + } + tx_status = ioread16 (ioaddr + TxStatus); + } + hw_frame_id = (tx_status >> 8) & 0xff; + } else { + hw_frame_id = ioread8(ioaddr + TxFrameId); + } + + if (np->pci_dev->revision >= 0x14) { + spin_lock(&np->lock); + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + int sw_frame_id; + sw_frame_id = (le32_to_cpu( + np->tx_ring[entry].status) >> 2) & 0xff; + if (sw_frame_id == hw_frame_id && + !(le32_to_cpu(np->tx_ring[entry].status) + & 0x00010000)) + break; + if (sw_frame_id == (hw_frame_id + 1) % + TX_RING_SIZE) + break; + skb = np->tx_skbuff[entry]; + /* Free the original skb. */ + dma_unmap_single(&np->pci_dev->dev, + le32_to_cpu(np->tx_ring[entry].frag.addr), + skb->len, DMA_TO_DEVICE); + dev_consume_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = NULL; + np->tx_ring[entry].frag.addr = 0; + np->tx_ring[entry].frag.length = 0; + } + spin_unlock(&np->lock); + } else { + spin_lock(&np->lock); + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + if (!(le32_to_cpu(np->tx_ring[entry].status) + & 0x00010000)) + break; + skb = np->tx_skbuff[entry]; + /* Free the original skb. */ + dma_unmap_single(&np->pci_dev->dev, + le32_to_cpu(np->tx_ring[entry].frag.addr), + skb->len, DMA_TO_DEVICE); + dev_consume_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = NULL; + np->tx_ring[entry].frag.addr = 0; + np->tx_ring[entry].frag.length = 0; + } + spin_unlock(&np->lock); + } + + if (netif_queue_stopped(dev) && + np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, clear busy flag. */ + netif_wake_queue (dev); + } + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & (IntrPCIErr | LinkChange | StatsMax)) + netdev_error(dev, intr_status); + } while (0); + if (netif_msg_intr(np)) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, ioread16(ioaddr + IntrStatus)); + return IRQ_RETVAL(handled); +} + +static void rx_poll(struct tasklet_struct *t) +{ + struct netdev_private *np = from_tasklet(np, t, rx_tasklet); + struct net_device *dev = np->ndev; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->budget; + void __iomem *ioaddr = np->base; + int received = 0; + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while (1) { + struct netdev_desc *desc = &(np->rx_ring[entry]); + u32 frame_status = le32_to_cpu(desc->status); + int pkt_len; + + if (--boguscnt < 0) { + goto not_done; + } + if (!(frame_status & DescOwn)) + break; + pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ + if (netif_msg_rx_status(np)) + printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", + frame_status); + if (frame_status & 0x001f4000) { + /* There was a error. */ + if (netif_msg_rx_err(np)) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + frame_status); + dev->stats.rx_errors++; + if (frame_status & 0x00100000) + dev->stats.rx_length_errors++; + if (frame_status & 0x00010000) + dev->stats.rx_fifo_errors++; + if (frame_status & 0x00060000) + dev->stats.rx_frame_errors++; + if (frame_status & 0x00080000) + dev->stats.rx_crc_errors++; + if (frame_status & 0x00100000) { + printk(KERN_WARNING "%s: Oversized Ethernet frame," + " status %8.8x.\n", + dev->name, frame_status); + } + } else { + struct sk_buff *skb; +#ifndef final_version + if (netif_msg_rx_status(np)) + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" + ", bogus_cnt %d.\n", + pkt_len, boguscnt); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak && + (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { + skb_reserve(skb, 2); /* 16 byte align the IP header */ + dma_sync_single_for_cpu(&np->pci_dev->dev, + le32_to_cpu(desc->frag.addr), + np->rx_buf_sz, DMA_FROM_DEVICE); + skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len); + dma_sync_single_for_device(&np->pci_dev->dev, + le32_to_cpu(desc->frag.addr), + np->rx_buf_sz, DMA_FROM_DEVICE); + skb_put(skb, pkt_len); + } else { + dma_unmap_single(&np->pci_dev->dev, + le32_to_cpu(desc->frag.addr), + np->rx_buf_sz, DMA_FROM_DEVICE); + skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; + } + skb->protocol = eth_type_trans(skb, dev); + /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */ + netif_rx(skb); + } + entry = (entry + 1) % RX_RING_SIZE; + received++; + } + np->cur_rx = entry; + refill_rx (dev); + np->budget -= received; + iowrite16(DEFAULT_INTR, ioaddr + IntrEnable); + return; + +not_done: + np->cur_rx = entry; + refill_rx (dev); + if (!received) + received = 1; + np->budget -= received; + if (np->budget <= 0) + np->budget = RX_BUDGET; + tasklet_schedule(&np->rx_tasklet); +} + +static void refill_rx (struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + int entry; + + /* Refill the Rx ring buffers. */ + for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0; + np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) { + struct sk_buff *skb; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = netdev_alloc_skb(dev, np->rx_buf_sz + 2); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + np->rx_ring[entry].frag.addr = cpu_to_le32( + dma_map_single(&np->pci_dev->dev, skb->data, + np->rx_buf_sz, DMA_FROM_DEVICE)); + if (dma_mapping_error(&np->pci_dev->dev, + np->rx_ring[entry].frag.addr)) { + dev_kfree_skb_irq(skb); + np->rx_skbuff[entry] = NULL; + break; + } + } + /* Perhaps we need not reset this field. */ + np->rx_ring[entry].frag.length = + cpu_to_le32(np->rx_buf_sz | LastFrag); + np->rx_ring[entry].status = 0; + } +} +static void netdev_error(struct net_device *dev, int intr_status) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + u16 mii_ctl, mii_advertise, mii_lpa; + int speed; + + if (intr_status & LinkChange) { + if (mdio_wait_link(dev, 10) == 0) { + printk(KERN_INFO "%s: Link up\n", dev->name); + if (np->an_enable) { + mii_advertise = mdio_read(dev, np->phys[0], + MII_ADVERTISE); + mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); + mii_advertise &= mii_lpa; + printk(KERN_INFO "%s: Link changed: ", + dev->name); + if (mii_advertise & ADVERTISE_100FULL) { + np->speed = 100; + printk("100Mbps, full duplex\n"); + } else if (mii_advertise & ADVERTISE_100HALF) { + np->speed = 100; + printk("100Mbps, half duplex\n"); + } else if (mii_advertise & ADVERTISE_10FULL) { + np->speed = 10; + printk("10Mbps, full duplex\n"); + } else if (mii_advertise & ADVERTISE_10HALF) { + np->speed = 10; + printk("10Mbps, half duplex\n"); + } else + printk("\n"); + + } else { + mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR); + speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; + np->speed = speed; + printk(KERN_INFO "%s: Link changed: %dMbps ,", + dev->name, speed); + printk("%s duplex.\n", + (mii_ctl & BMCR_FULLDPLX) ? + "full" : "half"); + } + check_duplex(dev); + if (np->flowctrl && np->mii_if.full_duplex) { + iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, + ioaddr + MulticastFilter1+2); + iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, + ioaddr + MACCtrl0); + } + netif_carrier_on(dev); + } else { + printk(KERN_INFO "%s: Link down\n", dev->name); + netif_carrier_off(dev); + } + } + if (intr_status & StatsMax) { + get_stats(dev); + } + if (intr_status & IntrPCIErr) { + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* We must do a global reset of DMA to continue. */ + } +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + unsigned long flags; + u8 late_coll, single_coll, mult_coll; + + spin_lock_irqsave(&np->statlock, flags); + /* The chip only need report frame silently dropped. */ + dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); + dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK); + dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK); + dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); + + mult_coll = ioread8(ioaddr + StatsMultiColl); + np->xstats.tx_multiple_collisions += mult_coll; + single_coll = ioread8(ioaddr + StatsOneColl); + np->xstats.tx_single_collisions += single_coll; + late_coll = ioread8(ioaddr + StatsLateColl); + np->xstats.tx_late_collisions += late_coll; + dev->stats.collisions += mult_coll + + single_coll + + late_coll; + + np->xstats.tx_deferred += ioread8(ioaddr + StatsTxDefer); + np->xstats.tx_deferred_excessive += ioread8(ioaddr + StatsTxXSDefer); + np->xstats.tx_aborted += ioread8(ioaddr + StatsTxAbort); + np->xstats.tx_bcasts += ioread8(ioaddr + StatsBcastTx); + np->xstats.rx_bcasts += ioread8(ioaddr + StatsBcastRx); + np->xstats.tx_mcasts += ioread8(ioaddr + StatsMcastTx); + np->xstats.rx_mcasts += ioread8(ioaddr + StatsMcastRx); + + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; + + spin_unlock_irqrestore(&np->statlock, flags); + + return &dev->stats; +} + +static void set_rx_mode(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + u16 mc_filter[4]; /* Multicast hash filter */ + u32 rx_mode; + int i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + } else if (!netdev_mc_empty(dev)) { + struct netdev_hw_addr *ha; + int bit; + int index; + int crc; + memset (mc_filter, 0, sizeof (mc_filter)); + netdev_for_each_mc_addr(ha, dev) { + crc = ether_crc_le(ETH_ALEN, ha->addr); + for (index=0, bit=0; bit < 6; bit++, crc <<= 1) + if (crc & 0x80000000) index |= 1 << bit; + mc_filter[index/16] |= (1 << (index % 16)); + } + rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys; + } else { + iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); + return; + } + if (np->mii_if.full_duplex && np->flowctrl) + mc_filter[3] |= 0x0200; + + for (i = 0; i < 4; i++) + iowrite16(mc_filter[i], ioaddr + MulticastFilter0 + i*2); + iowrite8(rx_mode, ioaddr + RxMode); +} + +static int __set_mac_addr(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + u16 addr16; + + addr16 = (dev->dev_addr[0] | (dev->dev_addr[1] << 8)); + iowrite16(addr16, np->base + StationAddr); + addr16 = (dev->dev_addr[2] | (dev->dev_addr[3] << 8)); + iowrite16(addr16, np->base + StationAddr+2); + addr16 = (dev->dev_addr[4] | (dev->dev_addr[5] << 8)); + iowrite16(addr16, np->base + StationAddr+4); + return 0; +} + +/* Invoked with rtnl_lock held */ +static int sundance_set_mac_addr(struct net_device *dev, void *data) +{ + const struct sockaddr *addr = data; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + eth_hw_addr_set(dev, addr->sa_data); + __set_mac_addr(dev); + + return 0; +} + +static const struct { + const char name[ETH_GSTRING_LEN]; +} sundance_stats[] = { + { "tx_multiple_collisions" }, + { "tx_single_collisions" }, + { "tx_late_collisions" }, + { "tx_deferred" }, + { "tx_deferred_excessive" }, + { "tx_aborted" }, + { "tx_bcasts" }, + { "rx_bcasts" }, + { "tx_mcasts" }, + { "rx_mcasts" }, +}; + +static int check_if_running(struct net_device *dev) +{ + if (!netif_running(dev)) + return -EINVAL; + return 0; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct netdev_private *np = netdev_priv(dev); + strscpy(info->driver, DRV_NAME, sizeof(info->driver)); + strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); +} + +static int get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + struct netdev_private *np = netdev_priv(dev); + spin_lock_irq(&np->lock); + mii_ethtool_get_link_ksettings(&np->mii_if, cmd); + spin_unlock_irq(&np->lock); + return 0; +} + +static int set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) +{ + struct netdev_private *np = netdev_priv(dev); + int res; + spin_lock_irq(&np->lock); + res = mii_ethtool_set_link_ksettings(&np->mii_if, cmd); + spin_unlock_irq(&np->lock); + return res; +} + +static int nway_reset(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + return mii_nway_restart(&np->mii_if); +} + +static u32 get_link(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + return mii_link_ok(&np->mii_if); +} + +static u32 get_msglevel(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + return np->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + struct netdev_private *np = netdev_priv(dev); + np->msg_enable = val; +} + +static void get_strings(struct net_device *dev, u32 stringset, + u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, sundance_stats, sizeof(sundance_stats)); +} + +static int get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(sundance_stats); + default: + return -EOPNOTSUPP; + } +} + +static void get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct netdev_private *np = netdev_priv(dev); + int i = 0; + + get_stats(dev); + data[i++] = np->xstats.tx_multiple_collisions; + data[i++] = np->xstats.tx_single_collisions; + data[i++] = np->xstats.tx_late_collisions; + data[i++] = np->xstats.tx_deferred; + data[i++] = np->xstats.tx_deferred_excessive; + data[i++] = np->xstats.tx_aborted; + data[i++] = np->xstats.tx_bcasts; + data[i++] = np->xstats.rx_bcasts; + data[i++] = np->xstats.tx_mcasts; + data[i++] = np->xstats.rx_mcasts; +} + +#ifdef CONFIG_PM + +static void sundance_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + u8 wol_bits; + + wol->wolopts = 0; + + wol->supported = (WAKE_PHY | WAKE_MAGIC); + if (!np->wol_enabled) + return; + + wol_bits = ioread8(ioaddr + WakeEvent); + if (wol_bits & MagicPktEnable) + wol->wolopts |= WAKE_MAGIC; + if (wol_bits & LinkEventEnable) + wol->wolopts |= WAKE_PHY; +} + +static int sundance_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + u8 wol_bits; + + if (!device_can_wakeup(&np->pci_dev->dev)) + return -EOPNOTSUPP; + + np->wol_enabled = !!(wol->wolopts); + wol_bits = ioread8(ioaddr + WakeEvent); + wol_bits &= ~(WakePktEnable | MagicPktEnable | + LinkEventEnable | WolEnable); + + if (np->wol_enabled) { + if (wol->wolopts & WAKE_MAGIC) + wol_bits |= (MagicPktEnable | WolEnable); + if (wol->wolopts & WAKE_PHY) + wol_bits |= (LinkEventEnable | WolEnable); + } + iowrite8(wol_bits, ioaddr + WakeEvent); + + device_set_wakeup_enable(&np->pci_dev->dev, np->wol_enabled); + + return 0; +} +#else +#define sundance_get_wol NULL +#define sundance_set_wol NULL +#endif /* CONFIG_PM */ + +static const struct ethtool_ops ethtool_ops = { + .begin = check_if_running, + .get_drvinfo = get_drvinfo, + .nway_reset = nway_reset, + .get_link = get_link, + .get_wol = sundance_get_wol, + .set_wol = sundance_set_wol, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_strings = get_strings, + .get_sset_count = get_sset_count, + .get_ethtool_stats = get_ethtool_stats, + .get_link_ksettings = get_link_ksettings, + .set_link_ksettings = set_link_ksettings, +}; + +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct netdev_private *np = netdev_priv(dev); + int rc; + + if (!netif_running(dev)) + return -EINVAL; + + spin_lock_irq(&np->lock); + rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL); + spin_unlock_irq(&np->lock); + + return rc; +} + +static int netdev_close(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + struct sk_buff *skb; + int i; + + /* Wait and kill tasklet */ + tasklet_kill(&np->rx_tasklet); + tasklet_kill(&np->tx_tasklet); + np->cur_tx = 0; + np->dirty_tx = 0; + np->cur_task = 0; + np->last_tx = NULL; + + netif_stop_queue(dev); + + if (netif_msg_ifdown(np)) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x " + "Rx %4.4x Int %2.2x.\n", + dev->name, ioread8(ioaddr + TxStatus), + ioread32(ioaddr + RxStatus), ioread16(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + iowrite16(0x0000, ioaddr + IntrEnable); + + /* Disable Rx and Tx DMA for safely release resource */ + iowrite32(0x500, ioaddr + DMACtrl); + + /* Stop the chip's Tx and Rx processes. */ + iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); + + for (i = 2000; i > 0; i--) { + if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0) + break; + mdelay(1); + } + + iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset, + ioaddr + ASIC_HI_WORD(ASICCtrl)); + + for (i = 2000; i > 0; i--) { + if ((ioread16(ioaddr + ASIC_HI_WORD(ASICCtrl)) & ResetBusy) == 0) + break; + mdelay(1); + } + +#ifdef __i386__ + if (netif_msg_hw(np)) { + printk(KERN_DEBUG " Tx ring at %8.8x:\n", + (int)(np->tx_ring_dma)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(KERN_DEBUG " #%d desc. %4.4x %8.8x %8.8x.\n", + i, np->tx_ring[i].status, np->tx_ring[i].frag.addr, + np->tx_ring[i].frag.length); + printk(KERN_DEBUG " Rx ring %8.8x:\n", + (int)(np->rx_ring_dma)); + for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) { + printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", + i, np->rx_ring[i].status, np->rx_ring[i].frag.addr, + np->rx_ring[i].frag.length); + } + } +#endif /* __i386__ debugging only */ + + free_irq(np->pci_dev->irq, dev); + + timer_delete_sync(&np->timer); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].status = 0; + skb = np->rx_skbuff[i]; + if (skb) { + dma_unmap_single(&np->pci_dev->dev, + le32_to_cpu(np->rx_ring[i].frag.addr), + np->rx_buf_sz, DMA_FROM_DEVICE); + dev_kfree_skb(skb); + np->rx_skbuff[i] = NULL; + } + np->rx_ring[i].frag.addr = cpu_to_le32(0xBADF00D0); /* poison */ + } + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].next_desc = 0; + skb = np->tx_skbuff[i]; + if (skb) { + dma_unmap_single(&np->pci_dev->dev, + le32_to_cpu(np->tx_ring[i].frag.addr), + skb->len, DMA_TO_DEVICE); + dev_kfree_skb(skb); + np->tx_skbuff[i] = NULL; + } + } + + return 0; +} + +static void sundance_remove1(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct netdev_private *np = netdev_priv(dev); + unregister_netdev(dev); + dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, + np->rx_ring, np->rx_ring_dma); + dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, + np->tx_ring, np->tx_ring_dma); + pci_iounmap(pdev, np->base); + pci_release_regions(pdev); + free_netdev(dev); + } +} + +static int __maybe_unused sundance_suspend(struct device *dev_d) +{ + struct net_device *dev = dev_get_drvdata(dev_d); + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base; + + if (!netif_running(dev)) + return 0; + + netdev_close(dev); + netif_device_detach(dev); + + if (np->wol_enabled) { + iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); + iowrite16(RxEnable, ioaddr + MACCtrl1); + } + + device_set_wakeup_enable(dev_d, np->wol_enabled); + + return 0; +} + +static int __maybe_unused sundance_resume(struct device *dev_d) +{ + struct net_device *dev = dev_get_drvdata(dev_d); + int err = 0; + + if (!netif_running(dev)) + return 0; + + err = netdev_open(dev); + if (err) { + printk(KERN_ERR "%s: Can't resume interface!\n", + dev->name); + goto out; + } + + netif_device_attach(dev); + +out: + return err; +} + +static SIMPLE_DEV_PM_OPS(sundance_pm_ops, sundance_suspend, sundance_resume); + +static struct pci_driver sundance_driver = { + .name = DRV_NAME, + .id_table = sundance_pci_tbl, + .probe = sundance_probe1, + .remove = sundance_remove1, + .driver.pm = &sundance_pm_ops, +}; + +module_pci_driver(sundance_driver); From d2644cbc736f737142a7595fa9346f63e6fc9b33 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 1 Sep 2025 14:08:18 -0700 Subject: [PATCH 1103/1292] eth: sundance: fix endian issues Fix sparse warnings about endianness. Store DMA addr to a variable of correct type and then only convert it when writing to the descriptor. Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250901210818.1025316-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/dlink/sundance.c | 35 +++++++++++++++------------ 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c index 29d59c42dfa37e..277c50ef773fbc 100644 --- a/drivers/net/ethernet/dlink/sundance.c +++ b/drivers/net/ethernet/dlink/sundance.c @@ -1033,21 +1033,22 @@ static void init_ring(struct net_device *dev) /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { + dma_addr_t addr; + struct sk_buff *skb = netdev_alloc_skb(dev, np->rx_buf_sz + 2); np->rx_skbuff[i] = skb; if (skb == NULL) break; skb_reserve(skb, 2); /* 16 byte align the IP header. */ - np->rx_ring[i].frag.addr = cpu_to_le32( - dma_map_single(&np->pci_dev->dev, skb->data, - np->rx_buf_sz, DMA_FROM_DEVICE)); - if (dma_mapping_error(&np->pci_dev->dev, - np->rx_ring[i].frag.addr)) { + addr = dma_map_single(&np->pci_dev->dev, skb->data, + np->rx_buf_sz, DMA_FROM_DEVICE); + if (dma_mapping_error(&np->pci_dev->dev, addr)) { dev_kfree_skb(skb); np->rx_skbuff[i] = NULL; break; } + np->rx_ring[i].frag.addr = cpu_to_le32(addr); np->rx_ring[i].frag.length = cpu_to_le32(np->rx_buf_sz | LastFrag); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1088,6 +1089,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); struct netdev_desc *txdesc; + dma_addr_t addr; unsigned entry; /* Calculate the next Tx descriptor entry. */ @@ -1095,13 +1097,14 @@ start_tx (struct sk_buff *skb, struct net_device *dev) np->tx_skbuff[entry] = skb; txdesc = &np->tx_ring[entry]; + addr = dma_map_single(&np->pci_dev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(&np->pci_dev->dev, addr)) + goto drop_frame; + txdesc->next_desc = 0; txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign); - txdesc->frag.addr = cpu_to_le32(dma_map_single(&np->pci_dev->dev, - skb->data, skb->len, DMA_TO_DEVICE)); - if (dma_mapping_error(&np->pci_dev->dev, - txdesc->frag.addr)) - goto drop_frame; + txdesc->frag.addr = cpu_to_le32(addr); txdesc->frag.length = cpu_to_le32 (skb->len | LastFrag); /* Increment cur_tx before tasklet_schedule() */ @@ -1419,6 +1422,8 @@ static void refill_rx (struct net_device *dev) for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0; np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) { struct sk_buff *skb; + dma_addr_t addr; + entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { skb = netdev_alloc_skb(dev, np->rx_buf_sz + 2); @@ -1426,15 +1431,15 @@ static void refill_rx (struct net_device *dev) if (skb == NULL) break; /* Better luck next round. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - np->rx_ring[entry].frag.addr = cpu_to_le32( - dma_map_single(&np->pci_dev->dev, skb->data, - np->rx_buf_sz, DMA_FROM_DEVICE)); - if (dma_mapping_error(&np->pci_dev->dev, - np->rx_ring[entry].frag.addr)) { + addr = dma_map_single(&np->pci_dev->dev, skb->data, + np->rx_buf_sz, DMA_FROM_DEVICE); + if (dma_mapping_error(&np->pci_dev->dev, addr)) { dev_kfree_skb_irq(skb); np->rx_skbuff[entry] = NULL; break; } + + np->rx_ring[entry].frag.addr = cpu_to_le32(addr); } /* Perhaps we need not reset this field. */ np->rx_ring[entry].frag.length = From fa390321aba0a54d0f7ae95ee4ecde1358bb9234 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Sat, 30 Aug 2025 15:55:38 -0700 Subject: [PATCH 1104/1292] net/tcp: Fix socket memory leak in TCP-AO failure handling for IPv6 When tcp_ao_copy_all_matching() fails in tcp_v6_syn_recv_sock() it just exits the function. This ends up causing a memory-leak: unreferenced object 0xffff0000281a8200 (size 2496): comm "softirq", pid 0, jiffies 4295174684 hex dump (first 32 bytes): 7f 00 00 06 7f 00 00 06 00 00 00 00 cb a8 88 13 ................ 0a 00 03 61 00 00 00 00 00 00 00 00 00 00 00 00 ...a............ backtrace (crc 5ebdbe15): kmemleak_alloc+0x44/0xe0 kmem_cache_alloc_noprof+0x248/0x470 sk_prot_alloc+0x48/0x120 sk_clone_lock+0x38/0x3b0 inet_csk_clone_lock+0x34/0x150 tcp_create_openreq_child+0x3c/0x4a8 tcp_v6_syn_recv_sock+0x1c0/0x620 tcp_check_req+0x588/0x790 tcp_v6_rcv+0x5d0/0xc18 ip6_protocol_deliver_rcu+0x2d8/0x4c0 ip6_input_finish+0x74/0x148 ip6_input+0x50/0x118 ip6_sublist_rcv+0x2fc/0x3b0 ipv6_list_rcv+0x114/0x170 __netif_receive_skb_list_core+0x16c/0x200 netif_receive_skb_list_internal+0x1f0/0x2d0 This is because in tcp_v6_syn_recv_sock (and the IPv4 counterpart), when exiting upon error, inet_csk_prepare_forced_close() and tcp_done() need to be called. They make sure the newsk will end up being correctly free'd. tcp_v4_syn_recv_sock() makes this very clear by having the put_and_exit label that takes care of things. So, this patch here makes sure tcp_v4_syn_recv_sock and tcp_v6_syn_recv_sock have similar error-handling and thus fixes the leak for TCP-AO. Fixes: 06b22ef29591 ("net/tcp: Wire TCP-AO to request sockets") Signed-off-by: Christoph Paasch Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Link: https://patch.msgid.link/20250830-tcpao_leak-v1-1-e5878c2c3173@openai.com Signed-off-by: Jakub Kicinski --- net/ipv6/tcp_ipv6.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7577e7eb2c97b8..e885629312a4a7 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1431,17 +1431,17 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * ireq = inet_rsk(req); if (sk_acceptq_is_full(sk)) - goto out_overflow; + goto exit_overflow; if (!dst) { dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_TCP); if (!dst) - goto out; + goto exit; } newsk = tcp_create_openreq_child(sk, req, skb); if (!newsk) - goto out_nonewsk; + goto exit_nonewsk; /* * No need to charge this sock to the relevant IPv6 refcnt debug socks @@ -1525,25 +1525,19 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * const union tcp_md5_addr *addr; addr = (union tcp_md5_addr *)&newsk->sk_v6_daddr; - if (tcp_md5_key_copy(newsk, addr, AF_INET6, 128, l3index, key)) { - inet_csk_prepare_forced_close(newsk); - tcp_done(newsk); - goto out; - } + if (tcp_md5_key_copy(newsk, addr, AF_INET6, 128, l3index, key)) + goto put_and_exit; } } #endif #ifdef CONFIG_TCP_AO /* Copy over tcp_ao_info if any */ if (tcp_ao_copy_all_matching(sk, newsk, req, skb, AF_INET6)) - goto out; /* OOM */ + goto put_and_exit; /* OOM */ #endif - if (__inet_inherit_port(sk, newsk) < 0) { - inet_csk_prepare_forced_close(newsk); - tcp_done(newsk); - goto out; - } + if (__inet_inherit_port(sk, newsk) < 0) + goto put_and_exit; *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), &found_dup_sk); if (*own_req) { @@ -1570,13 +1564,17 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * return newsk; -out_overflow: +exit_overflow: __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); -out_nonewsk: +exit_nonewsk: dst_release(dst); -out: +exit: tcp_listendrop(sk); return NULL; +put_and_exit: + inet_csk_prepare_forced_close(newsk); + tcp_done(newsk); + goto exit; } INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *, From 4beb44a2d62dddfe450f310aa1a950901731cb3a Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 31 Aug 2025 18:34:33 +0100 Subject: [PATCH 1105/1292] net: phy: add phy_interface_weight() Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1uslwn-00000001SOx-0a7H@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- include/linux/phy.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/phy.h b/include/linux/phy.h index 4c2b8b6e718792..bb45787d868484 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -169,6 +169,11 @@ static inline bool phy_interface_empty(const unsigned long *intf) return bitmap_empty(intf, PHY_INTERFACE_MODE_MAX); } +static inline unsigned int phy_interface_weight(const unsigned long *intf) +{ + return bitmap_weight(intf, PHY_INTERFACE_MODE_MAX); +} + static inline void phy_interface_and(unsigned long *dst, const unsigned long *a, const unsigned long *b) { From 1bd905dfea9897eafef532000702e63a66849f54 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 31 Aug 2025 18:34:38 +0100 Subject: [PATCH 1106/1292] net: phylink: provide phylink_get_inband_type() Provide a function to get the type of the inband signalling used for a PHY interface type. This will be used in the subsequent patch to address problems with 10G optical modules. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1uslws-00000001SP5-1R2R@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 79 ++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index c7f867b361dda8..8283416ccf5d20 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1016,6 +1016,42 @@ static void phylink_pcs_an_restart(struct phylink *pl) pl->pcs->ops->pcs_an_restart(pl->pcs); } +enum inband_type { + INBAND_NONE, + INBAND_CISCO_SGMII, + INBAND_BASEX, +}; + +static enum inband_type phylink_get_inband_type(phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_QUSGMII: + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_10G_QXGMII: + /* These protocols are designed for use with a PHY which + * communicates its negotiation result back to the MAC via + * inband communication. Note: there exist PHYs that run + * with SGMII but do not send the inband data. + */ + return INBAND_CISCO_SGMII; + + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + /* 1000base-X is designed for use media-side for Fibre + * connections, and thus the Autoneg bit needs to be + * taken into account. We also do this for 2500base-X + * as well, but drivers may not support this, so may + * need to override this. + */ + return INBAND_BASEX; + + default: + return INBAND_NONE; + } +} + /** * phylink_pcs_neg_mode() - helper to determine PCS inband mode * @pl: a pointer to a &struct phylink returned from phylink_create() @@ -1043,46 +1079,19 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, unsigned int pcs_ib_caps = 0; unsigned int phy_ib_caps = 0; unsigned int neg_mode, mode; - enum { - INBAND_CISCO_SGMII, - INBAND_BASEX, - } type; - - mode = pl->req_link_an_mode; + enum inband_type type; - pl->phy_ib_mode = 0; - - switch (interface) { - case PHY_INTERFACE_MODE_SGMII: - case PHY_INTERFACE_MODE_QSGMII: - case PHY_INTERFACE_MODE_QUSGMII: - case PHY_INTERFACE_MODE_USXGMII: - case PHY_INTERFACE_MODE_10G_QXGMII: - /* These protocols are designed for use with a PHY which - * communicates its negotiation result back to the MAC via - * inband communication. Note: there exist PHYs that run - * with SGMII but do not send the inband data. - */ - type = INBAND_CISCO_SGMII; - break; - - case PHY_INTERFACE_MODE_1000BASEX: - case PHY_INTERFACE_MODE_2500BASEX: - /* 1000base-X is designed for use media-side for Fibre - * connections, and thus the Autoneg bit needs to be - * taken into account. We also do this for 2500base-X - * as well, but drivers may not support this, so may - * need to override this. - */ - type = INBAND_BASEX; - break; - - default: + type = phylink_get_inband_type(interface); + if (type == INBAND_NONE) { pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE; - pl->act_link_an_mode = mode; + pl->act_link_an_mode = pl->req_link_an_mode; return; } + mode = pl->req_link_an_mode; + + pl->phy_ib_mode = 0; + if (pcs) pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface); From a21202743f9ce4063e86b99cccaef48ef9813379 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 31 Aug 2025 18:34:43 +0100 Subject: [PATCH 1107/1292] net: phylink: disable autoneg for interfaces that have no inband Mathew reports that as a result of commit 6561f0e547be ("net: pcs: pcs-lynx: implement pcs_inband_caps() method"), 10G SFP modules no longer work with the Lynx PCS. This problem is not specific to the Lynx PCS, but is caused by commit df874f9e52c3 ("net: phylink: add pcs_inband_caps() method") which added validation of the autoneg state to the optical SFP configuration path. Fix this by handling interface modes that fundamentally have no inband negotiation more correctly - if we only have a single interface mode, clear the Autoneg support bit and the advertising mask. If the module can operate with several different interface modes, autoneg may be supported for other modes, so leave the support mask alone and just clear the Autoneg bit in the advertising mask. This restores 10G optical module functionality with PCS that supply their inband support, and makes ethtool output look sane. Reported-by: Mathew McBride Closes: https://lore.kernel.org/r/025c0ebe-5537-4fa3-b05a-8b835e5ad317@app.fastmail.com Fixes: df874f9e52c3 ("net: phylink: add pcs_inband_caps() method") Signed-off-by: Russell King (Oracle) Tested-by: Vladimir Oltean Link: https://patch.msgid.link/E1uslwx-00000001SPB-2kiM@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 8283416ccf5d20..f1b57e3fdf30c3 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -3634,6 +3634,7 @@ static int phylink_sfp_config_optical(struct phylink *pl) { __ETHTOOL_DECLARE_LINK_MODE_MASK(support); struct phylink_link_state config; + enum inband_type inband_type; phy_interface_t interface; int ret; @@ -3680,6 +3681,23 @@ static int phylink_sfp_config_optical(struct phylink *pl) phylink_dbg(pl, "optical SFP: chosen %s interface\n", phy_modes(interface)); + inband_type = phylink_get_inband_type(interface); + if (inband_type == INBAND_NONE) { + /* If this is the sole interface, and there is no inband + * support, clear the advertising mask and Autoneg bit in + * the support mask. Otherwise, just clear the Autoneg bit + * in the advertising mask. + */ + if (phy_interface_weight(pl->sfp_interfaces) == 1) { + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + pl->sfp_support); + linkmode_zero(config.advertising); + } else { + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + config.advertising); + } + } + if (!phylink_validate_pcs_inband_autoneg(pl, interface, config.advertising)) { phylink_err(pl, "autoneg setting not compatible with PCS"); From d4736737110ffa83d29f1c5d17b26113864205f6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 31 Aug 2025 20:20:07 +0200 Subject: [PATCH 1108/1292] net: ethernet: mtk_eth_soc: fix tx vlan tag for llc packets When sending llc packets with vlan tx offload, the hardware fails to actually add the tag. Deal with this by fixing it up in software. Fixes: 656e705243fd ("net-next: mediatek: add support for MT7623 ethernet") Reported-by: Thibaut VARENE Signed-off-by: Felix Fietkau Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250831182007.51619-1-nbd@nbd.name Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 5a5fcde76dc0e7..e68997a29191b2 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1761,6 +1761,13 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) bool gso = false; int tx_num; + if (skb_vlan_tag_present(skb) && + !eth_proto_is_802_3(eth_hdr(skb)->h_proto)) { + skb = __vlan_hwaccel_push_inside(skb); + if (!skb) + goto dropped; + } + /* normally we can rely on the stack not calling this more than once, * however we have 2 queues running on the same ring so we need to lock * the ring access @@ -1806,8 +1813,9 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) drop: spin_unlock(ð->page_lock); - stats->tx_dropped++; dev_kfree_skb_any(skb); +dropped: + stats->tx_dropped++; return NETDEV_TX_OK; } From a7195a3d67dace056af7ca65144a11874df79562 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 1 Sep 2025 12:20:19 +0100 Subject: [PATCH 1109/1292] net: pcs: rzn1-miic: Correct MODCTRL register offset Correct the Mode Control Register (MODCTRL) offset for RZ/N MIIC. According to the R-IN Engine and Ethernet Peripherals Manual (Rev.1.30) [0], Table 10.1 "Ethernet Accessory Register List", MODCTRL is at offset 0x8, not 0x20 as previously defined. Offset 0x20 actually maps to the Port Trigger Control Register (PTCTRL), which controls PTP_MODE[3:0] and RGMII_CLKSEL[4]. Using this incorrect definition prevented the driver from configuring the SW_MODE[4:0] bits in MODCTRL, which control the internal connection of Ethernet ports. As a result, the MIIC could not be switched into the correct mode, leading to link setup failures and non-functional Ethernet ports on affected systems. [0] https://www.renesas.com/en/document/mah/rzn1d-group-rzn1s-group-rzn1l-group-users-manual-r-engine-and-ethernet-peripherals?r=1054571 Fixes: 7dc54d3b8d91 ("net: pcs: add Renesas MII converter driver") Cc: stable@kernel.org Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Russell King (Oracle) Reviewed-by: Geert Uytterhoeven Tested-by: Wolfram Sang Link: https://patch.msgid.link/20250901112019.16278-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-rzn1-miic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c index d79bb9b06cd22f..ce73d9474d5bfd 100644 --- a/drivers/net/pcs/pcs-rzn1-miic.c +++ b/drivers/net/pcs/pcs-rzn1-miic.c @@ -19,7 +19,7 @@ #define MIIC_PRCMD 0x0 #define MIIC_ESID_CODE 0x4 -#define MIIC_MODCTRL 0x20 +#define MIIC_MODCTRL 0x8 #define MIIC_MODCTRL_SW_MODE GENMASK(4, 0) #define MIIC_CONVCTRL(port) (0x100 + (port) * 4) From 6ead38147ebb813f08be6ea8ef547a0e4c09559a Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 1 Sep 2025 09:50:33 +0300 Subject: [PATCH 1110/1292] vxlan: Fix NPD when refreshing an FDB entry with a nexthop object VXLAN FDB entries can point to either a remote destination or an FDB nexthop group. The latter is usually used in EVPN deployments where learning is disabled. However, when learning is enabled, an incoming packet might try to refresh an FDB entry that points to an FDB nexthop group and therefore does not have a remote. Such packets should be dropped, but they are only dropped after dereferencing the non-existent remote, resulting in a NPD [1] which can be reproduced using [2]. Fix by dropping such packets earlier. Remove the misleading comment from first_remote_rcu(). [1] BUG: kernel NULL pointer dereference, address: 0000000000000000 [...] CPU: 13 UID: 0 PID: 361 Comm: mausezahn Not tainted 6.17.0-rc1-virtme-g9f6b606b6b37 #1 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-4.fc41 04/01/2014 RIP: 0010:vxlan_snoop+0x98/0x1e0 [...] Call Trace: vxlan_encap_bypass+0x209/0x240 encap_bypass_if_local+0xb1/0x100 vxlan_xmit_one+0x1375/0x17e0 vxlan_xmit+0x6b4/0x15f0 dev_hard_start_xmit+0x5d/0x1c0 __dev_queue_xmit+0x246/0xfd0 packet_sendmsg+0x113a/0x1850 __sock_sendmsg+0x38/0x70 __sys_sendto+0x126/0x180 __x64_sys_sendto+0x24/0x30 do_syscall_64+0xa4/0x260 entry_SYSCALL_64_after_hwframe+0x4b/0x53 [2] #!/bin/bash ip address add 192.0.2.1/32 dev lo ip address add 192.0.2.2/32 dev lo ip nexthop add id 1 via 192.0.2.3 fdb ip nexthop add id 10 group 1 fdb ip link add name vx0 up type vxlan id 10010 local 192.0.2.1 dstport 12345 localbypass ip link add name vx1 up type vxlan id 10020 local 192.0.2.2 dstport 54321 learning bridge fdb add 00:11:22:33:44:55 dev vx0 self static dst 192.0.2.2 port 54321 vni 10020 bridge fdb add 00:aa:bb:cc:dd:ee dev vx1 self static nhid 10 mausezahn vx0 -a 00:aa:bb:cc:dd:ee -b 00:11:22:33:44:55 -c 1 -q Fixes: 1274e1cc4226 ("vxlan: ecmp support for mac fdb entries") Reported-by: Marlin Cremers Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250901065035.159644-2-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/vxlan/vxlan_core.c | 8 ++++---- drivers/net/vxlan/vxlan_private.h | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index f32be2e301f265..0f6a7c89a66948 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1445,6 +1445,10 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev, if (READ_ONCE(f->updated) != now) WRITE_ONCE(f->updated, now); + /* Don't override an fdb with nexthop with a learnt entry */ + if (rcu_access_pointer(f->nh)) + return SKB_DROP_REASON_VXLAN_ENTRY_EXISTS; + if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) && rdst->remote_ifindex == ifindex)) return SKB_NOT_DROPPED_YET; @@ -1453,10 +1457,6 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev, if (f->state & (NUD_PERMANENT | NUD_NOARP)) return SKB_DROP_REASON_VXLAN_ENTRY_EXISTS; - /* Don't override an fdb with nexthop with a learnt entry */ - if (rcu_access_pointer(f->nh)) - return SKB_DROP_REASON_VXLAN_ENTRY_EXISTS; - if (net_ratelimit()) netdev_info(dev, "%pM migrated from %pIS to %pIS\n", diff --git a/drivers/net/vxlan/vxlan_private.h b/drivers/net/vxlan/vxlan_private.h index 6c625fb29c6cea..99fe772ad6791e 100644 --- a/drivers/net/vxlan/vxlan_private.h +++ b/drivers/net/vxlan/vxlan_private.h @@ -61,9 +61,7 @@ static inline struct hlist_head *vs_head(struct net *net, __be16 port) return &vn->sock_list[hash_32(ntohs(port), PORT_HASH_BITS)]; } -/* First remote destination for a forwarding entry. - * Guaranteed to be non-NULL because remotes are never deleted. - */ +/* First remote destination for a forwarding entry. */ static inline struct vxlan_rdst *first_remote_rcu(struct vxlan_fdb *fdb) { if (rcu_access_pointer(fdb->nh)) From 1f5d2fd1ca04a23c18b1bde9a43ce2fa2ffa1bce Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 1 Sep 2025 09:50:34 +0300 Subject: [PATCH 1111/1292] vxlan: Fix NPD in {arp,neigh}_reduce() when using nexthop objects When the "proxy" option is enabled on a VXLAN device, the device will suppress ARP requests and IPv6 Neighbor Solicitation messages if it is able to reply on behalf of the remote host. That is, if a matching and valid neighbor entry is configured on the VXLAN device whose MAC address is not behind the "any" remote (0.0.0.0 / ::). The code currently assumes that the FDB entry for the neighbor's MAC address points to a valid remote destination, but this is incorrect if the entry is associated with an FDB nexthop group. This can result in a NPD [1][3] which can be reproduced using [2][4]. Fix by checking that the remote destination exists before dereferencing it. [1] BUG: kernel NULL pointer dereference, address: 0000000000000000 [...] CPU: 4 UID: 0 PID: 365 Comm: arping Not tainted 6.17.0-rc2-virtme-g2a89cb21162c #2 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-4.fc41 04/01/2014 RIP: 0010:vxlan_xmit+0xb58/0x15f0 [...] Call Trace: dev_hard_start_xmit+0x5d/0x1c0 __dev_queue_xmit+0x246/0xfd0 packet_sendmsg+0x113a/0x1850 __sock_sendmsg+0x38/0x70 __sys_sendto+0x126/0x180 __x64_sys_sendto+0x24/0x30 do_syscall_64+0xa4/0x260 entry_SYSCALL_64_after_hwframe+0x4b/0x53 [2] #!/bin/bash ip address add 192.0.2.1/32 dev lo ip nexthop add id 1 via 192.0.2.2 fdb ip nexthop add id 10 group 1 fdb ip link add name vx0 up type vxlan id 10010 local 192.0.2.1 dstport 4789 proxy ip neigh add 192.0.2.3 lladdr 00:11:22:33:44:55 nud perm dev vx0 bridge fdb add 00:11:22:33:44:55 dev vx0 self static nhid 10 arping -b -c 1 -s 192.0.2.1 -I vx0 192.0.2.3 [3] BUG: kernel NULL pointer dereference, address: 0000000000000000 [...] CPU: 13 UID: 0 PID: 372 Comm: ndisc6 Not tainted 6.17.0-rc2-virtmne-g6ee90cb26014 #3 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1v996), BIOS 1.17.0-4.fc41 04/01/2x014 RIP: 0010:vxlan_xmit+0x803/0x1600 [...] Call Trace: dev_hard_start_xmit+0x5d/0x1c0 __dev_queue_xmit+0x246/0xfd0 ip6_finish_output2+0x210/0x6c0 ip6_finish_output+0x1af/0x2b0 ip6_mr_output+0x92/0x3e0 ip6_send_skb+0x30/0x90 rawv6_sendmsg+0xe6e/0x12e0 __sock_sendmsg+0x38/0x70 __sys_sendto+0x126/0x180 __x64_sys_sendto+0x24/0x30 do_syscall_64+0xa4/0x260 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x7f383422ec77 [4] #!/bin/bash ip address add 2001:db8:1::1/128 dev lo ip nexthop add id 1 via 2001:db8:1::1 fdb ip nexthop add id 10 group 1 fdb ip link add name vx0 up type vxlan id 10010 local 2001:db8:1::1 dstport 4789 proxy ip neigh add 2001:db8:1::3 lladdr 00:11:22:33:44:55 nud perm dev vx0 bridge fdb add 00:11:22:33:44:55 dev vx0 self static nhid 10 ndisc6 -r 1 -s 2001:db8:1::1 -w 1 2001:db8:1::3 vx0 Fixes: 1274e1cc4226 ("vxlan: ecmp support for mac fdb entries") Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250901065035.159644-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/vxlan/vxlan_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 0f6a7c89a66948..dab864bc733c25 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1877,6 +1877,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) n = neigh_lookup(&arp_tbl, &tip, dev); if (n) { + struct vxlan_rdst *rdst = NULL; struct vxlan_fdb *f; struct sk_buff *reply; @@ -1887,7 +1888,9 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) rcu_read_lock(); f = vxlan_find_mac_tx(vxlan, n->ha, vni); - if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) { + if (f) + rdst = first_remote_rcu(f); + if (rdst && vxlan_addr_any(&rdst->remote_ip)) { /* bridge-local neighbor */ neigh_release(n); rcu_read_unlock(); @@ -2044,6 +2047,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) n = neigh_lookup(ipv6_stub->nd_tbl, &msg->target, dev); if (n) { + struct vxlan_rdst *rdst = NULL; struct vxlan_fdb *f; struct sk_buff *reply; @@ -2053,7 +2057,9 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) } f = vxlan_find_mac_tx(vxlan, n->ha, vni); - if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) { + if (f) + rdst = first_remote_rcu(f); + if (rdst && vxlan_addr_any(&rdst->remote_ip)) { /* bridge-local neighbor */ neigh_release(n); goto out; From 2c9fb925c2ccc6ee475134840cff6c6b73851730 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 1 Sep 2025 09:50:35 +0300 Subject: [PATCH 1112/1292] selftests: net: Add a selftest for VXLAN with FDB nexthop groups Add test cases for VXLAN with FDB nexthop groups, testing both IPv4 and IPv6. Test basic Tx functionality as well as some corner cases. Example output: # ./test_vxlan_nh.sh TEST: VXLAN FDB nexthop: IPv4 basic Tx [ OK ] TEST: VXLAN FDB nexthop: IPv6 basic Tx [ OK ] TEST: VXLAN FDB nexthop: learning [ OK ] TEST: VXLAN FDB nexthop: IPv4 proxy [ OK ] TEST: VXLAN FDB nexthop: IPv6 proxy [ OK ] Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Link: https://patch.msgid.link/20250901065035.159644-4-idosch@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/test_vxlan_nh.sh | 223 +++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100755 tools/testing/selftests/net/test_vxlan_nh.sh diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index b31a71f2b37295..c7e03e1d6f63bb 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -99,6 +99,7 @@ TEST_GEN_PROGS += bind_wildcard TEST_GEN_PROGS += bind_timewait TEST_PROGS += test_vxlan_mdb.sh TEST_PROGS += test_bridge_neigh_suppress.sh +TEST_PROGS += test_vxlan_nh.sh TEST_PROGS += test_vxlan_nolocalbypass.sh TEST_PROGS += test_bridge_backup_port.sh TEST_PROGS += test_neigh.sh diff --git a/tools/testing/selftests/net/test_vxlan_nh.sh b/tools/testing/selftests/net/test_vxlan_nh.sh new file mode 100755 index 00000000000000..20f3369f776b15 --- /dev/null +++ b/tools/testing/selftests/net/test_vxlan_nh.sh @@ -0,0 +1,223 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +source lib.sh +TESTS=" + basic_tx_ipv4 + basic_tx_ipv6 + learning + proxy_ipv4 + proxy_ipv6 +" +VERBOSE=0 + +################################################################################ +# Utilities + +run_cmd() +{ + local cmd="$1" + local out + local stderr="2>/dev/null" + + if [ "$VERBOSE" = "1" ]; then + echo "COMMAND: $cmd" + stderr= + fi + + out=$(eval "$cmd" "$stderr") + rc=$? + if [ "$VERBOSE" -eq 1 ] && [ -n "$out" ]; then + echo " $out" + fi + + return $rc +} + +################################################################################ +# Cleanup + +exit_cleanup_all() +{ + cleanup_all_ns + exit "${EXIT_STATUS}" +} + +################################################################################ +# Tests + +nh_stats_get() +{ + ip -n "$ns1" -s -j nexthop show id 10 | jq ".[][\"group_stats\"][][\"packets\"]" +} + +tc_stats_get() +{ + tc_rule_handle_stats_get "dev dummy1 egress" 101 ".packets" "-n $ns1" +} + +basic_tx_common() +{ + local af_str=$1; shift + local proto=$1; shift + local local_addr=$1; shift + local plen=$1; shift + local remote_addr=$1; shift + + RET=0 + + # Test basic Tx functionality. Check that stats are incremented on + # both the FDB nexthop group and the egress device. + + run_cmd "ip -n $ns1 link add name dummy1 up type dummy" + run_cmd "ip -n $ns1 route add $remote_addr/$plen dev dummy1" + run_cmd "tc -n $ns1 qdisc add dev dummy1 clsact" + run_cmd "tc -n $ns1 filter add dev dummy1 egress proto $proto pref 1 handle 101 flower ip_proto udp dst_ip $remote_addr dst_port 4789 action pass" + + run_cmd "ip -n $ns1 address add $local_addr/$plen dev lo" + + run_cmd "ip -n $ns1 nexthop add id 1 via $remote_addr fdb" + run_cmd "ip -n $ns1 nexthop add id 10 group 1 fdb" + + run_cmd "ip -n $ns1 link add name vx0 up type vxlan id 10010 local $local_addr dstport 4789" + run_cmd "bridge -n $ns1 fdb add 00:11:22:33:44:55 dev vx0 self static nhid 10" + + run_cmd "ip netns exec $ns1 mausezahn vx0 -a own -b 00:11:22:33:44:55 -c 1 -q" + + busywait "$BUSYWAIT_TIMEOUT" until_counter_is "== 1" nh_stats_get > /dev/null + check_err $? "FDB nexthop group stats did not increase" + + busywait "$BUSYWAIT_TIMEOUT" until_counter_is "== 1" tc_stats_get > /dev/null + check_err $? "tc filter stats did not increase" + + log_test "VXLAN FDB nexthop: $af_str basic Tx" +} + +basic_tx_ipv4() +{ + basic_tx_common "IPv4" ipv4 192.0.2.1 32 192.0.2.2 +} + +basic_tx_ipv6() +{ + basic_tx_common "IPv6" ipv6 2001:db8:1::1 128 2001:db8:1::2 +} + +learning() +{ + RET=0 + + # When learning is enabled on the VXLAN device, an incoming packet + # might try to refresh an FDB entry that points to an FDB nexthop group + # instead of an ordinary remote destination. Check that the kernel does + # not crash in this situation. + + run_cmd "ip -n $ns1 address add 192.0.2.1/32 dev lo" + run_cmd "ip -n $ns1 address add 192.0.2.2/32 dev lo" + + run_cmd "ip -n $ns1 nexthop add id 1 via 192.0.2.3 fdb" + run_cmd "ip -n $ns1 nexthop add id 10 group 1 fdb" + + run_cmd "ip -n $ns1 link add name vx0 up type vxlan id 10010 local 192.0.2.1 dstport 12345 localbypass" + run_cmd "ip -n $ns1 link add name vx1 up type vxlan id 10020 local 192.0.2.2 dstport 54321 learning" + + run_cmd "bridge -n $ns1 fdb add 00:11:22:33:44:55 dev vx0 self static dst 192.0.2.2 port 54321 vni 10020" + run_cmd "bridge -n $ns1 fdb add 00:aa:bb:cc:dd:ee dev vx1 self static nhid 10" + + run_cmd "ip netns exec $ns1 mausezahn vx0 -a 00:aa:bb:cc:dd:ee -b 00:11:22:33:44:55 -c 1 -q" + + log_test "VXLAN FDB nexthop: learning" +} + +proxy_common() +{ + local af_str=$1; shift + local local_addr=$1; shift + local plen=$1; shift + local remote_addr=$1; shift + local neigh_addr=$1; shift + local ping_cmd=$1; shift + + RET=0 + + # When the "proxy" option is enabled on the VXLAN device, the device + # will suppress ARP requests and IPv6 Neighbor Solicitation messages if + # it is able to reply on behalf of the remote host. That is, if a + # matching and valid neighbor entry is configured on the VXLAN device + # whose MAC address is not behind the "any" remote (0.0.0.0 / ::). The + # FDB entry for the neighbor's MAC address might point to an FDB + # nexthop group instead of an ordinary remote destination. Check that + # the kernel does not crash in this situation. + + run_cmd "ip -n $ns1 address add $local_addr/$plen dev lo" + + run_cmd "ip -n $ns1 nexthop add id 1 via $remote_addr fdb" + run_cmd "ip -n $ns1 nexthop add id 10 group 1 fdb" + + run_cmd "ip -n $ns1 link add name vx0 up type vxlan id 10010 local $local_addr dstport 4789 proxy" + + run_cmd "ip -n $ns1 neigh add $neigh_addr lladdr 00:11:22:33:44:55 nud perm dev vx0" + + run_cmd "bridge -n $ns1 fdb add 00:11:22:33:44:55 dev vx0 self static nhid 10" + + run_cmd "ip netns exec $ns1 $ping_cmd" + + log_test "VXLAN FDB nexthop: $af_str proxy" +} + +proxy_ipv4() +{ + proxy_common "IPv4" 192.0.2.1 32 192.0.2.2 192.0.2.3 \ + "arping -b -c 1 -s 192.0.2.1 -I vx0 192.0.2.3" +} + +proxy_ipv6() +{ + proxy_common "IPv6" 2001:db8:1::1 128 2001:db8:1::2 2001:db8:1::3 \ + "ndisc6 -r 1 -s 2001:db8:1::1 -w 1 2001:db8:1::3 vx0" +} + +################################################################################ +# Usage + +usage() +{ + cat < Test(s) to run (default: all) + (options: $TESTS) + -p Pause on fail + -v Verbose mode (show commands and output) +EOF +} + +################################################################################ +# Main + +while getopts ":t:pvh" opt; do + case $opt in + t) TESTS=$OPTARG;; + p) PAUSE_ON_FAIL=yes;; + v) VERBOSE=$((VERBOSE + 1));; + h) usage; exit 0;; + *) usage; exit 1;; + esac +done + +require_command mausezahn +require_command arping +require_command ndisc6 +require_command jq + +if ! ip nexthop help 2>&1 | grep -q "stats"; then + echo "SKIP: iproute2 ip too old, missing nexthop stats support" + exit "$ksft_skip" +fi + +trap exit_cleanup_all EXIT + +for t in $TESTS +do + setup_ns ns1; $t; cleanup_all_ns; +done From 3a5f55500f3e93cf4d62351c753452279b088b4b Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Mon, 1 Sep 2025 20:37:25 +0800 Subject: [PATCH 1113/1292] ipv6: annotate data-races around devconf->rpl_seg_enabled devconf->rpl_seg_enabled can be changed concurrently from /proc/sys/net/ipv6/conf, annotate lockless reads on it. Signed-off-by: Yue Haibing Link: https://patch.msgid.link/20250901123726.1972881-2-yuehaibing@huawei.com Signed-off-by: Jakub Kicinski --- net/ipv6/exthdrs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index d1ef9644f82629..a23eb8734e151d 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -494,10 +494,8 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) idev = __in6_dev_get(skb->dev); - accept_rpl_seg = net->ipv6.devconf_all->rpl_seg_enabled; - if (accept_rpl_seg > idev->cnf.rpl_seg_enabled) - accept_rpl_seg = idev->cnf.rpl_seg_enabled; - + accept_rpl_seg = min(READ_ONCE(net->ipv6.devconf_all->rpl_seg_enabled), + READ_ONCE(idev->cnf.rpl_seg_enabled)); if (!accept_rpl_seg) { kfree_skb(skb); return -1; From f63e7c8a83892781f6ceb55566f9497639c44555 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 1 Sep 2025 15:32:23 +0800 Subject: [PATCH 1114/1292] net: dsa: mv88e6xxx: Fix fwnode reference leaks in mv88e6xxx_port_setup_leds Fix multiple fwnode reference leaks: 1. The function calls fwnode_get_named_child_node() to get the "leds" node, but never calls fwnode_handle_put(leds) to release this reference. 2. Within the fwnode_for_each_child_node() loop, the early return paths that don't properly release the "led" fwnode reference. This fix follows the same pattern as commit d029edefed39 ("net dsa: qca8k: fix usages of device_get_named_child_node()") Fixes: 94a2a84f5e9e ("net: dsa: mv88e6xxx: Support LED control") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250901073224.2273103-1-linmq006@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/leds.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c index 1c88bfaea46ba6..ab3bc645da5665 100644 --- a/drivers/net/dsa/mv88e6xxx/leds.c +++ b/drivers/net/dsa/mv88e6xxx/leds.c @@ -779,7 +779,8 @@ int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port) continue; if (led_num > 1) { dev_err(dev, "invalid LED specified port %d\n", port); - return -EINVAL; + ret = -EINVAL; + goto err_put_led; } if (led_num == 0) @@ -823,17 +824,25 @@ int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port) init_data.devname_mandatory = true; init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name, port, led_num); - if (!init_data.devicename) - return -ENOMEM; + if (!init_data.devicename) { + ret = -ENOMEM; + goto err_put_led; + } ret = devm_led_classdev_register_ext(dev, l, &init_data); kfree(init_data.devicename); if (ret) { dev_err(dev, "Failed to init LED %d for port %d", led_num, port); - return ret; + goto err_put_led; } } + fwnode_handle_put(leds); return 0; + +err_put_led: + fwnode_handle_put(led); + fwnode_handle_put(leds); + return ret; } From 0c3813d855b2006f021f7b5055f231977a58c784 Mon Sep 17 00:00:00 2001 From: Bharath SM Date: Tue, 2 Sep 2025 00:02:24 +0530 Subject: [PATCH 1115/1292] smb: client: fix spellings in comments correct spellings in comments Signed-off-by: Bharath SM Acked-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French --- fs/smb/client/reparse.c | 2 +- fs/smb/client/smb1ops.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index 7869cec58f529a..10c84c095fe783 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -278,7 +278,7 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, } /* - * For absolute symlinks it is not possible to determinate + * For absolute symlinks it is not possible to determine * if it should point to directory or file. */ if (symname[0] == '/') { diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 893a1ea8c000ac..a02d41d1ce4a3f 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -1005,7 +1005,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, rc = -EOPNOTSUPP; } - /* Fallback to SMB_COM_SETATTR command when absolutelty needed. */ + /* Fallback to SMB_COM_SETATTR command when absolutely needed. */ if (rc == -EOPNOTSUPP) { cifs_dbg(FYI, "calling SetInformation since SetPathInfo for attrs/times not supported by this server\n"); rc = SMBSetInformation(xid, tcon, full_path, @@ -1039,7 +1039,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, cifsFileInfo_put(open_file); /* - * Setting the read-only bit is not honered on non-NT servers when done + * Setting the read-only bit is not honored on non-NT servers when done * via open-semantics. So for setting it, use SMB_COM_SETATTR command. * This command works only after the file is closed, so use it only when * operation was called without the filehandle. From 72595cb6da1841b355644fe8882d60e725205c32 Mon Sep 17 00:00:00 2001 From: Bharath SM Date: Tue, 2 Sep 2025 20:10:25 +0530 Subject: [PATCH 1116/1292] smb: client: add new tracepoint to trace lease break notification Add smb3_lease_break_enter to trace lease break notifications, recording lease state, flags, epoch, and lease key. Align smb3_lease_not_found to use the same payload and print format. Signed-off-by: Bharath SM Acked-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French --- fs/smb/client/smb2misc.c | 19 +++++++++++---- fs/smb/client/smb2pdu.c | 4 ++-- fs/smb/client/trace.h | 52 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index cddf273c14aed7..89d933b4a8bc28 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -614,6 +614,15 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) struct cifs_tcon *tcon; struct cifs_pending_open *open; + /* Trace receipt of lease break request from server */ + trace_smb3_lease_break_enter(le32_to_cpu(rsp->CurrentLeaseState), + le32_to_cpu(rsp->Flags), + le16_to_cpu(rsp->Epoch), + le32_to_cpu(rsp->hdr.Id.SyncId.TreeId), + le64_to_cpu(rsp->hdr.SessionId), + *((u64 *)rsp->LeaseKey), + *((u64 *)&rsp->LeaseKey[8])); + cifs_dbg(FYI, "Checking for lease break\n"); /* If server is a channel, select the primary channel */ @@ -660,10 +669,12 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) spin_unlock(&cifs_tcp_ses_lock); cifs_dbg(FYI, "Can not process lease break - no lease matched\n"); trace_smb3_lease_not_found(le32_to_cpu(rsp->CurrentLeaseState), - le32_to_cpu(rsp->hdr.Id.SyncId.TreeId), - le64_to_cpu(rsp->hdr.SessionId), - *((u64 *)rsp->LeaseKey), - *((u64 *)&rsp->LeaseKey[8])); + le32_to_cpu(rsp->Flags), + le16_to_cpu(rsp->Epoch), + le32_to_cpu(rsp->hdr.Id.SyncId.TreeId), + le64_to_cpu(rsp->hdr.SessionId), + *((u64 *)rsp->LeaseKey), + *((u64 *)&rsp->LeaseKey[8])); return false; } diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 2df93a75e3b8f3..c3b9d3f6210ff9 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -6192,11 +6192,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, please_key_high = (__u64 *)(lease_key+8); if (rc) { cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE); - trace_smb3_lease_err(le32_to_cpu(lease_state), tcon->tid, + trace_smb3_lease_ack_err(le32_to_cpu(lease_state), tcon->tid, ses->Suid, *please_key_low, *please_key_high, rc); cifs_dbg(FYI, "Send error in Lease Break = %d\n", rc); } else - trace_smb3_lease_done(le32_to_cpu(lease_state), tcon->tid, + trace_smb3_lease_ack_done(le32_to_cpu(lease_state), tcon->tid, ses->Suid, *please_key_low, *please_key_high); return rc; diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 93e5b2bb9f28a2..fe0e075bc63c3c 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -1171,8 +1171,54 @@ DEFINE_EVENT(smb3_lease_done_class, smb3_##name, \ __u64 lease_key_high), \ TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high)) -DEFINE_SMB3_LEASE_DONE_EVENT(lease_done); -DEFINE_SMB3_LEASE_DONE_EVENT(lease_not_found); +DEFINE_SMB3_LEASE_DONE_EVENT(lease_ack_done); +/* Tracepoint when a lease break request is received/entered (includes epoch and flags) */ +DECLARE_EVENT_CLASS(smb3_lease_enter_class, + TP_PROTO(__u32 lease_state, + __u32 flags, + __u16 epoch, + __u32 tid, + __u64 sesid, + __u64 lease_key_low, + __u64 lease_key_high), + TP_ARGS(lease_state, flags, epoch, tid, sesid, lease_key_low, lease_key_high), + TP_STRUCT__entry( + __field(__u32, lease_state) + __field(__u32, flags) + __field(__u16, epoch) + __field(__u32, tid) + __field(__u64, sesid) + __field(__u64, lease_key_low) + __field(__u64, lease_key_high) + ), + TP_fast_assign( + __entry->lease_state = lease_state; + __entry->flags = flags; + __entry->epoch = epoch; + __entry->tid = tid; + __entry->sesid = sesid; + __entry->lease_key_low = lease_key_low; + __entry->lease_key_high = lease_key_high; + ), + TP_printk("sid=0x%llx tid=0x%x lease_key=0x%llx%llx lease_state=0x%x flags=0x%x epoch=%u", + __entry->sesid, __entry->tid, __entry->lease_key_high, + __entry->lease_key_low, __entry->lease_state, __entry->flags, __entry->epoch) +) + +#define DEFINE_SMB3_LEASE_ENTER_EVENT(name) \ +DEFINE_EVENT(smb3_lease_enter_class, smb3_##name, \ + TP_PROTO(__u32 lease_state, \ + __u32 flags, \ + __u16 epoch, \ + __u32 tid, \ + __u64 sesid, \ + __u64 lease_key_low, \ + __u64 lease_key_high), \ + TP_ARGS(lease_state, flags, epoch, tid, sesid, lease_key_low, lease_key_high)) + +DEFINE_SMB3_LEASE_ENTER_EVENT(lease_break_enter); +/* Lease not found: reuse lease_enter payload (includes epoch and flags) */ +DEFINE_SMB3_LEASE_ENTER_EVENT(lease_not_found); DECLARE_EVENT_CLASS(smb3_lease_err_class, TP_PROTO(__u32 lease_state, @@ -1213,7 +1259,7 @@ DEFINE_EVENT(smb3_lease_err_class, smb3_##name, \ int rc), \ TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high, rc)) -DEFINE_SMB3_LEASE_ERR_EVENT(lease_err); +DEFINE_SMB3_LEASE_ERR_EVENT(lease_ack_err); DECLARE_EVENT_CLASS(smb3_connect_class, TP_PROTO(char *hostname, From 91be128b496c0de60a7dceb70d34935a29d38bbd Mon Sep 17 00:00:00 2001 From: Bharath SM Date: Tue, 2 Sep 2025 15:28:57 +0530 Subject: [PATCH 1117/1292] smb: client: show negotiated cipher in DebugData Print the negotiated encryption cipher type in DebugData Signed-off-by: Bharath SM Acked-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index edb2e7f7fc23ad..2337cf795db3f8 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -347,6 +347,22 @@ static __always_inline const char *compression_alg_str(__le16 alg) } } +static __always_inline const char *cipher_alg_str(__le16 cipher) +{ + switch (cipher) { + case SMB2_ENCRYPTION_AES128_CCM: + return "AES128-CCM"; + case SMB2_ENCRYPTION_AES128_GCM: + return "AES128-GCM"; + case SMB2_ENCRYPTION_AES256_CCM: + return "AES256-CCM"; + case SMB2_ENCRYPTION_AES256_GCM: + return "AES256-GCM"; + default: + return "UNKNOWN"; + } +} + static int cifs_debug_data_proc_show(struct seq_file *m, void *v) { struct mid_q_entry *mid_entry; @@ -539,6 +555,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) else seq_puts(m, "disabled (not supported by this server)"); + /* Show negotiated encryption cipher, even if not required */ + seq_puts(m, "\nEncryption: "); + if (server->cipher_type) + seq_printf(m, "Negotiated cipher (%s)", cipher_alg_str(server->cipher_type)); + seq_printf(m, "\n\n\tSessions: "); i = 0; list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { @@ -576,12 +597,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) /* dump session id helpful for use with network trace */ seq_printf(m, " SessionId: 0x%llx", ses->Suid); - if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) { + if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) seq_puts(m, " encrypted"); - /* can help in debugging to show encryption type */ - if (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM) - seq_puts(m, "(gcm256)"); - } if (ses->sign) seq_puts(m, " signed"); From 827733acbe4c3a0e117b6ebde5ed269fb7686427 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 1 Sep 2025 09:50:11 -0700 Subject: [PATCH 1118/1292] crypto: sha1 - Implement export_core() and import_core() Since commit 9d7a0ab1c753 ("crypto: ahash - Handle partial blocks in API"), the recently-added export_core() and import_core() methods in struct shash_alg have effectively become mandatory (even though it is not tested or enforced), since legacy drivers that need a fallback depend on them. Make crypto/sha1.c compatible with these legacy drivers by adding export_core() and import_core() methods to it. Reported-by: Giovanni Cabiddu Reported-by: Ovidiu Panait Closes: https://lore.kernel.org/r/aLSnCc9Ws5L9y+8X@gcabiddu-mobl.ger.corp.intel.com Fixes: b10a74abcfc5 ("crypto: sha1 - Use same state format as legacy drivers") Tested-by: Giovanni Cabiddu Tested-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250901165013.48649-2-ebiggers@kernel.org Signed-off-by: Eric Biggers --- crypto/sha1.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/crypto/sha1.c b/crypto/sha1.c index ecef4bf2d9c00e..4fbf61cf037096 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -49,6 +49,18 @@ static int __crypto_sha1_import(struct sha1_ctx *ctx, const void *in) return 0; } +static int __crypto_sha1_export_core(const struct sha1_ctx *ctx, void *out) +{ + memcpy(out, ctx, offsetof(struct sha1_ctx, buf)); + return 0; +} + +static int __crypto_sha1_import_core(struct sha1_ctx *ctx, const void *in) +{ + memcpy(ctx, in, offsetof(struct sha1_ctx, buf)); + return 0; +} + const u8 sha1_zero_message_hash[SHA1_DIGEST_SIZE] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, @@ -94,6 +106,16 @@ static int crypto_sha1_import(struct shash_desc *desc, const void *in) return __crypto_sha1_import(SHA1_CTX(desc), in); } +static int crypto_sha1_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha1_export_core(SHA1_CTX(desc), out); +} + +static int crypto_sha1_import_core(struct shash_desc *desc, const void *in) +{ + return __crypto_sha1_import_core(SHA1_CTX(desc), in); +} + #define HMAC_SHA1_KEY(tfm) ((struct hmac_sha1_key *)crypto_shash_ctx(tfm)) #define HMAC_SHA1_CTX(desc) ((struct hmac_sha1_ctx *)shash_desc_ctx(desc)) @@ -143,6 +165,19 @@ static int crypto_hmac_sha1_import(struct shash_desc *desc, const void *in) return __crypto_sha1_import(&ctx->sha_ctx, in); } +static int crypto_hmac_sha1_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha1_export_core(&HMAC_SHA1_CTX(desc)->sha_ctx, out); +} + +static int crypto_hmac_sha1_import_core(struct shash_desc *desc, const void *in) +{ + struct hmac_sha1_ctx *ctx = HMAC_SHA1_CTX(desc); + + ctx->ostate = HMAC_SHA1_KEY(desc->tfm)->ostate; + return __crypto_sha1_import_core(&ctx->sha_ctx, in); +} + static struct shash_alg algs[] = { { .base.cra_name = "sha1", @@ -157,6 +192,8 @@ static struct shash_alg algs[] = { .digest = crypto_sha1_digest, .export = crypto_sha1_export, .import = crypto_sha1_import, + .export_core = crypto_sha1_export_core, + .import_core = crypto_sha1_import_core, .descsize = sizeof(struct sha1_ctx), .statesize = SHA1_SHASH_STATE_SIZE, }, @@ -175,6 +212,8 @@ static struct shash_alg algs[] = { .digest = crypto_hmac_sha1_digest, .export = crypto_hmac_sha1_export, .import = crypto_hmac_sha1_import, + .export_core = crypto_hmac_sha1_export_core, + .import_core = crypto_hmac_sha1_import_core, .descsize = sizeof(struct hmac_sha1_ctx), .statesize = SHA1_SHASH_STATE_SIZE, }, From 30b2a8c4f2f3833f4f813d3e0d003f7c50cdf275 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 1 Sep 2025 09:50:12 -0700 Subject: [PATCH 1119/1292] crypto: sha256 - Implement export_core() and import_core() Since commit 9d7a0ab1c753 ("crypto: ahash - Handle partial blocks in API"), the recently-added export_core() and import_core() methods in struct shash_alg have effectively become mandatory (even though it is not tested or enforced), since legacy drivers that need a fallback depend on them. Make crypto/sha256.c compatible with these legacy drivers by adding export_core() and import_core() methods to it. Reported-by: Giovanni Cabiddu Reported-by: Ovidiu Panait Closes: https://lore.kernel.org/r/aLSnCc9Ws5L9y+8X@gcabiddu-mobl.ger.corp.intel.com Fixes: 07f090959bba ("crypto: sha256 - Use same state format as legacy drivers") Tested-by: Giovanni Cabiddu Tested-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250901165013.48649-3-ebiggers@kernel.org Signed-off-by: Eric Biggers --- crypto/sha256.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/crypto/sha256.c b/crypto/sha256.c index 052806559f06ce..fb81defe084c68 100644 --- a/crypto/sha256.c +++ b/crypto/sha256.c @@ -50,6 +50,19 @@ static int __crypto_sha256_import(struct __sha256_ctx *ctx, const void *in) return 0; } +static int __crypto_sha256_export_core(const struct __sha256_ctx *ctx, + void *out) +{ + memcpy(out, ctx, offsetof(struct __sha256_ctx, buf)); + return 0; +} + +static int __crypto_sha256_import_core(struct __sha256_ctx *ctx, const void *in) +{ + memcpy(ctx, in, offsetof(struct __sha256_ctx, buf)); + return 0; +} + /* SHA-224 */ const u8 sha224_zero_message_hash[SHA224_DIGEST_SIZE] = { @@ -98,6 +111,16 @@ static int crypto_sha224_import(struct shash_desc *desc, const void *in) return __crypto_sha256_import(&SHA224_CTX(desc)->ctx, in); } +static int crypto_sha224_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha256_export_core(&SHA224_CTX(desc)->ctx, out); +} + +static int crypto_sha224_import_core(struct shash_desc *desc, const void *in) +{ + return __crypto_sha256_import_core(&SHA224_CTX(desc)->ctx, in); +} + /* SHA-256 */ const u8 sha256_zero_message_hash[SHA256_DIGEST_SIZE] = { @@ -146,6 +169,16 @@ static int crypto_sha256_import(struct shash_desc *desc, const void *in) return __crypto_sha256_import(&SHA256_CTX(desc)->ctx, in); } +static int crypto_sha256_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha256_export_core(&SHA256_CTX(desc)->ctx, out); +} + +static int crypto_sha256_import_core(struct shash_desc *desc, const void *in) +{ + return __crypto_sha256_import_core(&SHA256_CTX(desc)->ctx, in); +} + /* HMAC-SHA224 */ #define HMAC_SHA224_KEY(tfm) ((struct hmac_sha224_key *)crypto_shash_ctx(tfm)) @@ -198,6 +231,21 @@ static int crypto_hmac_sha224_import(struct shash_desc *desc, const void *in) return __crypto_sha256_import(&ctx->ctx.sha_ctx, in); } +static int crypto_hmac_sha224_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha256_export_core(&HMAC_SHA224_CTX(desc)->ctx.sha_ctx, + out); +} + +static int crypto_hmac_sha224_import_core(struct shash_desc *desc, + const void *in) +{ + struct hmac_sha224_ctx *ctx = HMAC_SHA224_CTX(desc); + + ctx->ctx.ostate = HMAC_SHA224_KEY(desc->tfm)->key.ostate; + return __crypto_sha256_import_core(&ctx->ctx.sha_ctx, in); +} + /* HMAC-SHA256 */ #define HMAC_SHA256_KEY(tfm) ((struct hmac_sha256_key *)crypto_shash_ctx(tfm)) @@ -250,6 +298,21 @@ static int crypto_hmac_sha256_import(struct shash_desc *desc, const void *in) return __crypto_sha256_import(&ctx->ctx.sha_ctx, in); } +static int crypto_hmac_sha256_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha256_export_core(&HMAC_SHA256_CTX(desc)->ctx.sha_ctx, + out); +} + +static int crypto_hmac_sha256_import_core(struct shash_desc *desc, + const void *in) +{ + struct hmac_sha256_ctx *ctx = HMAC_SHA256_CTX(desc); + + ctx->ctx.ostate = HMAC_SHA256_KEY(desc->tfm)->key.ostate; + return __crypto_sha256_import_core(&ctx->ctx.sha_ctx, in); +} + /* Algorithm definitions */ static struct shash_alg algs[] = { @@ -266,6 +329,8 @@ static struct shash_alg algs[] = { .digest = crypto_sha224_digest, .export = crypto_sha224_export, .import = crypto_sha224_import, + .export_core = crypto_sha224_export_core, + .import_core = crypto_sha224_import_core, .descsize = sizeof(struct sha224_ctx), .statesize = SHA256_SHASH_STATE_SIZE, }, @@ -282,6 +347,8 @@ static struct shash_alg algs[] = { .digest = crypto_sha256_digest, .export = crypto_sha256_export, .import = crypto_sha256_import, + .export_core = crypto_sha256_export_core, + .import_core = crypto_sha256_import_core, .descsize = sizeof(struct sha256_ctx), .statesize = SHA256_SHASH_STATE_SIZE, }, @@ -300,6 +367,8 @@ static struct shash_alg algs[] = { .digest = crypto_hmac_sha224_digest, .export = crypto_hmac_sha224_export, .import = crypto_hmac_sha224_import, + .export_core = crypto_hmac_sha224_export_core, + .import_core = crypto_hmac_sha224_import_core, .descsize = sizeof(struct hmac_sha224_ctx), .statesize = SHA256_SHASH_STATE_SIZE, }, @@ -318,6 +387,8 @@ static struct shash_alg algs[] = { .digest = crypto_hmac_sha256_digest, .export = crypto_hmac_sha256_export, .import = crypto_hmac_sha256_import, + .export_core = crypto_hmac_sha256_export_core, + .import_core = crypto_hmac_sha256_import_core, .descsize = sizeof(struct hmac_sha256_ctx), .statesize = SHA256_SHASH_STATE_SIZE, }, From cdb03b6d1896c2d23f9c47dc779edba0a9241115 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 1 Sep 2025 09:50:13 -0700 Subject: [PATCH 1120/1292] crypto: sha512 - Implement export_core() and import_core() Since commit 9d7a0ab1c753 ("crypto: ahash - Handle partial blocks in API"), the recently-added export_core() and import_core() methods in struct shash_alg have effectively become mandatory (even though it is not tested or enforced), since legacy drivers that need a fallback depend on them. Make crypto/sha512.c compatible with these legacy drivers by adding export_core() and import_core() methods to it. Reported-by: Giovanni Cabiddu Reported-by: Ovidiu Panait Closes: https://lore.kernel.org/r/aLSnCc9Ws5L9y+8X@gcabiddu-mobl.ger.corp.intel.com Fixes: 4bc7f7b687a2 ("crypto: sha512 - Use same state format as legacy drivers") Tested-by: Giovanni Cabiddu Tested-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250901165013.48649-4-ebiggers@kernel.org Signed-off-by: Eric Biggers --- crypto/sha512.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/crypto/sha512.c b/crypto/sha512.c index fb1c520978ef3c..d320fe53913faf 100644 --- a/crypto/sha512.c +++ b/crypto/sha512.c @@ -50,6 +50,19 @@ static int __crypto_sha512_import(struct __sha512_ctx *ctx, const void *in) return 0; } +static int __crypto_sha512_export_core(const struct __sha512_ctx *ctx, + void *out) +{ + memcpy(out, ctx, offsetof(struct __sha512_ctx, buf)); + return 0; +} + +static int __crypto_sha512_import_core(struct __sha512_ctx *ctx, const void *in) +{ + memcpy(ctx, in, offsetof(struct __sha512_ctx, buf)); + return 0; +} + /* SHA-384 */ const u8 sha384_zero_message_hash[SHA384_DIGEST_SIZE] = { @@ -100,6 +113,16 @@ static int crypto_sha384_import(struct shash_desc *desc, const void *in) return __crypto_sha512_import(&SHA384_CTX(desc)->ctx, in); } +static int crypto_sha384_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha512_export_core(&SHA384_CTX(desc)->ctx, out); +} + +static int crypto_sha384_import_core(struct shash_desc *desc, const void *in) +{ + return __crypto_sha512_import_core(&SHA384_CTX(desc)->ctx, in); +} + /* SHA-512 */ const u8 sha512_zero_message_hash[SHA512_DIGEST_SIZE] = { @@ -152,6 +175,16 @@ static int crypto_sha512_import(struct shash_desc *desc, const void *in) return __crypto_sha512_import(&SHA512_CTX(desc)->ctx, in); } +static int crypto_sha512_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha512_export_core(&SHA512_CTX(desc)->ctx, out); +} + +static int crypto_sha512_import_core(struct shash_desc *desc, const void *in) +{ + return __crypto_sha512_import_core(&SHA512_CTX(desc)->ctx, in); +} + /* HMAC-SHA384 */ #define HMAC_SHA384_KEY(tfm) ((struct hmac_sha384_key *)crypto_shash_ctx(tfm)) @@ -204,6 +237,21 @@ static int crypto_hmac_sha384_import(struct shash_desc *desc, const void *in) return __crypto_sha512_import(&ctx->ctx.sha_ctx, in); } +static int crypto_hmac_sha384_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha512_export_core(&HMAC_SHA384_CTX(desc)->ctx.sha_ctx, + out); +} + +static int crypto_hmac_sha384_import_core(struct shash_desc *desc, + const void *in) +{ + struct hmac_sha384_ctx *ctx = HMAC_SHA384_CTX(desc); + + ctx->ctx.ostate = HMAC_SHA384_KEY(desc->tfm)->key.ostate; + return __crypto_sha512_import_core(&ctx->ctx.sha_ctx, in); +} + /* HMAC-SHA512 */ #define HMAC_SHA512_KEY(tfm) ((struct hmac_sha512_key *)crypto_shash_ctx(tfm)) @@ -256,6 +304,21 @@ static int crypto_hmac_sha512_import(struct shash_desc *desc, const void *in) return __crypto_sha512_import(&ctx->ctx.sha_ctx, in); } +static int crypto_hmac_sha512_export_core(struct shash_desc *desc, void *out) +{ + return __crypto_sha512_export_core(&HMAC_SHA512_CTX(desc)->ctx.sha_ctx, + out); +} + +static int crypto_hmac_sha512_import_core(struct shash_desc *desc, + const void *in) +{ + struct hmac_sha512_ctx *ctx = HMAC_SHA512_CTX(desc); + + ctx->ctx.ostate = HMAC_SHA512_KEY(desc->tfm)->key.ostate; + return __crypto_sha512_import_core(&ctx->ctx.sha_ctx, in); +} + /* Algorithm definitions */ static struct shash_alg algs[] = { @@ -272,6 +335,8 @@ static struct shash_alg algs[] = { .digest = crypto_sha384_digest, .export = crypto_sha384_export, .import = crypto_sha384_import, + .export_core = crypto_sha384_export_core, + .import_core = crypto_sha384_import_core, .descsize = sizeof(struct sha384_ctx), .statesize = SHA512_SHASH_STATE_SIZE, }, @@ -288,6 +353,8 @@ static struct shash_alg algs[] = { .digest = crypto_sha512_digest, .export = crypto_sha512_export, .import = crypto_sha512_import, + .export_core = crypto_sha512_export_core, + .import_core = crypto_sha512_import_core, .descsize = sizeof(struct sha512_ctx), .statesize = SHA512_SHASH_STATE_SIZE, }, @@ -306,6 +373,8 @@ static struct shash_alg algs[] = { .digest = crypto_hmac_sha384_digest, .export = crypto_hmac_sha384_export, .import = crypto_hmac_sha384_import, + .export_core = crypto_hmac_sha384_export_core, + .import_core = crypto_hmac_sha384_import_core, .descsize = sizeof(struct hmac_sha384_ctx), .statesize = SHA512_SHASH_STATE_SIZE, }, @@ -324,6 +393,8 @@ static struct shash_alg algs[] = { .digest = crypto_hmac_sha512_digest, .export = crypto_hmac_sha512_export, .import = crypto_hmac_sha512_import, + .export_core = crypto_hmac_sha512_export_core, + .import_core = crypto_hmac_sha512_import_core, .descsize = sizeof(struct hmac_sha512_ctx), .statesize = SHA512_SHASH_STATE_SIZE, }, From 8409816b1eb306eb1f6137f83317fc756722d7d0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 3 Sep 2025 08:52:24 +0300 Subject: [PATCH 1121/1292] ALSA: rme32: Fix serialization in snd_rme32_capture_adat_open() We accidentally deleted the wrong line of code when we did the conversion to guard() locks. If the rme32->capture_substream has already been set we should return -EBUSY. Fixes: 8bb75ae244c5 ("ALSA: rme32: Use guard() for spin locks") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aLfXmIQRFTXr5h8O@stanley.mountain Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 123dddcb697211..ca9bbf55465091 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -936,7 +936,7 @@ snd_rme32_capture_adat_open(struct snd_pcm_substream *substream) scoped_guard(spinlock_irq, &rme32->lock) { if (rme32->capture_substream != NULL) - spin_unlock_irq(&rme32->lock); + return -EBUSY; rme32->capture_substream = substream; } From f8f15f6742b8874e59c9c715d0af3474608310ad Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 29 Aug 2025 15:48:28 +0300 Subject: [PATCH 1122/1292] wifi: cw1200: cap SSID length in cw1200_do_join() If the ssidie[1] length is more that 32 it leads to memory corruption. Fixes: a910e4a94f69 ("cw1200: add driver for the ST-E CW1100 & CW1200 WLAN chipsets") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/e91fb43fcedc4893b604dfb973131661510901a7.1756456951.git.dan.carpenter@linaro.org Signed-off-by: Johannes Berg --- drivers/net/wireless/st/cw1200/sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index b1dd76e8aecbfe..5d8eaa700779e5 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1291,7 +1291,7 @@ static void cw1200_do_join(struct cw1200_common *priv) rcu_read_lock(); ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); if (ssidie) { - join.ssid_len = ssidie[1]; + join.ssid_len = min(ssidie[1], IEEE80211_MAX_SSID_LEN); memcpy(join.ssid, &ssidie[2], join.ssid_len); } rcu_read_unlock(); From c786794bd27b0d7a5fd9063695df83206009be59 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 29 Aug 2025 15:48:35 +0300 Subject: [PATCH 1123/1292] wifi: libertas: cap SSID len in lbs_associate() If the ssid_eid[1] length is more that 32 it leads to memory corruption. Fixes: a910e4a94f69 ("cw1200: add driver for the ST-E CW1100 & CW1200 WLAN chipsets") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/2a40f5ec7617144aef412034c12919a4927d90ad.1756456951.git.dan.carpenter@linaro.org Signed-off-by: Johannes Berg --- drivers/net/wireless/marvell/libertas/cfg.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 94dd488becaf6e..caba7491cd5abc 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1151,10 +1151,13 @@ static int lbs_associate(struct lbs_private *priv, /* add SSID TLV */ rcu_read_lock(); ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); - if (ssid_eid) - pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); - else + if (ssid_eid) { + u32 ssid_len = min(ssid_eid[1], IEEE80211_MAX_SSID_LEN); + + pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_len); + } else { lbs_deb_assoc("no SSID\n"); + } rcu_read_unlock(); /* add DS param TLV */ From 62b635dcd69c4fde7ce1de4992d71420a37e51e3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 29 Aug 2025 15:48:45 +0300 Subject: [PATCH 1124/1292] wifi: cfg80211: sme: cap SSID length in __cfg80211_connect_result() If the ssid->datalen is more than IEEE80211_MAX_SSID_LEN (32) it would lead to memory corruption so add some bounds checking. Fixes: c38c70185101 ("wifi: cfg80211: Set SSID if it is not already set") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/0aaaae4a3ed37c6252363c34ae4904b1604e8e32.1756456951.git.dan.carpenter@linaro.org Signed-off-by: Johannes Berg --- net/wireless/sme.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 826ec0a6355f1c..3a028ff287fbbe 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -900,13 +900,16 @@ void __cfg80211_connect_result(struct net_device *dev, if (!wdev->u.client.ssid_len) { rcu_read_lock(); for_each_valid_link(cr, link) { + u32 ssid_len; + ssid = ieee80211_bss_get_elem(cr->links[link].bss, WLAN_EID_SSID); if (!ssid || !ssid->datalen) continue; - memcpy(wdev->u.client.ssid, ssid->data, ssid->datalen); + ssid_len = min(ssid->datalen, IEEE80211_MAX_SSID_LEN); + memcpy(wdev->u.client.ssid, ssid->data, ssid_len); wdev->u.client.ssid_len = ssid->datalen; break; } From fe9e4d0c39311d0f97b024147a0d155333f388b5 Mon Sep 17 00:00:00 2001 From: "Ajay.Kathat@microchip.com" Date: Fri, 29 Aug 2025 22:58:43 +0000 Subject: [PATCH 1125/1292] wifi: wilc1000: avoid buffer overflow in WID string configuration Fix the following copy overflow warning identified by Smatch checker. drivers/net/wireless/microchip/wilc1000/wlan_cfg.c:184 wilc_wlan_parse_response_frame() error: '__memcpy()' 'cfg->s[i]->str' copy overflow (512 vs 65537) This patch introduces size check before accessing the memory buffer. The checks are base on the WID type of received data from the firmware. For WID string configuration, the size limit is determined by individual element size in 'struct wilc_cfg_str_vals' that is maintained in 'len' field of 'struct wilc_cfg_str'. Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-wireless/aLFbr9Yu9j_TQTey@stanley.mountain Suggested-by: Dan Carpenter Signed-off-by: Ajay Singh Link: https://patch.msgid.link/20250829225829.5423-1-ajay.kathat@microchip.com Signed-off-by: Johannes Berg --- .../wireless/microchip/wilc1000/wlan_cfg.c | 37 ++++++++++++++----- .../wireless/microchip/wilc1000/wlan_cfg.h | 5 ++- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c index 131388886acbfa..cfabd5aebb5400 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c @@ -41,10 +41,10 @@ static const struct wilc_cfg_word g_cfg_word[] = { }; static const struct wilc_cfg_str g_cfg_str[] = { - {WID_FIRMWARE_VERSION, NULL}, - {WID_MAC_ADDR, NULL}, - {WID_ASSOC_RES_INFO, NULL}, - {WID_NIL, NULL} + {WID_FIRMWARE_VERSION, 0, NULL}, + {WID_MAC_ADDR, 0, NULL}, + {WID_ASSOC_RES_INFO, 0, NULL}, + {WID_NIL, 0, NULL} }; #define WILC_RESP_MSG_TYPE_CONFIG_REPLY 'R' @@ -147,44 +147,58 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size) switch (FIELD_GET(WILC_WID_TYPE, wid)) { case WID_CHAR: + len = 3; + if (len + 2 > size) + return; + while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid) i++; if (cfg->b[i].id == wid) cfg->b[i].val = info[4]; - len = 3; break; case WID_SHORT: + len = 4; + if (len + 2 > size) + return; + while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid) i++; if (cfg->hw[i].id == wid) cfg->hw[i].val = get_unaligned_le16(&info[4]); - len = 4; break; case WID_INT: + len = 6; + if (len + 2 > size) + return; + while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid) i++; if (cfg->w[i].id == wid) cfg->w[i].val = get_unaligned_le32(&info[4]); - len = 6; break; case WID_STR: + len = 2 + get_unaligned_le16(&info[2]); + while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid) i++; - if (cfg->s[i].id == wid) + if (cfg->s[i].id == wid) { + if (len > cfg->s[i].len || (len + 2 > size)) + return; + memcpy(cfg->s[i].str, &info[2], - get_unaligned_le16(&info[2]) + 2); + len); + } - len = 2 + get_unaligned_le16(&info[2]); break; default: @@ -384,12 +398,15 @@ int wilc_wlan_cfg_init(struct wilc *wl) /* store the string cfg parameters */ wl->cfg.s[i].id = WID_FIRMWARE_VERSION; wl->cfg.s[i].str = str_vals->firmware_version; + wl->cfg.s[i].len = sizeof(str_vals->firmware_version); i++; wl->cfg.s[i].id = WID_MAC_ADDR; wl->cfg.s[i].str = str_vals->mac_address; + wl->cfg.s[i].len = sizeof(str_vals->mac_address); i++; wl->cfg.s[i].id = WID_ASSOC_RES_INFO; wl->cfg.s[i].str = str_vals->assoc_rsp; + wl->cfg.s[i].len = sizeof(str_vals->assoc_rsp); i++; wl->cfg.s[i].id = WID_NIL; wl->cfg.s[i].str = NULL; diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h index 7038b74f8e8ff6..5ae74bced7d748 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h @@ -24,12 +24,13 @@ struct wilc_cfg_word { struct wilc_cfg_str { u16 id; + u16 len; u8 *str; }; struct wilc_cfg_str_vals { - u8 mac_address[7]; - u8 firmware_version[129]; + u8 mac_address[8]; + u8 firmware_version[130]; u8 assoc_rsp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; }; From 18dbcbfabfffc4a5d3ea10290c5ad27f22b0d240 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Mon, 11 Aug 2025 11:26:44 -0700 Subject: [PATCH 1126/1292] perf: Fix the POLL_HUP delivery breakage The event_limit can be set by the PERF_EVENT_IOC_REFRESH to limit the number of events. When the event_limit reaches 0, the POLL_HUP signal should be sent. But it's missed. The corresponding counter should be stopped when the event_limit reaches 0. It was implemented in the ARCH-specific code. However, since the commit 9734e25fbf5a ("perf: Fix the throttle logic for a group"), all the ARCH-specific code has been moved to the generic code. The code to handle the event_limit was lost. Add the event->pmu->stop(event, 0); back. Fixes: 9734e25fbf5a ("perf: Fix the throttle logic for a group") Closes: https://lore.kernel.org/lkml/aICYAqM5EQUlTqtX@li-2b55cdcc-350b-11b2-a85c-a78bff51fc11.ibm.com/ Reported-by: Sumanth Korikkar Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Tested-by: Sumanth Korikkar Link: https://lkml.kernel.org/r/20250811182644.1305952-1-kan.liang@linux.intel.com --- kernel/events/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index 872122e074e5fe..820127536e62b7 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -10330,6 +10330,7 @@ static int __perf_event_overflow(struct perf_event *event, ret = 1; event->pending_kill = POLL_HUP; perf_event_disable_inatomic(event); + event->pmu->stop(event, 0); } if (event->attr.sigtrap) { From 762af5a2aa0ad18da1316666dae30d369268d44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 25 Aug 2025 15:26:35 +0200 Subject: [PATCH 1127/1292] vdso/vsyscall: Avoid slow division loop in auxiliary clock update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The call to __iter_div_u64_rem() in vdso_time_update_aux() is a wrapper around subtraction. It cannot be used to divide large numbers, as that introduces long, computationally expensive delays. A regular u64 division is also not possible in the timekeeper update path as it can be too slow. Instead of splitting the ktime_t offset into into second and subsecond components during the timekeeper update fast-path, do it together with the adjustment of tk->offs_aux in the slow-path. Equivalent to the handling of offs_boot and monotonic_to_boot. Reuse the storage of monotonic_to_boot for the new field, as it is not used by auxiliary timekeepers. Fixes: 380b84e168e5 ("vdso/vsyscall: Update auxiliary clock data in the datapage") Reported-by: Miroslav Lichvar Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250825-vdso-auxclock-division-v1-1-a1d32a16a313@linutronix.de Closes: https://lore.kernel.org/lkml/aKwsNNWsHJg8IKzj@localhost/ --- include/linux/timekeeper_internal.h | 9 ++++++++- kernel/time/timekeeping.c | 10 ++++++++-- kernel/time/vsyscall.c | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index c27aac67cb3f15..b8ae89ea28abfc 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -76,6 +76,7 @@ struct tk_read_base { * @cs_was_changed_seq: The sequence number of clocksource change events * @clock_valid: Indicator for valid clock * @monotonic_to_boot: CLOCK_MONOTONIC to CLOCK_BOOTTIME offset + * @monotonic_to_aux: CLOCK_MONOTONIC to CLOCK_AUX offset * @cycle_interval: Number of clock cycles in one NTP interval * @xtime_interval: Number of clock shifted nano seconds in one NTP * interval. @@ -117,6 +118,9 @@ struct tk_read_base { * @offs_aux is used by the auxiliary timekeepers which do not utilize any * of the regular timekeeper offset fields. * + * @monotonic_to_aux is a timespec64 representation of @offs_aux to + * accelerate the VDSO update for CLOCK_AUX. + * * The cacheline ordering of the structure is optimized for in kernel usage of * the ktime_get() and ktime_get_ts64() family of time accessors. Struct * timekeeper is prepended in the core timekeeping code with a sequence count, @@ -159,7 +163,10 @@ struct timekeeper { u8 cs_was_changed_seq; u8 clock_valid; - struct timespec64 monotonic_to_boot; + union { + struct timespec64 monotonic_to_boot; + struct timespec64 monotonic_to_aux; + }; u64 cycle_interval; u64 xtime_interval; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 059fa8b79be60d..b6974fce800cd8 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -83,6 +83,12 @@ static inline bool tk_is_aux(const struct timekeeper *tk) } #endif +static inline void tk_update_aux_offs(struct timekeeper *tk, ktime_t offs) +{ + tk->offs_aux = offs; + tk->monotonic_to_aux = ktime_to_timespec64(offs); +} + /* flag for if timekeeping is suspended */ int __read_mostly timekeeping_suspended; @@ -1506,7 +1512,7 @@ static int __timekeeping_inject_offset(struct tk_data *tkd, const struct timespe timekeeping_restore_shadow(tkd); return -EINVAL; } - tks->offs_aux = offs; + tk_update_aux_offs(tks, offs); } timekeeping_update_from_shadow(tkd, TK_UPDATE_ALL); @@ -2937,7 +2943,7 @@ static int aux_clock_set(const clockid_t id, const struct timespec64 *tnew) * xtime ("realtime") is not applicable for auxiliary clocks and * kept in sync with "monotonic". */ - aux_tks->offs_aux = ktime_sub(timespec64_to_ktime(*tnew), tnow); + tk_update_aux_offs(aux_tks, ktime_sub(timespec64_to_ktime(*tnew), tnow)); timekeeping_update_from_shadow(aux_tkd, TK_UPDATE_ALL); return 0; diff --git a/kernel/time/vsyscall.c b/kernel/time/vsyscall.c index 8ba8b0d8a38731..aa59919b8f2c23 100644 --- a/kernel/time/vsyscall.c +++ b/kernel/time/vsyscall.c @@ -159,10 +159,10 @@ void vdso_time_update_aux(struct timekeeper *tk) if (clock_mode != VDSO_CLOCKMODE_NONE) { fill_clock_configuration(vc, &tk->tkr_mono); - vdso_ts->sec = tk->xtime_sec; + vdso_ts->sec = tk->xtime_sec + tk->monotonic_to_aux.tv_sec; nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift; - nsec += tk->offs_aux; + nsec += tk->monotonic_to_aux.tv_nsec; vdso_ts->sec += __iter_div_u64_rem(nsec, NSEC_PER_SEC, &nsec); nsec = nsec << tk->tkr_mono.shift; vdso_ts->nsec = nsec; From c3c9a75ede23fe2b244d2f1c4ac0c6cc3a4dc100 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 2 Sep 2025 17:48:41 +0200 Subject: [PATCH 1128/1292] ALSA: hda/conexant: Fix typos in comments s/OPLC/OLPC/ Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20250902154858.86102-2-thorsten.blum@linux.dev Signed-off-by: Takashi Iwai --- sound/hda/codecs/conexant.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c index c881bf213ebe67..5fcbc1312c6971 100644 --- a/sound/hda/codecs/conexant.c +++ b/sound/hda/codecs/conexant.c @@ -32,7 +32,7 @@ struct conexant_spec { unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ - /* OPLC XO specific */ + /* OLPC XO specific */ bool recording; bool dc_enable; unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ @@ -407,7 +407,7 @@ static void cxt_fixup_headset_mic(struct hda_codec *codec, } } -/* OPLC XO 1.5 fixup */ +/* OLPC XO 1.5 fixup */ /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) * through the microphone jack. From 9a6d3ff10f7f538835cae4799562004ee46922c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 21 Aug 2025 09:56:44 +0200 Subject: [PATCH 1129/1292] arm64: uapi: Provide correct __BITS_PER_LONG for the compat vDSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generic vDSO library uses the UAPI headers. On arm64 __BITS_PER_LONG is always '64' even when used from the compat vDSO. In that case __GENMASK() does an illegal bitshift, invoking undefined behaviour. Change __BITS_PER_LONG to also work when used from the comapt vDSO. To not confuse real userspace, only do this when building the kernel. Reported-by: John Stultz Closes: https://lore.kernel.org/lkml/CANDhNCqvKOc9JgphQwr0eDyJiyG4oLFS9R8rSFvU0fpurrJFDg@mail.gmail.com/ Fixes: cd3557a7618b ("vdso/gettimeofday: Add support for auxiliary clocks") Signed-off-by: Thomas Weißschuh Acked-by: Arnd Bergmann Tested-by: John Stultz Link: https://lore.kernel.org/r/20250821-vdso-arm64-compat-bitsperlong-v1-1-700bcabe7732@linutronix.de Signed-off-by: Catalin Marinas --- arch/arm64/include/uapi/asm/bitsperlong.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/include/uapi/asm/bitsperlong.h b/arch/arm64/include/uapi/asm/bitsperlong.h index 485d60bee26ca3..d59730975f30c0 100644 --- a/arch/arm64/include/uapi/asm/bitsperlong.h +++ b/arch/arm64/include/uapi/asm/bitsperlong.h @@ -17,7 +17,12 @@ #ifndef __ASM_BITSPERLONG_H #define __ASM_BITSPERLONG_H +#if defined(__KERNEL__) && !defined(__aarch64__) +/* Used by the compat vDSO */ +#define __BITS_PER_LONG 32 +#else #define __BITS_PER_LONG 64 +#endif #include From 0e3448f069646a72698b6f4933baf43daf92a9c0 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:37 +0200 Subject: [PATCH 1130/1292] ASoC: Intel: avs: hda: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-2-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/hdaudio.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index 19b2255a8ac3fe..aec769e2396c41 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -16,7 +16,7 @@ #include "../utils.h" static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count, - const char *platform_name, struct snd_soc_dai_link **links) + struct snd_soc_dai_link **links) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -29,7 +29,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; + platform->name = dev_name(dev); pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { @@ -142,7 +142,7 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) list_for_each_entry(pcm, &codec->pcm_list_head, list) pcm_count++; - ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links); + ret = avs_create_dai_links(card->dev, codec, pcm_count, &links); if (ret < 0) { dev_err(card->dev, "create links failed: %d\n", ret); return ret; @@ -197,7 +197,7 @@ static int avs_hdaudio_probe(struct platform_device *pdev) if (!binder->codecs->name) return -ENOMEM; - binder->platforms->name = mach->mach_params.platform; + binder->platforms->name = dev_name(dev); binder->num_platforms = 1; binder->codecs->dai_name = "codec-probing-DAI"; binder->num_codecs = 1; @@ -207,7 +207,10 @@ static int avs_hdaudio_probe(struct platform_device *pdev) return -ENOMEM; if (pdata->obsolete_card_names) { - card->name = binder->codecs->name; + card->name = devm_kasprintf(dev, GFP_KERNEL, "hdaudioB%dD%d", codec->bus->core.idx, + codec->core.addr); + if (!card->name) + return -ENOMEM; } else { card->driver_name = "avs_hdaudio"; if (hda_codec_is_display(codec)) From 7fa2ebe9b7f4a865030e6ea9be33635b4c1b9224 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:38 +0200 Subject: [PATCH 1131/1292] ASoC: Intel: avs: da7219: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-3-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/da7219.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 3ef0db2541422f..6782dc7efae310 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -165,8 +165,8 @@ avs_da7219_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_param return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -176,8 +176,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); @@ -193,6 +191,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -218,18 +217,16 @@ static int avs_da7219_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -259,10 +256,6 @@ static int avs_da7219_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 765ee69f5e237c33795a0b51417f68ce59fd31a1 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:39 +0200 Subject: [PATCH 1132/1292] ASoC: Intel: avs: dmic: Refactor dai_link creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow for multiple instances of the card, move away from static dai_link declaration. While at it, simplify the code as the name of the platform component matches the name of the card's platform_device: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-4-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/dmic.c | 80 +++++++++++++++++++------------ 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index a1448a98874d48..bf6f580a51643c 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -14,30 +14,6 @@ SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); -/* Name overridden on probe */ -SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM(""))); - -static struct snd_soc_dai_link card_dai_links[] = { - /* Back ends */ - { - .name = "DMIC", - .id = 0, - .capture_only = 1, - .nonatomic = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "DMIC WoV", - .id = 1, - .capture_only = 1, - .nonatomic = 1, - .no_pcm = 1, - .ignore_suspend = 1, - SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform), - }, -}; static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_MIC("SoC DMIC", NULL), @@ -47,12 +23,56 @@ static const struct snd_soc_dapm_route card_routes[] = { {"DMic", NULL, "SoC DMIC"}, }; +static int avs_create_dai_links(struct device *dev, const char *codec_name, + struct snd_soc_dai_link **links, int *num_links) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + const int num_dl = 2; + + dl = devm_kcalloc(dev, num_dl, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->codecs) + return -ENOMEM; + + dl->codecs->name = devm_kstrdup(dev, codec_name, GFP_KERNEL); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "dmic-hifi"); + if (!dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + platform->name = dev_name(dev); + dl[0].num_cpus = 1; + dl[0].num_codecs = 1; + dl[0].platforms = platform; + dl[0].num_platforms = 1; + dl[0].nonatomic = 1; + dl[0].no_pcm = 1; + dl[0].capture_only = 1; + memcpy(&dl[1], &dl[0], sizeof(*dl)); + + dl[0].name = "DMIC"; + dl[0].cpus = dmic_pin; + dl[0].id = 0; + dl[1].name = "DMIC WoV"; + dl[1].cpus = dmic_wov_pin; + dl[1].id = 1; + dl[1].ignore_suspend = 1; + + *links = dl; + *num_links = num_dl; + return 0; +} + static int avs_dmic_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; struct avs_mach_pdata *pdata; struct snd_soc_card *card; - struct device *dev = &pdev->dev; int ret; mach = dev_get_platdata(dev); @@ -62,6 +82,10 @@ static int avs_dmic_probe(struct platform_device *pdev) if (!card) return -ENOMEM; + ret = avs_create_dai_links(dev, pdata->codec_name, &card->dai_link, &card->num_links); + if (ret) + return ret; + if (pdata->obsolete_card_names) { card->name = "avs_dmic"; } else { @@ -70,18 +94,12 @@ static int avs_dmic_probe(struct platform_device *pdev) } card->dev = dev; card->owner = THIS_MODULE; - card->dai_link = card_dai_links; - card->num_links = ARRAY_SIZE(card_dai_links); card->dapm_widgets = card_widgets; card->num_dapm_widgets = ARRAY_SIZE(card_widgets); card->dapm_routes = card_routes; card->num_dapm_routes = ARRAY_SIZE(card_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From cd405e6a949723c4b35c44e8b60e7139aa6e3743 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:40 +0200 Subject: [PATCH 1133/1292] ASoC: Intel: avs: es8336: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-5-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/es8336.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index 1955f2d383c59c..12e4e0aba5fa24 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -195,8 +195,9 @@ static int avs_es8336_be_fixup(struct snd_soc_pcm_runtime *runtime, return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) + +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -206,8 +207,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -222,6 +221,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -263,18 +263,16 @@ static int avs_es8336_probe(struct platform_device *pdev) struct avs_card_drvdata *data; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -306,10 +304,6 @@ static int avs_es8336_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, data); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From d4b60caaef0cb8d23528ef17991bf9abae1ccff7 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:41 +0200 Subject: [PATCH 1134/1292] ASoC: Intel: avs: i2stest: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-6-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/i2s_test.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index f7b6d771573841..9a6b89ffdf1427 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -14,8 +14,8 @@ #include #include "../utils.h" -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -25,8 +25,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -39,6 +37,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -59,11 +58,9 @@ static int avs_i2s_test_probe(struct platform_device *pdev) struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; if (!avs_mach_singular_ssp(mach)) { @@ -94,7 +91,7 @@ static int avs_i2s_test_probe(struct platform_device *pdev) if (!card->name) return -ENOMEM; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d\n", ret); return ret; @@ -106,10 +103,6 @@ static int avs_i2s_test_probe(struct platform_device *pdev) card->num_links = 1; card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 314d8f574ae0c8f23f3225e0c75388ef8c565295 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:42 +0200 Subject: [PATCH 1135/1292] ASoC: Intel: avs: max98357a: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-7-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/max98357a.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 72053f83e98b79..e9a87804f91844 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -46,8 +46,8 @@ avs_max98357a_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_pa return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -57,8 +57,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -73,6 +71,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -96,18 +95,16 @@ static int avs_max98357a_probe(struct platform_device *pdev) struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -135,10 +132,6 @@ static int avs_max98357a_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From ed23ac9b300b809616dcfc63765aa5a33af38041 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:43 +0200 Subject: [PATCH 1136/1292] ASoC: Intel: avs: max98373: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-8-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/max98373.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index cdba1c3ee20b2e..8b45b643ca2996 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -95,8 +95,8 @@ static const struct snd_soc_ops avs_max98373_ops = { .hw_params = avs_max98373_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -106,8 +106,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -125,6 +123,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in !dl->codecs[1].name || !dl->codecs[1].dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 2; dl->platforms = platform; @@ -149,18 +148,16 @@ static int avs_max98373_probe(struct platform_device *pdev) struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -190,10 +187,6 @@ static int avs_max98373_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 31fc544ad8db01e58d671a5c4ec77b211bde3523 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:44 +0200 Subject: [PATCH 1137/1292] ASoC: Intel: avs: max98927: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-9-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/max98927.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index a68e227044c509..db073125fa4d56 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -92,8 +92,8 @@ static const struct snd_soc_ops avs_max98927_ops = { .hw_params = avs_max98927_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -103,8 +103,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -122,6 +120,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in !dl->codecs[1].name || !dl->codecs[1].dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 2; dl->platforms = platform; @@ -146,18 +145,16 @@ static int avs_max98927_probe(struct platform_device *pdev) struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -187,10 +184,6 @@ static int avs_max98927_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From ba3684328208129d1d72ec50c417bc8a9213d4c5 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:45 +0200 Subject: [PATCH 1138/1292] ASoC: Intel: avs: nau8825: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-10-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/nau8825.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index 3fb1a5d07ae123..9ca400a6412eb1 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -172,8 +172,8 @@ static const struct snd_soc_ops avs_nau8825_ops = { .trigger = avs_nau8825_trigger, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -183,8 +183,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -199,6 +197,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -250,18 +249,16 @@ static int avs_nau8825_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -293,10 +290,6 @@ static int avs_nau8825_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From a46b3da24cdce85b7fca6f012f68b3857494ade6 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:46 +0200 Subject: [PATCH 1139/1292] ASoC: Intel: avs: probe: Refactor dai_link creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow for multiple instances of the card, move away from static dai_link declaration. While at it, simplify the code as the name of the platform component matches the name of the card's platform_device: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-11-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/probe.c | 49 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c index 06c1f19f27aa76..73884f8a535ca3 100644 --- a/sound/soc/intel/avs/boards/probe.c +++ b/sound/soc/intel/avs/boards/probe.c @@ -9,45 +9,54 @@ #include #include #include -#include -SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); -SND_SOC_DAILINK_DEF(probe_cp, DAILINK_COMP_ARRAY(COMP_CPU("Probe Extraction CPU DAI"))); -SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("probe-platform"))); +static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **links, int *num_links) +{ + struct snd_soc_dai_link *dl; -static struct snd_soc_dai_link probe_mb_dai_links[] = { - { - .name = "Compress Probe Capture", - .nonatomic = 1, - SND_SOC_DAILINK_REG(probe_cp, dummy, platform), - }, -}; + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + if (!dl) + return -ENOMEM; + + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->platforms = devm_kzalloc(dev, sizeof(*dl->platforms), GFP_KERNEL); + if (!dl->cpus || !dl->platforms) + return -ENOMEM; + + dl->name = "Compress Probe Capture"; + dl->cpus->dai_name = "Probe Extraction CPU DAI"; + dl->num_cpus = 1; + dl->codecs = &snd_soc_dummy_dlc; + dl->num_codecs = 1; + dl->platforms->name = dev_name(dev); + dl->num_platforms = 1; + dl->nonatomic = 1; + + *links = dl; + *num_links = 1; + return 0; +} static int avs_probe_mb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct snd_soc_acpi_mach *mach; struct snd_soc_card *card; int ret; - mach = dev_get_platdata(dev); - card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; + ret = avs_create_dai_links(dev, &card->dai_link, &card->num_links); + if (ret) + return ret; + card->driver_name = "avs_probe_mb"; card->long_name = card->name = "AVS PROBE"; card->dev = dev; card->owner = THIS_MODULE; - card->dai_link = probe_mb_dai_links; - card->num_links = ARRAY_SIZE(probe_mb_dai_links); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 1a78108293dfe421255ee0abd69ef73e5c68539a Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:47 +0200 Subject: [PATCH 1140/1292] ASoC: Intel: avs: rt274: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-12-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt274.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index ec5382925157a6..67d2c4585cddc4 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -147,8 +147,8 @@ static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pc return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -158,8 +158,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -174,6 +172,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -214,18 +213,16 @@ static int avs_rt274_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -257,10 +254,6 @@ static int avs_rt274_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 210233c24d248e69b5309d651ab4b1021c6631e7 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:48 +0200 Subject: [PATCH 1141/1292] ASoC: Intel: avs: rt286: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-13-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt286.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 2566e971ce1cce..4c9ac545555a56 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -115,8 +115,8 @@ static const struct snd_soc_ops avs_rt286_ops = { .hw_params = avs_rt286_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -126,8 +126,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -142,6 +140,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -183,18 +182,16 @@ static int avs_rt286_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); @@ -227,10 +224,6 @@ static int avs_rt286_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From fffac55850d20c81f386938b4fa29e13cdf66b99 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:49 +0200 Subject: [PATCH 1142/1292] ASoC: Intel: avs: rt298: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-14-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt298.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index 7be34c8ad167a9..2d7a7748d5777f 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -132,8 +132,8 @@ static const struct snd_soc_ops avs_rt298_ops = { .hw_params = avs_rt298_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -143,8 +143,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -159,6 +157,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -203,18 +202,16 @@ static int avs_rt298_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -246,10 +243,6 @@ static int avs_rt298_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 69fe78271da6d7a8d43edd1797c245d22449256c Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:50 +0200 Subject: [PATCH 1143/1292] ASoC: Intel: avs: rt5514: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-15-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5514.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index 45f091f2ce22d0..00b99e36d23ca1 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -84,8 +84,8 @@ static const struct snd_soc_ops avs_rt5514_ops = { .hw_params = avs_rt5514_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -95,8 +95,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -111,6 +109,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -136,18 +135,16 @@ static int avs_rt5514_probe(struct platform_device *pdev) struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -173,10 +170,6 @@ static int avs_rt5514_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From b0e52296aa83bdbed0130ff89948bbb0ef1ee024 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:51 +0200 Subject: [PATCH 1144/1292] ASoC: Intel: avs: rt5663: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-16-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5663.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 51648801710af1..68fea325376ac0 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -134,8 +134,8 @@ static const struct snd_soc_ops avs_rt5663_ops = { }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -145,8 +145,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -161,6 +159,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -202,18 +201,16 @@ static int avs_rt5663_probe(struct platform_device *pdev) struct snd_soc_card *card; struct rt5663_private *priv; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -245,10 +242,6 @@ static int avs_rt5663_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, priv); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 6c402acec635969f2a48ff642b84f2eac0054175 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:52 +0200 Subject: [PATCH 1145/1292] ASoC: Intel: avs: rt5682: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-17-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/rt5682.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 9677b9ebeff10f..81863728da1d90 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -204,8 +204,8 @@ avs_rt5682_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_param return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -215,8 +215,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -231,6 +229,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -272,7 +271,6 @@ static int avs_rt5682_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; if (pdev->id_entry && pdev->id_entry->driver_data) @@ -282,14 +280,13 @@ static int avs_rt5682_probe(struct platform_device *pdev) dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk); mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -321,10 +318,6 @@ static int avs_rt5682_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From ce57b718006a069226b5e5d3afe7969acd59154e Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 2 Sep 2025 11:48:53 +0200 Subject: [PATCH 1146/1292] ASoC: Intel: avs: ssm4567: Adjust platform name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name of the platform component matches the name of the card's platform_device. This allows for simplifying card and dai_link initialization: - drop mach->mach_params.platform usage - drop snd_soc_fixup_dai_links_platform_name() usage Signed-off-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Message-ID: <20250902094853.1231842-18-cezary.rojewski@intel.com> Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/ssm4567.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index 3786eef8c494f8..ae0e6e27a8b856 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -81,8 +81,8 @@ avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_para return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -92,8 +92,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -111,6 +109,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in !dl->codecs[1].name || !dl->codecs[1].dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 2; dl->platforms = platform; @@ -135,18 +134,16 @@ static int avs_ssm4567_probe(struct platform_device *pdev) struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -176,10 +173,6 @@ static int avs_ssm4567_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - return devm_snd_soc_register_deferrable_card(dev, card); } From 5ab26b8ca5649e4a16e4b48efe5a0b92299c8f51 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Sep 2025 15:00:39 +0100 Subject: [PATCH 1147/1292] ASoC: qcom: x1e80100: set card driver name from match data Sound machine drivers for Qualcomm SoCs can be reused across multiple SoCs. But user space ALSA UCM files depend on the card driver name which should be set per board/SoC. Allow such customization by using driver match data as sound card driver name. Signed-off-by: Srinivas Kandagatla Message-ID: <20250902140044.54508-2-srinivas.kandagatla@oss.qualcomm.com> Signed-off-by: Mark Brown --- sound/soc/qcom/x1e80100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index 8eb57fc12f0dab..322010d54af632 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -210,14 +210,14 @@ static int x1e80100_platform_probe(struct platform_device *pdev) if (ret) return ret; - card->driver_name = "x1e80100"; + card->driver_name = of_device_get_match_data(dev); x1e80100_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } static const struct of_device_id snd_x1e80100_dt_match[] = { - { .compatible = "qcom,x1e80100-sndcard", }, + { .compatible = "qcom,x1e80100-sndcard", .data = "x1e80100" }, {} }; MODULE_DEVICE_TABLE(of, snd_x1e80100_dt_match); From 8f48b160e1b8f0c959e25df63994e6204b3794a8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Sep 2025 15:00:40 +0100 Subject: [PATCH 1148/1292] ASoC: dt-bindings: qcom,sm8250: Add glymur sound card Document the bindings for the glymur sound card which is audioreach based architecture. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Message-ID: <20250902140044.54508-3-srinivas.kandagatla@oss.qualcomm.com> Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 5d3dbb6cb1ae89..8ac91625dce5cc 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -31,6 +31,7 @@ properties: - fairphone,fp4-sndcard - fairphone,fp5-sndcard - qcom,apq8096-sndcard + - qcom,glymur-sndcard - qcom,qcm6490-idp-sndcard - qcom,qcs6490-rb3gen2-sndcard - qcom,qcs8275-sndcard From 8c7ea98650e644ff61d3774085f732b40d8f7788 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Sep 2025 15:00:41 +0100 Subject: [PATCH 1149/1292] ASoC: qcom: x1e80100: add compatible for glymur SoC Add support for glymur SoC based sound card support. Signed-off-by: Srinivas Kandagatla Message-ID: <20250902140044.54508-4-srinivas.kandagatla@oss.qualcomm.com> Signed-off-by: Mark Brown --- sound/soc/qcom/x1e80100.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index 322010d54af632..444f2162889f7d 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -218,6 +218,7 @@ static int x1e80100_platform_probe(struct platform_device *pdev) static const struct of_device_id snd_x1e80100_dt_match[] = { { .compatible = "qcom,x1e80100-sndcard", .data = "x1e80100" }, + { .compatible = "qcom,glymur-sndcard", .data = "glymur" }, {} }; MODULE_DEVICE_TABLE(of, snd_x1e80100_dt_match); From 25436580f025d42bd7ccf3b960f4c405f3c91512 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Sep 2025 15:00:42 +0100 Subject: [PATCH 1150/1292] ASoC: dt-bindings: qcom: Add Glymur LPASS wsa and va macro codecs Document compatibles for Qualcomm Glymur SoC macro digital codecs (VA and WSA), compatible with previous generation (SM8550 and SM8650). Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Message-ID: <20250902140044.54508-5-srinivas.kandagatla@oss.qualcomm.com> Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml | 1 + .../devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index dd549db6c841b8..2e8c26d89b0028 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -20,6 +20,7 @@ properties: - qcom,sc8280xp-lpass-va-macro - items: - enum: + - qcom,glymur-lpass-va-macro - qcom,sm8650-lpass-va-macro - qcom,sm8750-lpass-va-macro - qcom,x1e80100-lpass-va-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml index 9082e363c70943..b6f5ba5d1320b5 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml @@ -20,6 +20,7 @@ properties: - qcom,sc8280xp-lpass-wsa-macro - items: - enum: + - qcom,glymur-lpass-wsa-macro - qcom,sm8650-lpass-wsa-macro - qcom,sm8750-lpass-wsa-macro - qcom,x1e80100-lpass-wsa-macro From c73e2c5672dae4f6711cab99cabff9e72cd0591a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Sep 2025 15:00:43 +0100 Subject: [PATCH 1151/1292] ASoC: codecs: lpass-macro: add Codec version 2.9 Add support for lpass codec macro version 2.9, which is available in Qualcomm Glymur SoCs. Its compatible with 2.8 w.r.t register layouts. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Message-ID: <20250902140044.54508-6-srinivas.kandagatla@oss.qualcomm.com> Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-macro-common.h | 1 + sound/soc/codecs/lpass-va-macro.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index fb4b96cb2b232d..10ad682019fa7b 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -29,6 +29,7 @@ enum lpass_codec_version { LPASS_CODEC_VERSION_2_6, LPASS_CODEC_VERSION_2_7, LPASS_CODEC_VERSION_2_8, + LPASS_CODEC_VERSION_2_9, }; struct lpass_macro { diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index a49551f3fb29a6..2e1b77973a3e98 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1485,6 +1485,8 @@ static void va_macro_set_lpass_codec_version(struct va_macro *va) version = LPASS_CODEC_VERSION_2_7; if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x80 || core_id_2 == 0x81)) version = LPASS_CODEC_VERSION_2_8; + if ((core_id_0 == 0x02) && (core_id_1 == 0x0F) && (core_id_2 == 0x90 || core_id_2 == 0x91)) + version = LPASS_CODEC_VERSION_2_9; if (version == LPASS_CODEC_VERSION_UNKNOWN) dev_warn(va->dev, "Unknown Codec version, ID: %02x / %02x / %02x\n", From ce1a46b2d6a8465a86f7a6f71beb4c6de83bce5c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Sep 2025 15:00:44 +0100 Subject: [PATCH 1152/1292] ASoC: codecs: lpass-wsa-macro: add Codev version 2.9 Add support for lpass wsa codec macro version 2.9, which is available in Qualcomm Glymur SoCs. Its compatible with 2.8 w.r.t register layouts Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Message-ID: <20250902140044.54508-7-srinivas.kandagatla@oss.qualcomm.com> Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index da6adb3de21d77..187805b3926454 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2690,6 +2690,7 @@ static int wsa_macro_component_probe(struct snd_soc_component *comp) case LPASS_CODEC_VERSION_2_6: case LPASS_CODEC_VERSION_2_7: case LPASS_CODEC_VERSION_2_8: + case LPASS_CODEC_VERSION_2_9: widgets = wsa_macro_dapm_widgets_v2_5; num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_5); break; @@ -2838,6 +2839,7 @@ static int wsa_macro_probe(struct platform_device *pdev) case LPASS_CODEC_VERSION_2_6: case LPASS_CODEC_VERSION_2_7: case LPASS_CODEC_VERSION_2_8: + case LPASS_CODEC_VERSION_2_9: wsa->reg_layout = &wsa_codec_v2_5; def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_5); reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults), From 1991a458528588ff34e98b6365362560d208710f Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Wed, 3 Sep 2025 13:56:24 +0200 Subject: [PATCH 1153/1292] spi: spi-qpic-snand: unregister ECC engine on probe error and device remove The on-host hardware ECC engine remains registered both when the spi_register_controller() function returns with an error and also on device removal. Change the qcom_spi_probe() function to unregister the engine on the error path, and add the missing unregistering call to qcom_spi_remove() to avoid possible use-after-free issues. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Gabor Juhos Message-ID: <20250903-qpic-snand-unregister-ecceng-v1-1-ef5387b0abdc@gmail.com> Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 0ceaad7dba3cb5..780abb967822a5 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -1615,11 +1615,13 @@ static int qcom_spi_probe(struct platform_device *pdev) ret = spi_register_controller(ctlr); if (ret) { dev_err(&pdev->dev, "spi_register_controller failed.\n"); - goto err_spi_init; + goto err_register_controller; } return 0; +err_register_controller: + nand_ecc_unregister_on_host_hw_engine(&snandc->qspi->ecc_eng); err_spi_init: qcom_nandc_unalloc(snandc); err_snand_alloc: @@ -1641,7 +1643,7 @@ static void qcom_spi_remove(struct platform_device *pdev) struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi_unregister_controller(ctlr); - + nand_ecc_unregister_on_host_hw_engine(&snandc->qspi->ecc_eng); qcom_nandc_unalloc(snandc); clk_disable_unprepare(snandc->aon_clk); From ba3319e5905710abe495b11a1aaf03ebb51d62e2 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Tue, 26 Aug 2025 00:27:47 -0500 Subject: [PATCH 1154/1292] cpufreq/amd-pstate: Fix a regression leading to EPP 0 after resume During the suspend sequence the cached CPPC request is destroyed with the expectation that it's restored during resume. This assumption broke when the separate cache EPP variable was removed, and then it was broken again by commit 608a76b65288 ("cpufreq/amd-pstate: Add support for the "Requested CPU Min frequency" BIOS option") which explicitly set it to zero during suspend. Remove the invalidation and set the value during the suspend call to update limits so that the cached variable can be used to restore on resume. Fixes: 608a76b65288 ("cpufreq/amd-pstate: Add support for the "Requested CPU Min frequency" BIOS option") Fixes: b7a41156588a ("cpufreq/amd-pstate: Invalidate cppc_req_cached during suspend") Reported-by: goldens Closes: https://community.frame.work/t/increased-power-usage-after-resuming-from-suspend-on-ryzen-7040-kernel-6-15-regression/ Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2391221 Tested-by: goldens Tested-by: Willian Wang Reported-by: Vincent Mauirn Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219981 Tested-by: Alex De Lorenzo Reviewed-by: Gautham R. Shenoy Link: https://lore.kernel.org/r/20250826052747.2240670-1-superm1@kernel.org Signed-off-by: Mario Limonciello (AMD) --- drivers/cpufreq/amd-pstate.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 5cd91489fcbe58..b4c79fde1979b6 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -1628,13 +1628,14 @@ static int amd_pstate_suspend(struct cpufreq_policy *policy) * min_perf value across kexec reboots. If this CPU is just resumed back without kexec, * the limits, epp and desired perf will get reset to the cached values in cpudata struct */ - ret = amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false); + ret = amd_pstate_update_perf(policy, perf.bios_min_perf, + FIELD_GET(AMD_CPPC_DES_PERF_MASK, cpudata->cppc_req_cached), + FIELD_GET(AMD_CPPC_MAX_PERF_MASK, cpudata->cppc_req_cached), + FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached), + false); if (ret) return ret; - /* invalidate to ensure it's rewritten during resume */ - cpudata->cppc_req_cached = 0; - /* set this flag to avoid setting core offline*/ cpudata->suspended = true; From 5ebf512f335053a42482ebff91e46c6dc156bf8c Mon Sep 17 00:00:00 2001 From: Christian Loehle Date: Wed, 3 Sep 2025 16:48:32 +0100 Subject: [PATCH 1155/1292] sched: Fix sched_numa_find_nth_cpu() if mask offline sched_numa_find_nth_cpu() uses a bsearch to look for the 'closest' CPU in sched_domains_numa_masks and given cpus mask. However they might not intersect if all CPUs in the cpus mask are offline. bsearch will return NULL in that case, bail out instead of dereferencing a bogus pointer. The previous behaviour lead to this bug when using maxcpus=4 on an rk3399 (LLLLbb) (i.e. booting with all big CPUs offline): [ 1.422922] Unable to handle kernel paging request at virtual address ffffff8000000000 [ 1.423635] Mem abort info: [ 1.423889] ESR = 0x0000000096000006 [ 1.424227] EC = 0x25: DABT (current EL), IL = 32 bits [ 1.424715] SET = 0, FnV = 0 [ 1.424995] EA = 0, S1PTW = 0 [ 1.425279] FSC = 0x06: level 2 translation fault [ 1.425735] Data abort info: [ 1.425998] ISV = 0, ISS = 0x00000006, ISS2 = 0x00000000 [ 1.426499] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 1.426952] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 1.427428] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000004a9f000 [ 1.428038] [ffffff8000000000] pgd=18000000f7fff403, p4d=18000000f7fff403, pud=18000000f7fff403, pmd=0000000000000000 [ 1.429014] Internal error: Oops: 0000000096000006 [#1] SMP [ 1.429525] Modules linked in: [ 1.429813] CPU: 3 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.17.0-rc4-dirty #343 PREEMPT [ 1.430559] Hardware name: Pine64 RockPro64 v2.1 (DT) [ 1.431012] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 1.431634] pc : sched_numa_find_nth_cpu+0x2a0/0x488 [ 1.432094] lr : sched_numa_find_nth_cpu+0x284/0x488 [ 1.432543] sp : ffffffc084e1b960 [ 1.432843] x29: ffffffc084e1b960 x28: ffffff80078a8800 x27: ffffffc0846eb1d0 [ 1.433495] x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000000 [ 1.434144] x23: 0000000000000000 x22: fffffffffff7f093 x21: ffffffc081de6378 [ 1.434792] x20: 0000000000000000 x19: 0000000ffff7f093 x18: 00000000ffffffff [ 1.435441] x17: 3030303866666666 x16: 66663d736b73616d x15: ffffffc104e1b5b7 [ 1.436091] x14: 0000000000000000 x13: ffffffc084712860 x12: 0000000000000372 [ 1.436739] x11: 0000000000000126 x10: ffffffc08476a860 x9 : ffffffc084712860 [ 1.437389] x8 : 00000000ffffefff x7 : ffffffc08476a860 x6 : 0000000000000000 [ 1.438036] x5 : 000000000000bff4 x4 : 0000000000000000 x3 : 0000000000000000 [ 1.438683] x2 : 0000000000000000 x1 : ffffffc0846eb000 x0 : ffffff8000407b68 [ 1.439332] Call trace: [ 1.439559] sched_numa_find_nth_cpu+0x2a0/0x488 (P) [ 1.440016] smp_call_function_any+0xc8/0xd0 [ 1.440416] armv8_pmu_init+0x58/0x27c [ 1.440770] armv8_cortex_a72_pmu_init+0x20/0x2c [ 1.441199] arm_pmu_device_probe+0x1e4/0x5e8 [ 1.441603] armv8_pmu_device_probe+0x1c/0x28 [ 1.442007] platform_probe+0x5c/0xac [ 1.442347] really_probe+0xbc/0x298 [ 1.442683] __driver_probe_device+0x78/0x12c [ 1.443087] driver_probe_device+0xdc/0x160 [ 1.443475] __driver_attach+0x94/0x19c [ 1.443833] bus_for_each_dev+0x74/0xd4 [ 1.444190] driver_attach+0x24/0x30 [ 1.444525] bus_add_driver+0xe4/0x208 [ 1.444874] driver_register+0x60/0x128 [ 1.445233] __platform_driver_register+0x24/0x30 [ 1.445662] armv8_pmu_driver_init+0x28/0x4c [ 1.446059] do_one_initcall+0x44/0x25c [ 1.446416] kernel_init_freeable+0x1dc/0x3bc [ 1.446820] kernel_init+0x20/0x1d8 [ 1.447151] ret_from_fork+0x10/0x20 [ 1.447493] Code: 90022e21 f000e5f5 910de2b5 2a1703e2 (f8767803) [ 1.448040] ---[ end trace 0000000000000000 ]--- [ 1.448483] note: swapper/0[1] exited with preempt_count 1 [ 1.449047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 1.449741] SMP: stopping secondary CPUs [ 1.450105] Kernel Offset: disabled [ 1.450419] CPU features: 0x000000,00080000,20002001,0400421b [ 1.450935] Memory Limit: none [ 1.451217] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- Yury: with the fix, the function returns cpu == nr_cpu_ids, and later in smp_call_function_any -> smp_call_function_single -> generic_exec_single we test the cpu for '>= nr_cpu_ids' and return -ENXIO. So everything is handled correctly. Fixes: cd7f55359c90 ("sched: add sched_numa_find_nth_cpu()") Cc: stable@vger.kernel.org Signed-off-by: Christian Loehle Signed-off-by: Yury Norov (NVIDIA) --- kernel/sched/topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 977e133bb8a443..6e2f54169e66c0 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -2201,6 +2201,8 @@ int sched_numa_find_nth_cpu(const struct cpumask *cpus, int cpu, int node) goto unlock; hop_masks = bsearch(&k, k.masks, sched_domains_numa_levels, sizeof(k.masks[0]), hop_cmp); + if (!hop_masks) + goto unlock; hop = hop_masks - k.masks; ret = hop ? From d302effafae5a6a632bf581ced97ef91c95a2ac6 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Wed, 13 Aug 2025 19:44:38 +0200 Subject: [PATCH 1156/1292] ARM: at91: select ARCH_MICROCHIP Like with the ARM64 Microchip platforms, lets add a generic ARCH_MICROCHIP symbol and select it so that drivers that are reused for multiple product generation or lines, can just depend on it instead of adding each SoC symbol as their dependencies. Signed-off-by: Robert Marko Acked-by: Nicolas Ferre Acked-by: Daniel Machon Link: https://lore.kernel.org/r/20250813174720.540015-3-robert.marko@sartura.hr Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 04bd91c72521c3..c5ef27e3cd8f08 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only +config ARCH_MICROCHIP + bool + menuconfig ARCH_AT91 bool "AT91/Microchip SoCs" depends on (CPU_LITTLE_ENDIAN && (ARCH_MULTI_V4T || ARCH_MULTI_V5)) || \ @@ -8,6 +11,7 @@ menuconfig ARCH_AT91 select GPIOLIB select PINCTRL select SOC_BUS + select ARCH_MICROCHIP if ARCH_AT91 config SOC_SAMV7 From 217efb440933bf97a78ef328b211d8a39f4ff171 Mon Sep 17 00:00:00 2001 From: Ryan Wanner Date: Tue, 19 Aug 2025 10:05:24 -0700 Subject: [PATCH 1157/1292] ARM: dts: microchip: sama7d65: Force SDMMC Legacy mode The SDMMC in this IP currently only supports legacy mode due to a hardware quirk, setting the flags to reflect the limitation. Fixes: deaa14ab6b06 ("ARM: dts: microchip: add support for sama7d65_curiosity board") Signed-off-by: Ryan Wanner Acked-by: Nicolas Ferre Link: https://lore.kernel.org/r/20250819170528.126010-1-Ryan.Wanner@microchip.com Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts index 7eaf6ca233ec67..d086437f5e6fcd 100644 --- a/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts +++ b/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts @@ -387,6 +387,8 @@ &sdmmc1 { bus-width = <4>; + no-1-8-v; + sdhci-caps-mask = <0x0 0x00200000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc1_default>; status = "okay"; From 3254959b4dd065eae396cf78ccc1361460b2f53e Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Wed, 3 Sep 2025 22:47:47 +0530 Subject: [PATCH 1158/1292] ASoC: amd: amd_sdw: Add quirks for some new Dell laptops Add a quirk to include the codec amplifier function for Dell SKU's listed in quirk table. Note: In these SKU's, the RT722 codec amplifier is excluded, and an external amplifier is used instead. Signed-off-by: Syed Saba Kareem Message-ID: <20250903171817.2549507-1-syed.sabakareem@amd.com> Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-sdw-legacy-mach.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index c2197b75a7dd8c..5a3cfedacbafd4 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -79,6 +79,22 @@ static const struct dmi_system_id soc_sdw_quirk_table[] = { }, .driver_data = (void *)(ASOC_SDW_CODEC_SPKR), }, + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0DD3"), + }, + .driver_data = (void *)(ASOC_SDW_CODEC_SPKR), + }, + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0DD4"), + }, + .driver_data = (void *)(ASOC_SDW_CODEC_SPKR), + }, {} }; From 666d2206f1ee8a4f21ffbec438381a524a62815b Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 3 Sep 2025 16:15:26 +0100 Subject: [PATCH 1159/1292] perf tests: Fix "PE file support" test build filename__read_build_id() now takes a blocking/non-blocking argument. The original behavior of filename__read_build_id() was blocking so add block=true to fix the build. Fixes: 2c369d91d093 ("perf symbol: Add blocking argument to filename__read_build_id") Signed-off-by: James Clark Reviewed-by: Ian Rogers Reviewed-by: Arnaldo Carvalho de Melo Link: https://lore.kernel.org/r/20250903-james-perf-read-build-id-fix-v1-1-6a694d0a980f@linaro.org Signed-off-by: Namhyung Kim --- tools/perf/tests/pe-file-parsing.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/pe-file-parsing.c b/tools/perf/tests/pe-file-parsing.c index 30c7da79e109b4..8b31d1d05f905f 100644 --- a/tools/perf/tests/pe-file-parsing.c +++ b/tools/perf/tests/pe-file-parsing.c @@ -37,7 +37,7 @@ static int run_dir(const char *d) size_t idx; scnprintf(filename, PATH_MAX, "%s/pe-file.exe", d); - ret = filename__read_build_id(filename, &bid); + ret = filename__read_build_id(filename, &bid, /*block=*/true); TEST_ASSERT_VAL("Failed to read build_id", ret == sizeof(expect_build_id)); TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id, @@ -49,7 +49,7 @@ static int run_dir(const char *d) !strcmp(debuglink, expect_debuglink)); scnprintf(debugfile, PATH_MAX, "%s/%s", d, debuglink); - ret = filename__read_build_id(debugfile, &bid); + ret = filename__read_build_id(debugfile, &bid, /*block=*/true); TEST_ASSERT_VAL("Failed to read debug file build_id", ret == sizeof(expect_build_id)); TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id, From 467e00b30dfe75c4cfc2197ceef1fddca06adc25 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Sep 2025 13:40:50 +0100 Subject: [PATCH 1160/1292] drm/amd/amdgpu: Fix missing error return on kzalloc failure Currently the kzalloc failure check just sets reports the failure and sets the variable ret to -ENOMEM, which is not checked later for this specific error. Fix this by just returning -ENOMEM rather than setting ret. Fixes: 4fb930715468 ("drm/amd/amdgpu: remove redundant host to psp cmd buf allocations") Signed-off-by: Colin Ian King Signed-off-by: Alex Deucher (cherry picked from commit 1ee9d1a0962c13ba5ab7e47d33a80e3b8dc4b52e) --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 23484317a5fa3b..693357caa9a8d7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -448,7 +448,7 @@ static int psp_sw_init(struct amdgpu_ip_block *ip_block) psp->cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); if (!psp->cmd) { dev_err(adev->dev, "Failed to allocate memory to command buffer!\n"); - ret = -ENOMEM; + return -ENOMEM; } adev->psp.xgmi_context.supports_extended_data = From 4540f1d23e7f387880ce46d11b5cd3f27248bf8d Mon Sep 17 00:00:00 2001 From: Stanislav Fort Date: Tue, 2 Sep 2025 14:00:49 +0300 Subject: [PATCH 1161/1292] audit: fix out-of-bounds read in audit_compare_dname_path() When a watch on dir=/ is combined with an fsnotify event for a single-character name directly under / (e.g., creating /a), an out-of-bounds read can occur in audit_compare_dname_path(). The helper parent_len() returns 1 for "/". In audit_compare_dname_path(), when parentlen equals the full path length (1), the code sets p = path + 1 and pathlen = 1 - 1 = 0. The subsequent loop then dereferences p[pathlen - 1] (i.e., p[-1]), causing an out-of-bounds read. Fix this by adding a pathlen > 0 check to the while loop condition to prevent the out-of-bounds access. Cc: stable@vger.kernel.org Fixes: e92eebb0d611 ("audit: fix suffixed '/' filename matching") Reported-by: Stanislav Fort Suggested-by: Linus Torvalds Signed-off-by: Stanislav Fort [PM: subject tweak, sign-off email fixes] Signed-off-by: Paul Moore --- kernel/auditfilter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index e3f42018ed46fa..f7708fe2c45722 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1326,7 +1326,7 @@ int audit_compare_dname_path(const struct qstr *dname, const char *path, int par /* handle trailing slashes */ pathlen -= parentlen; - while (p[pathlen - 1] == '/') + while (pathlen > 0 && p[pathlen - 1] == '/') pathlen--; if (pathlen != dlen) From b4ada0618eed0fbd1b1630f73deb048c592b06a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Tue, 2 Sep 2025 15:59:59 +0000 Subject: [PATCH 1162/1292] tools: ynl-gen: fix nested array counting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The blamed commit introduced the concept of split attribute counting, and later allocating an array to hold them, however TypeArrayNest wasn't updated to use the new counting variable. Abbreviated example from tools/net/ynl/generated/nl80211-user.c: nl80211_if_combination_attributes_parse(...): unsigned int n_limits = 0; [...] ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len) if (type == NL80211_IFACE_COMB_LIMITS) ynl_attr_for_each_nested(attr2, attr) dst->_count.limits++; if (n_limits) { dst->_count.limits = n_limits; /* allocate and parse attributes */ } In the above example n_limits is guaranteed to always be 0, hence the conditional is unsatisfiable and is optimized out. This patch changes the attribute counting to use n_limits++ in the attribute counting loop in the above example. Fixes: 58da455b31ba ("tools: ynl-gen: improve unwind on parsing errors") Signed-off-by: AsbjĆørn Sloth TĆønnesen Link: https://patch.msgid.link/20250902160001.760953-1-ast@fiberby.net Signed-off-by: Jakub Kicinski --- tools/net/ynl/pyynl/ynl_gen_c.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index ef032e17fec44e..eb295756c3bf7b 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -830,7 +830,7 @@ def _attr_get(self, ri, var): 'ynl_attr_for_each_nested(attr2, attr) {', '\tif (ynl_attr_validate(yarg, attr2))', '\t\treturn YNL_PARSE_CB_ERROR;', - f'\t{var}->_count.{self.c_name}++;', + f'\tn_{self.c_name}++;', '}'] return get_lines, None, local_vars From cd6c956fbc13156bcbcca084b46a8380caebc2a8 Mon Sep 17 00:00:00 2001 From: Jonas Jelonek Date: Sun, 31 Aug 2025 10:04:46 +0000 Subject: [PATCH 1163/1292] i2c: rtl9300: fix channel number bound check Fix the current check for number of channels (child nodes in the device tree). Before, this was: if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN) RTL9300_I2C_MUX_NCHAN gives the maximum number of channels so checking with '>=' isn't correct because it doesn't allow the last channel number. Thus, fix it to: if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN) Issue occured on a TP-Link TL-ST1008F v2.0 device (8 SFP+ ports) and fix is tested there. Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") Cc: stable@vger.kernel.org # v6.13+ Signed-off-by: Jonas Jelonek Tested-by: Sven Eckelmann Reviewed-by: Chris Packham Tested-by: Chris Packham # On RTL9302C based board Tested-by: Markus Stockhausen Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250831100457.3114-2-jelonek.jonas@gmail.com --- drivers/i2c/busses/i2c-rtl9300.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index cfafe089102aa2..1a63790f1957d8 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -353,7 +353,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN) + if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN) return dev_err_probe(dev, -EINVAL, "Too many channels\n"); device_for_each_child_node(dev, child) { From 06418cb5a1a542a003fdb4ad8e76ea542d57cfba Mon Sep 17 00:00:00 2001 From: Jonas Jelonek Date: Sun, 31 Aug 2025 10:04:47 +0000 Subject: [PATCH 1164/1292] i2c: rtl9300: ensure data length is within supported range Add an explicit check for the xfer length to 'rtl9300_i2c_config_xfer' to ensure the data length isn't within the supported range. In particular a data length of 0 is not supported by the hardware and causes unintended or destructive behaviour. This limitation becomes obvious when looking at the register documentation [1]. 4 bits are reserved for DATA_WIDTH and the value of these 4 bits is used as N + 1, allowing a data length range of 1 <= len <= 16. Affected by this is the SMBus Quick Operation which works with a data length of 0. Passing 0 as the length causes an underflow of the value due to: (len - 1) & 0xf and effectively specifying a transfer length of 16 via the registers. This causes a 16-byte write operation instead of a Quick Write. For example, on SFP modules without write-protected EEPROM this soft-bricks them by overwriting some initial bytes. For completeness, also add a quirk for the zero length. [1] https://svanheule.net/realtek/longan/register/i2c_mst1_ctrl2 Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") Cc: stable@vger.kernel.org # v6.13+ Signed-off-by: Jonas Jelonek Tested-by: Sven Eckelmann Reviewed-by: Chris Packham Tested-by: Chris Packham # On RTL9302C based board Tested-by: Markus Stockhausen Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250831100457.3114-3-jelonek.jonas@gmail.com --- drivers/i2c/busses/i2c-rtl9300.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index 1a63790f1957d8..2b3e80aa1bdf76 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -99,6 +99,9 @@ static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c { u32 val, mask; + if (len < 1 || len > 16) + return -EINVAL; + val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS; mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK; @@ -323,7 +326,7 @@ static const struct i2c_algorithm rtl9300_i2c_algo = { }; static struct i2c_adapter_quirks rtl9300_i2c_quirks = { - .flags = I2C_AQ_NO_CLK_STRETCH, + .flags = I2C_AQ_NO_CLK_STRETCH | I2C_AQ_NO_ZERO_LEN, .max_read_len = 16, .max_write_len = 16, }; From ede965fd555ac2536cf651893a998dbfd8e57b86 Mon Sep 17 00:00:00 2001 From: Jonas Jelonek Date: Sun, 31 Aug 2025 10:04:48 +0000 Subject: [PATCH 1165/1292] i2c: rtl9300: remove broken SMBus Quick operation support Remove the SMBus Quick operation from this driver because it is not natively supported by the hardware and is wrongly implemented in the driver. The I2C controllers in Realtek RTL9300 and RTL9310 are SMBus-compliant but there doesn't seem to be native support for the SMBus Quick operation. It is not explicitly mentioned in the documentation but looking at the registers which configure an SMBus transaction, one can see that the data length cannot be set to 0. This suggests that the hardware doesn't allow any SMBus message without data bytes (except for those it does on it's own, see SMBus Block Read). The current implementation of SMBus Quick operation passes a length of 0 (which is actually invalid). Before the fix of a bug in a previous commit, this led to a read operation of 16 bytes from any register (the one of a former transaction or any other value. This caused issues like soft-bricked SFP modules after a simple probe with i2cdetect which uses Quick by default. Running this with SFP modules whose EEPROM isn't write-protected, some of the initial bytes are overwritten because a 16-byte write operation is executed instead of a Quick Write. (This temporarily soft-bricked one of my DAC cables.) Because SMBus Quick operation is obviously not supported on these controllers (because a length of 0 cannot be set, even when no register address is set), remove that instead of claiming there is support. There also shouldn't be any kind of emulated 'Quick' which just does another kind of operation in the background. Otherwise, specific issues occur in case of a 'Quick' Write which actually writes unknown data to an unknown register. Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") Cc: stable@vger.kernel.org # v6.13+ Signed-off-by: Jonas Jelonek Tested-by: Sven Eckelmann Reviewed-by: Chris Packham Tested-by: Chris Packham # On RTL9302C based board Tested-by: Markus Stockhausen Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250831100457.3114-4-jelonek.jonas@gmail.com --- drivers/i2c/busses/i2c-rtl9300.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index 2b3e80aa1bdf76..9e1f71fed0feac 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -225,15 +225,6 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s } switch (size) { - case I2C_SMBUS_QUICK: - ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); - if (ret) - goto out_unlock; - ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); - if (ret) - goto out_unlock; - break; - case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_WRITE) { ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); @@ -315,9 +306,9 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s static u32 rtl9300_i2c_func(struct i2c_adapter *a) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; + return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK; } static const struct i2c_algorithm rtl9300_i2c_algo = { From 5d6b58c932ec451a5c41482790eb5b1ecf165a94 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Sep 2025 18:36:03 +0000 Subject: [PATCH 1166/1292] net: lockless sock_i_ino() Followup of commit c51da3f7a161 ("net: remove sock_i_uid()") A recent syzbot report was the trigger for this change. Over the years, we had many problems caused by the read_lock[_bh](&sk->sk_callback_lock) in sock_i_uid(). We could fix smc_diag_dump_proto() or make a more radical move: Instead of waiting for new syzbot reports, cache the socket inode number in sk->sk_ino, so that we no longer need to acquire sk->sk_callback_lock in sock_i_ino(). This makes socket dumps faster (one less cache line miss, and two atomic ops avoided). Prior art: commit 25a9c8a4431c ("netlink: Add __sock_i_ino() for __netlink_diag_dump().") commit 4f9bf2a2f5aa ("tcp: Don't acquire inet_listen_hashbucket::lock with disabled BH.") commit efc3dbc37412 ("rds: Make rds_sock_lock BH rather than IRQ safe.") Fixes: d2d6422f8bd1 ("x86: Allow to enable PREEMPT_RT.") Reported-by: syzbot+50603c05bbdf4dfdaffa@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/68b73804.050a0220.3db4df.01d8.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Reviewed-by: Kuniyuki Iwashima Reviewed-by: Sebastian Andrzej Siewior Link: https://patch.msgid.link/20250902183603.740428-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/sock.h | 17 +++++++++++++---- net/core/sock.c | 22 ---------------------- net/mptcp/protocol.c | 1 - net/netlink/diag.c | 2 +- 4 files changed, 14 insertions(+), 28 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index c8a4b283df6fc4..fb13322a11fcf7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -285,6 +285,7 @@ struct sk_filter; * @sk_ack_backlog: current listen backlog * @sk_max_ack_backlog: listen backlog set in listen() * @sk_uid: user id of owner + * @sk_ino: inode number (zero if orphaned) * @sk_prefer_busy_poll: prefer busypolling over softirq processing * @sk_busy_poll_budget: napi processing budget when busypolling * @sk_priority: %SO_PRIORITY setting @@ -518,6 +519,7 @@ struct sock { u32 sk_ack_backlog; u32 sk_max_ack_backlog; kuid_t sk_uid; + unsigned long sk_ino; spinlock_t sk_peer_lock; int sk_bind_phc; struct pid *sk_peer_pid; @@ -2056,6 +2058,10 @@ static inline int sk_rx_queue_get(const struct sock *sk) static inline void sk_set_socket(struct sock *sk, struct socket *sock) { sk->sk_socket = sock; + if (sock) { + WRITE_ONCE(sk->sk_uid, SOCK_INODE(sock)->i_uid); + WRITE_ONCE(sk->sk_ino, SOCK_INODE(sock)->i_ino); + } } static inline wait_queue_head_t *sk_sleep(struct sock *sk) @@ -2077,6 +2083,7 @@ static inline void sock_orphan(struct sock *sk) sk_set_socket(sk, NULL); sk->sk_wq = NULL; /* Note: sk_uid is unchanged. */ + WRITE_ONCE(sk->sk_ino, 0); write_unlock_bh(&sk->sk_callback_lock); } @@ -2087,20 +2094,22 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) rcu_assign_pointer(sk->sk_wq, &parent->wq); parent->sk = sk; sk_set_socket(sk, parent); - WRITE_ONCE(sk->sk_uid, SOCK_INODE(parent)->i_uid); security_sock_graft(sk, parent); write_unlock_bh(&sk->sk_callback_lock); } +static inline unsigned long sock_i_ino(const struct sock *sk) +{ + /* Paired with WRITE_ONCE() in sock_graft() and sock_orphan() */ + return READ_ONCE(sk->sk_ino); +} + static inline kuid_t sk_uid(const struct sock *sk) { /* Paired with WRITE_ONCE() in sockfs_setattr() */ return READ_ONCE(sk->sk_uid); } -unsigned long __sock_i_ino(struct sock *sk); -unsigned long sock_i_ino(struct sock *sk); - static inline kuid_t sock_net_uid(const struct net *net, const struct sock *sk) { return sk ? sk_uid(sk) : make_kuid(net->user_ns, 0); diff --git a/net/core/sock.c b/net/core/sock.c index 7c26ec8dce630f..158bddd23134c4 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2780,28 +2780,6 @@ void sock_pfree(struct sk_buff *skb) EXPORT_SYMBOL(sock_pfree); #endif /* CONFIG_INET */ -unsigned long __sock_i_ino(struct sock *sk) -{ - unsigned long ino; - - read_lock(&sk->sk_callback_lock); - ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0; - read_unlock(&sk->sk_callback_lock); - return ino; -} -EXPORT_SYMBOL(__sock_i_ino); - -unsigned long sock_i_ino(struct sock *sk) -{ - unsigned long ino; - - local_bh_disable(); - ino = __sock_i_ino(sk); - local_bh_enable(); - return ino; -} -EXPORT_SYMBOL(sock_i_ino); - /* * Allocate a skb from the socket's send buffer. */ diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 9a287b75c1b31b..e6fd97b21e9eea 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3554,7 +3554,6 @@ void mptcp_sock_graft(struct sock *sk, struct socket *parent) write_lock_bh(&sk->sk_callback_lock); rcu_assign_pointer(sk->sk_wq, &parent->wq); sk_set_socket(sk, parent); - WRITE_ONCE(sk->sk_uid, SOCK_INODE(parent)->i_uid); write_unlock_bh(&sk->sk_callback_lock); } diff --git a/net/netlink/diag.c b/net/netlink/diag.c index 61981e01fd6ff1..b8e58132e8af12 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c @@ -168,7 +168,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - __sock_i_ino(sk)) < 0) { + sock_i_ino(sk)) < 0) { ret = 1; break; } From 3bc32fd9db47a20f38b0783364fdb2f2f1c97220 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 1 Sep 2025 12:52:56 +0100 Subject: [PATCH 1167/1292] net: phylink: move PHY interrupt request to non-fail path The blamed commit added code which could return an error after we requested the PHY interrupt. When we return an error, the caller will call phy_detach() which fails to free the interrupt. Rearrange the code such that failing operations happen before the interrupt is requested, thereby allowing phy_detach() to be used. Note that replacing phy_detach() with phy_disconnect() in these paths could lead to freeing an interrupt which was never requested. Fixes: 1942b1c6f687 ("net: phylink: make configuring clock-stop dependent on MAC support") Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1ut35k-00000001UEl-0iq6@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index f1b57e3fdf30c3..c7cb95aa80074a 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2141,9 +2141,6 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising); - if (phy_interrupt_is_valid(phy)) - phy_request_interrupt(phy); - if (pl->config->mac_managed_pm) phy->mac_managed_pm = true; @@ -2160,6 +2157,9 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, ret = 0; } + if (ret == 0 && phy_interrupt_is_valid(phy)) + phy_request_interrupt(phy); + return ret; } From 9d28f94912589f04ab51fbccaef287d4f40e0d1f Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 1 Sep 2025 14:30:18 -0700 Subject: [PATCH 1168/1292] net: thunder_bgx: add a missing of_node_put phy_np needs to get freed, just like the other child nodes. Fixes: 5fc7cf179449 ("net: thunderx: Cleanup PHY probing code.") Signed-off-by: Rosen Penev Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250901213018.47392-1-rosenp@gmail.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/cavium/thunder/thunder_bgx.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 21495b5dce254d..0f913db4814ea8 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -1493,13 +1493,17 @@ static int bgx_init_of_phy(struct bgx *bgx) * this cortina phy, for which there is no driver * support, ignore it. */ - if (phy_np && - !of_device_is_compatible(phy_np, "cortina,cs4223-slice")) { - /* Wait until the phy drivers are available */ - pd = of_phy_find_device(phy_np); - if (!pd) - goto defer; - bgx->lmac[lmac].phydev = pd; + if (phy_np) { + if (!of_device_is_compatible(phy_np, "cortina,cs4223-slice")) { + /* Wait until the phy drivers are available */ + pd = of_phy_find_device(phy_np); + if (!pd) { + of_node_put(phy_np); + goto defer; + } + bgx->lmac[lmac].phydev = pd; + } + of_node_put(phy_np); } lmac++; From 9e3d71a92e561ccc77025689dab25d201fee7a3e Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 1 Sep 2025 14:33:14 -0700 Subject: [PATCH 1169/1292] net: thunder_bgx: decrement cleanup index before use All paths in probe that call goto defer do so before assigning phydev and thus it makes sense to cleanup the prior index. It also fixes a bug where index 0 does not get cleaned up. Fixes: b7d3e3d3d21a ("net: thunderx: Don't leak phy device references on -EPROBE_DEFER condition.") Signed-off-by: Rosen Penev Reviewed-by: Vadim Fedorenko Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250901213314.48599-1-rosenp@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 0f913db4814ea8..9efb60842ad1fe 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -1519,11 +1519,11 @@ static int bgx_init_of_phy(struct bgx *bgx) * for phy devices we may have already found. */ while (lmac) { + lmac--; if (bgx->lmac[lmac].phydev) { put_device(&bgx->lmac[lmac].phydev->mdio.dev); bgx->lmac[lmac].phydev = NULL; } - lmac--; } of_node_put(node); return -EPROBE_DEFER; From a51160f8da850a65afbf165f5bbac7ffb388bf74 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Sep 2025 09:36:08 +0300 Subject: [PATCH 1170/1292] ipv4: Fix NULL vs error pointer check in inet_blackhole_dev_init() The inetdev_init() function never returns NULL. Check for error pointers instead. Fixes: 22600596b675 ("ipv4: give an IPv4 dev to blackhole_netdev") Signed-off-by: Dan Carpenter Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/aLaQWL9NguWmeM1i@stanley.mountain Signed-off-by: Jakub Kicinski --- net/ipv4/devinet.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c47d3828d4f656..942a887bf08930 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -340,14 +340,13 @@ static void inetdev_destroy(struct in_device *in_dev) static int __init inet_blackhole_dev_init(void) { - int err = 0; + struct in_device *in_dev; rtnl_lock(); - if (!inetdev_init(blackhole_netdev)) - err = -ENOMEM; + in_dev = inetdev_init(blackhole_netdev); rtnl_unlock(); - return err; + return PTR_ERR_OR_ZERO(in_dev); } late_initcall(inet_blackhole_dev_init); From cc282f73bc0cbdf3ee7af2f2d3a2ef4e6b19242d Mon Sep 17 00:00:00 2001 From: Mahanta Jambigi Date: Tue, 2 Sep 2025 10:20:41 +0200 Subject: [PATCH 1171/1292] net/smc: Remove validation of reserved bits in CLC Decline message Currently SMC code is validating the reserved bits while parsing the incoming CLC decline message & when this validation fails, its treated as a protocol error. As a result, the SMC connection is terminated instead of falling back to TCP. As per RFC7609[1] specs we shouldn't be validating the reserved bits that is part of CLC message. This patch fixes this issue. CLC Decline message format can viewed here[2]. [1] https://datatracker.ietf.org/doc/html/rfc7609#page-92 [2] https://datatracker.ietf.org/doc/html/rfc7609#page-105 Fixes: 8ade200c269f ("net/smc: add v2 format of CLC decline message") Signed-off-by: Mahanta Jambigi Reviewed-by: Sidraya Jayagond Reviewed-by: Alexandra Winter Reviewed-by: Dust Li Link: https://patch.msgid.link/20250902082041.98996-1-mjambigi@linux.ibm.com Signed-off-by: Jakub Kicinski --- net/smc/smc_clc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c index 5a4db151fe9578..08be56dfb3f24e 100644 --- a/net/smc/smc_clc.c +++ b/net/smc/smc_clc.c @@ -426,8 +426,6 @@ smc_clc_msg_decl_valid(struct smc_clc_msg_decline *dclc) { struct smc_clc_msg_hdr *hdr = &dclc->hdr; - if (hdr->typev1 != SMC_TYPE_R && hdr->typev1 != SMC_TYPE_D) - return false; if (hdr->version == SMC_V1) { if (ntohs(hdr->length) != sizeof(struct smc_clc_msg_decline)) return false; From a125c8fb9ddbcb0602103a50727a476fd30dec01 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Tue, 2 Sep 2025 03:20:55 -0700 Subject: [PATCH 1172/1292] mctp: return -ENOPROTOOPT for unknown getsockopt options In mctp_getsockopt(), unrecognized options currently return -EINVAL. In contrast, mctp_setsockopt() returns -ENOPROTOOPT for unknown options. Update mctp_getsockopt() to also return -ENOPROTOOPT for unknown options. This aligns the behavior of getsockopt() and setsockopt(), and matches the standard kernel socket API convention for handling unsupported options. Fixes: 99ce45d5e7db ("mctp: Implement extended addressing") Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20250902102059.1370008-1-alok.a.tiwari@oracle.com Signed-off-by: Jakub Kicinski --- net/mctp/af_mctp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c index df4e8cf33899be..685524800d70a0 100644 --- a/net/mctp/af_mctp.c +++ b/net/mctp/af_mctp.c @@ -425,7 +425,7 @@ static int mctp_getsockopt(struct socket *sock, int level, int optname, return 0; } - return -EINVAL; + return -ENOPROTOOPT; } /* helpers for reading/writing the tag ioc, handling compatibility across the From 8156210d36a43e76372312c87eb5ea3dbb405a85 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 2 Sep 2025 12:46:42 +0000 Subject: [PATCH 1173/1292] ax25: properly unshare skbs in ax25_kiss_rcv() Bernard Pidoux reported a regression apparently caused by commit c353e8983e0d ("net: introduce per netns packet chains"). skb->dev becomes NULL and we crash in __netif_receive_skb_core(). Before above commit, different kind of bugs or corruptions could happen without a major crash. But the root cause is that ax25_kiss_rcv() can queue/mangle input skb without checking if this skb is shared or not. Many thanks to Bernard Pidoux for his help, diagnosis and tests. We had a similar issue years ago fixed with commit 7aaed57c5c28 ("phonet: properly unshare skbs in phonet_rcv()"). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Bernard Pidoux Closes: https://lore.kernel.org/netdev/1713f383-c538-4918-bc64-13b3288cd542@free.fr/ Tested-by: Bernard Pidoux Signed-off-by: Eric Dumazet Cc: Joerg Reuter Cc: David Ranch Cc: Folkert van Heusden Reviewed-by: Dan Cross Link: https://patch.msgid.link/20250902124642.212705-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ax25/ax25_in.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 1cac25aca63784..f2d66af8635957 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -433,6 +433,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + skb_orphan(skb); if (!net_eq(dev_net(dev), &init_net)) { From 3e681899cc6e6c77eca55dd8c7cc57b27868e8a2 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 3 Sep 2025 20:12:27 +0800 Subject: [PATCH 1174/1292] cpufreq: mediatek: avoid redundant conditions While 'if (i <= 0) ... else if (i > 0) ...' is technically equivalent to 'if (i <= 0) ... else ...', the latter is vastly easier to read because it avoids writing out a condition that is unnecessary. Let's drop such unnecessary conditions. Signed-off-by: Liao Yuanhong Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index fae062a6431fb6..00de1166188ab7 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -123,7 +123,7 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, soc_data->sram_max_volt); return ret; } - } else if (pre_vproc > new_vproc) { + } else { vproc = max(new_vproc, pre_vsram - soc_data->max_volt_shift); ret = regulator_set_voltage(proc_reg, vproc, From 661a4f307fe0f80c1d544e09476ccba9037e8e65 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 27 Aug 2025 19:17:32 +0200 Subject: [PATCH 1175/1292] selftests: netfilter: fix udpclash tool hang Yi Chen reports that 'udpclash' loops forever depending on compiler (and optimization level used); while (x == 1) gets optimized into for (;;). Add volatile qualifier to avoid that. While at it, also run it under timeout(1) and fix the resize script to not ignore the timeout passed as second parameter to insert_flood. Reported-by: Yi Chen Suggested-by: Yi Chen Fixes: 78a588363587 ("selftests: netfilter: add conntrack clash resolution test case") Signed-off-by: Florian Westphal --- tools/testing/selftests/net/netfilter/conntrack_clash.sh | 2 +- tools/testing/selftests/net/netfilter/conntrack_resize.sh | 5 +++-- tools/testing/selftests/net/netfilter/udpclash.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/netfilter/conntrack_clash.sh b/tools/testing/selftests/net/netfilter/conntrack_clash.sh index 606a43a60f7368..7fc6c5dbd5516e 100755 --- a/tools/testing/selftests/net/netfilter/conntrack_clash.sh +++ b/tools/testing/selftests/net/netfilter/conntrack_clash.sh @@ -99,7 +99,7 @@ run_one_clash_test() local entries local cre - if ! ip netns exec "$ns" ./udpclash $daddr $dport;then + if ! ip netns exec "$ns" timeout 30 ./udpclash $daddr $dport;then echo "INFO: did not receive expected number of replies for $daddr:$dport" ip netns exec "$ctns" conntrack -S # don't fail: check if clash resolution triggered after all. diff --git a/tools/testing/selftests/net/netfilter/conntrack_resize.sh b/tools/testing/selftests/net/netfilter/conntrack_resize.sh index 788cd56ea4a0dc..615fe3c6f405da 100755 --- a/tools/testing/selftests/net/netfilter/conntrack_resize.sh +++ b/tools/testing/selftests/net/netfilter/conntrack_resize.sh @@ -187,7 +187,7 @@ ct_udpclash() [ -x udpclash ] || return while [ $now -lt $end ]; do - ip netns exec "$ns" ./udpclash 127.0.0.1 $((RANDOM%65536)) > /dev/null 2>&1 + ip netns exec "$ns" timeout 30 ./udpclash 127.0.0.1 $((RANDOM%65536)) > /dev/null 2>&1 now=$(date +%s) done @@ -277,6 +277,7 @@ check_taint() insert_flood() { local n="$1" + local timeout="$2" local r=0 r=$((RANDOM%$insert_count)) @@ -302,7 +303,7 @@ test_floodresize_all() read tainted_then < /proc/sys/kernel/tainted for n in "$nsclient1" "$nsclient2";do - insert_flood "$n" & + insert_flood "$n" "$timeout" & done # resize table constantly while flood/insert/dump/flushs diff --git a/tools/testing/selftests/net/netfilter/udpclash.c b/tools/testing/selftests/net/netfilter/udpclash.c index 85c7b906ad08f7..79de163d61ab79 100644 --- a/tools/testing/selftests/net/netfilter/udpclash.c +++ b/tools/testing/selftests/net/netfilter/udpclash.c @@ -29,7 +29,7 @@ struct thread_args { int sockfd; }; -static int wait = 1; +static volatile int wait = 1; static void *thread_main(void *varg) { From 4039ce7ef40474d5ba46f414c50cc7020b9cf8ae Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 7 Aug 2025 15:49:59 +0200 Subject: [PATCH 1176/1292] netfilter: nf_tables: Introduce NFTA_DEVICE_PREFIX This new attribute is supposed to be used instead of NFTA_DEVICE_NAME for simple wildcard interface specs. It holds a NUL-terminated string representing an interface name prefix to match on. While kernel code to distinguish full names from prefixes in NFTA_DEVICE_NAME is simpler than this solution, reusing the existing attribute with different semantics leads to confusion between different versions of kernel and user space though: * With old kernels, wildcards submitted by user space are accepted yet silently treated as regular names. * With old user space, wildcards submitted by kernel may cause crashes since libnftnl expects NUL-termination when there is none. Using a distinct attribute type sanitizes these situations as the receiving part detects and rejects the unexpected attribute nested in *_HOOK_DEVS attributes. Fixes: 6d07a289504a ("netfilter: nf_tables: Support wildcard netdev hook specs") Signed-off-by: Phil Sutter Signed-off-by: Florian Westphal --- include/uapi/linux/netfilter/nf_tables.h | 2 ++ net/netfilter/nf_tables_api.c | 42 +++++++++++++++++------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 2beb30be2c5f8e..8e0eb832bc01ec 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1784,10 +1784,12 @@ enum nft_synproxy_attributes { * enum nft_device_attributes - nf_tables device netlink attributes * * @NFTA_DEVICE_NAME: name of this device (NLA_STRING) + * @NFTA_DEVICE_PREFIX: device name prefix, a simple wildcard (NLA_STRING) */ enum nft_devices_attributes { NFTA_DEVICE_UNSPEC, NFTA_DEVICE_NAME, + NFTA_DEVICE_PREFIX, __NFTA_DEVICE_MAX }; #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 58c5425d61c225..c1082de0965676 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1959,6 +1959,18 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats) return -ENOSPC; } +static bool hook_is_prefix(struct nft_hook *hook) +{ + return strlen(hook->ifname) >= hook->ifnamelen; +} + +static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook) +{ + int attr = hook_is_prefix(hook) ? NFTA_DEVICE_PREFIX : NFTA_DEVICE_NAME; + + return nla_put_string(skb, attr, hook->ifname); +} + static int nft_dump_basechain_hook(struct sk_buff *skb, const struct net *net, int family, const struct nft_base_chain *basechain, @@ -1990,16 +2002,15 @@ static int nft_dump_basechain_hook(struct sk_buff *skb, if (!first) first = hook; - if (nla_put(skb, NFTA_DEVICE_NAME, - hook->ifnamelen, hook->ifname)) + if (nft_nla_put_hook_dev(skb, hook)) goto nla_put_failure; n++; } nla_nest_end(skb, nest_devs); if (n == 1 && - nla_put(skb, NFTA_HOOK_DEV, - first->ifnamelen, first->ifname)) + !hook_is_prefix(first) && + nla_put_string(skb, NFTA_HOOK_DEV, first->ifname)) goto nla_put_failure; } nla_nest_end(skb, nest); @@ -2310,7 +2321,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain) } static struct nft_hook *nft_netdev_hook_alloc(struct net *net, - const struct nlattr *attr) + const struct nlattr *attr, + bool prefix) { struct nf_hook_ops *ops; struct net_device *dev; @@ -2327,7 +2339,8 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net, if (err < 0) goto err_hook_free; - hook->ifnamelen = nla_len(attr); + /* include the terminating NUL-char when comparing non-prefixes */ + hook->ifnamelen = strlen(hook->ifname) + !prefix; /* nf_tables_netdev_event() is called under rtnl_mutex, this is * indirectly serializing all the other holders of the commit_mutex with @@ -2374,14 +2387,22 @@ static int nf_tables_parse_netdev_hooks(struct net *net, struct nft_hook *hook, *next; const struct nlattr *tmp; int rem, n = 0, err; + bool prefix; nla_for_each_nested(tmp, attr, rem) { - if (nla_type(tmp) != NFTA_DEVICE_NAME) { + switch (nla_type(tmp)) { + case NFTA_DEVICE_NAME: + prefix = false; + break; + case NFTA_DEVICE_PREFIX: + prefix = true; + break; + default: err = -EINVAL; goto err_hook; } - hook = nft_netdev_hook_alloc(net, tmp); + hook = nft_netdev_hook_alloc(net, tmp, prefix); if (IS_ERR(hook)) { NL_SET_BAD_ATTR(extack, tmp); err = PTR_ERR(hook); @@ -2427,7 +2448,7 @@ static int nft_chain_parse_netdev(struct net *net, struct nlattr *tb[], int err; if (tb[NFTA_HOOK_DEV]) { - hook = nft_netdev_hook_alloc(net, tb[NFTA_HOOK_DEV]); + hook = nft_netdev_hook_alloc(net, tb[NFTA_HOOK_DEV], false); if (IS_ERR(hook)) { NL_SET_BAD_ATTR(extack, tb[NFTA_HOOK_DEV]); return PTR_ERR(hook); @@ -9458,8 +9479,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, list_for_each_entry_rcu(hook, hook_list, list, lockdep_commit_lock_is_held(net)) { - if (nla_put(skb, NFTA_DEVICE_NAME, - hook->ifnamelen, hook->ifname)) + if (nft_nla_put_hook_dev(skb, hook)) goto nla_put_failure; } nla_nest_end(skb, nest_devs); From 0a228624bcc00af41f281a2a84c928595a74c17d Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Mon, 1 Sep 2025 14:35:37 +0800 Subject: [PATCH 1177/1292] net: atm: fix memory leak in atm_register_sysfs when device_register fail When device_register() return error in atm_register_sysfs(), which can be triggered by kzalloc fail in device_private_init() or other reasons, kmemleak reports the following memory leaks: unreferenced object 0xffff88810182fb80 (size 8): comm "insmod", pid 504, jiffies 4294852464 hex dump (first 8 bytes): 61 64 75 6d 6d 79 30 00 adummy0. backtrace (crc 14dfadaf): __kmalloc_node_track_caller_noprof+0x335/0x450 kvasprintf+0xb3/0x130 kobject_set_name_vargs+0x45/0x120 dev_set_name+0xa9/0xe0 atm_register_sysfs+0xf3/0x220 atm_dev_register+0x40b/0x780 0xffffffffa000b089 do_one_initcall+0x89/0x300 do_init_module+0x27b/0x7d0 load_module+0x54cd/0x5ff0 init_module_from_file+0xe4/0x150 idempotent_init_module+0x32c/0x610 __x64_sys_finit_module+0xbd/0x120 do_syscall_64+0xa8/0x270 entry_SYSCALL_64_after_hwframe+0x77/0x7f When device_create_file() return error in atm_register_sysfs(), the same issue also can be triggered. Function put_device() should be called to release kobj->name memory and other device resource, instead of kfree(). Fixes: 1fa5ae857bb1 ("driver core: get rid of struct device's bus_id string array") Signed-off-by: Wang Liang Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250901063537.1472221-1-wangliang74@huawei.com Signed-off-by: Paolo Abeni --- net/atm/resources.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/atm/resources.c b/net/atm/resources.c index b19d851e1f4439..7c6fdedbcf4e5c 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -112,7 +112,9 @@ struct atm_dev *atm_dev_register(const char *type, struct device *parent, if (atm_proc_dev_register(dev) < 0) { pr_err("atm_proc_dev_register failed for dev %s\n", type); - goto out_fail; + mutex_unlock(&atm_dev_mutex); + kfree(dev); + return NULL; } if (atm_register_sysfs(dev, parent) < 0) { @@ -128,7 +130,7 @@ struct atm_dev *atm_dev_register(const char *type, struct device *parent, return dev; out_fail: - kfree(dev); + put_device(&dev->class_dev); dev = NULL; goto out; } From 68f27f7c7708183e7873c585ded2f1b057ac5b97 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 4 Sep 2025 12:18:50 +0200 Subject: [PATCH 1178/1292] ASoC: qcom: q6apm-lpass-dais: Fix NULL pointer dereference if source graph failed If earlier opening of source graph fails (e.g. ADSP rejects due to incorrect audioreach topology), the graph is closed and "dai_data->graph[dai->id]" is assigned NULL. Preparing the DAI for sink graph continues though and next call to q6apm_lpass_dai_prepare() receives dai_data->graph[dai->id]=NULL leading to NULL pointer exception: qcom-apm gprsvc:service:2:1: Error (1) Processing 0x01001002 cmd qcom-apm gprsvc:service:2:1: DSP returned error[1001002] 1 q6apm-lpass-dais 30000000.remoteproc:glink-edge:gpr:service@1:bedais: fail to start APM port 78 q6apm-lpass-dais 30000000.remoteproc:glink-edge:gpr:service@1:bedais: ASoC: error at snd_soc_pcm_dai_prepare on TX_CODEC_DMA_TX_3: -22 Unable to handle kernel NULL pointer dereference at virtual address 00000000000000a8 ... Call trace: q6apm_graph_media_format_pcm+0x48/0x120 (P) q6apm_lpass_dai_prepare+0x110/0x1b4 snd_soc_pcm_dai_prepare+0x74/0x108 __soc_pcm_prepare+0x44/0x160 dpcm_be_dai_prepare+0x124/0x1c0 Fixes: 30ad723b93ad ("ASoC: qdsp6: audioreach: add q6apm lpass dai support") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Message-ID: <20250904101849.121503-2-krzysztof.kozlowski@linaro.org> Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index a0d90462fd6a38..20974f10406bfe 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -213,8 +213,10 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s return 0; err: - q6apm_graph_close(dai_data->graph[dai->id]); - dai_data->graph[dai->id] = NULL; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + q6apm_graph_close(dai_data->graph[dai->id]); + dai_data->graph[dai->id] = NULL; + } return rc; } From acd2fa47aac568052bd8321586be64958e3e93b2 Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Wed, 3 Sep 2025 18:01:17 +0200 Subject: [PATCH 1179/1292] ASoC: dt-bindings: everest,es8316: Document routing strings Add a list of the es8316 pin names to the binding's description to make it self-contained and improve the user experience for board developers. Signed-off-by: Jihed Chaibi Acked-by: Rob Herring (Arm) Message-ID: <20250903160119.83625-2-jihed.chaibi.dev@gmail.com> Signed-off-by: Mark Brown --- .../bindings/sound/everest,es8316.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml index e4b2eb5fae2fc2..81a0215050e015 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml @@ -12,6 +12,22 @@ maintainers: - Matteo Martelli - Binbin Zhou +description: | + Everest ES8311, ES8316 and ES8323 audio CODECs + + Pins on the device (for linking into audio routes): + + Outputs: + * LOUT: Left Analog Output + * ROUT: Right Analog Output + * MICBIAS: Microphone Bias + + Inputs: + * MIC1P: Microphone 1 Positive Analog Input + * MIC1N: Microphone 1 Negative Analog Input + * MIC2P: Microphone 2 Positive Analog Input + * MIC2N: Microphone 2 Negative Analog Input + allOf: - $ref: dai-common.yaml# From 118ddab8bb4a06fd5e13446d11d69e301044087d Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Wed, 3 Sep 2025 18:01:18 +0200 Subject: [PATCH 1180/1292] ASoC: dt-bindings: nuvoton,nau8825: Document routing strings Add a list of the nau8825 pin names to the binding's description to make it self-contained and improve the user experience for board developers. Signed-off-by: Jihed Chaibi Acked-by: Rob Herring (Arm) Message-ID: <20250903160119.83625-3-jihed.chaibi.dev@gmail.com> Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nuvoton,nau8825.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml index a54f194a0b4923..4ebbcb4e605698 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml @@ -9,6 +9,20 @@ title: NAU8825 audio CODEC maintainers: - John Hsu +description: | + NAU8825 audio CODEC + + Pins on the device (for linking into audio routes): + + Outputs: + * HPOL : Headphone Left Output + * HPOR : Headphone Right Output + * MICBIAS : Microphone Bias Output + + Inputs: + * MICP : Analog Microphone Positive Input + * MICN : Analog Microphone Negative Input + allOf: - $ref: dai-common.yaml# From 0ccc1eeda155c947d88ef053e0b54e434e218ee2 Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Wed, 3 Sep 2025 18:01:19 +0200 Subject: [PATCH 1181/1292] ASoC: dt-bindings: wlf,wm8960: Document routing strings (pin names) Add a list of the wm8960 pin names to the binding's description to make it self-contained and improve the user experience for board developers. Signed-off-by: Jihed Chaibi Reviewed-by: Charles Keepax Acked-by: Rob Herring (Arm) Message-ID: <20250903160119.83625-4-jihed.chaibi.dev@gmail.com> Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wlf,wm8960.yaml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml index 3c2b9790ffcf59..c8c786cb6c4ba5 100644 --- a/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml +++ b/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml @@ -9,6 +9,28 @@ title: Wolfson WM8960 audio codec maintainers: - patches@opensource.cirrus.com +description: | + Wolfson WM8960 audio codec + + Pins on the device (for linking into audio routes): + + Outputs: + * HP_L : Left Headphone/Line Output + * HP_R : Right Headphone/Line Output + * SPK_LP : Left Speaker Output (Positive) + * SPK_LN : Left Speaker Output (Negative) + * SPK_RP : Right Speaker Output (Positive) + * SPK_RN : Right Speaker Output (Negative) + * OUT3 : Mono, Left, Right or buffered midrail output for capless mode + + Inputs: + * LINPUT1 : Left single-ended or negative differential microphone input + * RINPUT1 : Right single-ended or negative differential microphone input + * LINPUT2 : Left line input or positive differential microphone input + * RINPUT2 : Right line input or positive differential microphone input + * LINPUT3 : Left line input, positive differential microphone, or Jack Detect 2 + * RINPUT3 : Right line input, positive differential microphone, or Jack Detect 3 + properties: compatible: const: wlf,wm8960 From f81e63047600d023cbfda372b6de8f2821ff6839 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Aug 2025 17:37:15 +0100 Subject: [PATCH 1182/1292] ASoC: SDCA: Fix return value in sdca_regmap_mbq_size() The MBQ size function returns an integer representing the size of a Control. Currently if the Control is not found the function will return false which makes little sense. Correct this typo to return -EINVAL. Fixes: e3f7caf74b79 ("ASoC: SDCA: Add generic regmap SDCA helpers") Signed-off-by: Charles Keepax Message-ID: <20250820163717.1095846-2-ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c index 5cb3048ea8cfc3..72f893e00ff506 100644 --- a/sound/soc/sdca/sdca_regmap.c +++ b/sound/soc/sdca/sdca_regmap.c @@ -196,7 +196,7 @@ int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg) control = function_find_control(function, reg); if (!control) - return false; + return -EINVAL; return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32)); } From 16c912ec34edc4d7daecde58e40d480858830a12 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Aug 2025 17:37:16 +0100 Subject: [PATCH 1183/1292] ASoC: SDCA: Fix return value in detected_mode_handler() The detected mode IRQ handler should return an irqreturn_t not a regular error code. Correct the return value in detected_mode_handler(). Fixes: b9ab3b618241 ("ASoC: SDCA: Add some initial IRQ handlers") Signed-off-by: Charles Keepax Message-ID: <20250820163717.1095846-3-ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown --- sound/soc/sdca/sdca_interrupts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index 8018773ee4265e..79bf3042f57d42 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -155,7 +155,7 @@ static irqreturn_t detected_mode_handler(int irq, void *data) SDCA_CTL_SELECTED_MODE_NAME); if (!name) - return -ENOMEM; + return IRQ_NONE; kctl = snd_soc_component_get_kcontrol(component, name); if (!kctl) { From ec630c2c8ce215dd365b8c3644f004f645714a0f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Aug 2025 17:37:17 +0100 Subject: [PATCH 1184/1292] ASoC: SDCA: Reorder members of hide struct to remove holes Remove some padding holes in the sdca_entity_hide struct by reordering the members. Signed-off-by: Charles Keepax Message-ID: <20250820163717.1095846-4-ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 06ec126cdcc34a..ea68856e4c8c44 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -1063,27 +1063,30 @@ struct sdca_entity_ge { /** * struct sdca_entity_hide - information specific to HIDE Entities * @hid: HID device structure - * @hidtx_ids: HIDTx Report ID * @num_hidtx_ids: number of HIDTx Report ID - * @hidrx_ids: HIDRx Report ID * @num_hidrx_ids: number of HIDRx Report ID - * @hide_reside_function_num: indicating which Audio Function Numbers within this Device - * @max_delay: the maximum time in microseconds allowed for the Device to change the ownership from Device to Host - * @af_number_list: which Audio Function Numbers within this Device are sending/receiving the messages in this HIDE - * @hid_desc: HID descriptor for the HIDE Entity + * @hidtx_ids: HIDTx Report ID + * @hidrx_ids: HIDRx Report ID + * @af_number_list: which Audio Function Numbers within this Device are + * sending/receiving the messages in this HIDE + * @hide_reside_function_num: indicating which Audio Function Numbers + * within this Device + * @max_delay: the maximum time in microseconds allowed for the Device + * to change the ownership from Device to Host * @hid_report_desc: HID Report Descriptor for the HIDE Entity + * @hid_desc: HID descriptor for the HIDE Entity */ struct sdca_entity_hide { struct hid_device *hid; unsigned int *hidtx_ids; - int num_hidtx_ids; unsigned int *hidrx_ids; + int num_hidtx_ids; int num_hidrx_ids; + unsigned int af_number_list[SDCA_MAX_FUNCTION_COUNT]; unsigned int hide_reside_function_num; unsigned int max_delay; - unsigned int af_number_list[SDCA_MAX_FUNCTION_COUNT]; - struct hid_descriptor hid_desc; unsigned char *hid_report_desc; + struct hid_descriptor hid_desc; }; /** From 638ca7601f41a3f8368811f3185b06e2547b7a0f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 3 Sep 2025 10:45:44 +0100 Subject: [PATCH 1185/1292] ASoC: cs42l43: Rename system suspend callback and fix debug print There is some confusion around cs42l43_codec_runtime_force_suspend(). This function is the system suspend callback, however the name and the debug print both use the words runtime. Rename the function to the simpler cs42l43_codec_suspend() and correct the debug print. Signed-off-by: Charles Keepax Message-ID: <20250903094549.271068-2-ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index b0c27d696c58a9..4d177994158176 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2386,11 +2386,11 @@ static int cs42l43_codec_runtime_resume(struct device *dev) return 0; } -static int cs42l43_codec_runtime_force_suspend(struct device *dev) +static int cs42l43_codec_suspend(struct device *dev) { struct cs42l43_codec *priv = dev_get_drvdata(dev); - dev_dbg(priv->dev, "Runtime suspend\n"); + dev_dbg(priv->dev, "System suspend\n"); priv->suspend_jack_debounce = true; @@ -2401,7 +2401,7 @@ static int cs42l43_codec_runtime_force_suspend(struct device *dev) static const struct dev_pm_ops cs42l43_codec_pm_ops = { RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) - SYSTEM_SLEEP_PM_OPS(cs42l43_codec_runtime_force_suspend, pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, pm_runtime_force_resume) }; static const struct platform_device_id cs42l43_codec_id_table[] = { From 149dda5f42a8fa6dacf2cff1d16952de28622d30 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 3 Sep 2025 10:45:45 +0100 Subject: [PATCH 1186/1292] ASoC: cs42l43: Store IRQ domain in codec private data To support future refactoring store a pointer to the IRQ domain in the codec private data allowing easier access to it outside of probe. Signed-off-by: Charles Keepax Message-ID: <20250903094549.271068-3-ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43.c | 29 +++++++++++++---------------- sound/soc/codecs/cs42l43.h | 1 + 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 4d177994158176..241f7d013189cc 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2210,13 +2210,12 @@ static const struct cs42l43_irq cs42l43_irqs[] = { }; static int cs42l43_request_irq(struct cs42l43_codec *priv, - struct irq_domain *dom, const char * const name, - unsigned int irq, irq_handler_t handler, - unsigned long flags) + const char * const name, unsigned int irq, + irq_handler_t handler, unsigned long flags) { int ret; - ret = irq_create_mapping(dom, irq); + ret = irq_create_mapping(priv->dom, irq); if (ret < 0) return dev_err_probe(priv->dev, ret, "Failed to map IRQ %s\n", name); @@ -2230,8 +2229,7 @@ static int cs42l43_request_irq(struct cs42l43_codec *priv, return 0; } -static int cs42l43_shutter_irq(struct cs42l43_codec *priv, - struct irq_domain *dom, unsigned int shutter, +static int cs42l43_shutter_irq(struct cs42l43_codec *priv, unsigned int shutter, const char * const open_name, const char * const close_name, irq_handler_t handler) @@ -2259,25 +2257,20 @@ static int cs42l43_shutter_irq(struct cs42l43_codec *priv, return 0; } - ret = cs42l43_request_irq(priv, dom, close_name, close_irq, handler, IRQF_SHARED); + ret = cs42l43_request_irq(priv, close_name, close_irq, handler, IRQF_SHARED); if (ret) return ret; - return cs42l43_request_irq(priv, dom, open_name, open_irq, handler, IRQF_SHARED); + return cs42l43_request_irq(priv, open_name, open_irq, handler, IRQF_SHARED); } static int cs42l43_codec_probe(struct platform_device *pdev) { struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); struct cs42l43_codec *priv; - struct irq_domain *dom; unsigned int val; int i, ret; - dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY); - if (!dom) - return -EPROBE_DEFER; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -2285,6 +2278,10 @@ static int cs42l43_codec_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->core = cs42l43; + priv->dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY); + if (!priv->dom) + return -EPROBE_DEFER; + platform_set_drvdata(pdev, priv); mutex_init(&priv->jack_lock); @@ -2314,7 +2311,7 @@ static int cs42l43_codec_probe(struct platform_device *pdev) goto err_pm; for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) { - ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name, + ret = cs42l43_request_irq(priv, cs42l43_irqs[i].name, cs42l43_irqs[i].irq, cs42l43_irqs[i].handler, 0); if (ret) @@ -2327,13 +2324,13 @@ static int cs42l43_codec_probe(struct platform_device *pdev) goto err_pm; } - ret = cs42l43_shutter_irq(priv, dom, val & CS42L43_MIC_SHUTTER_CFG_MASK, + ret = cs42l43_shutter_irq(priv, val & CS42L43_MIC_SHUTTER_CFG_MASK, "mic shutter open", "mic shutter close", cs42l43_mic_shutter); if (ret) goto err_pm; - ret = cs42l43_shutter_irq(priv, dom, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >> + ret = cs42l43_shutter_irq(priv, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >> CS42L43_SPK_SHUTTER_CFG_SHIFT, "spk shutter open", "spk shutter close", cs42l43_spk_shutter); diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h index 3ea36362b11a4d..f4ef93d1fc2a4d 100644 --- a/sound/soc/codecs/cs42l43.h +++ b/sound/soc/codecs/cs42l43.h @@ -44,6 +44,7 @@ struct cs42l43_codec { struct device *dev; struct cs42l43 *core; struct snd_soc_component *component; + struct irq_domain *dom; struct clk *mclk; From a69b4ba19a07896e7e4246446bad002f5fc0dae1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 3 Sep 2025 10:45:46 +0100 Subject: [PATCH 1187/1292] ASoC: cs42l43: Disable IRQs in system suspend Currently the MFD driver disables all the IRQs upon entering system suspend, however there are some issues with this approach. As this device uses runtime force suspend. The regmap IRQ handler can run, claim a PM runtime reference and get scheduled, the MFD can then force suspend. When the IRQ thread gets rescheduled it will try to access volatile registers on the suspended device. Furthermore, this race also applies to work queue items scheduled by the IRQ handlers. As the MFD code doesn't know about the individual work queue items, the end drivers must mask their own IRQs and sync in any work queues as part of entering system suspend. Update the code here to do so. Signed-off-by: Charles Keepax Message-ID: <20250903094549.271068-4-ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43.c | 78 ++++++++++++++++++++++++++++++-------- sound/soc/codecs/cs42l43.h | 1 + 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 241f7d013189cc..405926149a1375 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2229,12 +2229,29 @@ static int cs42l43_request_irq(struct cs42l43_codec *priv, return 0; } +static void cs42l43_disable_irq(struct cs42l43_codec *priv, unsigned int irq) +{ + int ret; + + ret = irq_find_mapping(priv->dom, irq); + if (ret > 0) + disable_irq(ret); +} + +static void cs42l43_enable_irq(struct cs42l43_codec *priv, unsigned int irq) +{ + int ret; + + ret = irq_find_mapping(priv->dom, irq); + if (ret > 0) + enable_irq(ret); +} + static int cs42l43_shutter_irq(struct cs42l43_codec *priv, unsigned int shutter, - const char * const open_name, - const char * const close_name, + const char * const open_name, unsigned int *open_irq, + const char * const close_name, unsigned int *close_irq, irq_handler_t handler) { - unsigned int open_irq, close_irq; int ret; switch (shutter) { @@ -2242,26 +2259,26 @@ static int cs42l43_shutter_irq(struct cs42l43_codec *priv, unsigned int shutter, dev_warn(priv->dev, "Manual shutters, notifications not available\n"); return 0; case 0x2: - open_irq = CS42L43_GPIO1_RISE; - close_irq = CS42L43_GPIO1_FALL; + *open_irq = CS42L43_GPIO1_RISE; + *close_irq = CS42L43_GPIO1_FALL; break; case 0x4: - open_irq = CS42L43_GPIO2_RISE; - close_irq = CS42L43_GPIO2_FALL; + *open_irq = CS42L43_GPIO2_RISE; + *close_irq = CS42L43_GPIO2_FALL; break; case 0x8: - open_irq = CS42L43_GPIO3_RISE; - close_irq = CS42L43_GPIO3_FALL; + *open_irq = CS42L43_GPIO3_RISE; + *close_irq = CS42L43_GPIO3_FALL; break; default: return 0; } - ret = cs42l43_request_irq(priv, close_name, close_irq, handler, IRQF_SHARED); + ret = cs42l43_request_irq(priv, close_name, *close_irq, handler, IRQF_SHARED); if (ret) return ret; - return cs42l43_request_irq(priv, open_name, open_irq, handler, IRQF_SHARED); + return cs42l43_request_irq(priv, open_name, *open_irq, handler, IRQF_SHARED); } static int cs42l43_codec_probe(struct platform_device *pdev) @@ -2325,14 +2342,16 @@ static int cs42l43_codec_probe(struct platform_device *pdev) } ret = cs42l43_shutter_irq(priv, val & CS42L43_MIC_SHUTTER_CFG_MASK, - "mic shutter open", "mic shutter close", + "mic shutter open", &priv->shutter_irqs[0], + "mic shutter close", &priv->shutter_irqs[1], cs42l43_mic_shutter); if (ret) goto err_pm; ret = cs42l43_shutter_irq(priv, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >> CS42L43_SPK_SHUTTER_CFG_SHIFT, - "spk shutter open", "spk shutter close", + "spk shutter open", &priv->shutter_irqs[2], + "spk shutter close", &priv->shutter_irqs[3], cs42l43_spk_shutter); if (ret) goto err_pm; @@ -2386,19 +2405,48 @@ static int cs42l43_codec_runtime_resume(struct device *dev) static int cs42l43_codec_suspend(struct device *dev) { struct cs42l43_codec *priv = dev_get_drvdata(dev); + int i; dev_dbg(priv->dev, "System suspend\n"); priv->suspend_jack_debounce = true; - pm_runtime_force_suspend(dev); + for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) + cs42l43_disable_irq(priv, cs42l43_irqs[i].irq); + + for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++) + if (priv->shutter_irqs[i]) + cs42l43_disable_irq(priv, priv->shutter_irqs[i]); + + cancel_delayed_work_sync(&priv->bias_sense_timeout); + cancel_delayed_work_sync(&priv->tip_sense_work); + cancel_delayed_work_sync(&priv->hp_ilimit_clear_work); + + return pm_runtime_force_suspend(dev); +} + +static int cs42l43_codec_resume(struct device *dev) +{ + struct cs42l43_codec *priv = dev_get_drvdata(dev); + int ret, i; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) + cs42l43_enable_irq(priv, cs42l43_irqs[i].irq); + + for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++) + if (priv->shutter_irqs[i]) + cs42l43_enable_irq(priv, priv->shutter_irqs[i]); return 0; } static const struct dev_pm_ops cs42l43_codec_pm_ops = { RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) - SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume) }; static const struct platform_device_id cs42l43_codec_id_table[] = { diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h index f4ef93d1fc2a4d..0951ad3525efee 100644 --- a/sound/soc/codecs/cs42l43.h +++ b/sound/soc/codecs/cs42l43.h @@ -45,6 +45,7 @@ struct cs42l43_codec { struct cs42l43 *core; struct snd_soc_component *component; struct irq_domain *dom; + unsigned int shutter_irqs[4]; struct clk *mclk; From dd7ae5b8b3c291c0206f127a564ae1e316705ca0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 3 Sep 2025 10:45:47 +0100 Subject: [PATCH 1188/1292] ASoC: cs42l43: Shutdown jack detection on suspend Fully power down the jack detection on system suspend since the device will not be powered up during. Signed-off-by: Charles Keepax Message-ID: <20250903094549.271068-5-ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43-jack.c | 8 +++++--- sound/soc/codecs/cs42l43.c | 2 ++ sound/soc/codecs/cs42l43.h | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c index 2a0a4986a9ce8f..867e23d4fb8d8b 100644 --- a/sound/soc/codecs/cs42l43-jack.c +++ b/sound/soc/codecs/cs42l43-jack.c @@ -684,7 +684,7 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv) } } -static void cs42l43_clear_jack(struct cs42l43_codec *priv) +void cs42l43_clear_jack(struct cs42l43_codec *priv) { struct cs42l43 *cs42l43 = priv->core; @@ -703,8 +703,6 @@ static void cs42l43_clear_jack(struct cs42l43_codec *priv) regmap_update_bits(cs42l43->regmap, CS42L43_HS2, CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT); - - snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF); } void cs42l43_tip_sense_work(struct work_struct *work) @@ -753,6 +751,8 @@ void cs42l43_tip_sense_work(struct work_struct *work) cs42l43_clear_jack(priv); + snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF); + if (cs42l43->sdw && priv->jack_present) { pm_runtime_put(priv->dev); priv->jack_present = false; @@ -903,6 +903,8 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u cs42l43_clear_jack(priv); + snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF); + if (!override) { queue_delayed_work(system_long_wq, &priv->tip_sense_work, 0); } else { diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 405926149a1375..b61df09f20cf49 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2422,6 +2422,8 @@ static int cs42l43_codec_suspend(struct device *dev) cancel_delayed_work_sync(&priv->tip_sense_work); cancel_delayed_work_sync(&priv->hp_ilimit_clear_work); + cs42l43_clear_jack(priv); + return pm_runtime_force_suspend(dev); } diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h index 0951ad3525efee..b2fa2cd1d99f87 100644 --- a/sound/soc/codecs/cs42l43.h +++ b/sound/soc/codecs/cs42l43.h @@ -132,6 +132,7 @@ static inline int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream int cs42l43_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *d); void cs42l43_bias_sense_timeout(struct work_struct *work); +void cs42l43_clear_jack(struct cs42l43_codec *priv); void cs42l43_tip_sense_work(struct work_struct *work); irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data); irqreturn_t cs42l43_button_press(int irq, void *data); From 7748328c2fd82efed24257b2bfd796eb1fa1d09b Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Wed, 3 Sep 2025 20:43:30 +0530 Subject: [PATCH 1189/1292] ASoC: dt-bindings: qcom,lpass-va-macro: Update bindings for clocks to support ADSP Manage clock settings for ADSP solution. On Existing ADSP bypass solutions, the macro and dcodec GDSCs are enabled using power domains in lpass-va-macro which is not applicable for ADSP based platform. Co-developed-by: Prasad Kumpatla Signed-off-by: Prasad Kumpatla Signed-off-by: Mohammad Rafi Shaik Reviewed-by: Krzysztof Kozlowski Message-ID: <20250903151337.1037246-2-mohammad.rafi.shaik@oss.qualcomm.com> Signed-off-by: Mark Brown --- .../bindings/sound/qcom,lpass-va-macro.yaml | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index 2e8c26d89b0028..1c0d78af3c051f 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -80,12 +80,25 @@ allOf: compatible: contains: const: qcom,sc7280-lpass-va-macro + then: - properties: - clocks: - maxItems: 1 - clock-names: - maxItems: 1 + if: + required: + - power-domains + then: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + else: + properties: + clocks: + minItems: 3 + maxItems: 3 + clock-names: + minItems: 3 + maxItems: 3 - if: properties: From ace1817ab49b3f92b3e965caa63b4a78e69266cd Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Wed, 3 Sep 2025 13:09:45 +0800 Subject: [PATCH 1190/1292] ALSA: usb-audio: rename QUIRK_FLAG_MIXER_MIN_MUTE to QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE As a preparation of introduction QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE Also make it printing an info while applying Signed-off-by: Cryolitia PukNgae Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250903-sound-v1-1-d4ca777b8512@uniontech.com --- sound/usb/mixer_quirks.c | 7 +++++-- sound/usb/quirks.c | 20 ++++++++++---------- sound/usb/usbaudio.h | 4 ++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index b8275c81802e60..2a1abc24dbfc0c 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -4543,9 +4543,12 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, } /* lowest playback value is muted on some devices */ - if (mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_MIN_MUTE) - if (strstr(kctl->id.name, "Playback")) + if (mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE) + if (strstr(kctl->id.name, "Playback")) { + usb_audio_info(mixer->chip, + "applying playback min mute quirk\n"); cval->min_mute = 1; + } /* ALSA-ify some Plantronics headset control names */ if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f && diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 766db7d00cbc95..0fe31af3158f08 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2200,9 +2200,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0572, 0x1b08, /* Conexant Systems (Rockwell), Inc. */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x0572, 0x1b09, /* Conexant Systems (Rockwell), Inc. */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x05a3, 0x9420, /* ELP HD USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x05a7, 0x1020, /* Bose Companion 5 */ @@ -2246,15 +2246,15 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */ QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x0bda, 0x498a, /* Realtek Semiconductor Corp. */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0c45, 0x636b, /* Microdia JP001 USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0d8c, 0x000c, /* C-Media */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x0d8c, 0x0014, /* C-Media */ - QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ QUIRK_FLAG_FIXED_RATE), DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */ @@ -2264,7 +2264,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x12d1, 0x3a07, /* Huawei Technologies Co., Ltd. */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ @@ -2304,7 +2304,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x1901, 0x0191, /* GE B850V3 CP2114 audio interface */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x19f7, 0x0003, /* RODE NT-USB */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1bcf, 0x2281, /* HD Webcam */ @@ -2356,7 +2356,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x2a70, 0x1881, /* OnePlus Technology (Shenzhen) Co., Ltd. BE02T */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */ QUIRK_FLAG_GENERIC_IMPLICIT_FB), DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */ @@ -2368,13 +2368,13 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x2d95, 0x8021, /* VIVO USB-C-XE710 HEADSET */ QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x2d99, 0x0026, /* HECATE G2 GAMING HEADSET */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x2fc6, 0xf0b7, /* iBasso DC07 Pro */ QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */ QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */ - QUIRK_FLAG_MIXER_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 59335b94103004..707b3037b1b3a3 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -219,7 +219,7 @@ extern bool snd_usb_skip_validation; * for the given endpoint. * QUIRK_FLAG_MIC_RES_16 and QUIRK_FLAG_MIC_RES_384 * Set the fixed resolution for Mic Capture Volume (mostly for webcams) - * QUIRK_FLAG_MIXER_MIN_MUTE + * QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE * Set minimum volume control value as mute for devices where the lowest * playback value represents muted state instead of minimum audible volume */ @@ -248,6 +248,6 @@ extern bool snd_usb_skip_validation; #define QUIRK_FLAG_FIXED_RATE (1U << 21) #define QUIRK_FLAG_MIC_RES_16 (1U << 22) #define QUIRK_FLAG_MIC_RES_384 (1U << 23) -#define QUIRK_FLAG_MIXER_MIN_MUTE (1U << 24) +#define QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE (1U << 24) #endif /* __USBAUDIO_H */ From 759b5ce3e6e804ee333f0e0da3cf93c38b77b890 Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Wed, 3 Sep 2025 13:09:46 +0800 Subject: [PATCH 1191/1292] ALSA: usb-audio: add quirk QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE The same hardware problem to QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE also occurs on the capture streams on some USB devices. Add a new flag for processing the quirk. Link: https://lore.kernel.org/all/C22C1A172EBB9BD9+eccc2e4a-d21e-4a7d-848c-bbf3982feb94@uniontech.com/ Signed-off-by: Cryolitia PukNgae Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250903-sound-v1-2-d4ca777b8512@uniontech.com --- Documentation/sound/alsa-configuration.rst | 1 + sound/usb/mixer_quirks.c | 7 +++++++ sound/usb/usbaudio.h | 3 +++ 3 files changed, 11 insertions(+) diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index 062b86522e4d9c..bf45df1558bbc3 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -2329,6 +2329,7 @@ quirk_flags * bit 24: Set minimum volume control value as mute for devices where the lowest playback value represents muted state instead of minimum audible volume + * bit 25: Be similar to bit 24 but for capture streams This module supports multiple devices, autoprobe and hotplugging. diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 2a1abc24dbfc0c..828af3095b86ee 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -4550,6 +4550,13 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, cval->min_mute = 1; } + /* lowest capture value is muted on some devices */ + if (mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE) + if (strstr(kctl->id.name, "Capture")) { + usb_audio_info(mixer->chip, + "applying capture min mute quirk\n"); + cval->min_mute = 1; + } /* ALSA-ify some Plantronics headset control names */ if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f && (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME)) diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 707b3037b1b3a3..30b5102e3caed0 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -222,6 +222,8 @@ extern bool snd_usb_skip_validation; * QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE * Set minimum volume control value as mute for devices where the lowest * playback value represents muted state instead of minimum audible volume + * QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE + * Similar to QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE, but for capture streams */ #define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0) @@ -249,5 +251,6 @@ extern bool snd_usb_skip_validation; #define QUIRK_FLAG_MIC_RES_16 (1U << 22) #define QUIRK_FLAG_MIC_RES_384 (1U << 23) #define QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE (1U << 24) +#define QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE (1U << 25) #endif /* __USBAUDIO_H */ From 806a38293fc0dfc80e556ec8f389dffc6ea90059 Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Wed, 3 Sep 2025 13:09:47 +0800 Subject: [PATCH 1192/1292] ALSA: usb-audio: apply "mixer_min_mute" quirks on some devices - QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE - QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE Suggested-by: Guoli An Signed-off-by: Cryolitia PukNgae Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250903-sound-v1-3-d4ca777b8512@uniontech.com --- sound/usb/quirks.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 0fe31af3158f08..d736a475035659 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2243,16 +2243,20 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */ QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0b05, 0x18a6, /* ASUSTek Computer, Inc. */ + QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */ QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x0bda, 0x498a, /* Realtek Semiconductor Corp. */ - QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE | QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0c45, 0x636b, /* Microdia JP001 USB Camera */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0d8c, 0x000c, /* C-Media */ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x0d8c, 0x0012, /* C-Media */ + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x0d8c, 0x0014, /* C-Media */ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ @@ -2264,7 +2268,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x12d1, 0x3a07, /* Huawei Technologies Co., Ltd. */ - QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE | QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ @@ -2356,7 +2360,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x2a70, 0x1881, /* OnePlus Technology (Shenzhen) Co., Ltd. BE02T */ - QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE | QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */ QUIRK_FLAG_GENERIC_IMPLICIT_FB), DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */ From a73349c5dd27bc544b048e2e2c8ef6394f05b793 Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Wed, 3 Sep 2025 13:09:48 +0800 Subject: [PATCH 1193/1292] ALSA: usb-audio: apply quirk for MOONDROP Quark2 It reports a MIN value -15360 for volume control, but will mute when setting it less than -14208 Tested-by: Guoli An Signed-off-by: Cryolitia PukNgae Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250903-sound-v1-4-d4ca777b8512@uniontech.com --- sound/usb/mixer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 5fcf1117777d1a..34bcbfd8b54e66 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1182,6 +1182,13 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, cval->res = 1; } break; + case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, + "set volume quirk for MOONDROP Quark2\n"); + cval->min = -14208; /* Mute under it */ + } + break; } } From 8bbceba7dc5090c00105e006ce28d1292cfda8dd Mon Sep 17 00:00:00 2001 From: Abin Joseph Date: Wed, 3 Sep 2025 08:22:13 +0530 Subject: [PATCH 1194/1292] net: xilinx: axienet: Add error handling for RX metadata pointer retrieval Add proper error checking for dmaengine_desc_get_metadata_ptr() which can return an error pointer and lead to potential crashes or undefined behaviour if the pointer retrieval fails. Properly handle the error by unmapping DMA buffer, freeing the skb and returning early to prevent further processing with invalid data. Fixes: 6a91b846af85 ("net: axienet: Introduce dmaengine support") Signed-off-by: Abin Joseph Reviewed-by: Radhey Shyam Pandey Link: https://patch.msgid.link/20250903025213.3120181-1-abin.joseph@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 0d8a05fe541afb..ec6d47dc984aa8 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1168,6 +1168,15 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result) &meta_max_len); dma_unmap_single(lp->dev, skbuf_dma->dma_address, lp->max_frm_size, DMA_FROM_DEVICE); + + if (IS_ERR(app_metadata)) { + if (net_ratelimit()) + netdev_err(lp->ndev, "Failed to get RX metadata pointer\n"); + dev_kfree_skb_any(skb); + lp->ndev->stats.rx_dropped++; + goto rx_submit; + } + /* TODO: Derive app word index programmatically */ rx_len = (app_metadata[LEN_APP] & 0xFFFF); skb_put(skb, rx_len); @@ -1180,6 +1189,7 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result) u64_stats_add(&lp->rx_bytes, rx_len); u64_stats_update_end(&lp->rx_stat_sync); +rx_submit: for (i = 0; i < CIRC_SPACE(lp->rx_ring_head, lp->rx_ring_tail, RX_BUF_NUM_DEFAULT); i++) axienet_rx_submit_desc(lp->ndev); From 311942ce763e21dacef7e53996d5a1e19b8adab1 Mon Sep 17 00:00:00 2001 From: "Shang song (Lenovo)" Date: Mon, 25 Aug 2025 23:02:29 -0400 Subject: [PATCH 1195/1292] ACPI: PRM: Skip handlers with NULL handler_address or NULL VA If handler_address or mapped VA is NULL, the related buffer address and VA can be ignored, so make acpi_parse_prmt() skip the current handler in those cases. Signed-off-by: Shang song (Lenovo) Link: https://patch.msgid.link/20250826030229.834901-1-shangsong2@foxmail.com [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/prmt.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c index be033bbb126a44..6792d4385eee48 100644 --- a/drivers/acpi/prmt.c +++ b/drivers/acpi/prmt.c @@ -150,15 +150,28 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end) th = &tm->handlers[cur_handler]; guid_copy(&th->guid, (guid_t *)handler_info->handler_guid); + + /* + * Print an error message if handler_address is NULL, the parse of VA also + * can be skipped. + */ + if (unlikely(!handler_info->handler_address)) { + pr_info("Skipping handler with NULL address for GUID: %pUL", + (guid_t *)handler_info->handler_guid); + continue; + } + th->handler_addr = (void *)efi_pa_va_lookup(&th->guid, handler_info->handler_address); /* - * Print a warning message if handler_addr is zero which is not expected to - * ever happen. + * Print a warning message and skip the parse of VA if handler_addr is zero + * which is not expected to ever happen. */ - if (unlikely(!th->handler_addr)) + if (unlikely(!th->handler_addr)) { pr_warn("Failed to find VA of handler for GUID: %pUL, PA: 0x%llx", &th->guid, handler_info->handler_address); + continue; + } th->static_data_buffer_addr = efi_pa_va_lookup(&th->guid, handler_info->static_data_buffer_address); From 4844123fe0b853a4982c02666cb3fd863d701d50 Mon Sep 17 00:00:00 2001 From: Qingfang Deng Date: Wed, 3 Sep 2025 18:07:26 +0800 Subject: [PATCH 1196/1292] ppp: fix memory leak in pad_compress_skb If alloc_skb() fails in pad_compress_skb(), it returns NULL without releasing the old skb. The caller does: skb = pad_compress_skb(ppp, skb); if (!skb) goto drop; drop: kfree_skb(skb); When pad_compress_skb() returns NULL, the reference to the old skb is lost and kfree_skb(skb) ends up doing nothing, leading to a memory leak. Align pad_compress_skb() semantics with realloc(): only free the old skb if allocation and compression succeed. At the call site, use the new_skb variable so the original skb is not lost when pad_compress_skb() fails. Fixes: b3f9b92a6ec1 ("[PPP]: add PPP MPPE encryption module") Signed-off-by: Qingfang Deng Reviewed-by: Eric Dumazet Reviewed-by: Yue Haibing Link: https://patch.msgid.link/20250903100726.269839-1-dqfext@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ppp/ppp_generic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 824c8dc4120b33..702a7f7183ce29 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1744,7 +1744,6 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) */ if (net_ratelimit()) netdev_err(ppp->dev, "ppp: compressor dropped pkt\n"); - kfree_skb(skb); consume_skb(new_skb); new_skb = NULL; } @@ -1845,9 +1844,10 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) "down - pkt dropped.\n"); goto drop; } - skb = pad_compress_skb(ppp, skb); - if (!skb) + new_skb = pad_compress_skb(ppp, skb); + if (!new_skb) goto drop; + skb = new_skb; } /* From b1ab3b029ff137f124c547452d0795e9de20ca63 Mon Sep 17 00:00:00 2001 From: Jeroen de Borst Date: Wed, 3 Sep 2025 10:56:49 -0700 Subject: [PATCH 1197/1292] gve: update MAINTAINERS Jeroen is leaving Google and Josh is taking his place as a maintainer. Signed-off-by: Jeroen de Borst Link: https://patch.msgid.link/20250903175649.23246-1-jeroendb@google.com Signed-off-by: Jakub Kicinski --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1819c477eee3b4..c6f470250f6ab4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10388,7 +10388,7 @@ S: Maintained F: drivers/input/touchscreen/goodix* GOOGLE ETHERNET DRIVERS -M: Jeroen de Borst +M: Joshua Washington M: Harshitha Ramamurthy L: netdev@vger.kernel.org S: Maintained From 6a989d37302a41a8a8d6231a4c265fdb6b09d6eb Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 3 Sep 2025 14:20:54 -0700 Subject: [PATCH 1198/1292] MAINTAINERS: add Sabrina to TLS maintainers Sabrina has been very helpful reviewing TLS patches, fixing bugs, and, I believe, the last one to implement any major feature in the TLS code base (rekeying). Add her as a maintainer. Acked-by: Sabrina Dubroca Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250903212054.1885058-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c6f470250f6ab4..2dd6e8e5c0fa51 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17850,6 +17850,7 @@ F: net/ipv6/tcp*.c NETWORKING [TLS] M: John Fastabend M: Jakub Kicinski +M: Sabrina Dubroca L: netdev@vger.kernel.org S: Maintained F: include/net/tls.h From ed42d80f3bae89592fbb2ffaf8b6b2e720d53f6a Mon Sep 17 00:00:00 2001 From: zhang jiao Date: Wed, 3 Sep 2025 14:36:20 +0800 Subject: [PATCH 1199/1292] tools: gpio: remove the include directory on make clean Remove the generated include directory when running make clean. Fixes: 8674cea84dc6 ("tools/gpio: move to tools buildsystem") Signed-off-by: Zhang Jiao Link: https://lore.kernel.org/r/20250903063621.2424-1-zhangjiao2@cmss.chinamobile.com [Bartosz: add Fixes tag, improve the commit message] Signed-off-by: Bartosz Golaszewski --- tools/gpio/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index ed565eb52275f1..342e056c8c665a 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -77,7 +77,7 @@ $(OUTPUT)gpio-watch: $(GPIO_WATCH_IN) clean: rm -f $(ALL_PROGRAMS) - rm -f $(OUTPUT)include/linux/gpio.h + rm -rf $(OUTPUT)include find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete -o -name '\.*.cmd' -delete install: $(ALL_PROGRAMS) From fd2004d82d8d8faa94879e3de3096c8511728637 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 3 Sep 2025 22:28:51 +0000 Subject: [PATCH 1200/1292] selftest: net: Fix weird setsockopt() in bind_bhash.c. bind_bhash.c passes (SO_REUSEADDR | SO_REUSEPORT) to setsockopt(). In the asm-generic definition, the value happens to match with the bare SO_REUSEPORT, (2 | 15) == 15, but not on some arch. arch/alpha/include/uapi/asm/socket.h:18:#define SO_REUSEADDR 0x0004 arch/alpha/include/uapi/asm/socket.h:24:#define SO_REUSEPORT 0x0200 arch/mips/include/uapi/asm/socket.h:24:#define SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */ arch/mips/include/uapi/asm/socket.h:33:#define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ arch/parisc/include/uapi/asm/socket.h:12:#define SO_REUSEADDR 0x0004 arch/parisc/include/uapi/asm/socket.h:18:#define SO_REUSEPORT 0x0200 arch/sparc/include/uapi/asm/socket.h:13:#define SO_REUSEADDR 0x0004 arch/sparc/include/uapi/asm/socket.h:20:#define SO_REUSEPORT 0x0200 include/uapi/asm-generic/socket.h:12:#define SO_REUSEADDR 2 include/uapi/asm-generic/socket.h:27:#define SO_REUSEPORT 15 Let's pass SO_REUSEPORT only. Fixes: c35ecb95c448 ("selftests/net: Add test for timing a bind request to a port with a populated bhash entry") Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Link: https://patch.msgid.link/20250903222938.2601522-1-kuniyu@google.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/bind_bhash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/bind_bhash.c b/tools/testing/selftests/net/bind_bhash.c index 57ff67a3751eb3..da04b0b19b73ca 100644 --- a/tools/testing/selftests/net/bind_bhash.c +++ b/tools/testing/selftests/net/bind_bhash.c @@ -75,7 +75,7 @@ static void *setup(void *arg) int *array = (int *)arg; for (i = 0; i < MAX_CONNECTIONS; i++) { - sock_fd = bind_socket(SO_REUSEADDR | SO_REUSEPORT, setup_addr); + sock_fd = bind_socket(SO_REUSEPORT, setup_addr); if (sock_fd < 0) { ret = sock_fd; pthread_exit(&ret); @@ -103,7 +103,7 @@ int main(int argc, const char *argv[]) setup_addr = use_v6 ? setup_addr_v6 : setup_addr_v4; - listener_fd = bind_socket(SO_REUSEADDR | SO_REUSEPORT, setup_addr); + listener_fd = bind_socket(SO_REUSEPORT, setup_addr); if (listen(listener_fd, 100) < 0) { perror("listen failed"); return -1; From 9b2bfdbf43adb9929c5ddcdd96efedbf1c88cf53 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 2 Sep 2025 14:12:59 +0200 Subject: [PATCH 1201/1292] phy: mscc: Stop taking ts_lock for tx_queue and use its own lock When transmitting a PTP frame which is timestamp using 2 step, the following warning appears if CONFIG_PROVE_LOCKING is enabled: ============================= [ BUG: Invalid wait context ] 6.17.0-rc1-00326-ge6160462704e #427 Not tainted ----------------------------- ptp4l/119 is trying to lock: c2a44ed4 (&vsc8531->ts_lock){+.+.}-{3:3}, at: vsc85xx_txtstamp+0x50/0xac other info that might help us debug this: context-{4:4} 4 locks held by ptp4l/119: #0: c145f068 (rcu_read_lock_bh){....}-{1:2}, at: __dev_queue_xmit+0x58/0x1440 #1: c29df974 (dev->qdisc_tx_busylock ?: &qdisc_tx_busylock){+...}-{2:2}, at: __dev_queue_xmit+0x5c4/0x1440 #2: c2aaaad0 (_xmit_ETHER#2){+.-.}-{2:2}, at: sch_direct_xmit+0x108/0x350 #3: c2aac170 (&lan966x->tx_lock){+.-.}-{2:2}, at: lan966x_port_xmit+0xd0/0x350 stack backtrace: CPU: 0 UID: 0 PID: 119 Comm: ptp4l Not tainted 6.17.0-rc1-00326-ge6160462704e #427 NONE Hardware name: Generic DT based system Call trace: unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x7c/0xac dump_stack_lvl from __lock_acquire+0x8e8/0x29dc __lock_acquire from lock_acquire+0x108/0x38c lock_acquire from __mutex_lock+0xb0/0xe78 __mutex_lock from mutex_lock_nested+0x1c/0x24 mutex_lock_nested from vsc85xx_txtstamp+0x50/0xac vsc85xx_txtstamp from lan966x_fdma_xmit+0xd8/0x3a8 lan966x_fdma_xmit from lan966x_port_xmit+0x1bc/0x350 lan966x_port_xmit from dev_hard_start_xmit+0xc8/0x2c0 dev_hard_start_xmit from sch_direct_xmit+0x8c/0x350 sch_direct_xmit from __dev_queue_xmit+0x680/0x1440 __dev_queue_xmit from packet_sendmsg+0xfa4/0x1568 packet_sendmsg from __sys_sendto+0x110/0x19c __sys_sendto from sys_send+0x18/0x20 sys_send from ret_fast_syscall+0x0/0x1c Exception stack(0xf0b05fa8 to 0xf0b05ff0) 5fa0: 00000001 0000000e 0000000e 0004b47a 0000003a 00000000 5fc0: 00000001 0000000e 00000000 00000121 0004af58 00044874 00000000 00000000 5fe0: 00000001 bee9d420 00025a10 b6e75c7c So, instead of using the ts_lock for tx_queue, use the spinlock that skb_buff_head has. Reviewed-by: Vadim Fedorenko Fixes: 7d272e63e0979d ("net: phy: mscc: timestamping and PHC support") Signed-off-by: Horatiu Vultur Link: https://patch.msgid.link/20250902121259.3257536-1-horatiu.vultur@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc/mscc_ptp.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c index 72847320cb652d..d692df7d975c70 100644 --- a/drivers/net/phy/mscc/mscc_ptp.c +++ b/drivers/net/phy/mscc/mscc_ptp.c @@ -456,12 +456,12 @@ static void vsc85xx_dequeue_skb(struct vsc85xx_ptp *ptp) *p++ = (reg >> 24) & 0xff; } - len = skb_queue_len(&ptp->tx_queue); + len = skb_queue_len_lockless(&ptp->tx_queue); if (len < 1) return; while (len--) { - skb = __skb_dequeue(&ptp->tx_queue); + skb = skb_dequeue(&ptp->tx_queue); if (!skb) return; @@ -486,7 +486,7 @@ static void vsc85xx_dequeue_skb(struct vsc85xx_ptp *ptp) * packet in the FIFO right now, reschedule it for later * packets. */ - __skb_queue_tail(&ptp->tx_queue, skb); + skb_queue_tail(&ptp->tx_queue, skb); } } @@ -1068,6 +1068,7 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, case HWTSTAMP_TX_ON: break; case HWTSTAMP_TX_OFF: + skb_queue_purge(&vsc8531->ptp->tx_queue); break; default: return -ERANGE; @@ -1092,9 +1093,6 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, mutex_lock(&vsc8531->ts_lock); - __skb_queue_purge(&vsc8531->ptp->tx_queue); - __skb_queue_head_init(&vsc8531->ptp->tx_queue); - /* Disable predictor while configuring the 1588 block */ val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_PREDICTOR); @@ -1180,9 +1178,7 @@ static void vsc85xx_txtstamp(struct mii_timestamper *mii_ts, skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - mutex_lock(&vsc8531->ts_lock); - __skb_queue_tail(&vsc8531->ptp->tx_queue, skb); - mutex_unlock(&vsc8531->ts_lock); + skb_queue_tail(&vsc8531->ptp->tx_queue, skb); return; out: @@ -1548,6 +1544,7 @@ void vsc8584_ptp_deinit(struct phy_device *phydev) if (vsc8531->ptp->ptp_clock) { ptp_clock_unregister(vsc8531->ptp->ptp_clock); skb_queue_purge(&vsc8531->rx_skbs_list); + skb_queue_purge(&vsc8531->ptp->tx_queue); } } @@ -1571,7 +1568,7 @@ irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev) if (rc & VSC85XX_1588_INT_FIFO_ADD) { vsc85xx_get_tx_ts(priv->ptp); } else if (rc & VSC85XX_1588_INT_FIFO_OVERFLOW) { - __skb_queue_purge(&priv->ptp->tx_queue); + skb_queue_purge(&priv->ptp->tx_queue); vsc85xx_ts_reset_fifo(phydev); } @@ -1591,6 +1588,7 @@ int vsc8584_ptp_probe(struct phy_device *phydev) mutex_init(&vsc8531->phc_lock); mutex_init(&vsc8531->ts_lock); skb_queue_head_init(&vsc8531->rx_skbs_list); + skb_queue_head_init(&vsc8531->ptp->tx_queue); /* Retrieve the shared load/save GPIO. Request it as non exclusive as * the same GPIO can be requested by all the PHYs of the same package. From f3ef7110924b897f4b79db9f7ac75d319ec09c4a Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 28 Aug 2025 19:22:43 +0800 Subject: [PATCH 1202/1292] ACPI/IORT: Fix memory leak in iort_rmr_alloc_sids() If krealloc_array() fails in iort_rmr_alloc_sids(), the function returns NULL but does not free the original 'sids' allocation. This results in a memory leak since the caller overwrites the original pointer with the NULL return value. Fixes: 491cf4a6735a ("ACPI/IORT: Add support to retrieve IORT RMR reserved regions") Cc: # 6.0.x Signed-off-by: Miaoqian Lin Reviewed-by: Hanjun Guo Link: https://lore.kernel.org/r/20250828112243.61460-1-linmq006@gmail.com Signed-off-by: Catalin Marinas --- drivers/acpi/arm64/iort.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 98759d6199d3ac..65f0f56ad7538a 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -937,8 +937,10 @@ static u32 *iort_rmr_alloc_sids(u32 *sids, u32 count, u32 id_start, new_sids = krealloc_array(sids, count + new_count, sizeof(*new_sids), GFP_KERNEL); - if (!new_sids) + if (!new_sids) { + kfree(sids); return NULL; + } for (i = count; i < total_count; i++) new_sids[i] = id_start++; From 93dec51e716db88f32d770dc9ab268964fff320b Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Wed, 3 Sep 2025 09:41:40 +0800 Subject: [PATCH 1203/1292] md/raid1: fix data lost for writemostly rdev If writemostly is enabled, alloc_behind_master_bio() will allocate a new bio for rdev, with bi_opf set to 0. Later, raid1_write_request() will clone from this bio, hence bi_opf is still 0 for the cloned bio. Submit this cloned bio will end up to be read, causing write data lost. Fix this problem by inheriting bi_opf from original bio for behind_mast_bio. Fixes: e879a0d9cb08 ("md/raid1,raid10: don't ignore IO flags") Reported-and-tested-by: Ian Dall Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220507 Link: https://lore.kernel.org/linux-raid/20250903014140.3690499-1-yukuai1@huaweicloud.com Signed-off-by: Yu Kuai Reviewed-by: Li Nan --- drivers/md/raid1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 408c263983215e..bf44878ec640e5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1225,7 +1225,7 @@ static void alloc_behind_master_bio(struct r1bio *r1_bio, int i = 0; struct bio *behind_bio = NULL; - behind_bio = bio_alloc_bioset(NULL, vcnt, 0, GFP_NOIO, + behind_bio = bio_alloc_bioset(NULL, vcnt, bio->bi_opf, GFP_NOIO, &r1_bio->mddev->bio_set); /* discard op, we don't support writezero/writesame yet */ From 7202082b7b7a256d04ec96131c7f859df0a79f64 Mon Sep 17 00:00:00 2001 From: Li Nan Date: Thu, 4 Sep 2025 15:34:52 +0800 Subject: [PATCH 1204/1292] md: prevent incorrect update of resync/recovery offset In md_do_sync(), when md_sync_action returns ACTION_FROZEN, subsequent call to md_sync_position() will return MaxSector. This causes 'curr_resync' (and later 'recovery_offset') to be set to MaxSector too, which incorrectly signals that recovery/resync has completed, even though disk data has not actually been updated. To fix this issue, skip updating any offset values when the sync action is FROZEN. The same holds true for IDLE. Fixes: 7d9f107a4e94 ("md: use new helpers in md_do_sync()") Signed-off-by: Li Nan Link: https://lore.kernel.org/linux-raid/20250904073452.3408516-1-linan666@huaweicloud.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 1baaf52c603c1c..4e033c26fdd461 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -9125,6 +9125,11 @@ void md_do_sync(struct md_thread *thread) } action = md_sync_action(mddev); + if (action == ACTION_FROZEN || action == ACTION_IDLE) { + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + goto skip; + } + desc = md_sync_action_name(action); mddev->last_sync_action = action; From 70bccd9855dae56942f2b18a08ba137bb54093a0 Mon Sep 17 00:00:00 2001 From: Makar Semyonov Date: Thu, 4 Sep 2025 15:28:41 +0300 Subject: [PATCH 1205/1292] cifs: prevent NULL pointer dereference in UTF16 conversion There can be a NULL pointer dereference bug here. NULL is passed to __cifs_sfu_make_node without checks, which passes it unchecked to cifs_strndup_to_utf16, which in turn passes it to cifs_local_to_utf16_bytes where '*from' is dereferenced, causing a crash. This patch adds a check for NULL 'src' in cifs_strndup_to_utf16 and returns NULL early to prevent dereferencing NULL pointer. Found by Linux Verification Center (linuxtesting.org) with SVACE Signed-off-by: Makar Semyonov Cc: stable@vger.kernel.org Signed-off-by: Steve French --- fs/smb/client/cifs_unicode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/smb/client/cifs_unicode.c b/fs/smb/client/cifs_unicode.c index 4cc6e0896fad37..f8659d36793f17 100644 --- a/fs/smb/client/cifs_unicode.c +++ b/fs/smb/client/cifs_unicode.c @@ -629,6 +629,9 @@ cifs_strndup_to_utf16(const char *src, const int maxlen, int *utf16_len, int len; __le16 *dst; + if (!src) + return NULL; + len = cifs_local_to_utf16_bytes(src, maxlen, cp); len += 2; /* NULL */ dst = kmalloc(len, GFP_KERNEL); From d0f61658db58583b3acd1ada70a5352c39cd0388 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Sep 2025 09:44:04 +0200 Subject: [PATCH 1206/1292] ASoC: codecs: lpass-rx-macro: Fix playback quality distortion Commit bb4a0f497bc1 ("ASoC: codecs: lpass: Drop unused AIF_INVALID first DAI identifier") removed first entry in enum with DAI identifiers, because it looked unused. Turns out that there is a relation between DAI ID and "RX_MACRO RX0 MUX"-like kcontrols which use "rx_macro_mux_text" array. That "rx_macro_mux_text" array used first three entries of DAI IDs enum, with value '0' being invalid. The value passed tp "RX_MACRO RX0 MUX"-like kcontrols was used as DAI ID and set to configure active channel count and mask, which are arrays indexed by DAI ID. After removal of first AIF_INVALID DAI identifier, this kcontrol was updating wrong entries in active channel count and mask arrays which was visible in reduced quality (distortions) during headset playback on the Qualcomm SM8750 MTP8750 board. It seems it also fixes recording silence (instead of actual sound) via headset, even though that's different macro codec. Reported-by: Alexey Klimov Fixes: bb4a0f497bc1 ("ASoC: codecs: lpass: Drop unused AIF_INVALID first DAI identifier") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Tested-by: Srinivas Kandagatla Message-ID: <20250901074403.137263-2-krzysztof.kozlowski@linaro.org> Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 238dbdb46c18d4..a8fc842cc94ef4 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -618,6 +618,7 @@ static struct interp_sample_rate sr_val_tbl[] = { {176400, 0xB}, {352800, 0xC}, }; +/* Matches also rx_macro_mux_text */ enum { RX_MACRO_AIF1_PB, RX_MACRO_AIF2_PB, @@ -722,6 +723,7 @@ static const char * const rx_int2_2_interp_mux_text[] = { "ZERO", "RX INT2_2 MUX", }; +/* Order must match RX_MACRO_MAX_DAIS enum (offset by 1) */ static const char *const rx_macro_mux_text[] = { "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB" }; @@ -2474,6 +2476,7 @@ static int rx_macro_mux_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_update *update = NULL; u32 rx_port_value = ucontrol->value.enumerated.item[0]; + unsigned int dai_id; u32 aif_rst; struct rx_macro *rx = snd_soc_component_get_drvdata(component); @@ -2490,19 +2493,24 @@ static int rx_macro_mux_put(struct snd_kcontrol *kcontrol, switch (rx_port_value) { case 0: - if (rx->active_ch_cnt[aif_rst]) { - clear_bit(widget->shift, - &rx->active_ch_mask[aif_rst]); - rx->active_ch_cnt[aif_rst]--; + /* + * active_ch_cnt and active_ch_mask use DAI IDs (RX_MACRO_MAX_DAIS). + * active_ch_cnt == 0 was tested in if() above. + */ + dai_id = aif_rst - 1; + if (rx->active_ch_cnt[dai_id]) { + clear_bit(widget->shift, &rx->active_ch_mask[dai_id]); + rx->active_ch_cnt[dai_id]--; } break; case 1: case 2: case 3: case 4: - set_bit(widget->shift, - &rx->active_ch_mask[rx_port_value]); - rx->active_ch_cnt[rx_port_value]++; + /* active_ch_cnt and active_ch_mask use DAI IDs (WSA_MACRO_MAX_DAIS). */ + dai_id = rx_port_value - 1; + set_bit(widget->shift, &rx->active_ch_mask[dai_id]); + rx->active_ch_cnt[dai_id]++; break; default: dev_err(component->dev, From 9004a450fccbeb40a71cc173747da37a459fd4dc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 31 Aug 2025 17:14:02 +0200 Subject: [PATCH 1207/1292] ASoC: codecs: lpass-wsa-macro: Fix speaker quality distortion Commit bb4a0f497bc1 ("ASoC: codecs: lpass: Drop unused AIF_INVALID first DAI identifier") removed first entry in enum with DAI identifiers, because it looked unused. Turns out that there is a relation between DAI ID and "WSA RX0 Mux"-like kcontrols (which use "rx_mux_text" array). That "rx_mux_text" array used first three entries of DAI IDs enum, with value '0' being invalid. The value passed tp "WSA RX0 Mux"-like kcontrols was used as DAI ID and set to configure active channel count and mask, which are arrays indexed by DAI ID. After removal of first AIF_INVALID DAI identifier, this kcontrol was updating wrong entries in active channel count and mask arrays which was visible in reduced quality (distortions) during speaker playback on several boards like Lenovo T14s laptop and Qualcomm SM8550-based boards. Reported-by: Alexey Klimov Fixes: bb4a0f497bc1 ("ASoC: codecs: lpass: Drop unused AIF_INVALID first DAI identifier") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Tested-by: Srinivas Kandagatla Message-ID: <20250831151401.30897-2-krzysztof.kozlowski@linaro.org> Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index da6adb3de21d77..d7eec9fdaf9c65 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -368,6 +368,7 @@ static struct interp_sample_rate int_mix_sample_rate_val[] = { {192000, 0x6}, /* 192K */ }; +/* Matches also rx_mux_text */ enum { WSA_MACRO_AIF1_PB, WSA_MACRO_AIF_MIX1_PB, @@ -465,6 +466,7 @@ static const char *const rx_mix_ec_text[] = { "ZERO", "RX_MIX_TX0", "RX_MIX_TX1" }; +/* Order must match WSA_MACRO_MAX_DAIS enum (offset by 1) */ static const char *const rx_mux_text[] = { "ZERO", "AIF1_PB", "AIF_MIX1_PB" }; @@ -2207,6 +2209,7 @@ static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol, u32 rx_port_value = ucontrol->value.integer.value[0]; u32 bit_input; u32 aif_rst; + unsigned int dai_id; struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); aif_rst = wsa->rx_port_value[widget->shift]; @@ -2224,17 +2227,22 @@ static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol, switch (rx_port_value) { case 0: - if (wsa->active_ch_cnt[aif_rst]) { - clear_bit(bit_input, - &wsa->active_ch_mask[aif_rst]); - wsa->active_ch_cnt[aif_rst]--; + /* + * active_ch_cnt and active_ch_mask use DAI IDs (WSA_MACRO_MAX_DAIS). + * active_ch_cnt == 0 was tested in if() above. + */ + dai_id = aif_rst - 1; + if (wsa->active_ch_cnt[dai_id]) { + clear_bit(bit_input, &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]--; } break; case 1: case 2: - set_bit(bit_input, - &wsa->active_ch_mask[rx_port_value]); - wsa->active_ch_cnt[rx_port_value]++; + /* active_ch_cnt and active_ch_mask use DAI IDs (WSA_MACRO_MAX_DAIS). */ + dai_id = rx_port_value - 1; + set_bit(bit_input, &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]++; break; default: dev_err(component->dev, From 4aac453deca0d9c61df18d968f8864c3ae7d3d8d Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Thu, 28 Aug 2025 01:38:14 -0400 Subject: [PATCH 1208/1292] ACPI: TAD: Add missing sysfs_remove_group() for ACPI_TAD_RT Previously, after `rmmod acpi_tad`, `modprobe acpi_tad` would fail with this dmesg: sysfs: cannot create duplicate filename '/devices/platform/ACPI000E:00/time' Call Trace: dump_stack_lvl+0x6c/0x90 dump_stack+0x10/0x20 sysfs_warn_dup+0x8b/0xa0 sysfs_add_file_mode_ns+0x122/0x130 internal_create_group+0x1dd/0x4c0 sysfs_create_group+0x13/0x20 acpi_tad_probe+0x147/0x1f0 [acpi_tad] platform_probe+0x42/0xb0 acpi-tad ACPI000E:00: probe with driver acpi-tad failed with error -17 Fixes: 3230b2b3c1ab ("ACPI: TAD: Add low-level support for real time capability") Signed-off-by: Daniel Tang Reviewed-by: Mika Westerberg Link: https://patch.msgid.link/2881298.hMirdbgypa@daniel-desktop3 Cc: 5.2+ # 5.2+ Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_tad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index 91d7d90c47dacc..33418dd6768a1b 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -565,6 +565,9 @@ static void acpi_tad_remove(struct platform_device *pdev) pm_runtime_get_sync(dev); + if (dd->capabilities & ACPI_TAD_RT) + sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group); + if (dd->capabilities & ACPI_TAD_DC_WAKE) sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); From 3f6b537a13c815f4c93dcc5a0d1c48a8f5619dc0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Aug 2025 13:02:01 +0200 Subject: [PATCH 1209/1292] ACPI: thermal: Get rid of a dummy local variable The second argument of acpi_bus_update_power() can be NULL, so drop the power_state dummy local variable in acpi_thermal_resume() used just for avoiding passing NULL as the second argument to that function. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/13851842.uLZWGnKmhe@rafael.j.wysocki --- drivers/acpi/thermal.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 5c2defe55898f1..8537395b417b0f 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -924,7 +924,7 @@ static int acpi_thermal_suspend(struct device *dev) static int acpi_thermal_resume(struct device *dev) { struct acpi_thermal *tz; - int i, j, power_state; + int i, j; if (!dev) return -EINVAL; @@ -939,10 +939,8 @@ static int acpi_thermal_resume(struct device *dev) if (!acpi_thermal_trip_valid(acpi_trip)) break; - for (j = 0; j < acpi_trip->devices.count; j++) { - acpi_bus_update_power(acpi_trip->devices.handles[j], - &power_state); - } + for (j = 0; j < acpi_trip->devices.count; j++) + acpi_bus_update_power(acpi_trip->devices.handles[j], NULL); } acpi_queue_thermal_check(tz); From 7a9490a1c929e00250f4be7749bd666f19a9c7ef Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Aug 2025 13:03:13 +0200 Subject: [PATCH 1210/1292] ACPI: fan: Fold two simple functions into their only caller Both acpi_fan_has_fst() and acpi_fan_is_acpi4() are called from one place only, so fold them both into there caller which yields slightly leaner code that is somewhat easier to follow. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3386797.aeNJFYEL58@rafael.j.wysocki --- drivers/acpi/fan_core.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c index 095502086b4120..04ff608f2ff02c 100644 --- a/drivers/acpi/fan_core.c +++ b/drivers/acpi/fan_core.c @@ -203,18 +203,6 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = { * -------------------------------------------------------------------------- */ -static bool acpi_fan_has_fst(struct acpi_device *device) -{ - return acpi_has_method(device->handle, "_FST"); -} - -static bool acpi_fan_is_acpi4(struct acpi_device *device) -{ - return acpi_has_method(device->handle, "_FIF") && - acpi_has_method(device->handle, "_FPS") && - acpi_has_method(device->handle, "_FSL"); -} - static int acpi_fan_get_fif(struct acpi_device *device) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -331,9 +319,11 @@ static int acpi_fan_probe(struct platform_device *pdev) device->driver_data = fan; platform_set_drvdata(pdev, fan); - if (acpi_fan_has_fst(device)) { + if (acpi_has_method(device->handle, "_FST")) { fan->has_fst = true; - fan->acpi4 = acpi_fan_is_acpi4(device); + fan->acpi4 = acpi_has_method(device->handle, "_FIF") && + acpi_has_method(device->handle, "_FPS") && + acpi_has_method(device->handle, "_FSL"); } if (fan->acpi4) { From 4405a214df146775338a1e6232701a29024b82e1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 29 Aug 2025 16:27:48 +0200 Subject: [PATCH 1211/1292] ACPI: scan: Add Intel CVS ACPI HIDs to acpi_ignore_dep_ids[] Some x86/ACPI laptops with MIPI cameras have a INTC10DE or INTC10E0 ACPI device in the _DEP dependency list of the ACPI devices for the camera- sensors (which have flags.honor_deps set). These devices are for an Intel Vision CVS chip for which an out of tree driver is available [1]. The camera sensor works fine without a driver being loaded for this ACPI device on the 2 laptops this was tested on: ThinkPad X1 Carbon Gen 12 (Meteor Lake) ThinkPad X1 2-in-1 Gen 10 (Arrow Lake) For now add these HIDs to acpi_ignore_dep_ids[] so that acpi_dev_ready_for_enumeration() will return true once the other _DEP dependencies are met and an i2c_client for the camera sensor will get instantiated. Link: https://github.com/intel/vision-drivers/ [1] Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250829142748.21089-1-hansg@kernel.org Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fb1fe9f3b1a366..9865faa996b0d9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -845,6 +845,8 @@ static bool acpi_info_matches_ids(struct acpi_device_info *info, static const char * const acpi_ignore_dep_ids[] = { "PNP0D80", /* Windows-compatible System Power Management Controller */ "INT33BD", /* Intel Baytrail Mailbox Device */ + "INTC10DE", /* Intel CVS LNL */ + "INTC10E0", /* Intel CVS ARL */ "LATT2021", /* Lattice FW Update Client Driver */ NULL }; From 3a351de0d9c86e23b9eca25838b19468aab02f38 Mon Sep 17 00:00:00 2001 From: Sam van Kampen Date: Fri, 29 Aug 2025 14:52:22 +0000 Subject: [PATCH 1212/1292] ACPI: resource: Skip IRQ override on ASUS Vivobook Pro N6506CU Just like the other Vivobooks here, the N6506CU has its keyboard IRQ described as ActiveLow in the DSDT, which the kernel overrides to EdgeHigh, causing the internal keyboard not to work. Add the N6506CU to the irq1_level_low_skip_override[] quirk table to fix this. Signed-off-by: Sam van Kampen Link: https://patch.msgid.link/20250829145221.2294784-2-sam@tehsvk.net Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index b1ab192d7a0809..ddedb6956a0dfd 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -510,6 +510,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { DMI_MATCH(DMI_BOARD_NAME, "N6506M"), }, }, + { + /* Asus Vivobook Pro N6506CU* */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "N6506CU"), + }, + }, { /* LG Electronics 17U70P */ .matches = { From 56a232d93cea0ba14da5e3157830330756a45b4c Mon Sep 17 00:00:00 2001 From: Samuel Wu Date: Wed, 20 Aug 2025 17:42:33 -0700 Subject: [PATCH 1213/1292] PM: sleep: Make pm_wakeup_clear() call more clear Move pm_wakeup_clear() to the same location as other functions that do bookkeeping prior to suspend_prepare(). Since calling pm_wakeup_clear() is a prerequisite to setting up for suspend and enabling functionalities of suspend (like aborting during suspend), moving pm_wakeup_clear() higher up the call stack makes its intent more clear and obvious that it is called prior to suspend_prepare(). After this change, there is a slightly larger window when abort events can be registered, but otherwise suspend functionality is the same. Suggested-by: Saravana Kannan Signed-off-by: Samuel Wu Link: https://patch.msgid.link/20250821004237.2712312-2-wusamuel@google.com Reviewed-by: Saravana Kannan [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- kernel/power/process.c | 1 - kernel/power/suspend.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/process.c b/kernel/power/process.c index dc0dfc349f22b4..8ff68ebaa1e08e 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -132,7 +132,6 @@ int freeze_processes(void) if (!pm_freezing) static_branch_inc(&freezer_active); - pm_wakeup_clear(0); pm_freezing = true; error = try_to_freeze_tasks(true); if (!error) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index b4ca17c2fecf4d..4bb4686c1c0881 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -595,6 +595,7 @@ static int enter_state(suspend_state_t state) } pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]); + pm_wakeup_clear(0); pm_suspend_clear_flags(); error = suspend_prepare(state); if (error) From 28cef1632339ac54253e8eef89726a6e0a349939 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 25 Aug 2025 15:27:46 +0200 Subject: [PATCH 1214/1292] thermal: gov_step_wise: Clean up local variable initialization Make the initialization of local variable throttle in thermal_zone_trip_update() more straightforward. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Lukasz Luba Link: https://patch.msgid.link/6203592.lOV4Wx5bFT@rafael.j.wysocki --- drivers/thermal/gov_step_wise.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c index d1bb59f1dfbd39..6506ae270101a5 100644 --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c @@ -69,16 +69,14 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, const struct thermal_trip_desc *td, int trip_threshold) { + bool throttle = tz->temperature >= trip_threshold; const struct thermal_trip *trip = &td->trip; enum thermal_trend trend = get_tz_trend(tz, trip); int trip_id = thermal_zone_trip_id(tz, trip); struct thermal_instance *instance; - bool throttle = false; - if (tz->temperature >= trip_threshold) { - throttle = true; + if (throttle) trace_thermal_zone_trip(tz, trip_id, trip->type); - } dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", trip_id, trip->type, trip_threshold, trend, throttle); From 6b4decef4c9454a9121109788fae761319ea44b4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 25 Aug 2025 15:28:34 +0200 Subject: [PATCH 1215/1292] thermal: gov_step_wise: Clarify cooling logic description comment The cooling logic description comment next to the get_target_state() definition is slightly ambiguous in what it means by "lower cooling state", so clarify that by replacing the ambuguous phrase with "the minimum applicable cooling state". No functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Lukasz Luba Link: https://patch.msgid.link/4690596.LvFx2qVVIh@rafael.j.wysocki --- drivers/thermal/gov_step_wise.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c index 6506ae270101a5..a29676d3e50dc0 100644 --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c @@ -23,8 +23,8 @@ * b. if the trend is THERMAL_TREND_DROPPING, do nothing * If the temperature is lower than a trip point, * a. if the trend is THERMAL_TREND_RAISING, do nothing - * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling - * state for this trip point, if the cooling state already + * b. if the trend is THERMAL_TREND_DROPPING, use the minimum applicable + * cooling state for this trip point, or if the cooling state already * equals lower limit, deactivate the thermal instance */ static unsigned long get_target_state(struct thermal_instance *instance, From 2e82368359f63567862a0d438710ddffcb1ace83 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 25 Aug 2025 15:31:53 +0200 Subject: [PATCH 1216/1292] thermal: gov_step_wise: Allow cooling level to be reduced earlier The current behavior of the Step-wise thermal governor is to increase the cooling level one step at a time after trip point threshold passing by thermal zone temperature until the temperature stops to rise. Then, nothing is done until the temperature decreases below the (possibly updated) trip point threshold, at which point the cooling level is reduced straight to the applicable minimum. While this generally works, it is not in agreement with the throttling logic description comment in step_wise_manage() any more after some relatively recent changes, and in the case of passive cooling, it may lead to undesirable performance oscillations between high and low levels. For this reason, modify the governor's cooling device state selection function, get_target_state(), to reduce cooling by one level even if the temperature is still above the thermal zone threshold, but the temperature has started to fall down. However, ensure that the cooling level will remain above the applicable minimum in that case to pull the zone temperature further down, possibly until it falls below the trip threshold (which may now be equal to the low temperature of the trip). Doing so should help higher performance to be restored earlier in some cases which is desirable especially for passive trip points with relatively high hysteresis values. Signed-off-by: Rafael J. Wysocki Reviewed-by: Lukasz Luba Link: https://patch.msgid.link/1947735.tdWV9SEqCh@rafael.j.wysocki [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/thermal/gov_step_wise.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c index a29676d3e50dc0..ea277c466d8d2e 100644 --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c @@ -20,7 +20,9 @@ * If the temperature is higher than a trip point, * a. if the trend is THERMAL_TREND_RAISING, use higher cooling * state for this trip point - * b. if the trend is THERMAL_TREND_DROPPING, do nothing + * b. if the trend is THERMAL_TREND_DROPPING, use a lower cooling state + * for this trip point, but keep the cooling state above the applicable + * minimum * If the temperature is lower than a trip point, * a. if the trend is THERMAL_TREND_RAISING, do nothing * b. if the trend is THERMAL_TREND_DROPPING, use the minimum applicable @@ -51,6 +53,17 @@ static unsigned long get_target_state(struct thermal_instance *instance, if (throttle) { if (trend == THERMAL_TREND_RAISING) return clamp(cur_state + 1, instance->lower, instance->upper); + + /* + * If the zone temperature is falling, the cooling level can + * be reduced, but it should still be above the lower state of + * the given thermal instance to pull the temperature further + * down. + */ + if (trend == THERMAL_TREND_DROPPING) + return clamp(cur_state - 1, + min(instance->lower + 1, instance->upper), + instance->upper); } else if (trend == THERMAL_TREND_DROPPING) { if (cur_state <= instance->lower) return THERMAL_NO_TARGET; From 0115d063559fa6d25e41751cf455dda40aa2c856 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 28 Aug 2025 13:15:41 -0700 Subject: [PATCH 1217/1292] thermal: intel: selftests: workload_hint: Mask unsupported types The workload hint may contain some other hints which are not defined. So mask out unsupported types. Currently only lower 4 bits of workload type hints are defined. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20250828201541.931425-1-srinivas.pandruvada@linux.intel.com [ rjw: Subject cleanup ] Signed-off-by: Rafael J. Wysocki --- .../selftests/thermal/intel/workload_hint/workload_hint_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c b/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c index ba58589a114544..ca2bd03154e4d2 100644 --- a/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c +++ b/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c @@ -144,6 +144,8 @@ int main(int argc, char **argv) ret = sscanf(index_str, "%d", &index); if (ret < 0) break; + + index &= 0x0f; if (index > WORKLOAD_TYPE_MAX_INDEX) printf("Invalid workload type index\n"); else From 41f9049cff324b7033e6ed1ded7dfff803cf550a Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 10 Jul 2025 13:25:26 -0700 Subject: [PATCH 1218/1292] riscv: Only allow LTO with CMODEL_MEDANY When building with CONFIG_CMODEL_MEDLOW and CONFIG_LTO_CLANG, there is a series of errors due to some files being unconditionally compiled with '-mcmodel=medany', mismatching with the rest of the kernel built with '-mcmodel=medlow': ld.lld: error: Function Import: link error: linking module flags 'Code Model': IDs have conflicting values: 'i32 3' from vmlinux.a(init.o at 899908), and 'i32 1' from vmlinux.a(net-traces.o at 1014628) Only allow LTO to be performed when CONFIG_CMODEL_MEDANY is enabled to ensure there will be no code model mismatch errors. An alternative solution would be disabling LTO for the files with a different code model than the main kernel like some specialized areas of the kernel do but doing that for individual files is not as sustainable than forbidding the combination altogether. Cc: stable@vger.kernel.org Fixes: 021d23428bdb ("RISC-V: build: Allow LTO to be selected") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202506290255.KBVM83vZ-lkp@intel.com/ Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20250710-riscv-restrict-lto-to-medany-v1-1-b1dac9871ecf@kernel.org Signed-off-by: Paul Walmsley --- arch/riscv/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a4b233a0659ed8..51dcd8eaa24356 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -65,7 +65,7 @@ config RISCV select ARCH_SUPPORTS_HUGE_PFNMAP if TRANSPARENT_HUGEPAGE select ARCH_SUPPORTS_HUGETLBFS if MMU # LLD >= 14: https://github.com/llvm/llvm-project/issues/50505 - select ARCH_SUPPORTS_LTO_CLANG if LLD_VERSION >= 140000 + select ARCH_SUPPORTS_LTO_CLANG if LLD_VERSION >= 140000 && CMODEL_MEDANY select ARCH_SUPPORTS_LTO_CLANG_THIN if LLD_VERSION >= 140000 select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS if 64BIT && MMU select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU From 5b3706597b90a7b6c9ae148edd07a43531dcd49e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 20:05:59 +0530 Subject: [PATCH 1219/1292] ACPI: RISC-V: Fix FFH_CPPC_CSR error handling The cppc_ffh_csr_read() and cppc_ffh_csr_write() returns Linux error code in "data->ret.error" so cpc_read_ffh() and cpc_write_ffh() must not use sbi_err_map_linux_errno() for FFH_CPPC_CSR. Fixes: 30f3ffbee86b ("ACPI: RISC-V: Add CPPC driver") Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Reviewed-by: Troy Mitchell Reviewed-by: Sunil V L Reviewed-by: Nutty Liu Reviewed-by: Atish Patra Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250818143600.894385-2-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/acpi/riscv/cppc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/riscv/cppc.c b/drivers/acpi/riscv/cppc.c index 440cf9fb91aabb..42c1a90524707f 100644 --- a/drivers/acpi/riscv/cppc.c +++ b/drivers/acpi/riscv/cppc.c @@ -119,7 +119,7 @@ int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val) *val = data.ret.value; - return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0; + return data.ret.error; } return -EINVAL; @@ -148,7 +148,7 @@ int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val) smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1); - return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0; + return data.ret.error; } return -EINVAL; From 744175e972ac7c1f1be53556e186e5976e39f735 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Fri, 22 Aug 2025 14:25:39 +0200 Subject: [PATCH 1220/1292] perf test: Checking BPF metadata collection fails on version string commit edf2cadf01e8f ("perf test: add test for BPF metadata collection") fails consistently on the version string check. The perf version string on some of the constant integration test machines contains characters with special meaning in grep's extended regular expression matching algorithm. The output of perf version is: # perf version perf version 6.17.0-20250814.rc1.git20.24ea63ea3877.63.fc42.s390x+git # and the '+' character has special meaning in egrep command. Also the use of egrep is deprecated. Change the perf version string check to fixed character matching and get rid of egrep's warning being deprecated. Use grep -F instead. Output before: # perf test -F 102 Checking BPF metadata collection egrep: warning: egrep is obsolescent; using grep -E Basic BPF metadata test [Failed invalid output] 102: BPF metadata collection test : FAILED! # Output after: # perf test -F 102 Checking BPF metadata collection Basic BPF metadata test [Success] 102: BPF metadata collection test : Ok # Fixes: edf2cadf01e8f ("perf test: add test for BPF metadata collection") Signed-off-by: Thomas Richter Reviewed-by: Ian Rogers Reviewed-by: Arnaldo Carvalho de Melo Acked-by: Sumanth Korikkar Cc: Blake Jones Link: https://lore.kernel.org/r/20250822122540.4104658-1-tmricht@linux.ibm.com Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/test_bpf_metadata.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/test_bpf_metadata.sh b/tools/perf/tests/shell/test_bpf_metadata.sh index 69e3c2055134f5..be67d56e0f0994 100755 --- a/tools/perf/tests/shell/test_bpf_metadata.sh +++ b/tools/perf/tests/shell/test_bpf_metadata.sh @@ -61,7 +61,7 @@ test_bpf_metadata() { /perf_version/ { if (entry) print $NF; } - ' | egrep "$VERS" > /dev/null + ' | grep -qF "$VERS" then echo "Basic BPF metadata test [Failed invalid output]" err=1 From ca81e74dc34734078d34485d4aa123561ba75b15 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 4 Sep 2025 09:17:31 -0700 Subject: [PATCH 1221/1292] perf symbol-elf: Add support for the block argument for libbfd James Clark caught that the BUILD_NONDISTRO=1 build with libbfd was broken due to an update to the read_build_id function adding a blocking argument. Add support for this argument by first opening the file blocking or non-blocking, then switching from bfd_openr to bfd_fdopenr and passing the opened fd. bfd_fdopenr closes the fd on error and when bfd_close are called. Reported-by: James Clark Closes: https://lore.kernel.org/lkml/20250903-james-perf-read-build-id-fix-v1-2-6a694d0a980f@linaro.org/ Fixes: 2c369d91d093 ("perf symbol: Add blocking argument to filename__read_build_id") Signed-off-by: Ian Rogers Reviewed-by: James Clark Link: https://lore.kernel.org/r/20250904161731.1193729-1-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/util/symbol-elf.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 033c79231a54cd..1346fd18065365 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -873,13 +873,17 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) #ifdef HAVE_LIBBFD_BUILDID_SUPPORT -static int read_build_id(const char *filename, struct build_id *bid) +static int read_build_id(const char *filename, struct build_id *bid, bool block) { size_t size = sizeof(bid->data); - int err = -1; + int err = -1, fd; bfd *abfd; - abfd = bfd_openr(filename, NULL); + fd = open(filename, block ? O_RDONLY : (O_RDONLY | O_NONBLOCK)); + if (fd < 0) + return -1; + + abfd = bfd_fdopenr(filename, /*target=*/NULL, fd); if (!abfd) return -1; From be585f7ebc99598edf97c3001d0f8d67954ab376 Mon Sep 17 00:00:00 2001 From: Charles Han Date: Fri, 5 Sep 2025 17:18:44 +0800 Subject: [PATCH 1222/1292] ASoC: codecs: fs210x: Add NULL check in fs210x_register_snd_component Add check for the return value of devm_kmemdup() to prevent potential null pointer dereference. Fixes: 756117701779 ("ASoC: codecs: Add FourSemi FS2104/5S audio amplifier driver") Signed-off-by: Charles Han Message-ID: <20250905091845.1559-1-hanchunchao@inspur.com> Signed-off-by: Mark Brown --- sound/soc/codecs/fs210x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c index b4f51ee7235abe..e2f85714972d55 100644 --- a/sound/soc/codecs/fs210x.c +++ b/sound/soc/codecs/fs210x.c @@ -1458,6 +1458,9 @@ static int fs210x_register_snd_component(struct fs210x_priv *fs210x) dai_drv->name = devm_kasprintf(fs210x->dev, GFP_KERNEL, "%s-%d", dai_drv->name, instance_id); + if (!dai_drv->name) + return -ENOMEM; + instance_id++; if (fs210x->devid == FS2105S_DEVICE_ID) { From 9e5eb8b49ffe3c173bf7b8c338a57dfa09fb4634 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 5 Sep 2025 11:10:15 +0200 Subject: [PATCH 1223/1292] ASoC: replace use of system_unbound_wq with system_dfl_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. system_unbound_wq should be the default workqueue so as not to enforce locality constraints for random work whenever it's not required. Adding system_dfl_wq to encourage its use when unbound work should be used. queue_work() / queue_delayed_work() / mod_delayed_work() will now use the new unbound wq: whether the user still use the old wq a warn will be printed along with a wq redirect to the new one. The old system_unbound_wq will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Message-ID: <20250905091016.109428-2-marco.crivellari@suse.com> Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 8a1d5cc75d6c23..82c76338df2165 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1043,7 +1043,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - queue_work(system_unbound_wq, &dsp->boot_work); + queue_work(system_dfl_wq, &dsp->boot_work); break; case SND_SOC_DAPM_PRE_PMD: wm_adsp_power_down(dsp); From a7ed7b9d0ebb038db9963d574da0311cab0b666a Mon Sep 17 00:00:00 2001 From: panfan Date: Thu, 4 Sep 2025 20:22:36 -0700 Subject: [PATCH 1224/1292] arm64: ftrace: fix unreachable PLT for ftrace_caller in init_module with CONFIG_DYNAMIC_FTRACE On arm64, it has been possible for a module's sections to be placed more than 128M away from each other since commit: commit 3e35d303ab7d ("arm64: module: rework module VA range selection") Due to this, an ftrace callsite in a module's .init.text section can be out of branch range for the module's ftrace PLT entry (in the module's .text section). Any attempt to enable tracing of that callsite will result in a BRK being patched into the callsite, resulting in a fatal exception when the callsite is later executed. Fix this by adding an additional trampoline for .init.text, which will be within range. No additional trampolines are necessary due to the way a given module's executable sections are packed together. Any executable section beginning with ".init" will be placed in MOD_INIT_TEXT, and any other executable section, including those beginning with ".exit", will be placed in MOD_TEXT. Fixes: 3e35d303ab7d ("arm64: module: rework module VA range selection") Cc: # 6.5.x Signed-off-by: panfan Acked-by: Mark Rutland Link: https://lore.kernel.org/r/20250905032236.3220885-1-panfan@qti.qualcomm.com Signed-off-by: Catalin Marinas --- arch/arm64/include/asm/module.h | 1 + arch/arm64/include/asm/module.lds.h | 1 + arch/arm64/kernel/ftrace.c | 13 ++++++++++--- arch/arm64/kernel/module-plts.c | 12 +++++++++++- arch/arm64/kernel/module.c | 11 +++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index 79550b22ba19ce..fb9b88eebeb15a 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -19,6 +19,7 @@ struct mod_arch_specific { /* for CONFIG_DYNAMIC_FTRACE */ struct plt_entry *ftrace_trampolines; + struct plt_entry *init_ftrace_trampolines; }; u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, diff --git a/arch/arm64/include/asm/module.lds.h b/arch/arm64/include/asm/module.lds.h index b9ae8349e35dbb..fb944b46846dae 100644 --- a/arch/arm64/include/asm/module.lds.h +++ b/arch/arm64/include/asm/module.lds.h @@ -2,6 +2,7 @@ SECTIONS { .plt 0 : { BYTE(0) } .init.plt 0 : { BYTE(0) } .text.ftrace_trampoline 0 : { BYTE(0) } + .init.text.ftrace_trampoline 0 : { BYTE(0) } #ifdef CONFIG_KASAN_SW_TAGS /* diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c index 5a890714ee2e98..5adad37ab4faff 100644 --- a/arch/arm64/kernel/ftrace.c +++ b/arch/arm64/kernel/ftrace.c @@ -258,10 +258,17 @@ int ftrace_update_ftrace_func(ftrace_func_t func) return ftrace_modify_code(pc, 0, new, false); } -static struct plt_entry *get_ftrace_plt(struct module *mod) +static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr) { #ifdef CONFIG_MODULES - struct plt_entry *plt = mod->arch.ftrace_trampolines; + struct plt_entry *plt = NULL; + + if (within_module_mem_type(addr, mod, MOD_INIT_TEXT)) + plt = mod->arch.init_ftrace_trampolines; + else if (within_module_mem_type(addr, mod, MOD_TEXT)) + plt = mod->arch.ftrace_trampolines; + else + return NULL; return &plt[FTRACE_PLT_IDX]; #else @@ -332,7 +339,7 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec, if (WARN_ON(!mod)) return false; - plt = get_ftrace_plt(mod); + plt = get_ftrace_plt(mod, pc); if (!plt) { pr_err("ftrace: no module PLT for %ps\n", (void *)*addr); return false; diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index bde32979c06afc..7afd370da9f48f 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c @@ -283,7 +283,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, unsigned long core_plts = 0; unsigned long init_plts = 0; Elf64_Sym *syms = NULL; - Elf_Shdr *pltsec, *tramp = NULL; + Elf_Shdr *pltsec, *tramp = NULL, *init_tramp = NULL; int i; /* @@ -298,6 +298,9 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, else if (!strcmp(secstrings + sechdrs[i].sh_name, ".text.ftrace_trampoline")) tramp = sechdrs + i; + else if (!strcmp(secstrings + sechdrs[i].sh_name, + ".init.text.ftrace_trampoline")) + init_tramp = sechdrs + i; else if (sechdrs[i].sh_type == SHT_SYMTAB) syms = (Elf64_Sym *)sechdrs[i].sh_addr; } @@ -363,5 +366,12 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry); } + if (init_tramp) { + init_tramp->sh_type = SHT_NOBITS; + init_tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + init_tramp->sh_addralign = __alignof__(struct plt_entry); + init_tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry); + } + return 0; } diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 40148d2725ceda..d6d443c4a01aca 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -466,6 +466,17 @@ static int module_init_ftrace_plt(const Elf_Ehdr *hdr, __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR); mod->arch.ftrace_trampolines = plts; + + s = find_section(hdr, sechdrs, ".init.text.ftrace_trampoline"); + if (!s) + return -ENOEXEC; + + plts = (void *)s->sh_addr; + + __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR); + + mod->arch.init_ftrace_trampolines = plts; + #endif return 0; } From 97248d05b70edc674f2f2fa835fed33172686b1d Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Tue, 2 Sep 2025 15:33:23 +0800 Subject: [PATCH 1225/1292] cpufreq: Drop redundant freq_table parameter Since commit e0b3165ba521 ("cpufreq: add 'freq_table' in struct cpufreq_policy"), freq_table has been stored in struct cpufreq_policy instead of being maintained separately. However, several helpers in freq_table.c still take both policy and freq_table as parameters, even though policy->freq_table can always be used. This leads to redundant function arguments and increases the chance of inconsistencies. This patch removes the unnecessary freq_table argument from these functions and updates their callers to only pass policy. This makes the code simpler, more consistent, and avoids duplication. Signed-off-by: Zihuan Zhang Acked-by: Viresh Kumar Link: https://patch.msgid.link/20250902073323.48330-1-zhangzihuan@kylinos.cn Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 +- drivers/cpufreq/freq_table.c | 14 ++++++-------- drivers/cpufreq/sh-cpufreq.c | 6 ++---- drivers/cpufreq/virtual-cpufreq.c | 2 +- include/linux/cpufreq.h | 7 +++---- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a615c98d80ca01..5fcc99f768d2ee 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2793,7 +2793,7 @@ int cpufreq_boost_set_sw(struct cpufreq_policy *policy, int state) if (!policy->freq_table) return -ENXIO; - ret = cpufreq_frequency_table_cpuinfo(policy, policy->freq_table); + ret = cpufreq_frequency_table_cpuinfo(policy); if (ret) { pr_err("%s: Policy frequency update failed\n", __func__); return ret; diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 35de513af6c94e..d5111ee56e3803 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -28,10 +28,9 @@ static bool policy_has_boost_freq(struct cpufreq_policy *policy) return false; } -int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table) +int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy) { - struct cpufreq_frequency_table *pos; + struct cpufreq_frequency_table *pos, *table = policy->freq_table; unsigned int min_freq = ~0; unsigned int max_freq = 0; unsigned int freq; @@ -65,10 +64,9 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, return 0; } -int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy, - struct cpufreq_frequency_table *table) +int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy) { - struct cpufreq_frequency_table *pos; + struct cpufreq_frequency_table *pos, *table = policy->freq_table; unsigned int freq, prev_smaller = 0; bool found = false; @@ -110,7 +108,7 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy) if (!policy->freq_table) return -ENODEV; - return cpufreq_frequency_table_verify(policy, policy->freq_table); + return cpufreq_frequency_table_verify(policy); } EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); @@ -354,7 +352,7 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy) return 0; } - ret = cpufreq_frequency_table_cpuinfo(policy, policy->freq_table); + ret = cpufreq_frequency_table_cpuinfo(policy); if (ret) return ret; diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index 9c0b01e00508c9..642ddb9ea217ed 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -89,11 +89,9 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, static int sh_cpufreq_verify(struct cpufreq_policy_data *policy) { struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu); - struct cpufreq_frequency_table *freq_table; - freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; - if (freq_table) - return cpufreq_frequency_table_verify(policy, freq_table); + if (policy->freq_table) + return cpufreq_frequency_table_verify(policy); cpufreq_verify_within_cpu_limits(policy); diff --git a/drivers/cpufreq/virtual-cpufreq.c b/drivers/cpufreq/virtual-cpufreq.c index 7dd1b0c263c7ed..6ffa16d239b2be 100644 --- a/drivers/cpufreq/virtual-cpufreq.c +++ b/drivers/cpufreq/virtual-cpufreq.c @@ -250,7 +250,7 @@ static int virt_cpufreq_offline(struct cpufreq_policy *policy) static int virt_cpufreq_verify_policy(struct cpufreq_policy_data *policy) { if (policy->freq_table) - return cpufreq_frequency_table_verify(policy, policy->freq_table); + return cpufreq_frequency_table_verify(policy); cpufreq_verify_within_cpu_limits(policy); return 0; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 95f3807c8c551d..40966512ea1812 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -780,11 +780,10 @@ struct cpufreq_frequency_table { else -int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table); +int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy); + +int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy); -int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy, - struct cpufreq_frequency_table *table); int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy); int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, From b49d70849530f046b1f9a42c963840ca91c60929 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 2 Sep 2025 19:45:42 +0800 Subject: [PATCH 1226/1292] cpufreq: Use int type to store negative error codes Change the 'ret' variable in store_scaling_setspeed() from unsigned int to int, as it needs to store either negative error codes or zero returned by kstrtouint(). No effect on runtime. Signed-off-by: Qianfeng Rong Acked-by: Viresh Kumar Link: https://patch.msgid.link/20250902114545.651661-2-rongqianfeng@vivo.com Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5fcc99f768d2ee..6812afdf0dbfff 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -914,7 +914,7 @@ static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, const char *buf, size_t count) { unsigned int freq = 0; - unsigned int ret; + int ret; if (!policy->governor || !policy->governor->store_setspeed) return -EINVAL; From e5e9b7bd864261f8132abb542afac4758e6232a3 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 2 Sep 2025 19:45:44 +0800 Subject: [PATCH 1227/1292] cpufreq: speedstep-lib: Use int type to store negative error codes Change the return type of the speedstep_get_freqs() function from unsigned int to int because it may return negative error codes. For the same reason, change the 'ret' variables to int type as well. No effect on runtime. Signed-off-by: Qianfeng Rong Acked-by: Viresh Kumar Link: https://patch.msgid.link/20250902114545.651661-4-rongqianfeng@vivo.com Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/speedstep-lib.c | 12 ++++++------ drivers/cpufreq/speedstep-lib.h | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c index 0b66df4ed51340..f8b42e981635a8 100644 --- a/drivers/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -378,16 +378,16 @@ EXPORT_SYMBOL_GPL(speedstep_detect_processor); * DETECT SPEEDSTEP SPEEDS * *********************************************************************/ -unsigned int speedstep_get_freqs(enum speedstep_processor processor, - unsigned int *low_speed, - unsigned int *high_speed, - unsigned int *transition_latency, - void (*set_state) (unsigned int state)) +int speedstep_get_freqs(enum speedstep_processor processor, + unsigned int *low_speed, + unsigned int *high_speed, + unsigned int *transition_latency, + void (*set_state)(unsigned int state)) { unsigned int prev_speed; - unsigned int ret = 0; unsigned long flags; ktime_t tv1, tv2; + int ret = 0; if ((!processor) || (!low_speed) || (!high_speed) || (!set_state)) return -EINVAL; diff --git a/drivers/cpufreq/speedstep-lib.h b/drivers/cpufreq/speedstep-lib.h index dc762ea786be96..48329647d4c40d 100644 --- a/drivers/cpufreq/speedstep-lib.h +++ b/drivers/cpufreq/speedstep-lib.h @@ -41,8 +41,8 @@ extern unsigned int speedstep_get_frequency(enum speedstep_processor processor); * SPEEDSTEP_LOW; the second argument is zero so that no * cpufreq_notify_transition calls are initiated. */ -extern unsigned int speedstep_get_freqs(enum speedstep_processor processor, - unsigned int *low_speed, - unsigned int *high_speed, - unsigned int *transition_latency, - void (*set_state) (unsigned int state)); +extern int speedstep_get_freqs(enum speedstep_processor processor, + unsigned int *low_speed, + unsigned int *high_speed, + unsigned int *transition_latency, + void (*set_state)(unsigned int state)); From be82483d1b60baf6747884bd74cb7de484deaf76 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Sep 2025 15:55:45 +0200 Subject: [PATCH 1228/1292] PM: sleep: core: Clear power.must_resume in noirq suspend error path If system suspend is aborted in the "noirq" phase (for instance, due to an error returned by one of the device callbacks), power.is_noirq_suspended will not be set for some devices and device_resume_noirq() will return early for them. Consequently, noirq resume callbacks will not run for them at all because the noirq suspend callbacks have not run for them yet. If any of them has power.must_resume set and late suspend has been skipped for it (due to power.smart_suspend), early resume should be skipped for it either, or its state may become inconsistent (for instance, if the early resume assumes that it will always follow noirq resume). Make that happen by clearing power.must_resume in device_resume_noirq() for devices with power.is_noirq_suspended clear that have been left in suspend by device_suspend_late(), which will subsequently cause device_resume_early() to leave the device in suspend and avoid changing its state. Fixes: 0d4b54c6fee8 ("PM / core: Add LEAVE_SUSPENDED driver flag") Link: https://lore.kernel.org/linux-pm/5d692b81-6f58-4e86-9cb0-ede69a09d799@rowland.harvard.edu/ Signed-off-by: Rafael J. Wysocki Reviewed-by: Ulf Hansson Link: https://patch.msgid.link/3381776.aeNJFYEL58@rafael.j.wysocki --- drivers/base/power/main.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2ea6e05e6ec90e..c883b01ffbddc4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -724,8 +724,20 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy if (dev->power.syscore || dev->power.direct_complete) goto Out; - if (!dev->power.is_noirq_suspended) + if (!dev->power.is_noirq_suspended) { + /* + * This means that system suspend has been aborted in the noirq + * phase before invoking the noirq suspend callback for the + * device, so if device_suspend_late() has left it in suspend, + * device_resume_early() should leave it in suspend either in + * case the early resume of it depends on the noirq resume that + * has not run. + */ + if (dev_pm_skip_suspend(dev)) + dev->power.must_resume = false; + goto Out; + } if (!dpm_wait_for_superior(dev, async)) goto Out; From e54ddc44506f018f75e61c76a213227bd67dffb6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 3 Sep 2025 16:52:45 +0200 Subject: [PATCH 1229/1292] thermal: testing: Rearrange variable declarations involving __free() Follow cleanup.h recommendations and always define and assign variables in one statement when __free() is used. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/5934556.DvuYhMxLoT@rafael.j.wysocki --- drivers/thermal/testing/zone.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/thermal/testing/zone.c b/drivers/thermal/testing/zone.c index 4257d813d572d1..c12c405225bbcc 100644 --- a/drivers/thermal/testing/zone.c +++ b/drivers/thermal/testing/zone.c @@ -184,15 +184,14 @@ static void tt_add_tz_work_fn(struct work_struct *work) int tt_add_tz(void) { - struct tt_thermal_zone *tt_zone __free(kfree); - struct tt_work *tt_work __free(kfree) = NULL; int ret; - tt_zone = kzalloc(sizeof(*tt_zone), GFP_KERNEL); + struct tt_thermal_zone *tt_zone __free(kfree) = kzalloc(sizeof(*tt_zone), + GFP_KERNEL); if (!tt_zone) return -ENOMEM; - tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL); + struct tt_work *tt_work __free(kfree) = kzalloc(sizeof(*tt_work), GFP_KERNEL); if (!tt_work) return -ENOMEM; @@ -237,7 +236,6 @@ static void tt_zone_unregister_tz(struct tt_thermal_zone *tt_zone) int tt_del_tz(const char *arg) { - struct tt_work *tt_work __free(kfree) = NULL; struct tt_thermal_zone *tt_zone, *aux; int ret; int id; @@ -246,7 +244,7 @@ int tt_del_tz(const char *arg) if (ret != 1) return -EINVAL; - tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL); + struct tt_work *tt_work __free(kfree) = kzalloc(sizeof(*tt_work), GFP_KERNEL); if (!tt_work) return -ENOMEM; @@ -330,20 +328,17 @@ static void tt_zone_add_trip_work_fn(struct work_struct *work) int tt_zone_add_trip(const char *arg) { - struct tt_thermal_zone *tt_zone __free(put_tt_zone) = NULL; - struct tt_trip *tt_trip __free(kfree) = NULL; - struct tt_work *tt_work __free(kfree); int id; - tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL); + struct tt_work *tt_work __free(kfree) = kzalloc(sizeof(*tt_work), GFP_KERNEL); if (!tt_work) return -ENOMEM; - tt_trip = kzalloc(sizeof(*tt_trip), GFP_KERNEL); + struct tt_trip *tt_trip __free(kfree) = kzalloc(sizeof(*tt_trip), GFP_KERNEL); if (!tt_trip) return -ENOMEM; - tt_zone = tt_get_tt_zone(arg); + struct tt_thermal_zone *tt_zone __free(put_tt_zone) = tt_get_tt_zone(arg); if (IS_ERR(tt_zone)) return PTR_ERR(tt_zone); @@ -387,7 +382,6 @@ static const struct thermal_zone_device_ops tt_zone_ops = { static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) { - struct thermal_trip *trips __free(kfree) = NULL; struct thermal_zone_device *tz; struct tt_trip *tt_trip; int i; @@ -397,7 +391,8 @@ static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) if (tt_zone->tz) return -EINVAL; - trips = kcalloc(tt_zone->num_trips, sizeof(*trips), GFP_KERNEL); + struct thermal_trip *trips __free(kfree) = kcalloc(tt_zone->num_trips, + sizeof(*trips), GFP_KERNEL); if (!trips) return -ENOMEM; @@ -421,9 +416,7 @@ static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) int tt_zone_reg(const char *arg) { - struct tt_thermal_zone *tt_zone __free(put_tt_zone); - - tt_zone = tt_get_tt_zone(arg); + struct tt_thermal_zone *tt_zone __free(put_tt_zone) = tt_get_tt_zone(arg); if (IS_ERR(tt_zone)) return PTR_ERR(tt_zone); @@ -432,9 +425,7 @@ int tt_zone_reg(const char *arg) int tt_zone_unreg(const char *arg) { - struct tt_thermal_zone *tt_zone __free(put_tt_zone); - - tt_zone = tt_get_tt_zone(arg); + struct tt_thermal_zone *tt_zone __free(put_tt_zone) = tt_get_tt_zone(arg); if (IS_ERR(tt_zone)) return PTR_ERR(tt_zone); From c05fa4091863468fd53abf1334c05052eda1ff52 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 3 Sep 2025 16:56:04 +0200 Subject: [PATCH 1230/1292] cpufreq: core: Rearrange variable declarations involving __free() Follow cleanup.h recommendations and always define and assign variables in one statement when __free() is used. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Krzysztof Kozlowski Acked-by: Viresh Kumar Link: https://patch.msgid.link/4691667.LvFx2qVVIh@rafael.j.wysocki --- drivers/cpufreq/cpufreq.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 6812afdf0dbfff..30e8e9b3c12fc0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1845,7 +1845,6 @@ static unsigned int cpufreq_verify_current_freq(struct cpufreq_policy *policy, b */ unsigned int cpufreq_quick_get(unsigned int cpu) { - struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; unsigned long flags; read_lock_irqsave(&cpufreq_driver_lock, flags); @@ -1860,7 +1859,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu) read_unlock_irqrestore(&cpufreq_driver_lock, flags); - policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (policy) return policy->cur; @@ -1876,9 +1875,7 @@ EXPORT_SYMBOL(cpufreq_quick_get); */ unsigned int cpufreq_quick_get_max(unsigned int cpu) { - struct cpufreq_policy *policy __free(put_cpufreq_policy); - - policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (policy) return policy->max; @@ -1894,9 +1891,7 @@ EXPORT_SYMBOL(cpufreq_quick_get_max); */ __weak unsigned int cpufreq_get_hw_max_freq(unsigned int cpu) { - struct cpufreq_policy *policy __free(put_cpufreq_policy); - - policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (policy) return policy->cpuinfo.max_freq; @@ -1920,9 +1915,7 @@ static unsigned int __cpufreq_get(struct cpufreq_policy *policy) */ unsigned int cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy __free(put_cpufreq_policy); - - policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (!policy) return 0; @@ -2751,9 +2744,7 @@ static void cpufreq_policy_refresh(struct cpufreq_policy *policy) */ void cpufreq_update_policy(unsigned int cpu) { - struct cpufreq_policy *policy __free(put_cpufreq_policy); - - policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (!policy) return; @@ -2770,9 +2761,7 @@ EXPORT_SYMBOL(cpufreq_update_policy); */ void cpufreq_update_limits(unsigned int cpu) { - struct cpufreq_policy *policy __free(put_cpufreq_policy); - - policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (!policy) return; @@ -3054,9 +3043,7 @@ static int __init cpufreq_core_init(void) static bool cpufreq_policy_is_good_for_eas(unsigned int cpu) { - struct cpufreq_policy *policy __free(put_cpufreq_policy); - - policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (!policy) { pr_debug("cpufreq policy not set for CPU: %d\n", cpu); return false; From 5f2ec3536d7933a804d28d2541e4e918ba32587b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 3 Sep 2025 16:59:47 +0200 Subject: [PATCH 1231/1292] cpufreq: intel_pstate: Rearrange variable declaration involving __free() Follow cleanup.h recommendations and define and assign a variable in one statement when __free() is used. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Krzysztof Kozlowski Acked-by: Viresh Kumar Reviewed-by: Zihuan Zhang Link: https://patch.msgid.link/2251447.irdbgypaU6@rafael.j.wysocki --- drivers/cpufreq/intel_pstate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index f366d35c58404f..81fc1408754ab6 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1502,9 +1502,7 @@ static void __intel_pstate_update_max_freq(struct cpufreq_policy *policy, static bool intel_pstate_update_max_freq(struct cpudata *cpudata) { - struct cpufreq_policy *policy __free(put_cpufreq_policy); - - policy = cpufreq_cpu_get(cpudata->cpu); + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu); if (!policy) return false; From 5136380b74f1e562ad96268578f22d8b1a29cb90 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Wed, 3 Sep 2025 21:20:59 +0200 Subject: [PATCH 1232/1292] thermal: hwmon: replace deprecated strcpy() with strscpy() Since strcpy() is deprecated and the last user of it in the thermal subsystem is thermal_hwmon_lookup_by_type(), replace strcpy() in that function with strscpy(). Signed-off-by: Osama Abdelkader Reviewed-by: Lukasz Luba Link: https://patch.msgid.link/20250903192059.11353-1-osama.abdelkader@gmail.com [ rjw: Changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- drivers/thermal/thermal_hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c index 0ecccd4d8556c4..64cc3ab949fed4 100644 --- a/drivers/thermal/thermal_hwmon.c +++ b/drivers/thermal/thermal_hwmon.c @@ -96,7 +96,7 @@ thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz) mutex_lock(&thermal_hwmon_list_lock); list_for_each_entry(hwmon, &thermal_hwmon_list, node) { - strcpy(type, tz->type); + strscpy(type, tz->type); strreplace(type, '-', '_'); if (!strcmp(hwmon->type, type)) { mutex_unlock(&thermal_hwmon_list_lock); From 42c74f6b1c3694892ab92750a60aeb6212d73ac1 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 3 Sep 2025 17:06:07 -0700 Subject: [PATCH 1233/1292] cpufreq: intel_pstate: Remove EPB-related code The intel_pstate driver does not enable HWP mode when CPUID.06H:EAX[10] is not set, indicating that EPP (Energy Performance Preference) is not supported by the hardware. When EPP is unavailable, the system falls back to using EPB (Energy Performance Bias) if the feature is supported. However, since the intel_pstate driver will not enable HWP in this scenario, any EPB-related code becomes unreachable and irrelevant. Remove the EPB handling code paths simplifying the driver logic and reducing code size. Signed-off-by: Srinivas Pandruvada Link: https://patch.msgid.link/20250904000608.260817-1-srinivas.pandruvada@linux.intel.com [ rjw: Subject adjustment ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 49 +++------------------------------- 1 file changed, 4 insertions(+), 45 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 81fc1408754ab6..e9fe5dd6c7927b 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -620,24 +620,9 @@ static int min_perf_pct_min(void) (cpu->pstate.min_pstate * 100 / turbo_pstate) : 0; } -static s16 intel_pstate_get_epb(struct cpudata *cpu_data) -{ - u64 epb; - int ret; - - if (!boot_cpu_has(X86_FEATURE_EPB)) - return -ENXIO; - - ret = rdmsrq_on_cpu(cpu_data->cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb); - if (ret) - return (s16)ret; - - return (s16)(epb & 0x0f); -} - static s16 intel_pstate_get_epp(struct cpudata *cpu_data, u64 hwp_req_data) { - s16 epp; + s16 epp = -EOPNOTSUPP; if (boot_cpu_has(X86_FEATURE_HWP_EPP)) { /* @@ -651,34 +636,13 @@ static s16 intel_pstate_get_epp(struct cpudata *cpu_data, u64 hwp_req_data) return epp; } epp = (hwp_req_data >> 24) & 0xff; - } else { - /* When there is no EPP present, HWP uses EPB settings */ - epp = intel_pstate_get_epb(cpu_data); } return epp; } -static int intel_pstate_set_epb(int cpu, s16 pref) -{ - u64 epb; - int ret; - - if (!boot_cpu_has(X86_FEATURE_EPB)) - return -ENXIO; - - ret = rdmsrq_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb); - if (ret) - return ret; - - epb = (epb & ~0x0f) | pref; - wrmsrq_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, epb); - - return 0; -} - /* - * EPP/EPB display strings corresponding to EPP index in the + * EPP display strings corresponding to EPP index in the * energy_perf_strings[] * index String *------------------------------------- @@ -782,7 +746,7 @@ static int intel_pstate_set_energy_pref_index(struct cpudata *cpu_data, u32 raw_epp) { int epp = -EINVAL; - int ret; + int ret = -EOPNOTSUPP; if (!pref_index) epp = cpu_data->epp_default; @@ -802,10 +766,6 @@ static int intel_pstate_set_energy_pref_index(struct cpudata *cpu_data, return -EBUSY; ret = intel_pstate_set_epp(cpu_data, epp); - } else { - if (epp == -EINVAL) - epp = (pref_index - 1) << 2; - ret = intel_pstate_set_epb(cpu_data->cpu, epp); } return ret; @@ -1337,9 +1297,8 @@ static void intel_pstate_hwp_set(unsigned int cpu) if (boot_cpu_has(X86_FEATURE_HWP_EPP)) { value &= ~GENMASK_ULL(31, 24); value |= (u64)epp << 24; - } else { - intel_pstate_set_epb(cpu, epp); } + skip_epp: WRITE_ONCE(cpu_data->hwp_req_cached, value); wrmsrq_on_cpu(cpu, MSR_HWP_REQUEST, value); From 9d68320b2bca876278856fdc1e8684a7494dd069 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Fri, 5 Sep 2025 16:18:58 +0800 Subject: [PATCH 1234/1292] ACPI: processor: idle: Fix function defined but not used warning If CONFIG_ACPI_PROCESSOR_IDLE=n, acpi_processor_register_idle_driver() and acpi_processor_unregister_idle_driver() are never used and the empty stubs of them are not needed. Moreover, they cause the compiler to complain [1], so remove them. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508300519.tZQHY6HA-lkp@intel.com/ [1] Fixes: 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration") Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250905081900.663869-2-lihuisong@huawei.com [ rjw: Changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- include/acpi/processor.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 360b673f05e575..ff864c1cee3a4c 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -445,12 +445,6 @@ static inline int acpi_processor_hotplug(struct acpi_processor *pr) { return -ENODEV; } -static inline void acpi_processor_register_idle_driver(void) -{ -} -static inline void acpi_processor_unregister_idle_driver(void) -{ -} #endif /* CONFIG_ACPI_PROCESSOR_IDLE */ /* in processor_thermal.c */ From e108c8a94f3f958c877f6ec7a6052a893ae4aa98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Fri, 25 Jul 2025 18:54:09 +0200 Subject: [PATCH 1235/1292] riscv: use lw when reading int cpu in new_vmalloc_check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REG_L is wrong, because thread_info.cpu is 32-bit, not xlen-bit wide. The struct currently has a hole after cpu, so little endian accesses seemed fine. Fixes: 503638e0babf ("riscv: Stop emitting preventive sfence.vma for new vmalloc mappings") Cc: stable@vger.kernel.org Reviewed-by: Alexandre Ghiti Signed-off-by: Radim KrčmÔř Link: https://lore.kernel.org/r/20250725165410.2896641-4-rkrcmar@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/kernel/entry.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 3a0ec6fd595691..d0ded2438533c4 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -46,7 +46,7 @@ * a0 = &new_vmalloc[BIT_WORD(cpu)] * a1 = BIT_MASK(cpu) */ - REG_L a2, TASK_TI_CPU(tp) + lw a2, TASK_TI_CPU(tp) /* * Compute the new_vmalloc element position: * (cpu / 64) * 8 = (cpu >> 6) << 3 From 1046791390af6703a5e24718a16f37974adb11db Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 25 Jul 2025 00:08:52 +0200 Subject: [PATCH 1236/1292] riscv: uaccess: fix __put_user_nocheck for unaligned accesses The type of the value to write should be determined by the size of the destination, not by the value itself, which may be a constant. This aligns the behavior with x86_64, where __typeof__(*(__gu_ptr)) is used to infer the correct type. This fixes an issue in put_cmsg, which was only writing 4 out of 8 bytes to the cmsg_len field, causing the glibc tst-socket-timestamp test to fail. Fixes: ca1a66cdd685 ("riscv: uaccess: do not do misaligned accesses in get/put_user()") Signed-off-by: Aurelien Jarno Reviewed-by: Alexandre Ghiti Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250724220853.1969954-1-aurelien@aurel32.net Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index b88a6218b7f243..22e3f52a763d1c 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -311,7 +311,7 @@ do { \ do { \ if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && \ !IS_ALIGNED((uintptr_t)__gu_ptr, sizeof(*__gu_ptr))) { \ - __inttype(x) ___val = (__inttype(x))x; \ + __typeof__(*(__gu_ptr)) ___val = (x); \ if (__asm_copy_to_user_sum_enabled(__gu_ptr, &(___val), sizeof(*__gu_ptr))) \ goto label; \ break; \ From ad5348c765914766a98ad26cf7a8c28d51a16bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Tue, 12 Aug 2025 11:02:55 +0200 Subject: [PATCH 1237/1292] riscv, bpf: use lw when reading int cpu in BPF_MOV64_PERCPU_REG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit emit_ld is wrong, because thread_info.cpu is 32-bit, not xlen-bit wide. The struct currently has a hole after cpu, so little endian accesses seemed fine. Fixes: 19c56d4e5be1 ("riscv, bpf: add internal-only MOV instruction to resolve per-CPU addrs") Cc: stable@vger.kernel.org Signed-off-by: Radim KrčmÔř Reviewed-by: Pu Lehui Acked-by: Bjƶrn Tƶpel Tested-by: Bjƶrn Tƶpel # QEMU Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250812090256.757273-3-rkrcmar@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/net/bpf_jit_comp64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 10e01ff06312d9..6e1554d89681ff 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1356,7 +1356,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, emit_mv(rd, rs, ctx); #ifdef CONFIG_SMP /* Load current CPU number in T1 */ - emit_ld(RV_REG_T1, offsetof(struct thread_info, cpu), + emit_lw(RV_REG_T1, offsetof(struct thread_info, cpu), RV_REG_TP, ctx); /* Load address of __per_cpu_offset array in T2 */ emit_addr(RV_REG_T2, (u64)&__per_cpu_offset, extra_pass, ctx); From 8a16586fa7b8a01360890d284896b90c217dca44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Tue, 12 Aug 2025 11:02:56 +0200 Subject: [PATCH 1238/1292] riscv, bpf: use lw when reading int cpu in bpf_get_smp_processor_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit emit_ld is wrong, because thread_info.cpu is 32-bit, not xlen-bit wide. The struct currently has a hole after cpu, so little endian accesses seemed fine. Fixes: 2ddec2c80b44 ("riscv, bpf: inline bpf_get_smp_processor_id()") Cc: stable@vger.kernel.org Signed-off-by: Radim KrčmÔř Reviewed-by: Pu Lehui Link: https://lore.kernel.org/r/20250812090256.757273-4-rkrcmar@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/net/bpf_jit_comp64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 6e1554d89681ff..9883a55d61b5b9 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1763,7 +1763,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, */ if (insn->src_reg == 0 && insn->imm == BPF_FUNC_get_smp_processor_id) { /* Load current CPU number in R0 */ - emit_ld(bpf_to_rv_reg(BPF_REG_0, ctx), offsetof(struct thread_info, cpu), + emit_lw(bpf_to_rv_reg(BPF_REG_0, ctx), offsetof(struct thread_info, cpu), RV_REG_TP, ctx); break; } From f4ea67a722e8c9e1fb8109adebb9fb881ff0793a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Fri, 25 Jul 2025 18:54:10 +0200 Subject: [PATCH 1239/1292] riscv: use lw when reading int cpu in asm_per_cpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REG_L is wrong, because thread_info.cpu is 32-bit, not xlen-bit wide. The struct currently has a hole after cpu, so little endian accesses seemed fine. Fixes: be97d0db5f44 ("riscv: VMAP_STACK overflow detection thread-safe") Cc: stable@vger.kernel.org Reviewed-by: Alexandre Ghiti Signed-off-by: Radim KrčmÔř Link: https://lore.kernel.org/r/20250725165410.2896641-5-rkrcmar@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/asm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h index a8a2af6dfe9d24..2a16e88e13deda 100644 --- a/arch/riscv/include/asm/asm.h +++ b/arch/riscv/include/asm/asm.h @@ -91,7 +91,7 @@ #endif .macro asm_per_cpu dst sym tmp - REG_L \tmp, TASK_TI_CPU_NUM(tp) + lw \tmp, TASK_TI_CPU_NUM(tp) slli \tmp, \tmp, PER_CPU_OFFSET_SHIFT la \dst, __per_cpu_offset add \dst, \dst, \tmp From 95c54cd9c769a198118772e196adfaa1f002e365 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 27 Aug 2025 03:42:22 -0700 Subject: [PATCH 1240/1292] riscv: kexec: Initialize kexec_buf struct The kexec_buf structure was previously declared without initialization. commit bf454ec31add ("kexec_file: allow to place kexec_buf randomly") added a field that is always read but not consistently populated by all architectures. This un-initialized field will contain garbage. This is also triggering a UBSAN warning when the uninitialized data was accessed: ------------[ cut here ]------------ UBSAN: invalid-load in ./include/linux/kexec.h:210:10 load of value 252 is not a valid value for type '_Bool' Zero-initializing kexec_buf at declaration ensures all fields are cleanly set, preventing future instances of uninitialized memory being used. Fixes: bf454ec31add ("kexec_file: allow to place kexec_buf randomly") Signed-off-by: Breno Leitao Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250827-kbuf_all-v1-2-1df9882bb01a@debian.org Signed-off-by: Paul Walmsley --- arch/riscv/kernel/kexec_elf.c | 4 ++-- arch/riscv/kernel/kexec_image.c | 2 +- arch/riscv/kernel/machine_kexec_file.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/kernel/kexec_elf.c b/arch/riscv/kernel/kexec_elf.c index 56444c7bd34eb1..531d348db84d73 100644 --- a/arch/riscv/kernel/kexec_elf.c +++ b/arch/riscv/kernel/kexec_elf.c @@ -28,7 +28,7 @@ static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, int i; int ret = 0; size_t size; - struct kexec_buf kbuf; + struct kexec_buf kbuf = {}; const struct elf_phdr *phdr; kbuf.image = image; @@ -66,7 +66,7 @@ static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, { int i; int ret; - struct kexec_buf kbuf; + struct kexec_buf kbuf = {}; const struct elf_phdr *phdr; unsigned long lowest_paddr = ULONG_MAX; unsigned long lowest_vaddr = ULONG_MAX; diff --git a/arch/riscv/kernel/kexec_image.c b/arch/riscv/kernel/kexec_image.c index 26a81774a78a36..8f2eb900910b14 100644 --- a/arch/riscv/kernel/kexec_image.c +++ b/arch/riscv/kernel/kexec_image.c @@ -41,7 +41,7 @@ static void *image_load(struct kimage *image, struct riscv_image_header *h; u64 flags; bool be_image, be_kernel; - struct kexec_buf kbuf; + struct kexec_buf kbuf = {}; int ret; /* Check Image header */ diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c index e36104af2e247f..b9eb41b0a97519 100644 --- a/arch/riscv/kernel/machine_kexec_file.c +++ b/arch/riscv/kernel/machine_kexec_file.c @@ -261,7 +261,7 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start, int ret; void *fdt; unsigned long initrd_pbase = 0UL; - struct kexec_buf kbuf; + struct kexec_buf kbuf = {}; char *modified_cmdline = NULL; kbuf.image = image; From fef7ded169ed7e133612f90a032dc2af1ce19bef Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Wed, 3 Sep 2025 18:53:08 +0000 Subject: [PATCH 1241/1292] riscv: Fix sparse warning in __get_user_error() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to assign 0 to x without an appropriate cast which results in sparse complaining when x is a pointer: >> block/ioctl.c:72:39: sparse: sparse: Using plain integer as NULL pointer So fix this by casting 0 to the correct type of x. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508062321.gHv4kvuY-lkp@intel.com/ Fixes: f6bff7827a48 ("riscv: uaccess: use 'asm_goto_output' for get_user()") Cc: stable@vger.kernel.org Signed-off-by: Alexandre Ghiti Reviewed-by: ClĆ©ment LĆ©ger Reviewed-by: Cyril Bur Link: https://lore.kernel.org/r/20250903-dev-alex-sparse_warnings_v1-v1-1-7e6350beb700@rivosinc.com Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index 22e3f52a763d1c..551e7490737eff 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -209,7 +209,7 @@ do { \ err = 0; \ break; \ __gu_failed: \ - x = 0; \ + x = (__typeof__(x))0; \ err = -EFAULT; \ } while (0) From a03ee11b8f850bd008226c6d392da24163dfb56e Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Wed, 3 Sep 2025 18:53:09 +0000 Subject: [PATCH 1242/1292] riscv: Fix sparse warning about different address spaces We did not propagate the __user attribute of the pointers in __get_kernel_nofault() and __put_kernel_nofault(), which results in sparse complaining: >> mm/maccess.c:41:17: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] __user *from @@ got unsigned long long [usertype] * @@ mm/maccess.c:41:17: sparse: expected void const [noderef] __user *from mm/maccess.c:41:17: sparse: got unsigned long long [usertype] * So fix this by correctly casting those pointers. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508161713.RWu30Lv1-lkp@intel.com/ Suggested-by: Al Viro Fixes: f6bff7827a48 ("riscv: uaccess: use 'asm_goto_output' for get_user()") Cc: stable@vger.kernel.org Signed-off-by: Alexandre Ghiti Reviewed-by: Cyril Bur Link: https://lore.kernel.org/r/20250903-dev-alex-sparse_warnings_v1-v1-2-7e6350beb700@rivosinc.com Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/uaccess.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index 551e7490737eff..f5f4f7f85543f2 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -438,10 +438,10 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n) } #define __get_kernel_nofault(dst, src, type, err_label) \ - __get_user_nocheck(*((type *)(dst)), (type *)(src), err_label) + __get_user_nocheck(*((type *)(dst)), (__force __user type *)(src), err_label) #define __put_kernel_nofault(dst, src, type, err_label) \ - __put_user_nocheck(*((type *)(src)), (type *)(dst), err_label) + __put_user_nocheck(*((type *)(src)), (__force __user type *)(dst), err_label) static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len) { From fdd9ae23bb989fa9ed1beebba7d3e0c82c7c81ae Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Sep 2025 15:43:50 +0200 Subject: [PATCH 1243/1292] PM: core: Annotate loops walking device links as _srcu Since SRCU is used for the protection of device link lists, the loops over device link lists in multiple places in drivers/base/power/main.c and in pm_runtime_get_suppliers() should be annotated as _srcu rather than as _rcu which is the case currently. Change the annotations accordingly. Signed-off-by: Rafael J. Wysocki Reviewed-by: Ulf Hansson Acked-by: Greg Kroah-Hartman Link: https://patch.msgid.link/2393512.ElGaqSPkdT@rafael.j.wysocki --- drivers/base/power/main.c | 18 +++++++++--------- drivers/base/power/runtime.c | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2ea6e05e6ec90e..2fa53896db82e2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -40,8 +40,8 @@ typedef int (*pm_callback_t)(struct device *); -#define list_for_each_entry_rcu_locked(pos, head, member) \ - list_for_each_entry_rcu(pos, head, member, \ +#define list_for_each_entry_srcu_locked(pos, head, member) \ + list_for_each_entry_srcu(pos, head, member, \ device_links_read_lock_held()) /* @@ -281,7 +281,7 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async) * callbacks freeing the link objects for the links in the list we're * walking. */ - list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) + list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_wait(link->supplier, async); @@ -338,7 +338,7 @@ static void dpm_wait_for_consumers(struct device *dev, bool async) * continue instead of trying to continue in parallel with its * unregistration). */ - list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node) + list_for_each_entry_srcu_locked(link, &dev->links.consumers, s_node) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_wait(link->consumer, async); @@ -675,7 +675,7 @@ static void dpm_async_resume_subordinate(struct device *dev, async_func_t func) idx = device_links_read_lock(); /* Start processing the device's "async" consumers. */ - list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node) + list_for_each_entry_srcu_locked(link, &dev->links.consumers, s_node) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_async_with_cleanup(link->consumer, func); @@ -1330,7 +1330,7 @@ static void dpm_async_suspend_superior(struct device *dev, async_func_t func) idx = device_links_read_lock(); /* Start processing the device's "async" suppliers. */ - list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) + list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_async_with_cleanup(link->supplier, func); @@ -1384,7 +1384,7 @@ static void dpm_superior_set_must_resume(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) + list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) link->supplier->power.must_resume = true; device_links_read_unlock(idx); @@ -1813,7 +1813,7 @@ static void dpm_clear_superiors_direct_complete(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) { + list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) { spin_lock_irq(&link->supplier->power.lock); link->supplier->power.direct_complete = false; spin_unlock_irq(&link->supplier->power.lock); @@ -2065,7 +2065,7 @@ static bool device_prepare_smart_suspend(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) { + list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) { if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) continue; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3e84dc4122defe..8c23a11e801764 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1903,8 +1903,8 @@ void pm_runtime_get_suppliers(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, - device_links_read_lock_held()) + list_for_each_entry_srcu(link, &dev->links.suppliers, c_node, + device_links_read_lock_held()) if (device_link_test(link, DL_FLAG_PM_RUNTIME)) { link->supplier_preactivated = true; pm_runtime_get_sync(link->supplier); From 3ce3f569991347d2085925041f4932232da43bcf Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Sep 2025 15:45:14 +0200 Subject: [PATCH 1244/1292] PM: core: Add two macros for walking device links Add separate macros for walking links to suppliers and consumers of a device to help device links users to avoid exposing the internals of struct dev_links_info in their code and possible coding mistakes related to that. Accordingly, use the new macros to replace open-coded device links list walks in the core power management code. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Ulf Hansson Acked-by: Greg Kroah-Hartman Link: https://patch.msgid.link/1944671.tdWV9SEqCh@rafael.j.wysocki --- drivers/base/base.h | 8 ++++++++ drivers/base/power/main.c | 18 +++++++----------- drivers/base/power/runtime.c | 3 +-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index 123031a757d916..700aecd22fd34a 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -251,6 +251,14 @@ void device_links_unbind_consumers(struct device *dev); void fw_devlink_drivers_done(void); void fw_devlink_probing_done(void); +#define dev_for_each_link_to_supplier(__link, __dev) \ + list_for_each_entry_srcu(__link, &(__dev)->links.suppliers, c_node, \ + device_links_read_lock_held()) + +#define dev_for_each_link_to_consumer(__link, __dev) \ + list_for_each_entry_srcu(__link, &(__dev)->links.consumers, s_node, \ + device_links_read_lock_held()) + /* device pm support */ void device_pm_move_to_tail(struct device *dev); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2fa53896db82e2..e3a7f25bf8d39b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -40,10 +40,6 @@ typedef int (*pm_callback_t)(struct device *); -#define list_for_each_entry_srcu_locked(pos, head, member) \ - list_for_each_entry_srcu(pos, head, member, \ - device_links_read_lock_held()) - /* * The entries in the dpm_list list are in a depth first order, simply * because children are guaranteed to be discovered after parents, and @@ -281,7 +277,7 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async) * callbacks freeing the link objects for the links in the list we're * walking. */ - list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) + dev_for_each_link_to_supplier(link, dev) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_wait(link->supplier, async); @@ -338,7 +334,7 @@ static void dpm_wait_for_consumers(struct device *dev, bool async) * continue instead of trying to continue in parallel with its * unregistration). */ - list_for_each_entry_srcu_locked(link, &dev->links.consumers, s_node) + dev_for_each_link_to_consumer(link, dev) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_wait(link->consumer, async); @@ -675,7 +671,7 @@ static void dpm_async_resume_subordinate(struct device *dev, async_func_t func) idx = device_links_read_lock(); /* Start processing the device's "async" consumers. */ - list_for_each_entry_srcu_locked(link, &dev->links.consumers, s_node) + dev_for_each_link_to_consumer(link, dev) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_async_with_cleanup(link->consumer, func); @@ -1330,7 +1326,7 @@ static void dpm_async_suspend_superior(struct device *dev, async_func_t func) idx = device_links_read_lock(); /* Start processing the device's "async" suppliers. */ - list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) + dev_for_each_link_to_supplier(link, dev) if (READ_ONCE(link->status) != DL_STATE_DORMANT) dpm_async_with_cleanup(link->supplier, func); @@ -1384,7 +1380,7 @@ static void dpm_superior_set_must_resume(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) + dev_for_each_link_to_supplier(link, dev) link->supplier->power.must_resume = true; device_links_read_unlock(idx); @@ -1813,7 +1809,7 @@ static void dpm_clear_superiors_direct_complete(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) { + dev_for_each_link_to_supplier(link, dev) { spin_lock_irq(&link->supplier->power.lock); link->supplier->power.direct_complete = false; spin_unlock_irq(&link->supplier->power.lock); @@ -2065,7 +2061,7 @@ static bool device_prepare_smart_suspend(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_srcu_locked(link, &dev->links.suppliers, c_node) { + dev_for_each_link_to_supplier(link, dev) { if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) continue; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 8c23a11e801764..7420b9851fe0fd 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1903,8 +1903,7 @@ void pm_runtime_get_suppliers(struct device *dev) idx = device_links_read_lock(); - list_for_each_entry_srcu(link, &dev->links.suppliers, c_node, - device_links_read_lock_held()) + dev_for_each_link_to_supplier(link, dev) if (device_link_test(link, DL_FLAG_PM_RUNTIME)) { link->supplier_preactivated = true; pm_runtime_get_sync(link->supplier); From fc33bf0e097c6834646b98a7b3da0ae5b617f0f9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Aug 2025 18:58:23 +0300 Subject: [PATCH 1245/1292] PM / devfreq: mtk-cci: Fix potential error pointer dereference in probe() The drv->sram_reg pointer could be set to ERR_PTR(-EPROBE_DEFER) which would lead to a error pointer dereference. Use IS_ERR_OR_NULL() to check that the pointer is valid. Fixes: e09bd5757b52 ("PM / devfreq: mtk-cci: Handle sram regulator probe deferral") Signed-off-by: Dan Carpenter Signed-off-by: Chanwoo Choi Link: https://patchwork.kernel.org/project/linux-pm/patch/aJTNHz8kk8s6Q2os@stanley.mountain/ --- drivers/devfreq/mtk-cci-devfreq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-cci-devfreq.c index 22fe9e631f8aaf..5730076846e1be 100644 --- a/drivers/devfreq/mtk-cci-devfreq.c +++ b/drivers/devfreq/mtk-cci-devfreq.c @@ -386,7 +386,8 @@ static int mtk_ccifreq_probe(struct platform_device *pdev) out_free_resources: if (regulator_is_enabled(drv->proc_reg)) regulator_disable(drv->proc_reg); - if (drv->sram_reg && regulator_is_enabled(drv->sram_reg)) + if (!IS_ERR_OR_NULL(drv->sram_reg) && + regulator_is_enabled(drv->sram_reg)) regulator_disable(drv->sram_reg); return ret; From 400f60b27415f927f8964dd32d1f5baa53782e5f Mon Sep 17 00:00:00 2001 From: Chandra Mohan Sundar Date: Sat, 6 Sep 2025 21:51:54 +0530 Subject: [PATCH 1246/1292] ALSA: cs4281: Send the PCM period elapsed notification properly As part of spin lock code cleanup using guard(), a new variable (period_elapsed) was introduced. However this variable is never set, causing period elapsed notification to be not sent. Set the value of period_elapsed appropiately. This issue was reported by static coverity analyzer. Fixes: 7a5127c2c8a5a ("ALSA: cs4281: Use guard() for spin locks") Signed-off-by: Chandra Mohan Sundar Link: https://patch.msgid.link/20250906162158.564899-1-chandramohan.explore@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/cs4281.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index c519fb9cdd1ee1..d00b2c9fb1e38c 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1752,6 +1752,7 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id) chip->spurious_dtc_irq++; continue; } + period_elapsed = true; } if (period_elapsed) snd_pcm_period_elapsed(cdma->substream); From cbd676874e64a2122edd03ba6a2406b24779df05 Mon Sep 17 00:00:00 2001 From: "Geoffrey D. Bennett" Date: Fri, 5 Sep 2025 01:23:51 +0930 Subject: [PATCH 1247/1292] ALSA: scarlett2: Add Vocaster speaker/headphone mute controls Add support for the speaker and headphone mute controls on Focusrite Vocaster interfaces. Unlike other Focusrite interfaces, these mute controls are per-output, not per-channel. Signed-off-by: Geoffrey D. Bennett Link: https://patch.msgid.link/aLm2Dy6+O/eLTGVn@m.b4.vu Signed-off-by: Takashi Iwai --- sound/usb/mixer_scarlett2.c | 97 ++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index e762d6110b1aba..f2446bf3982c66 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -10,8 +10,9 @@ * - Solo/2i2/4i4 Gen 4 * - Clarett 2Pre/4Pre/8Pre USB * - Clarett+ 2Pre/4Pre/8Pre + * - Vocaster One/Two * - * Copyright (c) 2018-2024 by Geoffrey D. Bennett + * Copyright (c) 2018-2025 by Geoffrey D. Bennett * Copyright (c) 2020-2021 by Vladimir Sadovnikov * Copyright (c) 2022 by Christian Colglazier * @@ -75,6 +76,9 @@ * to many LinuxMusicians people and to Focusrite for hardware * donations). * + * Support for Vocaster One and Two added in Mar 2024 (thanks to many + * LinuxMusicians people and to Focusrite for hardware donations). + * * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes * - mixer-matrix gain stages @@ -364,6 +368,21 @@ static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { "Mute Playback Switch", "Dim Playback Switch" }; +/* Vocaster One speaker/headphone mute names */ +static const char *const vocaster_one_sp_hp_mute_names[] = { + "Speaker Mute Playback Switch", + "Headphones Mute Playback Switch", + NULL +}; + +/* Vocaster Two speaker/headphone mute names */ +static const char *const vocaster_two_sp_hp_mute_names[] = { + "Speaker Mute Playback Switch", + "Headphones 1 Mute Playback Switch", + "Headphones 2 Mute Playback Switch", + NULL +}; + /* The autogain_status is set based on the autogain_switch and * raw_autogain_status values. * @@ -547,6 +566,7 @@ enum { SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN, SCARLETT2_CONFIG_BLUETOOTH_VOLUME, SCARLETT2_CONFIG_SPDIF_MODE, + SCARLETT2_CONFIG_SP_HP_MUTE, SCARLETT2_CONFIG_COUNT }; @@ -814,6 +834,9 @@ static const struct scarlett2_config_set scarlett2_config_set_vocaster = { [SCARLETT2_CONFIG_BLUETOOTH_VOLUME] = { .offset = 0xbf, .size = 8, .activate = 28 }, + + [SCARLETT2_CONFIG_SP_HP_MUTE] = { + .offset = 0xab, .size = 8, .activate = 10 }, } }; @@ -1177,6 +1200,9 @@ struct scarlett2_device_info { /* additional description for the line out volume controls */ const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; + /* Vocaster speaker/headphone mute control names */ + const char * const *sp_hp_mute_names; + /* number of sources/destinations of each port type */ const int port_count[SCARLETT2_PORT_TYPE_COUNT][SCARLETT2_PORT_DIRNS]; @@ -1249,6 +1275,7 @@ struct scarlett2_data { u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; + u8 sp_hp_mute; u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; u8 dsp_switch[SCARLETT2_DSP_SWITCH_MAX]; s32 compressor_values[SCARLETT2_COMPRESSOR_CTLS_MAX]; @@ -1791,6 +1818,7 @@ static const struct scarlett2_device_info vocaster_one_info = { .peq_flt_total_count = 4, .mute_input_count = 1, .gain_input_count = 1, + .sp_hp_mute_names = vocaster_one_sp_hp_mute_names, .port_count = { [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, @@ -1835,6 +1863,7 @@ static const struct scarlett2_device_info vocaster_two_info = { .mute_input_count = 2, .gain_input_count = 2, .has_bluetooth = 1, + .sp_hp_mute_names = vocaster_two_sp_hp_mute_names, .port_count = { [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, @@ -6293,6 +6322,61 @@ static const struct snd_kcontrol_new scarlett2_dim_mute_ctl = { .put = scarlett2_dim_mute_ctl_put }; +/*** Vocaster Speaker/Headphone Mute Controls ***/ + +static int scarlett2_sp_hp_mute_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = + !!(private->sp_hp_mute & (1 << elem->control)); + + return 0; +} + +static int scarlett2_sp_hp_mute_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int index = elem->control; + int val, err; + + guard(mutex)(&private->data_mutex); + + if (private->hwdep_in_use) + return -EBUSY; + + val = private->sp_hp_mute; + + if (ucontrol->value.integer.value[0]) + val |= (1 << index); + else + val &= ~(1 << index); + + if (val == private->sp_hp_mute) + return 0; + + private->sp_hp_mute = val; + + /* Send change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SP_HP_MUTE, + 0, val); + + return err < 0 ? err : 1; +} + +static const struct snd_kcontrol_new scarlett2_sp_hp_mute_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_sp_hp_mute_ctl_get, + .put = scarlett2_sp_hp_mute_ctl_put +}; + /*** Create the analogue output controls ***/ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) @@ -6325,6 +6409,17 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) return err; } + /* Add Vocaster speaker/headphone mute controls */ + if (private->info->sp_hp_mute_names) + for (i = 0; private->info->sp_hp_mute_names[i]; i++) { + err = scarlett2_add_new_ctl( + mixer, &scarlett2_sp_hp_mute_ctl, + i, 1, private->info->sp_hp_mute_names[i], + NULL); + if (err < 0) + return err; + } + /* Remaining controls are only applicable if the device * has per-channel line-out volume controls. */ From 76eeb9b8de9880ca38696b2fb56ac45ac0a25c6c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 7 Sep 2025 14:22:57 -0700 Subject: [PATCH 1248/1292] Linux 6.17-rc5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b9c66191325044..cf37b94078211c 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Baby Opossum Posse # *DOCUMENTATION* From 2c92e2fbe9e22cefdae87d8a0d654691ee4c1957 Mon Sep 17 00:00:00 2001 From: Joris Verhaegen Date: Fri, 5 Sep 2025 10:12:54 +0100 Subject: [PATCH 1249/1292] ALSA: compress_offload: Add 64-bit safe timestamp infrastructure The copied_total field in struct snd_compr_tstamp is a 32-bit value that can overflow on long-running high-bitrate streams, leading to incorrect calculations for buffer availablility. This patch adds a 64-bit safe timestamping mechanism. A new UAPI struct, snd_compr_tstamp64, is added which uses 64-bit types for byte counters. The relevant ops structures across the ASoC and core compress code are updated to use this new struct. ASoC drivers are updated to use u64 counters. Internal timestamps being u64 now, a compatibility function is added to convert the 64-bit timestamp back to the 32-bit format for legacy ioctl callers. Reviewed-by: Miller Liang Tested-by: Joris Verhaegen Signed-off-by: Joris Verhaegen Reviewed-by: Srinivas Kandagatla Reviewed-by: Charles Keepax Acked-by: Mark Brown Acked-by: Vinod Koul Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250905091301.2711705-2-verhaegen@google.com --- include/sound/compress_driver.h | 2 +- include/sound/soc-component.h | 4 +- include/sound/soc-dai.h | 7 +-- include/uapi/sound/compress_offload.h | 19 +++++++ sound/core/compress_offload.c | 52 +++++++++++++------ sound/soc/codecs/wm_adsp.c | 4 +- sound/soc/codecs/wm_adsp.h | 2 +- .../intel/atom/sst-mfld-platform-compress.c | 12 +++-- sound/soc/intel/atom/sst-mfld-platform.h | 2 +- sound/soc/intel/atom/sst/sst_drv_interface.c | 9 ++-- sound/soc/intel/avs/probes.c | 2 +- sound/soc/qcom/qdsp6/q6apm-dai.c | 26 ++++++---- sound/soc/qcom/qdsp6/q6asm-dai.c | 26 ++++++---- sound/soc/soc-component.c | 2 +- sound/soc/soc-compress.c | 2 +- sound/soc/soc-dai.c | 2 +- sound/soc/sof/amd/acp-probes.c | 2 +- sound/soc/sof/compress.c | 2 +- sound/soc/sof/intel/hda-probes.c | 2 +- sound/soc/sof/sof-client-probes.c | 2 +- sound/soc/sof/sof-client-probes.h | 4 +- sound/soc/sprd/sprd-pcm-compress.c | 6 +-- sound/soc/sprd/sprd-pcm-dma.h | 4 +- sound/soc/uniphier/aio-compress.c | 2 +- 24 files changed, 125 insertions(+), 72 deletions(-) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index b55c9eeb2b54ca..9e3d801e45ecd5 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -161,7 +161,7 @@ struct snd_compr_ops { struct snd_compr_metadata *metadata); int (*trigger)(struct snd_compr_stream *stream, int cmd); int (*pointer)(struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp); + struct snd_compr_tstamp64 *tstamp); int (*copy)(struct snd_compr_stream *stream, char __user *buf, size_t count); int (*mmap)(struct snd_compr_stream *stream, diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 2caa807c6249c4..cdb536c4ab2be7 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -47,7 +47,7 @@ struct snd_compress_ops { struct snd_compr_stream *stream, int cmd); int (*pointer)(struct snd_soc_component *component, struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp); + struct snd_compr_tstamp64 *tstamp); int (*copy)(struct snd_soc_component *component, struct snd_compr_stream *stream, char __user *buf, size_t count); @@ -498,7 +498,7 @@ int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_compr_codec_caps *codec); int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes); int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp); + struct snd_compr_tstamp64 *tstamp); int snd_soc_component_compr_copy(struct snd_compr_stream *cstream, char __user *buf, size_t count); int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream, diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 166c29557e9d7c..224396927aef35 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -256,7 +256,7 @@ int snd_soc_dai_compr_ack(struct snd_soc_dai *dai, size_t bytes); int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp); + struct snd_compr_tstamp64 *tstamp); int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata); @@ -383,8 +383,9 @@ struct snd_soc_cdai_ops { struct snd_compr_metadata *, struct snd_soc_dai *); int (*trigger)(struct snd_compr_stream *, int, struct snd_soc_dai *); - int (*pointer)(struct snd_compr_stream *, - struct snd_compr_tstamp *, struct snd_soc_dai *); + int (*pointer)(struct snd_compr_stream *stream, + struct snd_compr_tstamp64 *tstamp, + struct snd_soc_dai *dai); int (*ack)(struct snd_compr_stream *, size_t, struct snd_soc_dai *); }; diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index d62eb93af0edb7..abd0ea3f86eedc 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -56,6 +56,25 @@ struct snd_compr_tstamp { __u32 sampling_rate; } __attribute__((packed, aligned(4))); +/** + * struct snd_compr_tstamp64 - timestamp descriptor with fields in 64 bit + * @byte_offset: Byte offset in ring buffer to DSP + * @copied_total: Total number of bytes copied from/to ring buffer to/by DSP + * @pcm_frames: Frames decoded or encoded by DSP. This field will evolve by + * large steps and should only be used to monitor encoding/decoding + * progress. It shall not be used for timing estimates. + * @pcm_io_frames: Frames rendered or received by DSP into a mixer or an audio + * output/input. This field should be used for A/V sync or time estimates. + * @sampling_rate: sampling rate of audio + */ +struct snd_compr_tstamp64 { + __u32 byte_offset; + __u64 copied_total; + __u64 pcm_frames; + __u64 pcm_io_frames; + __u32 sampling_rate; +} __attribute__((packed, aligned(4))); + /** * struct snd_compr_avail - avail descriptor * @avail: Number of bytes available in ring buffer for writing/reading diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index a66f258cafaa87..d3164aa07158dc 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -176,14 +176,25 @@ static int snd_compr_free(struct inode *inode, struct file *f) return 0; } +static void +snd_compr_tstamp32_from_64(struct snd_compr_tstamp *tstamp32, + const struct snd_compr_tstamp64 *tstamp64) +{ + tstamp32->byte_offset = tstamp64->byte_offset; + tstamp32->copied_total = (u32)tstamp64->copied_total; + tstamp32->pcm_frames = (u32)tstamp64->pcm_frames; + tstamp32->pcm_io_frames = (u32)tstamp64->pcm_io_frames; + tstamp32->sampling_rate = tstamp64->sampling_rate; +} + static int snd_compr_update_tstamp(struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { if (!stream->ops->pointer) return -ENOTSUPP; stream->ops->pointer(stream, tstamp); - pr_debug("dsp consumed till %d total %d bytes\n", - tstamp->byte_offset, tstamp->copied_total); + pr_debug("dsp consumed till %u total %llu bytes\n", tstamp->byte_offset, + tstamp->copied_total); if (stream->direction == SND_COMPRESS_PLAYBACK) stream->runtime->total_bytes_transferred = tstamp->copied_total; else @@ -194,8 +205,11 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, struct snd_compr_avail *avail) { + struct snd_compr_tstamp64 tstamp64 = { 0 }; + memset(avail, 0, sizeof(*avail)); - snd_compr_update_tstamp(stream, &avail->tstamp); + snd_compr_update_tstamp(stream, &tstamp64); + snd_compr_tstamp32_from_64(&avail->tstamp, &tstamp64); /* Still need to return avail even if tstamp can't be filled in */ if (stream->runtime->total_bytes_available == 0 && @@ -204,9 +218,9 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, pr_debug("detected init and someone forgot to do a write\n"); return stream->runtime->buffer_size; } - pr_debug("app wrote %lld, DSP consumed %lld\n", - stream->runtime->total_bytes_available, - stream->runtime->total_bytes_transferred); + pr_debug("app wrote %llu, DSP consumed %llu\n", + stream->runtime->total_bytes_available, + stream->runtime->total_bytes_transferred); if (stream->runtime->total_bytes_available == stream->runtime->total_bytes_transferred) { if (stream->direction == SND_COMPRESS_PLAYBACK) { @@ -223,7 +237,7 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, if (stream->direction == SND_COMPRESS_PLAYBACK) avail->avail = stream->runtime->buffer_size - avail->avail; - pr_debug("ret avail as %lld\n", avail->avail); + pr_debug("ret avail as %llu\n", avail->avail); return avail->avail; } @@ -274,8 +288,7 @@ static int snd_compr_write_data(struct snd_compr_stream *stream, (app_pointer * runtime->buffer_size); dstn = runtime->buffer + app_pointer; - pr_debug("copying %ld at %lld\n", - (unsigned long)count, app_pointer); + pr_debug("copying %lu at %llu\n", (unsigned long)count, app_pointer); if (count < runtime->buffer_size - app_pointer) { if (copy_from_user(dstn, buf, count)) return -EFAULT; @@ -318,7 +331,7 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf, } avail = snd_compr_get_avail(stream); - pr_debug("avail returned %ld\n", (unsigned long)avail); + pr_debug("avail returned %lu\n", (unsigned long)avail); /* calculate how much we can write to buffer */ if (avail > count) avail = count; @@ -374,7 +387,7 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, } avail = snd_compr_get_avail(stream); - pr_debug("avail returned %ld\n", (unsigned long)avail); + pr_debug("avail returned %lu\n", (unsigned long)avail); /* calculate how much we can read from buffer */ if (avail > count) avail = count; @@ -443,7 +456,7 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) #endif avail = snd_compr_get_avail(stream); - pr_debug("avail is %ld\n", (unsigned long)avail); + pr_debug("avail is %lu\n", (unsigned long)avail); /* check if we have at least one fragment to fill */ switch (runtime->state) { case SNDRV_PCM_STATE_DRAINING: @@ -726,13 +739,18 @@ snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg) static inline int snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) { - struct snd_compr_tstamp tstamp = {0}; + struct snd_compr_tstamp64 tstamp64 = { 0 }; + struct snd_compr_tstamp tstamp32 = { 0 }; int ret; - ret = snd_compr_update_tstamp(stream, &tstamp); - if (ret == 0) + ret = snd_compr_update_tstamp(stream, &tstamp64); + if (ret == 0) { + snd_compr_tstamp32_from_64(&tstamp32, &tstamp64); ret = copy_to_user((struct snd_compr_tstamp __user *)arg, - &tstamp, sizeof(tstamp)) ? -EFAULT : 0; + &tstamp32, sizeof(tstamp32)) ? + -EFAULT : + 0; + } return ret; } diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 8a1d5cc75d6c23..f197034fd594fa 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -173,7 +173,7 @@ struct wm_adsp_compr { struct snd_compressed_buffer size; u32 *raw_buf; - unsigned int copied_total; + u64 copied_total; unsigned int sample_rate; @@ -1860,7 +1860,7 @@ static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf) int wm_adsp_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct wm_adsp_compr *compr = stream->runtime->private_data; struct wm_adsp *dsp = compr->dsp; diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 25210d404bf141..8035fda71f8db4 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -131,7 +131,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); int wm_adsp_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp); + struct snd_compr_tstamp64 *tstamp); int wm_adsp_compr_copy(struct snd_soc_component *component, struct snd_compr_stream *stream, char __user *buf, size_t count); diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c index 89c9c5ad6b2193..9dfb0a814b941e 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-compress.c +++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "sst-mfld-platform.h" /* compress stream operations */ @@ -202,15 +203,16 @@ static int sst_platform_compr_trigger(struct snd_soc_component *component, static int sst_platform_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct sst_runtime_stream *stream; + u64 temp_copied_total = tstamp->copied_total; - stream = cstream->runtime->private_data; + stream = cstream->runtime->private_data; stream->compr_ops->tstamp(sst->dev, stream->id, tstamp); - tstamp->byte_offset = tstamp->copied_total % - (u32)cstream->runtime->buffer_size; - pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); + tstamp->byte_offset = + do_div(temp_copied_total, cstream->runtime->buffer_size); + pr_debug("calc bytes offset/copied bytes as %u\n", tstamp->byte_offset); return 0; } diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 8b5777d3229a7c..a0e33f7f01c517 100644 --- a/sound/soc/intel/atom/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h @@ -105,7 +105,7 @@ struct compress_sst_ops { int (*stream_pause_release)(struct device *dev, unsigned int str_id); int (*tstamp)(struct device *dev, unsigned int str_id, - struct snd_compr_tstamp *tstamp); + struct snd_compr_tstamp64 *tstamp); int (*ack)(struct device *dev, unsigned int str_id, unsigned long bytes); int (*close)(struct device *dev, unsigned int str_id); diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 8bb27f86eb6536..2646c4632ca1ca 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -326,7 +326,7 @@ static int sst_cdev_stream_partial_drain(struct device *dev, } static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_sst_tstamp fw_tstamp = {0,}; struct stream_info *stream; @@ -349,10 +349,11 @@ static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, (u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24)); tstamp->sampling_rate = fw_tstamp.sampling_frequency; - dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); - dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n", + dev_dbg(dev, "PCM = %llu\n", tstamp->pcm_io_frames); + dev_dbg(dev, + "Ptr Query on strid = %d copied_total %llu, decodec %llu\n", str_id, tstamp->copied_total, tstamp->pcm_frames); - dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames); + dev_dbg(dev, "rendered %llu\n", tstamp->pcm_io_frames); return 0; } diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index a42736b9aa55b7..b5b4b0754b716a 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -213,7 +213,7 @@ static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, } static int avs_probe_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai) + struct snd_compr_tstamp64 *tstamp, struct snd_soc_dai *dai) { struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); struct snd_soc_pcm_stream *pstream; diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index 2cd522108221a2..09da26f712a6ad 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -65,9 +66,9 @@ struct q6apm_dai_rtd { unsigned int pcm_size; unsigned int pcm_count; unsigned int periods; - unsigned int bytes_sent; - unsigned int bytes_received; - unsigned int copied_total; + uint64_t bytes_sent; + uint64_t bytes_received; + uint64_t copied_total; uint16_t bits_per_sample; snd_pcm_uframes_t queue_ptr; bool next_track; @@ -575,15 +576,17 @@ static int q6apm_dai_compr_get_codec_caps(struct snd_soc_component *component, static int q6apm_dai_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_compr_runtime *runtime = stream->runtime; struct q6apm_dai_rtd *prtd = runtime->private_data; unsigned long flags; + uint64_t temp_copied_total; spin_lock_irqsave(&prtd->lock, flags); tstamp->copied_total = prtd->copied_total; - tstamp->byte_offset = prtd->copied_total % prtd->pcm_size; + temp_copied_total = tstamp->copied_total; + tstamp->byte_offset = do_div(temp_copied_total, prtd->pcm_size); spin_unlock_irqrestore(&prtd->lock, flags); return 0; @@ -760,21 +763,24 @@ static int q6apm_compr_copy(struct snd_soc_component *component, size_t copy; u32 wflags = 0; u32 app_pointer; - u32 bytes_received; + uint64_t bytes_received; + uint64_t temp_bytes_received; uint32_t bytes_to_write; - int avail, bytes_in_flight = 0; + uint64_t avail, bytes_in_flight = 0; bytes_received = prtd->bytes_received; + temp_bytes_received = bytes_received; /** * Make sure that next track data pointer is aligned at 32 bit boundary * This is a Mandatory requirement from DSP data buffers alignment */ - if (prtd->next_track) + if (prtd->next_track) { bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count); + temp_bytes_received = bytes_received; + } - app_pointer = bytes_received/prtd->pcm_size; - app_pointer = bytes_received - (app_pointer * prtd->pcm_size); + app_pointer = do_div(temp_bytes_received, prtd->pcm_size); dstn = prtd->dma_buffer.area + app_pointer; if (count < prtd->pcm_size - app_pointer) { diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index a400c9a31fead5..b616ce316d2f13 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -59,9 +60,9 @@ struct q6asm_dai_rtd { unsigned int pcm_count; unsigned int pcm_irq_pos; /* IRQ position */ unsigned int periods; - unsigned int bytes_sent; - unsigned int bytes_received; - unsigned int copied_total; + uint64_t bytes_sent; + uint64_t bytes_received; + uint64_t copied_total; uint16_t bits_per_sample; uint16_t source; /* Encoding source bit mask */ struct audio_client *audio_client; @@ -1026,16 +1027,18 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component, static int q6asm_dai_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_compr_runtime *runtime = stream->runtime; struct q6asm_dai_rtd *prtd = runtime->private_data; unsigned long flags; + uint64_t temp_copied_total; spin_lock_irqsave(&prtd->lock, flags); tstamp->copied_total = prtd->copied_total; - tstamp->byte_offset = prtd->copied_total % prtd->pcm_size; + temp_copied_total = tstamp->copied_total; + tstamp->byte_offset = do_div(temp_copied_total, prtd->pcm_size); spin_unlock_irqrestore(&prtd->lock, flags); @@ -1050,23 +1053,26 @@ static int q6asm_compr_copy(struct snd_soc_component *component, struct q6asm_dai_rtd *prtd = runtime->private_data; unsigned long flags; u32 wflags = 0; - int avail, bytes_in_flight = 0; + uint64_t avail, bytes_in_flight = 0; void *dstn; size_t copy; u32 app_pointer; - u32 bytes_received; + uint64_t bytes_received; + uint64_t temp_bytes_received; bytes_received = prtd->bytes_received; + temp_bytes_received = bytes_received; /** * Make sure that next track data pointer is aligned at 32 bit boundary * This is a Mandatory requirement from DSP data buffers alignment */ - if (prtd->next_track) + if (prtd->next_track) { bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count); + temp_bytes_received = bytes_received; + } - app_pointer = bytes_received/prtd->pcm_size; - app_pointer = bytes_received - (app_pointer * prtd->pcm_size); + app_pointer = do_div(temp_bytes_received, prtd->pcm_size); dstn = prtd->dma_buffer.area + app_pointer; if (count < prtd->pcm_size - app_pointer) { diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 65c4950940244c..c815fd1b3fd19a 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -637,7 +637,7 @@ int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes) EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack); int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 01d1d6bee28cf6..7b81dffc6a935a 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -457,7 +457,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) } static int soc_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; int ret; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 32f46a38682b79..f231b4174b5fcb 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -774,7 +774,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack); int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { int ret = 0; diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c index 0d0f8ec4aed838..ce51ed108a47b7 100644 --- a/sound/soc/sof/amd/acp-probes.c +++ b/sound/soc/sof/amd/acp-probes.c @@ -108,7 +108,7 @@ static int acp_probes_compr_trigger(struct sof_client_dev *cdev, static int acp_probes_compr_pointer(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, + struct snd_compr_tstamp64 *tstamp, struct snd_soc_dai *dai) { struct acp_dsp_stream *stream = cstream->runtime->private_data; diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index d7b044f33d7963..90b932ae3bab2c 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -361,7 +361,7 @@ static int sof_compr_copy(struct snd_soc_component *component, static int sof_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_sof_pcm *spcm; struct snd_soc_pcm_runtime *rtd = cstream->private_data; diff --git a/sound/soc/sof/intel/hda-probes.c b/sound/soc/sof/intel/hda-probes.c index c645346c2c847c..b06933cebc4547 100644 --- a/sound/soc/sof/intel/hda-probes.c +++ b/sound/soc/sof/intel/hda-probes.c @@ -112,7 +112,7 @@ static int hda_probes_compr_trigger(struct sof_client_dev *cdev, static int hda_probes_compr_pointer(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, + struct snd_compr_tstamp64 *tstamp, struct snd_soc_dai *dai) { struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 663c0d3c314c66..1353e911501a2e 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -137,7 +137,7 @@ static int sof_probes_compr_trigger(struct snd_compr_stream *cstream, int cmd, } static int sof_probes_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, + struct snd_compr_tstamp64 *tstamp, struct snd_soc_dai *dai) { struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component); diff --git a/sound/soc/sof/sof-client-probes.h b/sound/soc/sof/sof-client-probes.h index da04d65b8d995e..8713b69cda4b22 100644 --- a/sound/soc/sof/sof-client-probes.h +++ b/sound/soc/sof/sof-client-probes.h @@ -4,7 +4,7 @@ #define __SOF_CLIENT_PROBES_H struct snd_compr_stream; -struct snd_compr_tstamp; +struct snd_compr_tstamp64; struct snd_compr_params; struct sof_client_dev; struct snd_soc_dai; @@ -24,7 +24,7 @@ struct sof_probes_host_ops { int (*trigger)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, int cmd, struct snd_soc_dai *dai); int (*pointer)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, + struct snd_compr_tstamp64 *tstamp, struct snd_soc_dai *dai); }; diff --git a/sound/soc/sprd/sprd-pcm-compress.c b/sound/soc/sprd/sprd-pcm-compress.c index 57bd1a0728ac25..4b6ebfa5b03391 100644 --- a/sound/soc/sprd/sprd-pcm-compress.c +++ b/sound/soc/sprd/sprd-pcm-compress.c @@ -85,9 +85,9 @@ struct sprd_compr_stream { int info_size; /* Data size copied to IRAM buffer */ - int copied_total; + u64 copied_total; /* Total received data size from userspace */ - int received_total; + u64 received_total; /* Stage 0 IRAM buffer received data size */ int received_stage0; /* Stage 1 DDR buffer received data size */ @@ -513,7 +513,7 @@ static int sprd_platform_compr_trigger(struct snd_soc_component *component, static int sprd_platform_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_compr_runtime *runtime = cstream->runtime; struct sprd_compr_stream *stream = runtime->private_data; diff --git a/sound/soc/sprd/sprd-pcm-dma.h b/sound/soc/sprd/sprd-pcm-dma.h index be5e385f5e4286..c5935a1367e629 100644 --- a/sound/soc/sprd/sprd-pcm-dma.h +++ b/sound/soc/sprd/sprd-pcm-dma.h @@ -19,7 +19,7 @@ struct sprd_compr_playinfo { int total_time; int current_time; int total_data_length; - int current_data_offset; + u64 current_data_offset; }; struct sprd_compr_params { @@ -46,7 +46,7 @@ struct sprd_compr_ops { int (*stop)(int str_id); int (*pause)(int str_id); int (*pause_release)(int str_id); - int (*drain)(int received_total); + int (*drain)(u64 received_total); int (*set_params)(int str_id, struct sprd_compr_params *params); }; diff --git a/sound/soc/uniphier/aio-compress.c b/sound/soc/uniphier/aio-compress.c index 4a19d4908ffd64..b18af98a552b75 100644 --- a/sound/soc/uniphier/aio-compress.c +++ b/sound/soc/uniphier/aio-compress.c @@ -249,7 +249,7 @@ static int uniphier_aio_compr_trigger(struct snd_soc_component *component, static int uniphier_aio_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_compr_runtime *runtime = cstream->runtime; From f20a53974f79619d0ef6c9f17bb8693499fb6ebb Mon Sep 17 00:00:00 2001 From: Joris Verhaegen Date: Fri, 5 Sep 2025 10:12:55 +0100 Subject: [PATCH 1250/1292] ALSA: compress_offload: Add SNDRV_COMPRESS_TSTAMP64 ioctl The previous patch introduced the internal infrastructure for handling 64-bit timestamps. This patch exposes this capability to user-space. Define the new ioctl command SNDRV_COMPRESS_TSTAMP64, which allows applications to fetch the overflow-safe struct snd_compr_tstamp64. The ioctl dispatch table is updated to handle the new command by calling a new snd_compr_tstamp64 handler, while the legacy path is renamed to snd_compr_tstamp32 for clarity. This patch bumps the SNDRV_COMPRESS_VERSION to 0.4.0. Reviewed-by: Miller Liang Tested-by: Joris Verhaegen Signed-off-by: Joris Verhaegen Reviewed-by: Charles Keepax Acked-by: Mark Brown Acked-by: Vinod Koul Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250905091301.2711705-3-verhaegen@google.com --- include/uapi/sound/compress_offload.h | 5 +++-- sound/core/compress_offload.c | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index abd0ea3f86eedc..70b8921601f931 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -13,8 +13,7 @@ #include #include - -#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 0) +#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 4, 0) /** * struct snd_compressed_buffer - compressed buffer * @fragment_size: size of buffer fragment in bytes @@ -208,6 +207,7 @@ struct snd_compr_task_status { * Note: only codec params can be changed runtime and stream params cant be * SNDRV_COMPRESS_GET_PARAMS: Query codec params * SNDRV_COMPRESS_TSTAMP: get the current timestamp value + * SNDRV_COMPRESS_TSTAMP64: get the current timestamp value in 64 bit format * SNDRV_COMPRESS_AVAIL: get the current buffer avail value. * This also queries the tstamp properties * SNDRV_COMPRESS_PAUSE: Pause the running stream @@ -230,6 +230,7 @@ struct snd_compr_task_status { struct snd_compr_metadata) #define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x20, struct snd_compr_tstamp) #define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail) +#define SNDRV_COMPRESS_TSTAMP64 _IOR('C', 0x22, struct snd_compr_tstamp64) #define SNDRV_COMPRESS_PAUSE _IO('C', 0x30) #define SNDRV_COMPRESS_RESUME _IO('C', 0x31) #define SNDRV_COMPRESS_START _IO('C', 0x32) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index d3164aa07158dc..445220fdb6a085 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -736,18 +736,23 @@ snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg) return retval; } -static inline int -snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) +static inline int snd_compr_tstamp(struct snd_compr_stream *stream, + unsigned long arg, bool is_32bit) { struct snd_compr_tstamp64 tstamp64 = { 0 }; struct snd_compr_tstamp tstamp32 = { 0 }; + const void *copy_from = &tstamp64; + size_t copy_size = sizeof(tstamp64); int ret; ret = snd_compr_update_tstamp(stream, &tstamp64); if (ret == 0) { - snd_compr_tstamp32_from_64(&tstamp32, &tstamp64); - ret = copy_to_user((struct snd_compr_tstamp __user *)arg, - &tstamp32, sizeof(tstamp32)) ? + if (is_32bit) { + snd_compr_tstamp32_from_64(&tstamp32, &tstamp64); + copy_from = &tstamp32; + copy_size = sizeof(tstamp32); + } + ret = copy_to_user((void __user *)arg, copy_from, copy_size) ? -EFAULT : 0; } @@ -1327,7 +1332,9 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) switch (cmd) { case SNDRV_COMPRESS_TSTAMP: - return snd_compr_tstamp(stream, arg); + return snd_compr_tstamp(stream, arg, true); + case SNDRV_COMPRESS_TSTAMP64: + return snd_compr_tstamp(stream, arg, false); case SNDRV_COMPRESS_AVAIL: return snd_compr_ioctl_avail(stream, arg); case SNDRV_COMPRESS_PAUSE: From 86eec88c5bddf9a57bfebe701d9c7a4d439aed9b Mon Sep 17 00:00:00 2001 From: Joris Verhaegen Date: Fri, 5 Sep 2025 10:12:56 +0100 Subject: [PATCH 1251/1292] ALSA: compress_offload: Add SNDRV_COMPRESS_AVAIL64 ioctl The previous patch introduced a 64-bit timestamp ioctl (SNDRV_COMPRESS_TSTAMP64). To provide a consistent API, this patch adds a corresponding 64-bit version of the SNDRV_COMPRESS_AVAIL ioctl. A new struct snd_compr_avail64 is added to the UAPI, which includes the 64-bit timestamp. The existing ioctl implementation is refactored to handle both the 32-bit and 64-bit variants. Reviewed-by: Miller Liang Tested-by: Joris Verhaegen Signed-off-by: Joris Verhaegen Acked-by: Vinod Koul Reviewed-by: Charles Keepax Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20250905091301.2711705-4-verhaegen@google.com --- include/uapi/sound/compress_offload.h | 11 +++++++ sound/core/compress_offload.c | 43 +++++++++++++++++---------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 70b8921601f931..26f756cc2e6215 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -84,6 +84,16 @@ struct snd_compr_avail { struct snd_compr_tstamp tstamp; } __attribute__((packed, aligned(4))); +/** + * struct snd_compr_avail64 - avail descriptor with tstamp in 64 bit format + * @avail: Number of bytes available in ring buffer for writing/reading + * @tstamp: timestamp information + */ +struct snd_compr_avail64 { + __u64 avail; + struct snd_compr_tstamp64 tstamp; +} __attribute__((packed, aligned(4))); + enum snd_compr_direction { SND_COMPRESS_PLAYBACK = 0, SND_COMPRESS_CAPTURE, @@ -231,6 +241,7 @@ struct snd_compr_task_status { #define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x20, struct snd_compr_tstamp) #define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail) #define SNDRV_COMPRESS_TSTAMP64 _IOR('C', 0x22, struct snd_compr_tstamp64) +#define SNDRV_COMPRESS_AVAIL64 _IOR('C', 0x23, struct snd_compr_avail64) #define SNDRV_COMPRESS_PAUSE _IO('C', 0x30) #define SNDRV_COMPRESS_RESUME _IO('C', 0x31) #define SNDRV_COMPRESS_START _IO('C', 0x32) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 445220fdb6a085..da514fef45bca0 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -203,13 +203,10 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, } static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, - struct snd_compr_avail *avail) + struct snd_compr_avail64 *avail) { - struct snd_compr_tstamp64 tstamp64 = { 0 }; - memset(avail, 0, sizeof(*avail)); - snd_compr_update_tstamp(stream, &tstamp64); - snd_compr_tstamp32_from_64(&avail->tstamp, &tstamp64); + snd_compr_update_tstamp(stream, &avail->tstamp); /* Still need to return avail even if tstamp can't be filled in */ if (stream->runtime->total_bytes_available == 0 && @@ -237,28 +234,43 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, if (stream->direction == SND_COMPRESS_PLAYBACK) avail->avail = stream->runtime->buffer_size - avail->avail; - pr_debug("ret avail as %llu\n", avail->avail); + pr_debug("ret avail as %zu\n", (size_t)avail->avail); return avail->avail; } static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream) { - struct snd_compr_avail avail; + struct snd_compr_avail64 avail; return snd_compr_calc_avail(stream, &avail); } -static int -snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) +static void snd_compr_avail32_from_64(struct snd_compr_avail *avail32, + const struct snd_compr_avail64 *avail64) { - struct snd_compr_avail ioctl_avail; + avail32->avail = avail64->avail; + snd_compr_tstamp32_from_64(&avail32->tstamp, &avail64->tstamp); +} + +static int snd_compr_ioctl_avail(struct snd_compr_stream *stream, + unsigned long arg, bool is_32bit) +{ + struct snd_compr_avail64 ioctl_avail64; + struct snd_compr_avail ioctl_avail32; size_t avail; + const void *copy_from = &ioctl_avail64; + size_t copy_size = sizeof(ioctl_avail64); if (stream->direction == SND_COMPRESS_ACCEL) return -EBADFD; - avail = snd_compr_calc_avail(stream, &ioctl_avail); - ioctl_avail.avail = avail; + avail = snd_compr_calc_avail(stream, &ioctl_avail64); + ioctl_avail64.avail = avail; + if (is_32bit) { + snd_compr_avail32_from_64(&ioctl_avail32, &ioctl_avail64); + copy_from = &ioctl_avail32; + copy_size = sizeof(ioctl_avail32); + } switch (stream->runtime->state) { case SNDRV_PCM_STATE_OPEN: @@ -269,8 +281,7 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) break; } - if (copy_to_user((__u64 __user *)arg, - &ioctl_avail, sizeof(ioctl_avail))) + if (copy_to_user((__u64 __user *)arg, copy_from, copy_size)) return -EFAULT; return 0; } @@ -1336,7 +1347,9 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) case SNDRV_COMPRESS_TSTAMP64: return snd_compr_tstamp(stream, arg, false); case SNDRV_COMPRESS_AVAIL: - return snd_compr_ioctl_avail(stream, arg); + return snd_compr_ioctl_avail(stream, arg, true); + case SNDRV_COMPRESS_AVAIL64: + return snd_compr_ioctl_avail(stream, arg, false); case SNDRV_COMPRESS_PAUSE: return snd_compr_pause(stream); case SNDRV_COMPRESS_RESUME: From 6d0982ae7880f2c4d5fbd1b5f7574ea93d1311ac Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 3 Sep 2025 20:14:52 +0800 Subject: [PATCH 1252/1292] PM / devfreq: mtk-cci: avoid redundant conditions While 'if (i <= 0) ... else if (i > 0) ...' is technically equivalent to 'if (i <= 0) ... else ...', the latter is vastly easier to read because it avoids writing out a condition that is unnecessary. Let's drop such unnecessary conditions. Signed-off-by: Liao Yuanhong Signed-off-by: Chanwoo Choi Link: https://patchwork.kernel.org/project/linux-pm/patch/20250903121452.387023-1-liaoyuanhong@vivo.com/ --- drivers/devfreq/mtk-cci-devfreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-cci-devfreq.c index 5730076846e1be..4c22be728f6a03 100644 --- a/drivers/devfreq/mtk-cci-devfreq.c +++ b/drivers/devfreq/mtk-cci-devfreq.c @@ -86,7 +86,7 @@ static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage) soc_data->sram_max_volt); return ret; } - } else if (pre_voltage > new_voltage) { + } else { voltage = max(new_voltage, pre_vsram - soc_data->max_volt_shift); ret = regulator_set_voltage(drv->proc_reg, voltage, From 16d4b44cf063e90a5495dba26ac9010bb1a77273 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 8 Sep 2025 02:08:57 +0000 Subject: [PATCH 1253/1292] ASoC: renesas: msiof: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Kuninori Morimoto Message-ID: <87jz291yrr.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/msiof.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c index 77e1dadec14d27..f5338bbb037c55 100644 --- a/sound/soc/renesas/rcar/msiof.c +++ b/sound/soc/renesas/rcar/msiof.c @@ -372,10 +372,9 @@ static int msiof_trigger(struct snd_soc_component *component, { struct device *dev = component->dev; struct msiof_priv *priv = dev_get_drvdata(dev); - unsigned long flags; int ret = -EINVAL; - spin_lock_irqsave(&priv->lock, flags); + guard(spinlock_irqsave)(&priv->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -392,8 +391,6 @@ static int msiof_trigger(struct snd_soc_component *component, break; } - spin_unlock_irqrestore(&priv->lock, flags); - return ret; } @@ -404,23 +401,18 @@ static int msiof_hw_params(struct snd_soc_component *component, struct msiof_priv *priv = dev_get_drvdata(component->dev); struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); struct dma_slave_config cfg = {}; - unsigned long flags; int ret; - spin_lock_irqsave(&priv->lock, flags); + guard(spinlock_irqsave)(&priv->lock); ret = snd_hwparams_to_dma_slave_config(substream, params, &cfg); if (ret < 0) - goto hw_params_out; + return ret; cfg.dst_addr = priv->phy_addr + SITFDR; cfg.src_addr = priv->phy_addr + SIRFDR; - ret = dmaengine_slave_config(chan, &cfg); -hw_params_out: - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; + return dmaengine_slave_config(chan, &cfg); } static const struct snd_soc_component_driver msiof_component_driver = { @@ -439,12 +431,10 @@ static irqreturn_t msiof_interrupt(int irq, void *data) struct snd_pcm_substream *substream; u32 sistr; - spin_lock(&priv->lock); - - sistr = msiof_read(priv, SISTR); - msiof_write(priv, SISTR, SISTR_ERR_TX | SISTR_ERR_RX); - - spin_unlock(&priv->lock); + scoped_guard(spinlock, &priv->lock) { + sistr = msiof_read(priv, SISTR); + msiof_write(priv, SISTR, SISTR_ERR_TX | SISTR_ERR_RX); + } /* overflow/underflow error */ substream = priv->substream[SNDRV_PCM_STREAM_PLAYBACK]; From 075a730b85e96d3d6f052f04f45c4f8b77fb8d56 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 8 Sep 2025 02:10:20 +0000 Subject: [PATCH 1254/1292] ASoC: renesas: rsnd: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Kuninori Morimoto Message-ID: <87ikht1ypg.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/core.c | 18 +++++------------- sound/soc/renesas/rcar/src.c | 19 ++++++++----------- sound/soc/renesas/rcar/ssi.c | 35 +++++++++++++++++------------------ 3 files changed, 30 insertions(+), 42 deletions(-) diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c index 37d954495ea5a9..00225690da3371 100644 --- a/sound/soc/renesas/rcar/core.c +++ b/sound/soc/renesas/rcar/core.c @@ -696,25 +696,21 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); int ret; - unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); + guard(spinlock_irqsave)(&priv->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: ret = rsnd_dai_call(init, io, priv); if (ret < 0) - goto dai_trigger_end; + break; ret = rsnd_dai_call(start, io, priv); if (ret < 0) - goto dai_trigger_end; + break; ret = rsnd_dai_call(irq, io, priv, 1); - if (ret < 0) - goto dai_trigger_end; - break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -729,9 +725,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret = -EINVAL; } -dai_trigger_end: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; } @@ -1545,15 +1538,14 @@ static int rsnd_hw_update(struct snd_pcm_substream *substream, struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); struct rsnd_priv *priv = rsnd_io_to_priv(io); - unsigned long flags; int ret; - spin_lock_irqsave(&priv->lock, flags); + guard(spinlock_irqsave)(&priv->lock); + if (hw_params) ret = rsnd_dai_call(hw_params, io, substream, hw_params); else ret = rsnd_dai_call(hw_free, io, substream); - spin_unlock_irqrestore(&priv->lock, flags); return ret; } diff --git a/sound/soc/renesas/rcar/src.c b/sound/soc/renesas/rcar/src.c index f47bf38c2f940e..6a3dbc84f4746a 100644 --- a/sound/soc/renesas/rcar/src.c +++ b/sound/soc/renesas/rcar/src.c @@ -558,19 +558,16 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); bool stop = false; - spin_lock(&priv->lock); - - /* ignore all cases if not working */ - if (!rsnd_io_is_working(io)) - goto rsnd_src_interrupt_out; + scoped_guard(spinlock, &priv->lock) { + /* ignore all cases if not working */ + if (!rsnd_io_is_working(io)) + break; - if (rsnd_src_error_occurred(mod)) - stop = true; + if (rsnd_src_error_occurred(mod)) + stop = true; - rsnd_src_status_clear(mod); -rsnd_src_interrupt_out: - - spin_unlock(&priv->lock); + rsnd_src_status_clear(mod); + } if (stop) snd_pcm_stop_xrun(io->substream); diff --git a/sound/soc/renesas/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c index d52056caa3ec90..0420041e282c5d 100644 --- a/sound/soc/renesas/rcar/ssi.c +++ b/sound/soc/renesas/rcar/ssi.c @@ -680,31 +680,30 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, bool elapsed = false; bool stop = false; - spin_lock(&priv->lock); + scoped_guard(spinlock, &priv->lock) { - /* ignore all cases if not working */ - if (!rsnd_io_is_working(io)) - goto rsnd_ssi_interrupt_out; + /* ignore all cases if not working */ + if (!rsnd_io_is_working(io)) + break; - status = rsnd_ssi_status_get(mod); + status = rsnd_ssi_status_get(mod); - /* PIO only */ - if (!is_dma && (status & DIRQ)) - elapsed = rsnd_ssi_pio_interrupt(mod, io); + /* PIO only */ + if (!is_dma && (status & DIRQ)) + elapsed = rsnd_ssi_pio_interrupt(mod, io); - /* DMA only */ - if (is_dma && (status & (UIRQ | OIRQ))) { - rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); + /* DMA only */ + if (is_dma && (status & (UIRQ | OIRQ))) { + rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); - stop = true; - } + stop = true; + } - stop |= rsnd_ssiu_busif_err_status_clear(mod); + stop |= rsnd_ssiu_busif_err_status_clear(mod); - rsnd_ssi_status_clear(mod); -rsnd_ssi_interrupt_out: - spin_unlock(&priv->lock); + rsnd_ssi_status_clear(mod); + } if (elapsed) snd_pcm_period_elapsed(io->substream); From 15583c4dbbf1f3ef44bc5eb8e9936f7069bc61e9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 8 Sep 2025 02:10:25 +0000 Subject: [PATCH 1255/1292] ASoC: renesas: fsi: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Kuninori Morimoto Message-ID: <87h5xd1ypa.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/fsi.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c index 221ce91f195005..630c2f52e1cf58 100644 --- a/sound/soc/renesas/fsi.c +++ b/sound/soc/renesas/fsi.c @@ -343,14 +343,9 @@ static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data) #define fsi_core_read(p, r) _fsi_master_read(p, p->core->r) static u32 _fsi_master_read(struct fsi_master *master, u32 reg) { - u32 ret; - unsigned long flags; + guard(spinlock_irqsave)(&master->lock); - spin_lock_irqsave(&master->lock, flags); - ret = __fsi_reg_read(master->base + reg); - spin_unlock_irqrestore(&master->lock, flags); - - return ret; + return __fsi_reg_read(master->base + reg); } #define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d) @@ -358,11 +353,9 @@ static u32 _fsi_master_read(struct fsi_master *master, u32 reg) static void _fsi_master_mask_set(struct fsi_master *master, u32 reg, u32 mask, u32 data) { - unsigned long flags; + guard(spinlock_irqsave)(&master->lock); - spin_lock_irqsave(&master->lock, flags); __fsi_reg_mask_set(master->base + reg, mask, data); - spin_unlock_irqrestore(&master->lock, flags); } /* @@ -499,14 +492,10 @@ static int fsi_stream_is_working(struct fsi_priv *fsi, struct fsi_stream *io) { struct fsi_master *master = fsi_get_master(fsi); - unsigned long flags; - int ret; - spin_lock_irqsave(&master->lock, flags); - ret = !!(io->substream && io->substream->runtime); - spin_unlock_irqrestore(&master->lock, flags); + guard(spinlock_irqsave)(&master->lock); - return ret; + return !!(io->substream && io->substream->runtime); } static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io) @@ -520,9 +509,9 @@ static void fsi_stream_init(struct fsi_priv *fsi, { struct snd_pcm_runtime *runtime = substream->runtime; struct fsi_master *master = fsi_get_master(fsi); - unsigned long flags; - spin_lock_irqsave(&master->lock, flags); + guard(spinlock_irqsave)(&master->lock); + io->substream = substream; io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size); io->buff_sample_pos = 0; @@ -533,16 +522,14 @@ static void fsi_stream_init(struct fsi_priv *fsi, io->oerr_num = -1; /* ignore 1st err */ io->uerr_num = -1; /* ignore 1st err */ fsi_stream_handler_call(io, init, fsi, io); - spin_unlock_irqrestore(&master->lock, flags); } static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) { struct snd_soc_dai *dai = fsi_get_dai(io->substream); struct fsi_master *master = fsi_get_master(fsi); - unsigned long flags; - spin_lock_irqsave(&master->lock, flags); + guard(spinlock_irqsave)(&master->lock); if (io->oerr_num > 0) dev_err(dai->dev, "over_run = %d\n", io->oerr_num); @@ -560,7 +547,6 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) io->bus_option = 0; io->oerr_num = 0; io->uerr_num = 0; - spin_unlock_irqrestore(&master->lock, flags); } static int fsi_stream_transfer(struct fsi_stream *io) From 7d083666123a425ba9f81dff1a52955b1f226540 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 8 Sep 2025 02:10:31 +0000 Subject: [PATCH 1256/1292] ASoC: renesas: rz-ssi: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Kuninori Morimoto Message-ID: <87frcx1yp5.wl-kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown --- sound/soc/renesas/rz-ssi.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c index 0f7458a4390198..e009408141570e 100644 --- a/sound/soc/renesas/rz-ssi.c +++ b/sound/soc/renesas/rz-ssi.c @@ -188,24 +188,18 @@ static void rz_ssi_set_substream(struct rz_ssi_stream *strm, struct snd_pcm_substream *substream) { struct rz_ssi_priv *ssi = strm->priv; - unsigned long flags; - spin_lock_irqsave(&ssi->lock, flags); + guard(spinlock_irqsave)(&ssi->lock); + strm->substream = substream; - spin_unlock_irqrestore(&ssi->lock, flags); } static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) { - unsigned long flags; - bool ret; - - spin_lock_irqsave(&ssi->lock, flags); - ret = strm->substream && strm->substream->runtime; - spin_unlock_irqrestore(&ssi->lock, flags); + guard(spinlock_irqsave)(&ssi->lock); - return ret; + return strm->substream && strm->substream->runtime; } static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm) From 06aba2126b414248a34b13584f22a78787c95450 Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Mon, 1 Sep 2025 11:40:08 -0700 Subject: [PATCH 1257/1292] ASoC: codecs: tlv320dac33: Remove unused struct tlv320dac33_platform_data and header file tlv320dac33-plat.h Remove the tlv320dac33_platform_data struct and header file tlv320dac33-plat.h as they are not used anywhere in the kernel or outside this driver. Signed-off-by: Alex Tran Message-ID: <20250901184008.1249535-3-alex.t.tran@gmail.com> Signed-off-by: Mark Brown --- include/sound/tlv320dac33-plat.h | 21 --------------------- sound/soc/codecs/tlv320dac33.c | 12 ------------ 2 files changed, 33 deletions(-) delete mode 100644 include/sound/tlv320dac33-plat.h diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h deleted file mode 100644 index 7a7249a896e3a1..00000000000000 --- a/include/sound/tlv320dac33-plat.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Platform header for Texas Instruments TLV320DAC33 codec driver - * - * Author: Peter Ujfalusi - * - * Copyright: (C) 2009 Nokia Corporation - */ - -#ifndef __TLV320DAC33_PLAT_H -#define __TLV320DAC33_PLAT_H - -struct tlv320dac33_platform_data { - int power_gpio; - int mode1_latency; /* latency caused by the i2c writes in us */ - int auto_fifo_config; /* FIFO config based on the period size */ - int keep_bclk; /* Keep the BCLK running in FIFO modes */ - u8 burst_bclkdiv; -}; - -#endif /* __TLV320DAC33_PLAT_H */ diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 423b9264a205e6..36b3de75a3f439 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -24,7 +24,6 @@ #include #include -#include #include "tlv320dac33.h" /* @@ -1462,16 +1461,9 @@ static struct snd_soc_dai_driver dac33_dai = { static int dac33_i2c_probe(struct i2c_client *client) { - struct tlv320dac33_platform_data *pdata; struct tlv320dac33_priv *dac33; int ret, i; - if (client->dev.platform_data == NULL) { - dev_err(&client->dev, "Platform data not set\n"); - return -ENODEV; - } - pdata = client->dev.platform_data; - dac33 = devm_kzalloc(&client->dev, sizeof(struct tlv320dac33_priv), GFP_KERNEL); if (dac33 == NULL) @@ -1488,10 +1480,6 @@ static int dac33_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, dac33); - dac33->power_gpio = pdata->power_gpio; - dac33->burst_bclkdiv = pdata->burst_bclkdiv; - dac33->keep_bclk = pdata->keep_bclk; - dac33->mode1_latency = pdata->mode1_latency; if (!dac33->mode1_latency) dac33->mode1_latency = 10000; /* 10ms */ dac33->irq = client->irq; From 960ef523cfe420ae8fdd801f1d12be0fb7ed8719 Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Mon, 1 Sep 2025 11:40:06 -0700 Subject: [PATCH 1258/1292] ASoC: codecs: tlv320dac33: Add default value for burst_bclkdiv Add default value for field burst_bclkdiv as initializing it to 0 is incorrect, potentially leading to a divide by 0 issue. Valid range is 2-17 per TI datasheet. 8 was chosen as a dummy value. Reference . Signed-off-by: Alex Tran Message-ID: <20250901184008.1249535-1-alex.t.tran@gmail.com> Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 36b3de75a3f439..feefc777c47e0b 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1480,6 +1480,8 @@ static int dac33_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, dac33); + if (!dac33->burst_bclkdiv) + dac33->burst_bclkdiv = 8; if (!dac33->mode1_latency) dac33->mode1_latency = 10000; /* 10ms */ dac33->irq = client->irq; From 1cf87861a2e02432fb68f8bcc8f20a8e42acde59 Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Mon, 1 Sep 2025 11:40:07 -0700 Subject: [PATCH 1259/1292] ASoC: codecs: tlv320dac33: Convert to use gpiod api Convert driver to use the gpiod api instead of the legacy GPIO interface. Replace power_gpio integer with reset_gpiod descriptor in the dac33 struct. Use devm_gpiod_get_optional() to automatically handle resource cleanup and add proper error checking when setting GPIO values. Signed-off-by: Alex Tran Message-ID: <20250901184008.1249535-2-alex.t.tran@gmail.com> Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 55 ++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index feefc777c47e0b..c495be1cf2ed3b 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -79,7 +79,7 @@ struct tlv320dac33_priv { struct snd_soc_component *component; struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES]; struct snd_pcm_substream *substream; - int power_gpio; + struct gpio_desc *reset_gpiod; int chip_power; int irq; unsigned int refclk; @@ -382,14 +382,26 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) goto exit; } - if (dac33->power_gpio >= 0) - gpio_set_value(dac33->power_gpio, 1); + if (dac33->reset_gpiod) { + ret = gpiod_set_value(dac33->reset_gpiod, 1); + if (ret < 0) { + dev_err(&dac33->i2c->dev, + "Failed to set reset GPIO: %d\n", ret); + goto exit; + } + } dac33->chip_power = 1; } else { dac33_soft_power(component, 0); - if (dac33->power_gpio >= 0) - gpio_set_value(dac33->power_gpio, 0); + if (dac33->reset_gpiod) { + ret = gpiod_set_value(dac33->reset_gpiod, 0); + if (ret < 0) { + dev_err(&dac33->i2c->dev, + "Failed to set reset GPIO: %d\n", ret); + goto exit; + } + } ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); @@ -1488,16 +1500,14 @@ static int dac33_i2c_probe(struct i2c_client *client) /* Disable FIFO use by default */ dac33->fifo_mode = DAC33_FIFO_BYPASS; - /* Check if the reset GPIO number is valid and request it */ - if (dac33->power_gpio >= 0) { - ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset"); - if (ret < 0) { - dev_err(&client->dev, - "Failed to request reset GPIO (%d)\n", - dac33->power_gpio); - goto err_gpio; - } - gpio_direction_output(dac33->power_gpio, 0); + /* request optional reset GPIO */ + dac33->reset_gpiod = + devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(dac33->reset_gpiod)) { + ret = PTR_ERR(dac33->reset_gpiod); + dev_err_probe(&client->dev, ret, + "Failed to get reset GPIO\n"); + goto err; } for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++) @@ -1508,19 +1518,17 @@ static int dac33_i2c_probe(struct i2c_client *client) if (ret != 0) { dev_err(&client->dev, "Failed to request supplies: %d\n", ret); - goto err_get; + goto err; } ret = devm_snd_soc_register_component(&client->dev, &soc_component_dev_tlv320dac33, &dac33_dai, 1); if (ret < 0) - goto err_get; + goto err; return ret; -err_get: - if (dac33->power_gpio >= 0) - gpio_free(dac33->power_gpio); -err_gpio: + +err: return ret; } @@ -1530,9 +1538,6 @@ static void dac33_i2c_remove(struct i2c_client *client) if (unlikely(dac33->chip_power)) dac33_hard_power(dac33->component, 0); - - if (dac33->power_gpio >= 0) - gpio_free(dac33->power_gpio); } static const struct i2c_device_id tlv320dac33_i2c_id[] = { From b20eb0e8de383116f1e1470d74da2a3c83c4e345 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Sep 2025 19:18:19 +0200 Subject: [PATCH 1260/1292] ASoC: Intel: bytcht_es8316: Fix invalid quirk input mapping When an invalid value is passed via quirk option, currently bytcht_es8316 driver just ignores and leaves as is, which may lead to unepxected results like OOB access. This patch adds the sanity check and corrects the input mapping to the certain default value if an invalid value is passed. Fixes: 249d2fc9e55c ("ASoC: Intel: bytcht_es8316: Set card long_name based on quirks") Signed-off-by: Takashi Iwai Message-ID: <20250902171826.27329-2-tiwai@suse.de> Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 62594e7966ab0f..b384d38654e658 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -47,7 +47,8 @@ enum { BYT_CHT_ES8316_INTMIC_IN2_MAP, }; -#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_CHT_ES8316_MAP_MASK GENMASK(3, 0) +#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & BYT_CHT_ES8316_MAP_MASK) #define BYT_CHT_ES8316_SSP0 BIT(16) #define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) #define BYT_CHT_ES8316_JD_INVERTED BIT(18) @@ -60,10 +61,23 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { - if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP) + int map; + + map = BYT_CHT_ES8316_MAP(quirk); + switch (map) { + case BYT_CHT_ES8316_INTMIC_IN1_MAP: dev_info(dev, "quirk IN1_MAP enabled"); - if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP) + break; + case BYT_CHT_ES8316_INTMIC_IN2_MAP: dev_info(dev, "quirk IN2_MAP enabled"); + break; + default: + dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to INTMIC_IN1_MAP\n", map); + quirk &= ~BYT_CHT_ES8316_MAP_MASK; + quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP; + break; + } + if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) From fba404e4b4af4f4f747bb0e41e9fff7d03c7bcc0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Sep 2025 19:18:20 +0200 Subject: [PATCH 1261/1292] ASoC: Intel: bytcr_rt5640: Fix invalid quirk input mapping When an invalid value is passed via quirk option, currently bytcr_rt5640 driver only shows an error message but leaves as is. This may lead to unepxected results like OOB access. This patch corrects the input mapping to the certain default value if an invalid value is passed. Fixes: 063422ca2a9d ("ASoC: Intel: bytcr_rt5640: Set card long_name based on quirks") Signed-off-by: Takashi Iwai Message-ID: <20250902171826.27329-3-tiwai@suse.de> Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 0f3b8f44e70112..bc846558480e41 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -68,7 +68,8 @@ enum { BYT_RT5640_OVCD_SF_1P5 = (RT5640_OVCD_SF_1P5 << 13), }; -#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_RT5640_MAP_MASK GENMASK(3, 0) +#define BYT_RT5640_MAP(quirk) ((quirk) & BYT_RT5640_MAP_MASK) #define BYT_RT5640_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4) #define BYT_RT5640_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8) #define BYT_RT5640_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13) @@ -140,7 +141,9 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk NO_INTERNAL_MIC_MAP enabled\n"); break; default: - dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map); + dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to DMIC1_MAP\n", map); + byt_rt5640_quirk &= ~BYT_RT5640_MAP_MASK; + byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP; break; } if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) From 4336efb59ef364e691ef829a73d9dbd4d5ed7c7b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Sep 2025 19:18:21 +0200 Subject: [PATCH 1262/1292] ASoC: Intel: bytcr_rt5651: Fix invalid quirk input mapping When an invalid value is passed via quirk option, currently bytcr_rt5640 driver just ignores and leaves as is, which may lead to unepxected results like OOB access. This patch adds the sanity check and corrects the input mapping to the certain default value if an invalid value is passed. Fixes: 64484ccee7af ("ASoC: Intel: bytcr_rt5651: Set card long_name based on quirks") Signed-off-by: Takashi Iwai Message-ID: <20250902171826.27329-4-tiwai@suse.de> Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 67c62844ca2a91..604a35d380e9ab 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -58,7 +58,8 @@ enum { BYT_RT5651_OVCD_SF_1P5 = (RT5651_OVCD_SF_1P5 << 13), }; -#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_RT5651_MAP_MASK GENMASK(3, 0) +#define BYT_RT5651_MAP(quirk) ((quirk) & BYT_RT5651_MAP_MASK) #define BYT_RT5651_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4) #define BYT_RT5651_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8) #define BYT_RT5651_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13) @@ -100,14 +101,29 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP) + int map; + + map = BYT_RT5651_MAP(byt_rt5651_quirk); + switch (map) { + case BYT_RT5651_DMIC_MAP: dev_info(dev, "quirk DMIC_MAP enabled"); - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_MAP) + break; + case BYT_RT5651_IN1_MAP: dev_info(dev, "quirk IN1_MAP enabled"); - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP) + break; + case BYT_RT5651_IN2_MAP: dev_info(dev, "quirk IN2_MAP enabled"); - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_IN2_MAP) + break; + case BYT_RT5651_IN1_IN2_MAP: dev_info(dev, "quirk IN1_IN2_MAP enabled"); + break; + default: + dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to DMIC_MAP\n", map); + byt_rt5651_quirk &= ~BYT_RT5651_MAP_MASK; + byt_rt5651_quirk |= BYT_RT5651_DMIC_MAP; + break; + } + if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) { dev_info(dev, "quirk realtek,jack-detect-source %ld\n", BYT_RT5651_JDSRC(byt_rt5651_quirk)); From 2167bb92bdebb187e8b3a102987356ce981b77de Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Fri, 5 Sep 2025 21:24:09 +0800 Subject: [PATCH 1263/1292] ACPI: processor: thermal: Release policy references using __free() Replace the manual cpufreq_cpu_put() with __free(put_cpufreq_policy) for policy references. This reduces the risk of reference counting mistakes and aligns the code with the latest kernel style. No functional change intended. Signed-off-by: Zihuan Zhang Link: https://patch.msgid.link/20250905132413.1376220-3-zhangzihuan@kylinos.cn [ rjw: Subject and changelog edits, whitespace fixups ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_thermal.c | 52 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 1219adb11ab927..c7b1dc5687eccc 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -62,19 +62,14 @@ static int phys_package_first_cpu(int cpu) return 0; } -static int cpu_has_cpufreq(unsigned int cpu) +static bool cpu_has_cpufreq(unsigned int cpu) { - struct cpufreq_policy *policy; - if (!acpi_processor_cpufreq_init) return 0; - policy = cpufreq_cpu_get(cpu); - if (policy) { - cpufreq_cpu_put(policy); - return 1; - } - return 0; + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); + + return policy != NULL; } static int cpufreq_get_max_state(unsigned int cpu) @@ -93,12 +88,31 @@ static int cpufreq_get_cur_state(unsigned int cpu) return reduction_step(cpu); } +static bool cpufreq_update_thermal_limit(unsigned int cpu, struct acpi_processor *pr) +{ + unsigned long max_freq; + int ret; + + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); + if (!policy) + return false; + + max_freq = (policy->cpuinfo.max_freq * + (100 - reduction_step(cpu) * cpufreq_thermal_reduction_pctg)) / 100; + + ret = freq_qos_update_request(&pr->thermal_req, max_freq); + if (ret < 0) { + pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n", + pr->id, ret); + } + + return true; +} + static int cpufreq_set_cur_state(unsigned int cpu, int state) { - struct cpufreq_policy *policy; struct acpi_processor *pr; - unsigned long max_freq; - int i, ret; + int i; if (!cpu_has_cpufreq(cpu)) return 0; @@ -120,20 +134,8 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) if (unlikely(!freq_qos_request_active(&pr->thermal_req))) continue; - policy = cpufreq_cpu_get(i); - if (!policy) + if (!cpufreq_update_thermal_limit(i, pr)) return -EINVAL; - - max_freq = (policy->cpuinfo.max_freq * - (100 - reduction_step(i) * cpufreq_thermal_reduction_pctg)) / 100; - - cpufreq_cpu_put(policy); - - ret = freq_qos_update_request(&pr->thermal_req, max_freq); - if (ret < 0) { - pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n", - pr->id, ret); - } } return 0; } From 7ceb69ca82b1456a66783a1472d6e677e00065a1 Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Sat, 30 Aug 2025 14:14:58 +0800 Subject: [PATCH 1264/1292] ASoC: tas2781: Add tas2118, tas2x20, tas5825 support Add tas2020, tas2118, tas2120, tas2320, tas2570, tas2572, tas5825 tas5827 support in tas2781 driver. Tas2118, tas2x20, tas257x have no on-chip DSP, tas582x have on-chip DSP but have no calibration required stereo smart amplifier. Signed-off-by: Baojun Xu Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- include/sound/tas2781.h | 14 +- include/sound/tas2x20-tlv.h | 259 ++++++++++++++++++++++++++ sound/soc/codecs/tas2781-comlib-i2c.c | 2 + sound/soc/codecs/tas2781-i2c.c | 184 +++++++++++++----- 4 files changed, 410 insertions(+), 49 deletions(-) create mode 100644 include/sound/tas2x20-tlv.h diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index f0aefc04a957a9..ddd997ac3216a8 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -51,7 +51,9 @@ /* Software Reset, compatble with new device (TAS5825). */ #define TASDEVICE_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01) -#define TASDEVICE_REG_SWRESET_RESET (BIT(0) | BIT(4)) +#define TASDEVICE_REG_SWRESET_RESET BIT(0) + +#define TAS5825_REG_SWRESET_RESET (BIT(0) | BIT(4)) /* Checksum */ #define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e) @@ -110,8 +112,17 @@ #define TAS2781_RUNTIME_RE_REG TASDEVICE_REG(0x64, 0x63, 0x44) enum audio_device { + TAS2020, + TAS2118, + TAS2120, + TAS2320, TAS2563, + TAS2570, + TAS2572, TAS2781, + TAS5825, + TAS5827, + TAS_OTHERS, }; enum dspbin_type { @@ -194,6 +205,7 @@ struct tasdevice_priv { unsigned char coef_binaryname[64]; unsigned char rca_binaryname[64]; unsigned char dev_name[32]; + const unsigned char (*dvc_tlv_table)[4]; const char *name_prefix; unsigned char ndev; unsigned int dspbin_typ; diff --git a/include/sound/tas2x20-tlv.h b/include/sound/tas2x20-tlv.h new file mode 100644 index 00000000000000..6e6bcec4a0a122 --- /dev/null +++ b/include/sound/tas2x20-tlv.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// +// ALSA SoC Texas Instruments TAS2x20/TAS2118 Audio Smart Amplifier +// +// Copyright (C) 2025 Texas Instruments Incorporated +// https://www.ti.com +// +// The TAS2x20/TAS2118 hda driver implements for one, two, or even multiple +// TAS2x20/TAS2118 chips. +// +// Author: Baojun Xu +// + +#ifndef __TAS2X20_TLV_H__ +#define __TAS2X20_TLV_H__ + +#define TAS2X20_DVC_LEVEL TASDEVICE_REG(0x0, 0x2, 0x0c) +#define TAS2X20_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x07) + +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2x20_dvc_tlv, 1650, 50, 0); +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2x20_amp_tlv, 2100, 50, 0); + +/* pow(10, db/20) * pow(2,22) */ +static const __maybe_unused unsigned char tas2x20_dvc_table[][4] = { + { 0X00, 0X00, 0X0D, 0X00 }, /* -110.0db */ + { 0X00, 0X00, 0X0E, 0X00 }, /* -109.5db */ + { 0X00, 0X00, 0X0E, 0X00 }, /* -109.0db */ + { 0X00, 0X00, 0X0F, 0X00 }, /* -108.5db */ + { 0X00, 0X00, 0X10, 0X00 }, /* -108.0db */ + { 0X00, 0X00, 0X11, 0X00 }, /* -107.5db */ + { 0X00, 0X00, 0X12, 0X00 }, /* -107.0db */ + { 0X00, 0X00, 0X13, 0X00 }, /* -106.5db */ + { 0X00, 0X00, 0X15, 0X00 }, /* -106.0db */ + { 0X00, 0X00, 0X16, 0X00 }, /* -105.5db */ + { 0X00, 0X00, 0X17, 0X00 }, /* -105.0db */ + { 0X00, 0X00, 0X18, 0X00 }, /* -104.5db */ + { 0X00, 0X00, 0X1A, 0X00 }, /* -104.0db */ + { 0X00, 0X00, 0X1C, 0X00 }, /* -103.5db */ + { 0X00, 0X00, 0X1D, 0X00 }, /* -103.0db */ + { 0X00, 0X00, 0X1F, 0X00 }, /* -102.5db */ + { 0X00, 0X00, 0X21, 0X00 }, /* -102.0db */ + { 0X00, 0X00, 0X23, 0X00 }, /* -101.5db */ + { 0X00, 0X00, 0X25, 0X00 }, /* -101.0db */ + { 0X00, 0X00, 0X27, 0X00 }, /* -100.5db */ + { 0X00, 0X00, 0X29, 0X00 }, /* -100.0db */ + { 0X00, 0X00, 0X2C, 0X00 }, /* -99.5db */ + { 0X00, 0X00, 0X2F, 0X00 }, /* -99.0db */ + { 0X00, 0X00, 0X31, 0X00 }, /* -98.5db */ + { 0X00, 0X00, 0X34, 0X00 }, /* -98.0db */ + { 0X00, 0X00, 0X37, 0X00 }, /* -97.5db */ + { 0X00, 0X00, 0X3B, 0X00 }, /* -97.0db */ + { 0X00, 0X00, 0X3E, 0X00 }, /* -96.5db */ + { 0X00, 0X00, 0X42, 0X00 }, /* -96.0db */ + { 0X00, 0X00, 0X46, 0X00 }, /* -95.5db */ + { 0X00, 0X00, 0X4A, 0X00 }, /* -95.0db */ + { 0X00, 0X00, 0X4F, 0X00 }, /* -94.5db */ + { 0X00, 0X00, 0X53, 0X00 }, /* -94.0db */ + { 0X00, 0X00, 0X58, 0X00 }, /* -93.5db */ + { 0X00, 0X00, 0X5D, 0X00 }, /* -93.0db */ + { 0X00, 0X00, 0X63, 0X00 }, /* -92.5db */ + { 0X00, 0X00, 0X69, 0X00 }, /* -92.0db */ + { 0X00, 0X00, 0X6F, 0X00 }, /* -91.5db */ + { 0X00, 0X00, 0X76, 0X00 }, /* -91.0db */ + { 0X00, 0X00, 0X7D, 0X00 }, /* -90.5db */ + { 0X00, 0X00, 0X84, 0X00 }, /* -90.0db */ + { 0X00, 0X00, 0X8C, 0X00 }, /* -89.5db */ + { 0X00, 0X00, 0X94, 0X00 }, /* -89.0db */ + { 0X00, 0X00, 0X9D, 0X00 }, /* -88.5db */ + { 0X00, 0X00, 0XA6, 0X00 }, /* -88.0db */ + { 0X00, 0X00, 0XB0, 0X00 }, /* -87.5db */ + { 0X00, 0X00, 0XBB, 0X00 }, /* -87.0db */ + { 0X00, 0X00, 0XC6, 0X00 }, /* -86.5db */ + { 0X00, 0X00, 0XD2, 0X00 }, /* -86.0db */ + { 0X00, 0X00, 0XDE, 0X00 }, /* -85.5db */ + { 0X00, 0X00, 0XEB, 0X00 }, /* -85.0db */ + { 0X00, 0X00, 0XF9, 0X00 }, /* -84.5db */ + { 0X00, 0X01, 0X08, 0X00 }, /* -84.0db */ + { 0X00, 0X01, 0X18, 0X00 }, /* -83.5db */ + { 0X00, 0X01, 0X28, 0X00 }, /* -83.0db */ + { 0X00, 0X01, 0X3A, 0X00 }, /* -82.5db */ + { 0X00, 0X01, 0X4D, 0X00 }, /* -82.0db */ + { 0X00, 0X01, 0X60, 0X00 }, /* -81.5db */ + { 0X00, 0X01, 0X75, 0X00 }, /* -81.0db */ + { 0X00, 0X01, 0X8B, 0X00 }, /* -80.5db */ + { 0X00, 0X01, 0XA3, 0X00 }, /* -80.0db */ + { 0X00, 0X01, 0XBC, 0X00 }, /* -79.5db */ + { 0X00, 0X01, 0XD6, 0X00 }, /* -79.0db */ + { 0X00, 0X01, 0XF2, 0X00 }, /* -78.5db */ + { 0X00, 0X02, 0X10, 0X00 }, /* -78.0db */ + { 0X00, 0X02, 0X2F, 0X00 }, /* -77.5db */ + { 0X00, 0X02, 0X50, 0X00 }, /* -77.0db */ + { 0X00, 0X02, 0X73, 0X00 }, /* -76.5db */ + { 0X00, 0X02, 0X98, 0X00 }, /* -76.0db */ + { 0X00, 0X02, 0XC0, 0X00 }, /* -75.5db */ + { 0X00, 0X02, 0XE9, 0X00 }, /* -75.0db */ + { 0X00, 0X03, 0X16, 0X00 }, /* -74.5db */ + { 0X00, 0X03, 0X44, 0X00 }, /* -74.0db */ + { 0X00, 0X03, 0X76, 0X00 }, /* -73.5db */ + { 0X00, 0X03, 0XAA, 0X00 }, /* -73.0db */ + { 0X00, 0X03, 0XE2, 0X00 }, /* -72.5db */ + { 0X00, 0X04, 0X1D, 0X00 }, /* -72.0db */ + { 0X00, 0X04, 0X5B, 0X00 }, /* -71.5db */ + { 0X00, 0X04, 0X9E, 0X00 }, /* -71.0db */ + { 0X00, 0X04, 0XE4, 0X00 }, /* -70.5db */ + { 0X00, 0X05, 0X2E, 0X00 }, /* -70.0db */ + { 0X00, 0X05, 0X7C, 0X00 }, /* -69.5db */ + { 0X00, 0X05, 0XD0, 0X00 }, /* -69.0db */ + { 0X00, 0X06, 0X28, 0X00 }, /* -68.5db */ + { 0X00, 0X06, 0X85, 0X00 }, /* -68.0db */ + { 0X00, 0X06, 0XE8, 0X00 }, /* -67.5db */ + { 0X00, 0X07, 0X51, 0X00 }, /* -67.0db */ + { 0X00, 0X07, 0XC0, 0X00 }, /* -66.5db */ + { 0X00, 0X08, 0X36, 0X00 }, /* -66.0db */ + { 0X00, 0X08, 0XB2, 0X00 }, /* -65.5db */ + { 0X00, 0X09, 0X36, 0X00 }, /* -65.0db */ + { 0X00, 0X09, 0XC2, 0X00 }, /* -64.5db */ + { 0X00, 0X0A, 0X56, 0X00 }, /* -64.0db */ + { 0X00, 0X0A, 0XF3, 0X00 }, /* -63.5db */ + { 0X00, 0X0B, 0X99, 0X00 }, /* -63.0db */ + { 0X00, 0X0C, 0X49, 0X00 }, /* -62.5db */ + { 0X00, 0X0D, 0X03, 0X00 }, /* -62.0db */ + { 0X00, 0X0D, 0XC9, 0X00 }, /* -61.5db */ + { 0X00, 0X0E, 0X9A, 0X00 }, /* -61.0db */ + { 0X00, 0X0F, 0X77, 0X00 }, /* -60.5db */ + { 0X00, 0X10, 0X62, 0X00 }, /* -60.0db */ + { 0X00, 0X11, 0X5A, 0X00 }, /* -59.5db */ + { 0X00, 0X12, 0X62, 0X00 }, /* -59.0db */ + { 0X00, 0X13, 0X78, 0X00 }, /* -58.5db */ + { 0X00, 0X14, 0XA0, 0X00 }, /* -58.0db */ + { 0X00, 0X15, 0XD9, 0X00 }, /* -57.5db */ + { 0X00, 0X17, 0X24, 0X00 }, /* -57.0db */ + { 0X00, 0X18, 0X83, 0X00 }, /* -56.5db */ + { 0X00, 0X19, 0XF7, 0X00 }, /* -56.0db */ + { 0X00, 0X1B, 0X81, 0X00 }, /* -55.5db */ + { 0X00, 0X1D, 0X22, 0X00 }, /* -55.0db */ + { 0X00, 0X1E, 0XDC, 0X00 }, /* -54.5db */ + { 0X00, 0X20, 0XB0, 0X00 }, /* -54.0db */ + { 0X00, 0X22, 0XA0, 0X00 }, /* -53.5db */ + { 0X00, 0X24, 0XAD, 0X00 }, /* -53.0db */ + { 0X00, 0X26, 0XDA, 0X00 }, /* -52.5db */ + { 0X00, 0X29, 0X27, 0X00 }, /* -52.0db */ + { 0X00, 0X2B, 0X97, 0X00 }, /* -51.5db */ + { 0X00, 0X2E, 0X2D, 0X00 }, /* -51.0db */ + { 0X00, 0X30, 0XE9, 0X00 }, /* -50.5db */ + { 0X00, 0X33, 0XCF, 0X00 }, /* -50.0db */ + { 0X00, 0X36, 0XE1, 0X00 }, /* -49.5db */ + { 0X00, 0X3A, 0X21, 0X00 }, /* -49.0db */ + { 0X00, 0X3D, 0X93, 0X00 }, /* -48.5db */ + { 0X00, 0X41, 0X39, 0X00 }, /* -48.0db */ + { 0X00, 0X45, 0X17, 0X00 }, /* -47.5db */ + { 0X00, 0X49, 0X2F, 0X00 }, /* -47.0db */ + { 0X00, 0X4D, 0X85, 0X00 }, /* -46.5db */ + { 0X00, 0X52, 0X1D, 0X00 }, /* -46.0db */ + { 0X00, 0X56, 0XFA, 0X00 }, /* -45.5db */ + { 0X00, 0X5C, 0X22, 0X00 }, /* -45.0db */ + { 0X00, 0X61, 0X97, 0X00 }, /* -44.5db */ + { 0X00, 0X67, 0X60, 0X00 }, /* -44.0db */ + { 0X00, 0X6D, 0X80, 0X00 }, /* -43.5db */ + { 0X00, 0X73, 0XFD, 0X00 }, /* -43.0db */ + { 0X00, 0X7A, 0XDC, 0X00 }, /* -42.5db */ + { 0X00, 0X82, 0X24, 0X00 }, /* -42.0db */ + { 0X00, 0X89, 0XDA, 0X00 }, /* -41.5db */ + { 0X00, 0X92, 0X05, 0X00 }, /* -41.0db */ + { 0X00, 0X9A, 0XAC, 0X00 }, /* -40.5db */ + { 0X00, 0XA3, 0XD7, 0X00 }, /* -40.0db */ + { 0X00, 0XAD, 0X8C, 0X00 }, /* -39.5db */ + { 0X00, 0XB7, 0XD4, 0X00 }, /* -39.0db */ + { 0X00, 0XC2, 0XB9, 0X00 }, /* -38.5db */ + { 0X00, 0XCE, 0X43, 0X00 }, /* -38.0db */ + { 0X00, 0XDA, 0X7B, 0X00 }, /* -37.5db */ + { 0X00, 0XE7, 0X6E, 0X00 }, /* -37.0db */ + { 0X00, 0XF5, 0X24, 0X00 }, /* -36.5db */ + { 0X01, 0X03, 0XAB, 0X00 }, /* -36.0db */ + { 0X01, 0X13, 0X0E, 0X00 }, /* -35.5db */ + { 0X01, 0X23, 0X5A, 0X00 }, /* -35.0db */ + { 0X01, 0X34, 0X9D, 0X00 }, /* -34.5db */ + { 0X01, 0X46, 0XE7, 0X00 }, /* -34.0db */ + { 0X01, 0X5A, 0X46, 0X00 }, /* -33.5db */ + { 0X01, 0X6E, 0XCA, 0X00 }, /* -33.0db */ + { 0X01, 0X84, 0X86, 0X00 }, /* -32.5db */ + { 0X01, 0X9B, 0X8C, 0X00 }, /* -32.0db */ + { 0X01, 0XB3, 0XEE, 0X00 }, /* -31.5db */ + { 0X01, 0XCD, 0XC3, 0X00 }, /* -31.0db */ + { 0X01, 0XE9, 0X20, 0X00 }, /* -30.5db */ + { 0X02, 0X06, 0X1B, 0X00 }, /* -30.0db */ + { 0X02, 0X24, 0XCE, 0X00 }, /* -29.5db */ + { 0X02, 0X45, 0X53, 0X00 }, /* -29.0db */ + { 0X02, 0X67, 0XC5, 0X00 }, /* -28.5db */ + { 0X02, 0X8C, 0X42, 0X00 }, /* -28.0db */ + { 0X02, 0XB2, 0XE8, 0X00 }, /* -27.5db */ + { 0X02, 0XDB, 0XD8, 0X00 }, /* -27.0db */ + { 0X03, 0X07, 0X36, 0X00 }, /* -26.5db */ + { 0X03, 0X35, 0X25, 0X00 }, /* -26.0db */ + { 0X03, 0X65, 0XCD, 0X00 }, /* -25.5db */ + { 0X03, 0X99, 0X57, 0X00 }, /* -25.0db */ + { 0X03, 0XCF, 0XEE, 0X00 }, /* -24.5db */ + { 0X04, 0X09, 0XC2, 0X00 }, /* -24.0db */ + { 0X04, 0X47, 0X03, 0X00 }, /* -23.5db */ + { 0X04, 0X87, 0XE5, 0X00 }, /* -23.0db */ + { 0X04, 0XCC, 0XA0, 0X00 }, /* -22.5db */ + { 0X05, 0X15, 0X6D, 0X00 }, /* -22.0db */ + { 0X05, 0X62, 0X8A, 0X00 }, /* -21.5db */ + { 0X05, 0XB4, 0X39, 0X00 }, /* -21.0db */ + { 0X06, 0X0A, 0XBF, 0X00 }, /* -20.5db */ + { 0X06, 0X66, 0X66, 0X00 }, /* -20.0db */ + { 0X06, 0XC7, 0X7B, 0X00 }, /* -19.5db */ + { 0X07, 0X2E, 0X50, 0X00 }, /* -19.0db */ + { 0X07, 0X9B, 0X3D, 0X00 }, /* -18.5db */ + { 0X08, 0X0E, 0X9F, 0X00 }, /* -18.0db */ + { 0X08, 0X88, 0XD7, 0X00 }, /* -17.5db */ + { 0X09, 0X0A, 0X4D, 0X00 }, /* -17.0db */ + { 0X09, 0X93, 0X6E, 0X00 }, /* -16.5db */ + { 0X0A, 0X24, 0XB0, 0X00 }, /* -16.0db */ + { 0X0A, 0XBE, 0X8D, 0X00 }, /* -15.5db */ + { 0X0B, 0X61, 0X88, 0X00 }, /* -15.0db */ + { 0X0C, 0X0E, 0X2B, 0X00 }, /* -14.5db */ + { 0X0C, 0XC5, 0X09, 0X00 }, /* -14.0db */ + { 0X0D, 0X86, 0XBD, 0X00 }, /* -13.5db */ + { 0X0E, 0X53, 0XEB, 0X00 }, /* -13.0db */ + { 0X0F, 0X2D, 0X42, 0X00 }, /* -12.5db */ + { 0X10, 0X13, 0X79, 0X00 }, /* -12.0db */ + { 0X11, 0X07, 0X54, 0X00 }, /* -11.5db */ + { 0X12, 0X09, 0XA3, 0X00 }, /* -11.0db */ + { 0X13, 0X1B, 0X40, 0X00 }, /* -10.5db */ + { 0X14, 0X3D, 0X13, 0X00 }, /* -10.0db */ + { 0X15, 0X70, 0X12, 0X00 }, /* -9.5db */ + { 0X16, 0XB5, 0X43, 0X00 }, /* -9.0db */ + { 0X18, 0X0D, 0XB8, 0X00 }, /* -8.5db */ + { 0X19, 0X7A, 0X96, 0X00 }, /* -8.0db */ + { 0X1A, 0XFD, 0X13, 0X00 }, /* -7.5db */ + { 0X1C, 0X96, 0X76, 0X00 }, /* -7.0db */ + { 0X1E, 0X48, 0X1C, 0X00 }, /* -6.5db */ + { 0X20, 0X13, 0X73, 0X00 }, /* -6.0db */ + { 0X21, 0XFA, 0X02, 0X00 }, /* -5.5db */ + { 0X23, 0XFD, 0X66, 0X00 }, /* -5.0db */ + { 0X26, 0X1F, 0X54, 0X00 }, /* -4.5db */ + { 0X28, 0X61, 0X9A, 0X00 }, /* -4.0db */ + { 0X2A, 0XC6, 0X25, 0X00 }, /* -3.5db */ + { 0X2D, 0X4E, 0XFB, 0X00 }, /* -3.0db */ + { 0X2F, 0XFE, 0X44, 0X00 }, /* -2.5db */ + { 0X32, 0XD6, 0X46, 0X00 }, /* -2.0db */ + { 0X35, 0XD9, 0X6B, 0X00 }, /* -1.5db */ + { 0X39, 0X0A, 0X41, 0X00 }, /* -1.0db */ + { 0X3C, 0X6B, 0X7E, 0X00 }, /* -0.5db */ + { 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */ + { 0X43, 0XCA, 0XD0, 0X00 }, /* 0.5db */ + { 0X47, 0XCF, 0X26, 0X00 }, /* 1.0db */ + { 0X4C, 0X10, 0X6B, 0X00 }, /* 1.5db */ + { 0X50, 0X92, 0X3B, 0X00 }, /* 2.0db */ + { 0X55, 0X58, 0X6A, 0X00 }, /* 2.5db */ + { 0X5A, 0X67, 0X03, 0X00 }, /* 3.0db */ + { 0X5F, 0XC2, 0X53, 0X00 }, /* 3.5db */ + { 0X65, 0X6E, 0XE3, 0X00 }, /* 4.0db */ + { 0X6B, 0X71, 0X86, 0X00 }, /* 4.5db */ + { 0X71, 0XCF, 0X54, 0X00 }, /* 5.0db */ + { 0X78, 0X8D, 0XB4, 0X00 }, /* 5.5db */ + { 0X7F, 0XB2, 0X61, 0X00 }, /* 6.0db */ +}; +#endif diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c index c078bb0a843700..b3fd7350143bdb 100644 --- a/sound/soc/codecs/tas2781-comlib-i2c.c +++ b/sound/soc/codecs/tas2781-comlib-i2c.c @@ -320,6 +320,8 @@ void tasdevice_reset(struct tasdevice_priv *tas_dev) for (i = 0; i < tas_dev->ndev; i++) { ret = tasdevice_dev_write(tas_dev, i, TASDEVICE_REG_SWRESET, + tas_dev->chip_id >= TAS5825 ? + TAS5825_REG_SWRESET_RESET : TASDEVICE_REG_SWRESET_RESET); if (ret < 0) dev_err(tas_dev->dev, diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 0e09d794516fc7..0b8e3638c2ac51 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -30,8 +30,10 @@ #include #include #include +#include #include #include +#include #include #define X2563_CL_STT_VAL(xreg, xval) \ @@ -98,16 +100,32 @@ static const struct bulk_reg_val tas2781_cali_start_reg[] = { }; static const struct i2c_device_id tasdevice_id[] = { + { "tas2020", TAS2020 }, + { "tas2118", TAS2118 }, + { "tas2120", TAS2120 }, + { "tas2320", TAS2320 }, { "tas2563", TAS2563 }, + { "tas2570", TAS2570 }, + { "tas2572", TAS2572 }, { "tas2781", TAS2781 }, + { "tas5825", TAS5825 }, + { "tas5827", TAS5827 }, {} }; MODULE_DEVICE_TABLE(i2c, tasdevice_id); #ifdef CONFIG_OF static const struct of_device_id tasdevice_of_match[] = { + { .compatible = "ti,tas2020" }, + { .compatible = "ti,tas2118" }, + { .compatible = "ti,tas2120" }, + { .compatible = "ti,tas2320" }, { .compatible = "ti,tas2563" }, + { .compatible = "ti,tas2570" }, + { .compatible = "ti,tas2572" }, { .compatible = "ti,tas2781" }, + { .compatible = "ti,tas5825" }, + { .compatible = "ti,tas5827" }, {}, }; MODULE_DEVICE_TABLE(of, tasdevice_of_match); @@ -797,7 +815,7 @@ static int tasdev_nop_get( return 0; } -static int tas2563_digital_gain_get( +static int tasdevice_digital_gain_get( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -823,15 +841,15 @@ static int tas2563_digital_gain_get( while (r > 1 + l) { mid = (l + r) / 2; - ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]); + ar_mid = get_unaligned_be32(tas_dev->dvc_tlv_table[mid]); if (target < ar_mid) r = mid; else l = mid; } - ar_l = get_unaligned_be32(tas2563_dvc_table[l]); - ar_r = get_unaligned_be32(tas2563_dvc_table[r]); + ar_l = get_unaligned_be32(tas_dev->dvc_tlv_table[l]); + ar_r = get_unaligned_be32(tas_dev->dvc_tlv_table[r]); /* find out the member same as or closer to the current volume */ ucontrol->value.integer.value[0] = @@ -841,7 +859,7 @@ static int tas2563_digital_gain_get( return 0; } -static int tas2563_digital_gain_put( +static int tasdevice_digital_gain_put( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -867,7 +885,7 @@ static int tas2563_digital_gain_put( } volrd = get_unaligned_be32(&data[0]); - volwr = get_unaligned_be32(tas2563_dvc_table[vol]); + volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]); if (volrd == volwr) { rc = 0; @@ -876,7 +894,7 @@ static int tas2563_digital_gain_put( for (i = 0; i < tas_dev->ndev; i++) { ret = tasdevice_dev_bulk_write(tas_dev, i, reg, - (unsigned char *)tas2563_dvc_table[vol], 4); + (unsigned char *)tas_dev->dvc_tlv_table[vol], 4); if (ret) { dev_err(tas_dev->dev, "%s, set digital vol error in dev %d\n", @@ -892,11 +910,6 @@ static int tas2563_digital_gain_put( return rc; } -static const struct snd_kcontrol_new tasdevice_snd_controls[] = { - SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, - tasdev_force_fwload_get, tasdev_force_fwload_put), -}; - static const struct snd_kcontrol_new tasdevice_cali_controls[] = { SOC_SINGLE_EXT("Calibration Stop", SND_SOC_NOPM, 0, 1, 0, tasdev_nop_get, tasdev_calib_stop_put), @@ -907,6 +920,16 @@ static const struct snd_kcontrol_new tasdevice_cali_controls[] = { SND_SOC_BYTES_EXT("Amp XMA2 Data", 6, tasdev_XMA2_data_get, NULL), }; +static const struct snd_kcontrol_new tas2x20_snd_controls[] = { + SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2X20_AMP_LEVEL, + 0, 0, 42, 1, tas2781_amp_getvol, + tas2781_amp_putvol, tas2x20_amp_tlv), + SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2X20_DVC_LEVEL, + 0, 0, ARRAY_SIZE(tas2x20_dvc_table) - 1, 0, + tasdevice_digital_gain_get, tasdevice_digital_gain_put, + tas2x20_dvc_tlv), +}; + static const struct snd_kcontrol_new tas2781_snd_controls[] = { SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, @@ -916,6 +939,15 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { tas2781_digital_putvol, tas2781_dvc_tlv), }; +static const struct snd_kcontrol_new tas5825_snd_controls[] = { + SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL, + 0, 0, 31, 1, tas2781_amp_getvol, + tas2781_amp_putvol, tas5825_amp_tlv), + SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL, + 0, 0, 254, 1, tas2781_amp_getvol, + tas2781_amp_putvol, tas5825_dvc_tlv), +}; + static const struct snd_kcontrol_new tas2781_cali_controls[] = { SND_SOC_BYTES_EXT("Amp Latch Data", 3, tas2781_latch_reg_get, NULL), }; @@ -923,7 +955,7 @@ static const struct snd_kcontrol_new tas2781_cali_controls[] = { static const struct snd_kcontrol_new tas2563_snd_controls[] = { SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0, 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0, - tas2563_digital_gain_get, tas2563_digital_gain_put, + tasdevice_digital_gain_get, tasdevice_digital_gain_put, tas2563_dvc_tlv), }; @@ -968,8 +1000,8 @@ static int tasdevice_info_chip_id(struct snd_kcontrol *kcontrol, { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; - uinfo->value.integer.min = TAS2563; - uinfo->value.integer.max = TAS2781; + uinfo->value.integer.min = TAS2020; + uinfo->value.integer.max = TAS_OTHERS; return 0; } @@ -1168,9 +1200,9 @@ static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol, static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv) { struct snd_kcontrol_new *dsp_ctrls; - char *active_dev_num, *chip_id; + char *active_dev_num, *chip_id, *fw_load; char *conf_name, *prog_name; - int nr_controls = 4; + int nr_controls = 5; int mix_index = 0; /* Alloc kcontrol via devm_kzalloc, which don't manually @@ -1228,6 +1260,19 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv) dsp_ctrls[mix_index].get = tasdevice_get_chip_id; mix_index++; + fw_load = devm_kstrdup(tas_priv->dev, "Speaker Force Firmware Load", + GFP_KERNEL); + if (!fw_load) + return -ENOMEM; + + dsp_ctrls[mix_index].name = fw_load; + dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + dsp_ctrls[mix_index].info = snd_soc_info_bool_ext; + dsp_ctrls[mix_index].put = tasdev_force_fwload_put; + dsp_ctrls[mix_index].get = tasdev_force_fwload_get; + dsp_ctrls[mix_index].private_value = 0UL; + mix_index++; + return snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls, nr_controls < mix_index ? nr_controls : mix_index); } @@ -1587,6 +1632,16 @@ static void tasdevice_fw_ready(const struct firmware *fmw, * failing to load DSP firmware is NOT an error. */ tas_priv->fw_state = TASDEVICE_RCA_FW_OK; + /* There is no DSP firmware required for TAS2118/2X20/257X. */ + switch (tas_priv->chip_id) { + case TAS2020: + case TAS2118: + case TAS2120: + case TAS2320: + case TAS2570: + case TAS2572: + goto out; + } if (tas_priv->name_prefix) scnprintf(tas_priv->coef_binaryname, 64, "%s-%s_coef.bin", tas_priv->name_prefix, tas_priv->dev_name); @@ -1608,34 +1663,37 @@ static void tasdevice_fw_ready(const struct firmware *fmw, dev_err(tas_priv->dev, "dsp controls error\n"); goto out; } - - ret = tasdevice_create_cali_ctrls(tas_priv); - if (ret) { - dev_err(tas_priv->dev, "cali controls error\n"); - goto out; - } - tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; - /* If calibrated data occurs error, dsp will still works with default - * calibrated data inside algo. - */ - for (i = 0; i < tas_priv->ndev; i++) { - if (tas_priv->name_prefix) - scnprintf(tas_priv->cal_binaryname[i], 64, - "%s-%s_cal_0x%02x.bin", tas_priv->name_prefix, - tas_priv->dev_name, - tas_priv->tasdevice[i].dev_addr); - else - scnprintf(tas_priv->cal_binaryname[i], 64, - "%s_cal_0x%02x.bin", tas_priv->dev_name, - tas_priv->tasdevice[i].dev_addr); - ret = tas2781_load_calibration(tas_priv, - tas_priv->cal_binaryname[i], i); - if (ret != 0) - dev_err(tas_priv->dev, - "%s: load %s error, default will effect\n", - __func__, tas_priv->cal_binaryname[i]); + /* There is no calibration required for TAS5825/TAS5827. */ + if (tas_priv->chip_id < TAS5825) { + ret = tasdevice_create_cali_ctrls(tas_priv); + if (ret) { + dev_err(tas_priv->dev, "cali controls error\n"); + goto out; + } + /* If calibrated data occurs error, dsp will still works + * with default calibrated data inside algo. + */ + for (i = 0; i < tas_priv->ndev; i++) { + if (tas_priv->name_prefix) + scnprintf(tas_priv->cal_binaryname[i], 64, + "%s-%s_cal_0x%02x.bin", + tas_priv->name_prefix, + tas_priv->dev_name, + tas_priv->tasdevice[i].dev_addr); + else + scnprintf(tas_priv->cal_binaryname[i], 64, + "%s_cal_0x%02x.bin", + tas_priv->dev_name, + tas_priv->tasdevice[i].dev_addr); + ret = tas2781_load_calibration(tas_priv, + tas_priv->cal_binaryname[i], i); + if (ret != 0) + dev_err(tas_priv->dev, + "%s: load %s error, keep default.\n", + __func__, tas_priv->cal_binaryname[i]); + } } tasdevice_prmg_load(tas_priv, 0); @@ -1653,8 +1711,14 @@ static void tasdevice_fw_ready(const struct firmware *fmw, #endif out: if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) { - /* If DSP FW fail, DSP kcontrol won't be created. */ - tasdevice_dsp_remove(tas_priv); + switch (tas_priv->chip_id) { + case TAS2563: + case TAS2781: + case TAS5825: + case TAS5827: + /* If DSP FW fail, DSP kcontrol won't be created. */ + tasdevice_dsp_remove(tas_priv); + } } mutex_unlock(&tas_priv->codec_lock); release_firmware(fmw); @@ -1798,13 +1862,30 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec) int rc; switch (tas_priv->chip_id) { + case TAS2020: + case TAS2118: + case TAS2120: + case TAS2320: + case TAS2570: + case TAS2572: + p = (struct snd_kcontrol_new *)tas2x20_snd_controls; + size = ARRAY_SIZE(tas2x20_snd_controls); + tas_priv->dvc_tlv_table = tas2x20_dvc_table; + break; case TAS2781: p = (struct snd_kcontrol_new *)tas2781_snd_controls; size = ARRAY_SIZE(tas2781_snd_controls); break; + case TAS5825: + case TAS5827: + p = (struct snd_kcontrol_new *)tas5825_snd_controls; + size = ARRAY_SIZE(tas5825_snd_controls); + break; default: p = (struct snd_kcontrol_new *)tas2563_snd_controls; size = ARRAY_SIZE(tas2563_snd_controls); + tas_priv->dvc_tlv_table = tas2563_dvc_table; + break; } rc = snd_soc_add_component_controls(codec, p, size); @@ -1844,8 +1925,6 @@ static const struct snd_soc_component_driver soc_codec_driver_tasdevice = { .probe = tasdevice_codec_probe, .remove = tasdevice_codec_remove, - .controls = tasdevice_snd_controls, - .num_controls = ARRAY_SIZE(tasdevice_snd_controls), .dapm_widgets = tasdevice_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets), .dapm_routes = tasdevice_audio_map, @@ -1961,7 +2040,16 @@ static void tasdevice_i2c_remove(struct i2c_client *client) #ifdef CONFIG_ACPI static const struct acpi_device_id tasdevice_acpi_match[] = { - { "TAS2781", TAS2781 }, + { "TXNW2020", TAS2020 }, + { "TXNW2118", TAS2118 }, + { "TXNW2120", TAS2120 }, + { "TXNW2320", TAS2320 }, + { "TXNW2563", TAS2563 }, + { "TXNW2570", TAS2570 }, + { "TXNW2572", TAS2572 }, + { "TXNW2781", TAS2781 }, + { "TXNW5825", TAS5825 }, + { "TXNW5827", TAS5827 }, {}, }; From 7095d688de38de197c408f8904cf1c1d8b257dae Mon Sep 17 00:00:00 2001 From: Baojun Xu Date: Sat, 30 Aug 2025 14:14:59 +0800 Subject: [PATCH 1265/1292] ASoC: tas2781: Add tas2118, tas2x20, tas5825 support Update ti,tas2781.yaml for adding tas2118, tas2x20, tas257x and tas582x. Signed-off-by: Baojun Xu Reviewed-by: Rob Herring (Arm) Signed-off-by: Takashi Iwai --- .../devicetree/bindings/sound/ti,tas2781.yaml | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/ti,tas2781.yaml b/Documentation/devicetree/bindings/sound/ti,tas2781.yaml index 5ea1cdc593b50a..011211112be4be 100644 --- a/Documentation/devicetree/bindings/sound/ti,tas2781.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas2781.yaml @@ -1,5 +1,5 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -# Copyright (C) 2022 - 2023 Texas Instruments Incorporated +# Copyright (C) 2022 - 2025 Texas Instruments Incorporated %YAML 1.2 --- $id: http://devicetree.org/schemas/sound/ti,tas2781.yaml# @@ -11,30 +11,77 @@ maintainers: - Shenghao Ding description: | + The TAS2118/TAS2X20/TAS257x is mono, digital input Class-D audio + amplifier optimized for efficiently driving high peak power into + small loudspeakers. + Integrated speaker voltage and current sense provides for + real time monitoring of loudspeaker behavior. The TAS2563/TAS2781 is a mono, digital input Class-D audio amplifier optimized for efficiently driving high peak power into small loudspeakers. An integrated on-chip DSP supports Texas Instruments Smart Amp speaker protection algorithm. The integrated speaker voltage and current sense provides for real time monitoring of loudspeaker behavior. + The TAS5825/TAS5827 is a stereo, digital input Class-D audio + amplifier optimized for efficiently driving high peak power into + small loudspeakers. An integrated on-chip DSP supports Texas + Instruments Smart Amp speaker protection algorithm. The + integrated speaker voltage and current sense provides for real time + monitoring of loudspeaker behavior. Specifications about the audio amplifier can be found at: + https://www.ti.com/lit/gpn/tas2120 + https://www.ti.com/lit/gpn/tas2320 https://www.ti.com/lit/gpn/tas2563 + https://www.ti.com/lit/gpn/tas2572 https://www.ti.com/lit/gpn/tas2781 + https://www.ti.com/lit/gpn/tas5825m + https://www.ti.com/lit/gpn/tas5827 properties: compatible: description: | + ti,tas2020: 3.2-W Mono Digital Input Class-D Speaker Amp with 5.5V PVDD + Support. + + ti,tas2118: 5-W Mono Digital Input Class-D Speaker Amp with Integrated + 8.4-V Class-H Boost. + + ti,tas2120: 8.2-W Mono Digital Input Class-D Speaker Amp with + Integrated 14.75V Class-H Boost. + + ti,tas2320: 15-W Mono Digital Input Class-D Speaker Amp with 15V Support. + ti,tas2563: 6.1-W Boosted Class-D Audio Amplifier With Integrated DSP and IV Sense, 16/20/24/32bit stereo I2S or multichannel TDM. + ti,tas2570: 5.8-W Digital Input smart amp with I/V sense and integrated + 11-V Class-H Boost + + ti,tas2572: 6.6-W Digital Input smart amp with I/V sense and integrated + 13-V Class-H Boost + ti,tas2781: 24-V Class-D Amplifier with Real Time Integrated Speaker Protection and Audio Processing, 16/20/24/32bit stereo I2S or multichannel TDM. + + ti,tas5825: 38-W Stereo, Inductor-Less, Digital Input, Closed-Loop 4.5V + to 26.4V Class-D Audio Amplifier with 192-kHz Extended Audio Processing. + + ti,tas5827: 47-W Stereo, Digital Input, High Efficiency Closed-Loop Class-D + Amplifier with Class-H Algorithm oneOf: - items: - enum: + - ti,tas2020 + - ti,tas2118 + - ti,tas2120 + - ti,tas2320 - ti,tas2563 + - ti,tas2570 + - ti,tas2572 + - ti,tas5825 + - ti,tas5827 - const: ti,tas2781 - enum: - ti,tas2781 @@ -61,6 +108,23 @@ required: allOf: - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - ti,tas2020 + - ti,tas2118 + - ti,tas2120 + - ti,tas2320 + then: + properties: + reg: + maxItems: 4 + items: + minimum: 0x48 + maximum: 0x4b + - if: properties: compatible: @@ -79,6 +143,21 @@ allOf: minimum: 0x4c maximum: 0x4f + - if: + properties: + compatible: + contains: + enum: + - ti,tas2570 + - ti,tas2572 + then: + properties: + reg: + maxItems: 4 + items: + minimum: 0x48 + maximum: 0x4b + - if: properties: compatible: @@ -97,6 +176,21 @@ allOf: minimum: 0x38 maximum: 0x3f + - if: + properties: + compatible: + contains: + enum: + - ti,tas5825 + - ti,tas5827 + then: + properties: + reg: + maxItems: 4 + items: + minimum: 0x4c + maximum: 0x4f + additionalProperties: false examples: From 69e5d50fcf4093fb3f9f41c4f931f12c2ca8c467 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Sep 2025 15:52:03 +0200 Subject: [PATCH 1266/1292] cpufreq: intel_pstate: Fix object lifecycle issue in update_qos_request() The cpufreq_cpu_put() call in update_qos_request() takes place too early because the latter subsequently calls freq_qos_update_request() that indirectly accesses the policy object in question through the QoS request object passed to it. Fortunately, update_qos_request() is called under intel_pstate_driver_lock, so this issue does not matter for changing the intel_pstate operation mode, but it theoretically can cause a crash to occur on CPU device hot removal (which currently can only happen in virt, but it is formally supported nevertheless). Address this issue by modifying update_qos_request() to drop the reference to the policy later. Fixes: da5c504c7aae ("cpufreq: intel_pstate: Implement QoS supported freq constraints") Cc: 5.4+ # 5.4+ Signed-off-by: Rafael J. Wysocki Reviewed-by: Zihuan Zhang Link: https://patch.msgid.link/2255671.irdbgypaU6@rafael.j.wysocki --- drivers/cpufreq/intel_pstate.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index e9fe5dd6c7927b..4cb5e40dd26422 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1667,10 +1667,10 @@ static void update_qos_request(enum freq_qos_req_type type) continue; req = policy->driver_data; - cpufreq_cpu_put(policy); - - if (!req) + if (!req) { + cpufreq_cpu_put(policy); continue; + } if (hwp_active) intel_pstate_get_hwp_cap(cpu); @@ -1686,6 +1686,8 @@ static void update_qos_request(enum freq_qos_req_type type) if (freq_qos_update_request(req, freq) < 0) pr_warn("Failed to update freq constraint: CPU%d\n", i); + + cpufreq_cpu_put(policy); } } From f1bbf5bbf254cba0ae3a46cf4c0a9a6257805b79 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Sep 2025 15:52:54 +0200 Subject: [PATCH 1267/1292] cpufreq: intel_pstate: Rearrange freq QoS updates using __free() Move the code from the for_each_possible_cpu() loop in update_qos_request() to a separate function and use __free() for cpufreq policy reference counting in it to avoid having to call cpufreq_cpu_put() repeatedly (or using goto). While at it, rename update_qos_request() to update_qos_requests() because it updates multiple requests in one go. No intentional functional impact. Link: https://lore.kernel.org/linux-pm/CAJZ5v0gN1T5woSF0tO=TbAh+2-sWzxFjWyDbB7wG2TFCOU01iQ@mail.gmail.com/ Signed-off-by: Rafael J. Wysocki Reviewed-by: Zihuan Zhang Link: https://patch.msgid.link/3026597.e9J7NaK4W3@rafael.j.wysocki [ rjw: Rename "cpu" to "cpudata" and "cpunum" to "cpu" in new code ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 57 +++++++++++++++++----------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 4cb5e40dd26422..33a3debb139f9d 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1652,43 +1652,42 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b, return count; } -static void update_qos_request(enum freq_qos_req_type type) +static void update_cpu_qos_request(int cpu, enum freq_qos_req_type type) { + struct cpudata *cpudata = all_cpu_data[cpu]; struct freq_qos_request *req; - struct cpufreq_policy *policy; - int i; + unsigned int freq, perf_pct; - for_each_possible_cpu(i) { - struct cpudata *cpu = all_cpu_data[i]; - unsigned int freq, perf_pct; + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); + if (!policy) + return; - policy = cpufreq_cpu_get(i); - if (!policy) - continue; + req = policy->driver_data; + if (!req) + return; - req = policy->driver_data; - if (!req) { - cpufreq_cpu_put(policy); - continue; - } + if (hwp_active) + intel_pstate_get_hwp_cap(cpudata); - if (hwp_active) - intel_pstate_get_hwp_cap(cpu); + if (type == FREQ_QOS_MIN) { + perf_pct = global.min_perf_pct; + } else { + req++; + perf_pct = global.max_perf_pct; + } - if (type == FREQ_QOS_MIN) { - perf_pct = global.min_perf_pct; - } else { - req++; - perf_pct = global.max_perf_pct; - } + freq = DIV_ROUND_UP(cpudata->pstate.turbo_freq * perf_pct, 100); - freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * perf_pct, 100); + if (freq_qos_update_request(req, freq) < 0) + pr_warn("Failed to update freq constraint: CPU%d\n", cpu); +} - if (freq_qos_update_request(req, freq) < 0) - pr_warn("Failed to update freq constraint: CPU%d\n", i); +static void update_qos_requests(enum freq_qos_req_type type) +{ + int i; - cpufreq_cpu_put(policy); - } + for_each_possible_cpu(i) + update_cpu_qos_request(i, type); } static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b, @@ -1717,7 +1716,7 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b, if (intel_pstate_driver == &intel_pstate) intel_pstate_update_policies(); else - update_qos_request(FREQ_QOS_MAX); + update_qos_requests(FREQ_QOS_MAX); mutex_unlock(&intel_pstate_driver_lock); @@ -1751,7 +1750,7 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct kobj_attribute *b, if (intel_pstate_driver == &intel_pstate) intel_pstate_update_policies(); else - update_qos_request(FREQ_QOS_MIN); + update_qos_requests(FREQ_QOS_MIN); mutex_unlock(&intel_pstate_driver_lock); From ae1bdd23b99f64335c69d546bff99ca39b894c18 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Sep 2025 15:53:54 +0200 Subject: [PATCH 1268/1292] cpufreq: intel_pstate: Adjust frequency percentage computations Adjust frequency percentage computations in update_cpu_qos_request() to avoid going above the exact numerical percentage in the FREQ_QOS_MAX case. Signed-off-by: Rafael J. Wysocki Acked-by: Zihuan Zhang Link: https://patch.msgid.link/3395556.44csPzL39Z@rafael.j.wysocki [ rjw: Rename "cpu" to "cpudata" and "cpunum" to "cpu" ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 33a3debb139f9d..20746c35d3ba27 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1655,8 +1655,8 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b, static void update_cpu_qos_request(int cpu, enum freq_qos_req_type type) { struct cpudata *cpudata = all_cpu_data[cpu]; + unsigned int freq = cpudata->pstate.turbo_freq; struct freq_qos_request *req; - unsigned int freq, perf_pct; struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); if (!policy) @@ -1670,14 +1670,12 @@ static void update_cpu_qos_request(int cpu, enum freq_qos_req_type type) intel_pstate_get_hwp_cap(cpudata); if (type == FREQ_QOS_MIN) { - perf_pct = global.min_perf_pct; + freq = DIV_ROUND_UP(freq * global.min_perf_pct, 100); } else { req++; - perf_pct = global.max_perf_pct; + freq = (freq * global.max_perf_pct) / 100; } - freq = DIV_ROUND_UP(cpudata->pstate.turbo_freq * perf_pct, 100); - if (freq_qos_update_request(req, freq) < 0) pr_warn("Failed to update freq constraint: CPU%d\n", cpu); } From f89c7fb83ae95578e355bed1a7aeea5f3ca5a067 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Fri, 30 May 2025 15:38:08 +0200 Subject: [PATCH 1269/1292] PM / devfreq: rockchip-dfi: double count on RK3588 On RK3588 with LPDDR4X memory, the cycle count as returned by perf stat -a -e rockchip_ddr/cycles/ sleep 1 consistently reads half as much as what the actual DDR frequency is at. For a LPDDR4X module running at 2112MHz, I get more like 1056059916 cycles per second, which is almost bang-on half what it should be. No, I'm not mixing up megatransfers and megahertz. Consulting the downstream driver, this appears to be because the RK3588 hardware specifically (and RK3528 as well, for future reference) needs a multiplier of 2 to get to the correct frequency with everything but LPDDR5. The RK3588's actual memory bandwidth measurements in MB/s are correct however, as confirmed with stress-ng --stream. This makes me think the access counters are not affected in the same way. This tracks with the vendor kernel not multiplying the access counts either. Solve this by adding a new member to the dfi struct, which each SoC can set to whatever they want, but defaults to 1 if left unset by the SoC init functions. The event_get_count op can then use this multiplier if the cycle count is requested. The cycle multiplier is not used in rockchip_dfi_get_event because the vendor driver doesn't use it there either, and we don't do other actual bandwidth unit conversion stuff in there anyway. Fixes: 481d97ba61e1 ("PM / devfreq: rockchip-dfi: add support for RK3588") Signed-off-by: Nicolas Frattaroli Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20250530-rk3588-dfi-improvements-v1-1-6e077c243a95@collabora.com/ --- drivers/devfreq/event/rockchip-dfi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c index 0470d7c175f4f6..54effb63519653 100644 --- a/drivers/devfreq/event/rockchip-dfi.c +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -116,6 +116,7 @@ struct rockchip_dfi { int buswidth[DMC_MAX_CHANNELS]; int ddrmon_stride; bool ddrmon_ctrl_single; + unsigned int count_multiplier; /* number of data clocks per count */ }; static int rockchip_dfi_enable(struct rockchip_dfi *dfi) @@ -435,7 +436,7 @@ static u64 rockchip_ddr_perf_event_get_count(struct perf_event *event) switch (event->attr.config) { case PERF_EVENT_CYCLES: - count = total.c[0].clock_cycles; + count = total.c[0].clock_cycles * dfi->count_multiplier; break; case PERF_EVENT_READ_BYTES: for (i = 0; i < dfi->max_channels; i++) @@ -655,6 +656,9 @@ static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi) break; } + if (!dfi->count_multiplier) + dfi->count_multiplier = 1; + ret = perf_pmu_register(pmu, "rockchip_ddr", -1); if (ret) return ret; @@ -751,6 +755,7 @@ static int rk3588_dfi_init(struct rockchip_dfi *dfi) dfi->max_channels = 4; dfi->ddrmon_stride = 0x4000; + dfi->count_multiplier = 2; return 0; }; From eddb5ba91b289faa15117d4fc1c2fb223f3493c2 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Fri, 30 May 2025 15:38:09 +0200 Subject: [PATCH 1270/1292] PM / devfreq: rockchip-dfi: add support for LPDDR5 The Rockchip RK3588 SoC can also support LPDDR5 memory. This type of memory needs some special case handling in the rockchip-dfi driver. Add support for it in rockchip-dfi, as well as the needed GRF register definitions. This has been tested as returning both the right cycle count and bandwidth on a LPDDR5 board where the CKR bit is 1. I couldn't test whether the values are correct on a system where CKR is 0, as I'm not savvy enough with the Rockchip tooling to know whether this can be set in the DDR init blob. Downstream has some special case handling for a hardware version where not just the control bits differ, but also the register. Since I don't know whether that hardware version is in any production silicon, it's left unimplemented for now, with an error message urging users to report if they have such a system. There is a slight change of behaviour for non-LPDDR5 systems: instead of writing 0 as the control flags to the control register and pretending everything is alright if the memory type is unknown, we now explicitly return an error. Signed-off-by: Nicolas Frattaroli Reviewed-by: Sascha Hauer Acked-by: Heiko Stuebner Signed-off-by: Chanwoo Choi Link: https://patchwork.kernel.org/project/linux-pm/patch/20250530-rk3588-dfi-improvements-v1-2-6e077c243a95@collabora.com/ --- drivers/devfreq/event/rockchip-dfi.c | 84 ++++++++++++++++++++++------ include/soc/rockchip/rk3588_grf.h | 8 ++- include/soc/rockchip/rockchip_grf.h | 1 + 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c index 54effb63519653..5a2c9badcc64c5 100644 --- a/drivers/devfreq/event/rockchip-dfi.c +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -34,15 +34,18 @@ /* DDRMON_CTRL */ #define DDRMON_CTRL 0x04 +#define DDRMON_CTRL_LPDDR5 BIT(6) #define DDRMON_CTRL_DDR4 BIT(5) #define DDRMON_CTRL_LPDDR4 BIT(4) #define DDRMON_CTRL_HARDWARE_EN BIT(3) #define DDRMON_CTRL_LPDDR23 BIT(2) #define DDRMON_CTRL_SOFTWARE_EN BIT(1) #define DDRMON_CTRL_TIMER_CNT_EN BIT(0) -#define DDRMON_CTRL_DDR_TYPE_MASK (DDRMON_CTRL_DDR4 | \ +#define DDRMON_CTRL_DDR_TYPE_MASK (DDRMON_CTRL_LPDDR5 | \ + DDRMON_CTRL_DDR4 | \ DDRMON_CTRL_LPDDR4 | \ DDRMON_CTRL_LPDDR23) +#define DDRMON_CTRL_LP5_BANK_MODE_MASK GENMASK(8, 7) #define DDRMON_CH0_WR_NUM 0x20 #define DDRMON_CH0_RD_NUM 0x24 @@ -116,13 +119,60 @@ struct rockchip_dfi { int buswidth[DMC_MAX_CHANNELS]; int ddrmon_stride; bool ddrmon_ctrl_single; + u32 lp5_bank_mode; + bool lp5_ckr; /* true if in 4:1 command-to-data clock ratio mode */ unsigned int count_multiplier; /* number of data clocks per count */ }; +static int rockchip_dfi_ddrtype_to_ctrl(struct rockchip_dfi *dfi, u32 *ctrl, + u32 *mask) +{ + u32 ddrmon_ver; + + *mask = DDRMON_CTRL_DDR_TYPE_MASK; + + switch (dfi->ddr_type) { + case ROCKCHIP_DDRTYPE_LPDDR2: + case ROCKCHIP_DDRTYPE_LPDDR3: + *ctrl = DDRMON_CTRL_LPDDR23; + break; + case ROCKCHIP_DDRTYPE_LPDDR4: + case ROCKCHIP_DDRTYPE_LPDDR4X: + *ctrl = DDRMON_CTRL_LPDDR4; + break; + case ROCKCHIP_DDRTYPE_LPDDR5: + ddrmon_ver = readl_relaxed(dfi->regs); + if (ddrmon_ver < 0x40) { + *ctrl = DDRMON_CTRL_LPDDR5 | dfi->lp5_bank_mode; + *mask |= DDRMON_CTRL_LP5_BANK_MODE_MASK; + break; + } + + /* + * As it is unknown whether the unpleasant special case + * behaviour used by the vendor kernel is needed for any + * shipping hardware, ask users to report if they have + * some of that hardware. + */ + dev_err(&dfi->edev->dev, + "unsupported DDRMON version 0x%04X, please let linux-rockchip know!\n", + ddrmon_ver); + return -EOPNOTSUPP; + default: + dev_err(&dfi->edev->dev, "unsupported memory type 0x%X\n", + dfi->ddr_type); + return -EOPNOTSUPP; + } + + return 0; +} + static int rockchip_dfi_enable(struct rockchip_dfi *dfi) { void __iomem *dfi_regs = dfi->regs; int i, ret = 0; + u32 ctrl; + u32 ctrl_mask; mutex_lock(&dfi->mutex); @@ -136,8 +186,11 @@ static int rockchip_dfi_enable(struct rockchip_dfi *dfi) goto out; } + ret = rockchip_dfi_ddrtype_to_ctrl(dfi, &ctrl, &ctrl_mask); + if (ret) + goto out; + for (i = 0; i < dfi->max_channels; i++) { - u32 ctrl = 0; if (!(dfi->channel_mask & BIT(i))) continue; @@ -147,21 +200,7 @@ static int rockchip_dfi_enable(struct rockchip_dfi *dfi) DDRMON_CTRL_SOFTWARE_EN | DDRMON_CTRL_HARDWARE_EN), dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); - /* set ddr type to dfi */ - switch (dfi->ddr_type) { - case ROCKCHIP_DDRTYPE_LPDDR2: - case ROCKCHIP_DDRTYPE_LPDDR3: - ctrl = DDRMON_CTRL_LPDDR23; - break; - case ROCKCHIP_DDRTYPE_LPDDR4: - case ROCKCHIP_DDRTYPE_LPDDR4X: - ctrl = DDRMON_CTRL_LPDDR4; - break; - default: - break; - } - - writel_relaxed(HIWORD_UPDATE(ctrl, DDRMON_CTRL_DDR_TYPE_MASK), + writel_relaxed(HIWORD_UPDATE(ctrl, ctrl_mask), dfi_regs + i * dfi->ddrmon_stride + DDRMON_CTRL); /* enable count, use software mode */ @@ -652,6 +691,7 @@ static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi) break; case ROCKCHIP_DDRTYPE_LPDDR4: case ROCKCHIP_DDRTYPE_LPDDR4X: + case ROCKCHIP_DDRTYPE_LPDDR5: dfi->burst_len = 16; break; } @@ -730,7 +770,7 @@ static int rk3568_dfi_init(struct rockchip_dfi *dfi) static int rk3588_dfi_init(struct rockchip_dfi *dfi) { struct regmap *regmap_pmu = dfi->regmap_pmu; - u32 reg2, reg3, reg4; + u32 reg2, reg3, reg4, reg6; regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG2, ®2); regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG3, ®3); @@ -757,6 +797,14 @@ static int rk3588_dfi_init(struct rockchip_dfi *dfi) dfi->ddrmon_stride = 0x4000; dfi->count_multiplier = 2; + if (dfi->ddr_type == ROCKCHIP_DDRTYPE_LPDDR5) { + regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG6, ®6); + dfi->lp5_bank_mode = FIELD_GET(RK3588_PMUGRF_OS_REG6_LP5_BANK_MODE, reg6) << 7; + dfi->lp5_ckr = FIELD_GET(RK3588_PMUGRF_OS_REG6_LP5_CKR, reg6); + if (dfi->lp5_ckr) + dfi->count_multiplier *= 2; + } + return 0; }; diff --git a/include/soc/rockchip/rk3588_grf.h b/include/soc/rockchip/rk3588_grf.h index 630b35a550640e..02a7b2432d9942 100644 --- a/include/soc/rockchip/rk3588_grf.h +++ b/include/soc/rockchip/rk3588_grf.h @@ -12,7 +12,11 @@ #define RK3588_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3 GENMASK(13, 12) #define RK3588_PMUGRF_OS_REG3_SYSREG_VERSION GENMASK(31, 28) -#define RK3588_PMUGRF_OS_REG4 0x210 -#define RK3588_PMUGRF_OS_REG5 0x214 +#define RK3588_PMUGRF_OS_REG4 0x210 +#define RK3588_PMUGRF_OS_REG5 0x214 +#define RK3588_PMUGRF_OS_REG6 0x218 +#define RK3588_PMUGRF_OS_REG6_LP5_BANK_MODE GENMASK(2, 1) +/* Whether the LPDDR5 is in 2:1 (= 0) or 4:1 (= 1) CKR a.k.a. DQS mode */ +#define RK3588_PMUGRF_OS_REG6_LP5_CKR BIT(0) #endif /* __SOC_RK3588_GRF_H */ diff --git a/include/soc/rockchip/rockchip_grf.h b/include/soc/rockchip/rockchip_grf.h index e46fd72aea8d1f..41c7bb26fd5387 100644 --- a/include/soc/rockchip/rockchip_grf.h +++ b/include/soc/rockchip/rockchip_grf.h @@ -13,6 +13,7 @@ enum { ROCKCHIP_DDRTYPE_LPDDR3 = 6, ROCKCHIP_DDRTYPE_LPDDR4 = 7, ROCKCHIP_DDRTYPE_LPDDR4X = 8, + ROCKCHIP_DDRTYPE_LPDDR5 = 9, }; #endif /* __SOC_ROCKCHIP_GRF_H */ From e0423541477dfb684fbc6e6b5386054bc650f264 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Sep 2025 15:44:45 +0200 Subject: [PATCH 1271/1292] PM: EM: Add function for registering a PD without capacity update The intel_pstate driver manages CPU capacity changes itself and it does not need an update of the capacity of all CPUs in the system to be carried out after registering a PD. Moreover, in some configurations (for instance, an SMT-capable hybrid x86 system booted with nosmt in the kernel command line) the em_check_capacity_update() call at the end of em_dev_register_perf_domain() always fails and reschedules itself to run once again in 1 s, so effectively it runs in vain every 1 s forever. To address this, introduce a new variant of em_dev_register_perf_domain(), called em_dev_register_pd_no_update(), that does not invoke em_check_capacity_update(), and make intel_pstate use it instead of the original. Fixes: 7b010f9b9061 ("cpufreq: intel_pstate: EAS support for hybrid platforms") Closes: https://lore.kernel.org/linux-pm/40212796-734c-4140-8a85-854f72b8144d@panix.com/ Reported-by: Kenneth R. Crudup Tested-by: Kenneth R. Crudup Cc: 6.16+ # 6.16+ Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 4 ++-- include/linux/energy_model.h | 10 ++++++++++ kernel/power/energy_model.c | 29 +++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index f366d35c58404f..0d5d283a5429b3 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1034,8 +1034,8 @@ static bool hybrid_register_perf_domain(unsigned int cpu) if (!cpu_dev) return false; - if (em_dev_register_perf_domain(cpu_dev, HYBRID_EM_STATE_COUNT, &cb, - cpumask_of(cpu), false)) + if (em_dev_register_pd_no_update(cpu_dev, HYBRID_EM_STATE_COUNT, &cb, + cpumask_of(cpu), false)) return false; cpudata->pd_registered = true; diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h index 7fa1eb3cc82399..61d50571ad88ac 100644 --- a/include/linux/energy_model.h +++ b/include/linux/energy_model.h @@ -171,6 +171,9 @@ int em_dev_update_perf_domain(struct device *dev, int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, const struct em_data_callback *cb, const cpumask_t *cpus, bool microwatts); +int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states, + const struct em_data_callback *cb, + const cpumask_t *cpus, bool microwatts); void em_dev_unregister_perf_domain(struct device *dev); struct em_perf_table *em_table_alloc(struct em_perf_domain *pd); void em_table_free(struct em_perf_table *table); @@ -350,6 +353,13 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, { return -EINVAL; } +static inline +int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states, + const struct em_data_callback *cb, + const cpumask_t *cpus, bool microwatts) +{ + return -EINVAL; +} static inline void em_dev_unregister_perf_domain(struct device *dev) { } diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index ea7995a25780f3..8df55397414a12 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -552,6 +552,30 @@ EXPORT_SYMBOL_GPL(em_cpu_get); int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, const struct em_data_callback *cb, const cpumask_t *cpus, bool microwatts) +{ + int ret = em_dev_register_pd_no_update(dev, nr_states, cb, cpus, microwatts); + + if (_is_cpu_device(dev)) + em_check_capacity_update(); + + return ret; +} +EXPORT_SYMBOL_GPL(em_dev_register_perf_domain); + +/** + * em_dev_register_pd_no_update() - Register a perf domain for a device + * @dev : Device to register the PD for + * @nr_states : Number of performance states in the new PD + * @cb : Callback functions for populating the energy model + * @cpus : CPUs to include in the new PD (mandatory if @dev is a CPU device) + * @microwatts : Whether or not the power values in the EM will be in uW + * + * Like em_dev_register_perf_domain(), but does not trigger a CPU capacity + * update after registering the PD, even if @dev is a CPU device. + */ +int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states, + const struct em_data_callback *cb, + const cpumask_t *cpus, bool microwatts) { struct em_perf_table *em_table; unsigned long cap, prev_cap = 0; @@ -636,12 +660,9 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, unlock: mutex_unlock(&em_pd_mutex); - if (_is_cpu_device(dev)) - em_check_capacity_update(); - return ret; } -EXPORT_SYMBOL_GPL(em_dev_register_perf_domain); +EXPORT_SYMBOL_GPL(em_dev_register_pd_no_update); /** * em_dev_unregister_perf_domain() - Unregister Energy Model (EM) for a device From 5590db443a40a35d7fba2db12701346be621a19e Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Sat, 6 Sep 2025 17:23:16 +0530 Subject: [PATCH 1272/1292] cpufreq: conservative: Replace sscanf() with kstrtouint() Replace sscanf() with kstrtouint() in all sysfs store functions to improve input validation and security. The kstrtouint() function provides better error detection, overflow protection, and consistent error handling compared to sscanf(). This maintains existing functionality while improving input validation robustness and following kernel coding best practices for string parsing. Signed-off-by: Kaushlendra Kumar Acked-by: Viresh Kumar Link: https://patch.msgid.link/20250906115316.3010384-1-kaushlendra.kumar@intel.com [ rjw: Dropped duplicate paragraph from the changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 56500b25d77c18..cce6a8d113e12f 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -152,9 +152,9 @@ static ssize_t sampling_down_factor_store(struct gov_attr_set *attr_set, struct dbs_data *dbs_data = to_dbs_data(attr_set); unsigned int input; int ret; - ret = sscanf(buf, "%u", &input); + ret = kstrtouint(buf, 0, &input); - if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) + if (ret || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) return -EINVAL; dbs_data->sampling_down_factor = input; @@ -168,9 +168,9 @@ static ssize_t up_threshold_store(struct gov_attr_set *attr_set, struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; unsigned int input; int ret; - ret = sscanf(buf, "%u", &input); + ret = kstrtouint(buf, 0, &input); - if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold) + if (ret || input > 100 || input <= cs_tuners->down_threshold) return -EINVAL; dbs_data->up_threshold = input; @@ -184,10 +184,10 @@ static ssize_t down_threshold_store(struct gov_attr_set *attr_set, struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; unsigned int input; int ret; - ret = sscanf(buf, "%u", &input); + ret = kstrtouint(buf, 0, &input); /* cannot be lower than 1 otherwise freq will not fall */ - if (ret != 1 || input < 1 || input >= dbs_data->up_threshold) + if (ret || input < 1 || input >= dbs_data->up_threshold) return -EINVAL; cs_tuners->down_threshold = input; @@ -201,9 +201,9 @@ static ssize_t ignore_nice_load_store(struct gov_attr_set *attr_set, unsigned int input; int ret; - ret = sscanf(buf, "%u", &input); - if (ret != 1) - return -EINVAL; + ret = kstrtouint(buf, 0, &input); + if (ret) + return ret; if (input > 1) input = 1; @@ -226,10 +226,10 @@ static ssize_t freq_step_store(struct gov_attr_set *attr_set, const char *buf, struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; unsigned int input; int ret; - ret = sscanf(buf, "%u", &input); + ret = kstrtouint(buf, 0, &input); - if (ret != 1) - return -EINVAL; + if (ret) + return ret; if (input > 100) input = 100; From 7f3cfb7943d27a7b61bdac8db739cf0bdc28e87d Mon Sep 17 00:00:00 2001 From: Sohil Mehta Date: Mon, 8 Sep 2025 16:06:55 -0700 Subject: [PATCH 1273/1292] cpufreq: ondemand: Update the efficient idle check for Intel extended Families IO time is considered busy by default for modern Intel processors. The current check covers recent Family 6 models but excludes the brand new Families 18 and 19. According to Arjan van de Ven, the model check was mainly due to a lack of testing on systems before INTEL_CORE2_MEROM. He suggests considering all Intel processors as having an efficient idle. Extend the IO busy classification to all Intel processors starting with Family 6, including Family 15 (Pentium 4s) and upcoming Families 18/19. Use an x86 VFM check and move the function to the header file to avoid using arch-specific #ifdefs in the C file. Signed-off-by: Sohil Mehta Link: https://patch.msgid.link/20250908230655.2562440-1-sohil.mehta@intel.com [ rjw: Added empty line after #include ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_ondemand.c | 25 +------------------------ drivers/cpufreq/cpufreq_ondemand.h | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 0e65d37c923113..a6ecc203f7b7f3 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -29,29 +29,6 @@ static struct od_ops od_ops; static unsigned int default_powersave_bias; -/* - * Not all CPUs want IO time to be accounted as busy; this depends on how - * efficient idling at a higher frequency/voltage is. - * Pavel Machek says this is not so for various generations of AMD and old - * Intel systems. - * Mike Chan (android.com) claims this is also not true for ARM. - * Because of this, whitelist specific known (series) of CPUs by default, and - * leave all others up to the user. - */ -static int should_io_be_busy(void) -{ -#if defined(CONFIG_X86) - /* - * For Intel, Core 2 (model 15) and later have an efficient idle. - */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_data.x86 == 6 && - boot_cpu_data.x86_model >= 15) - return 1; -#endif - return 0; -} - /* * Find right freq to be set now with powersave_bias on. * Returns the freq_hi to be used right now and will set freq_hi_delay_us, @@ -377,7 +354,7 @@ static int od_init(struct dbs_data *dbs_data) dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR; dbs_data->ignore_nice_load = 0; tuners->powersave_bias = default_powersave_bias; - dbs_data->io_is_busy = should_io_be_busy(); + dbs_data->io_is_busy = od_should_io_be_busy(); dbs_data->tuners = tuners; return 0; diff --git a/drivers/cpufreq/cpufreq_ondemand.h b/drivers/cpufreq/cpufreq_ondemand.h index 1af8e5c4b86fd0..2ca8f1aaf2e348 100644 --- a/drivers/cpufreq/cpufreq_ondemand.h +++ b/drivers/cpufreq/cpufreq_ondemand.h @@ -24,3 +24,26 @@ static inline struct od_policy_dbs_info *to_dbs_info(struct policy_dbs_info *pol struct od_dbs_tuners { unsigned int powersave_bias; }; + +#ifdef CONFIG_X86 +#include + +/* + * Not all CPUs want IO time to be accounted as busy; this depends on + * how efficient idling at a higher frequency/voltage is. + * + * Pavel Machek says this is not so for various generations of AMD and + * old Intel systems. Mike Chan (android.com) claims this is also not + * true for ARM. + * + * Because of this, select a known series of Intel CPUs (Family 6 and + * later) by default, and leave all others up to the user. + */ +static inline bool od_should_io_be_busy(void) +{ + return (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86_vfm >= INTEL_PENTIUM_PRO); +} +#else +static inline bool od_should_io_be_busy(void) { return false; } +#endif From cdc06f912670c8c199d5fa9e78b64b7ed8e871d0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 8 Sep 2025 17:22:12 +0200 Subject: [PATCH 1274/1292] cpuidle: qcom-spm: fix device and OF node leaks at probe Make sure to drop the reference to the saw device taken by of_find_device_by_node() after retrieving its driver data during probe(). Also drop the reference to the CPU node sooner to avoid leaking it in case there is no saw node or device. Fixes: 60f3692b5f0b ("cpuidle: qcom_spm: Detach state machine from main SPM handling") Signed-off-by: Johan Hovold Reviewed-by: Konrad Dybcio Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle-qcom-spm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c index 5f386761b1562a..f60a4cf5364237 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -96,20 +96,23 @@ static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu) return -ENODEV; saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0); + of_node_put(cpu_node); if (!saw_node) return -ENODEV; pdev = of_find_device_by_node(saw_node); of_node_put(saw_node); - of_node_put(cpu_node); if (!pdev) return -ENODEV; data = devm_kzalloc(cpuidle_dev, sizeof(*data), GFP_KERNEL); - if (!data) + if (!data) { + put_device(&pdev->dev); return -ENOMEM; + } data->spm = dev_get_drvdata(&pdev->dev); + put_device(&pdev->dev); if (!data->spm) return -EINVAL; From a2d100c47f4eccb0cb6c2a6a915f2c9e13b54ae7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 8 Sep 2025 17:22:13 +0200 Subject: [PATCH 1275/1292] cpuidle: qcom-spm: drop unnecessary initialisations Drop the unnecessary initialisations of the platform device and driver data pointers which are assigned on first use when registering the cpuidle device during probe. Signed-off-by: Johan Hovold Reviewed-by: Konrad Dybcio Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle-qcom-spm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c index f60a4cf5364237..7ab6f68b96a825 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -86,9 +86,9 @@ static const struct of_device_id qcom_idle_state_match[] = { static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu) { - struct platform_device *pdev = NULL; + struct platform_device *pdev; struct device_node *cpu_node, *saw_node; - struct cpuidle_qcom_spm_data *data = NULL; + struct cpuidle_qcom_spm_data *data; int ret; cpu_node = of_cpu_device_node_get(cpu); From 207cd1de01e398cd3d9a270bb78f8ca9388267d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:16 +0200 Subject: [PATCH 1276/1292] ALSA: aoa: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/core.c | 4 +- sound/aoa/soundbus/i2sbus/pcm.c | 126 ++++++++++++++----------------- 2 files changed, 58 insertions(+), 72 deletions(-) diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index ce84288168e459..f4d43c854bbdf8 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -93,14 +93,12 @@ static irqreturn_t i2sbus_bus_intr(int irq, void *devid) struct i2sbus_dev *dev = devid; u32 intreg; - spin_lock(&dev->low_lock); + guard(spinlock)(&dev->low_lock); intreg = in_le32(&dev->intfregs->intr_ctl); /* acknowledge interrupt reasons */ out_le32(&dev->intfregs->intr_ctl, intreg); - spin_unlock(&dev->low_lock); - return IRQ_HANDLED; } diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 1edda4c9c6ab38..fe11fee3c78fd4 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -505,20 +505,16 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) { struct codec_info_item *cii; struct pcm_info *pi; - int result = 0; - unsigned long flags; - spin_lock_irqsave(&i2sdev->low_lock, flags); + guard(spinlock_irqsave)(&i2sdev->low_lock); get_pcm_info(i2sdev, in, &pi, NULL); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - if (pi->dbdma_ring.running) { - result = -EALREADY; - goto out_unlock; - } + if (pi->dbdma_ring.running) + return -EALREADY; list_for_each_entry(cii, &i2sdev->sound.codec_list, list) if (cii->codec->start) cii->codec->start(cii, pi->substream); @@ -532,7 +528,7 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) udelay(10); if (in_le32(&pi->dbdma->status) & ACTIVE) { pi->dbdma_ring.stopping = 0; - goto out_unlock; /* keep running */ + return 0; /* keep running */ } } } @@ -558,10 +554,8 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - if (!pi->dbdma_ring.running) { - result = -EALREADY; - goto out_unlock; - } + if (!pi->dbdma_ring.running) + return -EALREADY; pi->dbdma_ring.running = 0; /* Set the S0 bit to make the DMA branch to the stop cmd */ @@ -573,13 +567,10 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) cii->codec->stop(cii, pi->substream); break; default: - result = -EINVAL; - goto out_unlock; + return -EINVAL; } - out_unlock: - spin_unlock_irqrestore(&i2sdev->low_lock, flags); - return result; + return 0; } static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) @@ -606,70 +597,67 @@ static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) int dma_stopped = 0; struct snd_pcm_runtime *runtime; - spin_lock(&i2sdev->low_lock); - get_pcm_info(i2sdev, in, &pi, NULL); - if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping) - goto out_unlock; + scoped_guard(spinlock, &i2sdev->low_lock) { + get_pcm_info(i2sdev, in, &pi, NULL); + if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping) + return; + + i = pi->current_period; + runtime = pi->substream->runtime; + while (pi->dbdma_ring.cmds[i].xfer_status) { + if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT) + /* + * BT is the branch taken bit. If it took a branch + * it is because we set the S0 bit to make it + * branch to the stop command. + */ + dma_stopped = 1; + pi->dbdma_ring.cmds[i].xfer_status = 0; + + if (++i >= runtime->periods) { + i = 0; + pi->frame_count += runtime->buffer_size; + } + pi->current_period = i; - i = pi->current_period; - runtime = pi->substream->runtime; - while (pi->dbdma_ring.cmds[i].xfer_status) { - if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT) /* - * BT is the branch taken bit. If it took a branch - * it is because we set the S0 bit to make it - * branch to the stop command. + * Check the frame count. The DMA tends to get a bit + * ahead of the frame counter, which confuses the core. */ - dma_stopped = 1; - pi->dbdma_ring.cmds[i].xfer_status = 0; - - if (++i >= runtime->periods) { - i = 0; - pi->frame_count += runtime->buffer_size; + fc = in_le32(&i2sdev->intfregs->frame_count); + nframes = i * runtime->period_size; + if (fc < pi->frame_count + nframes) + pi->frame_count = fc - nframes; } - pi->current_period = i; - - /* - * Check the frame count. The DMA tends to get a bit - * ahead of the frame counter, which confuses the core. - */ - fc = in_le32(&i2sdev->intfregs->frame_count); - nframes = i * runtime->period_size; - if (fc < pi->frame_count + nframes) - pi->frame_count = fc - nframes; - } - if (dma_stopped) { - timeout = 1000; - for (;;) { - status = in_le32(&pi->dbdma->status); - if (!(status & ACTIVE) && (!in || (status & 0x80))) - break; - if (--timeout <= 0) { - printk(KERN_ERR "i2sbus: timed out " - "waiting for DMA to stop!\n"); - break; + if (dma_stopped) { + timeout = 1000; + for (;;) { + status = in_le32(&pi->dbdma->status); + if (!(status & ACTIVE) && (!in || (status & 0x80))) + break; + if (--timeout <= 0) { + printk(KERN_ERR "i2sbus: timed out " + "waiting for DMA to stop!\n"); + break; + } + udelay(1); } - udelay(1); - } - /* Turn off DMA controller, clear S0 bit */ - out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + /* Turn off DMA controller, clear S0 bit */ + out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + + pi->dbdma_ring.stopping = 0; + if (pi->stop_completion) + complete(pi->stop_completion); + } - pi->dbdma_ring.stopping = 0; - if (pi->stop_completion) - complete(pi->stop_completion); + if (!pi->dbdma_ring.running) + return; } - if (!pi->dbdma_ring.running) - goto out_unlock; - spin_unlock(&i2sdev->low_lock); /* may call _trigger again, hence needs to be unlocked */ snd_pcm_period_elapsed(pi->substream); - return; - - out_unlock: - spin_unlock(&i2sdev->low_lock); } irqreturn_t i2sbus_tx_intr(int irq, void *devid) From 56100eed4f1dbe689b759064dd7d2d5b3604c80c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:17 +0200 Subject: [PATCH 1277/1292] ALSA: aoa: Don't split string across lines We shouldn't split a quoted string, as it worsens the grep-ability. Put back to the single line, which also makes checkpatch.pl happier. Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index fe11fee3c78fd4..4c480ad2c05dc1 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -637,8 +637,8 @@ static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) if (!(status & ACTIVE) && (!in || (status & 0x80))) break; if (--timeout <= 0) { - printk(KERN_ERR "i2sbus: timed out " - "waiting for DMA to stop!\n"); + printk(KERN_ERR + "i2sbus: timed out waiting for DMA to stop!\n"); break; } udelay(1); From 2d7d8e0fa54617a31b840a62541afe9669f38d38 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:18 +0200 Subject: [PATCH 1278/1292] ALSA: arm: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 172 ++++++++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 92 deletions(-) diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 881d5b067c2367..5548ed8e6b1c60 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -210,45 +210,43 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) return; } - spin_lock(&aacirun->lock); - - ptr = aacirun->ptr; - do { - unsigned int len = aacirun->fifo_bytes; - u32 val; - - if (aacirun->bytes <= 0) { - aacirun->bytes += aacirun->period; - period_elapsed = true; - } - if (!(aacirun->cr & CR_EN)) - break; - - val = readl(aacirun->base + AACI_SR); - if (!(val & SR_RXHF)) - break; - if (!(val & SR_RXFF)) - len >>= 1; - - aacirun->bytes -= len; - - /* reading 16 bytes at a time */ - for( ; len > 0; len -= 16) { - asm( - "ldmia %1, {r0, r1, r2, r3}\n\t" - "stmia %0!, {r0, r1, r2, r3}" - : "+r" (ptr) - : "r" (aacirun->fifo) - : "r0", "r1", "r2", "r3", "cc"); - - if (ptr >= aacirun->end) - ptr = aacirun->start; - } - } while(1); - - aacirun->ptr = ptr; - - spin_unlock(&aacirun->lock); + scoped_guard(spinlock, &aacirun->lock) { + ptr = aacirun->ptr; + do { + unsigned int len = aacirun->fifo_bytes; + u32 val; + + if (aacirun->bytes <= 0) { + aacirun->bytes += aacirun->period; + period_elapsed = true; + } + if (!(aacirun->cr & CR_EN)) + break; + + val = readl(aacirun->base + AACI_SR); + if (!(val & SR_RXHF)) + break; + if (!(val & SR_RXFF)) + len >>= 1; + + aacirun->bytes -= len; + + /* reading 16 bytes at a time */ + for( ; len > 0; len -= 16) { + asm( + "ldmia %1, {r0, r1, r2, r3}\n\t" + "stmia %0!, {r0, r1, r2, r3}" + : "+r" (ptr) + : "r" (aacirun->fifo) + : "r0", "r1", "r2", "r3", "cc"); + + if (ptr >= aacirun->end) + ptr = aacirun->start; + } + } while(1); + + aacirun->ptr = ptr; + } if (period_elapsed) snd_pcm_period_elapsed(aacirun->substream); @@ -270,45 +268,43 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) return; } - spin_lock(&aacirun->lock); - - ptr = aacirun->ptr; - do { - unsigned int len = aacirun->fifo_bytes; - u32 val; - - if (aacirun->bytes <= 0) { - aacirun->bytes += aacirun->period; - period_elapsed = true; - } - if (!(aacirun->cr & CR_EN)) - break; - - val = readl(aacirun->base + AACI_SR); - if (!(val & SR_TXHE)) - break; - if (!(val & SR_TXFE)) - len >>= 1; - - aacirun->bytes -= len; - - /* writing 16 bytes at a time */ - for ( ; len > 0; len -= 16) { - asm( - "ldmia %0!, {r0, r1, r2, r3}\n\t" - "stmia %1, {r0, r1, r2, r3}" - : "+r" (ptr) - : "r" (aacirun->fifo) - : "r0", "r1", "r2", "r3", "cc"); - - if (ptr >= aacirun->end) - ptr = aacirun->start; - } - } while (1); - - aacirun->ptr = ptr; - - spin_unlock(&aacirun->lock); + scoped_guard(spinlock, &aacirun->lock) { + ptr = aacirun->ptr; + do { + unsigned int len = aacirun->fifo_bytes; + u32 val; + + if (aacirun->bytes <= 0) { + aacirun->bytes += aacirun->period; + period_elapsed = true; + } + if (!(aacirun->cr & CR_EN)) + break; + + val = readl(aacirun->base + AACI_SR); + if (!(val & SR_TXHE)) + break; + if (!(val & SR_TXFE)) + len >>= 1; + + aacirun->bytes -= len; + + /* writing 16 bytes at a time */ + for ( ; len > 0; len -= 16) { + asm( + "ldmia %0!, {r0, r1, r2, r3}\n\t" + "stmia %1, {r0, r1, r2, r3}" + : "+r" (ptr) + : "r" (aacirun->fifo) + : "r0", "r1", "r2", "r3", "cc"); + + if (ptr >= aacirun->end) + ptr = aacirun->start; + } + } while (1); + + aacirun->ptr = ptr; + } if (period_elapsed) snd_pcm_period_elapsed(aacirun->substream); @@ -577,10 +573,8 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct aaci_runtime *aacirun = substream->runtime->private_data; - unsigned long flags; - int ret = 0; - spin_lock_irqsave(&aacirun->lock, flags); + guard(spinlock_irqsave)(&aacirun->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -606,12 +600,10 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm break; default: - ret = -EINVAL; + return -EINVAL; } - spin_unlock_irqrestore(&aacirun->lock, flags); - - return ret; + return 0; } static const struct snd_pcm_ops aaci_playback_ops = { @@ -661,10 +653,8 @@ static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct aaci_runtime *aacirun = substream->runtime->private_data; - unsigned long flags; - int ret = 0; - spin_lock_irqsave(&aacirun->lock, flags); + guard(spinlock_irqsave)(&aacirun->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -690,12 +680,10 @@ static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd break; default: - ret = -EINVAL; + return -EINVAL; } - spin_unlock_irqrestore(&aacirun->lock, flags); - - return ret; + return 0; } static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream) From f5bf18b076a685a7529dd61e31fc7f9904f5ac56 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:19 +0200 Subject: [PATCH 1279/1292] ALSA: sgio2audio: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 1af177f25c68f1..077fdf2181c15f 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -103,9 +103,8 @@ static int read_ad1843_reg(void *priv, int reg) { struct snd_sgio2audio *chip = priv; int val; - unsigned long flags; - spin_lock_irqsave(&chip->ad1843_lock, flags); + guard(spinlock_irqsave)(&chip->ad1843_lock); writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | CODEC_CONTROL_READ, &mace->perif.audio.codec_control); @@ -115,7 +114,6 @@ static int read_ad1843_reg(void *priv, int reg) val = readq(&mace->perif.audio.codec_read); - spin_unlock_irqrestore(&chip->ad1843_lock, flags); return val; } @@ -126,9 +124,8 @@ static int write_ad1843_reg(void *priv, int reg, int word) { struct snd_sgio2audio *chip = priv; int val; - unsigned long flags; - spin_lock_irqsave(&chip->ad1843_lock, flags); + guard(spinlock_irqsave)(&chip->ad1843_lock); writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | (word << CODEC_CONTROL_WORD_SHIFT), @@ -137,7 +134,6 @@ static int write_ad1843_reg(void *priv, int reg, int word) val = readq(&mace->perif.audio.codec_control); /* flush bus */ udelay(200); - spin_unlock_irqrestore(&chip->ad1843_lock, flags); return 0; } @@ -351,10 +347,9 @@ static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip, u64 *src; s16 *dst; u64 x; - unsigned long flags; struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; - spin_lock_irqsave(&chip->channel[ch].lock, flags); + guard(spinlock_irqsave)(&chip->channel[ch].lock); src_base = (unsigned long) chip->ring_base | (ch << CHANNEL_RING_SHIFT); src_pos = readq(&mace->perif.audio.chan[ch].read_ptr); @@ -383,7 +378,6 @@ static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip, writeq(src_pos, &mace->perif.audio.chan[ch].read_ptr); /* in bytes */ chip->channel[ch].pos = dst_pos; - spin_unlock_irqrestore(&chip->channel[ch].lock, flags); return ret; } @@ -399,10 +393,9 @@ static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip, int src_pos; u64 *dst; s16 *src; - unsigned long flags; struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; - spin_lock_irqsave(&chip->channel[ch].lock, flags); + guard(spinlock_irqsave)(&chip->channel[ch].lock); dst_base = (unsigned long)chip->ring_base | (ch << CHANNEL_RING_SHIFT); dst_pos = readq(&mace->perif.audio.chan[ch].write_ptr); @@ -433,7 +426,6 @@ static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip, writeq(dst_pos, &mace->perif.audio.chan[ch].write_ptr); /* in bytes */ chip->channel[ch].pos = src_pos; - spin_unlock_irqrestore(&chip->channel[ch].lock, flags); return ret; } @@ -584,9 +576,8 @@ static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_sgio2audio_chan *chan = substream->runtime->private_data; int ch = chan->idx; - unsigned long flags; - spin_lock_irqsave(&chip->channel[ch].lock, flags); + guard(spinlock_irqsave)(&chip->channel[ch].lock); /* Setup the pseudo-dma transfer pointers. */ chip->channel[ch].pos = 0; @@ -610,7 +601,6 @@ static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream) runtime->channels); break; } - spin_unlock_irqrestore(&chip->channel[ch].lock, flags); return 0; } From b10b93d1930b1db77df70157efd68695ecaf8c9d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:20 +0200 Subject: [PATCH 1280/1292] ALSA: snd-n64: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/mips/snd-n64.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/sound/mips/snd-n64.c b/sound/mips/snd-n64.c index e1b2ff65d8508a..f17e63f2ff5a67 100644 --- a/sound/mips/snd-n64.c +++ b/sound/mips/snd-n64.c @@ -81,10 +81,9 @@ static u32 n64mi_read_reg(struct n64audio *priv, const u8 reg) static void n64audio_push(struct n64audio *priv) { struct snd_pcm_runtime *runtime = priv->chan.substream->runtime; - unsigned long flags; u32 count; - spin_lock_irqsave(&priv->chan.lock, flags); + guard(spinlock_irqsave)(&priv->chan.lock); count = priv->chan.writesize; @@ -104,15 +103,12 @@ static void n64audio_push(struct n64audio *priv) priv->chan.nextpos %= priv->chan.bufsize; runtime->delay = runtime->period_size; - - spin_unlock_irqrestore(&priv->chan.lock, flags); } static irqreturn_t n64audio_isr(int irq, void *dev_id) { struct n64audio *priv = dev_id; const u32 intrs = n64mi_read_reg(priv, MI_INTR_REG); - unsigned long flags; // Check it's ours if (!(intrs & MI_INTR_AI)) @@ -121,11 +117,9 @@ static irqreturn_t n64audio_isr(int irq, void *dev_id) n64audio_write_reg(priv, AI_STATUS_REG, 1); if (priv->chan.substream && snd_pcm_running(priv->chan.substream)) { - spin_lock_irqsave(&priv->chan.lock, flags); - - priv->chan.pos = priv->chan.nextpos; - - spin_unlock_irqrestore(&priv->chan.lock, flags); + scoped_guard(spinlock_irqsave, &priv->chan.lock) { + priv->chan.pos = priv->chan.nextpos; + } snd_pcm_period_elapsed(priv->chan.substream); if (priv->chan.substream && snd_pcm_running(priv->chan.substream)) @@ -221,7 +215,7 @@ static int n64audio_pcm_prepare(struct snd_pcm_substream *substream) rate = 16; n64audio_write_reg(priv, AI_BITCLOCK_REG, rate - 1); - spin_lock_irq(&priv->chan.lock); + guard(spinlock_irq)(&priv->chan.lock); /* Setup the pseudo-dma transfer pointers. */ priv->chan.pos = 0; @@ -230,7 +224,6 @@ static int n64audio_pcm_prepare(struct snd_pcm_substream *substream) priv->chan.writesize = snd_pcm_lib_period_bytes(substream); priv->chan.bufsize = snd_pcm_lib_buffer_bytes(substream); - spin_unlock_irq(&priv->chan.lock); return 0; } From f1998e16b2566514b31a98bad6950ea96042c465 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:21 +0200 Subject: [PATCH 1281/1292] ALSA: parisc: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/parisc/harmony.c | 103 ++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 62 deletions(-) diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index 76dd2210f9eacd..4b5a54da25fb17 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -140,32 +140,25 @@ harmony_enable_interrupts(struct snd_harmony *h) static void harmony_mute(struct snd_harmony *h) { - unsigned long flags; - - spin_lock_irqsave(&h->mixer_lock, flags); + guard(spinlock_irqsave)(&h->mixer_lock); harmony_wait_for_control(h); harmony_write(h, HARMONY_GAINCTL, HARMONY_GAIN_SILENCE); - spin_unlock_irqrestore(&h->mixer_lock, flags); } static void harmony_unmute(struct snd_harmony *h) { - unsigned long flags; - - spin_lock_irqsave(&h->mixer_lock, flags); + guard(spinlock_irqsave)(&h->mixer_lock); harmony_wait_for_control(h); harmony_write(h, HARMONY_GAINCTL, h->st.gain); - spin_unlock_irqrestore(&h->mixer_lock, flags); } static void harmony_set_control(struct snd_harmony *h) { u32 ctrl; - unsigned long flags; - spin_lock_irqsave(&h->lock, flags); + guard(spinlock_irqsave)(&h->lock); ctrl = (HARMONY_CNTL_C | (h->st.format << 6) | @@ -174,8 +167,6 @@ harmony_set_control(struct snd_harmony *h) harmony_wait_for_control(h); harmony_write(h, HARMONY_CNTL, ctrl); - - spin_unlock_irqrestore(&h->lock, flags); } static irqreturn_t @@ -184,53 +175,53 @@ snd_harmony_interrupt(int irq, void *dev) u32 dstatus; struct snd_harmony *h = dev; - spin_lock(&h->lock); - harmony_disable_interrupts(h); - harmony_wait_for_control(h); - dstatus = harmony_read(h, HARMONY_DSTATUS); - spin_unlock(&h->lock); + scoped_guard(spinlock, &h->lock) { + harmony_disable_interrupts(h); + harmony_wait_for_control(h); + dstatus = harmony_read(h, HARMONY_DSTATUS); + } if (dstatus & HARMONY_DSTATUS_PN) { if (h->psubs && h->st.playing) { - spin_lock(&h->lock); - h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */ - h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */ - - harmony_write(h, HARMONY_PNXTADD, - h->pbuf.addr + h->pbuf.buf); - h->stats.play_intr++; - spin_unlock(&h->lock); + scoped_guard(spinlock, &h->lock) { + h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */ + h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */ + + harmony_write(h, HARMONY_PNXTADD, + h->pbuf.addr + h->pbuf.buf); + h->stats.play_intr++; + } snd_pcm_period_elapsed(h->psubs); } else { - spin_lock(&h->lock); - harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); - h->stats.silence_intr++; - spin_unlock(&h->lock); + scoped_guard(spinlock, &h->lock) { + harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); + h->stats.silence_intr++; + } } } if (dstatus & HARMONY_DSTATUS_RN) { if (h->csubs && h->st.capturing) { - spin_lock(&h->lock); - h->cbuf.buf += h->cbuf.count; - h->cbuf.buf %= h->cbuf.size; - - harmony_write(h, HARMONY_RNXTADD, - h->cbuf.addr + h->cbuf.buf); - h->stats.rec_intr++; - spin_unlock(&h->lock); + scoped_guard(spinlock, &h->lock) { + h->cbuf.buf += h->cbuf.count; + h->cbuf.buf %= h->cbuf.size; + + harmony_write(h, HARMONY_RNXTADD, + h->cbuf.addr + h->cbuf.buf); + h->stats.rec_intr++; + } snd_pcm_period_elapsed(h->csubs); } else { - spin_lock(&h->lock); - harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); - h->stats.graveyard_intr++; - spin_unlock(&h->lock); + scoped_guard(spinlock, &h->lock) { + harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); + h->stats.graveyard_intr++; + } } } - spin_lock(&h->lock); - harmony_enable_interrupts(h); - spin_unlock(&h->lock); + scoped_guard(spinlock, &h->lock) { + harmony_enable_interrupts(h); + } return IRQ_HANDLED; } @@ -297,7 +288,7 @@ snd_harmony_playback_trigger(struct snd_pcm_substream *ss, int cmd) if (h->st.capturing) return -EBUSY; - spin_lock(&h->lock); + guard(spinlock)(&h->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: h->st.playing = 1; @@ -316,11 +307,9 @@ snd_harmony_playback_trigger(struct snd_pcm_substream *ss, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_SUSPEND: default: - spin_unlock(&h->lock); snd_BUG(); return -EINVAL; } - spin_unlock(&h->lock); return 0; } @@ -333,7 +322,7 @@ snd_harmony_capture_trigger(struct snd_pcm_substream *ss, int cmd) if (h->st.playing) return -EBUSY; - spin_lock(&h->lock); + guard(spinlock)(&h->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: h->st.capturing = 1; @@ -352,11 +341,9 @@ snd_harmony_capture_trigger(struct snd_pcm_substream *ss, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_SUSPEND: default: - spin_unlock(&h->lock); snd_BUG(); return -EINVAL; } - spin_unlock(&h->lock); return 0; } @@ -674,7 +661,7 @@ snd_harmony_volume_get(struct snd_kcontrol *kc, int invert = (kc->private_value >> 24) & 0xff; int left, right; - spin_lock_irq(&h->mixer_lock); + guard(spinlock_irq)(&h->mixer_lock); left = (h->st.gain >> shift_left) & mask; right = (h->st.gain >> shift_right) & mask; @@ -687,8 +674,6 @@ snd_harmony_volume_get(struct snd_kcontrol *kc, if (shift_left != shift_right) ucontrol->value.integer.value[1] = right; - spin_unlock_irq(&h->mixer_lock); - return 0; } @@ -704,7 +689,7 @@ snd_harmony_volume_put(struct snd_kcontrol *kc, int left, right; int old_gain = h->st.gain; - spin_lock_irq(&h->mixer_lock); + guard(spinlock_irq)(&h->mixer_lock); left = ucontrol->value.integer.value[0] & mask; if (invert) @@ -722,8 +707,6 @@ snd_harmony_volume_put(struct snd_kcontrol *kc, snd_harmony_set_new_gain(h); - spin_unlock_irq(&h->mixer_lock); - return h->st.gain != old_gain; } @@ -743,13 +726,11 @@ snd_harmony_captureroute_get(struct snd_kcontrol *kc, struct snd_harmony *h = snd_kcontrol_chip(kc); int value; - spin_lock_irq(&h->mixer_lock); + guard(spinlock_irq)(&h->mixer_lock); value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1; ucontrol->value.enumerated.item[0] = value; - spin_unlock_irq(&h->mixer_lock); - return 0; } @@ -761,7 +742,7 @@ snd_harmony_captureroute_put(struct snd_kcontrol *kc, int value; int old_gain = h->st.gain; - spin_lock_irq(&h->mixer_lock); + guard(spinlock_irq)(&h->mixer_lock); value = ucontrol->value.enumerated.item[0] & 1; h->st.gain &= ~HARMONY_GAIN_IS_MASK; @@ -769,8 +750,6 @@ snd_harmony_captureroute_put(struct snd_kcontrol *kc, snd_harmony_set_new_gain(h); - spin_unlock_irq(&h->mixer_lock); - return h->st.gain != old_gain; } From 97bffca637975c6025b5bc5a3bf9926cc6985eab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:22 +0200 Subject: [PATCH 1282/1292] ALSA: snd_ps3: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index ce7ee2713f9d9a..225b20f0b71aaa 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -221,7 +221,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, int fill_stages, dma_ch, stage; enum snd_ps3_ch ch; uint32_t ch0_kick_event = 0; /* initialize to mute gcc */ - unsigned long irqsave; int silent = 0; switch (filltype) { @@ -242,7 +241,7 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, snd_ps3_verify_dma_stop(card, 700, 0); fill_stages = 4; - spin_lock_irqsave(&card->dma_lock, irqsave); + guard(spinlock_irqsave)(&card->dma_lock); for (ch = 0; ch < 2; ch++) { for (stage = 0; stage < fill_stages; stage++) { dma_ch = stage * 2 + ch; @@ -289,7 +288,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, } /* ensure the hardware sees the change */ wmb(); - spin_unlock_irqrestore(&card->dma_lock, irqsave); return 0; } @@ -561,7 +559,6 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - unsigned long irqsave; if (!snd_ps3_set_avsetting(substream)) { /* some parameter changed */ @@ -578,8 +575,7 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream) } /* restart ring buffer pointer */ - spin_lock_irqsave(&card->dma_lock, irqsave); - { + scoped_guard(spinlock_irqsave, &card->dma_lock) { card->dma_buffer_size = runtime->dma_bytes; card->dma_last_transfer_vaddr[SND_PS3_CH_L] = @@ -600,7 +596,6 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream) card->dma_start_bus_addr[SND_PS3_CH_L]); } - spin_unlock_irqrestore(&card->dma_lock, irqsave); /* ensure the hardware sees the change */ mb(); @@ -618,11 +613,9 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, /* clear outstanding interrupts */ update_reg(PS3_AUDIO_AX_IS, 0); - spin_lock(&card->dma_lock); - { + scoped_guard(spinlock, &card->dma_lock) { card->running = 1; } - spin_unlock(&card->dma_lock); snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); @@ -636,11 +629,9 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: - spin_lock(&card->dma_lock); - { + scoped_guard(spinlock, &card->dma_lock) { card->running = 0; } - spin_unlock(&card->dma_lock); snd_ps3_wait_for_dma_stop(card); break; default: @@ -661,12 +652,10 @@ static snd_pcm_uframes_t snd_ps3_pcm_pointer( size_t bytes; snd_pcm_uframes_t ret; - spin_lock(&card->dma_lock); - { + scoped_guard(spinlock, &card->dma_lock) { bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] - card->dma_start_vaddr[SND_PS3_CH_L]); } - spin_unlock(&card->dma_lock); ret = bytes_to_frames(substream->runtime, bytes * 2); From d20cce1ca598231367c05a55e674d243612f3353 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:23 +0200 Subject: [PATCH 1283/1292] ALSA: ppc: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/ppc/awacs.c | 24 +++--------- sound/ppc/beep.c | 17 +++------ sound/ppc/burgundy.c | 10 +---- sound/ppc/pmac.c | 88 ++++++++++++++++++++++---------------------- 4 files changed, 57 insertions(+), 82 deletions(-) diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 13a6f3af13ef89..c231a9d6d1dec7 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -137,13 +137,11 @@ static int snd_pmac_awacs_get_volume(struct snd_kcontrol *kcontrol, int reg = kcontrol->private_value & 0xff; int lshift = (kcontrol->private_value >> 8) & 0xff; int inverted = (kcontrol->private_value >> 16) & 1; - unsigned long flags; int vol[2]; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); vol[0] = (chip->awacs_reg[reg] >> lshift) & 0xf; vol[1] = chip->awacs_reg[reg] & 0xf; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (inverted) { vol[0] = 0x0f - vol[0]; vol[1] = 0x0f - vol[1]; @@ -161,7 +159,6 @@ static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol, int lshift = (kcontrol->private_value >> 8) & 0xff; int inverted = (kcontrol->private_value >> 16) & 1; int val, oldval; - unsigned long flags; unsigned int vol[2]; vol[0] = ucontrol->value.integer.value[0]; @@ -174,14 +171,13 @@ static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol, } vol[0] &= 0x0f; vol[1] &= 0x0f; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); oldval = chip->awacs_reg[reg]; val = oldval & ~(0xf | (0xf << lshift)); val |= vol[0] << lshift; val |= vol[1]; if (oldval != val) snd_pmac_awacs_write_reg(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); return oldval != reg; } @@ -204,11 +200,9 @@ static int snd_pmac_awacs_get_switch(struct snd_kcontrol *kcontrol, int shift = (kcontrol->private_value >> 8) & 0xff; int invert = (kcontrol->private_value >> 16) & 1; int val; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val = (chip->awacs_reg[reg] >> shift) & 1; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (invert) val = 1 - val; ucontrol->value.integer.value[0] = val; @@ -224,16 +218,14 @@ static int snd_pmac_awacs_put_switch(struct snd_kcontrol *kcontrol, int invert = (kcontrol->private_value >> 16) & 1; int mask = 1 << shift; int val, changed; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val = chip->awacs_reg[reg] & ~mask; if (ucontrol->value.integer.value[0] != invert) val |= mask; changed = chip->awacs_reg[reg] != val; if (changed) snd_pmac_awacs_write_reg(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); return changed; } @@ -541,14 +533,12 @@ static int snd_pmac_screamer_mic_boost_get(struct snd_kcontrol *kcontrol, { struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); int val = 0; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (chip->awacs_reg[6] & MASK_MIC_BOOST) val |= 2; if (chip->awacs_reg[0] & MASK_GAINLINE) val |= 1; - spin_unlock_irqrestore(&chip->reg_lock, flags); ucontrol->value.integer.value[0] = val; return 0; } @@ -559,9 +549,8 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); int changed = 0; int val0, val6; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); val0 = chip->awacs_reg[0] & ~MASK_GAINLINE; val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST; if (ucontrol->value.integer.value[0] & 1) @@ -576,7 +565,6 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol, snd_pmac_awacs_write_reg(chip, 6, val6); changed = 1; } - spin_unlock_irqrestore(&chip->reg_lock, flags); return changed; } diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index bf289783eafd22..ab2468790b0c6d 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -88,7 +88,6 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, { struct snd_pmac *chip; struct pmac_beep *beep; - unsigned long flags; int beep_speed = 0; int srate; int period, ncycles, nsamples; @@ -112,10 +111,9 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, return -1; if (! hz) { - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); if (beep->running) snd_pmac_beep_stop(chip); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } @@ -125,13 +123,11 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) hz = 1000; - spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->playback.running || chip->capture.running || beep->running) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + if (chip->playback.running || chip->capture.running || beep->running) + return 0; + beep->running = 1; } - beep->running = 1; - spin_unlock_irqrestore(&chip->reg_lock, flags); if (hz == beep->hz && beep->volume == beep->volume_play) { nsamples = beep->nsamples; @@ -151,9 +147,8 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, beep->nsamples = nsamples; } - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed); - spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index ba15bc34c9eca5..5d6accce3a72f4 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -59,9 +59,8 @@ static unsigned snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr) { unsigned val = 0; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); out_le32(&chip->awacs->codec_ctrl, addr + 0x100000); snd_pmac_burgundy_busy_wait(chip); @@ -83,8 +82,6 @@ snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr) snd_pmac_burgundy_extend_wait(chip); val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<24; - spin_unlock_irqrestore(&chip->reg_lock, flags); - return val; } @@ -100,17 +97,14 @@ static unsigned snd_pmac_burgundy_rcb(struct snd_pmac *chip, unsigned int addr) { unsigned val = 0; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); out_le32(&chip->awacs->codec_ctrl, addr + 0x100000); snd_pmac_burgundy_busy_wait(chip); snd_pmac_burgundy_extend_wait(chip); val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff; - spin_unlock_irqrestore(&chip->reg_lock, flags); - return val; } diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index a3d346f1cc0585..6d7dab26ddf27d 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -206,32 +206,32 @@ static int snd_pmac_pcm_prepare(struct snd_pmac *chip, struct pmac_stream *rec, * common to many PowerBook G3 systems and random noise otherwise * captured on iBook2's about every third time. -ReneR */ - spin_lock_irq(&chip->reg_lock); - snd_pmac_dma_stop(rec); - chip->extra_dma.cmds->command = cpu_to_le16(DBDMA_STOP); - snd_pmac_dma_set_command(rec, &chip->extra_dma); - snd_pmac_dma_run(rec, RUN); - spin_unlock_irq(&chip->reg_lock); - mdelay(5); - spin_lock_irq(&chip->reg_lock); - /* continuous DMA memory type doesn't provide the physical address, - * so we need to resolve the address here... - */ - offset = runtime->dma_addr; - for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) { - cp->phy_addr = cpu_to_le32(offset); - cp->req_count = cpu_to_le16(rec->period_size); - /*cp->res_count = cpu_to_le16(0);*/ - cp->xfer_status = cpu_to_le16(0); - offset += rec->period_size; + scoped_guard(spinlock_irq, &chip->reg_lock) { + snd_pmac_dma_stop(rec); + chip->extra_dma.cmds->command = cpu_to_le16(DBDMA_STOP); + snd_pmac_dma_set_command(rec, &chip->extra_dma); + snd_pmac_dma_run(rec, RUN); } - /* make loop */ - cp->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS); - cp->cmd_dep = cpu_to_le32(rec->cmd.addr); + mdelay(5); + scoped_guard(spinlock_irq, &chip->reg_lock) { + /* continuous DMA memory type doesn't provide the physical address, + * so we need to resolve the address here... + */ + offset = runtime->dma_addr; + for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) { + cp->phy_addr = cpu_to_le32(offset); + cp->req_count = cpu_to_le16(rec->period_size); + /*cp->res_count = cpu_to_le16(0);*/ + cp->xfer_status = cpu_to_le16(0); + offset += rec->period_size; + } + /* make loop */ + cp->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS); + cp->cmd_dep = cpu_to_le32(rec->cmd.addr); - snd_pmac_dma_stop(rec); - snd_pmac_dma_set_command(rec, &rec->cmd); - spin_unlock_irq(&chip->reg_lock); + snd_pmac_dma_stop(rec); + snd_pmac_dma_set_command(rec, &rec->cmd); + } return 0; } @@ -253,26 +253,26 @@ static int snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec, return -EBUSY; command = (subs->stream == SNDRV_PCM_STREAM_PLAYBACK ? OUTPUT_MORE : INPUT_MORE) + INTR_ALWAYS; - spin_lock(&chip->reg_lock); - snd_pmac_beep_stop(chip); - snd_pmac_pcm_set_format(chip); - for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) - out_le16(&cp->command, command); - snd_pmac_dma_set_command(rec, &rec->cmd); - (void)in_le32(&rec->dma->status); - snd_pmac_dma_run(rec, RUN|WAKE); - rec->running = 1; - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + snd_pmac_beep_stop(chip); + snd_pmac_pcm_set_format(chip); + for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) + out_le16(&cp->command, command); + snd_pmac_dma_set_command(rec, &rec->cmd); + (void)in_le32(&rec->dma->status); + snd_pmac_dma_run(rec, RUN|WAKE); + rec->running = 1; + } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - spin_lock(&chip->reg_lock); - rec->running = 0; - snd_pmac_dma_stop(rec); - for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) - out_le16(&cp->command, DBDMA_STOP); - spin_unlock(&chip->reg_lock); + scoped_guard(spinlock, &chip->reg_lock) { + rec->running = 0; + snd_pmac_dma_stop(rec); + for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) + out_le16(&cp->command, DBDMA_STOP); + } break; default: @@ -1321,14 +1321,12 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) void snd_pmac_suspend(struct snd_pmac *chip) { - unsigned long flags; - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); if (chip->suspend) chip->suspend(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_pmac_beep_stop(chip); - spin_unlock_irqrestore(&chip->reg_lock, flags); + scoped_guard(spinlock_irqsave, &chip->reg_lock) { + snd_pmac_beep_stop(chip); + } if (chip->irq >= 0) disable_irq(chip->irq); if (chip->tx_irq >= 0) From bdcdb4e7aa410122baa3496b93e7850dc20a90fa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:24 +0200 Subject: [PATCH 1284/1292] ALSA: line6: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 6 +----- sound/usb/line6/driver.c | 31 +++++++++++++++---------------- sound/usb/line6/midi.c | 10 ++-------- sound/usb/line6/pcm.c | 27 ++++++++++++--------------- 4 files changed, 30 insertions(+), 44 deletions(-) diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 84a9b7b76f43ca..9ef4faa006a038 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -145,8 +145,6 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) static void audio_in_callback(struct urb *urb) { int i, index, length = 0, shutdown = 0; - unsigned long flags; - struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; line6pcm->in.last_frame = urb->start_frame; @@ -156,7 +154,7 @@ static void audio_in_callback(struct urb *urb) if (urb == line6pcm->in.urbs[index]) break; - spin_lock_irqsave(&line6pcm->in.lock, flags); + guard(spinlock_irqsave)(&line6pcm->in.lock); for (i = 0; i < LINE6_ISO_PACKETS; ++i) { char *fbuf; @@ -211,8 +209,6 @@ static void audio_in_callback(struct urb *urb) test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) line6_capture_check_period(line6pcm, length); } - - spin_unlock_irqrestore(&line6pcm->in.lock, flags); } /* open capture callback */ diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index c505c1cba16233..e97368c31417cd 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -286,31 +286,30 @@ static void line6_data_received(struct urb *urb) { struct usb_line6 *line6 = (struct usb_line6 *)urb->context; struct midi_buffer *mb = &line6->line6midi->midibuf_in; - unsigned long flags; int done; if (urb->status == -ESHUTDOWN) return; if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) { - spin_lock_irqsave(&line6->line6midi->lock, flags); - done = - line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); - - if (done < urb->actual_length) { - line6_midibuf_ignore(mb, done); - dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", - done, urb->actual_length); + scoped_guard(spinlock_irqsave, &line6->line6midi->lock) { + done = + line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); + + if (done < urb->actual_length) { + line6_midibuf_ignore(mb, done); + dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", + done, urb->actual_length); + } } - spin_unlock_irqrestore(&line6->line6midi->lock, flags); for (;;) { - spin_lock_irqsave(&line6->line6midi->lock, flags); - done = - line6_midibuf_read(mb, line6->buffer_message, - LINE6_MIDI_MESSAGE_MAXLEN, - LINE6_MIDIBUF_READ_RX); - spin_unlock_irqrestore(&line6->line6midi->lock, flags); + scoped_guard(spinlock_irqsave, &line6->line6midi->lock) { + done = + line6_midibuf_read(mb, line6->buffer_message, + LINE6_MIDI_MESSAGE_MAXLEN, + LINE6_MIDIBUF_READ_RX); + } if (done <= 0) break; diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index 1d77794b4490bd..4731293728e63e 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -72,7 +72,6 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream) */ static void midi_sent(struct urb *urb) { - unsigned long flags; int status; int num; struct usb_line6 *line6 = (struct usb_line6 *)urb->context; @@ -84,7 +83,7 @@ static void midi_sent(struct urb *urb) if (status == -ESHUTDOWN) return; - spin_lock_irqsave(&line6->line6midi->lock, flags); + guard(spinlock_irqsave)(&line6->line6midi->lock); num = --line6->line6midi->num_active_send_urbs; if (num == 0) { @@ -94,8 +93,6 @@ static void midi_sent(struct urb *urb) if (num == 0) wake_up(&line6->line6midi->send_wait); - - spin_unlock_irqrestore(&line6->line6midi->lock, flags); } /* @@ -158,17 +155,14 @@ static int line6_midi_output_close(struct snd_rawmidi_substream *substream) static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { - unsigned long flags; struct usb_line6 *line6 = line6_rawmidi_substream_midi(substream)->line6; line6->line6midi->substream_transmit = substream; - spin_lock_irqsave(&line6->line6midi->lock, flags); + guard(spinlock_irqsave)(&line6->line6midi->lock); if (line6->line6midi->num_active_send_urbs == 0) line6_midi_transmit(substream); - - spin_unlock_irqrestore(&line6->line6midi->lock, flags); } static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 81e6d5e05135ad..f61d9f6cf754c8 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -182,11 +182,10 @@ static void line6_buffer_release(struct snd_line6_pcm *line6pcm, static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, int type) { - unsigned long flags; struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); int ret = 0; - spin_lock_irqsave(&pstr->lock, flags); + guard(spinlock_irqsave)(&pstr->lock); if (!test_and_set_bit(type, &pstr->running) && !(pstr->active_urbs || pstr->unlink_urbs)) { pstr->count = 0; @@ -199,7 +198,6 @@ static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, if (ret < 0) clear_bit(type, &pstr->running); - spin_unlock_irqrestore(&pstr->lock, flags); return ret; } @@ -207,21 +205,20 @@ static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, int type) { - unsigned long flags; struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); - spin_lock_irqsave(&pstr->lock, flags); - clear_bit(type, &pstr->running); - if (!pstr->running) { - spin_unlock_irqrestore(&pstr->lock, flags); - line6_unlink_audio_urbs(line6pcm, pstr); - spin_lock_irqsave(&pstr->lock, flags); - if (direction == SNDRV_PCM_STREAM_CAPTURE) { - line6pcm->prev_fbuf = NULL; - line6pcm->prev_fsize = 0; - } + scoped_guard(spinlock_irqsave, &pstr->lock) { + clear_bit(type, &pstr->running); + if (pstr->running) + return; + } + + line6_unlink_audio_urbs(line6pcm, pstr); + if (direction == SNDRV_PCM_STREAM_CAPTURE) { + guard(spinlock_irqsave)(&pstr->lock); + line6pcm->prev_fbuf = NULL; + line6pcm->prev_fsize = 0; } - spin_unlock_irqrestore(&pstr->lock, flags); } /* common PCM trigger callback */ From d5323227325696b6458eae3cf84705f5caa595fb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:25 +0200 Subject: [PATCH 1285/1292] ALSA: usb: fcp: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/usb/fcp.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c index 98f9964311a735..5ee8d8b660581c 100644 --- a/sound/usb/fcp.c +++ b/sound/usb/fcp.c @@ -820,7 +820,6 @@ static long fcp_hwdep_read(struct snd_hwdep *hw, char __user *buf, { struct usb_mixer_interface *mixer = hw->private_data; struct fcp_data *private = mixer->private_data; - unsigned long flags; long ret = 0; u32 event; @@ -832,10 +831,10 @@ static long fcp_hwdep_read(struct snd_hwdep *hw, char __user *buf, if (ret) return ret; - spin_lock_irqsave(&private->notify.lock, flags); - event = private->notify.event; - private->notify.event = 0; - spin_unlock_irqrestore(&private->notify.lock, flags); + scoped_guard(spinlock_irqsave, &private->notify.lock) { + event = private->notify.event; + private->notify.event = 0; + } if (copy_to_user(buf, &event, sizeof(event))) return -EFAULT; @@ -946,11 +945,9 @@ static void fcp_notify(struct urb *urb) } if (data) { - unsigned long flags; - - spin_lock_irqsave(&private->notify.lock, flags); - private->notify.event |= data; - spin_unlock_irqrestore(&private->notify.lock, flags); + scoped_guard(spinlock_irqsave, &private->notify.lock) { + private->notify.event |= data; + } wake_up_interruptible(&private->notify.queue); } From 02d0aba676ee07481a613a032897528247d31d34 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:26 +0200 Subject: [PATCH 1286/1292] ALSA: usb-audio: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 198 +++++++++++++++++++++++------------------------- 1 file changed, 95 insertions(+), 103 deletions(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 97e7c3b62c8e01..54d01dfd820fa7 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1528,8 +1528,6 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, int counts; unsigned int transfer_done, frame_limit, avail = 0; int i, stride, period_elapsed = 0; - unsigned long flags; - int err = 0; stride = ep->stride; @@ -1537,106 +1535,101 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, ctx->queued = 0; urb->number_of_packets = 0; - spin_lock_irqsave(&subs->lock, flags); - frame_limit = subs->frame_limit + ep->max_urb_frames; - transfer_done = subs->transfer_done; + scoped_guard(spinlock_irqsave, &subs->lock) { + frame_limit = subs->frame_limit + ep->max_urb_frames; + transfer_done = subs->transfer_done; - if (subs->lowlatency_playback && - runtime->state != SNDRV_PCM_STATE_DRAINING) { - unsigned int hwptr = subs->hwptr_done / stride; - - /* calculate the byte offset-in-buffer of the appl_ptr */ - avail = (runtime->control->appl_ptr - runtime->hw_ptr_base) - % runtime->buffer_size; - if (avail <= hwptr) - avail += runtime->buffer_size; - avail -= hwptr; - } + if (subs->lowlatency_playback && + runtime->state != SNDRV_PCM_STATE_DRAINING) { + unsigned int hwptr = subs->hwptr_done / stride; + + /* calculate the byte offset-in-buffer of the appl_ptr */ + avail = (runtime->control->appl_ptr - runtime->hw_ptr_base) + % runtime->buffer_size; + if (avail <= hwptr) + avail += runtime->buffer_size; + avail -= hwptr; + } - for (i = 0; i < ctx->packets; i++) { - counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail); - if (counts < 0) - break; - /* set up descriptor */ - urb->iso_frame_desc[i].offset = frames * stride; - urb->iso_frame_desc[i].length = counts * stride; - frames += counts; - avail -= counts; - urb->number_of_packets++; - transfer_done += counts; - if (transfer_done >= runtime->period_size) { - transfer_done -= runtime->period_size; - frame_limit = 0; - period_elapsed = 1; - if (subs->fmt_type == UAC_FORMAT_TYPE_II) { - if (transfer_done > 0) { - /* FIXME: fill-max mode is not - * supported yet */ - frames -= transfer_done; - counts -= transfer_done; - urb->iso_frame_desc[i].length = - counts * stride; - transfer_done = 0; - } - i++; - if (i < ctx->packets) { - /* add a transfer delimiter */ - urb->iso_frame_desc[i].offset = - frames * stride; - urb->iso_frame_desc[i].length = 0; - urb->number_of_packets++; - } + for (i = 0; i < ctx->packets; i++) { + counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail); + if (counts < 0) break; + /* set up descriptor */ + urb->iso_frame_desc[i].offset = frames * stride; + urb->iso_frame_desc[i].length = counts * stride; + frames += counts; + avail -= counts; + urb->number_of_packets++; + transfer_done += counts; + if (transfer_done >= runtime->period_size) { + transfer_done -= runtime->period_size; + frame_limit = 0; + period_elapsed = 1; + if (subs->fmt_type == UAC_FORMAT_TYPE_II) { + if (transfer_done > 0) { + /* FIXME: fill-max mode is not + * supported yet */ + frames -= transfer_done; + counts -= transfer_done; + urb->iso_frame_desc[i].length = + counts * stride; + transfer_done = 0; + } + i++; + if (i < ctx->packets) { + /* add a transfer delimiter */ + urb->iso_frame_desc[i].offset = + frames * stride; + urb->iso_frame_desc[i].length = 0; + urb->number_of_packets++; + } + break; + } } + /* finish at the period boundary or after enough frames */ + if ((period_elapsed || transfer_done >= frame_limit) && + !snd_usb_endpoint_implicit_feedback_sink(ep)) + break; } - /* finish at the period boundary or after enough frames */ - if ((period_elapsed || transfer_done >= frame_limit) && - !snd_usb_endpoint_implicit_feedback_sink(ep)) - break; - } - if (!frames) { - err = -EAGAIN; - goto unlock; - } - - bytes = frames * stride; - subs->transfer_done = transfer_done; - subs->frame_limit = frame_limit; - if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE && - subs->cur_audiofmt->dsd_dop)) { - fill_playback_urb_dsd_dop(subs, urb, bytes); - } else if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U8 && - subs->cur_audiofmt->dsd_bitrev)) { - fill_playback_urb_dsd_bitrev(subs, urb, bytes); - } else { - /* usual PCM */ - if (!subs->tx_length_quirk) - copy_to_urb(subs, urb, 0, stride, bytes); - else - bytes = copy_to_urb_quirk(subs, urb, stride, bytes); + if (!frames) + return -EAGAIN; + + bytes = frames * stride; + subs->transfer_done = transfer_done; + subs->frame_limit = frame_limit; + if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE && + subs->cur_audiofmt->dsd_dop)) { + fill_playback_urb_dsd_dop(subs, urb, bytes); + } else if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U8 && + subs->cur_audiofmt->dsd_bitrev)) { + fill_playback_urb_dsd_bitrev(subs, urb, bytes); + } else { + /* usual PCM */ + if (!subs->tx_length_quirk) + copy_to_urb(subs, urb, 0, stride, bytes); + else + bytes = copy_to_urb_quirk(subs, urb, stride, bytes); /* bytes is now amount of outgoing data */ - } + } - subs->last_frame_number = usb_get_current_frame_number(subs->dev); + subs->last_frame_number = usb_get_current_frame_number(subs->dev); - if (subs->trigger_tstamp_pending_update) { - /* this is the first actual URB submitted, - * update trigger timestamp to reflect actual start time - */ - snd_pcm_gettime(runtime, &runtime->trigger_tstamp); - subs->trigger_tstamp_pending_update = false; - } + if (subs->trigger_tstamp_pending_update) { + /* this is the first actual URB submitted, + * update trigger timestamp to reflect actual start time + */ + snd_pcm_gettime(runtime, &runtime->trigger_tstamp); + subs->trigger_tstamp_pending_update = false; + } - if (period_elapsed && !subs->running && subs->lowlatency_playback) { - subs->period_elapsed_pending = 1; - period_elapsed = 0; + if (period_elapsed && !subs->running && subs->lowlatency_playback) { + subs->period_elapsed_pending = 1; + period_elapsed = 0; + } } - unlock: - spin_unlock_irqrestore(&subs->lock, flags); - if (err < 0) - return err; urb->transfer_buffer_length = bytes; if (period_elapsed) { if (in_stream_lock) @@ -1654,24 +1647,23 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, static void retire_playback_urb(struct snd_usb_substream *subs, struct urb *urb) { - unsigned long flags; struct snd_urb_ctx *ctx = urb->context; bool period_elapsed = false; - spin_lock_irqsave(&subs->lock, flags); - if (ctx->queued) { - if (subs->inflight_bytes >= ctx->queued) - subs->inflight_bytes -= ctx->queued; - else - subs->inflight_bytes = 0; - } + scoped_guard(spinlock_irqsave, &subs->lock) { + if (ctx->queued) { + if (subs->inflight_bytes >= ctx->queued) + subs->inflight_bytes -= ctx->queued; + else + subs->inflight_bytes = 0; + } - subs->last_frame_number = usb_get_current_frame_number(subs->dev); - if (subs->running) { - period_elapsed = subs->period_elapsed_pending; - subs->period_elapsed_pending = 0; + subs->last_frame_number = usb_get_current_frame_number(subs->dev); + if (subs->running) { + period_elapsed = subs->period_elapsed_pending; + subs->period_elapsed_pending = 0; + } } - spin_unlock_irqrestore(&subs->lock, flags); if (period_elapsed) snd_pcm_period_elapsed(subs->pcm_substream); } From 4c680628ad09027d5f1b2ba8393da680e2256570 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:27 +0200 Subject: [PATCH 1287/1292] ALSA: sparc/amd7930: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/sparc/amd7930.c | 114 +++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 69 deletions(-) diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index e73d3b262f57e7..da04ed5cbac496 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -346,34 +346,25 @@ static struct snd_amd7930 *amd7930_list; /* Idle the AMD7930 chip. The amd->lock is not held. */ static __inline__ void amd7930_idle(struct snd_amd7930 *amd) { - unsigned long flags; - - spin_lock_irqsave(&amd->lock, flags); + guard(spinlock_irqsave)(&amd->lock); sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR); sbus_writeb(0, amd->regs + AMD7930_DR); - spin_unlock_irqrestore(&amd->lock, flags); } /* Enable chip interrupts. The amd->lock is not held. */ static __inline__ void amd7930_enable_ints(struct snd_amd7930 *amd) { - unsigned long flags; - - spin_lock_irqsave(&amd->lock, flags); + guard(spinlock_irqsave)(&amd->lock); sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR); sbus_writeb(AM_INIT_ACTIVE, amd->regs + AMD7930_DR); - spin_unlock_irqrestore(&amd->lock, flags); } /* Disable chip interrupts. The amd->lock is not held. */ static __inline__ void amd7930_disable_ints(struct snd_amd7930 *amd) { - unsigned long flags; - - spin_lock_irqsave(&amd->lock, flags); + guard(spinlock_irqsave)(&amd->lock); sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR); sbus_writeb(AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS, amd->regs + AMD7930_DR); - spin_unlock_irqrestore(&amd->lock, flags); } /* Commit amd7930_map settings to the hardware. @@ -497,34 +488,33 @@ static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id) unsigned int elapsed; u8 ir; - spin_lock(&amd->lock); - - elapsed = 0; - - ir = sbus_readb(amd->regs + AMD7930_IR); - if (ir & AMR_IR_BBUF) { - u8 byte; - - if (amd->flags & AMD7930_FLAG_PLAYBACK) { - if (amd->p_left > 0) { - byte = *(amd->p_cur++); - amd->p_left--; - sbus_writeb(byte, amd->regs + AMD7930_BBTB); - if (amd->p_left == 0) - elapsed |= AMD7930_FLAG_PLAYBACK; - } else - sbus_writeb(0, amd->regs + AMD7930_BBTB); - } else if (amd->flags & AMD7930_FLAG_CAPTURE) { - byte = sbus_readb(amd->regs + AMD7930_BBRB); - if (amd->c_left > 0) { - *(amd->c_cur++) = byte; - amd->c_left--; - if (amd->c_left == 0) - elapsed |= AMD7930_FLAG_CAPTURE; + scoped_guard(spinlock, &amd->lock) { + elapsed = 0; + + ir = sbus_readb(amd->regs + AMD7930_IR); + if (ir & AMR_IR_BBUF) { + u8 byte; + + if (amd->flags & AMD7930_FLAG_PLAYBACK) { + if (amd->p_left > 0) { + byte = *(amd->p_cur++); + amd->p_left--; + sbus_writeb(byte, amd->regs + AMD7930_BBTB); + if (amd->p_left == 0) + elapsed |= AMD7930_FLAG_PLAYBACK; + } else + sbus_writeb(0, amd->regs + AMD7930_BBTB); + } else if (amd->flags & AMD7930_FLAG_CAPTURE) { + byte = sbus_readb(amd->regs + AMD7930_BBRB); + if (amd->c_left > 0) { + *(amd->c_cur++) = byte; + amd->c_left--; + if (amd->c_left == 0) + elapsed |= AMD7930_FLAG_CAPTURE; + } } } } - spin_unlock(&amd->lock); if (elapsed & AMD7930_FLAG_PLAYBACK) snd_pcm_period_elapsed(amd->playback_substream); @@ -536,10 +526,9 @@ static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id) static int snd_amd7930_trigger(struct snd_amd7930 *amd, unsigned int flag, int cmd) { - unsigned long flags; int result = 0; - spin_lock_irqsave(&amd->lock, flags); + guard(spinlock_irqsave)(&amd->lock); if (cmd == SNDRV_PCM_TRIGGER_START) { if (!(amd->flags & flag)) { amd->flags |= flag; @@ -559,7 +548,6 @@ static int snd_amd7930_trigger(struct snd_amd7930 *amd, unsigned int flag, int c } else { result = -EINVAL; } - spin_unlock_irqrestore(&amd->lock, flags); return result; } @@ -583,10 +571,9 @@ static int snd_amd7930_playback_prepare(struct snd_pcm_substream *substream) struct snd_amd7930 *amd = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); - unsigned long flags; u8 new_mmr1; - spin_lock_irqsave(&amd->lock, flags); + guard(spinlock_irqsave)(&amd->lock); amd->flags |= AMD7930_FLAG_PLAYBACK; @@ -605,8 +592,6 @@ static int snd_amd7930_playback_prepare(struct snd_pcm_substream *substream) __amd7930_update_map(amd); } - spin_unlock_irqrestore(&amd->lock, flags); - return 0; } @@ -615,10 +600,9 @@ static int snd_amd7930_capture_prepare(struct snd_pcm_substream *substream) struct snd_amd7930 *amd = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); - unsigned long flags; u8 new_mmr1; - spin_lock_irqsave(&amd->lock, flags); + guard(spinlock_irqsave)(&amd->lock); amd->flags |= AMD7930_FLAG_CAPTURE; @@ -637,8 +621,6 @@ static int snd_amd7930_capture_prepare(struct snd_pcm_substream *substream) __amd7930_update_map(amd); } - spin_unlock_irqrestore(&amd->lock, flags); - return 0; } @@ -805,7 +787,6 @@ static int snd_amd7930_get_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct snd_amd7930 *amd = snd_kcontrol_chip(kctl); - unsigned long flags; int type = kctl->private_value; int *swval, change; @@ -822,7 +803,7 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem break; } - spin_lock_irqsave(&amd->lock, flags); + guard(spinlock_irqsave)(&amd->lock); if (*swval != ucontrol->value.integer.value[0]) { *swval = ucontrol->value.integer.value[0] & 0xff; @@ -831,8 +812,6 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem } else change = 0; - spin_unlock_irqrestore(&amd->lock, flags); - return change; } @@ -921,7 +900,6 @@ static int snd_amd7930_create(struct snd_card *card, struct snd_amd7930 **ramd) { struct snd_amd7930 *amd; - unsigned long flags; int err; *ramd = NULL; @@ -955,25 +933,23 @@ static int snd_amd7930_create(struct snd_card *card, amd7930_enable_ints(amd); - spin_lock_irqsave(&amd->lock, flags); - - amd->rgain = 128; - amd->pgain = 200; - amd->mgain = 0; - - memset(&amd->map, 0, sizeof(amd->map)); - amd->map.mmr1 = (AM_MAP_MMR1_GX | AM_MAP_MMR1_GER | - AM_MAP_MMR1_GR | AM_MAP_MMR1_STG); - amd->map.mmr2 = (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB); + scoped_guard(spinlock_irqsave, &amd->lock) { + amd->rgain = 128; + amd->pgain = 200; + amd->mgain = 0; - __amd7930_update_map(amd); + memset(&amd->map, 0, sizeof(amd->map)); + amd->map.mmr1 = (AM_MAP_MMR1_GX | AM_MAP_MMR1_GER | + AM_MAP_MMR1_GR | AM_MAP_MMR1_STG); + amd->map.mmr2 = (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB); - /* Always MUX audio (Ba) to channel Bb. */ - sbus_writeb(AMR_MUX_MCR1, amd->regs + AMD7930_CR); - sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4), - amd->regs + AMD7930_DR); + __amd7930_update_map(amd); - spin_unlock_irqrestore(&amd->lock, flags); + /* Always MUX audio (Ba) to channel Bb. */ + sbus_writeb(AMR_MUX_MCR1, amd->regs + AMD7930_CR); + sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4), + amd->regs + AMD7930_DR); + } err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, amd, &snd_amd7930_dev_ops); From 4baca4bf866c32ab8a3d67e1ad10aa35d93ae134 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:28 +0200 Subject: [PATCH 1288/1292] ALSA: sparc/cs4231: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/sparc/cs4231.c | 204 +++++++++++++++---------------------------- 1 file changed, 68 insertions(+), 136 deletions(-) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 8d54617e252689..d9e5cca94c7324 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -357,10 +357,9 @@ static void snd_cs4231_busy_wait(struct snd_cs4231 *chip) static void snd_cs4231_mce_up(struct snd_cs4231 *chip) { - unsigned long flags; int timeout; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); snd_cs4231_ready(chip); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) @@ -376,7 +375,6 @@ static void snd_cs4231_mce_up(struct snd_cs4231 *chip) if (!(timeout & CS4231_MCE)) __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231U(chip, REGSEL)); - spin_unlock_irqrestore(&chip->lock, flags); } static void snd_cs4231_mce_down(struct snd_cs4231 *chip) @@ -486,7 +484,6 @@ static int snd_cs4231_trigger(struct snd_pcm_substream *substream, int cmd) { unsigned int what = 0; struct snd_pcm_substream *s; - unsigned long flags; snd_pcm_group_for_each_entry(s, substream) { if (s == chip->playback_substream) { @@ -498,7 +495,7 @@ static int snd_cs4231_trigger(struct snd_pcm_substream *substream, int cmd) } } - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); if (cmd == SNDRV_PCM_TRIGGER_START) { cs4231_dma_trigger(substream, what, 1); chip->image[CS4231_IFACE_CTRL] |= what; @@ -508,7 +505,6 @@ static int snd_cs4231_trigger(struct snd_pcm_substream *substream, int cmd) } snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - spin_unlock_irqrestore(&chip->lock, flags); break; } default: @@ -564,14 +560,11 @@ static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, int format, static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute) { - unsigned long flags; - mute = mute ? 1 : 0; - spin_lock_irqsave(&chip->lock, flags); - if (chip->calibrate_mute == mute) { - spin_unlock_irqrestore(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); + if (chip->calibrate_mute == mute) return; - } + if (!mute) { snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]); @@ -599,26 +592,23 @@ static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute) snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]); chip->calibrate_mute = mute; - spin_unlock_irqrestore(&chip->lock, flags); } static void snd_cs4231_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char pdfr) { - unsigned long flags; - guard(mutex)(&chip->mce_mutex); snd_cs4231_calibrate_mute(chip, 1); snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, - (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ? - (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) : - pdfr); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, + (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ? + (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) : + pdfr); + } snd_cs4231_mce_down(chip); @@ -667,11 +657,10 @@ static unsigned long snd_cs4231_timer_resolution(struct snd_timer *timer) static int snd_cs4231_timer_start(struct snd_timer *timer) { - unsigned long flags; unsigned int ticks; struct snd_cs4231 *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); ticks = timer->sticks; if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 || (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] || @@ -686,44 +675,39 @@ static int snd_cs4231_timer_start(struct snd_timer *timer) chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE); } - spin_unlock_irqrestore(&chip->lock, flags); return 0; } static int snd_cs4231_timer_stop(struct snd_timer *timer) { - unsigned long flags; struct snd_cs4231 *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE; snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); - spin_unlock_irqrestore(&chip->lock, flags); return 0; } static void snd_cs4231_init(struct snd_cs4231 *chip) { - unsigned long flags; - snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE pr_debug("init: (1)\n"); #endif snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->lock, flags); - chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | - CS4231_PLAYBACK_PIO | - CS4231_RECORD_ENABLE | - CS4231_RECORD_PIO | - CS4231_CALIB_MODE); - chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; - snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | + CS4231_PLAYBACK_PIO | + CS4231_RECORD_ENABLE | + CS4231_RECORD_PIO | + CS4231_CALIB_MODE); + chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; + snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); + } snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -731,10 +715,10 @@ static void snd_cs4231_init(struct snd_cs4231 *chip) #endif snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, - chip->image[CS4231_ALT_FEATURE_1]); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1]); + } snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -742,16 +726,16 @@ static void snd_cs4231_init(struct snd_cs4231 *chip) chip->image[CS4231_ALT_FEATURE_1]); #endif - spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, - chip->image[CS4231_ALT_FEATURE_2]); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, + chip->image[CS4231_ALT_FEATURE_2]); + } snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, - chip->image[CS4231_PLAYBK_FORMAT]); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, + chip->image[CS4231_PLAYBK_FORMAT]); + } snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -759,9 +743,9 @@ static void snd_cs4231_init(struct snd_cs4231 *chip) #endif snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]); - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]); + } snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -771,8 +755,6 @@ static void snd_cs4231_init(struct snd_cs4231 *chip) static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode) { - unsigned long flags; - guard(mutex)(&chip->open_mutex); if ((chip->mode & mode)) return -EAGAIN; @@ -781,7 +763,7 @@ static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode) return 0; } /* ok. now enable and ack CODEC IRQ */ - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); @@ -794,8 +776,6 @@ static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode) CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - spin_unlock_irqrestore(&chip->lock, flags); - chip->mode = mode; return 0; } @@ -896,25 +876,18 @@ static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream) { struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - int ret = 0; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO); - if (WARN_ON(runtime->period_size > 0xffff + 1)) { - ret = -EINVAL; - goto out; - } + if (WARN_ON(runtime->period_size > 0xffff + 1)) + return -EINVAL; chip->p_periods_sent = 0; -out: - spin_unlock_irqrestore(&chip->lock, flags); - - return ret; + return 0; } static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream, @@ -934,27 +907,23 @@ static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream, static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream) { struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - unsigned long flags; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); chip->c_periods_sent = 0; - spin_unlock_irqrestore(&chip->lock, flags); return 0; } static void snd_cs4231_overrange(struct snd_cs4231 *chip) { - unsigned long flags; unsigned char res; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); res = snd_cs4231_in(chip, CS4231_TEST_INIT); - spin_unlock_irqrestore(&chip->lock, flags); /* detect overrange only above 0dB; may be user selectable? */ if (res & (0x08 | 0x02)) @@ -1013,7 +982,6 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer( static int snd_cs4231_probe(struct snd_cs4231 *chip) { - unsigned long flags; int i; int id = 0; int vers = 0; @@ -1024,11 +992,10 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip) if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) msleep(2); else { - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2); id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f; vers = snd_cs4231_in(chip, CS4231_VERSION); - spin_unlock_irqrestore(&chip->lock, flags); if (id == 0x0a) break; /* this is valid value */ } @@ -1038,14 +1005,12 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip) if (id != 0x0a) return -ENODEV; /* no valid device found */ - spin_lock_irqsave(&chip->lock, flags); - - /* clear any pendings IRQ */ - __cs4231_readb(chip, CS4231U(chip, STATUS)); - __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); - mb(); - - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + /* clear any pendings IRQ */ + __cs4231_readb(chip, CS4231U(chip, STATUS)); + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); + mb(); + } chip->image[CS4231_MISC_INFO] = CS4231_MODE2; chip->image[CS4231_IFACE_CTRL] = @@ -1059,12 +1024,10 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip) snd_cs4231_mce_down(chip); - spin_lock_irqsave(&chip->lock, flags); - - for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */ - snd_cs4231_out(chip, i, *ptr++); - - spin_unlock_irqrestore(&chip->lock, flags); + scoped_guard(spinlock_irqsave, &chip->lock) { + for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */ + snd_cs4231_out(chip, i, *ptr++); + } snd_cs4231_mce_up(chip); @@ -1273,14 +1236,12 @@ static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6; ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6; - spin_unlock_irqrestore(&chip->lock, flags); return 0; } @@ -1289,7 +1250,6 @@ static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; unsigned short left, right; int change; @@ -1299,7 +1259,7 @@ static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, left = ucontrol->value.enumerated.item[0] << 6; right = ucontrol->value.enumerated.item[1] << 6; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left; right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right; @@ -1308,8 +1268,6 @@ static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, snd_cs4231_out(chip, CS4231_LEFT_INPUT, left); snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right); - spin_unlock_irqrestore(&chip->lock, flags); - return change; } @@ -1331,18 +1289,15 @@ static int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; - spin_unlock_irqrestore(&chip->lock, flags); - if (invert) ucontrol->value.integer.value[0] = (mask - ucontrol->value.integer.value[0]); @@ -1354,7 +1309,6 @@ static int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -1367,14 +1321,12 @@ static int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, val = mask - val; val <<= shift; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); val = (chip->image[reg] & ~(mask << shift)) | val; change = val != chip->image[reg]; snd_cs4231_out(chip, reg, val); - spin_unlock_irqrestore(&chip->lock, flags); - return change; } @@ -1396,7 +1348,6 @@ static int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -1404,15 +1355,13 @@ static int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; - spin_unlock_irqrestore(&chip->lock, flags); - if (invert) { ucontrol->value.integer.value[0] = (mask - ucontrol->value.integer.value[0]); @@ -1427,7 +1376,6 @@ static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; @@ -1446,7 +1394,7 @@ static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; @@ -1455,8 +1403,6 @@ static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, snd_cs4231_out(chip, left_reg, val1); snd_cs4231_out(chip, right_reg, val2); - spin_unlock_irqrestore(&chip->lock, flags); - return change; } @@ -1601,7 +1547,6 @@ static int cs4231_attach_finish(struct snd_card *card) static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id) { - unsigned long flags; unsigned char status; u32 csr; struct snd_cs4231 *chip = dev_id; @@ -1638,9 +1583,8 @@ static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id) snd_cs4231_overrange(chip); /* ACK the CS4231 interrupt. */ - spin_lock_irqsave(&chip->lock, flags); + guard(spinlock_irqsave)(&chip->lock); snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); - spin_unlock_irqrestore(&chip->lock, flags); return IRQ_HANDLED; } @@ -1652,42 +1596,34 @@ static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id) static int sbus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len) { - unsigned long flags; u32 test, csr; - int err; struct sbus_dma_info *base = &dma_cont->sbus_info; if (len >= (1 << 24)) return -EINVAL; - spin_lock_irqsave(&base->lock, flags); + guard(spinlock_irqsave)(&base->lock); csr = sbus_readl(base->regs + APCCSR); - err = -EINVAL; test = APC_CDMA_READY; if (base->dir == APC_PLAY) test = APC_PDMA_READY; if (!(csr & test)) - goto out; - err = -EBUSY; + return -EINVAL; test = APC_XINT_CNVA; if (base->dir == APC_PLAY) test = APC_XINT_PNVA; if (!(csr & test)) - goto out; - err = 0; + return -EBUSY; sbus_writel(bus_addr, base->regs + base->dir + APCNVA); sbus_writel(len, base->regs + base->dir + APCNC); -out: - spin_unlock_irqrestore(&base->lock, flags); - return err; + return 0; } static void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d) { - unsigned long flags; u32 csr, test; struct sbus_dma_info *base = &dma_cont->sbus_info; - spin_lock_irqsave(&base->lock, flags); + guard(spinlock_irqsave)(&base->lock); csr = sbus_readl(base->regs + APCCSR); test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL | @@ -1697,16 +1633,14 @@ static void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d) APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL; csr |= test; sbus_writel(csr, base->regs + APCCSR); - spin_unlock_irqrestore(&base->lock, flags); } static void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on) { - unsigned long flags; u32 csr, shift; struct sbus_dma_info *base = &dma_cont->sbus_info; - spin_lock_irqsave(&base->lock, flags); + guard(spinlock_irqsave)(&base->lock); if (!on) { sbus_writel(0, base->regs + base->dir + APCNC); sbus_writel(0, base->regs + base->dir + APCNVA); @@ -1731,8 +1665,6 @@ static void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on) else csr &= ~(APC_CDMA_READY << shift); sbus_writel(csr, base->regs + APCCSR); - - spin_unlock_irqrestore(&base->lock, flags); } static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont) From 3c30d57544bf91d6adaf3cab8474194e4c4404bc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2025 13:09:29 +0200 Subject: [PATCH 1289/1292] ALSA: sparc/dbri: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: Takashi Iwai --- sound/sparc/dbri.c | 232 +++++++++++++++++++++------------------------ 1 file changed, 109 insertions(+), 123 deletions(-) diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 93cbe158009f20..75f82a92ff44fd 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -758,40 +758,38 @@ static void dbri_initialize(struct snd_dbri *dbri) u32 dvma_addr = (u32)dbri->dma_dvma; s32 *cmd; u32 dma_addr; - unsigned long flags; int n; - spin_lock_irqsave(&dbri->lock, flags); - - dbri_reset(dbri); + scoped_guard(spinlock_irqsave, &dbri->lock) { + dbri_reset(dbri); - /* Initialize pipes */ - for (n = 0; n < DBRI_NO_PIPES; n++) - dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; + /* Initialize pipes */ + for (n = 0; n < DBRI_NO_PIPES; n++) + dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; - spin_lock_init(&dbri->cmdlock); - /* - * Initialize the interrupt ring buffer. - */ - dma_addr = dvma_addr + dbri_dma_off(intr, 0); - dbri->dma->intr[0] = dma_addr; - dbri->dbri_irqp = 1; - /* - * Set up the interrupt queue - */ - spin_lock(&dbri->cmdlock); - cmd = dbri->cmdptr = dbri->dma->cmd; - *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); - *(cmd++) = dma_addr; - *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); - dbri->cmdptr = cmd; - *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); - *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); - dma_addr = dvma_addr + dbri_dma_off(cmd, 0); - sbus_writel(dma_addr, dbri->regs + REG8); - spin_unlock(&dbri->cmdlock); + spin_lock_init(&dbri->cmdlock); + /* + * Initialize the interrupt ring buffer. + */ + dma_addr = dvma_addr + dbri_dma_off(intr, 0); + dbri->dma->intr[0] = dma_addr; + dbri->dbri_irqp = 1; + /* + * Set up the interrupt queue + */ + scoped_guard(spinlock, &dbri->cmdlock) { + cmd = dbri->cmdptr = dbri->dma->cmd; + *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); + *(cmd++) = dma_addr; + *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); + dbri->cmdptr = cmd; + *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); + *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); + dma_addr = dvma_addr + dbri_dma_off(cmd, 0); + sbus_writel(dma_addr, dbri->regs + REG8); + } + } - spin_unlock_irqrestore(&dbri->lock, flags); dbri_cmdwait(dbri); } @@ -1002,7 +1000,6 @@ static void unlink_time_slot(struct snd_dbri *dbri, int pipe, static void xmit_fixed(struct snd_dbri *dbri, int pipe, unsigned int data) { s32 *cmd; - unsigned long flags; if (pipe < 16 || pipe > DBRI_MAX_PIPE) { printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); @@ -1037,9 +1034,10 @@ static void xmit_fixed(struct snd_dbri *dbri, int pipe, unsigned int data) *(cmd++) = data; *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); - spin_lock_irqsave(&dbri->lock, flags); - dbri_cmdsend(dbri, cmd, 3); - spin_unlock_irqrestore(&dbri->lock, flags); + scoped_guard(spinlock_irqsave, &dbri->lock) { + dbri_cmdsend(dbri, cmd, 3); + } + dbri_cmdwait(dbri); } @@ -1317,33 +1315,31 @@ to the DBRI via the CHI interface and few of the DBRI's PIO pins. */ static void cs4215_setup_pipes(struct snd_dbri *dbri) { - unsigned long flags; - - spin_lock_irqsave(&dbri->lock, flags); - /* - * Data mode: - * Pipe 4: Send timeslots 1-4 (audio data) - * Pipe 20: Send timeslots 5-8 (part of ctrl data) - * Pipe 6: Receive timeslots 1-4 (audio data) - * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via - * interrupt, and the rest of the data (slot 5 and 8) is - * not relevant for us (only for doublechecking). - * - * Control mode: - * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) - * Pipe 18: Receive timeslot 1 (clb). - * Pipe 19: Receive timeslot 7 (version). - */ + scoped_guard(spinlock_irqsave, &dbri->lock) { + /* + * Data mode: + * Pipe 4: Send timeslots 1-4 (audio data) + * Pipe 20: Send timeslots 5-8 (part of ctrl data) + * Pipe 6: Receive timeslots 1-4 (audio data) + * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via + * interrupt, and the rest of the data (slot 5 and 8) is + * not relevant for us (only for doublechecking). + * + * Control mode: + * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) + * Pipe 18: Receive timeslot 1 (clb). + * Pipe 19: Receive timeslot 7 (version). + */ - setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB); - setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); - setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB); - setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); + setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB); + setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); + setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB); + setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); - setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); - setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); - setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); - spin_unlock_irqrestore(&dbri->lock, flags); + setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); + setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); + setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); + } dbri_cmdwait(dbri); } @@ -1418,7 +1414,6 @@ static void cs4215_open(struct snd_dbri *dbri) { int data_width; u32 tmp; - unsigned long flags; dprintk(D_MM, "cs4215_open: %d channels, %d bits\n", dbri->mm.channels, dbri->mm.precision); @@ -1443,35 +1438,35 @@ static void cs4215_open(struct snd_dbri *dbri) * bits. The CS4215, it seems, observes TSIN (the delayed signal) * even if it's the CHI master. Don't ask me... */ - spin_lock_irqsave(&dbri->lock, flags); - tmp = sbus_readl(dbri->regs + REG0); - tmp &= ~(D_C); /* Disable CHI */ - sbus_writel(tmp, dbri->regs + REG0); + scoped_guard(spinlock_irqsave, &dbri->lock) { + tmp = sbus_readl(dbri->regs + REG0); + tmp &= ~(D_C); /* Disable CHI */ + sbus_writel(tmp, dbri->regs + REG0); - /* Switch CS4215 to data mode - set PIO3 to 1 */ - sbus_writel(D_ENPIO | D_PIO1 | D_PIO3 | - (dbri->mm.onboard ? D_PIO0 : D_PIO2), dbri->regs + REG2); + /* Switch CS4215 to data mode - set PIO3 to 1 */ + sbus_writel(D_ENPIO | D_PIO1 | D_PIO3 | + (dbri->mm.onboard ? D_PIO0 : D_PIO2), dbri->regs + REG2); - reset_chi(dbri, CHIslave, 128); + reset_chi(dbri, CHIslave, 128); - /* Note: this next doesn't work for 8-bit stereo, because the two - * channels would be on timeslots 1 and 3, with 2 and 4 idle. - * (See CS4215 datasheet Fig 15) - * - * DBRI non-contiguous mode would be required to make this work. - */ - data_width = dbri->mm.channels * dbri->mm.precision; + /* Note: this next doesn't work for 8-bit stereo, because the two + * channels would be on timeslots 1 and 3, with 2 and 4 idle. + * (See CS4215 datasheet Fig 15) + * + * DBRI non-contiguous mode would be required to make this work. + */ + data_width = dbri->mm.channels * dbri->mm.precision; - link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset); - link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32); - link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset); - link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40); + link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset); + link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32); + link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset); + link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40); - /* FIXME: enable CHI after _setdata? */ - tmp = sbus_readl(dbri->regs + REG0); - tmp |= D_C; /* Enable CHI */ - sbus_writel(tmp, dbri->regs + REG0); - spin_unlock_irqrestore(&dbri->lock, flags); + /* FIXME: enable CHI after _setdata? */ + tmp = sbus_readl(dbri->regs + REG0); + tmp |= D_C; /* Enable CHI */ + sbus_writel(tmp, dbri->regs + REG0); + } cs4215_setdata(dbri, 0); } @@ -1483,7 +1478,6 @@ static int cs4215_setctrl(struct snd_dbri *dbri) { int i, val; u32 tmp; - unsigned long flags; /* FIXME - let the CPU do something useful during these delays */ @@ -1520,34 +1514,34 @@ static int cs4215_setctrl(struct snd_dbri *dbri) * done in hardware by a TI 248 that delays the DBRI->4215 * frame sync signal by eight clock cycles. Anybody know why? */ - spin_lock_irqsave(&dbri->lock, flags); - tmp = sbus_readl(dbri->regs + REG0); - tmp &= ~D_C; /* Disable CHI */ - sbus_writel(tmp, dbri->regs + REG0); - - reset_chi(dbri, CHImaster, 128); - - /* - * Control mode: - * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) - * Pipe 18: Receive timeslot 1 (clb). - * Pipe 19: Receive timeslot 7 (version). - */ + scoped_guard(spinlock_irqsave, &dbri->lock) { + tmp = sbus_readl(dbri->regs + REG0); + tmp &= ~D_C; /* Disable CHI */ + sbus_writel(tmp, dbri->regs + REG0); + + reset_chi(dbri, CHImaster, 128); + + /* + * Control mode: + * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) + * Pipe 18: Receive timeslot 1 (clb). + * Pipe 19: Receive timeslot 7 (version). + */ - link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset); - link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset); - link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48); - spin_unlock_irqrestore(&dbri->lock, flags); + link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset); + link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset); + link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48); + } /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */ dbri->mm.ctrl[0] &= ~CS4215_CLB; xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); - spin_lock_irqsave(&dbri->lock, flags); - tmp = sbus_readl(dbri->regs + REG0); - tmp |= D_C; /* Enable CHI */ - sbus_writel(tmp, dbri->regs + REG0); - spin_unlock_irqrestore(&dbri->lock, flags); + scoped_guard(spinlock_irqsave, &dbri->lock) { + tmp = sbus_readl(dbri->regs + REG0); + tmp |= D_C; /* Enable CHI */ + sbus_writel(tmp, dbri->regs + REG0); + } for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) msleep_interruptible(1); @@ -1709,7 +1703,6 @@ static void xmit_descs(struct snd_dbri *dbri) struct dbri_streaminfo *info; u32 dvma_addr; s32 *cmd; - unsigned long flags; int first_td; if (dbri == NULL) @@ -1717,7 +1710,7 @@ static void xmit_descs(struct snd_dbri *dbri) dvma_addr = (u32)dbri->dma_dvma; info = &dbri->stream_info[DBRI_REC]; - spin_lock_irqsave(&dbri->lock, flags); + guard(spinlock_irqsave)(&dbri->lock); if (info->pipe >= 0) { first_td = dbri->pipes[info->pipe].first_desc; @@ -1760,8 +1753,6 @@ static void xmit_descs(struct snd_dbri *dbri) dbri->pipes[info->pipe].desc = first_td; } } - - spin_unlock_irqrestore(&dbri->lock, flags); } /* transmission_complete_intr() @@ -1932,7 +1923,7 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id) if (dbri == NULL) return IRQ_NONE; - spin_lock(&dbri->lock); + guard(spinlock)(&dbri->lock); /* * Read it, so the interrupt goes away. @@ -1977,8 +1968,6 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id) dbri_process_interrupt_buffer(dbri); - spin_unlock(&dbri->lock); - return IRQ_HANDLED; } @@ -2046,17 +2035,16 @@ static int snd_dbri_open(struct snd_pcm_substream *substream) struct snd_dbri *dbri = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); - unsigned long flags; dprintk(D_USR, "open audio output.\n"); runtime->hw = snd_dbri_pcm_hw; - spin_lock_irqsave(&dbri->lock, flags); - info->substream = substream; - info->offset = 0; - info->dvma_buffer = 0; - info->pipe = -1; - spin_unlock_irqrestore(&dbri->lock, flags); + scoped_guard(spinlock_irqsave, &dbri->lock) { + info->substream = substream; + info->offset = 0; + info->dvma_buffer = 0; + info->pipe = -1; + } snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, snd_hw_rule_format, NULL, SNDRV_PCM_HW_PARAM_FORMAT, @@ -2160,7 +2148,7 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) else info->pipe = 6; /* Receive pipe */ - spin_lock_irq(&dbri->lock); + guard(spinlock_irq)(&dbri->lock); info->offset = 0; /* Setup the all the transmit/receive descriptors to cover the @@ -2169,8 +2157,6 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) ret = setup_descs(dbri, DBRI_STREAMNO(substream), snd_pcm_lib_period_bytes(substream)); - spin_unlock_irq(&dbri->lock); - dprintk(D_USR, "prepare audio output. %d bytes\n", info->size); return ret; } From 449c9c02537a146ac97ef962327a221e21c9cab3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 10 Sep 2025 11:41:59 +0200 Subject: [PATCH 1290/1292] PM: hibernate: Restrict GFP mask in hibernation_snapshot() Commit 12ffc3b1513e ("PM: Restrict swap use to later in the suspend sequence") incorrectly removed a pm_restrict_gfp_mask() call from hibernation_snapshot(), so memory allocations involving swap are not prevented from being carried out in this code path any more which may lead to serious breakage. The symptoms of such breakage have become visible after adding a shrink_shmem_memory() call to hibernation_snapshot() in commit 2640e819474f ("PM: hibernate: shrink shmem pages after dev_pm_ops.prepare()") which caused this problem to be much more likely to manifest itself. However, since commit 2640e819474f was initially present in the DRM tree that did not include commit 12ffc3b1513e, the symptoms of this issue were not visible until merge commit 260f6f4fda93 ("Merge tag 'drm-next-2025-07-30' of https://gitlab.freedesktop.org/drm/kernel") that exposed it through an entirely reasonable merge conflict resolution. Fixes: 12ffc3b1513e ("PM: Restrict swap use to later in the suspend sequence") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220555 Reported-by: Todd Brandt Tested-by: Todd Brandt Cc: 6.16+ # 6.16+ Signed-off-by: Rafael J. Wysocki Reviewed-by: Mario Limonciello (AMD) --- kernel/power/hibernate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 1f1f30cca5732d..2f66ab45382319 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -449,6 +449,7 @@ int hibernation_snapshot(int platform_mode) shrink_shmem_memory(); console_suspend_all(); + pm_restrict_gfp_mask(); error = dpm_suspend(PMSG_FREEZE); From 59ba108806516adeaed51a536d55d4f5e9645881 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 10 Sep 2025 18:36:15 -0500 Subject: [PATCH 1291/1292] ASoC: dt-bindings: linux,spdif: Add "port" node The SPDIF receiver/transmitter can be connected to a DAI device via OF graph port. It is already in use and supported. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250910233615.775397-2-robh@kernel.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/linux,spdif.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/linux,spdif.yaml b/Documentation/devicetree/bindings/sound/linux,spdif.yaml index 0f4893e11ec44b..aea6230db54c81 100644 --- a/Documentation/devicetree/bindings/sound/linux,spdif.yaml +++ b/Documentation/devicetree/bindings/sound/linux,spdif.yaml @@ -23,6 +23,9 @@ properties: sound-name-prefix: true + port: + $ref: /schemas/graph.yaml#/properties/port + required: - "#sound-dai-cells" - compatible From e135eeef0b25d44fe71dc3b71b0106d48d825470 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 11 Sep 2025 23:43:22 +0200 Subject: [PATCH 1292/1292] ALSA: aoa: Remove redundant size arguments from strscpy() The size parameter of strscpy() is optional if the destination buffer has a fixed length and strscpy() can automatically determine its size using sizeof(). This makes many explicit size arguments redundant. Remove them to shorten and simplify the code. No functional changes intended. Signed-off-by: Thorsten Blum Signed-off-by: Takashi Iwai --- sound/aoa/codecs/onyx.c | 2 +- sound/aoa/codecs/tas.c | 2 +- sound/aoa/codecs/toonie.c | 2 +- sound/aoa/core/alsa.c | 8 ++++---- sound/aoa/fabrics/layout.c | 9 +++------ 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 7400a5aa47ca64..4cf959017c9d50 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -973,7 +973,7 @@ static int onyx_i2c_probe(struct i2c_client *client) goto fail; } - strscpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN); + strscpy(onyx->codec.name, "onyx"); onyx->codec.owner = THIS_MODULE; onyx->codec.init = onyx_init_codec; onyx->codec.exit = onyx_exit_codec; diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 70216aa059650e..7085e0b93e29b4 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -857,7 +857,7 @@ static int tas_i2c_probe(struct i2c_client *client) /* seems that half is a saner default */ tas->drc_range = TAS3004_DRC_MAX / 2; - strscpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN); + strscpy(tas->codec.name, "tas"); tas->codec.owner = THIS_MODULE; tas->codec.init = tas_init_codec; tas->codec.exit = tas_exit_codec; diff --git a/sound/aoa/codecs/toonie.c b/sound/aoa/codecs/toonie.c index 0da5af12949280..b59967c49e0a2c 100644 --- a/sound/aoa/codecs/toonie.c +++ b/sound/aoa/codecs/toonie.c @@ -126,7 +126,7 @@ static int __init toonie_init(void) if (!toonie) return -ENOMEM; - strscpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name)); + strscpy(toonie->codec.name, "toonie"); toonie->codec.owner = THIS_MODULE; toonie->codec.init = toonie_init_codec; toonie->codec.exit = toonie_exit_codec; diff --git a/sound/aoa/core/alsa.c b/sound/aoa/core/alsa.c index 7fce8581ddbd12..aad7dfe089c7d8 100644 --- a/sound/aoa/core/alsa.c +++ b/sound/aoa/core/alsa.c @@ -28,10 +28,10 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev) return err; aoa_card = alsa_card->private_data; aoa_card->alsa_card = alsa_card; - strscpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver)); - strscpy(alsa_card->shortname, name, sizeof(alsa_card->shortname)); - strscpy(alsa_card->longname, name, sizeof(alsa_card->longname)); - strscpy(alsa_card->mixername, name, sizeof(alsa_card->mixername)); + strscpy(alsa_card->driver, "AppleOnbdAudio"); + strscpy(alsa_card->shortname, name); + strscpy(alsa_card->longname, name); + strscpy(alsa_card->mixername, name); err = snd_card_register(aoa_card->alsa_card); if (err < 0) { printk(KERN_ERR "snd-aoa: couldn't register alsa card\n"); diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index e68b4cb4df296a..bb2a0ef3004bf8 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c @@ -949,8 +949,7 @@ static void layout_attached_codec(struct aoa_codec *codec) ldev->gpio.methods->set_lineout(codec->gpio, 1); ctl = snd_ctl_new1(&lineout_ctl, codec->gpio); if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) - strscpy(ctl->id.name, - "Headphone Switch", sizeof(ctl->id.name)); + strscpy(ctl->id.name, "Headphone Switch"); ldev->lineout_ctrl = ctl; aoa_snd_ctl_add(ctl); ldev->have_lineout_detect = @@ -964,15 +963,13 @@ static void layout_attached_codec(struct aoa_codec *codec) ldev); if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) strscpy(ctl->id.name, - "Headphone Detect Autoswitch", - sizeof(ctl->id.name)); + "Headphone Detect Autoswitch"); aoa_snd_ctl_add(ctl); ctl = snd_ctl_new1(&lineout_detected, ldev); if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) strscpy(ctl->id.name, - "Headphone Detected", - sizeof(ctl->id.name)); + "Headphone Detected"); ldev->lineout_detected_ctrl = ctl; aoa_snd_ctl_add(ctl); }